18329232eSGordon Ross /*
28329232eSGordon Ross  * This file and its contents are supplied under the terms of the
38329232eSGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
48329232eSGordon Ross  * You may only use this file in accordance with the terms of version
58329232eSGordon Ross  * 1.0 of the CDDL.
68329232eSGordon Ross  *
78329232eSGordon Ross  * A full copy of the text of the CDDL should have accompanied this
88329232eSGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
98329232eSGordon Ross  * http://www.illumos.org/license/CDDL.
108329232eSGordon Ross  */
118329232eSGordon Ross 
128329232eSGordon Ross /*
138329232eSGordon Ross  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
148329232eSGordon Ross  */
158329232eSGordon Ross 
168329232eSGordon Ross /*
178329232eSGordon Ross  * Helper functions for SMB signing using PKCS#11
188329232eSGordon Ross  *
198329232eSGordon Ross  * There are two implementations of these functions:
208329232eSGordon Ross  * This one (for user space) and another for kernel.
218329232eSGordon Ross  * See: uts/common/fs/smbclnt/netsmb/smb_sign_kcf.c
228329232eSGordon Ross  */
238329232eSGordon Ross 
248329232eSGordon Ross #include <stdlib.h>
258329232eSGordon Ross #include <strings.h>
26*686670eaSGordon Ross #include <sys/cmn_err.h>
278329232eSGordon Ross #include <netsmb/smb_signing.h>
288329232eSGordon Ross #include <security/cryptoki.h>
298329232eSGordon Ross #include <security/pkcs11.h>
308329232eSGordon Ross 
31*686670eaSGordon Ross /*
32*686670eaSGordon Ross  * Common function to see if a mech is available.
33*686670eaSGordon Ross  */
34*686670eaSGordon Ross static int
find_mech(smb_sign_mech_t * mech,ulong_t mid)35*686670eaSGordon Ross find_mech(smb_sign_mech_t *mech, ulong_t mid)
36*686670eaSGordon Ross {
37*686670eaSGordon Ross 	CK_SESSION_HANDLE hdl;
38*686670eaSGordon Ross 	CK_RV rv;
39*686670eaSGordon Ross 
40*686670eaSGordon Ross 	rv = SUNW_C_GetMechSession(mid, &hdl);
41*686670eaSGordon Ross 	if (rv != CKR_OK) {
42*686670eaSGordon Ross 		cmn_err(CE_NOTE, "PKCS#11: no mech 0x%x",
43*686670eaSGordon Ross 		    (unsigned int)mid);
44*686670eaSGordon Ross 		return (-1);
45*686670eaSGordon Ross 	}
46*686670eaSGordon Ross 	(void) C_CloseSession(hdl);
47*686670eaSGordon Ross 
48*686670eaSGordon Ross 	mech->mechanism = mid;
49*686670eaSGordon Ross 	mech->pParameter = NULL;
50*686670eaSGordon Ross 	mech->ulParameterLen = 0;
51*686670eaSGordon Ross 	return (0);
52*686670eaSGordon Ross }
53*686670eaSGordon Ross 
548329232eSGordon Ross /*
558329232eSGordon Ross  * SMB1 signing helpers:
568329232eSGordon Ross  * (getmech, init, update, final)
578329232eSGordon Ross  */
588329232eSGordon Ross 
59*686670eaSGordon Ross /*
60*686670eaSGordon Ross  * Find out if we have this mech.
61*686670eaSGordon Ross  */
628329232eSGordon Ross int
smb_md5_getmech(smb_sign_mech_t * mech)638329232eSGordon Ross smb_md5_getmech(smb_sign_mech_t *mech)
648329232eSGordon Ross {
65*686670eaSGordon Ross 	return (find_mech(mech, CKM_MD5));
668329232eSGordon Ross }
678329232eSGordon Ross 
688329232eSGordon Ross /*
698329232eSGordon Ross  * Start PKCS#11 session.
708329232eSGordon Ross  */
718329232eSGordon Ross int
smb_md5_init(smb_sign_ctx_t * ctxp,smb_sign_mech_t * mech)728329232eSGordon Ross smb_md5_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech)
738329232eSGordon Ross {
748329232eSGordon Ross 	CK_RV rv;
758329232eSGordon Ross 
768329232eSGordon Ross 	rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
778329232eSGordon Ross 	if (rv != CKR_OK)
788329232eSGordon Ross 		return (-1);
798329232eSGordon Ross 
808329232eSGordon Ross 	rv = C_DigestInit(*ctxp, mech);
818329232eSGordon Ross 
828329232eSGordon Ross 	return (rv == CKR_OK ? 0 : -1);
838329232eSGordon Ross }
848329232eSGordon Ross 
858329232eSGordon Ross /*
868329232eSGordon Ross  * Digest one segment
878329232eSGordon Ross  */
888329232eSGordon Ross int
smb_md5_update(smb_sign_ctx_t ctx,void * buf,size_t len)898329232eSGordon Ross smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
908329232eSGordon Ross {
918329232eSGordon Ross 	CK_RV rv;
928329232eSGordon Ross 
938329232eSGordon Ross 	rv = C_DigestUpdate(ctx, buf, len);
948329232eSGordon Ross 	if (rv != CKR_OK)
958329232eSGordon Ross 		(void) C_CloseSession(ctx);
968329232eSGordon Ross 
978329232eSGordon Ross 	return (rv == CKR_OK ? 0 : -1);
988329232eSGordon Ross }
998329232eSGordon Ross 
1008329232eSGordon Ross /*
1018329232eSGordon Ross  * Get the final digest.
1028329232eSGordon Ross  */
1038329232eSGordon Ross int
smb_md5_final(smb_sign_ctx_t ctx,uint8_t * digest16)1048329232eSGordon Ross smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
1058329232eSGordon Ross {
1068329232eSGordon Ross 	CK_ULONG len = MD5_DIGEST_LENGTH;
1078329232eSGordon Ross 	CK_RV rv;
1088329232eSGordon Ross 
1098329232eSGordon Ross 	rv = C_DigestFinal(ctx, digest16, &len);
1108329232eSGordon Ross 	(void) C_CloseSession(ctx);
1118329232eSGordon Ross 
1128329232eSGordon Ross 	return (rv == CKR_OK ? 0 : -1);
1138329232eSGordon Ross }
1148329232eSGordon Ross 
1158329232eSGordon Ross /*
1168329232eSGordon Ross  * SMB2 signing helpers:
1178329232eSGordon Ross  * (getmech, init, update, final)
1188329232eSGordon Ross  */
1198329232eSGordon Ross 
120*686670eaSGordon Ross /*
121*686670eaSGordon Ross  * Find out if we have this mech.
122*686670eaSGordon Ross  */
1238329232eSGordon Ross int
smb2_hmac_getmech(smb_sign_mech_t * mech)1248329232eSGordon Ross smb2_hmac_getmech(smb_sign_mech_t *mech)
1258329232eSGordon Ross {
126*686670eaSGordon Ross 	return (find_mech(mech, CKM_SHA256_HMAC));
1278329232eSGordon Ross }
1288329232eSGordon Ross 
1298329232eSGordon Ross /*
1308329232eSGordon Ross  * Start PKCS#11 session, load the key.
1318329232eSGordon Ross  */
1328329232eSGordon Ross int
smb2_hmac_init(smb_sign_ctx_t * ctxp,smb_sign_mech_t * mech,uint8_t * key,size_t key_len)1338329232eSGordon Ross smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech,
1348329232eSGordon Ross     uint8_t *key, size_t key_len)
1358329232eSGordon Ross {
1368329232eSGordon Ross 	CK_OBJECT_HANDLE hkey = 0;
1378329232eSGordon Ross 	CK_RV rv;
1388329232eSGordon Ross 
1398329232eSGordon Ross 	rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
1408329232eSGordon Ross 	if (rv != CKR_OK)
1418329232eSGordon Ross 		return (-1);
1428329232eSGordon Ross 
1438329232eSGordon Ross 	rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism,
1448329232eSGordon Ross 	    key, key_len, &hkey);
1458329232eSGordon Ross 	if (rv != CKR_OK)
1468329232eSGordon Ross 		return (-1);
1478329232eSGordon Ross 
1488329232eSGordon Ross 	rv = C_SignInit(*ctxp, mech, hkey);
1498329232eSGordon Ross 	(void) C_DestroyObject(*ctxp, hkey);
1508329232eSGordon Ross 
1518329232eSGordon Ross 	return (rv == CKR_OK ? 0 : -1);
1528329232eSGordon Ross }
1538329232eSGordon Ross 
1548329232eSGordon Ross /*
1558329232eSGordon Ross  * Digest one segment
1568329232eSGordon Ross  */
1578329232eSGordon Ross int
smb2_hmac_update(smb_sign_ctx_t ctx,uint8_t * in,size_t len)1588329232eSGordon Ross smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
1598329232eSGordon Ross {
1608329232eSGordon Ross 	CK_RV rv;
1618329232eSGordon Ross 
1628329232eSGordon Ross 	rv = C_SignUpdate(ctx, in, len);
1638329232eSGordon Ross 	if (rv != CKR_OK)
1648329232eSGordon Ross 		(void) C_CloseSession(ctx);
1658329232eSGordon Ross 
1668329232eSGordon Ross 	return (rv == CKR_OK ? 0 : -1);
1678329232eSGordon Ross }
1688329232eSGordon Ross 
1698329232eSGordon Ross /*
1708329232eSGordon Ross  * Note, the SMB2 signature is the first 16 bytes of the
1718329232eSGordon Ross  * 32-byte SHA256 HMAC digest.
1728329232eSGordon Ross  */
1738329232eSGordon Ross int
smb2_hmac_final(smb_sign_ctx_t ctx,uint8_t * digest16)1748329232eSGordon Ross smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
1758329232eSGordon Ross {
1768329232eSGordon Ross 	uint8_t full_digest[SHA256_DIGEST_LENGTH];
1778329232eSGordon Ross 	CK_ULONG len = SHA256_DIGEST_LENGTH;
1788329232eSGordon Ross 	CK_RV rv;
1798329232eSGordon Ross 
1808329232eSGordon Ross 	rv = C_SignFinal(ctx, full_digest, &len);
1818329232eSGordon Ross 	if (rv == CKR_OK)
1828329232eSGordon Ross 		bcopy(full_digest, digest16, 16);
1838329232eSGordon Ross 
1848329232eSGordon Ross 	(void) C_CloseSession(ctx);
1858329232eSGordon Ross 
1868329232eSGordon Ross 	return (rv == CKR_OK ? 0 : -1);
1878329232eSGordon Ross }
188*686670eaSGordon Ross 
189*686670eaSGordon Ross /*
190*686670eaSGordon Ross  * SMB3 signing helpers:
191*686670eaSGordon Ross  * (getmech, init, update, final)
192*686670eaSGordon Ross  */
193*686670eaSGordon Ross 
194*686670eaSGordon Ross /*
195*686670eaSGordon Ross  * Find out if we have this mech.
196*686670eaSGordon Ross  */
197*686670eaSGordon Ross int
smb3_cmac_getmech(smb_sign_mech_t * mech)198*686670eaSGordon Ross smb3_cmac_getmech(smb_sign_mech_t *mech)
199*686670eaSGordon Ross {
200*686670eaSGordon Ross 	return (find_mech(mech, CKM_AES_CMAC));
201*686670eaSGordon Ross }
202*686670eaSGordon Ross 
203*686670eaSGordon Ross /*
204*686670eaSGordon Ross  * Start PKCS#11 session, load the key.
205*686670eaSGordon Ross  */
206*686670eaSGordon Ross int
smb3_cmac_init(smb_sign_ctx_t * ctxp,smb_sign_mech_t * mech,uint8_t * key,size_t key_len)207*686670eaSGordon Ross smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech,
208*686670eaSGordon Ross     uint8_t *key, size_t key_len)
209*686670eaSGordon Ross {
210*686670eaSGordon Ross 	CK_OBJECT_HANDLE hkey = 0;
211*686670eaSGordon Ross 	CK_RV rv;
212*686670eaSGordon Ross 
213*686670eaSGordon Ross 	rv = SUNW_C_GetMechSession(mech->mechanism, ctxp);
214*686670eaSGordon Ross 	if (rv != CKR_OK)
215*686670eaSGordon Ross 		return (-1);
216*686670eaSGordon Ross 
217*686670eaSGordon Ross 	rv = SUNW_C_KeyToObject(*ctxp, mech->mechanism,
218*686670eaSGordon Ross 	    key, key_len, &hkey);
219*686670eaSGordon Ross 	if (rv != CKR_OK) {
220*686670eaSGordon Ross 		(void) C_CloseSession(*ctxp);
221*686670eaSGordon Ross 		return (-1);
222*686670eaSGordon Ross 	}
223*686670eaSGordon Ross 
224*686670eaSGordon Ross 	rv = C_SignInit(*ctxp, mech, hkey);
225*686670eaSGordon Ross 	(void) C_DestroyObject(*ctxp, hkey);
226*686670eaSGordon Ross 	if (rv != CKR_OK) {
227*686670eaSGordon Ross 		(void) C_CloseSession(*ctxp);
228*686670eaSGordon Ross 		return (-1);
229*686670eaSGordon Ross 	}
230*686670eaSGordon Ross 
231*686670eaSGordon Ross 	return (0);
232*686670eaSGordon Ross }
233*686670eaSGordon Ross 
234*686670eaSGordon Ross /*
235*686670eaSGordon Ross  * Digest one segment
236*686670eaSGordon Ross  */
237*686670eaSGordon Ross int
smb3_cmac_update(smb_sign_ctx_t ctx,uint8_t * in,size_t len)238*686670eaSGordon Ross smb3_cmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
239*686670eaSGordon Ross {
240*686670eaSGordon Ross 	CK_RV rv;
241*686670eaSGordon Ross 
242*686670eaSGordon Ross 	rv = C_SignUpdate(ctx, in, len);
243*686670eaSGordon Ross 	if (rv != CKR_OK)
244*686670eaSGordon Ross 		(void) C_CloseSession(ctx);
245*686670eaSGordon Ross 
246*686670eaSGordon Ross 	return (rv == CKR_OK ? 0 : -1);
247*686670eaSGordon Ross }
248*686670eaSGordon Ross 
249*686670eaSGordon Ross /*
250*686670eaSGordon Ross  * Note, the SMB2 signature is just the AES CMAC digest.
251*686670eaSGordon Ross  * (both are 16 bytes long)
252*686670eaSGordon Ross  */
253*686670eaSGordon Ross int
smb3_cmac_final(smb_sign_ctx_t ctx,uint8_t * digest)254*686670eaSGordon Ross smb3_cmac_final(smb_sign_ctx_t ctx, uint8_t *digest)
255*686670eaSGordon Ross {
256*686670eaSGordon Ross 	CK_ULONG len = SMB2_SIG_SIZE;
257*686670eaSGordon Ross 	CK_RV rv;
258*686670eaSGordon Ross 
259*686670eaSGordon Ross 	rv = C_SignFinal(ctx, digest, &len);
260*686670eaSGordon Ross 	(void) C_CloseSession(ctx);
261*686670eaSGordon Ross 
262*686670eaSGordon Ross 	return (rv == CKR_OK ? 0 : -1);
263*686670eaSGordon Ross }
264