cifsencrypt.c 21.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *   fs/cifs/cifsencrypt.c
 *
4
 *   Copyright (C) International Business Machines  Corp., 2005,2006
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <linux/fs.h>
23
#include <linux/slab.h>
L
Linus Torvalds 已提交
24
#include "cifspdu.h"
S
Steve French 已提交
25
#include "cifsglob.h"
L
Linus Torvalds 已提交
26 27 28
#include "cifs_debug.h"
#include "cifs_unicode.h"
#include "cifsproto.h"
29
#include "ntlmssp.h"
30
#include <linux/ctype.h>
S
Steve French 已提交
31
#include <linux/random.h>
L
Linus Torvalds 已提交
32

S
Steve French 已提交
33
/* Calculate and return the CIFS signature based on the mac key and SMB PDU */
L
Linus Torvalds 已提交
34 35
/* the 16 byte signature must be allocated by the caller  */
/* Note we only use the 1st eight bytes */
S
Steve French 已提交
36
/* Note that the smb header signature field on input contains the
L
Linus Torvalds 已提交
37 38 39 40
	sequence number before this function is called */

extern void mdfour(unsigned char *out, unsigned char *in, int n);
extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
41
extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
S
Steve French 已提交
42
		       unsigned char *p24);
43

S
Steve French 已提交
44
static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
45
				struct TCP_Server_Info *server, char *signature)
L
Linus Torvalds 已提交
46
{
47
	int rc;
L
Linus Torvalds 已提交
48

49
	if (cifs_pdu == NULL || signature == NULL || server == NULL)
L
Linus Torvalds 已提交
50 51
		return -EINVAL;

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
	if (!server->secmech.sdescmd5) {
		cERROR(1, "%s: Can't generate signature\n", __func__);
		return -1;
	}

	rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
	if (rc) {
		cERROR(1, "%s: Oould not init md5\n", __func__);
		return rc;
	}

	crypto_shash_update(&server->secmech.sdescmd5->shash,
		server->session_key.response, server->session_key.len);

	crypto_shash_update(&server->secmech.sdescmd5->shash,
		cifs_pdu->Protocol, cifs_pdu->smb_buf_length);

	rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature);
70

71
	return 0;
L
Linus Torvalds 已提交
72 73
}

74
/* must be called with server->srv_mutex held */
S
Steve French 已提交
75 76
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
		  __u32 *pexpected_response_sequence_number)
L
Linus Torvalds 已提交
77 78 79 80
{
	int rc = 0;
	char smb_signature[20];

S
Steve French 已提交
81
	if ((cifs_pdu == NULL) || (server == NULL))
L
Linus Torvalds 已提交
82 83
		return -EINVAL;

S
Steve French 已提交
84
	if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
L
Linus Torvalds 已提交
85 86
		return rc;

87 88
	cifs_pdu->Signature.Sequence.SequenceNumber =
			cpu_to_le32(server->sequence_number);
L
Linus Torvalds 已提交
89
	cifs_pdu->Signature.Sequence.Reserved = 0;
90

91 92
	*pexpected_response_sequence_number = server->sequence_number++;
	server->sequence_number++;
L
Linus Torvalds 已提交
93

94
	rc = cifs_calculate_signature(cifs_pdu, server, smb_signature);
S
Steve French 已提交
95
	if (rc)
L
Linus Torvalds 已提交
96 97 98 99 100 101 102
		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
	else
		memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);

	return rc;
}

S
Steve French 已提交
103
static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
104
				struct TCP_Server_Info *server, char *signature)
105
{
106
	int i;
107
	int rc;
108

109
	if (iov == NULL || signature == NULL || server == NULL)
110
		return -EINVAL;
111

112 113 114 115 116 117 118 119 120 121 122 123 124 125
	if (!server->secmech.sdescmd5) {
		cERROR(1, "%s: Can't generate signature\n", __func__);
		return -1;
	}

	rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
	if (rc) {
		cERROR(1, "%s: Oould not init md5\n", __func__);
		return rc;
	}

	crypto_shash_update(&server->secmech.sdescmd5->shash,
		server->session_key.response, server->session_key.len);

126
	for (i = 0; i < n_vec; i++) {
127 128
		if (iov[i].iov_len == 0)
			continue;
S
Steve French 已提交
129
		if (iov[i].iov_base == NULL) {
130
			cERROR(1, "null iovec entry");
131
			return -EIO;
132
		}
S
Steve French 已提交
133
		/* The first entry includes a length field (which does not get
134
		   signed that occupies the first 4 bytes before the header */
S
Steve French 已提交
135
		if (i == 0) {
136
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
137
				break; /* nothing to sign or corrupt header */
138 139
			crypto_shash_update(&server->secmech.sdescmd5->shash,
				iov[i].iov_base + 4, iov[i].iov_len - 4);
140
		} else
141 142
			crypto_shash_update(&server->secmech.sdescmd5->shash,
				iov[i].iov_base, iov[i].iov_len);
143
	}
144

145
	rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature);
