aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorSteve French <smfrench@gmail.com>2013-06-27 00:45:05 -0400
committerSteve French <smfrench@gmail.com>2013-06-27 00:45:05 -0400
commit429b46f4fdaf9c9007b7c0fc371b94e40c3764b2 (patch)
tree7643a60439f4e81159e6327539a0983270e38331 /fs/cifs
parentf87ab88b4065a9ef00620224c4fafadc201a430c (diff)
[CIFS] SMB3 Signing enablement
SMB3 uses a much faster method of signing (which is also better in other ways), AES-CMAC. With the kernel now supporting AES-CMAC since last release, we are overdue to allow SMB3 signing (today only CIFS and SMB2 and SMB2.1, but not SMB3 and SMB3.1 can sign) - and we need this also for checking secure negotation and also per-share encryption (two other new SMB3 features which we need to implement). This patch needs some work in a few areas - for example we need to move signing for SMB2/SMB3 from per-socket to per-user (we may be able to use the "nosharesock" mount option in the interim for the multiuser case), and Shirish found a bug in the earlier authentication overhaul (setting signing flags properly) - but those can be done in followon patches. Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/Kconfig1
-rw-r--r--fs/cifs/cifsencrypt.c29
-rw-r--r--fs/cifs/cifsglob.h3
-rw-r--r--fs/cifs/cifspdu.h5
-rw-r--r--fs/cifs/cifsproto.h1
-rw-r--r--fs/cifs/connect.c1
-rw-r--r--fs/cifs/smb2glob.h2
-rw-r--r--fs/cifs/smb2transport.c148
8 files changed, 188 insertions, 2 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index 2906ee276408..603f18a65c12 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -10,6 +10,7 @@ config CIFS
10 select CRYPTO_ECB 10 select CRYPTO_ECB
11 select CRYPTO_DES 11 select CRYPTO_DES
12 select CRYPTO_SHA256 12 select CRYPTO_SHA256
13 select CRYPTO_CMAC
13 help 14 help
14 This is the client VFS module for the Common Internet File System 15 This is the client VFS module for the Common Internet File System
15 (CIFS) protocol which is the successor to the Server Message Block 16 (CIFS) protocol which is the successor to the Server Message Block
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 330875948f18..3d8bf941d126 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -705,6 +705,9 @@ calc_seckey(struct cifs_ses *ses)
705void 705void
706cifs_crypto_shash_release(struct TCP_Server_Info *server) 706cifs_crypto_shash_release(struct TCP_Server_Info *server)
707{ 707{
708 if (server->secmech.cmacaes)
709 crypto_free_shash(server->secmech.cmacaes);
710
708 if (server->secmech.hmacsha256) 711 if (server->secmech.hmacsha256)
709 crypto_free_shash(server->secmech.hmacsha256); 712 crypto_free_shash(server->secmech.hmacsha256);
710 713
@@ -714,6 +717,8 @@ cifs_crypto_shash_release(struct TCP_Server_Info *server)
714 if (server->secmech.hmacmd5) 717 if (server->secmech.hmacmd5)
715 crypto_free_shash(server->secmech.hmacmd5); 718 crypto_free_shash(server->secmech.hmacmd5);
716 719
720 kfree(server->secmech.sdesccmacaes);
721
717 kfree(server->secmech.sdeschmacsha256); 722 kfree(server->secmech.sdeschmacsha256);
718 723
719 kfree(server->secmech.sdeschmacmd5); 724 kfree(server->secmech.sdeschmacmd5);
@@ -747,6 +752,13 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
747 goto crypto_allocate_hmacsha256_fail; 752 goto crypto_allocate_hmacsha256_fail;
748 } 753 }
749 754
755 server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
756 if (IS_ERR(server->secmech.cmacaes)) {
757 cifs_dbg(VFS, "could not allocate crypto cmac-aes");
758 rc = PTR_ERR(server->secmech.cmacaes);
759 goto crypto_allocate_cmacaes_fail;
760 }
761
750 size = sizeof(struct shash_desc) + 762 size = sizeof(struct shash_desc) +
751 crypto_shash_descsize(server->secmech.hmacmd5); 763 crypto_shash_descsize(server->secmech.hmacmd5);
752 server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); 764 server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
@@ -777,8 +789,22 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
777 server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256; 789 server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
778 server->secmech.sdeschmacsha256->shash.flags = 0x0; 790 server->secmech.sdeschmacsha256->shash.flags = 0x0;
779 791
792 size = sizeof(struct shash_desc) +
793 crypto_shash_descsize(server->secmech.cmacaes);
794 server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
795 if (!server->secmech.sdesccmacaes) {
796 cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
797 rc = -ENOMEM;
798 goto crypto_allocate_cmacaes_sdesc_fail;
799 }
800 server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
801 server->secmech.sdesccmacaes->shash.flags = 0x0;
802
780 return 0; 803 return 0;
781 804
805crypto_allocate_cmacaes_sdesc_fail:
806 kfree(server->secmech.sdeschmacsha256);
807
782crypto_allocate_hmacsha256_sdesc_fail: 808crypto_allocate_hmacsha256_sdesc_fail:
783 kfree(server->secmech.sdescmd5); 809 kfree(server->secmech.sdescmd5);
784 810
@@ -786,6 +812,9 @@ crypto_allocate_md5_sdesc_fail:
786 kfree(server->secmech.sdeschmacmd5); 812 kfree(server->secmech.sdeschmacmd5);
787 813
788crypto_allocate_hmacmd5_sdesc_fail: 814crypto_allocate_hmacmd5_sdesc_fail:
815 crypto_free_shash(server->secmech.cmacaes);
816
817crypto_allocate_cmacaes_fail:
789 crypto_free_shash(server->secmech.hmacsha256); 818 crypto_free_shash(server->secmech.hmacsha256);
790 819
791crypto_allocate_hmacsha256_fail: 820crypto_allocate_hmacsha256_fail:
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 9a1e37aad3b8..2d0f524ebeee 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -125,9 +125,11 @@ struct cifs_secmech {
125 struct crypto_shash *hmacmd5; /* hmac-md5 hash function */ 125 struct crypto_shash *hmacmd5; /* hmac-md5 hash function */
126 struct crypto_shash *md5; /* md5 hash function */ 126 struct crypto_shash *md5; /* md5 hash function */
127 struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */ 127 struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */
128 struct crypto_shash *cmacaes; /* block-cipher based MAC function */
128 struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */ 129 struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */
129 struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */ 130 struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
130 struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */ 131 struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */
132 struct sdesc *sdesccmacaes; /* ctxt to generate smb3 signature */
131}; 133};
132 134
133/* per smb session structure/fields */ 135/* per smb session structure/fields */
@@ -538,6 +540,7 @@ struct TCP_Server_Info {
538 int timeAdj; /* Adjust for difference in server time zone in sec */ 540 int timeAdj; /* Adjust for difference in server time zone in sec */
539 __u64 CurrentMid; /* multiplex id - rotating counter */ 541 __u64 CurrentMid; /* multiplex id - rotating counter */
540 char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */ 542 char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
543 char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
541 /* 16th byte of RFC1001 workstation name is always null */ 544 /* 16th byte of RFC1001 workstation name is always null */
542 char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; 545 char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
543 __u32 sequence_number; /* for signing, protected by srv_mutex */ 546 __u32 sequence_number; /* for signing, protected by srv_mutex */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 7e8523c5c18e..11ca24a8e054 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -142,6 +142,11 @@
142 */ 142 */
143#define CIFS_SESS_KEY_SIZE (16) 143#define CIFS_SESS_KEY_SIZE (16)
144 144
145/*
146 * Size of the smb3 signing key
147 */
148#define SMB3_SIGN_KEY_SIZE (16)
149
145#define CIFS_CLIENT_CHALLENGE_SIZE (8) 150#define CIFS_CLIENT_CHALLENGE_SIZE (8)
146#define CIFS_SERVER_CHALLENGE_SIZE (8) 151#define CIFS_SERVER_CHALLENGE_SIZE (8)
147#define CIFS_HMAC_MD5_HASH_SIZE (16) 152#define CIFS_HMAC_MD5_HASH_SIZE (16)
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index a82b3c09888b..ff669e7c5857 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -436,6 +436,7 @@ extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
436extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); 436extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
437extern void cifs_crypto_shash_release(struct TCP_Server_Info *); 437extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
438extern int calc_seckey(struct cifs_ses *); 438extern int calc_seckey(struct cifs_ses *);
439extern int generate_smb3signingkey(struct TCP_Server_Info *);
439 440
440#ifdef CONFIG_CIFS_WEAK_PW_HASH 441#ifdef CONFIG_CIFS_WEAK_PW_HASH
441extern int calc_lanman_hash(const char *password, const char *cryptkey, 442extern int calc_lanman_hash(const char *password, const char *cryptkey,
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 53a1780cd073..354ea7782dba 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3841,6 +3841,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
3841 server->sequence_number = 0x2; 3841 server->sequence_number = 0x2;
3842 server->session_estab = true; 3842 server->session_estab = true;
3843 ses->auth_key.response = NULL; 3843 ses->auth_key.response = NULL;
3844 generate_smb3signingkey(server);
3844 } 3845 }
3845 mutex_unlock(&server->srv_mutex); 3846 mutex_unlock(&server->srv_mutex);
3846 3847
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 7c0e2143e775..c38350851b08 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -54,5 +54,7 @@
54#define SMB2_SIGNATURE_SIZE (16) 54#define SMB2_SIGNATURE_SIZE (16)
55#define SMB2_NTLMV2_SESSKEY_SIZE (16) 55#define SMB2_NTLMV2_SESSKEY_SIZE (16)
56#define SMB2_HMACSHA256_SIZE (32) 56#define SMB2_HMACSHA256_SIZE (32)
57#define SMB2_CMACAES_SIZE (16)
58#define SMB3_SIGNKEY_SIZE (16)
57 59
58#endif /* _SMB2_GLOB_H */ 60#endif /* _SMB2_GLOB_H */
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index c802ecfa770e..87563ee58d30 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -117,10 +117,154 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
117} 117}
118 118
119int 119int
120generate_smb3signingkey(struct TCP_Server_Info *server)
121{
122 unsigned char zero = 0x0;
123 __u8 i[4] = {0, 0, 0, 1};
124 __u8 L[4] = {0, 0, 0, 128};
125 int rc = 0;
126 unsigned char prfhash[SMB2_HMACSHA256_SIZE];
127 unsigned char *hashptr = prfhash;
128
129 memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
130 memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);
131
132 rc = crypto_shash_setkey(server->secmech.hmacsha256,
133 server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
134 if (rc) {
135 cifs_dbg(VFS, "%s: Could not set with session key\n", __func__);
136 goto smb3signkey_ret;
137 }
138
139 rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
140 if (rc) {
141 cifs_dbg(VFS, "%s: Could not init sign hmac\n", __func__);
142 goto smb3signkey_ret;
143 }
144
145 rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
146 i, 4);
147 if (rc) {
148 cifs_dbg(VFS, "%s: Could not update with n\n", __func__);
149 goto smb3signkey_ret;
150 }
151
152 rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
153 "SMB2AESCMAC", 12);
154 if (rc) {
155 cifs_dbg(VFS, "%s: Could not update with label\n", __func__);
156 goto smb3signkey_ret;
157 }
158
159 rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
160 &zero, 1);
161 if (rc) {
162 cifs_dbg(VFS, "%s: Could not update with zero\n", __func__);
163 goto smb3signkey_ret;
164 }
165
166 rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
167 "SmbSign", 8);
168 if (rc) {
169 cifs_dbg(VFS, "%s: Could not update with context\n", __func__);
170 goto smb3signkey_ret;
171 }
172
173 rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
174 L, 4);
175 if (rc) {
176 cifs_dbg(VFS, "%s: Could not update with L\n", __func__);
177 goto smb3signkey_ret;
178 }
179
180 rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
181 hashptr);
182 if (rc) {
183 cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__);
184 goto smb3signkey_ret;
185 }
186
187 memcpy(server->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE);
188
189smb3signkey_ret:
190 return rc;
191}
192
193int
120smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) 194smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
121{ 195{
122 cifs_dbg(FYI, "smb3 signatures not supported yet\n"); 196 int i, rc;
123 return -EOPNOTSUPP; 197 unsigned char smb3_signature[SMB2_CMACAES_SIZE];
198 unsigned char *sigptr = smb3_signature;
199 struct kvec *iov = rqst->rq_iov;
200 int n_vec = rqst->rq_nvec;
201 struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
202
203 memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
204 memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
205
206 rc = crypto_shash_setkey(server->secmech.cmacaes,
207 server->smb3signingkey, SMB2_CMACAES_SIZE);
208 if (rc) {
209 cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
210 return rc;
211 }
212
213 rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash);
214 if (rc) {
215 cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
216 return rc;
217 }
218
219 for (i = 0; i < n_vec; i++) {
220 if (iov[i].iov_len == 0)
221 continue;
222 if (iov[i].iov_base == NULL) {
223 cifs_dbg(VFS, "null iovec entry");
224 return -EIO;
225 }
226 /*
227 * The first entry includes a length field (which does not get
228 * signed that occupies the first 4 bytes before the header).
229 */
230 if (i == 0) {
231 if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
232 break; /* nothing to sign or corrupt header */
233 rc =
234 crypto_shash_update(
235 &server->secmech.sdesccmacaes->shash,
236 iov[i].iov_base + 4, iov[i].iov_len - 4);
237 } else {
238 rc =
239 crypto_shash_update(
240 &server->secmech.sdesccmacaes->shash,
241 iov[i].iov_base, iov[i].iov_len);
242 }
243 if (rc) {
244 cifs_dbg(VFS, "%s: Couldn't update cmac aes with payload\n",
245 __func__);
246 return rc;
247 }
248 }
249
250 /* now hash over the rq_pages array */
251 for (i = 0; i < rqst->rq_npages; i++) {
252 struct kvec p_iov;
253
254 cifs_rqst_page_to_kvec(rqst, i, &p_iov);
255 crypto_shash_update(&server->secmech.sdesccmacaes->shash,
256 p_iov.iov_base, p_iov.iov_len);
257 kunmap(rqst->rq_pages[i]);
258 }
259
260 rc = crypto_shash_final(&server->secmech.sdesccmacaes->shash,
261 sigptr);
262 if (rc)
263 cifs_dbg(VFS, "%s: Could not generate cmac aes\n", __func__);
264
265 memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
266
267 return rc;
124} 268}
125 269
126/* must be called with server->srv_mutex held */ 270/* must be called with server->srv_mutex held */