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