146

147
	return rc;
148 149
}

150
/* must be called with server->srv_mutex held */
S
Steve French 已提交
151
int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
152
		   __u32 *pexpected_response_sequence_number)
153 154 155
{
	int rc = 0;
	char smb_signature[20];
S
Steve French 已提交
156
	struct smb_hdr *cifs_pdu = iov[0].iov_base;
157

S
Steve French 已提交
158
	if ((cifs_pdu == NULL) || (server == NULL))
159 160
		return -EINVAL;

S
Steve French 已提交
161
	if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
162 163
		return rc;

S
Steve French 已提交
164
	cifs_pdu->Signature.Sequence.SequenceNumber =
165
				cpu_to_le32(server->sequence_number);
S
Steve French 已提交
166
	cifs_pdu->Signature.Sequence.Reserved = 0;
167

S
Steve French 已提交
168 169
	*pexpected_response_sequence_number = server->sequence_number++;
	server->sequence_number++;
170

171
	rc = cifs_calc_signature2(iov, n_vec, server, smb_signature);
S
Steve French 已提交
172 173 174 175
	if (rc)
		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
	else
		memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
176

S
Steve French 已提交
177
	return rc;
178 179
}

180
int cifs_verify_signature(struct smb_hdr *cifs_pdu,
181
			  struct TCP_Server_Info *server,
S
Steve French 已提交
182
			  __u32 expected_sequence_number)
L
Linus Torvalds 已提交
183
{
184
	unsigned int rc;
L
Linus Torvalds 已提交
185 186 187
	char server_response_sig[8];
	char what_we_think_sig_should_be[20];

188
	if (cifs_pdu == NULL || server == NULL)
L
Linus Torvalds 已提交
189 190 191 192 193 194
		return -EINVAL;

	if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
		return 0;

	if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
195
		struct smb_com_lock_req *pSMB =
S
Steve French 已提交
196 197
			(struct smb_com_lock_req *)cifs_pdu;
	    if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
L
Linus Torvalds 已提交
198 199 200
			return 0;
	}

201 202 203
	/* BB what if signatures are supposed to be on for session but
	   server does not send one? BB */

L
Linus Torvalds 已提交
204
	/* Do not need to verify session setups with signature "BSRSPYL "  */
205
	if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
206 207
		cFYI(1, "dummy signature received for smb command 0x%x",
			cifs_pdu->Command);
L
Linus Torvalds 已提交
208 209 210

	/* save off the origiginal signature so we can modify the smb and check
		its signature against what the server sent */
211
	memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
L
Linus Torvalds 已提交
212

213 214
	cifs_pdu->Signature.Sequence.SequenceNumber =
					cpu_to_le32(expected_sequence_number);
L
Linus Torvalds 已提交
215 216
	cifs_pdu->Signature.Sequence.Reserved = 0;

217
	rc = cifs_calculate_signature(cifs_pdu, server,
L
Linus Torvalds 已提交
218 219
		what_we_think_sig_should_be);

220
	if (rc)
L
Linus Torvalds 已提交
221 222
		return rc;

223 224
/*	cifs_dump_mem("what we think it should be: ",
		      what_we_think_sig_should_be, 16); */
L
Linus Torvalds 已提交
225

226
	if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
L
Linus Torvalds 已提交
227 228 229 230 231 232
		return -EACCES;
	else
		return 0;

}

233 234
/* first calculate 24 bytes ntlm response and then 16 byte session key */
int setup_ntlm_response(struct cifsSesInfo *ses)
L
Linus Torvalds 已提交
235
{
236 237 238 239
	unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE;
	char temp_key[CIFS_SESS_KEY_SIZE];

	if (!ses)
L
Linus Torvalds 已提交
240 241
		return -EINVAL;

242 243 244 245 246 247 248
	ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL);
	if (!ses->auth_key.response) {
		cERROR(1, "NTLM can't allocate (%u bytes) memory", temp_len);
		return -ENOMEM;
	}
	ses->auth_key.len = temp_len;

