aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2015-11-12 22:46:49 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2016-03-28 14:05:27 -0400
commit16c568efff82e4a6a75d2bd86576e648fad8a7fe (patch)
tree1e002f9f43b5f90f9f6f0fad86cb819e2ddabd24
parent2da62906b1e298695e1bb725927041cd59942c98 (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.c97
-rw-r--r--fs/cifs/cifsproto.h3
-rw-r--r--fs/cifs/smb2transport.c107
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/* 69int __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 */
76static 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 */
130static 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 */
153int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server, 164int 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);
515int __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)
135int 135int
136smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) 136smb2_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)
395int 352int
396smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) 353smb3_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}