Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Shirish Pargaonkar and committed by
Steve French
32811d24 5c234aa5

+67 -24
+2 -3
fs/cifs/cifsglob.h
··· 366 366 void (*set_lease_key)(struct inode *, struct cifs_fid *fid); 367 367 /* generate new lease key */ 368 368 void (*new_lease_key)(struct cifs_fid *fid); 369 - /* The next two functions will need to be changed to per smb session */ 370 - void (*generate_signingkey)(struct TCP_Server_Info *server); 369 + int (*generate_signingkey)(struct cifs_ses *); 371 370 int (*calc_signature)(struct smb_rqst *rqst, 372 371 struct TCP_Server_Info *server); 373 372 int (*query_mf_symlink)(const unsigned char *path, char *pbuf, ··· 547 548 int timeAdj; /* Adjust for difference in server time zone in sec */ 548 549 __u64 CurrentMid; /* multiplex id - rotating counter */ 549 550 char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */ 550 - char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */ 551 551 /* 16th byte of RFC1001 workstation name is always null */ 552 552 char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; 553 553 __u32 sequence_number; /* for signing, protected by srv_mutex */ ··· 729 731 bool need_reconnect:1; /* connection reset, uid now invalid */ 730 732 #ifdef CONFIG_CIFS_SMB2 731 733 __u16 session_flags; 734 + char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */ 732 735 #endif /* CONFIG_CIFS_SMB2 */ 733 736 }; 734 737
+1 -1
fs/cifs/cifsproto.h
··· 431 431 extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); 432 432 extern void cifs_crypto_shash_release(struct TCP_Server_Info *); 433 433 extern int calc_seckey(struct cifs_ses *); 434 - extern void generate_smb3signingkey(struct TCP_Server_Info *); 434 + extern int generate_smb3signingkey(struct cifs_ses *); 435 435 436 436 #ifdef CONFIG_CIFS_WEAK_PW_HASH 437 437 extern int calc_lanman_hash(const char *password, const char *cryptkey,
+12 -2
fs/cifs/smb2pdu.c
··· 639 639 640 640 if (!rc) { 641 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 653 if (!server->session_estab) { 643 654 server->sequence_number = 0x2; 644 655 server->session_estab = true; 645 - if (server->ops->generate_signingkey) 646 - server->ops->generate_signingkey(server); 647 656 } 648 657 mutex_unlock(&server->srv_mutex); 649 658 ··· 663 654 spin_unlock(&GlobalMid_Lock); 664 655 } 665 656 657 + keygen_exit: 666 658 if (!server->sign) { 667 659 kfree(ses->auth_key.response); 668 660 ses->auth_key.response = NULL;
+52 -18
fs/cifs/smb2transport.c
··· 114 114 return 0; 115 115 } 116 116 117 + static struct cifs_ses * 118 + smb2_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 118 135 int 119 136 smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) ··· 141 124 struct kvec *iov = rqst->rq_iov; 142 125 int n_vec = rqst->rq_nvec; 143 126 struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; 127 + struct cifs_ses *ses; 128 + 129 + ses = smb2_find_smb_ses(smb2_pdu, server); 130 + if (!ses) { 131 + cifs_dbg(VFS, "%s: Could not find session\n", __func__); 132 + return 0; 133 + } 144 134 145 135 memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE); 146 136 memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE); ··· 159 135 } 160 136 161 137 rc = crypto_shash_setkey(server->secmech.hmacsha256, 162 - server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE); 138 + ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); 163 139 if (rc) { 164 140 cifs_dbg(VFS, "%s: Could not update with response\n", __func__); 165 141 return rc; ··· 222 198 return rc; 223 199 } 224 200 225 - void 226 - generate_smb3signingkey(struct TCP_Server_Info *server) 201 + int 202 + generate_smb3signingkey(struct cifs_ses *ses) 227 203 { 228 204 unsigned char zero = 0x0; 229 205 __u8 i[4] = {0, 0, 0, 1}; ··· 233 209 unsigned char *hashptr = prfhash; 234 210 235 211 memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); 236 - memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE); 212 + memset(ses->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE); 237 213 238 - rc = smb3_crypto_shash_allocate(server); 214 + rc = smb3_crypto_shash_allocate(ses->server); 239 215 if (rc) { 240 216 cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); 241 217 goto smb3signkey_ret; 242 218 } 243 219 244 - rc = crypto_shash_setkey(server->secmech.hmacsha256, 245 - server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE); 220 + rc = crypto_shash_setkey(ses->server->secmech.hmacsha256, 221 + ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE); 246 222 if (rc) { 247 223 cifs_dbg(VFS, "%s: Could not set with session key\n", __func__); 248 224 goto smb3signkey_ret; 249 225 } 250 226 251 - rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash); 227 + rc = crypto_shash_init(&ses->server->secmech.sdeschmacsha256->shash); 252 228 if (rc) { 253 229 cifs_dbg(VFS, "%s: Could not init sign hmac\n", __func__); 254 230 goto smb3signkey_ret; 255 231 } 256 232 257 - rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, 233 + rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, 258 234 i, 4); 259 235 if (rc) { 260 236 cifs_dbg(VFS, "%s: Could not update with n\n", __func__); 261 237 goto smb3signkey_ret; 262 238 } 263 239 264 - rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, 240 + rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, 265 241 "SMB2AESCMAC", 12); 266 242 if (rc) { 267 243 cifs_dbg(VFS, "%s: Could not update with label\n", __func__); 268 244 goto smb3signkey_ret; 269 245 } 270 246 271 - rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, 247 + rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, 272 248 &zero, 1); 273 249 if (rc) { 274 250 cifs_dbg(VFS, "%s: Could not update with zero\n", __func__); 275 251 goto smb3signkey_ret; 276 252 } 277 253 278 - rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, 254 + rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, 279 255 "SmbSign", 8); 280 256 if (rc) { 281 257 cifs_dbg(VFS, "%s: Could not update with context\n", __func__); 282 258 goto smb3signkey_ret; 283 259 } 284 260 285 - rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash, 261 + rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash, 286 262 L, 4); 287 263 if (rc) { 288 264 cifs_dbg(VFS, "%s: Could not update with L\n", __func__); 289 265 goto smb3signkey_ret; 290 266 } 291 267 292 - rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash, 268 + rc = crypto_shash_final(&ses->server->secmech.sdeschmacsha256->shash, 293 269 hashptr); 294 270 if (rc) { 295 271 cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); 296 272 goto smb3signkey_ret; 297 273 } 298 274 299 - memcpy(server->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE); 275 + memcpy(ses->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE); 300 276 301 277 smb3signkey_ret: 302 - return; 278 + return rc; 303 279 } 304 280 305 281 int 306 282 smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) 307 283 { 308 - int i, rc; 284 + int i; 285 + int rc = 0; 309 286 unsigned char smb3_signature[SMB2_CMACAES_SIZE]; 310 287 unsigned char *sigptr = smb3_signature; 311 288 struct kvec *iov = rqst->rq_iov; 312 289 int n_vec = rqst->rq_nvec; 313 290 struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; 291 + struct cifs_ses *ses; 292 + 293 + ses = smb2_find_smb_ses(smb2_pdu, server); 294 + if (!ses) { 295 + cifs_dbg(VFS, "%s: Could not find session\n", __func__); 296 + return 0; 297 + } 314 298 315 299 memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE); 316 300 memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE); 317 301 318 302 rc = crypto_shash_setkey(server->secmech.cmacaes, 319 - server->smb3signingkey, SMB2_CMACAES_SIZE); 303 + ses->smb3signingkey, SMB2_CMACAES_SIZE); 304 + 320 305 if (rc) { 321 306 cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); 322 307 return rc; ··· 422 389 struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)rqst->rq_iov[0].iov_base; 423 390 424 391 if ((smb2_pdu->Command == SMB2_NEGOTIATE) || 392 + (smb2_pdu->Command == SMB2_SESSION_SETUP) || 425 393 (smb2_pdu->Command == SMB2_OPLOCK_BREAK) || 426 394 (!server->session_estab)) 427 395 return 0;