249
	SMBNTencrypt(ses->password, ses->server->cryptkey,
250 251 252 253 254
			ses->auth_key.response + CIFS_SESS_KEY_SIZE);

	E_md4hash(ses->password, temp_key);
	mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE);

L
Linus Torvalds 已提交
255 256 257
	return 0;
}

258
#ifdef CONFIG_CIFS_WEAK_PW_HASH
259 260
void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
			char *lnm_session_key)
261 262 263 264 265
{
	int i;
	char password_with_pad[CIFS_ENCPWD_SIZE];

	memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
266 267 268
	if (password)
		strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);

269
	if (!encrypt && global_secflags & CIFSSEC_MAY_PLNTXT) {
270 271 272 273 274
		memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
		memcpy(lnm_session_key, password_with_pad,
			CIFS_ENCPWD_SIZE);
		return;
	}
275

276 277 278 279 280 281 282 283 284 285 286
	/* calculate old style session key */
	/* calling toupper is less broken than repeatedly
	calling nls_toupper would be since that will never
	work for UTF8, but neither handles multibyte code pages
	but the only alternative would be converting to UCS-16 (Unicode)
	(using a routine something like UniStrupr) then
	uppercasing and then converting back from Unicode - which
	would only worth doing it if we knew it were utf8. Basically
	utf8 and other multibyte codepages each need their own strupper
	function since a byte at a time will ont work. */

287
	for (i = 0; i < CIFS_ENCPWD_SIZE; i++)
288 289
		password_with_pad[i] = toupper(password_with_pad[i]);

290 291
	SMBencrypt(password_with_pad, cryptkey, lnm_session_key);

292 293 294 295 296
	/* clear password before we return/free memory */
	memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
}
#endif /* CIFS_WEAK_PW_HASH */

297 298 299 300
/* Build a proper attribute value/target info pairs blob.
 * Fill in netbios and dns domain name and workstation name
 * and client time (total five av pairs and + one end of fields indicator.
 * Allocate domain name which gets freed when session struct is deallocated.
301 302
 */
static int
303
build_avpair_blob(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
304
{
305 306 307 308 309 310
	unsigned int dlen;
	unsigned int wlen;
	unsigned int size = 6 * sizeof(struct ntlmssp2_name);
	__le64  curtime;
	char *defdmname = "WORKGROUP";
	unsigned char *blobptr;
311 312
	struct ntlmssp2_name *attrptr;

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
	if (!ses->domainName) {
		ses->domainName = kstrdup(defdmname, GFP_KERNEL);
		if (!ses->domainName)
			return -ENOMEM;
	}

	dlen = strlen(ses->domainName);
	wlen = strlen(ses->server->hostname);

	/* The length of this blob is a size which is
	 * six times the size of a structure which holds name/size +
	 * two times the unicode length of a domain name +
	 * two times the unicode length of a server name +
	 * size of a timestamp (which is 8 bytes).
	 */
328 329 330 331
	ses->auth_key.len = size + 2 * (2 * dlen) + 2 * (2 * wlen) + 8;
	ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL);
	if (!ses->auth_key.response) {
		ses->auth_key.len = 0;
332 333 334
		cERROR(1, "Challenge target info allocation failure");
		return -ENOMEM;
	}
335

336
	blobptr = ses->auth_key.response;
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
	attrptr = (struct ntlmssp2_name *) blobptr;

	attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME);
	attrptr->length = cpu_to_le16(2 * dlen);
	blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
	cifs_strtoUCS((__le16 *)blobptr, ses->domainName, dlen, nls_cp);

	blobptr += 2 * dlen;
	attrptr = (struct ntlmssp2_name *) blobptr;

	attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_COMPUTER_NAME);
	attrptr->length = cpu_to_le16(2 * wlen);
	blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
	cifs_strtoUCS((__le16 *)blobptr, ses->server->hostname, wlen, nls_cp);

	blobptr += 2 * wlen;
	attrptr = (struct ntlmssp2_name *) blobptr;

	attrptr->type = cpu_to_le16(NTLMSSP_AV_DNS_DOMAIN_NAME);
	attrptr->length = cpu_to_le16(2 * dlen);
	blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
	cifs_strtoUCS((__le16 *)blobptr, ses->domainName, dlen, nls_cp);

	blobptr += 2 * dlen;
	attrptr = (struct ntlmssp2_name *) blobptr;

	attrptr->type = cpu_to_le16(NTLMSSP_AV_DNS_COMPUTER_NAME);
	attrptr->length = cpu_to_le16(2 * wlen);
	blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
	cifs_strtoUCS((__le16 *)blobptr, ses->server->hostname, wlen, nls_cp);

	blobptr += 2 * wlen;
	attrptr = (struct ntlmssp2_name *) blobptr;

	attrptr->type = cpu_to_le16(NTLMSSP_AV_TIMESTAMP);
	attrptr->length = cpu_to_le16(sizeof(__le64));
	blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name);
	curtime = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
	memcpy(blobptr, &curtime, sizeof(__le64));
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390

	return 0;
}

