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