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 } 236