1b819cea2SGordon Ross /*
2b819cea2SGordon Ross  * This file and its contents are supplied under the terms of the
3b819cea2SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
4b819cea2SGordon Ross  * You may only use this file in accordance with the terms of version
5b819cea2SGordon Ross  * 1.0 of the CDDL.
6b819cea2SGordon Ross  *
7b819cea2SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
8b819cea2SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
9b819cea2SGordon Ross  * http://www.illumos.org/license/CDDL.
10b819cea2SGordon Ross  */
11b819cea2SGordon Ross 
12b819cea2SGordon Ross /*
13c51c88bdSMatt Barden  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
14*a4568e19SAlexander Stetsenko  * Copyright 2022 RackTop Systems, Inc.
15b819cea2SGordon Ross  */
16b819cea2SGordon Ross 
17b819cea2SGordon Ross /*
18a90cf9f2SGordon Ross  * Helper functions for SMB signing using PKCS#11
19b819cea2SGordon Ross  *
20b819cea2SGordon Ross  * There are two implementations of these functions:
21b819cea2SGordon Ross  * This one (for user space) and another for kernel.
22b819cea2SGordon Ross  * See: uts/common/fs/smbsrv/smb_sign_kcf.c
23b819cea2SGordon Ross  */
24b819cea2SGordon Ross 
25b819cea2SGordon Ross #include <stdlib.h>
26b819cea2SGordon Ross #include <smbsrv/smb_kproto.h>
271160dcf7SMatt Barden #include <smbsrv/smb_kcrypt.h>
28b819cea2SGordon Ross #include <security/cryptoki.h>
29b819cea2SGordon Ross #include <security/pkcs11.h>
30b819cea2SGordon Ross 
31c51c88bdSMatt Barden /*
32c51c88bdSMatt Barden  * Common function to see if a mech is available.
33c51c88bdSMatt Barden  */
34c51c88bdSMatt Barden static int
find_mech(smb_crypto_mech_t * mech,ulong_t mid)351160dcf7SMatt Barden find_mech(smb_crypto_mech_t *mech, ulong_t mid)
36c51c88bdSMatt Barden {
37c51c88bdSMatt Barden 	CK_SESSION_HANDLE hdl;
38c51c88bdSMatt Barden 	CK_RV rv;
39c51c88bdSMatt Barden 
40c51c88bdSMatt Barden 	rv = SUNW_C_GetMechSession(mid, &hdl);
41c51c88bdSMatt Barden 	if (rv != CKR_OK) {
42c51c88bdSMatt Barden 		cmn_err(CE_NOTE, "PKCS#11: no mech 0x%x",
43c51c88bdSMatt Barden 		    (unsigned int)mid);
44c51c88bdSMatt Barden 		return (-1);
45c51c88bdSMatt Barden 	}
46c51c88bdSMatt Barden 	(void) C_CloseSession(hdl);
47c51c88bdSMatt Barden 
48c51c88bdSMatt Barden 	mech->mechanism = mid;
49c51c88bdSMatt Barden 	mech->pParameter = NULL;
50c51c88bdSMatt Barden 	mech->ulParameterLen = 0;
51c51c88bdSMatt Barden 	return (0);
52c51c88bdSMatt Barden }
53c51c88bdSMatt Barden 
54b819cea2SGordon Ross /*
55b819cea2SGordon Ross  * SMB1 signing helpers:
56b819cea2SGordon Ross  * (getmech, init, update, final)
57b819cea2SGordon Ross  */
58b819cea2SGordon Ross 
59c51c88bdSMatt Barden /*
60c51c88bdSMatt Barden  * Find out if we have this mech.
61c51c88bdSMatt Barden  */
62b819cea2SGordon Ross int
smb_md5_getmech(smb_crypto_mech_t * mech)631160dcf7SMatt Barden smb_md5_getmech(smb_crypto_mech_t *mech)
64b819cea2SGordon Ross {
65c51c88bdSMatt Barden 	return (find_mech(mech, CKM_MD5));
66b819cea2SGordon Ross }
67b819cea2SGordon Ross 
68b819cea2SGordon Ross /*
69b819cea2SGordon Ross  * Start PKCS#11 session.
70b819cea2SGordon Ross  */
71b819cea2SGordon Ross int
smb_md5_init(smb_sign_ctx_t * ctxp,smb_crypto_mech_t * mech)721160dcf7SMatt Barden smb_md5_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech)
73b819cea2SGordon Ross {
74b819cea2SGordon Ross 	CK_RV rv;
75b819cea2SGordon Ross 
76b819cea2SGordon Ross 	rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
77b819cea2SGordon Ross 	if (rv != CKR_OK)
78b819cea2SGordon Ross 		return (-1);
79b819cea2SGordon Ross 
80b819cea2SGordon Ross 	rv = C_DigestInit(*ctxp, mech);
81b819cea2SGordon Ross 
82b819cea2SGordon Ross 	return (rv == CKR_OK ? 0 : -1);
83b819cea2SGordon Ross }
84b819cea2SGordon Ross 
85b819cea2SGordon Ross /*
86b819cea2SGordon Ross  * Digest one segment
87b819cea2SGordon Ross  */
88b819cea2SGordon Ross int
smb_md5_update(smb_sign_ctx_t ctx,void * buf,size_t len)89b819cea2SGordon Ross smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
90b819cea2SGordon Ross {
91b819cea2SGordon Ross 	CK_RV rv;
92b819cea2SGordon Ross 
93b819cea2SGordon Ross 	rv = C_DigestUpdate(ctx, buf, len);
94b819cea2SGordon Ross 	if (rv != CKR_OK)
95b819cea2SGordon Ross 		(void) C_CloseSession(ctx);
96b819cea2SGordon Ross 
97b819cea2SGordon Ross 	return (rv == CKR_OK ? 0 : -1);
98b819cea2SGordon Ross }
99b819cea2SGordon Ross 
100b819cea2SGordon Ross /*
101b819cea2SGordon Ross  * Get the final digest.
102b819cea2SGordon Ross  */
103b819cea2SGordon Ross int
smb_md5_final(smb_sign_ctx_t ctx,uint8_t * digest16)104b819cea2SGordon Ross smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
105b819cea2SGordon Ross {
106b819cea2SGordon Ross 	CK_ULONG len = MD5_DIGEST_LENGTH;
107b819cea2SGordon Ross 	CK_RV rv;
108b819cea2SGordon Ross 
109b819cea2SGordon Ross 	rv = C_DigestFinal(ctx, digest16, &len);
110b819cea2SGordon Ross 	(void) C_CloseSession(ctx);
111b819cea2SGordon Ross 
112b819cea2SGordon Ross 	return (rv == CKR_OK ? 0 : -1);
113b819cea2SGordon Ross }
114a90cf9f2SGordon Ross 
115a90cf9f2SGordon Ross /*
116a90cf9f2SGordon Ross  * SMB2 signing helpers:
117a90cf9f2SGordon Ross  * (getmech, init, update, final)
118a90cf9f2SGordon Ross  */
119a90cf9f2SGordon Ross 
120c51c88bdSMatt Barden /*
121c51c88bdSMatt Barden  * Find out if we have this mech.
122c51c88bdSMatt Barden  */
123a90cf9f2SGordon Ross int
smb2_hmac_getmech(smb_crypto_mech_t * mech)1241160dcf7SMatt Barden smb2_hmac_getmech(smb_crypto_mech_t *mech)
125a90cf9f2SGordon Ross {
126c51c88bdSMatt Barden 	return (find_mech(mech, CKM_SHA256_HMAC));
127a90cf9f2SGordon Ross }
128a90cf9f2SGordon Ross 
129a90cf9f2SGordon Ross /*
130a90cf9f2SGordon Ross  * Start PKCS#11 session, load the key.
131a90cf9f2SGordon Ross  */
132a90cf9f2SGordon Ross int
smb2_hmac_init(smb_sign_ctx_t * ctxp,smb_crypto_mech_t * mech,uint8_t * key,size_t key_len)1331160dcf7SMatt Barden smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech,
134a90cf9f2SGordon Ross     uint8_t *key, size_t key_len)
135a90cf9f2SGordon Ross {
136a90cf9f2SGordon Ross 	CK_OBJECT_HANDLE hkey = 0;
137a90cf9f2SGordon Ross 	CK_RV rv;
138a90cf9f2SGordon Ross 
139a90cf9f2SGordon Ross 	rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
140a90cf9f2SGordon Ross 	if (rv != CKR_OK)
141a90cf9f2SGordon Ross 		return (-1);
142a90cf9f2SGordon Ross 
143a90cf9f2SGordon Ross 	rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism,
144a90cf9f2SGordon Ross 	    key, key_len, &hkey);
145a90cf9f2SGordon Ross 	if (rv != CKR_OK)
146a90cf9f2SGordon Ross 		return (-1);
147a90cf9f2SGordon Ross 
148a90cf9f2SGordon Ross 	rv = C_SignInit(*ctxp, mech, hkey);
149a90cf9f2SGordon Ross 	(void) C_DestroyObject(*ctxp, hkey);
150a90cf9f2SGordon Ross 
151a90cf9f2SGordon Ross 	return (rv == CKR_OK ? 0 : -1);
152a90cf9f2SGordon Ross }
153a90cf9f2SGordon Ross 
154a90cf9f2SGordon Ross /*
155a90cf9f2SGordon Ross  * Digest one segment
156a90cf9f2SGordon Ross  */
157a90cf9f2SGordon Ross int
smb2_hmac_update(smb_sign_ctx_t ctx,uint8_t * in,size_t len)158a90cf9f2SGordon Ross smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
159a90cf9f2SGordon Ross {
160a90cf9f2SGordon Ross 	CK_RV rv;
161a90cf9f2SGordon Ross 
162a90cf9f2SGordon Ross 	rv = C_SignUpdate(ctx, in, len);
163a90cf9f2SGordon Ross 	if (rv != CKR_OK)
164a90cf9f2SGordon Ross 		(void) C_CloseSession(ctx);
165a90cf9f2SGordon Ross 
166a90cf9f2SGordon Ross 	return (rv == CKR_OK ? 0 : -1);
167a90cf9f2SGordon Ross }
168a90cf9f2SGordon Ross 
169a90cf9f2SGordon Ross /*
170a90cf9f2SGordon Ross  * Note, the SMB2 signature is the first 16 bytes of the
171*a4568e19SAlexander Stetsenko  * 32-byte SHA256 HMAC digest.  This is specifically for
172*a4568e19SAlexander Stetsenko  * SMB2 signing, and NOT a generic HMAC function.
173a90cf9f2SGordon Ross  */
174a90cf9f2SGordon Ross int
smb2_hmac_final(smb_sign_ctx_t ctx,uint8_t * digest16)175a90cf9f2SGordon Ross smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
176a90cf9f2SGordon Ross {
177a90cf9f2SGordon Ross 	uint8_t full_digest[SHA256_DIGEST_LENGTH];
178a90cf9f2SGordon Ross 	CK_ULONG len = SHA256_DIGEST_LENGTH;
179a90cf9f2SGordon Ross 	CK_RV rv;
180a90cf9f2SGordon Ross 
181a90cf9f2SGordon Ross 	rv = C_SignFinal(ctx, full_digest, &len);
182a90cf9f2SGordon Ross 	if (rv == CKR_OK)
183a90cf9f2SGordon Ross 		bcopy(full_digest, digest16, 16);
184a90cf9f2SGordon Ross 
185a90cf9f2SGordon Ross 	(void) C_CloseSession(ctx);
186a90cf9f2SGordon Ross 
187a90cf9f2SGordon Ross 	return (rv == CKR_OK ? 0 : -1);
188a90cf9f2SGordon Ross }
189c51c88bdSMatt Barden 
190*a4568e19SAlexander Stetsenko /*
191*a4568e19SAlexander Stetsenko  * One-shot HMAC function used in smb3_kdf
192*a4568e19SAlexander Stetsenko  */
193*a4568e19SAlexander Stetsenko int
smb2_hmac_one(smb_crypto_mech_t * mech,uint8_t * key,size_t key_len,uint8_t * data,size_t data_len,uint8_t * mac,size_t mac_len)194*a4568e19SAlexander Stetsenko smb2_hmac_one(smb_crypto_mech_t *mech,
195*a4568e19SAlexander Stetsenko     uint8_t *key, size_t key_len,
196*a4568e19SAlexander Stetsenko     uint8_t *data, size_t data_len,
197*a4568e19SAlexander Stetsenko     uint8_t *mac, size_t mac_len)
198*a4568e19SAlexander Stetsenko {
199*a4568e19SAlexander Stetsenko 	CK_SESSION_HANDLE hssn = 0;
200*a4568e19SAlexander Stetsenko 	CK_OBJECT_HANDLE hkey = 0;
201*a4568e19SAlexander Stetsenko 	CK_ULONG ck_maclen = mac_len;
202*a4568e19SAlexander Stetsenko 	CK_RV rv;
203*a4568e19SAlexander Stetsenko 	int rc = 0;
204*a4568e19SAlexander Stetsenko 
205*a4568e19SAlexander Stetsenko 	rv = SUNW_C_GetMechSession(mech->mechanism, &hssn);
206*a4568e19SAlexander Stetsenko 	if (rv != CKR_OK)
207*a4568e19SAlexander Stetsenko 		return (-1);
208*a4568e19SAlexander Stetsenko 
209*a4568e19SAlexander Stetsenko 	rv = SUNW_C_KeyToObject(hssn, mech->mechanism,
210*a4568e19SAlexander Stetsenko 	    key, key_len, &hkey);
211*a4568e19SAlexander Stetsenko 	if (rv != CKR_OK) {
212*a4568e19SAlexander Stetsenko 		rc = -2;
213*a4568e19SAlexander Stetsenko 		goto out;
214*a4568e19SAlexander Stetsenko 	}
215*a4568e19SAlexander Stetsenko 
216*a4568e19SAlexander Stetsenko 	rv = C_SignInit(hssn, mech, hkey);
217*a4568e19SAlexander Stetsenko 	if (rv != CKR_OK) {
218*a4568e19SAlexander Stetsenko 		rc = -3;
219*a4568e19SAlexander Stetsenko 		goto out;
220*a4568e19SAlexander Stetsenko 	}
221*a4568e19SAlexander Stetsenko 
222*a4568e19SAlexander Stetsenko 	rv = C_Sign(hssn, data, data_len, mac, &ck_maclen);
223*a4568e19SAlexander Stetsenko 	if (rv != CKR_OK) {
224*a4568e19SAlexander Stetsenko 		rc = -4;
225*a4568e19SAlexander Stetsenko 		goto out;
226*a4568e19SAlexander Stetsenko 	}
227*a4568e19SAlexander Stetsenko 
228*a4568e19SAlexander Stetsenko 	if (ck_maclen != mac_len) {
229*a4568e19SAlexander Stetsenko 		rc = -5;
230*a4568e19SAlexander Stetsenko 		goto out;
231*a4568e19SAlexander Stetsenko 	}
232*a4568e19SAlexander Stetsenko 	rc = 0;
233*a4568e19SAlexander Stetsenko 
234*a4568e19SAlexander Stetsenko out:
235*a4568e19SAlexander Stetsenko 	if (hkey != 0)
236*a4568e19SAlexander Stetsenko 		(void) C_DestroyObject(hssn, hkey);
237*a4568e19SAlexander Stetsenko 	if (hssn != 0)
238*a4568e19SAlexander Stetsenko 		(void) C_CloseSession(hssn);
239*a4568e19SAlexander Stetsenko 
240*a4568e19SAlexander Stetsenko 	return (rc);
241*a4568e19SAlexander Stetsenko }
242*a4568e19SAlexander Stetsenko 
243c51c88bdSMatt Barden /*
244c51c88bdSMatt Barden  * SMB3 signing helpers:
245c51c88bdSMatt Barden  * (getmech, init, update, final)
246c51c88bdSMatt Barden  */
247c51c88bdSMatt Barden 
248c51c88bdSMatt Barden /*
249c51c88bdSMatt Barden  * Find out if we have this mech.
250c51c88bdSMatt Barden  */
251c51c88bdSMatt Barden int
smb3_cmac_getmech(smb_crypto_mech_t * mech)2521160dcf7SMatt Barden smb3_cmac_getmech(smb_crypto_mech_t *mech)
253c51c88bdSMatt Barden {
254c51c88bdSMatt Barden 	return (find_mech(mech, CKM_AES_CMAC));
255c51c88bdSMatt Barden }
256c51c88bdSMatt Barden 
257c51c88bdSMatt Barden /*
258c51c88bdSMatt Barden  * Start PKCS#11 session, load the key.
259c51c88bdSMatt Barden  */
260c51c88bdSMatt Barden int
smb3_cmac_init(smb_sign_ctx_t * ctxp,smb_crypto_mech_t * mech,uint8_t * key,size_t key_len)2611160dcf7SMatt Barden smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech,
262c51c88bdSMatt Barden     uint8_t *key, size_t key_len)
263c51c88bdSMatt Barden {
264c51c88bdSMatt Barden 	CK_OBJECT_HANDLE hkey = 0;
265c51c88bdSMatt Barden 	CK_RV rv;
266c51c88bdSMatt Barden 
267c51c88bdSMatt Barden 	rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
268c51c88bdSMatt Barden 	if (rv != CKR_OK)
269c51c88bdSMatt Barden 		return (-1);
270c51c88bdSMatt Barden 
271c51c88bdSMatt Barden 	rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism,
272c51c88bdSMatt Barden 	    key, key_len, &hkey);
273686670eaSGordon Ross 	if (rv != CKR_OK) {
274686670eaSGordon Ross 		(void) C_CloseSession(*ctxp);
275c51c88bdSMatt Barden 		return (-1);
276686670eaSGordon Ross 	}
277c51c88bdSMatt Barden 
278c51c88bdSMatt Barden 	rv = C_SignInit(*ctxp, mech, hkey);
279c51c88bdSMatt Barden 	(void) C_DestroyObject(*ctxp, hkey);
280686670eaSGordon Ross 	if (rv != CKR_OK) {
281686670eaSGordon Ross 		(void) C_CloseSession(*ctxp);
282686670eaSGordon Ross 		return (-1);
283686670eaSGordon Ross 	}
284c51c88bdSMatt Barden 
285686670eaSGordon Ross 	return (0);
286c51c88bdSMatt Barden }
287c51c88bdSMatt Barden 
288c51c88bdSMatt Barden /*
289c51c88bdSMatt Barden  * Digest one segment
290c51c88bdSMatt Barden  */
291c51c88bdSMatt Barden int
smb3_cmac_update(smb_sign_ctx_t ctx,uint8_t * in,size_t len)292c51c88bdSMatt Barden smb3_cmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
293c51c88bdSMatt Barden {
294c51c88bdSMatt Barden 	CK_RV rv;
295c51c88bdSMatt Barden 
296c51c88bdSMatt Barden 	rv = C_SignUpdate(ctx, in, len);
297c51c88bdSMatt Barden 	if (rv != CKR_OK)
298c51c88bdSMatt Barden 		(void) C_CloseSession(ctx);
299c51c88bdSMatt Barden 
300c51c88bdSMatt Barden 	return (rv == CKR_OK ? 0 : -1);
301c51c88bdSMatt Barden }
302c51c88bdSMatt Barden 
303c51c88bdSMatt Barden /*
304c51c88bdSMatt Barden  * Note, the SMB2 signature is just the AES CMAC digest.
305c51c88bdSMatt Barden  * (both are 16 bytes long)
306c51c88bdSMatt Barden  */
307c51c88bdSMatt Barden int
smb3_cmac_final(smb_sign_ctx_t ctx,uint8_t * digest)308c51c88bdSMatt Barden smb3_cmac_final(smb_sign_ctx_t ctx, uint8_t *digest)
309c51c88bdSMatt Barden {
310c51c88bdSMatt Barden 	CK_ULONG len = SMB2_SIG_SIZE;
311c51c88bdSMatt Barden 	CK_RV rv;
312c51c88bdSMatt Barden 
313c51c88bdSMatt Barden 	rv = C_SignFinal(ctx, digest, &len);
314c51c88bdSMatt Barden 	(void) C_CloseSession(ctx);
315c51c88bdSMatt Barden 
316c51c88bdSMatt Barden 	return (rv == CKR_OK ? 0 : -1);
317c51c88bdSMatt Barden }
318