aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2013-08-29 09:35:11 -0400
committerSteve French <smfrench@gmail.com>2013-09-08 15:47:50 -0400
commit32811d242ff6f28da2ab18c90a15e32fd958e774 (patch)
treef267608208809072de59ac7d1bb073fc03d1d26f
parent5c234aa5e33ed9037354a4c94d0d3e0350abe5eb (diff)
cifs: Start using per session key for smb2/3 for signature generation
Switch smb2 code to use per session session key and smb3 code to use per session signing key instead of per connection key to generate signatures. For that, we need to find a session to fetch the session key to generate signature to match for every request and response packet. We also forgo checking signature for a session setup response from the server. Acked-by: Jeff Layton <jlayton@samba.org> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Signed-off-by: Steve French <smfrench@gmail.com>
-rw-r--r--fs/cifs/cifsglob.h5
-rw-r--r--fs/cifs/cifsproto.h2
-rw-r--r--fs/cifs/smb2pdu.c14
-rw-r--r--fs/cifs/smb2transport.c70
4 files changed, 67 insertions, 24 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 20c7f8f4fba8..92798f74f0c3 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -366,8 +366,7 @@ struct smb_version_operations {
366 void (*set_lease_key)(struct inode *, struct cifs_fid *fid); 366 void (*set_lease_key)(struct inode *, struct cifs_fid *fid);
367 /* generate new lease key */ 367 /* generate new lease key */
368 void (*new_lease_key)(struct cifs_fid *fid); 368 void (*new_lease_key)(struct cifs_fid *fid);
369 /* The next two functions will need to be changed to per smb session */ 369 int (*generate_signingkey)(struct cifs_ses *);
370 void (*generate_signingkey)(struct TCP_Server_Info *server);
371 int (*calc_signature)(struct smb_rqst *rqst, 370 int (*calc_signature)(struct smb_rqst *rqst,
372 struct TCP_Server_Info *server); 371 struct TCP_Server_Info *server);
373 int (*query_mf_symlink)(const unsigned char *path, char *pbuf, 372 int (*query_mf_symlink)(const unsigned char *path, char *pbuf,
@@ -548,7 +547,6 @@ struct TCP_Server_Info {
548 int timeAdj; /* Adjust for difference in server time zone in sec */ 547 int timeAdj; /* Adjust for difference in server time zone in sec */
549 __u64 CurrentMid; /* multiplex id - rotating counter */ 548 __u64 CurrentMid; /* multiplex id - rotating counter */
550 char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */ 549 char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
551 char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
552 /* 16th byte of RFC1001 workstation name is always null */ 550 /* 16th byte of RFC1001 workstation name is always null */
553 char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; 551 char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
554 __u32 sequence_number; /* for signing, protected by srv_mutex */ 552 __u32 sequence_number; /* for signing, protected by srv_mutex */
@@ -731,6 +729,7 @@ struct cifs_ses {
731 bool need_reconnect:1; /* connection reset, uid now invalid */ 729 bool need_reconnect:1; /* connection reset, uid now invalid */
732#ifdef CONFIG_CIFS_SMB2 730#ifdef CONFIG_CIFS_SMB2
733 __u16 session_flags; 731 __u16 session_flags;
732 char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
734#endif /* CONFIG_CIFS_SMB2 */ 733#endif /* CONFIG_CIFS_SMB2 */
735}; 734};
736 735
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 5b05eb082a41..b5ec2a268f56 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -431,7 +431,7 @@ extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
431extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); 431extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
432extern void cifs_crypto_shash_release(struct TCP_Server_Info *); 432extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
433extern int calc_seckey(struct cifs_ses *); 433extern int calc_seckey(struct cifs_ses *);
434extern void generate_smb3signingkey(struct TCP_Server_Info *); 434extern int generate_smb3signingkey(struct cifs_ses *);
435 435
436#ifdef CONFIG_CIFS_WEAK_PW_HASH 436#ifdef CONFIG_CIFS_WEAK_PW_HASH
437extern int calc_lanman_hash(const char *password, const char *cryptkey, 437extern int calc_lanman_hash(const char *password, const char *cryptkey,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 3d010766f267..0a9458282717 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -639,11 +639,20 @@ ssetup_exit:
639 639
640 if (!rc) { 640 if (!rc) {
641 mutex_lock(&server->srv_mutex); 641 mutex_lock(&server->srv_mutex);
642 if (server->sign && server->ops->generate_signingkey) {
643 rc = server->ops->generate_signingkey(ses);
644 kfree(ses->auth_key.response);
645 ses->auth_key.response = NULL;
646 if (rc) {
647 cifs_dbg(FYI,
648 "SMB3 session key generation failed\n");
649 mutex_unlock(&server->srv_mutex);
650 goto keygen_exit;
651 }
652 }
642 if (!server->session_estab) { 653 if (!server->session_estab) {
643 server->sequence_number = 0x2; 654 server->sequence_number = 0x2;
644 server->session_estab = true; 655 server->session_estab = true;
645 if (server->ops->generate_signingkey)
646 server->ops->generate_signingkey(server);
647 } 656 }
648 mutex_unlock(&server->srv_mutex); 657 mutex_unlock(&server->srv_mutex);
649 658
@@ -654,6 +663,7 @@ ssetup_exit:
654 spin_unlock(&GlobalMid_Lock); 663 spin_unlock(&GlobalMid_Lock);
655 } 664 }
656 665
666keygen_exit:
657 if (!server->sign) { 667 if (!server->sign) {
658 kfree(ses->auth_key.response); 668 kfree(ses->auth_key.response);
659 ses->auth_key.response = NULL; 669 ses->auth_key.response = NULL;
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 4f2300d020c7..340abca3aa52 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -114,6 +114,23 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
114 return 0; 114 return 0;
115} 115}
116 116
117static struct cifs_ses *
118smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server)
119{
120 struct cifs_ses *ses;
121
122 spin_lock(&cifs_tcp_ses_lock);
123 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
124 if (ses->Suid != smb2hdr->SessionId)
125 continue;
126 spin_unlock(&cifs_tcp_ses_lock);
127 return ses;
128 }
129 spin_unlock(&cifs_tcp_ses_lock);
130
131 return NULL;
132}
133
117 134
118int 135int
119smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) 136smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
@@ -124,6 +141,13 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
124 struct kvec *iov = rqst->rq_iov; 141 struct kvec *iov = rqst->rq_iov;
125 int n_vec = rqst->rq_nvec; 142 int n_vec = rqst->rq_nvec;
126 struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; 143 struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
144 struct cifs_ses *ses;
145
146 ses = smb2_find_smb_ses(smb2_pdu, server);
147 if (!ses) {
148 cifs_dbg(VFS, "%s: Could not find session\n", __func__);
149 return 0;
150 }
127 151
128 memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE); 152 memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
129 memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE); 153 memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
@@ -135,7 +159,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
135 } 159 }
136 160
137 rc = crypto_shash_setkey(server->secmech.hmacsha256, 161 rc = crypto_shash_setkey(server->secmech.hmacsha256,
138 server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE); 162 ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
139 if (rc) { 163 if (rc) {
140 cifs_dbg(VFS, "%s: Could not update with response\n", __func__); 164 cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
141 return rc; 165 return rc;
@@ -198,8 +222,8 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
198 return rc; 222 return rc;
199} 223}
200 224
201void 225int
202generate_smb3signingkey(struct TCP_Server_Info *server) 226generate_smb3signingkey(struct cifs_ses *ses)
203{ 227{
204 unsigned char zero = 0x0; 228 unsigned char zero = 0x0;
205 __u8 i[4] = {0, 0, 0, 1}; 229 __u8 i[4] = {0, 0, 0, 1};
@@ -209,90 +233,99 @@ generate_smb3signingkey(struct TCP_Server_Info *server)
209 unsigned char *hashptr = prfhash; 233 unsigned char *hashptr = prfhash;
210 234
211 memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); 235 memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
212 memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE); 236 memset(ses->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);
213 237
214 rc = smb3_crypto_shash_allocate(server); 238 rc = smb3_crypto_shash_allocate(ses->server);
215 if (rc) { 239 if (rc) {
216 cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); 240 cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
217 goto smb3signkey_ret; 241 goto smb3signkey_ret;
218 } 242 }
219 243
220 rc = crypto_shash_setkey(server->secmech.hmacsha256, 244 rc = crypto_shash_setkey(ses->server->secmech.hmacsha256,
221 server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE); 245 ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
222 if (rc) { 246 if (rc) {
223 cifs_dbg(VFS, "%s: Could not set with session key\n", __func__); 247 cifs_dbg(VFS, "%s: Could not set with session key\n", __func__);
224 goto smb3signkey_ret; 248 goto smb3signkey_ret;
225 } 249 }
226 250
227 rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash); 251 rc = crypto_shash_init(&ses->server->secmech.sdeschmacsha256->shash);
228 if (rc) { 252 if (rc) {
229 cifs_dbg(VFS, "%s: Could not init sign hmac\n", __func__); 253 cifs_dbg(VFS, "%s: Could not init sign hmac\n", __func__);
230 goto smb3signkey_ret; 254 goto smb3signkey_ret;
231 } 255 }
232 256
233 rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, 257 rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
234 i, 4); 258 i, 4);
235 if (rc) { 259 if (rc) {
236 cifs_dbg(VFS, "%s: Could not update with n\n", __func__); 260 cifs_dbg(VFS, "%s: Could not update with n\n", __func__);
237 goto smb3signkey_ret; 261 goto smb3signkey_ret;
238 } 262 }
239 263
240 rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, 264 rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
241 "SMB2AESCMAC", 12); 265 "SMB2AESCMAC", 12);
242 if (rc) { 266 if (rc) {
243 cifs_dbg(VFS, "%s: Could not update with label\n", __func__); 267 cifs_dbg(VFS, "%s: Could not update with label\n", __func__);
244 goto smb3signkey_ret; 268 goto smb3signkey_ret;
245 } 269 }
246 270
247 rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, 271 rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
248 &zero, 1); 272 &zero, 1);
249 if (rc) { 273 if (rc) {
250 cifs_dbg(VFS, "%s: Could not update with zero\n", __func__); 274 cifs_dbg(VFS, "%s: Could not update with zero\n", __func__);
251 goto smb3signkey_ret; 275 goto smb3signkey_ret;
252 } 276 }
253 277
254 rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, 278 rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
255 "SmbSign", 8); 279 "SmbSign", 8);
256 if (rc) { 280 if (rc) {
257 cifs_dbg(VFS, "%s: Could not update with context\n", __func__); 281 cifs_dbg(VFS, "%s: Could not update with context\n", __func__);
258 goto smb3signkey_ret; 282 goto smb3signkey_ret;
259 } 283 }
260 284
261 rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, 285 rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
262 L, 4); 286 L, 4);
263 if (rc) { 287 if (rc) {
264 cifs_dbg(VFS, "%s: Could not update with L\n", __func__); 288 cifs_dbg(VFS, "%s: Could not update with L\n", __func__);
265 goto smb3signkey_ret; 289 goto smb3signkey_ret;
266 } 290 }
267 291
268 rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash, 292 rc = crypto_shash_final(&ses->server->secmech.sdeschmacsha256->shash,
269 hashptr); 293 hashptr);
270 if (rc) { 294 if (rc) {
271 cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); 295 cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__);
272 goto smb3signkey_ret; 296 goto smb3signkey_ret;
273 } 297 }
274 298
275 memcpy(server->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE); 299 memcpy(ses->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE);
276 300
277smb3signkey_ret: 301smb3signkey_ret:
278 return; 302 return rc;
279} 303}
280 304
281int 305int
282smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) 306smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
283{ 307{
284 int i, rc; 308 int i;
309 int rc = 0;
285 unsigned char smb3_signature[SMB2_CMACAES_SIZE]; 310 unsigned char smb3_signature[SMB2_CMACAES_SIZE];
286 unsigned char *sigptr = smb3_signature; 311 unsigned char *sigptr = smb3_signature;
287 struct kvec *iov = rqst->rq_iov; 312 struct kvec *iov = rqst->rq_iov;
288 int n_vec = rqst->rq_nvec; 313 int n_vec = rqst->rq_nvec;
289 struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; 314 struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
315 struct cifs_ses *ses;
316
317 ses = smb2_find_smb_ses(smb2_pdu, server);
318 if (!ses) {
319 cifs_dbg(VFS, "%s: Could not find session\n", __func__);
320 return 0;
321 }
290 322
291 memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE); 323 memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
292 memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE); 324 memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
293 325
294 rc = crypto_shash_setkey(server->secmech.cmacaes, 326 rc = crypto_shash_setkey(server->secmech.cmacaes,
295 server->smb3signingkey, SMB2_CMACAES_SIZE); 327 ses->smb3signingkey, SMB2_CMACAES_SIZE);
328
296 if (rc) { 329 if (rc) {
297 cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); 330 cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
298 return rc; 331 return rc;
@@ -389,6 +422,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
389 struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)rqst->rq_iov[0].iov_base; 422 struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
390 423
391 if ((smb2_pdu->Command == SMB2_NEGOTIATE) || 424 if ((smb2_pdu->Command == SMB2_NEGOTIATE) ||
425 (smb2_pdu->Command == SMB2_SESSION_SETUP) ||
392 (smb2_pdu->Command == SMB2_OPLOCK_BREAK) || 426 (smb2_pdu->Command == SMB2_OPLOCK_BREAK) ||
393 (!server->session_estab)) 427 (!server->session_estab))
394 return 0; 428 return 0;