/* Server has provided av pairs/target info in the type 2 challenge
 * packet and we have plucked it and stored within smb session.
 * We parse that blob here to find netbios domain name to be used
 * as part of ntlmv2 authentication (in Target String), if not already
 * specified on the command line.
 * If this function returns without any error but without fetching
 * domain name, authentication may fail against some server but
 * may not fail against other (those who are not very particular
 * about target string i.e. for some, just user name might suffice.
 */
static int
391
find_domain_name(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
392 393 394 395 396 397 398 399
{
	unsigned int attrsize;
	unsigned int type;
	unsigned int onesize = sizeof(struct ntlmssp2_name);
	unsigned char *blobptr;
	unsigned char *blobend;
	struct ntlmssp2_name *attrptr;

400
	if (!ses->auth_key.len || !ses->auth_key.response)
401 402
		return 0;

403 404
	blobptr = ses->auth_key.response;
	blobend = blobptr + ses->auth_key.len;
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425

	while (blobptr + onesize < blobend) {
		attrptr = (struct ntlmssp2_name *) blobptr;
		type = le16_to_cpu(attrptr->type);
		if (type == NTLMSSP_AV_EOL)
			break;
		blobptr += 2; /* advance attr type */
		attrsize = le16_to_cpu(attrptr->length);
		blobptr += 2; /* advance attr size */
		if (blobptr + attrsize > blobend)
			break;
		if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
			if (!attrsize)
				break;
			if (!ses->domainName) {
				ses->domainName =
					kmalloc(attrsize + 1, GFP_KERNEL);
				if (!ses->domainName)
						return -ENOMEM;
				cifs_from_ucs2(ses->domainName,
					(__le16 *)blobptr, attrsize, attrsize,
426
					nls_cp, false);
427 428 429 430 431 432 433 434 435
				break;
			}
		}
		blobptr += attrsize; /* advance attr  value */
	}

	return 0;
}

436
static int calc_ntlmv2_hash(struct cifsSesInfo *ses, char *ntlmv2_hash,
437
			    const struct nls_table *nls_cp)
S
Steve French 已提交
438 439 440
{
	int rc = 0;
	int len;
441
	char nt_hash[CIFS_NTHASH_SIZE];
442 443
	wchar_t *user;
	wchar_t *domain;
444
	wchar_t *server;
S
Steve French 已提交
445

446 447 448 449
	if (!ses->server->secmech.sdeschmacmd5) {
		cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n");
		return -1;
	}
450

451 452
	/* calculate md4 hash of password */
	E_md4hash(ses->password, nt_hash);
453

454 455 456 457 458 459 460 461
	crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash,
				CIFS_NTHASH_SIZE);

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	if (rc) {
		cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n");
		return rc;
	}
S
Steve French 已提交
462 463

	/* convert ses->userName to unicode and uppercase */
S
Steve French 已提交
464 465
	len = strlen(ses->userName);
	user = kmalloc(2 + (len * 2), GFP_KERNEL);
466 467 468
	if (user == NULL) {
		cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n");
		rc = -ENOMEM;
S
Steve French 已提交
469
		goto calc_exit_2;
470
	}
471
	len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp);
S
Steve French 已提交
472
	UniStrupr(user);
473 474 475

	crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
				(char *)user, 2 * len);
