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");
674e065a9fSAlexander Stetsenko return (-1);
684e065a9fSAlexander Stetsenko }
694e065a9fSAlexander Stetsenko
70*4f0ce1daSGordon Ross mech->mechanism = CKM_AES_CCM;
71*4f0ce1daSGordon Ross return (0);
72*4f0ce1daSGordon Ross }
73*4f0ce1daSGordon Ross
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");
801160dcf7SMatt Barden return (-1);
811160dcf7SMatt Barden }
821160dcf7SMatt Barden
83*4f0ce1daSGordon Ross mech->mechanism = CKM_AES_GCM;
84*4f0ce1daSGordon Ross return (0);
85*4f0ce1daSGordon Ross }
86*4f0ce1daSGordon Ross
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 {
113*4f0ce1daSGordon Ross
114*4f0ce1daSGordon Ross ASSERT3U(noncesize, >=, SMB3_AES_GCM_NONCE_SIZE);
115*4f0ce1daSGordon Ross
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 */
122*4f0ce1daSGordon Ross
123*4f0ce1daSGordon Ross ctx->mech.pParameter = (caddr_t)&ctx->param.gcm;
124*4f0ce1daSGordon Ross ctx->mech.ulParameterLen = sizeof (ctx->param.gcm);
1254e065a9fSAlexander Stetsenko }
1264e065a9fSAlexander Stetsenko
1271160dcf7SMatt Barden /*
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.
1321160dcf7SMatt Barden */
133*4f0ce1daSGordon Ross 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)
1431160dcf7SMatt Barden return (-1);
1441160dcf7SMatt Barden
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);
1491160dcf7SMatt Barden
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;
172*4f0ce1daSGordon Ross
173*4f0ce1daSGordon Ross rv = SUNW_C_GetMechSession(mech->mechanism, &ctxp->ctx);
174*4f0ce1daSGordon Ross if (rv != CKR_OK)
1751160dcf7SMatt Barden 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)
2101160dcf7SMatt Barden 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;
2331160dcf7SMatt Barden }
2341160dcf7SMatt Barden
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)
2571160dcf7SMatt Barden 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;
2801160dcf7SMatt Barden }
2811160dcf7SMatt Barden
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);
292*4f0ce1daSGordon Ross }
293*4f0ce1daSGordon Ross
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