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-2021 Tintri by DDN, Inc. All rights reserved. 14 * Copyright 2022 RackTop Systems, Inc. 15 */ 16 17 /* 18 * Helper functions for SMB3 encryption using the 19 * Kernel Cryptographic Framework (KCF) 20 * 21 * There are two implementations of these functions: 22 * This one (for kernel) and another for user space: 23 * See: lib/smbsrv/libfksmbsrv/common/fksmb_encrypt_pkcs.c 24 * 25 * Contrary to what one might assume from the file name, 26 * there should be NO SMB implementation knowledge here 27 * beyond a few carefully selected things (smb_kcrypt.h). 28 */ 29 30 #include <sys/crypto/api.h> 31 #include <smbsrv/smb_kcrypt.h> 32 #include <sys/systm.h> 33 #include <sys/cmn_err.h> 34 35 /* 36 * Common function to see if a mech is available. 37 */ 38 static int 39 find_mech(smb_crypto_mech_t *mech, const char *name) 40 { 41 crypto_mech_type_t t; 42 43 t = crypto_mech2id(name); 44 if (t == CRYPTO_MECH_INVALID) { 45 cmn_err(CE_NOTE, "smb: no kcf mech: %s", name); 46 return (-1); 47 } 48 mech->cm_type = t; 49 return (0); 50 } 51 52 /* 53 * SMB3 encryption helpers: 54 * (getmech, init, update, final) 55 */ 56 57 int 58 smb3_aes_ccm_getmech(smb_crypto_mech_t *mech) 59 { 60 return (find_mech(mech, SUN_CKM_AES_CCM)); 61 } 62 63 int 64 smb3_aes_gcm_getmech(smb_crypto_mech_t *mech) 65 { 66 return (find_mech(mech, SUN_CKM_AES_GCM)); 67 } 68 69 void 70 smb3_crypto_init_ccm_param(smb_enc_ctx_t *ctx, 71 uint8_t *nonce, size_t noncesize, 72 uint8_t *auth, size_t authsize, 73 size_t datasize) 74 { 75 76 ASSERT3U(noncesize, >=, SMB3_AES_CCM_NONCE_SIZE); 77 78 ctx->param.ccm.ulMACSize = SMB2_SIG_SIZE; 79 ctx->param.ccm.ulNonceSize = SMB3_AES_CCM_NONCE_SIZE; 80 ctx->param.ccm.nonce = nonce; 81 ctx->param.ccm.ulDataSize = datasize; 82 ctx->param.ccm.ulAuthDataSize = authsize; 83 ctx->param.ccm.authData = auth; 84 85 ctx->mech.cm_param = (caddr_t)&ctx->param.ccm; 86 ctx->mech.cm_param_len = sizeof (ctx->param.ccm); 87 } 88 89 void 90 smb3_crypto_init_gcm_param(smb_enc_ctx_t *ctx, 91 uint8_t *nonce, size_t noncesize, 92 uint8_t *auth, size_t authsize) 93 { 94 95 ASSERT3U(noncesize, >=, SMB3_AES_GCM_NONCE_SIZE); 96 97 ctx->param.gcm.pIv = nonce; 98 ctx->param.gcm.ulIvLen = SMB3_AES_GCM_NONCE_SIZE; 99 ctx->param.gcm.ulTagBits = SMB2_SIG_SIZE << 3; /* bytes to bits */ 100 ctx->param.gcm.pAAD = auth; /* auth data */ 101 ctx->param.gcm.ulAADLen = authsize; /* auth data len */ 102 103 ctx->mech.cm_param = (caddr_t)&ctx->param.gcm; 104 ctx->mech.cm_param_len = sizeof (ctx->param.gcm); 105 } 106 107 /* 108 * KCF doesn't need anything to happen in this call, but 109 * wants that key when we call encrypt or decrypt, so 110 * just stash the key here. 111 * 112 * Todo: clone crypto context template here? 113 */ 114 int 115 smb3_encrypt_init(smb_enc_ctx_t *ctxp, 116 uint8_t *key, size_t keylen) 117 { 118 119 bzero(&ctxp->ckey, sizeof (ctxp->ckey)); 120 ctxp->ckey.ck_format = CRYPTO_KEY_RAW; 121 ctxp->ckey.ck_data = key; 122 ctxp->ckey.ck_length = keylen * 8; /* in bits */ 123 124 return (0); 125 } 126 127 int 128 smb3_decrypt_init(smb_enc_ctx_t *ctxp, 129 uint8_t *key, size_t keylen) 130 { 131 132 bzero(&ctxp->ckey, sizeof (ctxp->ckey)); 133 ctxp->ckey.ck_format = CRYPTO_KEY_RAW; 134 ctxp->ckey.ck_data = key; 135 ctxp->ckey.ck_length = keylen * 8; /* in bits */ 136 137 return (0); 138 } 139 140 /* 141 * Encrypt a whole message with scatter/gather (UIO) 142 */ 143 int 144 smb3_encrypt_uio(smb_enc_ctx_t *ctxp, uio_t *in_uio, uio_t *out_uio) 145 { 146 crypto_ctx_template_t tmpl = NULL; // todo 147 crypto_data_t in_cd, out_cd; 148 int rv; 149 150 bzero(&in_cd, sizeof (crypto_data_t)); 151 in_cd.cd_format = CRYPTO_DATA_UIO; 152 in_cd.cd_length = in_uio->uio_resid; 153 in_cd.cd_uio = in_uio; 154 155 bzero(&out_cd, sizeof (crypto_data_t)); 156 out_cd.cd_format = CRYPTO_DATA_UIO; 157 out_cd.cd_length = out_uio->uio_resid; 158 out_cd.cd_uio = out_uio; 159 160 rv = crypto_encrypt(&ctxp->mech, &in_cd, 161 &ctxp->ckey, tmpl, &out_cd, NULL); 162 if (rv != CRYPTO_SUCCESS) { 163 cmn_err(CE_WARN, "crypto_encrypt failed: 0x%x", rv); 164 return (-1); 165 } 166 167 return (0); 168 } 169 170 /* 171 * Decrypt a whole message with scatter/gather (UIO) 172 */ 173 int 174 smb3_decrypt_uio(smb_enc_ctx_t *ctxp, uio_t *in_uio, uio_t *out_uio) 175 { 176 crypto_ctx_template_t tmpl = NULL; // todo 177 crypto_data_t in_cd, out_cd; 178 int rv; 179 180 /* In is ciphertext */ 181 bzero(&in_cd, sizeof (crypto_data_t)); 182 in_cd.cd_format = CRYPTO_DATA_UIO; 183 in_cd.cd_length = in_uio->uio_resid; 184 in_cd.cd_uio = in_uio; 185 186 /* Out is plaintext */ 187 bzero(&out_cd, sizeof (crypto_data_t)); 188 out_cd.cd_format = CRYPTO_DATA_UIO; 189 out_cd.cd_length = out_uio->uio_resid; 190 out_cd.cd_uio = out_uio; 191 192 rv = crypto_decrypt(&ctxp->mech, &in_cd, 193 &ctxp->ckey, tmpl, &out_cd, NULL); 194 if (rv != CRYPTO_SUCCESS) { 195 cmn_err(CE_WARN, "crypto_decrypt failed: 0x%x", rv); 196 return (-1); 197 } 198 199 return (0); 200 } 201 202 void 203 smb3_enc_ctx_done(smb_enc_ctx_t *ctxp) 204 { 205 crypto_cancel_ctx(ctxp->ctx); 206 } 207