S
Steve French 已提交
476 477

	/* convert ses->domainName to unicode and uppercase */
478
	if (ses->domainName) {
S
Steve French 已提交
479
		len = strlen(ses->domainName);
S
Steve French 已提交
480

481
		domain = kmalloc(2 + (len * 2), GFP_KERNEL);
482 483 484
		if (domain == NULL) {
			cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure");
			rc = -ENOMEM;
S
Steve French 已提交
485
			goto calc_exit_1;
486
		}
487 488
		len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len,
					nls_cp);
489 490
		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
					(char *)domain, 2 * len);
S
Steve French 已提交
491
		kfree(domain);
492 493 494 495 496 497 498 499 500 501 502 503 504 505
	} else if (ses->serverName) {
		len = strlen(ses->serverName);

		server = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (server == NULL) {
			cERROR(1, "calc_ntlmv2_hash: server mem alloc failure");
			rc = -ENOMEM;
			goto calc_exit_1;
		}
		len = cifs_strtoUCS((__le16 *)server, ses->serverName, len,
					nls_cp);
		crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
					(char *)server, 2 * len);
		kfree(server);
S
Steve French 已提交
506
	}
507 508

	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
509
					ntlmv2_hash);
510

S
Steve French 已提交
511 512 513
calc_exit_1:
	kfree(user);
calc_exit_2:
514 515 516 517
	return rc;
}

static int
518
CalcNTLMv2_response(const struct cifsSesInfo *ses, char *ntlmv2_hash)
519 520 521 522 523 524 525 526 527 528
{
	int rc;
	unsigned int offset = CIFS_SESS_KEY_SIZE + 8;

	if (!ses->server->secmech.sdeschmacmd5) {
		cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n");
		return -1;
	}

	crypto_shash_setkey(ses->server->secmech.hmacmd5,
529
				ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
530 531 532 533 534 535 536

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	if (rc) {
		cERROR(1, "CalcNTLMv2_response: could not init hmacmd5");
		return rc;
	}

537 538
	if (ses->server->secType == RawNTLMSSP)
		memcpy(ses->auth_key.response + offset,
539
			ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
540 541 542
	else
		memcpy(ses->auth_key.response + offset,
			ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
543 544 545 546 547
	crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
		ses->auth_key.response + offset, ses->auth_key.len - offset);

	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
		ses->auth_key.response + CIFS_SESS_KEY_SIZE);
548 549 550 551

	return rc;
}

552

553
int
554
setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
555
{
556
	int rc;
557
	int baselen;
558
	unsigned int tilen;
559
	struct ntlmv2_resp *buf;
560 561
	char ntlmv2_hash[16];
	unsigned char *tiblob = NULL; /* target info blob */
S
Steve French 已提交
562

563 564
	if (ses->server->secType == RawNTLMSSP) {
		if (!ses->domainName) {
565
			rc = find_domain_name(ses, nls_cp);
566 567 568 569 570 571
			if (rc) {
				cERROR(1, "error %d finding domain name", rc);
				goto setup_ntlmv2_rsp_ret;
			}
		}
	} else {
572
		rc = build_avpair_blob(ses, nls_cp);
573 574
		if (rc) {
			cERROR(1, "error %d building av pair blob", rc);
575
			goto setup_ntlmv2_rsp_ret;
576 577
		}
	}
S
Steve French 已提交
578

579
	baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
580 581 582 583
	tilen = ses->auth_key.len;
	tiblob = ses->auth_key.response;

	ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL);
584 585
	if (!ses->auth_key.response) {
		rc = ENOMEM;
586
		ses->auth_key.len = 0;
587 588 589
		cERROR(1, "%s: Can't allocate auth blob", __func__);
		goto setup_ntlmv2_rsp_ret;
	}
590
	ses->auth_key.len += baselen;
591 592 593 594 595 596 597 598 599

	buf = (struct ntlmv2_resp *)
			(ses->auth_key.response + CIFS_SESS_KEY_SIZE);
	buf->blob_signature = cpu_to_le32(0x00000101);
	buf->reserved = 0;
	buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
	get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
	buf->reserved2 = 0;

600
	memcpy(ses->auth_key.response + baselen, tiblob, tilen);
601

602
	/* calculate ntlmv2_hash */
603
	rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
604
	if (rc) {
605
		cERROR(1, "could not get v2 hash rc %d", rc);
606 607
		goto setup_ntlmv2_rsp_ret;
	}
608 609

	/* calculate first part of the client response (CR1) */
610
	rc = CalcNTLMv2_response(ses, ntlmv2_hash);
611 612 613 614
	if (rc) {
		cERROR(1, "Could not calculate CR1  rc: %d", rc);
		goto setup_ntlmv2_rsp_ret;
	}
615

616
	/* now calculate the session key for NTLMv2 */
617
	crypto_shash_setkey(ses->server->secmech.hmacmd5,
618
		ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
619 620 621 622 623 624 625 626 627 628 629 630 631

	rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
	if (rc) {
		cERROR(1, "%s: Could not init hmacmd5\n", __func__);
		goto setup_ntlmv2_rsp_ret;
	}

	crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
		ses->auth_key.response + CIFS_SESS_KEY_SIZE,
		CIFS_HMAC_MD5_HASH_SIZE);

	rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
		ses->auth_key.response);
