aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2010-10-21 15:25:17 -0400
committerSteve French <sfrench@us.ibm.com>2010-10-26 14:38:06 -0400
commit307fbd31b61623ad1b5388b452118f8aea99f9d0 (patch)
tree71231b840aac77531d5dc26021ecb0451feab7ae
parentd2b915210b5ec01409f581421d633eca6c38d444 (diff)
NTLM auth and sign - Use kernel crypto apis to calculate hashes and smb signatures
Use kernel crypto sync hash apis insetead of cifs crypto functions. The calls typically corrospond one to one except that insead of key init, setkey is used. Use crypto apis to generate smb signagtures also. Use hmac-md5 to genereate ntlmv2 hash, ntlmv2 response, and HMAC (CR1 of ntlmv2 auth blob. User crypto apis to genereate signature and to verify signature. md5 hash is used to calculate signature. Use secondary key to calculate signature in case of ntlmssp. For ntlmv2 within ntlmssp, during signature calculation, only 16 bytes key (a nonce) stored within session key is used. during smb signature calculation. For ntlm and ntlmv2 without extended security, 16 bytes key as well as entire response (24 bytes in case of ntlm and variable length in case of ntlmv2) is used for smb signature calculation. For kerberos, there is no distinction between key and response. Acked-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/cifsencrypt.c195
-rw-r--r--fs/cifs/cifsproto.h1
2 files changed, 136 insertions, 60 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,
45static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, 45static 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,
92static int cifs_calc_signature2(const struct kvec *iov, int n_vec, 105static 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
128int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, 152int 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
466calc_exit_1: 517calc_exit_1:
467 kfree(user); 518 kfree(user);
468calc_exit_2: 519calc_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
523static int
524CalcNTLMv2_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
477int 555int
478setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp) 556setup_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
657void 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}
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 1e4728bcf065..edb6d90efdf2 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -366,7 +366,6 @@ extern int cifs_verify_signature(struct smb_hdr *,
366 __u32 expected_sequence_number); 366 __u32 expected_sequence_number);
367extern void SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *); 367extern void SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *);
368extern int setup_ntlm_response(struct cifsSesInfo *); 368extern int setup_ntlm_response(struct cifsSesInfo *);
369extern void CalcNTLMv2_response(const struct cifsSesInfo *);
370extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *); 369extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *);
371extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); 370extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
372extern void cifs_crypto_shash_release(struct TCP_Server_Info *); 371extern void cifs_crypto_shash_release(struct TCP_Server_Info *);