Print this page
12513 SMB 3.1.1 support for server
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb3_encrypt_kcf.c
+++ new/usr/src/uts/common/fs/smbsrv/smb3_encrypt_kcf.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
14 + * Copyright 2020 RackTop Systems, Inc.
14 15 */
15 16
16 17 /*
17 18 * Helper functions for SMB3 encryption using the
18 19 * Kernel Cryptographic Framework (KCF)
19 20 *
20 21 * There are two implementations of these functions:
21 22 * This one (for kernel) and another for user space:
22 23 * See: lib/smbsrv/libfksmbsrv/common/fksmb_encrypt_pkcs.c
23 24 */
24 25
25 26 #include <sys/crypto/api.h>
26 27 #include <smbsrv/smb_kcrypt.h>
27 28 #include <smbsrv/smb2_kproto.h>
28 29 #include <sys/cmn_err.h>
29 30
30 31 /*
31 - * SMB3 encryption helpers:
32 - * (getmech, init, update, final)
32 + * Common function to see if a mech is available.
33 33 */
34 -
35 -int
36 -smb3_encrypt_getmech(smb_crypto_mech_t *mech)
34 +static int
35 +find_mech(smb_crypto_mech_t *mech, crypto_mech_name_t name)
37 36 {
38 37 crypto_mech_type_t t;
39 38
40 - t = crypto_mech2id(SUN_CKM_AES_CCM);
39 + t = crypto_mech2id(name);
41 40 if (t == CRYPTO_MECH_INVALID) {
42 - cmn_err(CE_NOTE, "smb: no kcf mech: %s", SUN_CKM_AES_CCM);
41 + cmn_err(CE_NOTE, "smb: no kcf mech: %s", name);
43 42 return (-1);
44 43 }
45 44 mech->cm_type = t;
46 -
47 45 return (0);
48 46 }
49 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 +
50 65 void
51 -smb3_crypto_init_param(smb3_crypto_param_t *param,
66 +smb3_crypto_init_ccm_param(smb3_crypto_param_t *param,
52 67 uint8_t *nonce, size_t noncesize, uint8_t *auth, size_t authsize,
53 68 size_t datasize)
54 69 {
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;
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 */
61 89 }
62 90
63 91 /*
64 92 * Start the KCF session, load the key
65 93 */
66 94 static int
67 95 smb3_crypto_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
68 96 uint8_t *key, size_t key_len, smb3_crypto_param_t *param,
69 97 boolean_t is_encrypt)
70 98 {
71 99 crypto_key_t ckey;
72 100 int rv;
73 101
74 102 bzero(&ckey, sizeof (ckey));
75 103 ckey.ck_format = CRYPTO_KEY_RAW;
76 104 ckey.ck_data = key;
77 105 ckey.ck_length = key_len * 8; /* in bits */
78 106
79 107 mech->cm_param = (caddr_t)param;
80 108 mech->cm_param_len = sizeof (*param);
81 109
82 110 if (is_encrypt)
83 111 rv = crypto_encrypt_init(mech, &ckey, NULL, &ctxp->ctx, NULL);
84 112 else
85 113 rv = crypto_decrypt_init(mech, &ckey, NULL, &ctxp->ctx, NULL);
86 114
87 115 if (rv != CRYPTO_SUCCESS) {
88 116 if (is_encrypt)
89 117 cmn_err(CE_WARN,
90 118 "crypto_encrypt_init failed: 0x%x", rv);
91 119 else
92 120 cmn_err(CE_WARN,
93 121 "crypto_decrypt_init failed: 0x%x", rv);
94 122 }
95 123
96 124 return (rv == CRYPTO_SUCCESS ? 0 : -1);
97 125 }
98 126
99 127 int
100 128 smb3_encrypt_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
101 129 smb3_crypto_param_t *param, uint8_t *key, size_t keylen,
102 130 uint8_t *buf, size_t buflen)
103 131 {
104 132
105 133 bzero(&ctxp->output, sizeof (ctxp->output));
106 134 ctxp->output.cd_format = CRYPTO_DATA_RAW;
107 135 ctxp->output.cd_length = buflen;
108 136 ctxp->output.cd_raw.iov_len = buflen;
109 137 ctxp->output.cd_raw.iov_base = (void *)buf;
110 138
111 139 return (smb3_crypto_init(ctxp, mech, key, keylen,
112 140 param, B_TRUE));
113 141 }
114 142
115 143 int
116 144 smb3_decrypt_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech,
117 145 smb3_crypto_param_t *param, uint8_t *key, size_t keylen)
118 146 {
119 147 return (smb3_crypto_init(ctxp, mech, key, keylen,
120 148 param, B_FALSE));
121 149 }
122 150
123 151 /*
124 152 * Digest one segment
125 153 */
126 154 int
127 155 smb3_encrypt_update(smb3_enc_ctx_t *ctxp, uint8_t *in, size_t len)
128 156 {
129 157 crypto_data_t data;
130 158 int rv;
131 159
132 160 bzero(&data, sizeof (data));
133 161 data.cd_format = CRYPTO_DATA_RAW;
134 162 data.cd_length = len;
135 163 data.cd_raw.iov_base = (void *)in;
136 164 data.cd_raw.iov_len = len;
137 165
138 166 rv = crypto_encrypt_update(ctxp->ctx, &data, &ctxp->output, NULL);
139 167
140 168 if (rv != CRYPTO_SUCCESS) {
141 169 cmn_err(CE_WARN, "crypto_encrypt_update failed: 0x%x", rv);
142 170 crypto_cancel_ctx(ctxp->ctx);
143 171 return (-1);
144 172 }
145 173
146 174 len = ctxp->output.cd_length;
147 175 ctxp->len -= len;
148 176 ctxp->output.cd_offset += len;
149 177 ctxp->output.cd_length = ctxp->len;
150 178
151 179 return (0);
152 180 }
153 181
154 182 int
155 183 smb3_decrypt_update(smb3_enc_ctx_t *ctxp, uint8_t *in, size_t len)
156 184 {
157 185 crypto_data_t data;
158 186 int rv;
159 187
160 188 bzero(&data, sizeof (data));
161 189 data.cd_format = CRYPTO_DATA_RAW;
162 190 data.cd_length = len;
163 191 data.cd_raw.iov_base = (void *)in;
164 192 data.cd_raw.iov_len = len;
165 193
166 194 /*
167 195 * AES_CCM does not output data until decrypt_final,
168 196 * and only does so if the signature matches.
169 197 */
170 198 rv = crypto_decrypt_update(ctxp->ctx, &data, NULL, NULL);
171 199
172 200 if (rv != CRYPTO_SUCCESS) {
173 201 cmn_err(CE_WARN, "crypto_decrypt_update failed: 0x%x", rv);
174 202 crypto_cancel_ctx(ctxp->ctx);
175 203 return (-1);
176 204 }
177 205
178 206 return (0);
179 207 }
180 208
181 209 int
182 210 smb3_encrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *digest16)
183 211 {
184 212 crypto_data_t out;
185 213 int rv;
186 214 uint8_t buf[SMB2_SIG_SIZE + 16] = {0};
187 215 size_t outlen;
188 216
189 217 bzero(&out, sizeof (out));
190 218 out.cd_format = CRYPTO_DATA_RAW;
191 219 out.cd_length = sizeof (buf);
↓ open down ↓ |
121 lines elided |
↑ open up ↑ |
192 220 out.cd_raw.iov_len = sizeof (buf);
193 221 out.cd_raw.iov_base = (void *)buf;
194 222
195 223 rv = crypto_encrypt_final(ctxp->ctx, &out, 0);
196 224
197 225 if (rv != CRYPTO_SUCCESS) {
198 226 cmn_err(CE_WARN, "crypto_encrypt_final failed: 0x%x", rv);
199 227 return (-1);
200 228 }
201 229
202 - outlen = out.cd_offset - SMB2_SIG_SIZE;
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 +
203 246 if (outlen > 0)
204 247 bcopy(buf, ctxp->output.cd_raw.iov_base +
205 248 ctxp->output.cd_offset, outlen);
206 249 bcopy(buf + outlen, digest16, SMB2_SIG_SIZE);
207 250
208 251 return (0);
209 252 }
210 253
211 254 int
212 255 smb3_decrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *buf, size_t buflen)
213 256 {
214 257 crypto_data_t out;
215 258 int rv;
216 259
217 260 bzero(&out, sizeof (out));
218 261 out.cd_format = CRYPTO_DATA_RAW;
219 262 out.cd_length = buflen;
220 263 out.cd_raw.iov_len = buflen;
221 264 out.cd_raw.iov_base = (void *)buf;
222 265
223 266 rv = crypto_decrypt_final(ctxp->ctx, &out, NULL);
224 267
225 268 if (rv != CRYPTO_SUCCESS)
226 269 cmn_err(CE_WARN, "crypto_decrypt_final failed: 0x%x", rv);
227 270
228 271 return (rv == CRYPTO_SUCCESS ? 0 : -1);
229 272 }
230 273
231 274 void
232 275 smb3_encrypt_cancel(smb3_enc_ctx_t *ctxp)
233 276 {
234 277 crypto_cancel_ctx(ctxp->ctx);
235 278 }
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX