11160dcf7SMatt Barden /*
21160dcf7SMatt Barden  * This file and its contents are supplied under the terms of the
31160dcf7SMatt Barden  * Common Development and Distribution License ("CDDL"), version 1.0.
41160dcf7SMatt Barden  * You may only use this file in accordance with the terms of version
51160dcf7SMatt Barden  * 1.0 of the CDDL.
61160dcf7SMatt Barden  *
71160dcf7SMatt Barden  * A full copy of the text of the CDDL should have accompanied this
81160dcf7SMatt Barden  * source.  A copy of the CDDL is also available via the Internet at
91160dcf7SMatt Barden  * http://www.illumos.org/license/CDDL.
101160dcf7SMatt Barden  */
111160dcf7SMatt Barden 
121160dcf7SMatt Barden /*
13*4f0ce1daSGordon Ross  * Copyright 2018-2021 Tintri by DDN, Inc. All rights reserved.
14*4f0ce1daSGordon Ross  * Copyright 2021 RackTop Systems, Inc.
151160dcf7SMatt Barden  */
161160dcf7SMatt Barden 
171160dcf7SMatt Barden /*
181160dcf7SMatt Barden  * Helper functions for SMB3 encryption using PKCS#11
191160dcf7SMatt Barden  *
201160dcf7SMatt Barden  * There are two implementations of these functions:
211160dcf7SMatt Barden  * This one (for user space) and another for kernel.
221160dcf7SMatt Barden  * See: uts/common/fs/smbsrv/smb3_encrypt_kcf.c
231160dcf7SMatt Barden  *
24*4f0ce1daSGordon Ross  * Contrary to what one might assume from the file name,
25*4f0ce1daSGordon Ross  * there should be NO SMB implementation knowledge here
26*4f0ce1daSGordon Ross  * beyond a few carefully selected things (smb_kcrypt.h).
271160dcf7SMatt Barden  */
281160dcf7SMatt Barden 
29*4f0ce1daSGordon Ross #include <security/cryptoki.h>
30*4f0ce1daSGordon Ross #include <security/pkcs11.h>
311160dcf7SMatt Barden #include <smbsrv/smb_kcrypt.h>
32*4f0ce1daSGordon Ross 
33*4f0ce1daSGordon Ross #include <sys/cmn_err.h>
34*4f0ce1daSGordon Ross #include <sys/debug.h>
35*4f0ce1daSGordon Ross #include <stdlib.h>
36*4f0ce1daSGordon Ross #include <strings.h>
37*4f0ce1daSGordon Ross 
38*4f0ce1daSGordon Ross /*
39*4f0ce1daSGordon Ross  * Common function to see if a mech is available.
40*4f0ce1daSGordon Ross  */
41*4f0ce1daSGordon Ross static int
find_mech(CK_MECHANISM_TYPE id)42*4f0ce1daSGordon Ross find_mech(CK_MECHANISM_TYPE id)
43*4f0ce1daSGordon Ross {
44*4f0ce1daSGordon Ross 	CK_SESSION_HANDLE hdl;
45*4f0ce1daSGordon Ross 	CK_RV rv;
46*4f0ce1daSGordon Ross 
47*4f0ce1daSGordon Ross 	rv = SUNW_C_GetMechSession(id, &hdl);
48*4f0ce1daSGordon Ross 	if (rv != CKR_OK) {
49*4f0ce1daSGordon Ross 		return (-1);
50*4f0ce1daSGordon Ross 	}
51*4f0ce1daSGordon Ross 	(void) C_CloseSession(hdl);
52*4f0ce1daSGordon Ross 
53*4f0ce1daSGordon Ross 	return (0);
54*4f0ce1daSGordon Ross }
551160dcf7SMatt Barden 
561160dcf7SMatt Barden /*
571160dcf7SMatt Barden  * SMB3 encryption helpers:
581160dcf7SMatt Barden  * (getmech, init, update, final)
591160dcf7SMatt Barden  */
601160dcf7SMatt Barden 
611160dcf7SMatt Barden int
smb3_aes_ccm_getmech(smb_crypto_mech_t * mech)624e065a9fSAlexander Stetsenko smb3_aes_ccm_getmech(smb_crypto_mech_t *mech)
634e065a9fSAlexander Stetsenko {
64*4f0ce1daSGordon Ross 
65*4f0ce1daSGordon Ross 	if (find_mech(CKM_AES_CCM) != 0) {
66*4f0ce1daSGordon Ross 		cmn_err(CE_NOTE, "PKCS#11: no mech AES_CCM");
67*4f0ce1daSGordon Ross 		return (-1);
68*4f0ce1daSGordon Ross 	}
69*4f0ce1daSGordon Ross 
70*4f0ce1daSGordon Ross 	mech->mechanism = CKM_AES_CCM;
71*4f0ce1daSGordon Ross 	return (0);
724e065a9fSAlexander Stetsenko }
734e065a9fSAlexander Stetsenko 
744e065a9fSAlexander Stetsenko int
smb3_aes_gcm_getmech(smb_crypto_mech_t * mech)754e065a9fSAlexander Stetsenko smb3_aes_gcm_getmech(smb_crypto_mech_t *mech)
761160dcf7SMatt Barden {
77*4f0ce1daSGordon Ross 
78*4f0ce1daSGordon Ross 	if (find_mech(CKM_AES_GCM) != 0) {
79*4f0ce1daSGordon Ross 		cmn_err(CE_NOTE, "PKCS#11: no mech CKM_AES_GCM");
80*4f0ce1daSGordon Ross 		return (-1);
81*4f0ce1daSGordon Ross 	}
82*4f0ce1daSGordon Ross 
83*4f0ce1daSGordon Ross 	mech->mechanism = CKM_AES_GCM;
84*4f0ce1daSGordon Ross 	return (0);
851160dcf7SMatt Barden }
861160dcf7SMatt Barden 
871160dcf7SMatt Barden void
smb3_crypto_init_ccm_param(smb_enc_ctx_t * ctx,uint8_t * nonce,size_t noncesize,uint8_t * auth,size_t authsize,size_t datasize)88*4f0ce1daSGordon Ross smb3_crypto_init_ccm_param(smb_enc_ctx_t *ctx,
89*4f0ce1daSGordon Ross     uint8_t *nonce, size_t noncesize,
90*4f0ce1daSGordon Ross     uint8_t *auth, size_t authsize,
911160dcf7SMatt Barden     size_t datasize)
921160dcf7SMatt Barden {
93*4f0ce1daSGordon Ross 
94*4f0ce1daSGordon Ross 	ASSERT3U(noncesize, >=, SMB3_AES_CCM_NONCE_SIZE);
95*4f0ce1daSGordon Ross 
96*4f0ce1daSGordon Ross 	/* CK_CCM_PARAMS */
97*4f0ce1daSGordon Ross 	ctx->param.ccm.ulDataLen = datasize;
98*4f0ce1daSGordon Ross 	ctx->param.ccm.pNonce = nonce;
99*4f0ce1daSGordon Ross 	ctx->param.ccm.ulNonceLen = SMB3_AES_CCM_NONCE_SIZE;
100*4f0ce1daSGordon Ross 	ctx->param.ccm.pAAD = auth;
101*4f0ce1daSGordon Ross 	ctx->param.ccm.ulAADLen = authsize;
102*4f0ce1daSGordon Ross 	ctx->param.ccm.ulMACLen = SMB2_SIG_SIZE;
103*4f0ce1daSGordon Ross 
104*4f0ce1daSGordon Ross 	ctx->mech.pParameter = (caddr_t)&ctx->param.ccm;
105*4f0ce1daSGordon Ross 	ctx->mech.ulParameterLen = sizeof (ctx->param.ccm);
1061160dcf7SMatt Barden }
1071160dcf7SMatt Barden 
1084e065a9fSAlexander Stetsenko void
smb3_crypto_init_gcm_param(smb_enc_ctx_t * ctx,uint8_t * nonce,size_t noncesize,uint8_t * auth,size_t authsize)109*4f0ce1daSGordon Ross smb3_crypto_init_gcm_param(smb_enc_ctx_t *ctx,
110*4f0ce1daSGordon Ross     uint8_t *nonce, size_t noncesize,
111*4f0ce1daSGordon Ross     uint8_t *auth, size_t authsize)
1124e065a9fSAlexander Stetsenko {
1134e065a9fSAlexander Stetsenko 
114*4f0ce1daSGordon Ross 	ASSERT3U(noncesize, >=, SMB3_AES_GCM_NONCE_SIZE);
1151160dcf7SMatt Barden 
116*4f0ce1daSGordon Ross 	/* CK_GCM_PARAMS */
117*4f0ce1daSGordon Ross 	ctx->param.gcm.pIv = nonce;
118*4f0ce1daSGordon Ross 	ctx->param.gcm.ulIvLen = SMB3_AES_GCM_NONCE_SIZE;
119*4f0ce1daSGordon Ross 	ctx->param.gcm.pAAD = auth;			/* auth data */
120*4f0ce1daSGordon Ross 	ctx->param.gcm.ulAADLen = authsize;		/* auth data len */
121*4f0ce1daSGordon Ross 	ctx->param.gcm.ulTagBits = SMB2_SIG_SIZE << 3;	/* bytes to bits */
1221160dcf7SMatt Barden 
123*4f0ce1daSGordon Ross 	ctx->mech.pParameter = (caddr_t)&ctx->param.gcm;
124*4f0ce1daSGordon Ross 	ctx->mech.ulParameterLen = sizeof (ctx->param.gcm);
1251160dcf7SMatt Barden }
1261160dcf7SMatt Barden 
127*4f0ce1daSGordon Ross /*
128*4f0ce1daSGordon Ross  * Start the KCF encrypt session, load the key
129*4f0ce1daSGordon Ross  * If this returns zero, the caller should call
130*4f0ce1daSGordon Ross  * smb3_enc_ctx_done to cleanup the context,
131*4f0ce1daSGordon Ross  * even if there are intervening errors.
132*4f0ce1daSGordon Ross  */
1331160dcf7SMatt Barden int
smb3_encrypt_init(smb_enc_ctx_t * ctxp,uint8_t * key,size_t keylen)134*4f0ce1daSGordon Ross smb3_encrypt_init(smb_enc_ctx_t *ctxp,
135*4f0ce1daSGordon Ross     uint8_t *key, size_t keylen)
1361160dcf7SMatt Barden {
137*4f0ce1daSGordon Ross 	CK_OBJECT_HANDLE hkey = 0;
138*4f0ce1daSGordon Ross 	CK_MECHANISM *mech = &ctxp->mech;
139*4f0ce1daSGordon Ross 	CK_RV rv;
140*4f0ce1daSGordon Ross 
141*4f0ce1daSGordon Ross 	rv = SUNW_C_GetMechSession(mech->mechanism, &ctxp->ctx);
142*4f0ce1daSGordon Ross 	if (rv != CKR_OK)
143*4f0ce1daSGordon Ross 		return (-1);
144*4f0ce1daSGordon Ross 
145*4f0ce1daSGordon Ross 	rv = SUNW_C_KeyToObject(ctxp->ctx, mech->mechanism,
146*4f0ce1daSGordon Ross 	    key, keylen, &hkey);
147*4f0ce1daSGordon Ross 	if (rv != CKR_OK)
148*4f0ce1daSGordon Ross 		return (-1);
149*4f0ce1daSGordon Ross 
150*4f0ce1daSGordon Ross 	rv = C_EncryptInit(ctxp->ctx, mech, hkey);
151*4f0ce1daSGordon Ross 	if (rv != CKR_OK) {
152*4f0ce1daSGordon Ross 		cmn_err(CE_WARN, "C_EncryptInit failed: 0x%lx", rv);
153*4f0ce1daSGordon Ross 	}
154*4f0ce1daSGordon Ross 	(void) C_DestroyObject(ctxp->ctx, hkey);
155*4f0ce1daSGordon Ross 
156*4f0ce1daSGordon Ross 	return (rv == CKR_OK ? 0 : -1);
1571160dcf7SMatt Barden }
1581160dcf7SMatt Barden 
1591160dcf7SMatt Barden /*
160*4f0ce1daSGordon Ross  * Start the KCF decrypt session, load the key
161*4f0ce1daSGordon Ross  * If this returns zero, the caller should call
162*4f0ce1daSGordon Ross  * smb3_enc_ctx_done to cleanup the context,
163*4f0ce1daSGordon Ross  * even if there are intervening errors.
1641160dcf7SMatt Barden  */
1651160dcf7SMatt Barden int
smb3_decrypt_init(smb_enc_ctx_t * ctxp,uint8_t * key,size_t keylen)166*4f0ce1daSGordon Ross smb3_decrypt_init(smb_enc_ctx_t *ctxp,
167*4f0ce1daSGordon Ross     uint8_t *key, size_t keylen)
1681160dcf7SMatt Barden {
169*4f0ce1daSGordon Ross 	CK_OBJECT_HANDLE hkey = 0;
170*4f0ce1daSGordon Ross 	CK_MECHANISM *mech = &ctxp->mech;
171*4f0ce1daSGordon Ross 	CK_RV rv;
1721160dcf7SMatt Barden 
173*4f0ce1daSGordon Ross 	rv = SUNW_C_GetMechSession(mech->mechanism, &ctxp->ctx);
174*4f0ce1daSGordon Ross 	if (rv != CKR_OK)
175*4f0ce1daSGordon Ross 		return (-1);
176*4f0ce1daSGordon Ross 
177*4f0ce1daSGordon Ross 	rv = SUNW_C_KeyToObject(ctxp->ctx, mech->mechanism,
178*4f0ce1daSGordon Ross 	    key, keylen, &hkey);
179*4f0ce1daSGordon Ross 	if (rv != CKR_OK)
180*4f0ce1daSGordon Ross 		return (-1);
181*4f0ce1daSGordon Ross 
182*4f0ce1daSGordon Ross 	rv = C_DecryptInit(ctxp->ctx, mech, hkey);
183*4f0ce1daSGordon Ross 	if (rv != CKR_OK) {
184*4f0ce1daSGordon Ross 		cmn_err(CE_WARN, "C_DecryptInit failed: 0x%lx", rv);
185*4f0ce1daSGordon Ross 	}
186*4f0ce1daSGordon Ross 	(void) C_DestroyObject(ctxp->ctx, hkey);
187*4f0ce1daSGordon Ross 
188*4f0ce1daSGordon Ross 	return (rv == CKR_OK ? 0 : -1);
1891160dcf7SMatt Barden }
1901160dcf7SMatt Barden 
191*4f0ce1daSGordon Ross /*
192*4f0ce1daSGordon Ross  * Encrypt a whole message with scatter/gather (UIO)
193*4f0ce1daSGordon Ross  *
194*4f0ce1daSGordon Ross  * While the PKCS#11 implementation internally has the ability to
195*4f0ce1daSGordon Ross  * handle scatter/gather, it currently presents no interface for it.
196*4f0ce1daSGordon Ross  * As this library is used primarily for debugging, performance in
197*4f0ce1daSGordon Ross  * here is not a big concern, so we'll get around the limitation of
198*4f0ce1daSGordon Ross  * libpkcs11 by copying to/from a contiguous working buffer.
199*4f0ce1daSGordon Ross  */
2001160dcf7SMatt Barden int
smb3_encrypt_uio(smb_enc_ctx_t * ctxp,uio_t * in,uio_t * out)201*4f0ce1daSGordon Ross smb3_encrypt_uio(smb_enc_ctx_t *ctxp, uio_t *in, uio_t *out)
2021160dcf7SMatt Barden {
203*4f0ce1daSGordon Ross 	uint8_t *buf = NULL;
204*4f0ce1daSGordon Ross 	size_t inlen, outlen;
205*4f0ce1daSGordon Ross 	ulong_t tlen;
206*4f0ce1daSGordon Ross 	int err, rc = -1;
207*4f0ce1daSGordon Ross 	CK_RV rv;
208*4f0ce1daSGordon Ross 
209*4f0ce1daSGordon Ross 	if (in->uio_resid <= 0)
210*4f0ce1daSGordon Ross 		return (-1);
211*4f0ce1daSGordon Ross 	inlen = in->uio_resid;
212*4f0ce1daSGordon Ross 	outlen = inlen + 16;
213*4f0ce1daSGordon Ross 	buf = malloc(outlen);
214*4f0ce1daSGordon Ross 	if (buf == NULL)
215*4f0ce1daSGordon Ross 		return (-1);
216*4f0ce1daSGordon Ross 
217*4f0ce1daSGordon Ross 	/* Copy from uio segs to buf */
218*4f0ce1daSGordon Ross 	err = uiomove(buf, inlen, UIO_WRITE, in);
219*4f0ce1daSGordon Ross 	if (err != 0)
220*4f0ce1daSGordon Ross 		goto out;
221*4f0ce1daSGordon Ross 
222*4f0ce1daSGordon Ross 	/* Encrypt in-place in our work buffer. */
223*4f0ce1daSGordon Ross 	tlen = outlen;
224*4f0ce1daSGordon Ross 	rv = C_Encrypt(ctxp->ctx, buf, inlen, buf, &tlen);
225*4f0ce1daSGordon Ross 	if (rv != CKR_OK) {
226*4f0ce1daSGordon Ross 		cmn_err(CE_WARN, "C_Encrypt failed: 0x%lx", rv);
227*4f0ce1daSGordon Ross 		goto out;
228*4f0ce1daSGordon Ross 	}
229*4f0ce1daSGordon Ross 	if (tlen != outlen) {
230*4f0ce1daSGordon Ross 		cmn_err(CE_WARN, "smb3_encrypt_uio outlen %d vs %d",
231*4f0ce1daSGordon Ross 		    (int)tlen, (int)outlen);
232*4f0ce1daSGordon Ross 		goto out;
233*4f0ce1daSGordon Ross 	}
234*4f0ce1daSGordon Ross 
235*4f0ce1daSGordon Ross 	/* Copy from buf to uio segs */
236*4f0ce1daSGordon Ross 	err = uiomove(buf, outlen, UIO_READ, out);
237*4f0ce1daSGordon Ross 	if (err != 0)
238*4f0ce1daSGordon Ross 		goto out;
239*4f0ce1daSGordon Ross 
240*4f0ce1daSGordon Ross 	rc = 0;
241*4f0ce1daSGordon Ross out:
242*4f0ce1daSGordon Ross 	free(buf);
243*4f0ce1daSGordon Ross 
244*4f0ce1daSGordon Ross 	return (rc);
2451160dcf7SMatt Barden }
2461160dcf7SMatt Barden 
2471160dcf7SMatt Barden int
smb3_decrypt_uio(smb_enc_ctx_t * ctxp,uio_t * in,uio_t * out)248*4f0ce1daSGordon Ross smb3_decrypt_uio(smb_enc_ctx_t *ctxp, uio_t *in, uio_t *out)
2491160dcf7SMatt Barden {
250*4f0ce1daSGordon Ross 	uint8_t *buf = NULL;
251*4f0ce1daSGordon Ross 	size_t inlen, outlen;
252*4f0ce1daSGordon Ross 	ulong_t tlen;
253*4f0ce1daSGordon Ross 	int err, rc = -1;
254*4f0ce1daSGordon Ross 	CK_RV rv;
255*4f0ce1daSGordon Ross 
256*4f0ce1daSGordon Ross 	if (in->uio_resid <= 16)
257*4f0ce1daSGordon Ross 		return (-1);
258*4f0ce1daSGordon Ross 	inlen = in->uio_resid;
259*4f0ce1daSGordon Ross 	outlen = inlen - 16;
260*4f0ce1daSGordon Ross 	buf = malloc(inlen);
261*4f0ce1daSGordon Ross 	if (buf == NULL)
262*4f0ce1daSGordon Ross 		return (-1);
263*4f0ce1daSGordon Ross 
264*4f0ce1daSGordon Ross 	/* Copy from uio segs to buf */
265*4f0ce1daSGordon Ross 	err = uiomove(buf, inlen, UIO_WRITE, in);
266*4f0ce1daSGordon Ross 	if (err != 0)
267*4f0ce1daSGordon Ross 		goto out;
268*4f0ce1daSGordon Ross 
269*4f0ce1daSGordon Ross 	/* Decrypt in-place in our work buffer. */
270*4f0ce1daSGordon Ross 	tlen = outlen;
271*4f0ce1daSGordon Ross 	rv = C_Decrypt(ctxp->ctx, buf, inlen, buf, &tlen);
272*4f0ce1daSGordon Ross 	if (rv != CKR_OK) {
273*4f0ce1daSGordon Ross 		cmn_err(CE_WARN, "C_Decrypt failed: 0x%lx", rv);
274*4f0ce1daSGordon Ross 		goto out;
275*4f0ce1daSGordon Ross 	}
276*4f0ce1daSGordon Ross 	if (tlen != outlen) {
277*4f0ce1daSGordon Ross 		cmn_err(CE_WARN, "smb3_decrypt_uio outlen %d vs %d",
278*4f0ce1daSGordon Ross 		    (int)tlen, (int)outlen);
279*4f0ce1daSGordon Ross 		goto out;
280*4f0ce1daSGordon Ross 	}
281*4f0ce1daSGordon Ross 
282*4f0ce1daSGordon Ross 	/* Copy from buf to uio segs */
283*4f0ce1daSGordon Ross 	err = uiomove(buf, outlen, UIO_READ, out);
284*4f0ce1daSGordon Ross 	if (err != 0)
285*4f0ce1daSGordon Ross 		goto out;
286*4f0ce1daSGordon Ross 
287*4f0ce1daSGordon Ross 	rc = 0;
288*4f0ce1daSGordon Ross out:
289*4f0ce1daSGordon Ross 	free(buf);
290*4f0ce1daSGordon Ross 
291*4f0ce1daSGordon Ross 	return (rc);
2921160dcf7SMatt Barden }
2931160dcf7SMatt Barden 
2941160dcf7SMatt Barden void
smb3_enc_ctx_done(smb_enc_ctx_t * ctxp)295*4f0ce1daSGordon Ross smb3_enc_ctx_done(smb_enc_ctx_t *ctxp)
2961160dcf7SMatt Barden {
297*4f0ce1daSGordon Ross 	if (ctxp->ctx != 0) {
298*4f0ce1daSGordon Ross 		(void) C_CloseSession(ctxp->ctx);
299*4f0ce1daSGordon Ross 		ctxp->ctx = 0;
300*4f0ce1daSGordon Ross 	}
3011160dcf7SMatt Barden }
302