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 2018 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 /*
17 * Helper functions for SMB3 encryption 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_encrypt_pkcs.c
23 */
24
25 #include <sys/crypto/api.h>
26 #include <smbsrv/smb_kcrypt.h>
27 #include <smbsrv/smb2_kproto.h>
28 #include <sys/cmn_err.h>
29
30 /*
31 * SMB3 encryption helpers:
32 * (getmech, init, update, final)
33 */
34
35 int
36 smb3_encrypt_getmech(smb_crypto_mech_t *mech)
37 {
38 crypto_mech_type_t t;
39
40 t = crypto_mech2id(SUN_CKM_AES_CCM);
41 if (t == CRYPTO_MECH_INVALID) {
42 cmn_err(CE_NOTE, "smb: no kcf mech: %s", SUN_CKM_AES_CCM);
43 return (-1);
44 }
45 mech->cm_type = t;
46
47 return (0);
48 }
49
50 void
51 smb3_crypto_init_param(smb3_crypto_param_t *param,
52 uint8_t *nonce, size_t noncesize, uint8_t *auth, size_t authsize,
53 size_t datasize)
54 {
55 param->ulMACSize = SMB2_SIG_SIZE;
56 param->ulNonceSize = noncesize;
57 param->nonce = nonce;
58 param->ulDataSize = datasize;
59 param->ulAuthDataSize = authsize;
60 param->authData = auth;
61 }
62
63 /*
64 * Start the KCF session, load the key
65 */
66 static int
67 smb3_crypto_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
68 uint8_t *key, size_t key_len, smb3_crypto_param_t *param,
69 boolean_t is_encrypt)
70 {
71 crypto_key_t ckey;
72 int rv;
73
74 bzero(&ckey, sizeof (ckey));
75 ckey.ck_format = CRYPTO_KEY_RAW;
76 ckey.ck_data = key;
77 ckey.ck_length = key_len * 8; /* in bits */
78
79 mech->cm_param = (caddr_t)param;
80 mech->cm_param_len = sizeof (*param);
182 smb3_encrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *digest16)
183 {
184 crypto_data_t out;
185 int rv;
186 uint8_t buf[SMB2_SIG_SIZE + 16] = {0};
187 size_t outlen;
188
189 bzero(&out, sizeof (out));
190 out.cd_format = CRYPTO_DATA_RAW;
191 out.cd_length = sizeof (buf);
192 out.cd_raw.iov_len = sizeof (buf);
193 out.cd_raw.iov_base = (void *)buf;
194
195 rv = crypto_encrypt_final(ctxp->ctx, &out, 0);
196
197 if (rv != CRYPTO_SUCCESS) {
198 cmn_err(CE_WARN, "crypto_encrypt_final failed: 0x%x", rv);
199 return (-1);
200 }
201
202 outlen = out.cd_offset - SMB2_SIG_SIZE;
203 if (outlen > 0)
204 bcopy(buf, ctxp->output.cd_raw.iov_base +
205 ctxp->output.cd_offset, outlen);
206 bcopy(buf + outlen, digest16, SMB2_SIG_SIZE);
207
208 return (0);
209 }
210
211 int
212 smb3_decrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *buf, size_t buflen)
213 {
214 crypto_data_t out;
215 int rv;
216
217 bzero(&out, sizeof (out));
218 out.cd_format = CRYPTO_DATA_RAW;
219 out.cd_length = buflen;
220 out.cd_raw.iov_len = buflen;
221 out.cd_raw.iov_base = (void *)buf;
222
|
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 2018 Nexenta Systems, Inc. All rights reserved.
14 * Copyright 2020 RackTop Systems, Inc.
15 */
16
17 /*
18 * Helper functions for SMB3 encryption 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_encrypt_pkcs.c
24 */
25
26 #include <sys/crypto/api.h>
27 #include <smbsrv/smb_kcrypt.h>
28 #include <smbsrv/smb2_kproto.h>
29 #include <sys/cmn_err.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, crypto_mech_name_t 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 * SMB3 encryption helpers:
50 * (getmech, init, update, final)
51 */
52
53 int
54 smb3_aes_ccm_getmech(smb_crypto_mech_t *mech)
55 {
56 return (find_mech(mech, SUN_CKM_AES_CCM));
57 }
58
59 int
60 smb3_aes_gcm_getmech(smb_crypto_mech_t *mech)
61 {
62 return (find_mech(mech, SUN_CKM_AES_GCM));
63 }
64
65 void
66 smb3_crypto_init_ccm_param(smb3_crypto_param_t *param,
67 uint8_t *nonce, size_t noncesize, uint8_t *auth, size_t authsize,
68 size_t datasize)
69 {
70 param->ccm.ulMACSize = SMB2_SIG_SIZE;
71 param->ccm.ulNonceSize = noncesize;
72 param->ccm.nonce = nonce;
73 param->ccm.ulDataSize = datasize;
74 param->ccm.ulAuthDataSize = authsize;
75 param->ccm.authData = auth;
76 }
77
78 void
79 smb3_crypto_init_gcm_param(smb3_crypto_param_t *param,
80 uint8_t *nonce, size_t noncesize, uint8_t *auth, size_t authsize)
81 {
82 ASSERT3U(noncesize, ==, 12);
83 param->gcm.pIv = nonce;
84 param->gcm.ulIvLen = noncesize; /* should be 12 bytes */
85 /* tform hdr size - (protcolo id + signing) == 32 bytes */
86 param->gcm.ulTagBits = SMB2_SIG_SIZE << 3; /* convert bytes to bits */
87 param->gcm.pAAD = auth; /* auth data */
88 param->gcm.ulAADLen = authsize; /* auth data len */
89 }
90
91 /*
92 * Start the KCF session, load the key
93 */
94 static int
95 smb3_crypto_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
96 uint8_t *key, size_t key_len, smb3_crypto_param_t *param,
97 boolean_t is_encrypt)
98 {
99 crypto_key_t ckey;
100 int rv;
101
102 bzero(&ckey, sizeof (ckey));
103 ckey.ck_format = CRYPTO_KEY_RAW;
104 ckey.ck_data = key;
105 ckey.ck_length = key_len * 8; /* in bits */
106
107 mech->cm_param = (caddr_t)param;
108 mech->cm_param_len = sizeof (*param);
210 smb3_encrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *digest16)
211 {
212 crypto_data_t out;
213 int rv;
214 uint8_t buf[SMB2_SIG_SIZE + 16] = {0};
215 size_t outlen;
216
217 bzero(&out, sizeof (out));
218 out.cd_format = CRYPTO_DATA_RAW;
219 out.cd_length = sizeof (buf);
220 out.cd_raw.iov_len = sizeof (buf);
221 out.cd_raw.iov_base = (void *)buf;
222
223 rv = crypto_encrypt_final(ctxp->ctx, &out, 0);
224
225 if (rv != CRYPTO_SUCCESS) {
226 cmn_err(CE_WARN, "crypto_encrypt_final failed: 0x%x", rv);
227 return (-1);
228 }
229
230 /*
231 * For some reason AES module processes ccm_encrypt_final and
232 * gcm_encrypt_final differently.
233 * For GCM it restores original offset (which is 0) and updates
234 * cd_length to size of residual data + mac len.
235 * For CCM it does nothing, what means offset is updated and cd_length
236 * is decreased by size of residual data + mac len.
237 */
238 if (out.cd_offset == 0) {
239 /* GCM */
240 outlen = out.cd_length - SMB2_SIG_SIZE;
241 } else {
242 /* CCM */
243 outlen = out.cd_offset - SMB2_SIG_SIZE;
244 }
245
246 if (outlen > 0)
247 bcopy(buf, ctxp->output.cd_raw.iov_base +
248 ctxp->output.cd_offset, outlen);
249 bcopy(buf + outlen, digest16, SMB2_SIG_SIZE);
250
251 return (0);
252 }
253
254 int
255 smb3_decrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *buf, size_t buflen)
256 {
257 crypto_data_t out;
258 int rv;
259
260 bzero(&out, sizeof (out));
261 out.cd_format = CRYPTO_DATA_RAW;
262 out.cd_length = buflen;
263 out.cd_raw.iov_len = buflen;
264 out.cd_raw.iov_base = (void *)buf;
265
|