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 2017 Nexenta Systems, Inc. All rights reserved. 14 * Copyright 2022-2024 RackTop Systems, Inc. 15 */ 16 17 /* 18 * Helper functions for SMB signing using PKCS#11 19 * 20 * There are two implementations of these functions: 21 * This one (for user space) and another for kernel. 22 * See: uts/common/fs/smbclnt/netsmb/smb_sign_kcf.c 23 * 24 * Contrary to what one might assume from the file name, 25 * there should be NO SMB implementation knowledge here 26 * beyond a few carefully selected things (nsmb_kcrypt.h). 27 */ 28 29 #include <security/cryptoki.h> 30 #include <security/pkcs11.h> 31 #include <netsmb/nsmb_kcrypt.h> 32 33 #include <stdlib.h> 34 #include <strings.h> 35 #include <sys/cmn_err.h> 36 37 /* 38 * Common function to see if a mech is available. 39 */ 40 static int 41 find_mech(smb_crypto_mech_t *mech, ulong_t mid) 42 { 43 CK_SESSION_HANDLE hdl; 44 CK_RV rv; 45 46 rv = SUNW_C_GetMechSession(mid, &hdl); 47 if (rv != CKR_OK) { 48 cmn_err(CE_NOTE, "PKCS#11: no mech 0x%x", 49 (unsigned int)mid); 50 return (-1); 51 } 52 (void) C_CloseSession(hdl); 53 54 mech->mechanism = mid; 55 mech->pParameter = NULL; 56 mech->ulParameterLen = 0; 57 return (0); 58 } 59 60 /* 61 * SMB1 signing helpers: 62 * (getmech, init, update, final) 63 */ 64 65 /* 66 * Find out if we have this mech. 67 */ 68 int 69 nsmb_md5_getmech(smb_crypto_mech_t *mech) 70 { 71 return (find_mech(mech, CKM_MD5)); 72 } 73 74 /* 75 * Start PKCS#11 session. 76 */ 77 int 78 nsmb_md5_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech) 79 { 80 CK_RV rv; 81 82 rv = SUNW_C_GetMechSession(mech->mechanism, ctxp); 83 if (rv != CKR_OK) 84 return (-1); 85 86 rv = C_DigestInit(*ctxp, mech); 87 88 return (rv == CKR_OK ? 0 : -1); 89 } 90 91 /* 92 * Digest one segment 93 */ 94 int 95 nsmb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len) 96 { 97 CK_RV rv; 98 99 rv = C_DigestUpdate(ctx, buf, len); 100 if (rv != CKR_OK) 101 (void) C_CloseSession(ctx); 102 103 return (rv == CKR_OK ? 0 : -1); 104 } 105 106 /* 107 * Get the final digest. 108 */ 109 int 110 nsmb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16) 111 { 112 CK_ULONG len = MD5_DIGEST_LENGTH; 113 CK_RV rv; 114 115 rv = C_DigestFinal(ctx, digest16, &len); 116 (void) C_CloseSession(ctx); 117 118 return (rv == CKR_OK ? 0 : -1); 119 } 120 121 /* 122 * SMB2 signing helpers: 123 * (getmech, init, update, final) 124 */ 125 126 /* 127 * Find out if we have this mech. 128 */ 129 int 130 nsmb_hmac_getmech(smb_crypto_mech_t *mech) 131 { 132 return (find_mech(mech, CKM_SHA256_HMAC)); 133 } 134 135 /* 136 * Start PKCS#11 session, load the key. 137 */ 138 int 139 nsmb_hmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech, 140 uint8_t *key, size_t key_len) 141 { 142 CK_OBJECT_HANDLE hkey = 0; 143 CK_RV rv; 144 145 rv = SUNW_C_GetMechSession(mech->mechanism, ctxp); 146 if (rv != CKR_OK) 147 return (-1); 148 149 rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism, 150 key, key_len, &hkey); 151 if (rv != CKR_OK) 152 return (-1); 153 154 rv = C_SignInit(*ctxp, mech, hkey); 155 (void) C_DestroyObject(*ctxp, hkey); 156 157 return (rv == CKR_OK ? 0 : -1); 158 } 159 160 /* 161 * Digest one segment 162 */ 163 int 164 nsmb_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len) 165 { 166 CK_RV rv; 167 168 rv = C_SignUpdate(ctx, in, len); 169 if (rv != CKR_OK) 170 (void) C_CloseSession(ctx); 171 172 return (rv == CKR_OK ? 0 : -1); 173 } 174 175 /* 176 * Note, the SMB2 signature is the first 16 bytes of the 177 * 32-byte SHA256 HMAC digest. This is specifically for 178 * SMB2 signing, and NOT a generic HMAC function. 179 */ 180 int 181 nsmb_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16) 182 { 183 uint8_t full_digest[SHA256_DIGEST_LENGTH]; 184 CK_ULONG len = SHA256_DIGEST_LENGTH; 185 CK_RV rv; 186 187 rv = C_SignFinal(ctx, full_digest, &len); 188 if (rv == CKR_OK) 189 bcopy(full_digest, digest16, 16); 190 191 (void) C_CloseSession(ctx); 192 193 return (rv == CKR_OK ? 0 : -1); 194 } 195 196 /* 197 * One-shot HMAC function used in smb3_kdf 198 */ 199 int 200 nsmb_hmac_one(smb_crypto_mech_t *mech, 201 uint8_t *key, size_t key_len, 202 uint8_t *data, size_t data_len, 203 uint8_t *mac, size_t mac_len) 204 { 205 CK_SESSION_HANDLE hssn = 0; 206 CK_OBJECT_HANDLE hkey = 0; 207 CK_ULONG ck_maclen = mac_len; 208 CK_RV rv; 209 int rc = 0; 210 211 rv = SUNW_C_GetMechSession(mech->mechanism, &hssn); 212 if (rv != CKR_OK) 213 return (-1); 214 215 rv = SUNW_C_KeyToObject(hssn, mech->mechanism, 216 key, key_len, &hkey); 217 if (rv != CKR_OK) { 218 rc = -2; 219 goto out; 220 } 221 222 rv = C_SignInit(hssn, mech, hkey); 223 if (rv != CKR_OK) { 224 rc = -3; 225 goto out; 226 } 227 228 rv = C_Sign(hssn, data, data_len, mac, &ck_maclen); 229 if (rv != CKR_OK) { 230 rc = -4; 231 goto out; 232 } 233 234 if (ck_maclen != mac_len) { 235 rc = -5; 236 goto out; 237 } 238 rc = 0; 239 240 out: 241 if (hkey != 0) 242 (void) C_DestroyObject(hssn, hkey); 243 if (hssn != 0) 244 (void) C_CloseSession(hssn); 245 246 return (rc); 247 } 248 249 /* 250 * SMB3 signing helpers: 251 * (getmech, init, update, final) 252 */ 253 254 /* 255 * Find out if we have this mech. 256 */ 257 int 258 nsmb_cmac_getmech(smb_crypto_mech_t *mech) 259 { 260 return (find_mech(mech, CKM_AES_CMAC)); 261 } 262 263 /* 264 * Start PKCS#11 session, load the key. 265 */ 266 int 267 nsmb_cmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech, 268 uint8_t *key, size_t key_len) 269 { 270 CK_OBJECT_HANDLE hkey = 0; 271 CK_RV rv; 272 273 rv = SUNW_C_GetMechSession(mech->mechanism, ctxp); 274 if (rv != CKR_OK) 275 return (-1); 276 277 rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism, 278 key, key_len, &hkey); 279 if (rv != CKR_OK) { 280 (void) C_CloseSession(*ctxp); 281 return (-1); 282 } 283 284 rv = C_SignInit(*ctxp, mech, hkey); 285 (void) C_DestroyObject(*ctxp, hkey); 286 if (rv != CKR_OK) { 287 (void) C_CloseSession(*ctxp); 288 return (-1); 289 } 290 291 return (0); 292 } 293 294 /* 295 * Digest one segment 296 */ 297 int 298 nsmb_cmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len) 299 { 300 CK_RV rv; 301 302 rv = C_SignUpdate(ctx, in, len); 303 if (rv != CKR_OK) 304 (void) C_CloseSession(ctx); 305 306 return (rv == CKR_OK ? 0 : -1); 307 } 308 309 /* 310 * Note, the SMB2 signature is just the AES CMAC digest. 311 * (both are 16 bytes long) 312 */ 313 int 314 nsmb_cmac_final(smb_sign_ctx_t ctx, uint8_t *digest) 315 { 316 CK_ULONG len = SMB2_SIG_SIZE; 317 CK_RV rv; 318 319 rv = C_SignFinal(ctx, digest, &len); 320 (void) C_CloseSession(ctx); 321 322 return (rv == CKR_OK ? 0 : -1); 323 } 324