diff options
Diffstat (limited to 'fs/cifs/cifsencrypt.c')
-rw-r--r-- | fs/cifs/cifsencrypt.c | 616 |
1 files changed, 504 insertions, 112 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 35042d8f7338..5a0ee7f2af06 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -24,39 +24,50 @@ | |||
24 | #include "cifspdu.h" | 24 | #include "cifspdu.h" |
25 | #include "cifsglob.h" | 25 | #include "cifsglob.h" |
26 | #include "cifs_debug.h" | 26 | #include "cifs_debug.h" |
27 | #include "md5.h" | ||
28 | #include "cifs_unicode.h" | 27 | #include "cifs_unicode.h" |
29 | #include "cifsproto.h" | 28 | #include "cifsproto.h" |
29 | #include "ntlmssp.h" | ||
30 | #include <linux/ctype.h> | 30 | #include <linux/ctype.h> |
31 | #include <linux/random.h> | 31 | #include <linux/random.h> |
32 | 32 | ||
33 | /* Calculate and return the CIFS signature based on the mac key and SMB PDU */ | 33 | /* |
34 | /* the 16 byte signature must be allocated by the caller */ | 34 | * Calculate and return the CIFS signature based on the mac key and SMB PDU. |
35 | /* Note we only use the 1st eight bytes */ | 35 | * The 16 byte signature must be allocated by the caller. Note we only use the |
36 | /* Note that the smb header signature field on input contains the | 36 | * 1st eight bytes and that the smb header signature field on input contains |
37 | sequence number before this function is called */ | 37 | * the sequence number before this function is called. Also, this function |
38 | 38 | * should be called with the server->srv_mutex held. | |
39 | extern void mdfour(unsigned char *out, unsigned char *in, int n); | 39 | */ |
40 | extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); | ||
41 | extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, | ||
42 | unsigned char *p24); | ||
43 | |||
44 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, | 40 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, |
45 | const struct mac_key *key, char *signature) | 41 | struct TCP_Server_Info *server, char *signature) |
46 | { | 42 | { |
47 | struct MD5Context context; | 43 | int rc; |
48 | 44 | ||
49 | if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL)) | 45 | if (cifs_pdu == NULL || signature == NULL || server == NULL) |
50 | return -EINVAL; | 46 | return -EINVAL; |
51 | 47 | ||
52 | cifs_MD5_init(&context); | 48 | if (!server->secmech.sdescmd5) { |
53 | cifs_MD5_update(&context, (char *)&key->data, key->len); | 49 | cERROR(1, "%s: Can't generate signature\n", __func__); |
54 | cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); | 50 | return -1; |
51 | } | ||
52 | |||
53 | rc = crypto_shash_init(&server->secmech.sdescmd5->shash); | ||
54 | if (rc) { | ||
55 | cERROR(1, "%s: Oould not init md5\n", __func__); | ||
56 | return rc; | ||
57 | } | ||
58 | |||
59 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
60 | server->session_key.response, server->session_key.len); | ||
61 | |||
62 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
63 | cifs_pdu->Protocol, be32_to_cpu(cifs_pdu->smb_buf_length)); | ||
64 | |||
65 | rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); | ||
55 | 66 | ||
56 | cifs_MD5_final(signature, &context); | ||
57 | return 0; | 67 | return 0; |
58 | } | 68 | } |
59 | 69 | ||
70 | /* must be called with server->srv_mutex held */ | ||
60 | int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | 71 | int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, |
61 | __u32 *pexpected_response_sequence_number) | 72 | __u32 *pexpected_response_sequence_number) |
62 | { | 73 | { |
@@ -69,17 +80,14 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
69 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | 80 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) |
70 | return rc; | 81 | return rc; |
71 | 82 | ||
72 | spin_lock(&GlobalMid_Lock); | ||
73 | cifs_pdu->Signature.Sequence.SequenceNumber = | 83 | cifs_pdu->Signature.Sequence.SequenceNumber = |
74 | cpu_to_le32(server->sequence_number); | 84 | cpu_to_le32(server->sequence_number); |
75 | cifs_pdu->Signature.Sequence.Reserved = 0; | 85 | cifs_pdu->Signature.Sequence.Reserved = 0; |
76 | 86 | ||
77 | *pexpected_response_sequence_number = server->sequence_number++; | 87 | *pexpected_response_sequence_number = server->sequence_number++; |
78 | server->sequence_number++; | 88 | server->sequence_number++; |
79 | spin_unlock(&GlobalMid_Lock); | ||
80 | 89 | ||
81 | rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key, | 90 | rc = cifs_calculate_signature(cifs_pdu, server, smb_signature); |
82 | smb_signature); | ||
83 | if (rc) | 91 | if (rc) |
84 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 92 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
85 | else | 93 | else |
@@ -89,16 +97,28 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
89 | } | 97 | } |
90 | 98 | ||
91 | static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | 99 | static int cifs_calc_signature2(const struct kvec *iov, int n_vec, |
92 | const struct mac_key *key, char *signature) | 100 | struct TCP_Server_Info *server, char *signature) |
93 | { | 101 | { |
94 | struct MD5Context context; | ||
95 | int i; | 102 | int i; |
103 | int rc; | ||
96 | 104 | ||
97 | if ((iov == NULL) || (signature == NULL) || (key == NULL)) | 105 | if (iov == NULL || signature == NULL || server == NULL) |
98 | return -EINVAL; | 106 | return -EINVAL; |
99 | 107 | ||
100 | cifs_MD5_init(&context); | 108 | if (!server->secmech.sdescmd5) { |
101 | cifs_MD5_update(&context, (char *)&key->data, key->len); | 109 | cERROR(1, "%s: Can't generate signature\n", __func__); |
110 | return -1; | ||
111 | } | ||
112 | |||
113 | rc = crypto_shash_init(&server->secmech.sdescmd5->shash); | ||
114 | if (rc) { | ||
115 | cERROR(1, "%s: Oould not init md5\n", __func__); | ||
116 | return rc; | ||
117 | } | ||
118 | |||
119 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
120 | server->session_key.response, server->session_key.len); | ||
121 | |||
102 | for (i = 0; i < n_vec; i++) { | 122 | for (i = 0; i < n_vec; i++) { |
103 | if (iov[i].iov_len == 0) | 123 | if (iov[i].iov_len == 0) |
104 | continue; | 124 | continue; |
@@ -111,18 +131,19 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | |||
111 | if (i == 0) { | 131 | if (i == 0) { |
112 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | 132 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ |
113 | break; /* nothing to sign or corrupt header */ | 133 | break; /* nothing to sign or corrupt header */ |
114 | cifs_MD5_update(&context, iov[0].iov_base+4, | 134 | crypto_shash_update(&server->secmech.sdescmd5->shash, |
115 | iov[0].iov_len-4); | 135 | iov[i].iov_base + 4, iov[i].iov_len - 4); |
116 | } else | 136 | } else |
117 | cifs_MD5_update(&context, iov[i].iov_base, iov[i].iov_len); | 137 | crypto_shash_update(&server->secmech.sdescmd5->shash, |
138 | iov[i].iov_base, iov[i].iov_len); | ||
118 | } | 139 | } |
119 | 140 | ||
120 | cifs_MD5_final(signature, &context); | 141 | rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); |
121 | 142 | ||
122 | return 0; | 143 | return rc; |
123 | } | 144 | } |
124 | 145 | ||
125 | 146 | /* must be called with server->srv_mutex held */ | |
126 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | 147 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, |
127 | __u32 *pexpected_response_sequence_number) | 148 | __u32 *pexpected_response_sequence_number) |
128 | { | 149 | { |
@@ -136,17 +157,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | |||
136 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | 157 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) |
137 | return rc; | 158 | return rc; |
138 | 159 | ||
139 | spin_lock(&GlobalMid_Lock); | ||
140 | cifs_pdu->Signature.Sequence.SequenceNumber = | 160 | cifs_pdu->Signature.Sequence.SequenceNumber = |
141 | cpu_to_le32(server->sequence_number); | 161 | cpu_to_le32(server->sequence_number); |
142 | cifs_pdu->Signature.Sequence.Reserved = 0; | 162 | cifs_pdu->Signature.Sequence.Reserved = 0; |
143 | 163 | ||
144 | *pexpected_response_sequence_number = server->sequence_number++; | 164 | *pexpected_response_sequence_number = server->sequence_number++; |
145 | server->sequence_number++; | 165 | server->sequence_number++; |
146 | spin_unlock(&GlobalMid_Lock); | ||
147 | 166 | ||
148 | rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key, | 167 | rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); |
149 | smb_signature); | ||
150 | if (rc) | 168 | if (rc) |
151 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 169 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
152 | else | 170 | else |
@@ -156,17 +174,17 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | |||
156 | } | 174 | } |
157 | 175 | ||
158 | int cifs_verify_signature(struct smb_hdr *cifs_pdu, | 176 | int cifs_verify_signature(struct smb_hdr *cifs_pdu, |
159 | const struct mac_key *mac_key, | 177 | struct TCP_Server_Info *server, |
160 | __u32 expected_sequence_number) | 178 | __u32 expected_sequence_number) |
161 | { | 179 | { |
162 | unsigned int rc; | 180 | unsigned int rc; |
163 | char server_response_sig[8]; | 181 | char server_response_sig[8]; |
164 | char what_we_think_sig_should_be[20]; | 182 | char what_we_think_sig_should_be[20]; |
165 | 183 | ||
166 | if ((cifs_pdu == NULL) || (mac_key == NULL)) | 184 | if (cifs_pdu == NULL || server == NULL) |
167 | return -EINVAL; | 185 | return -EINVAL; |
168 | 186 | ||
169 | if (cifs_pdu->Command == SMB_COM_NEGOTIATE) | 187 | if (!server->session_estab) |
170 | return 0; | 188 | return 0; |
171 | 189 | ||
172 | if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { | 190 | if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { |
@@ -192,8 +210,10 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, | |||
192 | cpu_to_le32(expected_sequence_number); | 210 | cpu_to_le32(expected_sequence_number); |
193 | cifs_pdu->Signature.Sequence.Reserved = 0; | 211 | cifs_pdu->Signature.Sequence.Reserved = 0; |
194 | 212 | ||
195 | rc = cifs_calculate_signature(cifs_pdu, mac_key, | 213 | mutex_lock(&server->srv_mutex); |
214 | rc = cifs_calculate_signature(cifs_pdu, server, | ||
196 | what_we_think_sig_should_be); | 215 | what_we_think_sig_should_be); |
216 | mutex_unlock(&server->srv_mutex); | ||
197 | 217 | ||
198 | if (rc) | 218 | if (rc) |
199 | return rc; | 219 | return rc; |
@@ -208,26 +228,51 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, | |||
208 | 228 | ||
209 | } | 229 | } |
210 | 230 | ||
211 | /* We fill in key by putting in 40 byte array which was allocated by caller */ | 231 | /* first calculate 24 bytes ntlm response and then 16 byte session key */ |
212 | int cifs_calculate_mac_key(struct mac_key *key, const char *rn, | 232 | int setup_ntlm_response(struct cifs_ses *ses) |
213 | const char *password) | ||
214 | { | 233 | { |
215 | char temp_key[16]; | 234 | int rc = 0; |
216 | if ((key == NULL) || (rn == NULL)) | 235 | unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE; |
236 | char temp_key[CIFS_SESS_KEY_SIZE]; | ||
237 | |||
238 | if (!ses) | ||
217 | return -EINVAL; | 239 | return -EINVAL; |
218 | 240 | ||
219 | E_md4hash(password, temp_key); | 241 | ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL); |
220 | mdfour(key->data.ntlm, temp_key, 16); | 242 | if (!ses->auth_key.response) { |
221 | memcpy(key->data.ntlm+16, rn, CIFS_SESS_KEY_SIZE); | 243 | cERROR(1, "NTLM can't allocate (%u bytes) memory", temp_len); |
222 | key->len = 40; | 244 | return -ENOMEM; |
223 | return 0; | 245 | } |
246 | ses->auth_key.len = temp_len; | ||
247 | |||
248 | rc = SMBNTencrypt(ses->password, ses->server->cryptkey, | ||
249 | ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
250 | if (rc) { | ||
251 | cFYI(1, "%s Can't generate NTLM response, error: %d", | ||
252 | __func__, rc); | ||
253 | return rc; | ||
254 | } | ||
255 | |||
256 | rc = E_md4hash(ses->password, temp_key); | ||
257 | if (rc) { | ||
258 | cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc); | ||
259 | return rc; | ||
260 | } | ||
261 | |||
262 | rc = mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE); | ||
263 | if (rc) | ||
264 | cFYI(1, "%s Can't generate NTLM session key, error: %d", | ||
265 | __func__, rc); | ||
266 | |||
267 | return rc; | ||
224 | } | 268 | } |
225 | 269 | ||
226 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 270 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
227 | void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, | 271 | int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, |
228 | char *lnm_session_key) | 272 | char *lnm_session_key) |
229 | { | 273 | { |
230 | int i; | 274 | int i; |
275 | int rc; | ||
231 | char password_with_pad[CIFS_ENCPWD_SIZE]; | 276 | char password_with_pad[CIFS_ENCPWD_SIZE]; |
232 | 277 | ||
233 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); | 278 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); |
@@ -238,7 +283,7 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, | |||
238 | memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE); | 283 | memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE); |
239 | memcpy(lnm_session_key, password_with_pad, | 284 | memcpy(lnm_session_key, password_with_pad, |
240 | CIFS_ENCPWD_SIZE); | 285 | CIFS_ENCPWD_SIZE); |
241 | return; | 286 | return 0; |
242 | } | 287 | } |
243 | 288 | ||
244 | /* calculate old style session key */ | 289 | /* calculate old style session key */ |
@@ -255,116 +300,463 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, | |||
255 | for (i = 0; i < CIFS_ENCPWD_SIZE; i++) | 300 | for (i = 0; i < CIFS_ENCPWD_SIZE; i++) |
256 | password_with_pad[i] = toupper(password_with_pad[i]); | 301 | password_with_pad[i] = toupper(password_with_pad[i]); |
257 | 302 | ||
258 | SMBencrypt(password_with_pad, cryptkey, lnm_session_key); | 303 | rc = SMBencrypt(password_with_pad, cryptkey, lnm_session_key); |
259 | 304 | ||
260 | /* clear password before we return/free memory */ | 305 | return rc; |
261 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); | ||
262 | } | 306 | } |
263 | #endif /* CIFS_WEAK_PW_HASH */ | 307 | #endif /* CIFS_WEAK_PW_HASH */ |
264 | 308 | ||
265 | static int calc_ntlmv2_hash(struct cifsSesInfo *ses, | 309 | /* Build a proper attribute value/target info pairs blob. |
310 | * Fill in netbios and dns domain name and workstation name | ||
311 | * and client time (total five av pairs and + one end of fields indicator. | ||
312 | * Allocate domain name which gets freed when session struct is deallocated. | ||
313 | */ | ||
314 | static int | ||
315 | build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp) | ||
316 | { | ||
317 | unsigned int dlen; | ||
318 | unsigned int wlen; | ||
319 | unsigned int size = 6 * sizeof(struct ntlmssp2_name); | ||
320 | __le64 curtime; | ||
321 | char *defdmname = "WORKGROUP"; | ||
322 | unsigned char *blobptr; | ||
323 | struct ntlmssp2_name *attrptr; | ||
324 | |||
325 | if (!ses->domainName) { | ||
326 | ses->domainName = kstrdup(defdmname, GFP_KERNEL); | ||
327 | if (!ses->domainName) | ||
328 | return -ENOMEM; | ||
329 | } | ||
330 | |||
331 | dlen = strlen(ses->domainName); | ||
332 | wlen = strlen(ses->server->hostname); | ||
333 | |||
334 | /* The length of this blob is a size which is | ||
335 | * six times the size of a structure which holds name/size + | ||
336 | * two times the unicode length of a domain name + | ||
337 | * two times the unicode length of a server name + | ||
338 | * size of a timestamp (which is 8 bytes). | ||
339 | */ | ||
340 | ses->auth_key.len = size + 2 * (2 * dlen) + 2 * (2 * wlen) + 8; | ||
341 | ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL); | ||
342 | if (!ses->auth_key.response) { | ||
343 | ses->auth_key.len = 0; | ||
344 | cERROR(1, "Challenge target info allocation failure"); | ||
345 | return -ENOMEM; | ||
346 | } | ||
347 | |||
348 | blobptr = ses->auth_key.response; | ||
349 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
350 | |||
351 | attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME); | ||
352 | attrptr->length = cpu_to_le16(2 * dlen); | ||
353 | blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); | ||
354 | cifs_strtoUCS((__le16 *)blobptr, ses->domainName, dlen, nls_cp); | ||
355 | |||
356 | blobptr += 2 * dlen; | ||
357 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
358 | |||
359 | attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_COMPUTER_NAME); | ||
360 | attrptr->length = cpu_to_le16(2 * wlen); | ||
361 | blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); | ||
362 | cifs_strtoUCS((__le16 *)blobptr, ses->server->hostname, wlen, nls_cp); | ||
363 | |||
364 | blobptr += 2 * wlen; | ||
365 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
366 | |||
367 | attrptr->type = cpu_to_le16(NTLMSSP_AV_DNS_DOMAIN_NAME); | ||
368 | attrptr->length = cpu_to_le16(2 * dlen); | ||
369 | blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); | ||
370 | cifs_strtoUCS((__le16 *)blobptr, ses->domainName, dlen, nls_cp); | ||
371 | |||
372 | blobptr += 2 * dlen; | ||
373 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
374 | |||
375 | attrptr->type = cpu_to_le16(NTLMSSP_AV_DNS_COMPUTER_NAME); | ||
376 | attrptr->length = cpu_to_le16(2 * wlen); | ||
377 | blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); | ||
378 | cifs_strtoUCS((__le16 *)blobptr, ses->server->hostname, wlen, nls_cp); | ||
379 | |||
380 | blobptr += 2 * wlen; | ||
381 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
382 | |||
383 | attrptr->type = cpu_to_le16(NTLMSSP_AV_TIMESTAMP); | ||
384 | attrptr->length = cpu_to_le16(sizeof(__le64)); | ||
385 | blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); | ||
386 | curtime = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
387 | memcpy(blobptr, &curtime, sizeof(__le64)); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | /* Server has provided av pairs/target info in the type 2 challenge | ||
393 | * packet and we have plucked it and stored within smb session. | ||
394 | * We parse that blob here to find netbios domain name to be used | ||
395 | * as part of ntlmv2 authentication (in Target String), if not already | ||
396 | * specified on the command line. | ||
397 | * If this function returns without any error but without fetching | ||
398 | * domain name, authentication may fail against some server but | ||
399 | * may not fail against other (those who are not very particular | ||
400 | * about target string i.e. for some, just user name might suffice. | ||
401 | */ | ||
402 | static int | ||
403 | find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp) | ||
404 | { | ||
405 | unsigned int attrsize; | ||
406 | unsigned int type; | ||
407 | unsigned int onesize = sizeof(struct ntlmssp2_name); | ||
408 | unsigned char *blobptr; | ||
409 | unsigned char *blobend; | ||
410 | struct ntlmssp2_name *attrptr; | ||
411 | |||
412 | if (!ses->auth_key.len || !ses->auth_key.response) | ||
413 | return 0; | ||
414 | |||
415 | blobptr = ses->auth_key.response; | ||
416 | blobend = blobptr + ses->auth_key.len; | ||
417 | |||
418 | while (blobptr + onesize < blobend) { | ||
419 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
420 | type = le16_to_cpu(attrptr->type); | ||
421 | if (type == NTLMSSP_AV_EOL) | ||
422 | break; | ||
423 | blobptr += 2; /* advance attr type */ | ||
424 | attrsize = le16_to_cpu(attrptr->length); | ||
425 | blobptr += 2; /* advance attr size */ | ||
426 | if (blobptr + attrsize > blobend) | ||
427 | break; | ||
428 | if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { | ||
429 | if (!attrsize) | ||
430 | break; | ||
431 | if (!ses->domainName) { | ||
432 | ses->domainName = | ||
433 | kmalloc(attrsize + 1, GFP_KERNEL); | ||
434 | if (!ses->domainName) | ||
435 | return -ENOMEM; | ||
436 | cifs_from_ucs2(ses->domainName, | ||
437 | (__le16 *)blobptr, attrsize, attrsize, | ||
438 | nls_cp, false); | ||
439 | break; | ||
440 | } | ||
441 | } | ||
442 | blobptr += attrsize; /* advance attr value */ | ||
443 | } | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, | ||
266 | const struct nls_table *nls_cp) | 449 | const struct nls_table *nls_cp) |
267 | { | 450 | { |
268 | int rc = 0; | 451 | int rc = 0; |
269 | int len; | 452 | int len; |
270 | char nt_hash[16]; | 453 | char nt_hash[CIFS_NTHASH_SIZE]; |
271 | struct HMACMD5Context *pctxt; | ||
272 | wchar_t *user; | 454 | wchar_t *user; |
273 | wchar_t *domain; | 455 | wchar_t *domain; |
456 | wchar_t *server; | ||
274 | 457 | ||
275 | pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); | 458 | if (!ses->server->secmech.sdeschmacmd5) { |
276 | 459 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | |
277 | if (pctxt == NULL) | 460 | return -1; |
278 | return -ENOMEM; | 461 | } |
279 | 462 | ||
280 | /* calculate md4 hash of password */ | 463 | /* calculate md4 hash of password */ |
281 | E_md4hash(ses->password, nt_hash); | 464 | E_md4hash(ses->password, nt_hash); |
282 | 465 | ||
283 | /* convert Domainname to unicode and uppercase */ | 466 | crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash, |
284 | hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); | 467 | CIFS_NTHASH_SIZE); |
468 | |||
469 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); | ||
470 | if (rc) { | ||
471 | cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n"); | ||
472 | return rc; | ||
473 | } | ||
285 | 474 | ||
286 | /* convert ses->userName to unicode and uppercase */ | 475 | /* convert ses->user_name to unicode and uppercase */ |
287 | len = strlen(ses->userName); | 476 | len = strlen(ses->user_name); |
288 | user = kmalloc(2 + (len * 2), GFP_KERNEL); | 477 | user = kmalloc(2 + (len * 2), GFP_KERNEL); |
289 | if (user == NULL) | 478 | if (user == NULL) { |
479 | cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); | ||
480 | rc = -ENOMEM; | ||
290 | goto calc_exit_2; | 481 | goto calc_exit_2; |
291 | len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); | 482 | } |
483 | len = cifs_strtoUCS((__le16 *)user, ses->user_name, len, nls_cp); | ||
292 | UniStrupr(user); | 484 | UniStrupr(user); |
293 | hmac_md5_update((char *)user, 2*len, pctxt); | 485 | |
486 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
487 | (char *)user, 2 * len); | ||
294 | 488 | ||
295 | /* convert ses->domainName to unicode and uppercase */ | 489 | /* convert ses->domainName to unicode and uppercase */ |
296 | if (ses->domainName) { | 490 | if (ses->domainName) { |
297 | len = strlen(ses->domainName); | 491 | len = strlen(ses->domainName); |
298 | 492 | ||
299 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); | 493 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); |
300 | if (domain == NULL) | 494 | if (domain == NULL) { |
495 | cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure"); | ||
496 | rc = -ENOMEM; | ||
301 | goto calc_exit_1; | 497 | goto calc_exit_1; |
498 | } | ||
302 | len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, | 499 | len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, |
303 | nls_cp); | 500 | nls_cp); |
304 | /* the following line was removed since it didn't work well | 501 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, |
305 | with lower cased domain name that passed as an option. | 502 | (char *)domain, 2 * len); |
306 | Maybe converting the domain name earlier makes sense */ | ||
307 | /* UniStrupr(domain); */ | ||
308 | |||
309 | hmac_md5_update((char *)domain, 2*len, pctxt); | ||
310 | |||
311 | kfree(domain); | 503 | kfree(domain); |
504 | } else if (ses->serverName) { | ||
505 | len = strlen(ses->serverName); | ||
506 | |||
507 | server = kmalloc(2 + (len * 2), GFP_KERNEL); | ||
508 | if (server == NULL) { | ||
509 | cERROR(1, "calc_ntlmv2_hash: server mem alloc failure"); | ||
510 | rc = -ENOMEM; | ||
511 | goto calc_exit_1; | ||
512 | } | ||
513 | len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, | ||
514 | nls_cp); | ||
515 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
516 | (char *)server, 2 * len); | ||
517 | kfree(server); | ||
312 | } | 518 | } |
519 | |||
520 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
521 | ntlmv2_hash); | ||
522 | |||
313 | calc_exit_1: | 523 | calc_exit_1: |
314 | kfree(user); | 524 | kfree(user); |
315 | calc_exit_2: | 525 | calc_exit_2: |
316 | /* BB FIXME what about bytes 24 through 40 of the signing key? | 526 | return rc; |
317 | compare with the NTLM example */ | 527 | } |
318 | hmac_md5_final(ses->server->ntlmv2_hash, pctxt); | 528 | |
529 | static int | ||
530 | CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) | ||
531 | { | ||
532 | int rc; | ||
533 | unsigned int offset = CIFS_SESS_KEY_SIZE + 8; | ||
534 | |||
535 | if (!ses->server->secmech.sdeschmacmd5) { | ||
536 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | ||
537 | return -1; | ||
538 | } | ||
539 | |||
540 | crypto_shash_setkey(ses->server->secmech.hmacmd5, | ||
541 | ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); | ||
542 | |||
543 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); | ||
544 | if (rc) { | ||
545 | cERROR(1, "CalcNTLMv2_response: could not init hmacmd5"); | ||
546 | return rc; | ||
547 | } | ||
548 | |||
549 | if (ses->server->secType == RawNTLMSSP) | ||
550 | memcpy(ses->auth_key.response + offset, | ||
551 | ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); | ||
552 | else | ||
553 | memcpy(ses->auth_key.response + offset, | ||
554 | ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); | ||
555 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
556 | ses->auth_key.response + offset, ses->auth_key.len - offset); | ||
557 | |||
558 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
559 | ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
319 | 560 | ||
320 | kfree(pctxt); | ||
321 | return rc; | 561 | return rc; |
322 | } | 562 | } |
323 | 563 | ||
324 | void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, | 564 | |
325 | const struct nls_table *nls_cp) | 565 | int |
566 | setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) | ||
326 | { | 567 | { |
327 | int rc; | 568 | int rc; |
328 | struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; | 569 | int baselen; |
329 | struct HMACMD5Context context; | 570 | unsigned int tilen; |
571 | struct ntlmv2_resp *buf; | ||
572 | char ntlmv2_hash[16]; | ||
573 | unsigned char *tiblob = NULL; /* target info blob */ | ||
574 | |||
575 | if (ses->server->secType == RawNTLMSSP) { | ||
576 | if (!ses->domainName) { | ||
577 | rc = find_domain_name(ses, nls_cp); | ||
578 | if (rc) { | ||
579 | cERROR(1, "error %d finding domain name", rc); | ||
580 | goto setup_ntlmv2_rsp_ret; | ||
581 | } | ||
582 | } | ||
583 | } else { | ||
584 | rc = build_avpair_blob(ses, nls_cp); | ||
585 | if (rc) { | ||
586 | cERROR(1, "error %d building av pair blob", rc); | ||
587 | goto setup_ntlmv2_rsp_ret; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp); | ||
592 | tilen = ses->auth_key.len; | ||
593 | tiblob = ses->auth_key.response; | ||
330 | 594 | ||
595 | ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL); | ||
596 | if (!ses->auth_key.response) { | ||
597 | rc = ENOMEM; | ||
598 | ses->auth_key.len = 0; | ||
599 | cERROR(1, "%s: Can't allocate auth blob", __func__); | ||
600 | goto setup_ntlmv2_rsp_ret; | ||
601 | } | ||
602 | ses->auth_key.len += baselen; | ||
603 | |||
604 | buf = (struct ntlmv2_resp *) | ||
605 | (ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
331 | buf->blob_signature = cpu_to_le32(0x00000101); | 606 | buf->blob_signature = cpu_to_le32(0x00000101); |
332 | buf->reserved = 0; | 607 | buf->reserved = 0; |
333 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 608 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); |
334 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); | 609 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); |
335 | buf->reserved2 = 0; | 610 | buf->reserved2 = 0; |
336 | buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); | ||
337 | buf->names[0].length = 0; | ||
338 | buf->names[1].type = 0; | ||
339 | buf->names[1].length = 0; | ||
340 | 611 | ||
341 | /* calculate buf->ntlmv2_hash */ | 612 | memcpy(ses->auth_key.response + baselen, tiblob, tilen); |
342 | rc = calc_ntlmv2_hash(ses, nls_cp); | 613 | |
343 | if (rc) | 614 | /* calculate ntlmv2_hash */ |
615 | rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); | ||
616 | if (rc) { | ||
344 | cERROR(1, "could not get v2 hash rc %d", rc); | 617 | cERROR(1, "could not get v2 hash rc %d", rc); |
345 | CalcNTLMv2_response(ses, resp_buf); | 618 | goto setup_ntlmv2_rsp_ret; |
619 | } | ||
620 | |||
621 | /* calculate first part of the client response (CR1) */ | ||
622 | rc = CalcNTLMv2_response(ses, ntlmv2_hash); | ||
623 | if (rc) { | ||
624 | cERROR(1, "Could not calculate CR1 rc: %d", rc); | ||
625 | goto setup_ntlmv2_rsp_ret; | ||
626 | } | ||
627 | |||
628 | /* now calculate the session key for NTLMv2 */ | ||
629 | crypto_shash_setkey(ses->server->secmech.hmacmd5, | ||
630 | ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); | ||
346 | 631 | ||
347 | /* now calculate the MAC key for NTLMv2 */ | 632 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); |
348 | hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); | 633 | if (rc) { |
349 | hmac_md5_update(resp_buf, 16, &context); | 634 | cERROR(1, "%s: Could not init hmacmd5\n", __func__); |
350 | hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context); | 635 | goto setup_ntlmv2_rsp_ret; |
636 | } | ||
637 | |||
638 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
639 | ses->auth_key.response + CIFS_SESS_KEY_SIZE, | ||
640 | CIFS_HMAC_MD5_HASH_SIZE); | ||
641 | |||
642 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
643 | ses->auth_key.response); | ||
351 | 644 | ||
352 | memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf, | 645 | setup_ntlmv2_rsp_ret: |
353 | sizeof(struct ntlmv2_resp)); | 646 | kfree(tiblob); |
354 | ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp); | 647 | |
648 | return rc; | ||
355 | } | 649 | } |
356 | 650 | ||
357 | void CalcNTLMv2_response(const struct cifsSesInfo *ses, | 651 | int |
358 | char *v2_session_response) | 652 | calc_seckey(struct cifs_ses *ses) |
359 | { | 653 | { |
360 | struct HMACMD5Context context; | 654 | int rc; |
361 | /* rest of v2 struct already generated */ | 655 | struct crypto_blkcipher *tfm_arc4; |
362 | memcpy(v2_session_response + 8, ses->server->cryptKey, 8); | 656 | struct scatterlist sgin, sgout; |
363 | hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); | 657 | struct blkcipher_desc desc; |
658 | unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */ | ||
659 | |||
660 | get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE); | ||
661 | |||
662 | tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); | ||
663 | if (IS_ERR(tfm_arc4)) { | ||
664 | rc = PTR_ERR(tfm_arc4); | ||
665 | cERROR(1, "could not allocate crypto API arc4\n"); | ||
666 | return rc; | ||
667 | } | ||
668 | |||
669 | desc.tfm = tfm_arc4; | ||
670 | |||
671 | crypto_blkcipher_setkey(tfm_arc4, ses->auth_key.response, | ||
672 | CIFS_SESS_KEY_SIZE); | ||
673 | |||
674 | sg_init_one(&sgin, sec_key, CIFS_SESS_KEY_SIZE); | ||
675 | sg_init_one(&sgout, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); | ||
676 | |||
677 | rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE); | ||
678 | if (rc) { | ||
679 | cERROR(1, "could not encrypt session key rc: %d\n", rc); | ||
680 | crypto_free_blkcipher(tfm_arc4); | ||
681 | return rc; | ||
682 | } | ||
683 | |||
684 | /* make secondary_key/nonce as session key */ | ||
685 | memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE); | ||
686 | /* and make len as that of session key only */ | ||
687 | ses->auth_key.len = CIFS_SESS_KEY_SIZE; | ||
688 | |||
689 | crypto_free_blkcipher(tfm_arc4); | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | void | ||
695 | cifs_crypto_shash_release(struct TCP_Server_Info *server) | ||
696 | { | ||
697 | if (server->secmech.md5) | ||
698 | crypto_free_shash(server->secmech.md5); | ||
364 | 699 | ||
365 | hmac_md5_update(v2_session_response+8, | 700 | if (server->secmech.hmacmd5) |
366 | sizeof(struct ntlmv2_resp) - 8, &context); | 701 | crypto_free_shash(server->secmech.hmacmd5); |
367 | 702 | ||
368 | hmac_md5_final(v2_session_response, &context); | 703 | kfree(server->secmech.sdeschmacmd5); |
369 | /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ | 704 | |
705 | kfree(server->secmech.sdescmd5); | ||
706 | } | ||
707 | |||
708 | int | ||
709 | cifs_crypto_shash_allocate(struct TCP_Server_Info *server) | ||
710 | { | ||
711 | int rc; | ||
712 | unsigned int size; | ||
713 | |||
714 | server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0); | ||
715 | if (IS_ERR(server->secmech.hmacmd5)) { | ||
716 | cERROR(1, "could not allocate crypto hmacmd5\n"); | ||
717 | return PTR_ERR(server->secmech.hmacmd5); | ||
718 | } | ||
719 | |||
720 | server->secmech.md5 = crypto_alloc_shash("md5", 0, 0); | ||
721 | if (IS_ERR(server->secmech.md5)) { | ||
722 | cERROR(1, "could not allocate crypto md5\n"); | ||
723 | rc = PTR_ERR(server->secmech.md5); | ||
724 | goto crypto_allocate_md5_fail; | ||
725 | } | ||
726 | |||
727 | size = sizeof(struct shash_desc) + | ||
728 | crypto_shash_descsize(server->secmech.hmacmd5); | ||
729 | server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); | ||
730 | if (!server->secmech.sdeschmacmd5) { | ||
731 | cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n"); | ||
732 | rc = -ENOMEM; | ||
733 | goto crypto_allocate_hmacmd5_sdesc_fail; | ||
734 | } | ||
735 | server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5; | ||
736 | server->secmech.sdeschmacmd5->shash.flags = 0x0; | ||
737 | |||
738 | |||
739 | size = sizeof(struct shash_desc) + | ||
740 | crypto_shash_descsize(server->secmech.md5); | ||
741 | server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL); | ||
742 | if (!server->secmech.sdescmd5) { | ||
743 | cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n"); | ||
744 | rc = -ENOMEM; | ||
745 | goto crypto_allocate_md5_sdesc_fail; | ||
746 | } | ||
747 | server->secmech.sdescmd5->shash.tfm = server->secmech.md5; | ||
748 | server->secmech.sdescmd5->shash.flags = 0x0; | ||
749 | |||
750 | return 0; | ||
751 | |||
752 | crypto_allocate_md5_sdesc_fail: | ||
753 | kfree(server->secmech.sdeschmacmd5); | ||
754 | |||
755 | crypto_allocate_hmacmd5_sdesc_fail: | ||
756 | crypto_free_shash(server->secmech.md5); | ||
757 | |||
758 | crypto_allocate_md5_fail: | ||
759 | crypto_free_shash(server->secmech.hmacmd5); | ||
760 | |||
761 | return rc; | ||
370 | } | 762 | } |