xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_sign_kcf.c (revision a4568e19224dbd8e405999c57ff8d4e4fd0d877f)
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 2017 Nexenta Systems, Inc.  All rights reserved.
14  * Copyright 2022 RackTop Systems, Inc.
15  */
16 
17 /*
18  * Helper functions for SMB signing 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_sign_pkcs.c
24  */
25 
26 #include <sys/types.h>
27 #include <sys/kmem.h>
28 #include <sys/crypto/api.h>
29 #include <smbsrv/smb_kproto.h>
30 #include <smbsrv/smb_kcrypt.h>
31 
32 /*
33  * Common function to see if a mech is available.
34  */
35 static int
find_mech(smb_crypto_mech_t * mech,const char * name)36 find_mech(smb_crypto_mech_t *mech, const char *name)
37 {
38 	crypto_mech_type_t t;
39 
40 	t = crypto_mech2id(name);
41 	if (t == CRYPTO_MECH_INVALID) {
42 		cmn_err(CE_NOTE, "smb: no kcf mech: %s", name);
43 		return (-1);
44 	}
45 	mech->cm_type = t;
46 	return (0);
47 }
48 
49 /*
50  * SMB1 signing helpers:
51  * (getmech, init, update, final)
52  */
53 
54 int
smb_md5_getmech(smb_crypto_mech_t * mech)55 smb_md5_getmech(smb_crypto_mech_t *mech)
56 {
57 	return (find_mech(mech, SUN_CKM_MD5));
58 }
59 
60 /*
61  * Start the KCF session, load the key
62  */
63 int
smb_md5_init(smb_sign_ctx_t * ctxp,smb_crypto_mech_t * mech)64 smb_md5_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech)
65 {
66 	int rv;
67 
68 	rv = crypto_digest_init(mech, ctxp, NULL);
69 
70 	return (rv == CRYPTO_SUCCESS ? 0 : -1);
71 }
72 
73 /*
74  * Digest one segment
75  */
76 int
smb_md5_update(smb_sign_ctx_t ctx,void * buf,size_t len)77 smb_md5_update(smb_sign_ctx_t ctx, void *buf, size_t len)
78 {
79 	crypto_data_t data;
80 	int rv;
81 
82 	bzero(&data, sizeof (data));
83 	data.cd_format = CRYPTO_DATA_RAW;
84 	data.cd_length = len;
85 	data.cd_raw.iov_base = buf;
86 	data.cd_raw.iov_len = len;
87 
88 	rv = crypto_digest_update(ctx, &data, 0);
89 
90 	if (rv != CRYPTO_SUCCESS) {
91 		crypto_cancel_ctx(ctx);
92 		return (-1);
93 	}
94 
95 	return (0);
96 }
97 
98 /*
99  * Get the final digest.
100  */
101 int
smb_md5_final(smb_sign_ctx_t ctx,uint8_t * digest16)102 smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16)
103 {
104 	crypto_data_t out;
105 	int rv;
106 
107 	bzero(&out, sizeof (out));
108 	out.cd_format = CRYPTO_DATA_RAW;
109 	out.cd_length = MD5_DIGEST_LENGTH;
110 	out.cd_raw.iov_len = MD5_DIGEST_LENGTH;
111 	out.cd_raw.iov_base = (void *)digest16;
112 
113 	rv = crypto_digest_final(ctx, &out, 0);
114 
115 	return (rv == CRYPTO_SUCCESS ? 0 : -1);
116 }
117 
118 /*
119  * SMB2 signing helpers:
120  * (getmech, init, update, final)
121  */
122 
123 int
smb2_hmac_getmech(smb_crypto_mech_t * mech)124 smb2_hmac_getmech(smb_crypto_mech_t *mech)
125 {
126 	return (find_mech(mech, SUN_CKM_SHA256_HMAC));
127 }
128 
129 /*
130  * Start the KCF session, load the key
131  */
132 int
smb2_hmac_init(smb_sign_ctx_t * ctxp,smb_crypto_mech_t * mech,uint8_t * key,size_t key_len)133 smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech,
134     uint8_t *key, size_t key_len)
135 {
136 	crypto_key_t ckey;
137 	int rv;
138 
139 	bzero(&ckey, sizeof (ckey));
140 	ckey.ck_format = CRYPTO_KEY_RAW;
141 	ckey.ck_data = key;
142 	ckey.ck_length = key_len * 8; /* in bits */
143 
144 	rv = crypto_mac_init(mech, &ckey, NULL, ctxp, NULL);
145 
146 	return (rv == CRYPTO_SUCCESS ? 0 : -1);
147 }
148 
149 /*
150  * Digest one segment
151  */
152 int
smb2_hmac_update(smb_sign_ctx_t ctx,uint8_t * in,size_t len)153 smb2_hmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
154 {
155 	crypto_data_t data;
156 	int rv;
157 
158 	bzero(&data, sizeof (data));
159 	data.cd_format = CRYPTO_DATA_RAW;
160 	data.cd_length = len;
161 	data.cd_raw.iov_base = (void *)in;
162 	data.cd_raw.iov_len = len;
163 
164 	rv = crypto_mac_update(ctx, &data, 0);
165 
166 	if (rv != CRYPTO_SUCCESS) {
167 		crypto_cancel_ctx(ctx);
168 		return (-1);
169 	}
170 
171 	return (0);
172 }
173 
174 /*
175  * Note, the SMB2 signature is the first 16 bytes of the
176  * 32-byte SHA256 HMAC digest.  This is specifically for
177  * SMB2 signing, and NOT a generic HMAC function.
178  */
179 int
smb2_hmac_final(smb_sign_ctx_t ctx,uint8_t * digest16)180 smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
181 {
182 	uint8_t full_digest[SHA256_DIGEST_LENGTH];
183 	crypto_data_t out;
184 	int rv;
185 
186 	bzero(&out, sizeof (out));
187 	out.cd_format = CRYPTO_DATA_RAW;
188 	out.cd_length = SHA256_DIGEST_LENGTH;
189 	out.cd_raw.iov_len = SHA256_DIGEST_LENGTH;
190 	out.cd_raw.iov_base = (void *)full_digest;
191 
192 	rv = crypto_mac_final(ctx, &out, 0);
193 	if (rv == CRYPTO_SUCCESS)
194 		bcopy(full_digest, digest16, 16);
195 
196 	return (rv == CRYPTO_SUCCESS ? 0 : -1);
197 }
198 
199 /*
200  * One-shot HMAC function used in smb3_kdf
201  */
202 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)203 smb2_hmac_one(smb_crypto_mech_t *mech,
204     uint8_t *key, size_t key_len,
205     uint8_t *data, size_t data_len,
206     uint8_t *mac, size_t mac_len)
207 {
208 	crypto_key_t ckey;
209 	crypto_data_t cdata;
210 	crypto_data_t cmac;
211 	int rv;
212 
213 	bzero(&ckey, sizeof (ckey));
214 	ckey.ck_format = CRYPTO_KEY_RAW;
215 	ckey.ck_data = key;
216 	ckey.ck_length = key_len * 8; /* in bits */
217 
218 	bzero(&cdata, sizeof (cdata));
219 	cdata.cd_format = CRYPTO_DATA_RAW;
220 	cdata.cd_length = data_len;
221 	cdata.cd_raw.iov_base = (void *)data;
222 	cdata.cd_raw.iov_len = data_len;
223 
224 	bzero(&cmac, sizeof (cmac));
225 	cmac.cd_format = CRYPTO_DATA_RAW;
226 	cmac.cd_length = mac_len;
227 	cmac.cd_raw.iov_base = (void *)mac;
228 	cmac.cd_raw.iov_len = mac_len;
229 
230 	rv = crypto_mac(mech, &cdata, &ckey, NULL, &cmac, NULL);
231 
232 	return (rv == CRYPTO_SUCCESS ? 0 : -1);
233 }
234 
235 /*
236  * SMB3 signing helpers:
237  * (getmech, init, update, final)
238  */
239 
240 int
smb3_cmac_getmech(smb_crypto_mech_t * mech)241 smb3_cmac_getmech(smb_crypto_mech_t *mech)
242 {
243 	return (find_mech(mech, SUN_CKM_AES_CMAC));
244 }
245 
246 /*
247  * Start the KCF session, load the key
248  */
249 int
smb3_cmac_init(smb_sign_ctx_t * ctxp,smb_crypto_mech_t * mech,uint8_t * key,size_t key_len)250 smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech,
251     uint8_t *key, size_t key_len)
252 {
253 	crypto_key_t ckey;
254 	int rv;
255 
256 	bzero(&ckey, sizeof (ckey));
257 	ckey.ck_format = CRYPTO_KEY_RAW;
258 	ckey.ck_data = key;
259 	ckey.ck_length = key_len * 8; /* in bits */
260 
261 	rv = crypto_mac_init(mech, &ckey, NULL, ctxp, NULL);
262 
263 	return (rv == CRYPTO_SUCCESS ? 0 : -1);
264 }
265 
266 /*
267  * Digest one segment
268  */
269 int
smb3_cmac_update(smb_sign_ctx_t ctx,uint8_t * in,size_t len)270 smb3_cmac_update(smb_sign_ctx_t ctx, uint8_t *in, size_t len)
271 {
272 	crypto_data_t data;
273 	int rv;
274 
275 	bzero(&data, sizeof (data));
276 	data.cd_format = CRYPTO_DATA_RAW;
277 	data.cd_length = len;
278 	data.cd_raw.iov_base = (void *)in;
279 	data.cd_raw.iov_len = len;
280 
281 	rv = crypto_mac_update(ctx, &data, 0);
282 
283 	if (rv != CRYPTO_SUCCESS) {
284 		crypto_cancel_ctx(ctx);
285 		return (-1);
286 	}
287 
288 	return (0);
289 }
290 
291 /*
292  * Note, the SMB2 signature is just the AES CMAC digest.
293  * (both are 16 bytes long)
294  */
295 int
smb3_cmac_final(smb_sign_ctx_t ctx,uint8_t * digest16)296 smb3_cmac_final(smb_sign_ctx_t ctx, uint8_t *digest16)
297 {
298 	crypto_data_t out;
299 	int rv;
300 
301 	bzero(&out, sizeof (out));
302 	out.cd_format = CRYPTO_DATA_RAW;
303 	out.cd_length = SMB2_SIG_SIZE;
304 	out.cd_raw.iov_len = SMB2_SIG_SIZE;
305 	out.cd_raw.iov_base = (void *)digest16;
306 
307 	rv = crypto_mac_final(ctx, &out, 0);
308 
309 	return (rv == CRYPTO_SUCCESS ? 0 : -1);
310 }
311