1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Helper functions for SMB3 encryption using the
  18  * Kernel Cryptographic Framework (KCF)
  19  *
  20  * There are two implementations of these functions:
  21  * This one (for kernel) and another for user space:
  22  * See: lib/smbsrv/libfksmbsrv/common/fksmb_encrypt_pkcs.c
  23  */
  24 
  25 #include <sys/crypto/api.h>
  26 #include <smbsrv/smb_kcrypt.h>
  27 #include <smbsrv/smb2_kproto.h>
  28 #include <sys/cmn_err.h>
  29 
  30 /*
  31  * SMB3 encryption helpers:
  32  * (getmech, init, update, final)
  33  */
  34 
  35 int
  36 smb3_encrypt_getmech(smb_crypto_mech_t *mech)
  37 {
  38         crypto_mech_type_t t;
  39 
  40         t = crypto_mech2id(SUN_CKM_AES_CCM);
  41         if (t == CRYPTO_MECH_INVALID) {
  42                 cmn_err(CE_NOTE, "smb: no kcf mech: %s", SUN_CKM_AES_CCM);
  43                 return (-1);
  44         }
  45         mech->cm_type = t;
  46 
  47         return (0);
  48 }
  49 
  50 void
  51 smb3_crypto_init_param(smb3_crypto_param_t *param,
  52     uint8_t *nonce, size_t noncesize, uint8_t *auth, size_t authsize,
  53     size_t datasize)
  54 {
  55         param->ulMACSize = SMB2_SIG_SIZE;
  56         param->ulNonceSize = noncesize;
  57         param->nonce = nonce;
  58         param->ulDataSize = datasize;
  59         param->ulAuthDataSize = authsize;
  60         param->authData = auth;
  61 }
  62 
  63 /*
  64  * Start the KCF session, load the key
  65  */
  66 static int
  67 smb3_crypto_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
  68     uint8_t *key, size_t key_len, smb3_crypto_param_t *param,
  69     boolean_t is_encrypt)
  70 {
  71         crypto_key_t ckey;
  72         int rv;
  73 
  74         bzero(&ckey, sizeof (ckey));
  75         ckey.ck_format = CRYPTO_KEY_RAW;
  76         ckey.ck_data = key;
  77         ckey.ck_length = key_len * 8; /* in bits */
  78 
  79         mech->cm_param = (caddr_t)param;
  80         mech->cm_param_len = sizeof (*param);
  81 
  82         if (is_encrypt)
  83                 rv = crypto_encrypt_init(mech, &ckey, NULL, &ctxp->ctx, NULL);
  84         else
  85                 rv = crypto_decrypt_init(mech, &ckey, NULL, &ctxp->ctx, NULL);
  86 
  87         if (rv != CRYPTO_SUCCESS) {
  88                 if (is_encrypt)
  89                         cmn_err(CE_WARN,
  90                             "crypto_encrypt_init failed: 0x%x", rv);
  91                 else
  92                         cmn_err(CE_WARN,
  93                             "crypto_decrypt_init failed: 0x%x", rv);
  94         }
  95 
  96         return (rv == CRYPTO_SUCCESS ? 0 : -1);
  97 }
  98 
  99 int
 100 smb3_encrypt_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
 101     smb3_crypto_param_t *param, uint8_t *key, size_t keylen,
 102     uint8_t *buf, size_t buflen)
 103 {
 104 
 105         bzero(&ctxp->output, sizeof (ctxp->output));
 106         ctxp->output.cd_format = CRYPTO_DATA_RAW;
 107         ctxp->output.cd_length = buflen;
 108         ctxp->output.cd_raw.iov_len = buflen;
 109         ctxp->output.cd_raw.iov_base = (void *)buf;
 110 
 111         return (smb3_crypto_init(ctxp, mech, key, keylen,
 112             param, B_TRUE));
 113 }
 114 
 115 int
 116 smb3_decrypt_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
 117     smb3_crypto_param_t *param, uint8_t *key, size_t keylen)
 118 {
 119         return (smb3_crypto_init(ctxp, mech, key, keylen,
 120             param, B_FALSE));
 121 }
 122 
 123 /*
 124  * Digest one segment
 125  */
 126 int
 127 smb3_encrypt_update(smb3_enc_ctx_t *ctxp, uint8_t *in, size_t len)
 128 {
 129         crypto_data_t data;
 130         int rv;
 131 
 132         bzero(&data, sizeof (data));
 133         data.cd_format = CRYPTO_DATA_RAW;
 134         data.cd_length = len;
 135         data.cd_raw.iov_base = (void *)in;
 136         data.cd_raw.iov_len = len;
 137 
 138         rv = crypto_encrypt_update(ctxp->ctx, &data, &ctxp->output, NULL);
 139 
 140         if (rv != CRYPTO_SUCCESS) {
 141                 cmn_err(CE_WARN, "crypto_encrypt_update failed: 0x%x", rv);
 142                 crypto_cancel_ctx(ctxp->ctx);
 143                 return (-1);
 144         }
 145 
 146         len = ctxp->output.cd_length;
 147         ctxp->len -= len;
 148         ctxp->output.cd_offset += len;
 149         ctxp->output.cd_length = ctxp->len;
 150 
 151         return (0);
 152 }
 153 
 154 int
 155 smb3_decrypt_update(smb3_enc_ctx_t *ctxp, uint8_t *in, size_t len)
 156 {
 157         crypto_data_t data;
 158         int rv;
 159 
 160         bzero(&data, sizeof (data));
 161         data.cd_format = CRYPTO_DATA_RAW;
 162         data.cd_length = len;
 163         data.cd_raw.iov_base = (void *)in;
 164         data.cd_raw.iov_len = len;
 165 
 166         /*
 167          * AES_CCM does not output data until decrypt_final,
 168          * and only does so if the signature matches.
 169          */
 170         rv = crypto_decrypt_update(ctxp->ctx, &data, NULL, NULL);
 171 
 172         if (rv != CRYPTO_SUCCESS) {
 173                 cmn_err(CE_WARN, "crypto_decrypt_update failed: 0x%x", rv);
 174                 crypto_cancel_ctx(ctxp->ctx);
 175                 return (-1);
 176         }
 177 
 178         return (0);
 179 }
 180 
 181 int
 182 smb3_encrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *digest16)
 183 {
 184         crypto_data_t out;
 185         int rv;
 186         uint8_t buf[SMB2_SIG_SIZE + 16] = {0};
 187         size_t outlen;
 188 
 189         bzero(&out, sizeof (out));
 190         out.cd_format = CRYPTO_DATA_RAW;
 191         out.cd_length = sizeof (buf);
 192         out.cd_raw.iov_len = sizeof (buf);
 193         out.cd_raw.iov_base = (void *)buf;
 194 
 195         rv = crypto_encrypt_final(ctxp->ctx, &out, 0);
 196 
 197         if (rv != CRYPTO_SUCCESS) {
 198                 cmn_err(CE_WARN, "crypto_encrypt_final failed: 0x%x", rv);
 199                 return (-1);
 200         }
 201 
 202         outlen = out.cd_offset - SMB2_SIG_SIZE;
 203         if (outlen > 0)
 204                 bcopy(buf, ctxp->output.cd_raw.iov_base +
 205                     ctxp->output.cd_offset, outlen);
 206         bcopy(buf + outlen, digest16, SMB2_SIG_SIZE);
 207 
 208         return (0);
 209 }
 210 
 211 int
 212 smb3_decrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *buf, size_t buflen)
 213 {
 214         crypto_data_t out;
 215         int rv;
 216 
 217         bzero(&out, sizeof (out));
 218         out.cd_format = CRYPTO_DATA_RAW;
 219         out.cd_length = buflen;
 220         out.cd_raw.iov_len = buflen;
 221         out.cd_raw.iov_base = (void *)buf;
 222 
 223         rv = crypto_decrypt_final(ctxp->ctx, &out, NULL);
 224 
 225         if (rv != CRYPTO_SUCCESS)
 226                 cmn_err(CE_WARN, "crypto_decrypt_final failed: 0x%x", rv);
 227 
 228         return (rv == CRYPTO_SUCCESS ? 0 : -1);
 229 }
 230 
 231 void
 232 smb3_encrypt_cancel(smb3_enc_ctx_t *ctxp)
 233 {
 234         crypto_cancel_ctx(ctxp->ctx);
 235 }