aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifsencrypt.c
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2010-10-21 07:42:55 -0400
committerSteve French <sfrench@us.ibm.com>2010-10-26 14:20:10 -0400
commit21e733930be6458e0c33482b6783e7c15ba984eb (patch)
tree1458ccf45529649267451a7e06fcd25d9c7ab0ac /fs/cifs/cifsencrypt.c
parent6573e9b73e19c0f6b9dfa2b399267ea0f42d6c6b (diff)
NTLM auth and sign - Allocate session key/client response dynamically
Start calculating auth response within a session. Move/Add pertinet data structures like session key, server challenge and ntlmv2_hash in a session structure. We should do the calculations within a session before copying session key and response over to server data structures because a session setup can fail. Only after a very first smb session succeeds, it copy/make its session key, session key of smb connection. This key stays with the smb connection throughout its life. sequence_number within server is set to 0x2. The authentication Message Authentication Key (mak) which consists of session key followed by client response within structure session_key is now dynamic. Every authentication type allocates the key + response sized memory within its session structure and later either assigns or frees it once the client response is sent and if session's session key becomes connetion's session key. ntlm/ntlmi authentication functions are rearranged. A function named setup_ntlm_resp(), similar to setup_ntlmv2_resp(), replaces function cifs_calculate_session_key(). size of CIFS_SESS_KEY_SIZE is changed to 16, to reflect the byte size of the key it holds. Reviewed-by: Jeff Layton <jlayton@samba.org> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/cifsencrypt.c')
-rw-r--r--fs/cifs/cifsencrypt.c113
1 files changed, 65 insertions, 48 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 7ac0056294cf..987b479d55dd 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -43,15 +43,16 @@ extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
43 unsigned char *p24); 43 unsigned char *p24);
44 44
45static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, 45static 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 struct MD5Context context;
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 cifs_MD5_init(&context);
54 cifs_MD5_update(&context, (char *)&key->data, key->len); 54 cifs_MD5_update(&context, server->session_key.response,
55 server->session_key.len);
55 cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); 56 cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length);
56 57
57 cifs_MD5_final(signature, &context); 58 cifs_MD5_final(signature, &context);
@@ -79,8 +80,7 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
79 server->sequence_number++; 80 server->sequence_number++;
80 spin_unlock(&GlobalMid_Lock); 81 spin_unlock(&GlobalMid_Lock);
81 82
82 rc = cifs_calculate_signature(cifs_pdu, &server->session_key, 83 rc = cifs_calculate_signature(cifs_pdu, server, smb_signature);
83 smb_signature);
84 if (rc) 84 if (rc)
85 memset(cifs_pdu->Signature.SecuritySignature, 0, 8); 85 memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
86 else 86 else
@@ -90,16 +90,17 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
90} 90}
91 91
92static int cifs_calc_signature2(const struct kvec *iov, int n_vec, 92static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
93 const struct session_key *key, char *signature) 93 struct TCP_Server_Info *server, char *signature)
94{ 94{
95 struct MD5Context context; 95 struct MD5Context context;
96 int i; 96 int i;
97 97
98 if ((iov == NULL) || (signature == NULL) || (key == NULL)) 98 if (iov == NULL || signature == NULL || server == NULL)
99 return -EINVAL; 99 return -EINVAL;
100 100
101 cifs_MD5_init(&context); 101 cifs_MD5_init(&context);
102 cifs_MD5_update(&context, (char *)&key->data, key->len); 102 cifs_MD5_update(&context, server->session_key.response,
103 server->session_key.len);
103 for (i = 0; i < n_vec; i++) { 104 for (i = 0; i < n_vec; i++) {
104 if (iov[i].iov_len == 0) 105 if (iov[i].iov_len == 0)
105 continue; 106 continue;
@@ -146,8 +147,7 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
146 server->sequence_number++; 147 server->sequence_number++;
147 spin_unlock(&GlobalMid_Lock); 148 spin_unlock(&GlobalMid_Lock);
148 149
149 rc = cifs_calc_signature2(iov, n_vec, &server->session_key, 150 rc = cifs_calc_signature2(iov, n_vec, server, smb_signature);
150 smb_signature);
151 if (rc) 151 if (rc)
152 memset(cifs_pdu->Signature.SecuritySignature, 0, 8); 152 memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
153 else 153 else
@@ -157,14 +157,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
157} 157}
158 158
159int cifs_verify_signature(struct smb_hdr *cifs_pdu, 159int cifs_verify_signature(struct smb_hdr *cifs_pdu,
160 const struct session_key *session_key, 160 struct TCP_Server_Info *server,
161 __u32 expected_sequence_number) 161 __u32 expected_sequence_number)
162{ 162{
163 unsigned int rc; 163 unsigned int rc;
164 char server_response_sig[8]; 164 char server_response_sig[8];
165 char what_we_think_sig_should_be[20]; 165 char what_we_think_sig_should_be[20];
166 166
167 if (cifs_pdu == NULL || session_key == NULL) 167 if (cifs_pdu == NULL || server == NULL)
168 return -EINVAL; 168 return -EINVAL;
169 169
170 if (cifs_pdu->Command == SMB_COM_NEGOTIATE) 170 if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
@@ -193,7 +193,7 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
193 cpu_to_le32(expected_sequence_number); 193 cpu_to_le32(expected_sequence_number);
194 cifs_pdu->Signature.Sequence.Reserved = 0; 194 cifs_pdu->Signature.Sequence.Reserved = 0;
195 195
196 rc = cifs_calculate_signature(cifs_pdu, session_key, 196 rc = cifs_calculate_signature(cifs_pdu, server,
197 what_we_think_sig_should_be); 197 what_we_think_sig_should_be);
198 198
199 if (rc) 199 if (rc)
@@ -209,18 +209,28 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu,
209 209
210} 210}
211 211
212/* We fill in key by putting in 40 byte array which was allocated by caller */ 212/* first calculate 24 bytes ntlm response and then 16 byte session key */
213int cifs_calculate_session_key(struct session_key *key, const char *rn, 213int setup_ntlm_response(struct cifsSesInfo *ses)
214 const char *password)
215{ 214{
216 char temp_key[16]; 215 unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE;
217 if ((key == NULL) || (rn == NULL)) 216 char temp_key[CIFS_SESS_KEY_SIZE];
217
218 if (!ses)
218 return -EINVAL; 219 return -EINVAL;
219 220
220 E_md4hash(password, temp_key); 221 ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL);
221 mdfour(key->data.ntlm, temp_key, 16); 222 if (!ses->auth_key.response) {
222 memcpy(key->data.ntlm+16, rn, CIFS_SESS_KEY_SIZE); 223 cERROR(1, "NTLM can't allocate (%u bytes) memory", temp_len);
223 key->len = 40; 224 return -ENOMEM;
225 }
226 ses->auth_key.len = temp_len;
227
228 SMBNTencrypt(ses->password, ses->cryptKey,
229 ses->auth_key.response + CIFS_SESS_KEY_SIZE);
230
231 E_md4hash(ses->password, temp_key);
232 mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE);
233
224 return 0; 234 return 0;
225} 235}
226 236
@@ -465,19 +475,13 @@ calc_exit_2:
465} 475}
466 476
467int 477int
468setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, 478setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
469 const struct nls_table *nls_cp)
470{ 479{
471 int rc; 480 int rc;
472 struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; 481 int baselen;
482 struct ntlmv2_resp *buf;
473 struct HMACMD5Context context; 483 struct HMACMD5Context context;
474 484
475 buf->blob_signature = cpu_to_le32(0x00000101);
476 buf->reserved = 0;
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
481 if (ses->server->secType == RawNTLMSSP) { 485 if (ses->server->secType == RawNTLMSSP) {
482 if (!ses->domainName) { 486 if (!ses->domainName) {
483 rc = find_domain_name(ses); 487 rc = find_domain_name(ses);
@@ -494,22 +498,38 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
494 } 498 }
495 } 499 }
496 500
501 baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
502 ses->auth_key.len = baselen + ses->tilen;
503 ses->auth_key.response = kmalloc(ses->auth_key.len, GFP_KERNEL);
504 if (!ses->auth_key.response) {
505 rc = ENOMEM;
506 cERROR(1, "%s: Can't allocate auth blob", __func__);
507 goto setup_ntlmv2_rsp_ret;
508 }
509
510 buf = (struct ntlmv2_resp *)
511 (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
512 buf->blob_signature = cpu_to_le32(0x00000101);
513 buf->reserved = 0;
514 buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
515 get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
516 buf->reserved2 = 0;
517
518 memcpy(ses->auth_key.response + baselen, ses->tiblob, ses->tilen);
519
497 /* calculate buf->ntlmv2_hash */ 520 /* calculate buf->ntlmv2_hash */
498 rc = calc_ntlmv2_hash(ses, nls_cp); 521 rc = calc_ntlmv2_hash(ses, nls_cp);
499 if (rc) { 522 if (rc) {
500 cERROR(1, "could not get v2 hash rc %d", rc); 523 cERROR(1, "could not get v2 hash rc %d", rc);
501 goto setup_ntlmv2_rsp_ret; 524 goto setup_ntlmv2_rsp_ret;
502 } 525 }
503 CalcNTLMv2_response(ses, resp_buf); 526 CalcNTLMv2_response(ses);
504 527
505 /* now calculate the session key for NTLMv2 */ 528 /* now calculate the session key for NTLMv2 */
506 hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context); 529 hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context);
507 hmac_md5_update(resp_buf, 16, &context); 530 hmac_md5_update(ses->auth_key.response + CIFS_SESS_KEY_SIZE,
508 hmac_md5_final(ses->auth_key.data.ntlmv2.key, &context); 531 16, &context);
509 532 hmac_md5_final(ses->auth_key.response, &context);
510 memcpy(&ses->auth_key.data.ntlmv2.resp, resp_buf,
511 sizeof(struct ntlmv2_resp));
512 ses->auth_key.len = 16 + sizeof(struct ntlmv2_resp);
513 533
514 return 0; 534 return 0;
515 535
@@ -521,20 +541,17 @@ setup_ntlmv2_rsp_ret:
521 return rc; 541 return rc;
522} 542}
523 543
524void CalcNTLMv2_response(const struct cifsSesInfo *ses, 544void CalcNTLMv2_response(const struct cifsSesInfo *ses)
525 char *v2_session_response)
526{ 545{
546 unsigned int offset = CIFS_SESS_KEY_SIZE + 8;
527 struct HMACMD5Context context; 547 struct HMACMD5Context context;
548
528 /* rest of v2 struct already generated */ 549 /* rest of v2 struct already generated */
529 memcpy(v2_session_response + 8, ses->cryptKey, 8); 550 memcpy(ses->auth_key.response + offset, ses->cryptKey, 8);
530 hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context); 551 hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context);
531 552
532 hmac_md5_update(v2_session_response+8, 553 hmac_md5_update(ses->auth_key.response + offset,
533 sizeof(struct ntlmv2_resp) - 8, &context); 554 ses->auth_key.len - offset, &context);
534
535 if (ses->tilen)
536 hmac_md5_update(ses->tiblob, ses->tilen, &context);
537 555
538 hmac_md5_final(v2_session_response, &context); 556 hmac_md5_final(ses->auth_key.response + CIFS_SESS_KEY_SIZE, &context);
539/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
540} 557}