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 */ 15 16 /* 17 * Helper functions for SMB signing using PKCS#11 18 * 19 * There are two implementations of these functions: 20 * This one (for user space) and another for kernel. 21 * See: uts/common/fs/smbclnt/netsmb/smb_sign_kcf.c 22 */ 23 24 #include <stdlib.h> 25 #include <strings.h> 26 #include <sys/cmn_err.h> 27 #include <netsmb/smb_signing.h> 28 #include <security/cryptoki.h> 29 #include <security/pkcs11.h> 30 31 /* 32 * Common function to see if a mech is available. 33 */ 34 static int 35 find_mech(smb_sign_mech_t *mech, ulong_t mid) 36 { 37 CK_SESSION_HANDLE hdl; 38 CK_RV rv; 39 40 rv = SUNW_C_GetMechSession(mid, &hdl); 41 if (rv != CKR_OK) { 42 cmn_err(CE_NOTE, "PKCS#11: no mech 0x%x", 43 (unsigned int)mid); 44 return (-1); 45 } 46 (void) C_CloseSession(hdl); 47 48 mech->mechanism = mid; 49 mech->pParameter = NULL; 50 mech->ulParameterLen = 0; 51 return (0); 52 } 53 54 /* 55 * SMB1 signing helpers: 56 * (getmech, init, update, final) 57 */ 58 59 /* 60 * Find out if we have this mech. 61 */ 62 int 63 smb_md5_getmech(smb_sign_mech_t *mech) 64 { 65 return (find_mech(mech, CKM_MD5)); 66 } 67 68 /* 69 * Start PKCS#11 session. 70 */ 71 int 72 smb_md5_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech) 73 { 74 CK_RV rv; 75 76 rv = SUNW_C_GetMechSession(mech->mechanism, ctxp); 77 if (rv != CKR_OK) 78 return (-1); 79 80 rv = C_DigestInit(*ctxp, mech); 81 82 return (rv == CKR_OK ? 0 : -1); 83 } 84 85 /* 86 * Digest one segment 87 */ 88 int 89 smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len) 90 { 91 CK_RV rv; 92 93 rv = C_DigestUpdate(ctx, buf, len); 94 if (rv != CKR_OK) 95 (void) C_CloseSession(ctx); 96 97 return (rv == CKR_OK ? 0 : -1); 98 } 99 100 /* 101 * Get the final digest. 102 */ 103 int 104 smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16) 105 { 106 CK_ULONG len = MD5_DIGEST_LENGTH; 107 CK_RV rv; 108 109 rv = C_DigestFinal(ctx, digest16, &len); 110 (void) C_CloseSession(ctx); 111 112 return (rv == CKR_OK ? 0 : -1); 113 } 114 115 /* 116 * SMB2 signing helpers: 117 * (getmech, init, update, final) 118 */ 119 120 /* 121 * Find out if we have this mech. 122 */ 123 int 124 smb2_hmac_getmech(smb_sign_mech_t *mech) 125 { 126 return (find_mech(mech, CKM_SHA256_HMAC)); 127 } 128 129 /* 130 * Start PKCS#11 session, load the key. 131 */ 132 int 133 smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech, 134 uint8_t *key, size_t key_len) 135 { 136 CK_OBJECT_HANDLE hkey = 0; 137 CK_RV rv; 138 139 rv = SUNW_C_GetMechSession(mech->mechanism, ctxp); 140 if (rv != CKR_OK) 141 return (-1); 142 143 rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism, 144 key, key_len, &hkey); 145 if (rv != CKR_OK) 146 return (-1); 147 148 rv = C_SignInit(*ctxp, mech, hkey); 149 (void) C_DestroyObject(*ctxp, hkey); 150 151 return (rv == CKR_OK ? 0 : -1); 152 } 153 154 /* 155 * Digest one segment 156 */ 157 int 158 smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len) 159 { 160 CK_RV rv; 161 162 rv = C_SignUpdate(ctx, in, len); 163 if (rv != CKR_OK) 164 (void) C_CloseSession(ctx); 165 166 return (rv == CKR_OK ? 0 : -1); 167 } 168 169 /* 170 * Note, the SMB2 signature is the first 16 bytes of the 171 * 32-byte SHA256 HMAC digest. 172 */ 173 int 174 smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16) 175 { 176 uint8_t full_digest[SHA256_DIGEST_LENGTH]; 177 CK_ULONG len = SHA256_DIGEST_LENGTH; 178 CK_RV rv; 179 180 rv = C_SignFinal(ctx, full_digest, &len); 181 if (rv == CKR_OK) 182 bcopy(full_digest, digest16, 16); 183 184 (void) C_CloseSession(ctx); 185 186 return (rv == CKR_OK ? 0 : -1); 187 } 188 189 /* 190 * SMB3 signing helpers: 191 * (getmech, init, update, final) 192 */ 193 194 /* 195 * Find out if we have this mech. 196 */ 197 int 198 smb3_cmac_getmech(smb_sign_mech_t *mech) 199 { 200 return (find_mech(mech, CKM_AES_CMAC)); 201 } 202 203 /* 204 * Start PKCS#11 session, load the key. 205 */ 206 int 207 smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech, 208 uint8_t *key, size_t key_len) 209 { 210 CK_OBJECT_HANDLE hkey = 0; 211 CK_RV rv; 212 213 rv = SUNW_C_GetMechSession(mech->mechanism, ctxp); 214 if (rv != CKR_OK) 215 return (-1); 216 217 rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism, 218 key, key_len, &hkey); 219 if (rv != CKR_OK) { 220 (void) C_CloseSession(*ctxp); 221 return (-1); 222 } 223 224 rv = C_SignInit(*ctxp, mech, hkey); 225 (void) C_DestroyObject(*ctxp, hkey); 226 if (rv != CKR_OK) { 227 (void) C_CloseSession(*ctxp); 228 return (-1); 229 } 230 231 return (0); 232 } 233 234 /* 235 * Digest one segment 236 */ 237 int 238 smb3_cmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len) 239 { 240 CK_RV rv; 241 242 rv = C_SignUpdate(ctx, in, len); 243 if (rv != CKR_OK) 244 (void) C_CloseSession(ctx); 245 246 return (rv == CKR_OK ? 0 : -1); 247 } 248 249 /* 250 * Note, the SMB2 signature is just the AES CMAC digest. 251 * (both are 16 bytes long) 252 */ 253 int 254 smb3_cmac_final(smb_sign_ctx_t ctx, uint8_t *digest) 255 { 256 CK_ULONG len = SMB2_SIG_SIZE; 257 CK_RV rv; 258 259 rv = C_SignFinal(ctx, digest, &len); 260 (void) C_CloseSession(ctx); 261 262 return (rv == CKR_OK ? 0 : -1); 263 } 264