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);
81
82 if (is_encrypt)
83 rv = crypto_encrypt_init(mech, &ckey, NULL, &ctxp->ctx, NULL);
84 else
85 rv = crypto_decrypt_init(mech, &ckey, NULL, &ctxp->ctx, NULL);
86
87 if (rv != CRYPTO_SUCCESS) {
88 if (is_encrypt)
89 cmn_err(CE_WARN,
90 "crypto_encrypt_init failed: 0x%x", rv);
91 else
92 cmn_err(CE_WARN,
93 "crypto_decrypt_init failed: 0x%x", rv);
94 }
95
96 return (rv == CRYPTO_SUCCESS ? 0 : -1);
97 }
98
99 int
100 smb3_encrypt_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
101 smb3_crypto_param_t *param, uint8_t *key, size_t keylen,
102 uint8_t *buf, size_t buflen)
103 {
104
105 bzero(&ctxp->output, sizeof (ctxp->output));
106 ctxp->output.cd_format = CRYPTO_DATA_RAW;
107 ctxp->output.cd_length = buflen;
108 ctxp->output.cd_raw.iov_len = buflen;
109 ctxp->output.cd_raw.iov_base = (void *)buf;
110
111 return (smb3_crypto_init(ctxp, mech, key, keylen,
112 param, B_TRUE));
113 }
114
115 int
116 smb3_decrypt_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
117 smb3_crypto_param_t *param, uint8_t *key, size_t keylen)
118 {
119 return (smb3_crypto_init(ctxp, mech, key, keylen,
120 param, B_FALSE));
121 }
122
123 /*
124 * Digest one segment
125 */
126 int
127 smb3_encrypt_update(smb3_enc_ctx_t *ctxp, uint8_t *in, size_t len)
128 {
129 crypto_data_t data;
130 int rv;
131
132 bzero(&data, sizeof (data));
133 data.cd_format = CRYPTO_DATA_RAW;
134 data.cd_length = len;
135 data.cd_raw.iov_base = (void *)in;
136 data.cd_raw.iov_len = len;
137
138 rv = crypto_encrypt_update(ctxp->ctx, &data, &ctxp->output, NULL);
139
140 if (rv != CRYPTO_SUCCESS) {
141 cmn_err(CE_WARN, "crypto_encrypt_update failed: 0x%x", rv);
142 crypto_cancel_ctx(ctxp->ctx);
143 return (-1);
144 }
145
146 len = ctxp->output.cd_length;
147 ctxp->len -= len;
148 ctxp->output.cd_offset += len;
149 ctxp->output.cd_length = ctxp->len;
150
151 return (0);
152 }
153
154 int
155 smb3_decrypt_update(smb3_enc_ctx_t *ctxp, uint8_t *in, size_t len)
156 {
157 crypto_data_t data;
158 int rv;
159
160 bzero(&data, sizeof (data));
161 data.cd_format = CRYPTO_DATA_RAW;
162 data.cd_length = len;
163 data.cd_raw.iov_base = (void *)in;
164 data.cd_raw.iov_len = len;
165
166 /*
167 * AES_CCM does not output data until decrypt_final,
168 * and only does so if the signature matches.
169 */
170 rv = crypto_decrypt_update(ctxp->ctx, &data, NULL, NULL);
171
172 if (rv != CRYPTO_SUCCESS) {
173 cmn_err(CE_WARN, "crypto_decrypt_update failed: 0x%x", rv);
174 crypto_cancel_ctx(ctxp->ctx);
175 return (-1);
176 }
177
178 return (0);
179 }
180
181 int
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
223 rv = crypto_decrypt_final(ctxp->ctx, &out, NULL);
224
225 if (rv != CRYPTO_SUCCESS)
226 cmn_err(CE_WARN, "crypto_decrypt_final failed: 0x%x", rv);
227
228 return (rv == CRYPTO_SUCCESS ? 0 : -1);
229 }
230
231 void
232 smb3_encrypt_cancel(smb3_enc_ctx_t *ctxp)
233 {
234 crypto_cancel_ctx(ctxp->ctx);
235 }