diff options
Diffstat (limited to 'fs/cifs/cifsencrypt.c')
-rw-r--r-- | fs/cifs/cifsencrypt.c | 195 |
1 files changed, 136 insertions, 59 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index eaa2327ee7af..96908874a45c 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -45,17 +45,30 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, | |||
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 | struct TCP_Server_Info *server, 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 || server == 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, server->session_key.response, | 54 | cERROR(1, "%s: Can't generate signature\n", __func__); |
55 | server->session_key.len); | 55 | return -1; |
56 | cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); | 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); | ||
57 | 71 | ||
58 | cifs_MD5_final(signature, &context); | ||
59 | return 0; | 72 | return 0; |
60 | } | 73 | } |
61 | 74 | ||
@@ -92,15 +105,26 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
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 | struct TCP_Server_Info *server, 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 || server == 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, server->session_key.response, | 115 | cERROR(1, "%s: Can't generate signature\n", __func__); |
103 | server->session_key.len); | 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 | |||
104 | for (i = 0; i < n_vec; i++) { | 128 | for (i = 0; i < n_vec; i++) { |
105 | if (iov[i].iov_len == 0) | 129 | if (iov[i].iov_len == 0) |
106 | continue; | 130 | continue; |
@@ -113,18 +137,18 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | |||
113 | if (i == 0) { | 137 | if (i == 0) { |
114 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | 138 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ |
115 | break; /* nothing to sign or corrupt header */ | 139 | break; /* nothing to sign or corrupt header */ |
116 | cifs_MD5_update(&context, iov[0].iov_base+4, | 140 | crypto_shash_update(&server->secmech.sdescmd5->shash, |
117 | iov[0].iov_len-4); | 141 | iov[i].iov_base + 4, iov[i].iov_len - 4); |
118 | } else | 142 | } else |
119 | 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); | ||
120 | } | 145 | } |
121 | 146 | ||
122 | cifs_MD5_final(signature, &context); | 147 | rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); |
123 | 148 | ||
124 | return 0; | 149 | return rc; |
125 | } | 150 | } |
126 | 151 | ||
127 | |||
128 | 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, |
129 | __u32 *pexpected_response_sequence_number) | 153 | __u32 *pexpected_response_sequence_number) |
130 | { | 154 | { |
@@ -420,67 +444,120 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, | |||
420 | { | 444 | { |
421 | int rc = 0; | 445 | int rc = 0; |
422 | int len; | 446 | int len; |
423 | char nt_hash[16]; | 447 | char nt_hash[CIFS_NTHASH_SIZE]; |
424 | struct HMACMD5Context *pctxt; | ||
425 | wchar_t *user; | 448 | wchar_t *user; |
426 | wchar_t *domain; | 449 | wchar_t *domain; |
450 | wchar_t *server; | ||
427 | 451 | ||
428 | pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); | 452 | if (!ses->server->secmech.sdeschmacmd5) { |
429 | 453 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | |
430 | if (pctxt == NULL) | 454 | return -1; |
431 | return -ENOMEM; | 455 | } |
432 | 456 | ||
433 | /* calculate md4 hash of password */ | 457 | /* calculate md4 hash of password */ |
434 | E_md4hash(ses->password, nt_hash); | 458 | E_md4hash(ses->password, nt_hash); |
435 | 459 | ||
436 | /* convert Domainname to unicode and uppercase */ | 460 | crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash, |
437 | hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); | 461 | CIFS_NTHASH_SIZE); |
462 | |||
463 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); | ||
464 | if (rc) { | ||
465 | cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n"); | ||
466 | return rc; | ||
467 | } | ||
438 | 468 | ||
439 | /* convert ses->userName to unicode and uppercase */ | 469 | /* convert ses->userName to unicode and uppercase */ |
440 | len = strlen(ses->userName); | 470 | len = strlen(ses->userName); |
441 | user = kmalloc(2 + (len * 2), GFP_KERNEL); | 471 | user = kmalloc(2 + (len * 2), GFP_KERNEL); |
442 | if (user == NULL) | 472 | if (user == NULL) { |
473 | cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); | ||
474 | rc = -ENOMEM; | ||
443 | goto calc_exit_2; | 475 | goto calc_exit_2; |
476 | } | ||
444 | len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); | 477 | len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); |
445 | UniStrupr(user); | 478 | UniStrupr(user); |
446 | hmac_md5_update((char *)user, 2*len, pctxt); | 479 | |
480 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
481 | (char *)user, 2 * len); | ||
447 | 482 | ||
448 | /* convert ses->domainName to unicode and uppercase */ | 483 | /* convert ses->domainName to unicode and uppercase */ |
449 | if (ses->domainName) { | 484 | if (ses->domainName) { |
450 | len = strlen(ses->domainName); | 485 | len = strlen(ses->domainName); |
451 | 486 | ||
452 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); | 487 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); |
453 | if (domain == NULL) | 488 | if (domain == NULL) { |
489 | cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure"); | ||
490 | rc = -ENOMEM; | ||
454 | goto calc_exit_1; | 491 | goto calc_exit_1; |
492 | } | ||
455 | len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, | 493 | len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, |
456 | nls_cp); | 494 | nls_cp); |
457 | /* the following line was removed since it didn't work well | 495 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, |
458 | with lower cased domain name that passed as an option. | 496 | (char *)domain, 2 * len); |
459 | Maybe converting the domain name earlier makes sense */ | ||
460 | /* UniStrupr(domain); */ | ||
461 | |||
462 | hmac_md5_update((char *)domain, 2*len, pctxt); | ||
463 | |||
464 | kfree(domain); | 497 | kfree(domain); |
498 | } else if (ses->serverName) { | ||
499 | len = strlen(ses->serverName); | ||
500 | |||
501 | server = kmalloc(2 + (len * 2), GFP_KERNEL); | ||
502 | if (server == NULL) { | ||
503 | cERROR(1, "calc_ntlmv2_hash: server mem alloc failure"); | ||
504 | rc = -ENOMEM; | ||
505 | goto calc_exit_1; | ||
506 | } | ||
507 | len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, | ||
508 | nls_cp); | ||
509 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
510 | (char *)server, 2 * len); | ||
511 | kfree(server); | ||
465 | } | 512 | } |
513 | |||
514 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
515 | ses->ntlmv2_hash); | ||
516 | |||
466 | calc_exit_1: | 517 | calc_exit_1: |
467 | kfree(user); | 518 | kfree(user); |
468 | calc_exit_2: | 519 | calc_exit_2: |
469 | /* BB FIXME what about bytes 24 through 40 of the signing key? | 520 | return rc; |
470 | compare with the NTLM example */ | 521 | } |
471 | hmac_md5_final(ses->ntlmv2_hash, pctxt); | 522 | |
523 | static int | ||
524 | CalcNTLMv2_response(const struct cifsSesInfo *ses) | ||
525 | { | ||
526 | int rc; | ||
527 | unsigned int offset = CIFS_SESS_KEY_SIZE + 8; | ||
528 | |||
529 | if (!ses->server->secmech.sdeschmacmd5) { | ||
530 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | ||
531 | return -1; | ||
532 | } | ||
533 | |||
534 | crypto_shash_setkey(ses->server->secmech.hmacmd5, | ||
535 | ses->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); | ||
536 | |||
537 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); | ||
538 | if (rc) { | ||
539 | cERROR(1, "CalcNTLMv2_response: could not init hmacmd5"); | ||
540 | return rc; | ||
541 | } | ||
542 | |||
543 | memcpy(ses->auth_key.response + offset, | ||
544 | ses->cryptKey, CIFS_SERVER_CHALLENGE_SIZE); | ||
545 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
546 | ses->auth_key.response + offset, ses->auth_key.len - offset); | ||
547 | |||
548 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
549 | ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
472 | 550 | ||
473 | kfree(pctxt); | ||
474 | return rc; | 551 | return rc; |
475 | } | 552 | } |
476 | 553 | ||
554 | |||
477 | int | 555 | int |
478 | setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp) | 556 | setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp) |
479 | { | 557 | { |
480 | int rc; | 558 | int rc; |
481 | int baselen; | 559 | int baselen; |
482 | struct ntlmv2_resp *buf; | 560 | struct ntlmv2_resp *buf; |
483 | struct HMACMD5Context context; | ||
484 | 561 | ||
485 | if (ses->server->secType == RawNTLMSSP) { | 562 | if (ses->server->secType == RawNTLMSSP) { |
486 | if (!ses->domainName) { | 563 | if (!ses->domainName) { |
@@ -523,13 +600,28 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp) | |||
523 | cERROR(1, "could not get v2 hash rc %d", rc); | 600 | cERROR(1, "could not get v2 hash rc %d", rc); |
524 | goto setup_ntlmv2_rsp_ret; | 601 | goto setup_ntlmv2_rsp_ret; |
525 | } | 602 | } |
526 | CalcNTLMv2_response(ses); | 603 | rc = CalcNTLMv2_response(ses); |
604 | if (rc) { | ||
605 | cERROR(1, "Could not calculate CR1 rc: %d", rc); | ||
606 | goto setup_ntlmv2_rsp_ret; | ||
607 | } | ||
527 | 608 | ||
528 | /* now calculate the session key for NTLMv2 */ | 609 | /* now calculate the session key for NTLMv2 */ |
529 | hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context); | 610 | crypto_shash_setkey(ses->server->secmech.hmacmd5, |
530 | hmac_md5_update(ses->auth_key.response + CIFS_SESS_KEY_SIZE, | 611 | ses->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); |
531 | 16, &context); | 612 | |
532 | hmac_md5_final(ses->auth_key.response, &context); | 613 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); |
614 | if (rc) { | ||
615 | cERROR(1, "%s: Could not init hmacmd5\n", __func__); | ||
616 | goto setup_ntlmv2_rsp_ret; | ||
617 | } | ||
618 | |||
619 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
620 | ses->auth_key.response + CIFS_SESS_KEY_SIZE, | ||
621 | CIFS_HMAC_MD5_HASH_SIZE); | ||
622 | |||
623 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
624 | ses->auth_key.response); | ||
533 | 625 | ||
534 | return 0; | 626 | return 0; |
535 | 627 | ||
@@ -653,18 +745,3 @@ crypto_allocate_md5_fail: | |||
653 | 745 | ||
654 | return rc; | 746 | return rc; |
655 | } | 747 | } |
656 | |||
657 | void CalcNTLMv2_response(const struct cifsSesInfo *ses) | ||
658 | { | ||
659 | unsigned int offset = CIFS_SESS_KEY_SIZE + 8; | ||
660 | struct HMACMD5Context context; | ||
661 | |||
662 | /* rest of v2 struct already generated */ | ||
663 | memcpy(ses->auth_key.response + offset, ses->cryptKey, 8); | ||
664 | hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context); | ||
665 | |||
666 | hmac_md5_update(ses->auth_key.response + offset, | ||
667 | ses->auth_key.len - offset, &context); | ||
668 | |||
669 | hmac_md5_final(ses->auth_key.response + CIFS_SESS_KEY_SIZE, &context); | ||
670 | } | ||