diff options
| -rw-r--r-- | fs/cifs/Kconfig | 1 | ||||
| -rw-r--r-- | fs/cifs/cifsencrypt.c | 29 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 3 | ||||
| -rw-r--r-- | fs/cifs/cifspdu.h | 5 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 1 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 1 | ||||
| -rw-r--r-- | fs/cifs/smb2glob.h | 2 | ||||
| -rw-r--r-- | fs/cifs/smb2transport.c | 148 |
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) | |||
| 705 | void | 705 | void |
| 706 | cifs_crypto_shash_release(struct TCP_Server_Info *server) | 706 | cifs_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 | ||
| 805 | crypto_allocate_cmacaes_sdesc_fail: | ||
| 806 | kfree(server->secmech.sdeschmacsha256); | ||
| 807 | |||
| 782 | crypto_allocate_hmacsha256_sdesc_fail: | 808 | crypto_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 | ||
| 788 | crypto_allocate_hmacmd5_sdesc_fail: | 814 | crypto_allocate_hmacmd5_sdesc_fail: |
| 815 | crypto_free_shash(server->secmech.cmacaes); | ||
| 816 | |||
| 817 | crypto_allocate_cmacaes_fail: | ||
| 789 | crypto_free_shash(server->secmech.hmacsha256); | 818 | crypto_free_shash(server->secmech.hmacsha256); |
| 790 | 819 | ||
| 791 | crypto_allocate_hmacsha256_fail: | 820 | crypto_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 *); | |||
| 436 | extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); | 436 | extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); |
| 437 | extern void cifs_crypto_shash_release(struct TCP_Server_Info *); | 437 | extern void cifs_crypto_shash_release(struct TCP_Server_Info *); |
| 438 | extern int calc_seckey(struct cifs_ses *); | 438 | extern int calc_seckey(struct cifs_ses *); |
| 439 | extern int generate_smb3signingkey(struct TCP_Server_Info *); | ||
| 439 | 440 | ||
| 440 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 441 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
| 441 | extern int calc_lanman_hash(const char *password, const char *cryptkey, | 442 | extern 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 | ||
| 119 | int | 119 | int |
| 120 | generate_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 | |||
| 189 | smb3signkey_ret: | ||
| 190 | return rc; | ||
| 191 | } | ||
| 192 | |||
| 193 | int | ||
| 120 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | 194 | smb3_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 */ |
