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