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 2018-2021 Tintri by DDN, Inc. All rights reserved.
14  * Copyright 2022 RackTop Systems, Inc.
15  */
16 
17 /*
18  * Helper functions for SMB3 encryption using the
19  * Kernel Cryptographic Framework (KCF)
20  *
21  * There are two implementations of these functions:
22  * This one (for kernel) and another for user space:
23  * See: lib/smbsrv/libfksmbsrv/common/fksmb_encrypt_pkcs.c
24  *
25  * Contrary to what one might assume from the file name,
26  * there should be NO SMB implementation knowledge here
27  * beyond a few carefully selected things (smb_kcrypt.h).
28  */
29 
30 #include <sys/crypto/api.h>
31 #include <smbsrv/smb_kcrypt.h>
32 #include <sys/systm.h>
33 #include <sys/cmn_err.h>
34 
35 /*
36  * Common function to see if a mech is available.
37  */
38 static int
find_mech(smb_crypto_mech_t * mech,const char * name)39 find_mech(smb_crypto_mech_t *mech, const char *name)
40 {
41 	crypto_mech_type_t t;
42 
43 	t = crypto_mech2id(name);
44 	if (t == CRYPTO_MECH_INVALID) {
45 		cmn_err(CE_NOTE, "smb: no kcf mech: %s", name);
46 		return (-1);
47 	}
48 	mech->cm_type = t;
49 	return (0);
50 }
51 
52 /*
53  * SMB3 encryption helpers:
54  * (getmech, init, update, final)
55  */
56 
57 int
smb3_aes_ccm_getmech(smb_crypto_mech_t * mech)58 smb3_aes_ccm_getmech(smb_crypto_mech_t *mech)
59 {
60 	return (find_mech(mech, SUN_CKM_AES_CCM));
61 }
62 
63 int
smb3_aes_gcm_getmech(smb_crypto_mech_t * mech)64 smb3_aes_gcm_getmech(smb_crypto_mech_t *mech)
65 {
66 	return (find_mech(mech, SUN_CKM_AES_GCM));
67 }
68 
69 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)70 smb3_crypto_init_ccm_param(smb_enc_ctx_t *ctx,
71     uint8_t *nonce, size_t noncesize,
72     uint8_t *auth, size_t authsize,
73     size_t datasize)
74 {
75 
76 	ASSERT3U(noncesize, >=, SMB3_AES_CCM_NONCE_SIZE);
77 
78 	ctx->param.ccm.ulMACSize = SMB2_SIG_SIZE;
79 	ctx->param.ccm.ulNonceSize = SMB3_AES_CCM_NONCE_SIZE;
80 	ctx->param.ccm.nonce = nonce;
81 	ctx->param.ccm.ulDataSize = datasize;
82 	ctx->param.ccm.ulAuthDataSize = authsize;
83 	ctx->param.ccm.authData = auth;
84 
85 	ctx->mech.cm_param = (caddr_t)&ctx->param.ccm;
86 	ctx->mech.cm_param_len = sizeof (ctx->param.ccm);
87 }
88 
89 void
smb3_crypto_init_gcm_param(smb_enc_ctx_t * ctx,uint8_t * nonce,size_t noncesize,uint8_t * auth,size_t authsize)90 smb3_crypto_init_gcm_param(smb_enc_ctx_t *ctx,
91     uint8_t *nonce, size_t noncesize,
92     uint8_t *auth, size_t authsize)
93 {
94 
95 	ASSERT3U(noncesize, >=, SMB3_AES_GCM_NONCE_SIZE);
96 
97 	ctx->param.gcm.pIv = nonce;
98 	ctx->param.gcm.ulIvLen = SMB3_AES_GCM_NONCE_SIZE;
99 	ctx->param.gcm.ulTagBits = SMB2_SIG_SIZE << 3;	/* bytes to bits */
100 	ctx->param.gcm.pAAD = auth;			/* auth data */
101 	ctx->param.gcm.ulAADLen = authsize;		/* auth data len */
102 
103 	ctx->mech.cm_param = (caddr_t)&ctx->param.gcm;
104 	ctx->mech.cm_param_len = sizeof (ctx->param.gcm);
105 }
106 
107 /*
108  * KCF doesn't need anything to happen in this call, but
109  * wants that key when we call encrypt or decrypt, so
110  * just stash the key here.
111  *
112  * Todo: clone crypto context template here?
113  */
114 int
smb3_encrypt_init(smb_enc_ctx_t * ctxp,uint8_t * key,size_t keylen)115 smb3_encrypt_init(smb_enc_ctx_t *ctxp,
116     uint8_t *key, size_t keylen)
117 {
118 
119 	bzero(&ctxp->ckey, sizeof (ctxp->ckey));
120 	ctxp->ckey.ck_format = CRYPTO_KEY_RAW;
121 	ctxp->ckey.ck_data = key;
122 	ctxp->ckey.ck_length = keylen * 8; /* in bits */
123 
124 	return (0);
125 }
126 
127 int
smb3_decrypt_init(smb_enc_ctx_t * ctxp,uint8_t * key,size_t keylen)128 smb3_decrypt_init(smb_enc_ctx_t *ctxp,
129     uint8_t *key, size_t keylen)
130 {
131 
132 	bzero(&ctxp->ckey, sizeof (ctxp->ckey));
133 	ctxp->ckey.ck_format = CRYPTO_KEY_RAW;
134 	ctxp->ckey.ck_data = key;
135 	ctxp->ckey.ck_length = keylen * 8; /* in bits */
136 
137 	return (0);
138 }
139 
140 /*
141  * Encrypt a whole message with scatter/gather (UIO)
142  */
143 int
smb3_encrypt_uio(smb_enc_ctx_t * ctxp,uio_t * in_uio,uio_t * out_uio)144 smb3_encrypt_uio(smb_enc_ctx_t *ctxp, uio_t *in_uio, uio_t *out_uio)
145 {
146 	crypto_ctx_template_t tmpl = NULL;	// todo
147 	crypto_data_t in_cd, out_cd;
148 	int rv;
149 
150 	bzero(&in_cd, sizeof (crypto_data_t));
151 	in_cd.cd_format = CRYPTO_DATA_UIO;
152 	in_cd.cd_length = in_uio->uio_resid;
153 	in_cd.cd_uio = in_uio;
154 
155 	bzero(&out_cd, sizeof (crypto_data_t));
156 	out_cd.cd_format = CRYPTO_DATA_UIO;
157 	out_cd.cd_length = out_uio->uio_resid;
158 	out_cd.cd_uio = out_uio;
159 
160 	rv = crypto_encrypt(&ctxp->mech, &in_cd,
161 	    &ctxp->ckey, tmpl, &out_cd, NULL);
162 	if (rv != CRYPTO_SUCCESS) {
163 		cmn_err(CE_WARN, "crypto_encrypt failed: 0x%x", rv);
164 		return (-1);
165 	}
166 
167 	return (0);
168 }
169 
170 /*
171  * Decrypt a whole message with scatter/gather (UIO)
172  */
173 int
smb3_decrypt_uio(smb_enc_ctx_t * ctxp,uio_t * in_uio,uio_t * out_uio)174 smb3_decrypt_uio(smb_enc_ctx_t *ctxp, uio_t *in_uio, uio_t *out_uio)
175 {
176 	crypto_ctx_template_t tmpl = NULL;	// todo
177 	crypto_data_t in_cd, out_cd;
178 	int rv;
179 
180 	/* In is ciphertext */
181 	bzero(&in_cd, sizeof (crypto_data_t));
182 	in_cd.cd_format = CRYPTO_DATA_UIO;
183 	in_cd.cd_length = in_uio->uio_resid;
184 	in_cd.cd_uio = in_uio;
185 
186 	/* Out is plaintext */
187 	bzero(&out_cd, sizeof (crypto_data_t));
188 	out_cd.cd_format = CRYPTO_DATA_UIO;
189 	out_cd.cd_length = out_uio->uio_resid;
190 	out_cd.cd_uio = out_uio;
191 
192 	rv = crypto_decrypt(&ctxp->mech, &in_cd,
193 	    &ctxp->ckey, tmpl, &out_cd, NULL);
194 	if (rv != CRYPTO_SUCCESS) {
195 		cmn_err(CE_WARN, "crypto_decrypt failed: 0x%x", rv);
196 		return (-1);
197 	}
198 
199 	return (0);
200 }
201 
202 void
smb3_enc_ctx_done(smb_enc_ctx_t * ctxp)203 smb3_enc_ctx_done(smb_enc_ctx_t *ctxp)
204 {
205 	crypto_cancel_ctx(ctxp->ctx);
206 }
207