diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-11-12 22:46:49 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-03-28 14:05:27 -0400 |
commit | 16c568efff82e4a6a75d2bd86576e648fad8a7fe (patch) | |
tree | 1e002f9f43b5f90f9f6f0fad86cb819e2ddabd24 | |
parent | 2da62906b1e298695e1bb725927041cd59942c98 (diff) |
cifs: merge the hash calculation helpers
three practically identical copies...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/cifs/cifsencrypt.c | 97 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 3 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 107 |
3 files changed, 67 insertions, 140 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 4897dacf8944..6aeb8d4616a4 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -66,45 +66,15 @@ cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server) | |||
66 | return 0; | 66 | return 0; |
67 | } | 67 | } |
68 | 68 | ||
69 | /* | 69 | int __cifs_calc_signature(struct smb_rqst *rqst, |
70 | * Calculate and return the CIFS signature based on the mac key and SMB PDU. | 70 | struct TCP_Server_Info *server, char *signature, |
71 | * The 16 byte signature must be allocated by the caller. Note we only use the | 71 | struct shash_desc *shash) |
72 | * 1st eight bytes and that the smb header signature field on input contains | ||
73 | * the sequence number before this function is called. Also, this function | ||
74 | * should be called with the server->srv_mutex held. | ||
75 | */ | ||
76 | static int cifs_calc_signature(struct smb_rqst *rqst, | ||
77 | struct TCP_Server_Info *server, char *signature) | ||
78 | { | 72 | { |
79 | int i; | 73 | int i; |
80 | int rc; | 74 | int rc; |
81 | struct kvec *iov = rqst->rq_iov; | 75 | struct kvec *iov = rqst->rq_iov; |
82 | int n_vec = rqst->rq_nvec; | 76 | int n_vec = rqst->rq_nvec; |
83 | 77 | ||
84 | if (iov == NULL || signature == NULL || server == NULL) | ||
85 | return -EINVAL; | ||
86 | |||
87 | if (!server->secmech.sdescmd5) { | ||
88 | rc = cifs_crypto_shash_md5_allocate(server); | ||
89 | if (rc) { | ||
90 | cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__); | ||
91 | return -1; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | rc = crypto_shash_init(&server->secmech.sdescmd5->shash); | ||
96 | if (rc) { | ||
97 | cifs_dbg(VFS, "%s: Could not init md5\n", __func__); | ||
98 | return rc; | ||
99 | } | ||
100 | |||
101 | rc = crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
102 | server->session_key.response, server->session_key.len); | ||
103 | if (rc) { | ||
104 | cifs_dbg(VFS, "%s: Could not update with response\n", __func__); | ||
105 | return rc; | ||
106 | } | ||
107 | |||
108 | for (i = 0; i < n_vec; i++) { | 78 | for (i = 0; i < n_vec; i++) { |
109 | if (iov[i].iov_len == 0) | 79 | if (iov[i].iov_len == 0) |
110 | continue; | 80 | continue; |
@@ -117,12 +87,10 @@ static int cifs_calc_signature(struct smb_rqst *rqst, | |||
117 | if (i == 0) { | 87 | if (i == 0) { |
118 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | 88 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ |
119 | break; /* nothing to sign or corrupt header */ | 89 | break; /* nothing to sign or corrupt header */ |
120 | rc = | 90 | rc = crypto_shash_update(shash, |
121 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
122 | iov[i].iov_base + 4, iov[i].iov_len - 4); | 91 | iov[i].iov_base + 4, iov[i].iov_len - 4); |
123 | } else { | 92 | } else { |
124 | rc = | 93 | rc = crypto_shash_update(shash, |
125 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
126 | iov[i].iov_base, iov[i].iov_len); | 94 | iov[i].iov_base, iov[i].iov_len); |
127 | } | 95 | } |
128 | if (rc) { | 96 | if (rc) { |
@@ -134,21 +102,64 @@ static int cifs_calc_signature(struct smb_rqst *rqst, | |||
134 | 102 | ||
135 | /* now hash over the rq_pages array */ | 103 | /* now hash over the rq_pages array */ |
136 | for (i = 0; i < rqst->rq_npages; i++) { | 104 | for (i = 0; i < rqst->rq_npages; i++) { |
137 | struct kvec p_iov; | 105 | void *kaddr = kmap(rqst->rq_pages[i]); |
106 | size_t len = rqst->rq_pagesz; | ||
107 | |||
108 | if (i == rqst->rq_npages - 1) | ||
109 | len = rqst->rq_tailsz; | ||
110 | |||
111 | crypto_shash_update(shash, kaddr, len); | ||
138 | 112 | ||
139 | cifs_rqst_page_to_kvec(rqst, i, &p_iov); | ||
140 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
141 | p_iov.iov_base, p_iov.iov_len); | ||
142 | kunmap(rqst->rq_pages[i]); | 113 | kunmap(rqst->rq_pages[i]); |
143 | } | 114 | } |
144 | 115 | ||
145 | rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); | 116 | rc = crypto_shash_final(shash, signature); |
146 | if (rc) | 117 | if (rc) |
147 | cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); | 118 | cifs_dbg(VFS, "%s: Could not generate hash\n", __func__); |
148 | 119 | ||
149 | return rc; | 120 | return rc; |
150 | } | 121 | } |
151 | 122 | ||
123 | /* | ||
124 | * Calculate and return the CIFS signature based on the mac key and SMB PDU. | ||
125 | * The 16 byte signature must be allocated by the caller. Note we only use the | ||
126 | * 1st eight bytes and that the smb header signature field on input contains | ||
127 | * the sequence number before this function is called. Also, this function | ||
128 | * should be called with the server->srv_mutex held. | ||
129 | */ | ||
130 | static int cifs_calc_signature(struct smb_rqst *rqst, | ||
131 | struct TCP_Server_Info *server, char *signature) | ||
132 | { | ||
133 | int rc; | ||
134 | |||
135 | if (!rqst->rq_iov || !signature || !server) | ||
136 | return -EINVAL; | ||
137 | |||
138 | if (!server->secmech.sdescmd5) { | ||
139 | rc = cifs_crypto_shash_md5_allocate(server); | ||
140 | if (rc) { | ||
141 | cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__); | ||
142 | return -1; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | rc = crypto_shash_init(&server->secmech.sdescmd5->shash); | ||
147 | if (rc) { | ||
148 | cifs_dbg(VFS, "%s: Could not init md5\n", __func__); | ||
149 | return rc; | ||
150 | } | ||
151 | |||
152 | rc = crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
153 | server->session_key.response, server->session_key.len); | ||
154 | if (rc) { | ||
155 | cifs_dbg(VFS, "%s: Could not update with response\n", __func__); | ||
156 | return rc; | ||
157 | } | ||
158 | |||
159 | return __cifs_calc_signature(rqst, server, signature, | ||
160 | &server->secmech.sdescmd5->shash); | ||
161 | } | ||
162 | |||
152 | /* must be called with server->srv_mutex held */ | 163 | /* must be called with server->srv_mutex held */ |
153 | int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server, | 164 | int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server, |
154 | __u32 *pexpected_response_sequence_number) | 165 | __u32 *pexpected_response_sequence_number) |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index eed7ff50faf0..d9b4f444fdf9 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -512,4 +512,7 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, | |||
512 | struct cifs_sb_info *cifs_sb, | 512 | struct cifs_sb_info *cifs_sb, |
513 | const unsigned char *path, char *pbuf, | 513 | const unsigned char *path, char *pbuf, |
514 | unsigned int *pbytes_written); | 514 | unsigned int *pbytes_written); |
515 | int __cifs_calc_signature(struct smb_rqst *rqst, | ||
516 | struct TCP_Server_Info *server, char *signature, | ||
517 | struct shash_desc *shash); | ||
515 | #endif /* _CIFSPROTO_H */ | 518 | #endif /* _CIFSPROTO_H */ |
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 8732a43b1008..bc9a7b634643 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c | |||
@@ -135,11 +135,10 @@ smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server) | |||
135 | int | 135 | int |
136 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | 136 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
137 | { | 137 | { |
138 | int i, rc; | 138 | int rc; |
139 | unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; | 139 | unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; |
140 | unsigned char *sigptr = smb2_signature; | 140 | unsigned char *sigptr = smb2_signature; |
141 | struct kvec *iov = rqst->rq_iov; | 141 | struct kvec *iov = rqst->rq_iov; |
142 | int n_vec = rqst->rq_nvec; | ||
143 | struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; | 142 | struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; |
144 | struct cifs_ses *ses; | 143 | struct cifs_ses *ses; |
145 | 144 | ||
@@ -171,53 +170,11 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |||
171 | return rc; | 170 | return rc; |
172 | } | 171 | } |
173 | 172 | ||
174 | for (i = 0; i < n_vec; i++) { | 173 | rc = __cifs_calc_signature(rqst, server, sigptr, |
175 | if (iov[i].iov_len == 0) | 174 | &server->secmech.sdeschmacsha256->shash); |
176 | continue; | ||
177 | if (iov[i].iov_base == NULL) { | ||
178 | cifs_dbg(VFS, "null iovec entry\n"); | ||
179 | return -EIO; | ||
180 | } | ||
181 | /* | ||
182 | * The first entry includes a length field (which does not get | ||
183 | * signed that occupies the first 4 bytes before the header). | ||
184 | */ | ||
185 | if (i == 0) { | ||
186 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | ||
187 | break; /* nothing to sign or corrupt header */ | ||
188 | rc = | ||
189 | crypto_shash_update( | ||
190 | &server->secmech.sdeschmacsha256->shash, | ||
191 | iov[i].iov_base + 4, iov[i].iov_len - 4); | ||
192 | } else { | ||
193 | rc = | ||
194 | crypto_shash_update( | ||
195 | &server->secmech.sdeschmacsha256->shash, | ||
196 | iov[i].iov_base, iov[i].iov_len); | ||
197 | } | ||
198 | if (rc) { | ||
199 | cifs_dbg(VFS, "%s: Could not update with payload\n", | ||
200 | __func__); | ||
201 | return rc; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | /* now hash over the rq_pages array */ | ||
206 | for (i = 0; i < rqst->rq_npages; i++) { | ||
207 | struct kvec p_iov; | ||
208 | |||
209 | cifs_rqst_page_to_kvec(rqst, i, &p_iov); | ||
210 | crypto_shash_update(&server->secmech.sdeschmacsha256->shash, | ||
211 | p_iov.iov_base, p_iov.iov_len); | ||
212 | kunmap(rqst->rq_pages[i]); | ||
213 | } | ||
214 | |||
215 | rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash, | ||
216 | sigptr); | ||
217 | if (rc) | ||
218 | cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); | ||
219 | 175 | ||
220 | memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); | 176 | if (!rc) |
177 | memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); | ||
221 | 178 | ||
222 | return rc; | 179 | return rc; |
223 | } | 180 | } |
@@ -395,12 +352,10 @@ generate_smb311signingkey(struct cifs_ses *ses) | |||
395 | int | 352 | int |
396 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | 353 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
397 | { | 354 | { |
398 | int i; | ||
399 | int rc = 0; | 355 | int rc = 0; |
400 | unsigned char smb3_signature[SMB2_CMACAES_SIZE]; | 356 | unsigned char smb3_signature[SMB2_CMACAES_SIZE]; |
401 | unsigned char *sigptr = smb3_signature; | 357 | unsigned char *sigptr = smb3_signature; |
402 | struct kvec *iov = rqst->rq_iov; | 358 | struct kvec *iov = rqst->rq_iov; |
403 | int n_vec = rqst->rq_nvec; | ||
404 | struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; | 359 | struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; |
405 | struct cifs_ses *ses; | 360 | struct cifs_ses *ses; |
406 | 361 | ||
@@ -431,54 +386,12 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |||
431 | cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__); | 386 | cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__); |
432 | return rc; | 387 | return rc; |
433 | } | 388 | } |
389 | |||
390 | rc = __cifs_calc_signature(rqst, server, sigptr, | ||
391 | &server->secmech.sdesccmacaes->shash); | ||
434 | 392 | ||
435 | for (i = 0; i < n_vec; i++) { | 393 | if (!rc) |
436 | if (iov[i].iov_len == 0) | 394 | memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); |
437 | continue; | ||
438 | if (iov[i].iov_base == NULL) { | ||
439 | cifs_dbg(VFS, "null iovec entry"); | ||
440 | return -EIO; | ||
441 | } | ||
442 | /* | ||
443 | * The first entry includes a length field (which does not get | ||
444 | * signed that occupies the first 4 bytes before the header). | ||
445 | */ | ||
446 | if (i == 0) { | ||
447 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | ||
448 | break; /* nothing to sign or corrupt header */ | ||
449 | rc = | ||
450 | crypto_shash_update( | ||
451 | &server->secmech.sdesccmacaes->shash, | ||
452 | iov[i].iov_base + 4, iov[i].iov_len - 4); | ||
453 | } else { | ||
454 | rc = | ||
455 | crypto_shash_update( | ||
456 | &server->secmech.sdesccmacaes->shash, | ||
457 | iov[i].iov_base, iov[i].iov_len); | ||
458 | } | ||
459 | if (rc) { | ||
460 | cifs_dbg(VFS, "%s: Couldn't update cmac aes with payload\n", | ||
461 | __func__); | ||
462 | return rc; | ||
463 | } | ||
464 | } | ||
465 | |||
466 | /* now hash over the rq_pages array */ | ||
467 | for (i = 0; i < rqst->rq_npages; i++) { | ||
468 | struct kvec p_iov; | ||
469 | |||
470 | cifs_rqst_page_to_kvec(rqst, i, &p_iov); | ||
471 | crypto_shash_update(&server->secmech.sdesccmacaes->shash, | ||
472 | p_iov.iov_base, p_iov.iov_len); | ||
473 | kunmap(rqst->rq_pages[i]); | ||
474 | } | ||
475 | |||
476 | rc = crypto_shash_final(&server->secmech.sdesccmacaes->shash, | ||
477 | sigptr); | ||
478 | if (rc) | ||
479 | cifs_dbg(VFS, "%s: Could not generate cmac aes\n", __func__); | ||
480 | |||
481 | memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); | ||
482 | 395 | ||
483 | return rc; | 396 | return rc; |
484 | } | 397 | } |