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