#include <security/cryptoki.h>
#include <security/pkcs11.h>
#include <smbsrv/smb_kcrypt.h>
#include <sys/cmn_err.h>
#include <sys/debug.h>
#include <stdlib.h>
#include <strings.h>
static int
find_mech(CK_MECHANISM_TYPE id)
{
CK_SESSION_HANDLE hdl;
CK_RV rv;
rv = SUNW_C_GetMechSession(id, &hdl);
if (rv != CKR_OK) {
return (-1);
}
(void) C_CloseSession(hdl);
return (0);
}
int
smb3_aes_ccm_getmech(smb_crypto_mech_t *mech)
{
if (find_mech(CKM_AES_CCM) != 0) {
cmn_err(CE_NOTE, "PKCS#11: no mech AES_CCM");
return (-1);
}
mech->mechanism = CKM_AES_CCM;
return (0);
}
int
smb3_aes_gcm_getmech(smb_crypto_mech_t *mech)
{
if (find_mech(CKM_AES_GCM) != 0) {
cmn_err(CE_NOTE, "PKCS#11: no mech CKM_AES_GCM");
return (-1);
}
mech->mechanism = CKM_AES_GCM;
return (0);
}
void
smb3_crypto_init_ccm_param(smb_enc_ctx_t *ctx,
uint8_t *nonce, size_t noncesize,
uint8_t *auth, size_t authsize,
size_t datasize)
{
ASSERT3U(noncesize, >=, SMB3_AES_CCM_NONCE_SIZE);
ctx->param.ccm.ulDataLen = datasize;
ctx->param.ccm.pNonce = nonce;
ctx->param.ccm.ulNonceLen = SMB3_AES_CCM_NONCE_SIZE;
ctx->param.ccm.pAAD = auth;
ctx->param.ccm.ulAADLen = authsize;
ctx->param.ccm.ulMACLen = SMB2_SIG_SIZE;
ctx->mech.pParameter = (caddr_t)&ctx->param.ccm;
ctx->mech.ulParameterLen = sizeof (ctx->param.ccm);
}
void
smb3_crypto_init_gcm_param(smb_enc_ctx_t *ctx,
uint8_t *nonce, size_t noncesize,
uint8_t *auth, size_t authsize)
{
ASSERT3U(noncesize, >=, SMB3_AES_GCM_NONCE_SIZE);
ctx->param.gcm.pIv = nonce;
ctx->param.gcm.ulIvLen = SMB3_AES_GCM_NONCE_SIZE;
ctx->param.gcm.pAAD = auth;
ctx->param.gcm.ulAADLen = authsize;
ctx->param.gcm.ulTagBits = SMB2_SIG_SIZE << 3;
ctx->mech.pParameter = (caddr_t)&ctx->param.gcm;
ctx->mech.ulParameterLen = sizeof (ctx->param.gcm);
}
int
smb3_encrypt_init(smb_enc_ctx_t *ctxp,
uint8_t *key, size_t keylen)
{
CK_OBJECT_HANDLE hkey = 0;
CK_MECHANISM *mech = &ctxp->mech;
CK_RV rv;
rv = SUNW_C_GetMechSession(mech->mechanism, &ctxp->ctx);
if (rv != CKR_OK)
return (-1);
rv = SUNW_C_KeyToObject(ctxp->ctx, mech->mechanism,
key, keylen, &hkey);
if (rv != CKR_OK)
return (-1);
rv = C_EncryptInit(ctxp->ctx, mech, hkey);
if (rv != CKR_OK) {
cmn_err(CE_WARN, "C_EncryptInit failed: 0x%lx", rv);
}
(void) C_DestroyObject(ctxp->ctx, hkey);
return (rv == CKR_OK ? 0 : -1);
}
int
smb3_decrypt_init(smb_enc_ctx_t *ctxp,
uint8_t *key, size_t keylen)
{
CK_OBJECT_HANDLE hkey = 0;
CK_MECHANISM *mech = &ctxp->mech;
CK_RV rv;
rv = SUNW_C_GetMechSession(mech->mechanism, &ctxp->ctx);
if (rv != CKR_OK)
return (-1);
rv = SUNW_C_KeyToObject(ctxp->ctx, mech->mechanism,
key, keylen, &hkey);
if (rv != CKR_OK)
return (-1);
rv = C_DecryptInit(ctxp->ctx, mech, hkey);
if (rv != CKR_OK) {
cmn_err(CE_WARN, "C_DecryptInit failed: 0x%lx", rv);
}
(void) C_DestroyObject(ctxp->ctx, hkey);
return (rv == CKR_OK ? 0 : -1);
}
int
smb3_encrypt_uio(smb_enc_ctx_t *ctxp, uio_t *in, uio_t *out)
{
uint8_t *buf = NULL;
size_t inlen, outlen;
ulong_t tlen;
int err, rc = -1;
CK_RV rv;
if (in->uio_resid <= 0)
return (-1);
inlen = in->uio_resid;
outlen = inlen + 16;
buf = malloc(outlen);
if (buf == NULL)
return (-1);
err = uiomove(buf, inlen, UIO_WRITE, in);
if (err != 0)
goto out;
tlen = outlen;
rv = C_Encrypt(ctxp->ctx, buf, inlen, buf, &tlen);
if (rv != CKR_OK) {
cmn_err(CE_WARN, "C_Encrypt failed: 0x%lx", rv);
goto out;
}
if (tlen != outlen) {
cmn_err(CE_WARN, "smb3_encrypt_uio outlen %d vs %d",
(int)tlen, (int)outlen);
goto out;
}
err = uiomove(buf, outlen, UIO_READ, out);
if (err != 0)
goto out;
rc = 0;
out:
free(buf);
return (rc);
}
int
smb3_decrypt_uio(smb_enc_ctx_t *ctxp, uio_t *in, uio_t *out)
{
uint8_t *buf = NULL;
size_t inlen, outlen;
ulong_t tlen;
int err, rc = -1;
CK_RV rv;
if (in->uio_resid <= 16)
return (-1);
inlen = in->uio_resid;
outlen = inlen - 16;
buf = malloc(inlen);
if (buf == NULL)
return (-1);
err = uiomove(buf, inlen, UIO_WRITE, in);
if (err != 0)
goto out;
tlen = outlen;
rv = C_Decrypt(ctxp->ctx, buf, inlen, buf, &tlen);
if (rv != CKR_OK) {
cmn_err(CE_WARN, "C_Decrypt failed: 0x%lx", rv);
goto out;
}
if (tlen != outlen) {
cmn_err(CE_WARN, "smb3_decrypt_uio outlen %d vs %d",
(int)tlen, (int)outlen);
goto out;
}
err = uiomove(buf, outlen, UIO_READ, out);
if (err != 0)
goto out;
rc = 0;
out:
free(buf);
return (rc);
}
void
smb3_enc_ctx_done(smb_enc_ctx_t *ctxp)
{
if (ctxp->ctx != 0) {
(void) C_CloseSession(ctxp->ctx);
ctxp->ctx = 0;
}
}