632 633

setup_ntlmv2_rsp_ret:
634
	kfree(tiblob);
635 636

	return rc;
S
Steve French 已提交
637 638
}

639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
int
calc_seckey(struct cifsSesInfo *ses)
{
	int rc;
	struct crypto_blkcipher *tfm_arc4;
	struct scatterlist sgin, sgout;
	struct blkcipher_desc desc;
	unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */

	get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);

	tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
	if (!tfm_arc4 || IS_ERR(tfm_arc4)) {
		cERROR(1, "could not allocate crypto API arc4\n");
		return PTR_ERR(tfm_arc4);
	}

	desc.tfm = tfm_arc4;

	crypto_blkcipher_setkey(tfm_arc4, ses->auth_key.response,
					CIFS_SESS_KEY_SIZE);

	sg_init_one(&sgin, sec_key, CIFS_SESS_KEY_SIZE);
662
	sg_init_one(&sgout, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE);
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750

	rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE);
	if (rc) {
		cERROR(1, "could not encrypt session key rc: %d\n", rc);
		crypto_free_blkcipher(tfm_arc4);
		return rc;
	}

	/* make secondary_key/nonce as session key */
	memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE);
	/* and make len as that of session key only */
	ses->auth_key.len = CIFS_SESS_KEY_SIZE;

	crypto_free_blkcipher(tfm_arc4);

	return 0;
}

void
cifs_crypto_shash_release(struct TCP_Server_Info *server)
{
	if (server->secmech.md5)
		crypto_free_shash(server->secmech.md5);

	if (server->secmech.hmacmd5)
		crypto_free_shash(server->secmech.hmacmd5);

	kfree(server->secmech.sdeschmacmd5);

	kfree(server->secmech.sdescmd5);
}

int
cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
{
	int rc;
	unsigned int size;

	server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
	if (!server->secmech.hmacmd5 ||
			IS_ERR(server->secmech.hmacmd5)) {
		cERROR(1, "could not allocate crypto hmacmd5\n");
		return PTR_ERR(server->secmech.hmacmd5);
	}

	server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
	if (!server->secmech.md5 || IS_ERR(server->secmech.md5)) {
		cERROR(1, "could not allocate crypto md5\n");
		rc = PTR_ERR(server->secmech.md5);
		goto crypto_allocate_md5_fail;
	}

	size = sizeof(struct shash_desc) +
			crypto_shash_descsize(server->secmech.hmacmd5);
	server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
	if (!server->secmech.sdeschmacmd5) {
		cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n");
		rc = -ENOMEM;
		goto crypto_allocate_hmacmd5_sdesc_fail;
	}
	server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
	server->secmech.sdeschmacmd5->shash.flags = 0x0;


	size = sizeof(struct shash_desc) +
			crypto_shash_descsize(server->secmech.md5);
	server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
	if (!server->secmech.sdescmd5) {
		cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n");
		rc = -ENOMEM;
		goto crypto_allocate_md5_sdesc_fail;
	}
	server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
	server->secmech.sdescmd5->shash.flags = 0x0;

	return 0;

crypto_allocate_md5_sdesc_fail:
	kfree(server->secmech.sdeschmacmd5);

crypto_allocate_hmacmd5_sdesc_fail:
	crypto_free_shash(server->secmech.md5);

crypto_allocate_md5_fail:
	crypto_free_shash(server->secmech.hmacmd5);

	return rc;
}