#include <smbsrv/smb2_kproto.h>
#include <smbsrv/smb2.h>
#include <sys/crypto/api.h>
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_kcrypt.h>
int
smb3_sha512_getmech(smb_crypto_mech_t *mech)
{
crypto_mech_type_t t;
t = crypto_mech2id(SUN_CKM_SHA512);
if (t == CRYPTO_MECH_INVALID) {
cmn_err(CE_NOTE, "smb: no kcf mech: %s", SUN_CKM_SHA512);
return (-1);
}
mech->cm_type = t;
return (0);
}
void
smb31_preauth_init_mech(smb_session_t *s)
{
smb_crypto_mech_t *mech;
int rc;
ASSERT3S(s->dialect, >=, SMB_VERS_3_11);
if (s->preauth_mech != NULL)
return;
mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
rc = smb3_sha512_getmech(mech);
if (rc != 0) {
kmem_free(mech, sizeof (*mech));
return;
}
s->preauth_mech = mech;
}
void
smb31_preauth_fini(smb_session_t *s)
{
smb_crypto_mech_t *mech;
if ((mech = s->preauth_mech) != NULL) {
kmem_free(mech, sizeof (*mech));
s->preauth_mech = NULL;
}
}
int
smb_sha512_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_sha512_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_sha512_final(smb_sign_ctx_t ctx, uint8_t *digest)
{
crypto_data_t out;
int rv;
bzero(&out, sizeof (out));
out.cd_format = CRYPTO_DATA_RAW;
out.cd_length = SHA512_DIGEST_LENGTH;
out.cd_raw.iov_len = SHA512_DIGEST_LENGTH;
out.cd_raw.iov_base = (void *)digest;
rv = crypto_digest_final(ctx, &out, 0);
return (rv == CRYPTO_SUCCESS ? 0 : -1);
}
int
smb31_preauth_sha512_calc(smb_request_t *sr, struct mbuf_chain *mbc,
uint8_t *in_hashval, uint8_t *out_hashval)
{
smb_session_t *s = sr->session;
smb_sign_ctx_t ctx = 0;
struct mbuf *mbuf = mbc->chain;
int rc;
ASSERT3U(s->smb31_preauth_hashid, !=, 0);
if (s->preauth_mech == NULL)
return (-1);
if ((rc = smb_sha512_init(&ctx, s->preauth_mech)) != 0)
return (rc);
rc = smb_sha512_update(ctx, in_hashval, SHA512_DIGEST_LENGTH);
if (rc != 0)
return (rc);
while (mbuf != NULL) {
rc = smb_sha512_update(ctx, mbuf->m_data, mbuf->m_len);
if (rc != 0)
return (rc);
mbuf = mbuf->m_next;
}
rc = smb_sha512_final(ctx, out_hashval);
return (rc);
}