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