]>
Commit | Line | Data |
---|---|---|
929be906 | 1 | // SPDX-License-Identifier: LGPL-2.1 |
2dc7e1c0 | 2 | /* |
2dc7e1c0 PS |
3 | * |
4 | * Copyright (C) International Business Machines Corp., 2002, 2011 | |
5 | * Etersoft, 2012 | |
6 | * Author(s): Steve French (sfrench@us.ibm.com) | |
7 | * Jeremy Allison (jra@samba.org) 2006 | |
8 | * Pavel Shilovsky (pshilovsky@samba.org) 2012 | |
9 | * | |
2dc7e1c0 PS |
10 | */ |
11 | ||
12 | #include <linux/fs.h> | |
13 | #include <linux/list.h> | |
14 | #include <linux/wait.h> | |
15 | #include <linux/net.h> | |
16 | #include <linux/delay.h> | |
17 | #include <linux/uaccess.h> | |
18 | #include <asm/processor.h> | |
19 | #include <linux/mempool.h> | |
fb308a6f | 20 | #include <linux/highmem.h> |
026e93dc | 21 | #include <crypto/aead.h> |
2dc7e1c0 PS |
22 | #include "smb2pdu.h" |
23 | #include "cifsglob.h" | |
24 | #include "cifsproto.h" | |
25 | #include "smb2proto.h" | |
26 | #include "cifs_debug.h" | |
27 | #include "smb2status.h" | |
3c1bf7e4 PS |
28 | #include "smb2glob.h" |
29 | ||
95dc8dd1 SF |
30 | static int |
31 | smb3_crypto_shash_allocate(struct TCP_Server_Info *server) | |
32 | { | |
82fb82be | 33 | struct cifs_secmech *p = &server->secmech; |
95dc8dd1 SF |
34 | int rc; |
35 | ||
82fb82be AA |
36 | rc = cifs_alloc_hash("hmac(sha256)", |
37 | &p->hmacsha256, | |
38 | &p->sdeschmacsha256); | |
95dc8dd1 | 39 | if (rc) |
82fb82be | 40 | goto err; |
95dc8dd1 | 41 | |
82fb82be AA |
42 | rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes); |
43 | if (rc) | |
44 | goto err; | |
95dc8dd1 SF |
45 | |
46 | return 0; | |
82fb82be AA |
47 | err: |
48 | cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256); | |
49 | return rc; | |
95dc8dd1 SF |
50 | } |
51 | ||
5fcd7f3f AA |
52 | int |
53 | smb311_crypto_shash_allocate(struct TCP_Server_Info *server) | |
54 | { | |
55 | struct cifs_secmech *p = &server->secmech; | |
56 | int rc = 0; | |
57 | ||
58 | rc = cifs_alloc_hash("hmac(sha256)", | |
59 | &p->hmacsha256, | |
60 | &p->sdeschmacsha256); | |
61 | if (rc) | |
62 | return rc; | |
63 | ||
64 | rc = cifs_alloc_hash("cmac(aes)", &p->cmacaes, &p->sdesccmacaes); | |
65 | if (rc) | |
66 | goto err; | |
67 | ||
68 | rc = cifs_alloc_hash("sha512", &p->sha512, &p->sdescsha512); | |
69 | if (rc) | |
70 | goto err; | |
71 | ||
72 | return 0; | |
73 | ||
74 | err: | |
75 | cifs_free_hash(&p->cmacaes, &p->sdesccmacaes); | |
76 | cifs_free_hash(&p->hmacsha256, &p->sdeschmacsha256); | |
77 | return rc; | |
78 | } | |
5fcd7f3f | 79 | |
d70e9fa5 AA |
80 | |
81 | static | |
82 | int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) | |
83 | { | |
84 | struct cifs_chan *chan; | |
85 | struct cifs_ses *ses = NULL; | |
cc95b677 | 86 | struct TCP_Server_Info *it = NULL; |
d70e9fa5 AA |
87 | int i; |
88 | int rc = 0; | |
89 | ||
90 | spin_lock(&cifs_tcp_ses_lock); | |
91 | ||
cc95b677 AA |
92 | list_for_each_entry(it, &cifs_tcp_ses_list, tcp_ses_list) { |
93 | list_for_each_entry(ses, &it->smb_ses_list, smb_ses_list) { | |
d70e9fa5 AA |
94 | if (ses->Suid == ses_id) |
95 | goto found; | |
96 | } | |
97 | } | |
98 | cifs_server_dbg(VFS, "%s: Could not find session 0x%llx\n", | |
99 | __func__, ses_id); | |
100 | rc = -ENOENT; | |
101 | goto out; | |
102 | ||
103 | found: | |
104 | if (ses->binding) { | |
105 | /* | |
106 | * If we are in the process of binding a new channel | |
107 | * to an existing session, use the master connection | |
108 | * session key | |
109 | */ | |
110 | memcpy(key, ses->smb3signingkey, SMB3_SIGN_KEY_SIZE); | |
111 | goto out; | |
112 | } | |
113 | ||
114 | /* | |
115 | * Otherwise, use the channel key. | |
116 | */ | |
117 | ||
118 | for (i = 0; i < ses->chan_count; i++) { | |
119 | chan = ses->chans + i; | |
120 | if (chan->server == server) { | |
121 | memcpy(key, chan->signkey, SMB3_SIGN_KEY_SIZE); | |
122 | goto out; | |
123 | } | |
124 | } | |
125 | ||
126 | cifs_dbg(VFS, | |
127 | "%s: Could not find channel signing key for session 0x%llx\n", | |
128 | __func__, ses_id); | |
129 | rc = -ENOENT; | |
130 | ||
131 | out: | |
132 | spin_unlock(&cifs_tcp_ses_lock); | |
133 | return rc; | |
134 | } | |
135 | ||
38bd4906 SP |
136 | static struct cifs_ses * |
137 | smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) | |
32811d24 SP |
138 | { |
139 | struct cifs_ses *ses; | |
140 | ||
32811d24 | 141 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
026e93dc | 142 | if (ses->Suid != ses_id) |
32811d24 | 143 | continue; |
e695a9ad | 144 | ++ses->ses_count; |
32811d24 SP |
145 | return ses; |
146 | } | |
38bd4906 SP |
147 | |
148 | return NULL; | |
149 | } | |
150 | ||
151 | struct cifs_ses * | |
152 | smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id) | |
153 | { | |
154 | struct cifs_ses *ses; | |
155 | ||
156 | spin_lock(&cifs_tcp_ses_lock); | |
157 | ses = smb2_find_smb_ses_unlocked(server, ses_id); | |
32811d24 SP |
158 | spin_unlock(&cifs_tcp_ses_lock); |
159 | ||
38bd4906 SP |
160 | return ses; |
161 | } | |
162 | ||
163 | static struct cifs_tcon * | |
164 | smb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32 tid) | |
165 | { | |
166 | struct cifs_tcon *tcon; | |
167 | ||
168 | list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { | |
169 | if (tcon->tid != tid) | |
170 | continue; | |
171 | ++tcon->tc_count; | |
172 | return tcon; | |
173 | } | |
174 | ||
32811d24 SP |
175 | return NULL; |
176 | } | |
177 | ||
38bd4906 SP |
178 | /* |
179 | * Obtain tcon corresponding to the tid in the given | |
180 | * cifs_ses | |
181 | */ | |
182 | ||
183 | struct cifs_tcon * | |
184 | smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid) | |
185 | { | |
186 | struct cifs_ses *ses; | |
187 | struct cifs_tcon *tcon; | |
188 | ||
189 | spin_lock(&cifs_tcp_ses_lock); | |
190 | ses = smb2_find_smb_ses_unlocked(server, ses_id); | |
191 | if (!ses) { | |
192 | spin_unlock(&cifs_tcp_ses_lock); | |
193 | return NULL; | |
194 | } | |
195 | tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid); | |
e695a9ad SP |
196 | if (!tcon) { |
197 | cifs_put_smb_ses(ses); | |
198 | spin_unlock(&cifs_tcp_ses_lock); | |
199 | return NULL; | |
200 | } | |
38bd4906 | 201 | spin_unlock(&cifs_tcp_ses_lock); |
e695a9ad SP |
202 | /* tcon already has a ref to ses, so we don't need ses anymore */ |
203 | cifs_put_smb_ses(ses); | |
38bd4906 SP |
204 | |
205 | return tcon; | |
206 | } | |
207 | ||
38107d45 | 208 | int |
eda1c54f LL |
209 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, |
210 | bool allocate_crypto) | |
3c1bf7e4 | 211 | { |
16c568ef | 212 | int rc; |
3c1bf7e4 PS |
213 | unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; |
214 | unsigned char *sigptr = smb2_signature; | |
0b688cfc | 215 | struct kvec *iov = rqst->rq_iov; |
c713c877 | 216 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; |
32811d24 | 217 | struct cifs_ses *ses; |
a5c62f48 | 218 | struct shash_desc *shash; |
eda1c54f LL |
219 | struct crypto_shash *hash; |
220 | struct sdesc *sdesc = NULL; | |
8de8c460 | 221 | struct smb_rqst drqst; |
32811d24 | 222 | |
026e93dc | 223 | ses = smb2_find_smb_ses(server, shdr->SessionId); |
32811d24 | 224 | if (!ses) { |
afe6f653 | 225 | cifs_server_dbg(VFS, "%s: Could not find session\n", __func__); |
32811d24 SP |
226 | return 0; |
227 | } | |
3c1bf7e4 PS |
228 | |
229 | memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE); | |
31473fc4 | 230 | memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 | 231 | |
eda1c54f LL |
232 | if (allocate_crypto) { |
233 | rc = cifs_alloc_hash("hmac(sha256)", &hash, &sdesc); | |
234 | if (rc) { | |
235 | cifs_server_dbg(VFS, | |
236 | "%s: sha256 alloc failed\n", __func__); | |
e695a9ad | 237 | goto out; |
eda1c54f LL |
238 | } |
239 | shash = &sdesc->shash; | |
240 | } else { | |
241 | hash = server->secmech.hmacsha256; | |
242 | shash = &server->secmech.sdeschmacsha256->shash; | |
95dc8dd1 SF |
243 | } |
244 | ||
eda1c54f LL |
245 | rc = crypto_shash_setkey(hash, ses->auth_key.response, |
246 | SMB2_NTLMV2_SESSKEY_SIZE); | |
3c1bf7e4 | 247 | if (rc) { |
eda1c54f LL |
248 | cifs_server_dbg(VFS, |
249 | "%s: Could not update with response\n", | |
250 | __func__); | |
251 | goto out; | |
3c1bf7e4 PS |
252 | } |
253 | ||
8de8c460 | 254 | rc = crypto_shash_init(shash); |
3c1bf7e4 | 255 | if (rc) { |
afe6f653 | 256 | cifs_server_dbg(VFS, "%s: Could not init sha256", __func__); |
eda1c54f | 257 | goto out; |
3c1bf7e4 PS |
258 | } |
259 | ||
8de8c460 PA |
260 | /* |
261 | * For SMB2+, __cifs_calc_signature() expects to sign only the actual | |
262 | * data, that is, iov[0] should not contain a rfc1002 length. | |
263 | * | |
264 | * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to | |
265 | * __cifs_calc_signature(). | |
266 | */ | |
267 | drqst = *rqst; | |
268 | if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) { | |
269 | rc = crypto_shash_update(shash, iov[0].iov_base, | |
270 | iov[0].iov_len); | |
271 | if (rc) { | |
eda1c54f LL |
272 | cifs_server_dbg(VFS, |
273 | "%s: Could not update with payload\n", | |
274 | __func__); | |
275 | goto out; | |
8de8c460 PA |
276 | } |
277 | drqst.rq_iov++; | |
278 | drqst.rq_nvec--; | |
279 | } | |
3c1bf7e4 | 280 | |
8de8c460 | 281 | rc = __cifs_calc_signature(&drqst, server, sigptr, shash); |
16c568ef | 282 | if (!rc) |
31473fc4 | 283 | memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 | 284 | |
eda1c54f LL |
285 | out: |
286 | if (allocate_crypto) | |
287 | cifs_free_hash(&hash, &sdesc); | |
e695a9ad SP |
288 | if (ses) |
289 | cifs_put_smb_ses(ses); | |
3c1bf7e4 PS |
290 | return rc; |
291 | } | |
292 | ||
373512ec SF |
293 | static int generate_key(struct cifs_ses *ses, struct kvec label, |
294 | struct kvec context, __u8 *key, unsigned int key_size) | |
429b46f4 SF |
295 | { |
296 | unsigned char zero = 0x0; | |
297 | __u8 i[4] = {0, 0, 0, 1}; | |
45a4546c SP |
298 | __u8 L128[4] = {0, 0, 0, 128}; |
299 | __u8 L256[4] = {0, 0, 1, 0}; | |
429b46f4 SF |
300 | int rc = 0; |
301 | unsigned char prfhash[SMB2_HMACSHA256_SIZE]; | |
302 | unsigned char *hashptr = prfhash; | |
afe6f653 | 303 | struct TCP_Server_Info *server = ses->server; |
429b46f4 SF |
304 | |
305 | memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); | |
373512ec | 306 | memset(key, 0x0, key_size); |
429b46f4 | 307 | |
afe6f653 | 308 | rc = smb3_crypto_shash_allocate(server); |
95dc8dd1 | 309 | if (rc) { |
afe6f653 | 310 | cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__); |
95dc8dd1 SF |
311 | goto smb3signkey_ret; |
312 | } | |
313 | ||
afe6f653 | 314 | rc = crypto_shash_setkey(server->secmech.hmacsha256, |
32811d24 | 315 | ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); |
429b46f4 | 316 | if (rc) { |
afe6f653 | 317 | cifs_server_dbg(VFS, "%s: Could not set with session key\n", __func__); |
429b46f4 SF |
318 | goto smb3signkey_ret; |
319 | } | |
320 | ||
afe6f653 | 321 | rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash); |
429b46f4 | 322 | if (rc) { |
afe6f653 | 323 | cifs_server_dbg(VFS, "%s: Could not init sign hmac\n", __func__); |
429b46f4 SF |
324 | goto smb3signkey_ret; |
325 | } | |
326 | ||
afe6f653 | 327 | rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
328 | i, 4); |
329 | if (rc) { | |
afe6f653 | 330 | cifs_server_dbg(VFS, "%s: Could not update with n\n", __func__); |
429b46f4 SF |
331 | goto smb3signkey_ret; |
332 | } | |
333 | ||
afe6f653 | 334 | rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, |
373512ec | 335 | label.iov_base, label.iov_len); |
429b46f4 | 336 | if (rc) { |
afe6f653 | 337 | cifs_server_dbg(VFS, "%s: Could not update with label\n", __func__); |
429b46f4 SF |
338 | goto smb3signkey_ret; |
339 | } | |
340 | ||
afe6f653 | 341 | rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
342 | &zero, 1); |
343 | if (rc) { | |
afe6f653 | 344 | cifs_server_dbg(VFS, "%s: Could not update with zero\n", __func__); |
429b46f4 SF |
345 | goto smb3signkey_ret; |
346 | } | |
347 | ||
afe6f653 | 348 | rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, |
373512ec | 349 | context.iov_base, context.iov_len); |
429b46f4 | 350 | if (rc) { |
afe6f653 | 351 | cifs_server_dbg(VFS, "%s: Could not update with context\n", __func__); |
429b46f4 SF |
352 | goto smb3signkey_ret; |
353 | } | |
354 | ||
45a4546c SP |
355 | if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) || |
356 | (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) { | |
357 | rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, | |
358 | L256, 4); | |
359 | } else { | |
360 | rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, | |
361 | L128, 4); | |
362 | } | |
429b46f4 | 363 | if (rc) { |
afe6f653 | 364 | cifs_server_dbg(VFS, "%s: Could not update with L\n", __func__); |
429b46f4 SF |
365 | goto smb3signkey_ret; |
366 | } | |
367 | ||
afe6f653 | 368 | rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash, |
429b46f4 SF |
369 | hashptr); |
370 | if (rc) { | |
afe6f653 | 371 | cifs_server_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); |
429b46f4 SF |
372 | goto smb3signkey_ret; |
373 | } | |
374 | ||
373512ec | 375 | memcpy(key, hashptr, key_size); |
429b46f4 SF |
376 | |
377 | smb3signkey_ret: | |
32811d24 | 378 | return rc; |
429b46f4 SF |
379 | } |
380 | ||
373512ec SF |
381 | struct derivation { |
382 | struct kvec label; | |
383 | struct kvec context; | |
384 | }; | |
385 | ||
386 | struct derivation_triplet { | |
387 | struct derivation signing; | |
388 | struct derivation encryption; | |
389 | struct derivation decryption; | |
390 | }; | |
391 | ||
392 | static int | |
393 | generate_smb3signingkey(struct cifs_ses *ses, | |
394 | const struct derivation_triplet *ptriplet) | |
395 | { | |
396 | int rc; | |
45a4546c SP |
397 | #ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS |
398 | struct TCP_Server_Info *server = ses->server; | |
399 | #endif | |
373512ec | 400 | |
d70e9fa5 AA |
401 | /* |
402 | * All channels use the same encryption/decryption keys but | |
403 | * they have their own signing key. | |
404 | * | |
405 | * When we generate the keys, check if it is for a new channel | |
406 | * (binding) in which case we only need to generate a signing | |
407 | * key and store it in the channel as to not overwrite the | |
408 | * master connection signing key stored in the session | |
409 | */ | |
373512ec | 410 | |
d70e9fa5 AA |
411 | if (ses->binding) { |
412 | rc = generate_key(ses, ptriplet->signing.label, | |
413 | ptriplet->signing.context, | |
414 | cifs_ses_binding_channel(ses)->signkey, | |
415 | SMB3_SIGN_KEY_SIZE); | |
416 | if (rc) | |
417 | return rc; | |
418 | } else { | |
419 | rc = generate_key(ses, ptriplet->signing.label, | |
420 | ptriplet->signing.context, | |
421 | ses->smb3signingkey, | |
422 | SMB3_SIGN_KEY_SIZE); | |
423 | if (rc) | |
424 | return rc; | |
ff6b6f3f PAS |
425 | |
426 | memcpy(ses->chans[0].signkey, ses->smb3signingkey, | |
427 | SMB3_SIGN_KEY_SIZE); | |
428 | ||
d70e9fa5 AA |
429 | rc = generate_key(ses, ptriplet->encryption.label, |
430 | ptriplet->encryption.context, | |
431 | ses->smb3encryptionkey, | |
45a4546c | 432 | SMB3_ENC_DEC_KEY_SIZE); |
d70e9fa5 AA |
433 | rc = generate_key(ses, ptriplet->decryption.label, |
434 | ptriplet->decryption.context, | |
435 | ses->smb3decryptionkey, | |
45a4546c | 436 | SMB3_ENC_DEC_KEY_SIZE); |
d70e9fa5 AA |
437 | if (rc) |
438 | return rc; | |
439 | } | |
d38de3c6 AA |
440 | |
441 | if (rc) | |
442 | return rc; | |
443 | ||
444 | #ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS | |
445 | cifs_dbg(VFS, "%s: dumping generated AES session keys\n", __func__); | |
446 | /* | |
447 | * The session id is opaque in terms of endianness, so we can't | |
448 | * print it as a long long. we dump it as we got it on the wire | |
449 | */ | |
450 | cifs_dbg(VFS, "Session Id %*ph\n", (int)sizeof(ses->Suid), | |
451 | &ses->Suid); | |
45a4546c | 452 | cifs_dbg(VFS, "Cipher type %d\n", server->cipher_type); |
d38de3c6 AA |
453 | cifs_dbg(VFS, "Session Key %*ph\n", |
454 | SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response); | |
455 | cifs_dbg(VFS, "Signing Key %*ph\n", | |
456 | SMB3_SIGN_KEY_SIZE, ses->smb3signingkey); | |
45a4546c SP |
457 | if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) || |
458 | (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) { | |
459 | cifs_dbg(VFS, "ServerIn Key %*ph\n", | |
460 | SMB3_GCM256_CRYPTKEY_SIZE, ses->smb3encryptionkey); | |
461 | cifs_dbg(VFS, "ServerOut Key %*ph\n", | |
462 | SMB3_GCM256_CRYPTKEY_SIZE, ses->smb3decryptionkey); | |
463 | } else { | |
464 | cifs_dbg(VFS, "ServerIn Key %*ph\n", | |
465 | SMB3_GCM128_CRYPTKEY_SIZE, ses->smb3encryptionkey); | |
466 | cifs_dbg(VFS, "ServerOut Key %*ph\n", | |
467 | SMB3_GCM128_CRYPTKEY_SIZE, ses->smb3decryptionkey); | |
468 | } | |
d38de3c6 AA |
469 | #endif |
470 | return rc; | |
373512ec SF |
471 | } |
472 | ||
473 | int | |
474 | generate_smb30signingkey(struct cifs_ses *ses) | |
475 | ||
476 | { | |
477 | struct derivation_triplet triplet; | |
478 | struct derivation *d; | |
479 | ||
480 | d = &triplet.signing; | |
481 | d->label.iov_base = "SMB2AESCMAC"; | |
482 | d->label.iov_len = 12; | |
483 | d->context.iov_base = "SmbSign"; | |
484 | d->context.iov_len = 8; | |
485 | ||
486 | d = &triplet.encryption; | |
487 | d->label.iov_base = "SMB2AESCCM"; | |
488 | d->label.iov_len = 11; | |
489 | d->context.iov_base = "ServerIn "; | |
490 | d->context.iov_len = 10; | |
491 | ||
492 | d = &triplet.decryption; | |
493 | d->label.iov_base = "SMB2AESCCM"; | |
494 | d->label.iov_len = 11; | |
495 | d->context.iov_base = "ServerOut"; | |
496 | d->context.iov_len = 10; | |
497 | ||
498 | return generate_smb3signingkey(ses, &triplet); | |
499 | } | |
500 | ||
501 | int | |
502 | generate_smb311signingkey(struct cifs_ses *ses) | |
503 | ||
504 | { | |
505 | struct derivation_triplet triplet; | |
506 | struct derivation *d; | |
507 | ||
508 | d = &triplet.signing; | |
06e22908 SF |
509 | d->label.iov_base = "SMBSigningKey"; |
510 | d->label.iov_len = 14; | |
511 | d->context.iov_base = ses->preauth_sha_hash; | |
512 | d->context.iov_len = 64; | |
373512ec SF |
513 | |
514 | d = &triplet.encryption; | |
06e22908 SF |
515 | d->label.iov_base = "SMBC2SCipherKey"; |
516 | d->label.iov_len = 16; | |
517 | d->context.iov_base = ses->preauth_sha_hash; | |
518 | d->context.iov_len = 64; | |
373512ec SF |
519 | |
520 | d = &triplet.decryption; | |
06e22908 SF |
521 | d->label.iov_base = "SMBS2CCipherKey"; |
522 | d->label.iov_len = 16; | |
523 | d->context.iov_base = ses->preauth_sha_hash; | |
524 | d->context.iov_len = 64; | |
373512ec SF |
525 | |
526 | return generate_smb3signingkey(ses, &triplet); | |
527 | } | |
528 | ||
38107d45 | 529 | int |
eda1c54f LL |
530 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, |
531 | bool allocate_crypto) | |
38107d45 | 532 | { |
27c32b49 | 533 | int rc; |
429b46f4 SF |
534 | unsigned char smb3_signature[SMB2_CMACAES_SIZE]; |
535 | unsigned char *sigptr = smb3_signature; | |
536 | struct kvec *iov = rqst->rq_iov; | |
c713c877 | 537 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)iov[0].iov_base; |
eda1c54f LL |
538 | struct shash_desc *shash; |
539 | struct crypto_shash *hash; | |
540 | struct sdesc *sdesc = NULL; | |
27c32b49 | 541 | struct smb_rqst drqst; |
d70e9fa5 | 542 | u8 key[SMB3_SIGN_KEY_SIZE]; |
32811d24 | 543 | |
d70e9fa5 AA |
544 | rc = smb2_get_sign_key(shdr->SessionId, server, key); |
545 | if (rc) | |
32811d24 | 546 | return 0; |
429b46f4 | 547 | |
eda1c54f LL |
548 | if (allocate_crypto) { |
549 | rc = cifs_alloc_hash("cmac(aes)", &hash, &sdesc); | |
550 | if (rc) | |
551 | return rc; | |
552 | ||
553 | shash = &sdesc->shash; | |
554 | } else { | |
555 | hash = server->secmech.cmacaes; | |
556 | shash = &server->secmech.sdesccmacaes->shash; | |
557 | } | |
558 | ||
429b46f4 | 559 | memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE); |
31473fc4 | 560 | memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); |
429b46f4 | 561 | |
eda1c54f | 562 | rc = crypto_shash_setkey(hash, key, SMB2_CMACAES_SIZE); |
429b46f4 | 563 | if (rc) { |
afe6f653 | 564 | cifs_server_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); |
eda1c54f | 565 | goto out; |
429b46f4 SF |
566 | } |
567 | ||
95dc8dd1 SF |
568 | /* |
569 | * we already allocate sdesccmacaes when we init smb3 signing key, | |
570 | * so unlike smb2 case we do not have to check here if secmech are | |
571 | * initialized | |
572 | */ | |
27c32b49 | 573 | rc = crypto_shash_init(shash); |
429b46f4 | 574 | if (rc) { |
afe6f653 | 575 | cifs_server_dbg(VFS, "%s: Could not init cmac aes\n", __func__); |
eda1c54f | 576 | goto out; |
429b46f4 | 577 | } |
82fb82be | 578 | |
27c32b49 PA |
579 | /* |
580 | * For SMB2+, __cifs_calc_signature() expects to sign only the actual | |
581 | * data, that is, iov[0] should not contain a rfc1002 length. | |
582 | * | |
583 | * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to | |
584 | * __cifs_calc_signature(). | |
585 | */ | |
586 | drqst = *rqst; | |
587 | if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) { | |
588 | rc = crypto_shash_update(shash, iov[0].iov_base, | |
589 | iov[0].iov_len); | |
590 | if (rc) { | |
afe6f653 | 591 | cifs_server_dbg(VFS, "%s: Could not update with payload\n", |
27c32b49 | 592 | __func__); |
eda1c54f | 593 | goto out; |
27c32b49 PA |
594 | } |
595 | drqst.rq_iov++; | |
596 | drqst.rq_nvec--; | |
597 | } | |
429b46f4 | 598 | |
27c32b49 | 599 | rc = __cifs_calc_signature(&drqst, server, sigptr, shash); |
16c568ef | 600 | if (!rc) |
31473fc4 | 601 | memcpy(shdr->Signature, sigptr, SMB2_SIGNATURE_SIZE); |
429b46f4 | 602 | |
eda1c54f LL |
603 | out: |
604 | if (allocate_crypto) | |
605 | cifs_free_hash(&hash, &sdesc); | |
429b46f4 | 606 | return rc; |
38107d45 SF |
607 | } |
608 | ||
3c1bf7e4 PS |
609 | /* must be called with server->srv_mutex held */ |
610 | static int | |
0b688cfc | 611 | smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
3c1bf7e4 PS |
612 | { |
613 | int rc = 0; | |
d70e9fa5 AA |
614 | struct smb2_sync_hdr *shdr; |
615 | struct smb2_sess_setup_req *ssr; | |
616 | bool is_binding; | |
617 | bool is_signed; | |
3c1bf7e4 | 618 | |
d70e9fa5 AA |
619 | shdr = (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
620 | ssr = (struct smb2_sess_setup_req *)shdr; | |
3c1bf7e4 | 621 | |
d70e9fa5 AA |
622 | is_binding = shdr->Command == SMB2_SESSION_SETUP && |
623 | (ssr->Flags & SMB2_SESSION_REQ_FLAG_BINDING); | |
624 | is_signed = shdr->Flags & SMB2_FLAGS_SIGNED; | |
625 | ||
626 | if (!is_signed) | |
627 | return 0; | |
628 | if (server->tcpStatus == CifsNeedNegotiate) | |
629 | return 0; | |
630 | if (!is_binding && !server->session_estab) { | |
31473fc4 | 631 | strncpy(shdr->Signature, "BSRSPYL", 8); |
d70e9fa5 | 632 | return 0; |
3c1bf7e4 PS |
633 | } |
634 | ||
eda1c54f | 635 | rc = server->ops->calc_signature(rqst, server, false); |
3c1bf7e4 PS |
636 | |
637 | return rc; | |
638 | } | |
639 | ||
640 | int | |
0b688cfc | 641 | smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
3c1bf7e4 PS |
642 | { |
643 | unsigned int rc; | |
edad734c | 644 | char server_response_sig[SMB2_SIGNATURE_SIZE]; |
738f9de5 | 645 | struct smb2_sync_hdr *shdr = |
977b6170 | 646 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
3c1bf7e4 | 647 | |
31473fc4 PS |
648 | if ((shdr->Command == SMB2_NEGOTIATE) || |
649 | (shdr->Command == SMB2_SESSION_SETUP) || | |
650 | (shdr->Command == SMB2_OPLOCK_BREAK) || | |
4f5c10f1 | 651 | server->ignore_signature || |
3c1bf7e4 PS |
652 | (!server->session_estab)) |
653 | return 0; | |
654 | ||
655 | /* | |
656 | * BB what if signatures are supposed to be on for session but | |
657 | * server does not send one? BB | |
658 | */ | |
659 | ||
660 | /* Do not need to verify session setups with signature "BSRSPYL " */ | |
31473fc4 | 661 | if (memcmp(shdr->Signature, "BSRSPYL ", 8) == 0) |
f96637be | 662 | cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n", |
31473fc4 | 663 | shdr->Command); |
3c1bf7e4 PS |
664 | |
665 | /* | |
666 | * Save off the origiginal signature so we can modify the smb and check | |
667 | * our calculated signature against what the server sent. | |
668 | */ | |
31473fc4 | 669 | memcpy(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 | 670 | |
31473fc4 | 671 | memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE); |
3c1bf7e4 | 672 | |
eda1c54f | 673 | rc = server->ops->calc_signature(rqst, server, true); |
3c1bf7e4 PS |
674 | |
675 | if (rc) | |
676 | return rc; | |
677 | ||
f460c502 | 678 | if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE)) { |
9692ea9d SF |
679 | cifs_dbg(VFS, "sign fail cmd 0x%x message id 0x%llx\n", |
680 | shdr->Command, shdr->MessageId); | |
3c1bf7e4 | 681 | return -EACCES; |
f460c502 | 682 | } else |
3c1bf7e4 PS |
683 | return 0; |
684 | } | |
685 | ||
2dc7e1c0 PS |
686 | /* |
687 | * Set message id for the request. Should be called after wait_for_free_request | |
688 | * and when srv_mutex is held. | |
689 | */ | |
690 | static inline void | |
31473fc4 PS |
691 | smb2_seq_num_into_buf(struct TCP_Server_Info *server, |
692 | struct smb2_sync_hdr *shdr) | |
2dc7e1c0 | 693 | { |
31473fc4 | 694 | unsigned int i, num = le16_to_cpu(shdr->CreditCharge); |
cb7e9eab | 695 | |
31473fc4 | 696 | shdr->MessageId = get_next_mid64(server); |
cb7e9eab PS |
697 | /* skip message numbers according to CreditCharge field */ |
698 | for (i = 1; i < num; i++) | |
699 | get_next_mid(server); | |
2dc7e1c0 PS |
700 | } |
701 | ||
702 | static struct mid_q_entry * | |
31473fc4 | 703 | smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr, |
2dc7e1c0 PS |
704 | struct TCP_Server_Info *server) |
705 | { | |
706 | struct mid_q_entry *temp; | |
c781af7e | 707 | unsigned int credits = le16_to_cpu(shdr->CreditCharge); |
2dc7e1c0 PS |
708 | |
709 | if (server == NULL) { | |
f96637be | 710 | cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n"); |
2dc7e1c0 PS |
711 | return NULL; |
712 | } | |
713 | ||
714 | temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); | |
a6f74e80 | 715 | memset(temp, 0, sizeof(struct mid_q_entry)); |
696e420b | 716 | kref_init(&temp->refcount); |
a6f74e80 | 717 | temp->mid = le64_to_cpu(shdr->MessageId); |
c781af7e | 718 | temp->credits = credits > 0 ? credits : 1; |
a6f74e80 N |
719 | temp->pid = current->pid; |
720 | temp->command = shdr->Command; /* Always LE */ | |
721 | temp->when_alloc = jiffies; | |
722 | temp->server = server; | |
723 | ||
724 | /* | |
725 | * The default is for the mid to be synchronous, so the | |
726 | * default callback just wakes up the current task. | |
727 | */ | |
f1f27ad7 VW |
728 | get_task_struct(current); |
729 | temp->creator = current; | |
a6f74e80 N |
730 | temp->callback = cifs_wake_up_task; |
731 | temp->callback_data = current; | |
2dc7e1c0 PS |
732 | |
733 | atomic_inc(&midCount); | |
734 | temp->mid_state = MID_REQUEST_ALLOCATED; | |
53a3e0d9 SF |
735 | trace_smb3_cmd_enter(shdr->TreeId, shdr->SessionId, |
736 | le16_to_cpu(shdr->Command), temp->mid); | |
2dc7e1c0 PS |
737 | return temp; |
738 | } | |
739 | ||
740 | static int | |
f780bd3f AA |
741 | smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server, |
742 | struct smb2_sync_hdr *shdr, struct mid_q_entry **mid) | |
2dc7e1c0 | 743 | { |
f780bd3f | 744 | if (server->tcpStatus == CifsExiting) |
2dc7e1c0 PS |
745 | return -ENOENT; |
746 | ||
f780bd3f | 747 | if (server->tcpStatus == CifsNeedReconnect) { |
f96637be | 748 | cifs_dbg(FYI, "tcp session dead - return to caller to retry\n"); |
2dc7e1c0 PS |
749 | return -EAGAIN; |
750 | } | |
751 | ||
f780bd3f | 752 | if (server->tcpStatus == CifsNeedNegotiate && |
2084ed57 PS |
753 | shdr->Command != SMB2_NEGOTIATE) |
754 | return -EAGAIN; | |
755 | ||
7f48558e | 756 | if (ses->status == CifsNew) { |
31473fc4 PS |
757 | if ((shdr->Command != SMB2_SESSION_SETUP) && |
758 | (shdr->Command != SMB2_NEGOTIATE)) | |
2dc7e1c0 PS |
759 | return -EAGAIN; |
760 | /* else ok - we are setting up session */ | |
761 | } | |
7f48558e SP |
762 | |
763 | if (ses->status == CifsExiting) { | |
31473fc4 | 764 | if (shdr->Command != SMB2_LOGOFF) |
7f48558e SP |
765 | return -EAGAIN; |
766 | /* else ok - we are shutting down the session */ | |
767 | } | |
768 | ||
f780bd3f | 769 | *mid = smb2_mid_entry_alloc(shdr, server); |
2dc7e1c0 PS |
770 | if (*mid == NULL) |
771 | return -ENOMEM; | |
772 | spin_lock(&GlobalMid_Lock); | |
f780bd3f | 773 | list_add_tail(&(*mid)->qhead, &server->pending_mid_q); |
2dc7e1c0 | 774 | spin_unlock(&GlobalMid_Lock); |
53a3e0d9 | 775 | |
2dc7e1c0 PS |
776 | return 0; |
777 | } | |
778 | ||
779 | int | |
780 | smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, | |
781 | bool log_error) | |
782 | { | |
e19b2bc0 | 783 | unsigned int len = mid->resp_buf_size; |
977b6170 | 784 | struct kvec iov[1]; |
738f9de5 | 785 | struct smb_rqst rqst = { .rq_iov = iov, |
977b6170 | 786 | .rq_nvec = 1 }; |
0b688cfc | 787 | |
738f9de5 | 788 | iov[0].iov_base = (char *)mid->resp_buf; |
977b6170 | 789 | iov[0].iov_len = len; |
2dc7e1c0 PS |
790 | |
791 | dump_smb(mid->resp_buf, min_t(u32, 80, len)); | |
792 | /* convert the length into a more usable form */ | |
4326ed2f | 793 | if (len > 24 && server->sign && !mid->decrypted) { |
3c1bf7e4 PS |
794 | int rc; |
795 | ||
0b688cfc | 796 | rc = smb2_verify_signature(&rqst, server); |
3c1bf7e4 | 797 | if (rc) |
afe6f653 | 798 | cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n", |
f96637be | 799 | rc); |
3c1bf7e4 | 800 | } |
2dc7e1c0 PS |
801 | |
802 | return map_smb2_to_linux_error(mid->resp_buf, log_error); | |
803 | } | |
804 | ||
fec344e3 | 805 | struct mid_q_entry * |
f780bd3f AA |
806 | smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server, |
807 | struct smb_rqst *rqst) | |
2dc7e1c0 PS |
808 | { |
809 | int rc; | |
738f9de5 | 810 | struct smb2_sync_hdr *shdr = |
c713c877 | 811 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
2dc7e1c0 PS |
812 | struct mid_q_entry *mid; |
813 | ||
f780bd3f | 814 | smb2_seq_num_into_buf(server, shdr); |
2dc7e1c0 | 815 | |
f780bd3f | 816 | rc = smb2_get_mid_entry(ses, server, shdr, &mid); |
c781af7e | 817 | if (rc) { |
f780bd3f | 818 | revert_current_mid_from_hdr(server, shdr); |
fec344e3 | 819 | return ERR_PTR(rc); |
c781af7e PS |
820 | } |
821 | ||
f780bd3f | 822 | rc = smb2_sign_rqst(rqst, server); |
fec344e3 | 823 | if (rc) { |
f780bd3f | 824 | revert_current_mid_from_hdr(server, shdr); |
3c1bf7e4 | 825 | cifs_delete_mid(mid); |
fec344e3 JL |
826 | return ERR_PTR(rc); |
827 | } | |
c781af7e | 828 | |
fec344e3 | 829 | return mid; |
2dc7e1c0 PS |
830 | } |
831 | ||
fec344e3 JL |
832 | struct mid_q_entry * |
833 | smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |
c95b8eed | 834 | { |
fec344e3 | 835 | int rc; |
738f9de5 | 836 | struct smb2_sync_hdr *shdr = |
c713c877 | 837 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
c95b8eed PS |
838 | struct mid_q_entry *mid; |
839 | ||
2084ed57 PS |
840 | if (server->tcpStatus == CifsNeedNegotiate && |
841 | shdr->Command != SMB2_NEGOTIATE) | |
842 | return ERR_PTR(-EAGAIN); | |
843 | ||
31473fc4 | 844 | smb2_seq_num_into_buf(server, shdr); |
c95b8eed | 845 | |
31473fc4 | 846 | mid = smb2_mid_entry_alloc(shdr, server); |
c781af7e PS |
847 | if (mid == NULL) { |
848 | revert_current_mid_from_hdr(server, shdr); | |
fec344e3 | 849 | return ERR_PTR(-ENOMEM); |
c781af7e | 850 | } |
c95b8eed | 851 | |
fec344e3 | 852 | rc = smb2_sign_rqst(rqst, server); |
c95b8eed | 853 | if (rc) { |
c781af7e | 854 | revert_current_mid_from_hdr(server, shdr); |
c95b8eed | 855 | DeleteMidQEntry(mid); |
fec344e3 | 856 | return ERR_PTR(rc); |
3c1bf7e4 PS |
857 | } |
858 | ||
fec344e3 | 859 | return mid; |
c95b8eed | 860 | } |
026e93dc PS |
861 | |
862 | int | |
863 | smb3_crypto_aead_allocate(struct TCP_Server_Info *server) | |
864 | { | |
865 | struct crypto_aead *tfm; | |
866 | ||
867 | if (!server->secmech.ccmaesencrypt) { | |
63ca5656 SF |
868 | if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) || |
869 | (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) | |
2b2f7548 SF |
870 | tfm = crypto_alloc_aead("gcm(aes)", 0, 0); |
871 | else | |
872 | tfm = crypto_alloc_aead("ccm(aes)", 0, 0); | |
026e93dc | 873 | if (IS_ERR(tfm)) { |
63ca5656 | 874 | cifs_server_dbg(VFS, "%s: Failed alloc encrypt aead\n", |
026e93dc PS |
875 | __func__); |
876 | return PTR_ERR(tfm); | |
877 | } | |
878 | server->secmech.ccmaesencrypt = tfm; | |
879 | } | |
880 | ||
881 | if (!server->secmech.ccmaesdecrypt) { | |
63ca5656 SF |
882 | if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) || |
883 | (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) | |
2b2f7548 SF |
884 | tfm = crypto_alloc_aead("gcm(aes)", 0, 0); |
885 | else | |
886 | tfm = crypto_alloc_aead("ccm(aes)", 0, 0); | |
026e93dc PS |
887 | if (IS_ERR(tfm)) { |
888 | crypto_free_aead(server->secmech.ccmaesencrypt); | |
889 | server->secmech.ccmaesencrypt = NULL; | |
afe6f653 | 890 | cifs_server_dbg(VFS, "%s: Failed to alloc decrypt aead\n", |
026e93dc PS |
891 | __func__); |
892 | return PTR_ERR(tfm); | |
893 | } | |
894 | server->secmech.ccmaesdecrypt = tfm; | |
895 | } | |
896 | ||
897 | return 0; | |
898 | } |