#include <sys/types.h>
#include <sys/kmem.h>
#include <sys/crypto/api.h>
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_kcrypt.h>
static int
find_mech(smb_crypto_mech_t *mech, const char *name)
{
crypto_mech_type_t t;
t = crypto_mech2id(name);
if (t == CRYPTO_MECH_INVALID) {
cmn_err(CE_NOTE, "smb: no kcf mech: %s", name);
return (-1);
}
mech->cm_type = t;
return (0);
}
int
smb_md5_getmech(smb_crypto_mech_t *mech)
{
return (find_mech(mech, SUN_CKM_MD5));
}
int
smb_md5_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech)
{
int rv;
rv = crypto_digest_init(mech, ctxp, NULL);
return (rv == CRYPTO_SUCCESS ? 0 : -1);
}
int
smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
{
crypto_data_t data;
int rv;
bzero(&data, sizeof (data));
data.cd_format = CRYPTO_DATA_RAW;
data.cd_length = len;
data.cd_raw.iov_base = buf;
data.cd_raw.iov_len = len;
rv = crypto_digest_update(ctx, &data, 0);
if (rv != CRYPTO_SUCCESS) {
crypto_cancel_ctx(ctx);
return (-1);
}
return (0);
}
int
smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
{
crypto_data_t out;
int rv;
bzero(&out, sizeof (out));
out.cd_format = CRYPTO_DATA_RAW;
out.cd_length = MD5_DIGEST_LENGTH;
out.cd_raw.iov_len = MD5_DIGEST_LENGTH;
out.cd_raw.iov_base = (void *)digest16;
rv = crypto_digest_final(ctx, &out, 0);
return (rv == CRYPTO_SUCCESS ? 0 : -1);
}
int
smb2_hmac_getmech(smb_crypto_mech_t *mech)
{
return (find_mech(mech, SUN_CKM_SHA256_HMAC_GENERAL));
}
int
smb3_cmac_getmech(smb_crypto_mech_t *mech)
{
return (find_mech(mech, SUN_CKM_AES_CMAC));
}
int
smb3_gmac_getmech(smb_crypto_mech_t *mech)
{
return (find_mech(mech, SUN_CKM_AES_GMAC));
}
void
smb2_sign_init_hmac_param(smb_crypto_mech_t *mech, smb_crypto_param_t *param,
ulong_t hmac_len)
{
param->hmac = hmac_len;
mech->cm_param = (caddr_t)¶m->hmac;
mech->cm_param_len = sizeof (param->hmac);
}
void
smb3_sign_init_gmac_param(smb_crypto_mech_t *mech, smb_crypto_param_t *param,
uint8_t *iv)
{
param->gmac.pIv = iv;
param->gmac.pAAD = NULL;
param->gmac.ulAADLen = 0;
mech->cm_param = (caddr_t)¶m->gmac;
mech->cm_param_len = sizeof (param->gmac);
}
static int
smb2_mac(smb_crypto_mech_t *mech, uint8_t *key, size_t key_len,
crypto_data_t *input, void *mac_buf, size_t mac_len)
{
crypto_data_t out_cd = {
.cd_format = CRYPTO_DATA_RAW,
.cd_length = mac_len,
.cd_raw.iov_len = mac_len,
.cd_raw.iov_base = mac_buf
};
crypto_key_t ckey = {
.ck_format = CRYPTO_KEY_RAW,
.ck_data = key,
.ck_length = key_len * 8
};
int rv;
rv = crypto_mac(mech, input, &ckey, NULL, &out_cd, NULL);
if (rv != CRYPTO_SUCCESS) {
cmn_err(CE_WARN, "crypto_mac failed: 0x%x", rv);
return (-1);
}
return (0);
}
int
smb2_mac_uio(smb_crypto_mech_t *mech, uint8_t *key, size_t key_len,
uio_t *in_uio, uint8_t *digest16)
{
crypto_data_t in_cd = {
.cd_format = CRYPTO_DATA_UIO,
.cd_length = in_uio->uio_resid,
.cd_uio = in_uio
};
return (smb2_mac(mech, key, key_len, &in_cd, digest16, SMB2_SIG_SIZE));
}
int
smb2_mac_raw(smb_crypto_mech_t *mech,
uint8_t *key, size_t key_len,
uint8_t *data, size_t data_len,
uint8_t *mac, size_t mac_len)
{
crypto_data_t in_cd = {
.cd_format = CRYPTO_DATA_RAW,
.cd_length = data_len,
.cd_raw.iov_base = (void *)data,
.cd_raw.iov_len = data_len
};
return (smb2_mac(mech, key, key_len, &in_cd, mac, mac_len));
}