diff options
Diffstat (limited to 'fs/cifs/smb2transport.c')
-rw-r--r-- | fs/cifs/smb2transport.c | 148 |
1 files changed, 146 insertions, 2 deletions
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 */ |