aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2010-10-21 15:25:08 -0400
committerSteve French <sfrench@us.ibm.com>2010-10-26 14:35:31 -0400
commitd2b915210b5ec01409f581421d633eca6c38d444 (patch)
tree5e4467f4888eb8c9936fbfd7b5bd7b9058af26e9 /fs
parentb235f371a2572d7c86a121d96d889eee02ed00e2 (diff)
NTLM auth and sign - Define crypto hash functions and create and send keys needed for key exchange
Mark dependency on crypto modules in Kconfig. Defining per structures sdesc and cifs_secmech which are used to store crypto hash functions and contexts. They are stored per smb connection and used for all auth mechs to genereate hash values and signatures. Allocate crypto hashing functions, security descriptiors, and respective contexts when a smb/tcp connection is established. Release them when a tcp/smb connection is taken down. md5 and hmac-md5 are two crypto hashing functions that are used throught the life of an smb/tcp connection by various functions that calcualte signagure and ntlmv2 hash, HMAC etc. structure ntlmssp_auth is defined as per smb connection. ntlmssp_auth holds ciphertext which is genereated by rc4/arc4 encryption of secondary key, a nonce using ntlmv2 session key and sent in the session key field of the type 3 message sent by the client during ntlmssp negotiation/exchange A key is exchanged with the server if client indicates so in flags in type 1 messsage and server agrees in flag in type 2 message of ntlmssp negotiation. If both client and agree, a key sent by client in type 3 message of ntlmssp negotiation in the session key field. The key is a ciphertext generated off of secondary key, a nonce, using ntlmv2 hash via rc4/arc4. Signing works for ntlmssp in this patch. The sequence number within the server structure needs to be zero until session is established i.e. till type 3 packet of ntlmssp exchange of a to be very first smb session on that smb connection is sent. Acked-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/Kconfig3
-rw-r--r--fs/cifs/cifsencrypt.c113
-rw-r--r--fs/cifs/cifsglob.h26
-rw-r--r--fs/cifs/cifspdu.h6
-rw-r--r--fs/cifs/cifsproto.h4
-rw-r--r--fs/cifs/connect.c16
-rw-r--r--fs/cifs/sess.c26
7 files changed, 184 insertions, 10 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index 917b7d449bb2..0ed213970ced 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -2,6 +2,9 @@ config CIFS
2 tristate "CIFS support (advanced network filesystem, SMBFS successor)" 2 tristate "CIFS support (advanced network filesystem, SMBFS successor)"
3 depends on INET 3 depends on INET
4 select NLS 4 select NLS
5 select CRYPTO
6 select CRYPTO_MD5
7 select CRYPTO_ARC4
5 help 8 help
6 This is the client VFS module for the Common Internet File System 9 This is the client VFS module for the Common Internet File System
7 (CIFS) protocol which is the successor to the Server Message Block 10 (CIFS) protocol which is the successor to the Server Message Block
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 987b479d55dd..eaa2327ee7af 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -541,6 +541,119 @@ setup_ntlmv2_rsp_ret:
541 return rc; 541 return rc;
542} 542}
543 543
544int
545calc_seckey(struct cifsSesInfo *ses)
546{
547 int rc;
548 struct crypto_blkcipher *tfm_arc4;
549 struct scatterlist sgin, sgout;
550 struct blkcipher_desc desc;
551 unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */
552
553 get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE);
554
555 tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
556 if (!tfm_arc4 || IS_ERR(tfm_arc4)) {
557 cERROR(1, "could not allocate crypto API arc4\n");
558 return PTR_ERR(tfm_arc4);
559 }
560
561 desc.tfm = tfm_arc4;
562
563 crypto_blkcipher_setkey(tfm_arc4, ses->auth_key.response,
564 CIFS_SESS_KEY_SIZE);
565
566 sg_init_one(&sgin, sec_key, CIFS_SESS_KEY_SIZE);
567 sg_init_one(&sgout, ses->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE);
568
569 rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE);
570 if (rc) {
571 cERROR(1, "could not encrypt session key rc: %d\n", rc);
572 crypto_free_blkcipher(tfm_arc4);
573 return rc;
574 }
575
576 /* make secondary_key/nonce as session key */
577 memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE);
578 /* and make len as that of session key only */
579 ses->auth_key.len = CIFS_SESS_KEY_SIZE;
580
581 crypto_free_blkcipher(tfm_arc4);
582
583 return 0;
584}
585
586void
587cifs_crypto_shash_release(struct TCP_Server_Info *server)
588{
589 if (server->secmech.md5)
590 crypto_free_shash(server->secmech.md5);
591
592 if (server->secmech.hmacmd5)
593 crypto_free_shash(server->secmech.hmacmd5);
594
595 kfree(server->secmech.sdeschmacmd5);
596
597 kfree(server->secmech.sdescmd5);
598}
599
600int
601cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
602{
603 int rc;
604 unsigned int size;
605
606 server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
607 if (!server->secmech.hmacmd5 ||
608 IS_ERR(server->secmech.hmacmd5)) {
609 cERROR(1, "could not allocate crypto hmacmd5\n");
610 return PTR_ERR(server->secmech.hmacmd5);
611 }
612
613 server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
614 if (!server->secmech.md5 || IS_ERR(server->secmech.md5)) {
615 cERROR(1, "could not allocate crypto md5\n");
616 rc = PTR_ERR(server->secmech.md5);
617 goto crypto_allocate_md5_fail;
618 }
619
620 size = sizeof(struct shash_desc) +
621 crypto_shash_descsize(server->secmech.hmacmd5);
622 server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
623 if (!server->secmech.sdeschmacmd5) {
624 cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n");
625 rc = -ENOMEM;
626 goto crypto_allocate_hmacmd5_sdesc_fail;
627 }
628 server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
629 server->secmech.sdeschmacmd5->shash.flags = 0x0;
630
631
632 size = sizeof(struct shash_desc) +
633 crypto_shash_descsize(server->secmech.md5);
634 server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
635 if (!server->secmech.sdescmd5) {
636 cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n");
637 rc = -ENOMEM;
638 goto crypto_allocate_md5_sdesc_fail;
639 }
640 server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
641 server->secmech.sdescmd5->shash.flags = 0x0;
642
643 return 0;
644
645crypto_allocate_md5_sdesc_fail:
646 kfree(server->secmech.sdeschmacmd5);
647
648crypto_allocate_hmacmd5_sdesc_fail:
649 crypto_free_shash(server->secmech.md5);
650
651crypto_allocate_md5_fail:
652 crypto_free_shash(server->secmech.hmacmd5);
653
654 return rc;
655}
656
544void CalcNTLMv2_response(const struct cifsSesInfo *ses) 657void CalcNTLMv2_response(const struct cifsSesInfo *ses)
545{ 658{
546 unsigned int offset = CIFS_SESS_KEY_SIZE + 8; 659 unsigned int offset = CIFS_SESS_KEY_SIZE + 8;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 66f76b2d270b..7ca5f6d8ed80 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -25,6 +25,9 @@
25#include <linux/workqueue.h> 25#include <linux/workqueue.h>
26#include "cifs_fs_sb.h" 26#include "cifs_fs_sb.h"
27#include "cifsacl.h" 27#include "cifsacl.h"
28#include <crypto/internal/hash.h>
29#include <linux/scatterlist.h>
30
28/* 31/*
29 * The sizes of various internal tables and strings 32 * The sizes of various internal tables and strings
30 */ 33 */
@@ -102,6 +105,27 @@ struct session_key {
102 char *response; 105 char *response;
103}; 106};
104 107
108/* crypto security descriptor definition */
109struct sdesc {
110 struct shash_desc shash;
111 char ctx[];
112};
113
114/* crypto hashing related structure/fields, not speicific to a sec mech */
115struct cifs_secmech {
116 struct crypto_shash *hmacmd5; /* hmac-md5 hash function */
117 struct crypto_shash *md5; /* md5 hash function */
118 struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */
119 struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
120};
121
122/* per smb connection structure/fields */
123struct ntlmssp_auth {
124 __u32 client_flags; /* sent by client in type 1 ntlmsssp exchange */
125 __u32 server_flags; /* sent by server in type 2 ntlmssp exchange */
126 unsigned char ciphertext[CIFS_CPHTXT_SIZE]; /* sent to server */
127};
128
105struct cifs_cred { 129struct cifs_cred {
106 int uid; 130 int uid;
107 int gid; 131 int gid;
@@ -178,6 +202,7 @@ struct TCP_Server_Info {
178 struct session_key session_key; 202 struct session_key session_key;
179 unsigned long lstrp; /* when we got last response from this server */ 203 unsigned long lstrp; /* when we got last response from this server */
180 u16 dialect; /* dialect index that server chose */ 204 u16 dialect; /* dialect index that server chose */
205 struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
181 /* extended security flavors that server supports */ 206 /* extended security flavors that server supports */
182 bool sec_kerberos; /* supports plain Kerberos */ 207 bool sec_kerberos; /* supports plain Kerberos */
183 bool sec_mskerberos; /* supports legacy MS Kerberos */ 208 bool sec_mskerberos; /* supports legacy MS Kerberos */
@@ -220,6 +245,7 @@ struct cifsSesInfo {
220 char ntlmv2_hash[16]; 245 char ntlmv2_hash[16];
221 unsigned int tilen; /* length of the target info blob */ 246 unsigned int tilen; /* length of the target info blob */
222 unsigned char *tiblob; /* target info blob in challenge response */ 247 unsigned char *tiblob; /* target info blob in challenge response */
248 struct ntlmssp_auth ntlmssp; /* ciphertext, flags */
223 bool need_reconnect:1; /* connection reset, uid now invalid */ 249 bool need_reconnect:1; /* connection reset, uid now invalid */
224}; 250};
225/* no more than one of the following three session flags may be set */ 251/* no more than one of the following three session flags may be set */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index a152cd6db99b..de36b09763a8 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -140,6 +140,12 @@
140 */ 140 */
141#define CIFS_SESS_KEY_SIZE (16) 141#define CIFS_SESS_KEY_SIZE (16)
142 142
143#define CIFS_CLIENT_CHALLENGE_SIZE (8)
144#define CIFS_SERVER_CHALLENGE_SIZE (8)
145#define CIFS_HMAC_MD5_HASH_SIZE (16)
146#define CIFS_CPHTXT_SIZE (16)
147#define CIFS_NTHASH_SIZE (16)
148
143/* 149/*
144 * Maximum user name length 150 * Maximum user name length
145 */ 151 */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 8c2d0cf1a62f..1e4728bcf065 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -368,6 +368,10 @@ extern 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 *); 369extern void CalcNTLMv2_response(const struct cifsSesInfo *);
370extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *); 370extern int setup_ntlmv2_rsp(struct cifsSesInfo *, const struct nls_table *);
371extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
372extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
373extern int calc_seckey(struct cifsSesInfo *);
374
371#ifdef CONFIG_CIFS_WEAK_PW_HASH 375#ifdef CONFIG_CIFS_WEAK_PW_HASH
372extern void calc_lanman_hash(const char *password, const char *cryptkey, 376extern void calc_lanman_hash(const char *password, const char *cryptkey,
373 bool encrypt, char *lnm_session_key); 377 bool encrypt, char *lnm_session_key);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index dd9a4ae1d21d..04239a7ff320 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1563,6 +1563,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
1563 server->tcpStatus = CifsExiting; 1563 server->tcpStatus = CifsExiting;
1564 spin_unlock(&GlobalMid_Lock); 1564 spin_unlock(&GlobalMid_Lock);
1565 1565
1566 cifs_crypto_shash_release(server);
1566 cifs_fscache_release_client_cookie(server); 1567 cifs_fscache_release_client_cookie(server);
1567 1568
1568 kfree(server->session_key.response); 1569 kfree(server->session_key.response);
@@ -1621,10 +1622,16 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1621 goto out_err; 1622 goto out_err;
1622 } 1623 }
1623 1624
1625 rc = cifs_crypto_shash_allocate(tcp_ses);
1626 if (rc) {
1627 cERROR(1, "could not setup hash structures rc %d", rc);
1628 goto out_err;
1629 }
1630
1624 tcp_ses->hostname = extract_hostname(volume_info->UNC); 1631 tcp_ses->hostname = extract_hostname(volume_info->UNC);
1625 if (IS_ERR(tcp_ses->hostname)) { 1632 if (IS_ERR(tcp_ses->hostname)) {
1626 rc = PTR_ERR(tcp_ses->hostname); 1633 rc = PTR_ERR(tcp_ses->hostname);
1627 goto out_err; 1634 goto out_err2;
1628 } 1635 }
1629 1636
1630 tcp_ses->noblocksnd = volume_info->noblocksnd; 1637 tcp_ses->noblocksnd = volume_info->noblocksnd;
@@ -1668,7 +1675,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1668 } 1675 }
1669 if (rc < 0) { 1676 if (rc < 0) {
1670 cERROR(1, "Error connecting to socket. Aborting operation"); 1677 cERROR(1, "Error connecting to socket. Aborting operation");
1671 goto out_err; 1678 goto out_err2;
1672 } 1679 }
1673 1680
1674 /* 1681 /*
@@ -1682,7 +1689,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1682 rc = PTR_ERR(tcp_ses->tsk); 1689 rc = PTR_ERR(tcp_ses->tsk);
1683 cERROR(1, "error %d create cifsd thread", rc); 1690 cERROR(1, "error %d create cifsd thread", rc);
1684 module_put(THIS_MODULE); 1691 module_put(THIS_MODULE);
1685 goto out_err; 1692 goto out_err2;
1686 } 1693 }
1687 1694
1688 /* thread spawned, put it on the list */ 1695 /* thread spawned, put it on the list */
@@ -1694,6 +1701,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1694 1701
1695 return tcp_ses; 1702 return tcp_ses;
1696 1703
1704out_err2:
1705 cifs_crypto_shash_release(tcp_ses);
1706
1697out_err: 1707out_err:
1698 if (tcp_ses) { 1708 if (tcp_ses) {
1699 if (!IS_ERR(tcp_ses->hostname)) 1709 if (!IS_ERR(tcp_ses->hostname))
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index b2934683bd08..d998c4f7aae5 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -404,7 +404,7 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
404 /* In particular we can examine sign flags */ 404 /* In particular we can examine sign flags */
405 /* BB spec says that if AvId field of MsvAvTimestamp is populated then 405 /* BB spec says that if AvId field of MsvAvTimestamp is populated then
406 we must set the MIC field of the AUTHENTICATE_MESSAGE */ 406 we must set the MIC field of the AUTHENTICATE_MESSAGE */
407 407 ses->ntlmssp.server_flags = le32_to_cpu(pblob->NegotiateFlags);
408 tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); 408 tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset);
409 tilen = cpu_to_le16(pblob->TargetInfoArray.Length); 409 tilen = cpu_to_le16(pblob->TargetInfoArray.Length);
410 ses->tilen = tilen; 410 ses->tilen = tilen;
@@ -440,10 +440,12 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
440 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | 440 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
441 NTLMSSP_NEGOTIATE_NTLM; 441 NTLMSSP_NEGOTIATE_NTLM;
442 if (ses->server->secMode & 442 if (ses->server->secMode &
443 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) 443 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
444 flags |= NTLMSSP_NEGOTIATE_SIGN; 444 flags |= NTLMSSP_NEGOTIATE_SIGN;
445 if (ses->server->secMode & SECMODE_SIGN_REQUIRED) 445 if (!ses->server->session_estab)
446 flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; 446 flags |= NTLMSSP_NEGOTIATE_KEY_XCH |
447 NTLMSSP_NEGOTIATE_EXTENDED_SEC;
448 }
447 449
448 sec_blob->NegotiateFlags |= cpu_to_le32(flags); 450 sec_blob->NegotiateFlags |= cpu_to_le32(flags);
449 451
@@ -543,9 +545,19 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
543 sec_blob->WorkstationName.MaximumLength = 0; 545 sec_blob->WorkstationName.MaximumLength = 0;
544 tmp += 2; 546 tmp += 2;
545 547
546 sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); 548 if ((ses->ntlmssp.server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
547 sec_blob->SessionKey.Length = 0; 549 !calc_seckey(ses)) {
548 sec_blob->SessionKey.MaximumLength = 0; 550 memcpy(tmp, ses->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE);
551 sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
552 sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
553 sec_blob->SessionKey.MaximumLength =
554 cpu_to_le16(CIFS_CPHTXT_SIZE);
555 tmp += CIFS_CPHTXT_SIZE;
556 } else {
557 sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
558 sec_blob->SessionKey.Length = 0;
559 sec_blob->SessionKey.MaximumLength = 0;
560 }
549 561
550setup_ntlmv2_ret: 562setup_ntlmv2_ret:
551 *buflen = tmp - pbuffer; 563 *buflen = tmp - pbuffer;