diff options
Diffstat (limited to 'fs/cifs/cifsencrypt.c')
-rw-r--r-- | fs/cifs/cifsencrypt.c | 427 |
1 files changed, 320 insertions, 107 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 7ac0056294cf..f856732161ab 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -43,18 +43,32 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, | |||
43 | unsigned char *p24); | 43 | unsigned char *p24); |
44 | 44 | ||
45 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, | 45 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, |
46 | const struct session_key *key, char *signature) | 46 | struct TCP_Server_Info *server, char *signature) |
47 | { | 47 | { |
48 | struct MD5Context context; | 48 | int rc; |
49 | 49 | ||
50 | if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL)) | 50 | if (cifs_pdu == NULL || signature == NULL || server == NULL) |
51 | return -EINVAL; | 51 | return -EINVAL; |
52 | 52 | ||
53 | cifs_MD5_init(&context); | 53 | if (!server->secmech.sdescmd5) { |
54 | cifs_MD5_update(&context, (char *)&key->data, key->len); | 54 | cERROR(1, "%s: Can't generate signature\n", __func__); |
55 | cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); | 55 | return -1; |
56 | } | ||
57 | |||
58 | rc = crypto_shash_init(&server->secmech.sdescmd5->shash); | ||
59 | if (rc) { | ||
60 | cERROR(1, "%s: Oould not init md5\n", __func__); | ||
61 | return rc; | ||
62 | } | ||
63 | |||
64 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
65 | server->session_key.response, server->session_key.len); | ||
66 | |||
67 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
68 | cifs_pdu->Protocol, cifs_pdu->smb_buf_length); | ||
69 | |||
70 | rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); | ||
56 | 71 | ||
57 | cifs_MD5_final(signature, &context); | ||
58 | return 0; | 72 | return 0; |
59 | } | 73 | } |
60 | 74 | ||
@@ -79,8 +93,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
79 | server->sequence_number++; | 93 | server->sequence_number++; |
80 | spin_unlock(&GlobalMid_Lock); | 94 | spin_unlock(&GlobalMid_Lock); |
81 | 95 | ||
82 | rc = cifs_calculate_signature(cifs_pdu, &server->session_key, | 96 | rc = cifs_calculate_signature(cifs_pdu, server, smb_signature); |
83 | smb_signature); | ||
84 | if (rc) | 97 | if (rc) |
85 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 98 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
86 | else | 99 | else |
@@ -90,16 +103,28 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
90 | } | 103 | } |
91 | 104 | ||
92 | static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | 105 | static int cifs_calc_signature2(const struct kvec *iov, int n_vec, |
93 | const struct session_key *key, char *signature) | 106 | struct TCP_Server_Info *server, char *signature) |
94 | { | 107 | { |
95 | struct MD5Context context; | ||
96 | int i; | 108 | int i; |
109 | int rc; | ||
97 | 110 | ||
98 | if ((iov == NULL) || (signature == NULL) || (key == NULL)) | 111 | if (iov == NULL || signature == NULL || server == NULL) |
99 | return -EINVAL; | 112 | return -EINVAL; |
100 | 113 | ||
101 | cifs_MD5_init(&context); | 114 | if (!server->secmech.sdescmd5) { |
102 | cifs_MD5_update(&context, (char *)&key->data, key->len); | 115 | cERROR(1, "%s: Can't generate signature\n", __func__); |
116 | return -1; | ||
117 | } | ||
118 | |||
119 | rc = crypto_shash_init(&server->secmech.sdescmd5->shash); | ||
120 | if (rc) { | ||
121 | cERROR(1, "%s: Oould not init md5\n", __func__); | ||
122 | return rc; | ||
123 | } | ||
124 | |||
125 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
126 | server->session_key.response, server->session_key.len); | ||
127 | |||
103 | for (i = 0; i < n_vec; i++) { | 128 | for (i = 0; i < n_vec; i++) { |
104 | if (iov[i].iov_len == 0) | 129 | if (iov[i].iov_len == 0) |
105 | continue; | 130 | continue; |
@@ -112,18 +137,18 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | |||
112 | if (i == 0) { | 137 | if (i == 0) { |
113 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | 138 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ |
114 | break; /* nothing to sign or corrupt header */ | 139 | break; /* nothing to sign or corrupt header */ |
115 | cifs_MD5_update(&context, iov[0].iov_base+4, | 140 | crypto_shash_update(&server->secmech.sdescmd5->shash, |
116 | iov[0].iov_len-4); | 141 | iov[i].iov_base + 4, iov[i].iov_len - 4); |
117 | } else | 142 | } else |
118 | cifs_MD5_update(&context, iov[i].iov_base, iov[i].iov_len); | 143 | crypto_shash_update(&server->secmech.sdescmd5->shash, |
144 | iov[i].iov_base, iov[i].iov_len); | ||
119 | } | 145 | } |
120 | 146 | ||
121 | cifs_MD5_final(signature, &context); | 147 | rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); |
122 | 148 | ||
123 | return 0; | 149 | return rc; |
124 | } | 150 | } |
125 | 151 | ||
126 | |||
127 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | 152 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, |
128 | __u32 *pexpected_response_sequence_number) | 153 | __u32 *pexpected_response_sequence_number) |
129 | { | 154 | { |
@@ -146,8 +171,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | |||
146 | server->sequence_number++; | 171 | server->sequence_number++; |
147 | spin_unlock(&GlobalMid_Lock); | 172 | spin_unlock(&GlobalMid_Lock); |
148 | 173 | ||
149 | rc = cifs_calc_signature2(iov, n_vec, &server->session_key, | 174 | rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); |
150 | smb_signature); | ||
151 | if (rc) | 175 | if (rc) |
152 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 176 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
153 | else | 177 | else |
@@ -157,14 +181,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | |||
157 | } | 181 | } |
158 | 182 | ||
159 | int cifs_verify_signature(struct smb_hdr *cifs_pdu, | 183 | int cifs_verify_signature(struct smb_hdr *cifs_pdu, |
160 | const struct session_key *session_key, | 184 | struct TCP_Server_Info *server, |
161 | __u32 expected_sequence_number) | 185 | __u32 expected_sequence_number) |
162 | { | 186 | { |
163 | unsigned int rc; | 187 | unsigned int rc; |
164 | char server_response_sig[8]; | 188 | char server_response_sig[8]; |
165 | char what_we_think_sig_should_be[20]; | 189 | char what_we_think_sig_should_be[20]; |
166 | 190 | ||
167 | if (cifs_pdu == NULL || session_key == NULL) | 191 | if (cifs_pdu == NULL || server == NULL) |
168 | return -EINVAL; | 192 | return -EINVAL; |
169 | 193 | ||
170 | if (cifs_pdu->Command == SMB_COM_NEGOTIATE) | 194 | if (cifs_pdu->Command == SMB_COM_NEGOTIATE) |
@@ -193,7 +217,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, | |||
193 | cpu_to_le32(expected_sequence_number); | 217 | cpu_to_le32(expected_sequence_number); |
194 | cifs_pdu->Signature.Sequence.Reserved = 0; | 218 | cifs_pdu->Signature.Sequence.Reserved = 0; |
195 | 219 | ||
196 | rc = cifs_calculate_signature(cifs_pdu, session_key, | 220 | rc = cifs_calculate_signature(cifs_pdu, server, |
197 | what_we_think_sig_should_be); | 221 | what_we_think_sig_should_be); |
198 | 222 | ||
199 | if (rc) | 223 | if (rc) |
@@ -209,18 +233,28 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, | |||
209 | 233 | ||
210 | } | 234 | } |
211 | 235 | ||
212 | /* We fill in key by putting in 40 byte array which was allocated by caller */ | 236 | /* first calculate 24 bytes ntlm response and then 16 byte session key */ |
213 | int cifs_calculate_session_key(struct session_key *key, const char *rn, | 237 | int setup_ntlm_response(struct cifsSesInfo *ses) |
214 | const char *password) | ||
215 | { | 238 | { |
216 | char temp_key[16]; | 239 | unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE; |
217 | if ((key == NULL) || (rn == NULL)) | 240 | char temp_key[CIFS_SESS_KEY_SIZE]; |
241 | |||
242 | if (!ses) | ||
218 | return -EINVAL; | 243 | return -EINVAL; |
219 | 244 | ||
220 | E_md4hash(password, temp_key); | 245 | ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL); |
221 | mdfour(key->data.ntlm, temp_key, 16); | 246 | if (!ses->auth_key.response) { |
222 | memcpy(key->data.ntlm+16, rn, CIFS_SESS_KEY_SIZE); | 247 | cERROR(1, "NTLM can't allocate (%u bytes) memory", temp_len); |
223 | key->len = 40; | 248 | return -ENOMEM; |
249 | } | ||
250 | ses->auth_key.len = temp_len; | ||
251 | |||
252 | SMBNTencrypt(ses->password, ses->server->cryptkey, | ||
253 | ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
254 | |||
255 | E_md4hash(ses->password, temp_key); | ||
256 | mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE); | ||
257 | |||
224 | return 0; | 258 | return 0; |
225 | } | 259 | } |
226 | 260 | ||
@@ -294,15 +328,15 @@ build_avpair_blob(struct cifsSesInfo *ses, const struct nls_table *nls_cp) | |||
294 | * two times the unicode length of a server name + | 328 | * two times the unicode length of a server name + |
295 | * size of a timestamp (which is 8 bytes). | 329 | * size of a timestamp (which is 8 bytes). |
296 | */ | 330 | */ |
297 | ses->tilen = size + 2 * (2 * dlen) + 2 * (2 * wlen) + 8; | 331 | ses->auth_key.len = size + 2 * (2 * dlen) + 2 * (2 * wlen) + 8; |
298 | ses->tiblob = kzalloc(ses->tilen, GFP_KERNEL); | 332 | ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL); |
299 | if (!ses->tiblob) { | 333 | if (!ses->auth_key.response) { |
300 | ses->tilen = 0; | 334 | ses->auth_key.len = 0; |
301 | cERROR(1, "Challenge target info allocation failure"); | 335 | cERROR(1, "Challenge target info allocation failure"); |
302 | return -ENOMEM; | 336 | return -ENOMEM; |
303 | } | 337 | } |
304 | 338 | ||
305 | blobptr = ses->tiblob; | 339 | blobptr = ses->auth_key.response; |
306 | attrptr = (struct ntlmssp2_name *) blobptr; | 340 | attrptr = (struct ntlmssp2_name *) blobptr; |
307 | 341 | ||
308 | attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME); | 342 | attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME); |
@@ -357,7 +391,7 @@ build_avpair_blob(struct cifsSesInfo *ses, const struct nls_table *nls_cp) | |||
357 | * about target string i.e. for some, just user name might suffice. | 391 | * about target string i.e. for some, just user name might suffice. |
358 | */ | 392 | */ |
359 | static int | 393 | static int |
360 | find_domain_name(struct cifsSesInfo *ses) | 394 | find_domain_name(struct cifsSesInfo *ses, const struct nls_table *nls_cp) |
361 | { | 395 | { |
362 | unsigned int attrsize; | 396 | unsigned int attrsize; |
363 | unsigned int type; | 397 | unsigned int type; |
@@ -366,11 +400,11 @@ find_domain_name(struct cifsSesInfo *ses) | |||
366 | unsigned char *blobend; | 400 | unsigned char *blobend; |
367 | struct ntlmssp2_name *attrptr; | 401 | struct ntlmssp2_name *attrptr; |
368 | 402 | ||
369 | if (!ses->tilen || !ses->tiblob) | 403 | if (!ses->auth_key.len || !ses->auth_key.response) |
370 | return 0; | 404 | return 0; |
371 | 405 | ||
372 | blobptr = ses->tiblob; | 406 | blobptr = ses->auth_key.response; |
373 | blobend = ses->tiblob + ses->tilen; | 407 | blobend = blobptr + ses->auth_key.len; |
374 | 408 | ||
375 | while (blobptr + onesize < blobend) { | 409 | while (blobptr + onesize < blobend) { |
376 | attrptr = (struct ntlmssp2_name *) blobptr; | 410 | attrptr = (struct ntlmssp2_name *) blobptr; |
@@ -386,16 +420,13 @@ find_domain_name(struct cifsSesInfo *ses) | |||
386 | if (!attrsize) | 420 | if (!attrsize) |
387 | break; | 421 | break; |
388 | if (!ses->domainName) { | 422 | if (!ses->domainName) { |
389 | struct nls_table *default_nls; | ||
390 | ses->domainName = | 423 | ses->domainName = |
391 | kmalloc(attrsize + 1, GFP_KERNEL); | 424 | kmalloc(attrsize + 1, GFP_KERNEL); |
392 | if (!ses->domainName) | 425 | if (!ses->domainName) |
393 | return -ENOMEM; | 426 | return -ENOMEM; |
394 | default_nls = load_nls_default(); | ||
395 | cifs_from_ucs2(ses->domainName, | 427 | cifs_from_ucs2(ses->domainName, |
396 | (__le16 *)blobptr, attrsize, attrsize, | 428 | (__le16 *)blobptr, attrsize, attrsize, |
397 | default_nls, false); | 429 | nls_cp, false); |
398 | unload_nls(default_nls); | ||
399 | break; | 430 | break; |
400 | } | 431 | } |
401 | } | 432 | } |
@@ -405,82 +436,136 @@ find_domain_name(struct cifsSesInfo *ses) | |||
405 | return 0; | 436 | return 0; |
406 | } | 437 | } |
407 | 438 | ||
408 | static int calc_ntlmv2_hash(struct cifsSesInfo *ses, | 439 | static int calc_ntlmv2_hash(struct cifsSesInfo *ses, char *ntlmv2_hash, |
409 | const struct nls_table *nls_cp) | 440 | const struct nls_table *nls_cp) |
410 | { | 441 | { |
411 | int rc = 0; | 442 | int rc = 0; |
412 | int len; | 443 | int len; |
413 | char nt_hash[16]; | 444 | char nt_hash[CIFS_NTHASH_SIZE]; |
414 | struct HMACMD5Context *pctxt; | ||
415 | wchar_t *user; | 445 | wchar_t *user; |
416 | wchar_t *domain; | 446 | wchar_t *domain; |
447 | wchar_t *server; | ||
417 | 448 | ||
418 | pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); | 449 | if (!ses->server->secmech.sdeschmacmd5) { |
419 | 450 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | |
420 | if (pctxt == NULL) | 451 | return -1; |
421 | return -ENOMEM; | 452 | } |
422 | 453 | ||
423 | /* calculate md4 hash of password */ | 454 | /* calculate md4 hash of password */ |
424 | E_md4hash(ses->password, nt_hash); | 455 | E_md4hash(ses->password, nt_hash); |
425 | 456 | ||
426 | /* convert Domainname to unicode and uppercase */ | 457 | crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash, |
427 | hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); | 458 | CIFS_NTHASH_SIZE); |
459 | |||
460 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); | ||
461 | if (rc) { | ||
462 | cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n"); | ||
463 | return rc; | ||
464 | } | ||
428 | 465 | ||
429 | /* convert ses->userName to unicode and uppercase */ | 466 | /* convert ses->userName to unicode and uppercase */ |
430 | len = strlen(ses->userName); | 467 | len = strlen(ses->userName); |
431 | user = kmalloc(2 + (len * 2), GFP_KERNEL); | 468 | user = kmalloc(2 + (len * 2), GFP_KERNEL); |
432 | if (user == NULL) | 469 | if (user == NULL) { |
470 | cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); | ||
471 | rc = -ENOMEM; | ||
433 | goto calc_exit_2; | 472 | goto calc_exit_2; |
473 | } | ||
434 | len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); | 474 | len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); |
435 | UniStrupr(user); | 475 | UniStrupr(user); |
436 | hmac_md5_update((char *)user, 2*len, pctxt); | 476 | |
477 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
478 | (char *)user, 2 * len); | ||
437 | 479 | ||
438 | /* convert ses->domainName to unicode and uppercase */ | 480 | /* convert ses->domainName to unicode and uppercase */ |
439 | if (ses->domainName) { | 481 | if (ses->domainName) { |
440 | len = strlen(ses->domainName); | 482 | len = strlen(ses->domainName); |
441 | 483 | ||
442 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); | 484 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); |
443 | if (domain == NULL) | 485 | if (domain == NULL) { |
486 | cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure"); | ||
487 | rc = -ENOMEM; | ||
444 | goto calc_exit_1; | 488 | goto calc_exit_1; |
489 | } | ||
445 | len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, | 490 | len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, |
446 | nls_cp); | 491 | nls_cp); |
447 | /* the following line was removed since it didn't work well | 492 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, |
448 | with lower cased domain name that passed as an option. | 493 | (char *)domain, 2 * len); |
449 | Maybe converting the domain name earlier makes sense */ | ||
450 | /* UniStrupr(domain); */ | ||
451 | |||
452 | hmac_md5_update((char *)domain, 2*len, pctxt); | ||
453 | |||
454 | kfree(domain); | 494 | kfree(domain); |
495 | } else if (ses->serverName) { | ||
496 | len = strlen(ses->serverName); | ||
497 | |||
498 | server = kmalloc(2 + (len * 2), GFP_KERNEL); | ||
499 | if (server == NULL) { | ||
500 | cERROR(1, "calc_ntlmv2_hash: server mem alloc failure"); | ||
501 | rc = -ENOMEM; | ||
502 | goto calc_exit_1; | ||
503 | } | ||
504 | len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, | ||
505 | nls_cp); | ||
506 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
507 | (char *)server, 2 * len); | ||
508 | kfree(server); | ||
455 | } | 509 | } |
510 | |||
511 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
512 | ntlmv2_hash); | ||
513 | |||
456 | calc_exit_1: | 514 | calc_exit_1: |
457 | kfree(user); | 515 | kfree(user); |
458 | calc_exit_2: | 516 | calc_exit_2: |
459 | /* BB FIXME what about bytes 24 through 40 of the signing key? | 517 | return rc; |
460 | compare with the NTLM example */ | 518 | } |
461 | hmac_md5_final(ses->ntlmv2_hash, pctxt); | 519 | |
520 | static int | ||
521 | CalcNTLMv2_response(const struct cifsSesInfo *ses, char *ntlmv2_hash) | ||
522 | { | ||
523 | int rc; | ||
524 | unsigned int offset = CIFS_SESS_KEY_SIZE + 8; | ||
525 | |||
526 | if (!ses->server->secmech.sdeschmacmd5) { | ||
527 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | ||
528 | return -1; | ||
529 | } | ||
530 | |||
531 | crypto_shash_setkey(ses->server->secmech.hmacmd5, | ||
532 | ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); | ||
533 | |||
534 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); | ||
535 | if (rc) { | ||
536 | cERROR(1, "CalcNTLMv2_response: could not init hmacmd5"); | ||
537 | return rc; | ||
538 | } | ||
539 | |||
540 | if (ses->server->secType == RawNTLMSSP) | ||
541 | memcpy(ses->auth_key.response + offset, | ||
542 | ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); | ||
543 | else | ||
544 | memcpy(ses->auth_key.response + offset, | ||
545 | ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); | ||
546 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
547 | ses->auth_key.response + offset, ses->auth_key.len - offset); | ||
548 | |||
549 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
550 | ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
462 | 551 | ||
463 | kfree(pctxt); | ||
464 | return rc; | 552 | return rc; |
465 | } | 553 | } |
466 | 554 | ||
555 | |||
467 | int | 556 | int |
468 | setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, | 557 | setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp) |
469 | const struct nls_table *nls_cp) | ||
470 | { | 558 | { |
471 | int rc; | 559 | int rc; |
472 | struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; | 560 | int baselen; |
473 | struct HMACMD5Context context; | 561 | unsigned int tilen; |
474 | 562 | struct ntlmv2_resp *buf; | |
475 | buf->blob_signature = cpu_to_le32(0x00000101); | 563 | char ntlmv2_hash[16]; |
476 | buf->reserved = 0; | 564 | unsigned char *tiblob = NULL; /* target info blob */ |
477 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
478 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); | ||
479 | buf->reserved2 = 0; | ||
480 | 565 | ||
481 | if (ses->server->secType == RawNTLMSSP) { | 566 | if (ses->server->secType == RawNTLMSSP) { |
482 | if (!ses->domainName) { | 567 | if (!ses->domainName) { |
483 | rc = find_domain_name(ses); | 568 | rc = find_domain_name(ses, nls_cp); |
484 | if (rc) { | 569 | if (rc) { |
485 | cERROR(1, "error %d finding domain name", rc); | 570 | cERROR(1, "error %d finding domain name", rc); |
486 | goto setup_ntlmv2_rsp_ret; | 571 | goto setup_ntlmv2_rsp_ret; |
@@ -490,51 +575,179 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, | |||
490 | rc = build_avpair_blob(ses, nls_cp); | 575 | rc = build_avpair_blob(ses, nls_cp); |
491 | if (rc) { | 576 | if (rc) { |
492 | cERROR(1, "error %d building av pair blob", rc); | 577 | cERROR(1, "error %d building av pair blob", rc); |
493 | return rc; | 578 | goto setup_ntlmv2_rsp_ret; |
494 | } | 579 | } |
495 | } | 580 | } |
496 | 581 | ||
497 | /* calculate buf->ntlmv2_hash */ | 582 | baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp); |
498 | rc = calc_ntlmv2_hash(ses, nls_cp); | 583 | tilen = ses->auth_key.len; |
584 | tiblob = ses->auth_key.response; | ||
585 | |||
586 | ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL); | ||
587 | if (!ses->auth_key.response) { | ||
588 | rc = ENOMEM; | ||
589 | ses->auth_key.len = 0; | ||
590 | cERROR(1, "%s: Can't allocate auth blob", __func__); | ||
591 | goto setup_ntlmv2_rsp_ret; | ||
592 | } | ||
593 | ses->auth_key.len += baselen; | ||
594 | |||
595 | buf = (struct ntlmv2_resp *) | ||
596 | (ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
597 | buf->blob_signature = cpu_to_le32(0x00000101); | ||
598 | buf->reserved = 0; | ||
599 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
600 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); | ||
601 | buf->reserved2 = 0; | ||
602 | |||
603 | memcpy(ses->auth_key.response + baselen, tiblob, tilen); | ||
604 | |||
605 | /* calculate ntlmv2_hash */ | ||
606 | rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); | ||
499 | if (rc) { | 607 | if (rc) { |
500 | cERROR(1, "could not get v2 hash rc %d", rc); | 608 | cERROR(1, "could not get v2 hash rc %d", rc); |
501 | goto setup_ntlmv2_rsp_ret; | 609 | goto setup_ntlmv2_rsp_ret; |
502 | } | 610 | } |
503 | CalcNTLMv2_response(ses, resp_buf); | 611 | |
612 | /* calculate first part of the client response (CR1) */ | ||
613 | rc = CalcNTLMv2_response(ses, ntlmv2_hash); | ||
614 | if (rc) { | ||
615 | cERROR(1, "Could not calculate CR1 rc: %d", rc); | ||
616 | goto setup_ntlmv2_rsp_ret; | ||
617 | } | ||
504 | 618 | ||
505 | /* now calculate the session key for NTLMv2 */ | 619 | /* now calculate the session key for NTLMv2 */ |
506 | hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context); | 620 | crypto_shash_setkey(ses->server->secmech.hmacmd5, |
507 | hmac_md5_update(resp_buf, 16, &context); | 621 | ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); |
508 | hmac_md5_final(ses->auth_key.data.ntlmv2.key, &context); | 622 | |
623 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); | ||
624 | if (rc) { | ||
625 | cERROR(1, "%s: Could not init hmacmd5\n", __func__); | ||
626 | goto setup_ntlmv2_rsp_ret; | ||
627 | } | ||
509 | 628 | ||
510 | memcpy(&ses->auth_key.data.ntlmv2.resp, resp_buf, | 629 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, |
511 | sizeof(struct ntlmv2_resp)); | 630 | ses->auth_key.response + CIFS_SESS_KEY_SIZE, |
512 | ses->auth_key.len = 16 + sizeof(struct ntlmv2_resp); | 631 | CIFS_HMAC_MD5_HASH_SIZE); |
513 | 632 | ||
514 | return 0; | 633 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, |
634 | ses->auth_key.response); | ||
515 | 635 | ||
516 | setup_ntlmv2_rsp_ret: | 636 | setup_ntlmv2_rsp_ret: |
517 | kfree(ses->tiblob); | 637 | kfree(tiblob); |
518 | ses->tiblob = NULL; | ||
519 | ses->tilen = 0; | ||
520 | 638 | ||
521 | return rc; | 639 | return rc; |
522 | } | 640 | } |
523 | 641 | ||
524 | void CalcNTLMv2_response(const struct cifsSesInfo *ses, | 642 | int |
525 | char *v2_session_response) | 643 | calc_seckey(struct cifsSesInfo *ses) |
526 | { | 644 | { |
527 | struct HMACMD5Context context; | 645 | int rc; |
528 | /* rest of v2 struct already generated */ | 646 | struct crypto_blkcipher *tfm_arc4; |
529 | memcpy(v2_session_response + 8, ses->cryptKey, 8); | 647 | struct scatterlist sgin, sgout; |
530 | hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context); | 648 | struct blkcipher_desc desc; |
649 | unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */ | ||
650 | |||
651 | get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE); | ||
652 | |||
653 | tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); | ||
654 | if (!tfm_arc4 || IS_ERR(tfm_arc4)) { | ||
655 | cERROR(1, "could not allocate crypto API arc4\n"); | ||
656 | return PTR_ERR(tfm_arc4); | ||
657 | } | ||
531 | 658 | ||
532 | hmac_md5_update(v2_session_response+8, | 659 | desc.tfm = tfm_arc4; |
533 | sizeof(struct ntlmv2_resp) - 8, &context); | ||
534 | 660 | ||
535 | if (ses->tilen) | 661 | crypto_blkcipher_setkey(tfm_arc4, ses->auth_key.response, |
536 | hmac_md5_update(ses->tiblob, ses->tilen, &context); | 662 | CIFS_SESS_KEY_SIZE); |
537 | 663 | ||
538 | hmac_md5_final(v2_session_response, &context); | 664 | sg_init_one(&sgin, sec_key, CIFS_SESS_KEY_SIZE); |
539 | /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ | 665 | sg_init_one(&sgout, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); |
666 | |||
667 | rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE); | ||
668 | if (rc) { | ||
669 | cERROR(1, "could not encrypt session key rc: %d\n", rc); | ||
670 | crypto_free_blkcipher(tfm_arc4); | ||
671 | return rc; | ||
672 | } | ||
673 | |||
674 | /* make secondary_key/nonce as session key */ | ||
675 | memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE); | ||
676 | /* and make len as that of session key only */ | ||
677 | ses->auth_key.len = CIFS_SESS_KEY_SIZE; | ||
678 | |||
679 | crypto_free_blkcipher(tfm_arc4); | ||
680 | |||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | void | ||
685 | cifs_crypto_shash_release(struct TCP_Server_Info *server) | ||
686 | { | ||
687 | if (server->secmech.md5) | ||
688 | crypto_free_shash(server->secmech.md5); | ||
689 | |||
690 | if (server->secmech.hmacmd5) | ||
691 | crypto_free_shash(server->secmech.hmacmd5); | ||
692 | |||
693 | kfree(server->secmech.sdeschmacmd5); | ||
694 | |||
695 | kfree(server->secmech.sdescmd5); | ||
696 | } | ||
697 | |||
698 | int | ||
699 | cifs_crypto_shash_allocate(struct TCP_Server_Info *server) | ||
700 | { | ||
701 | int rc; | ||
702 | unsigned int size; | ||
703 | |||
704 | server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0); | ||
705 | if (!server->secmech.hmacmd5 || | ||
706 | IS_ERR(server->secmech.hmacmd5)) { | ||
707 | cERROR(1, "could not allocate crypto hmacmd5\n"); | ||
708 | return PTR_ERR(server->secmech.hmacmd5); | ||
709 | } | ||
710 | |||
711 | server->secmech.md5 = crypto_alloc_shash("md5", 0, 0); | ||
712 | if (!server->secmech.md5 || IS_ERR(server->secmech.md5)) { | ||
713 | cERROR(1, "could not allocate crypto md5\n"); | ||
714 | rc = PTR_ERR(server->secmech.md5); | ||
715 | goto crypto_allocate_md5_fail; | ||
716 | } | ||
717 | |||
718 | size = sizeof(struct shash_desc) + | ||
719 | crypto_shash_descsize(server->secmech.hmacmd5); | ||
720 | server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); | ||
721 | if (!server->secmech.sdeschmacmd5) { | ||
722 | cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n"); | ||
723 | rc = -ENOMEM; | ||
724 | goto crypto_allocate_hmacmd5_sdesc_fail; | ||
725 | } | ||
726 | server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5; | ||
727 | server->secmech.sdeschmacmd5->shash.flags = 0x0; | ||
728 | |||
729 | |||
730 | size = sizeof(struct shash_desc) + | ||
731 | crypto_shash_descsize(server->secmech.md5); | ||
732 | server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL); | ||
733 | if (!server->secmech.sdescmd5) { | ||
734 | cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n"); | ||
735 | rc = -ENOMEM; | ||
736 | goto crypto_allocate_md5_sdesc_fail; | ||
737 | } | ||
738 | server->secmech.sdescmd5->shash.tfm = server->secmech.md5; | ||
739 | server->secmech.sdescmd5->shash.flags = 0x0; | ||
740 | |||
741 | return 0; | ||
742 | |||
743 | crypto_allocate_md5_sdesc_fail: | ||
744 | kfree(server->secmech.sdeschmacmd5); | ||
745 | |||
746 | crypto_allocate_hmacmd5_sdesc_fail: | ||
747 | crypto_free_shash(server->secmech.md5); | ||
748 | |||
749 | crypto_allocate_md5_fail: | ||
750 | crypto_free_shash(server->secmech.hmacmd5); | ||
751 | |||
752 | return rc; | ||
540 | } | 753 | } |