aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2transport.c
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-09-18 19:20:30 -0400
committerSteve French <smfrench@gmail.com>2012-09-24 22:46:28 -0400
commit3c1bf7e48e9e463b65b1b90da4500a93dd2b27a7 (patch)
treec16caed7a01a5b1438b5acd8aa45929889da10ad /fs/cifs/smb2transport.c
parent009d344398bb3e844b31eb9e6a7860748c6f6dd3 (diff)
CIFS: Enable signing in SMB2
Use hmac-sha256 and rather than hmac-md5 that is used for CIFS/SMB. Signature field in SMB2 header is 16 bytes instead of 8 bytes. Automatically enable signing by client when requested by the server when signing ability is available to the client. Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Signed-off-by: Sachin Prabhu <sprabhu@redhat.com> Signed-off-by: Pavel Shilovsky <piastryyy@gmail.com> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/smb2transport.c')
-rw-r--r--fs/cifs/smb2transport.c165
1 files changed, 156 insertions, 9 deletions
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 31f5d420b3ea..66479f252ae5 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -36,6 +36,149 @@
36#include "smb2proto.h" 36#include "smb2proto.h"
37#include "cifs_debug.h" 37#include "cifs_debug.h"
38#include "smb2status.h" 38#include "smb2status.h"
39#include "smb2glob.h"
40
41static int
42smb2_calc_signature2(const struct kvec *iov, int n_vec,
43 struct TCP_Server_Info *server)
44{
45 int i, rc;
46 unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
47 unsigned char *sigptr = smb2_signature;
48 struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
49
50 memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
51 memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
52
53 rc = crypto_shash_setkey(server->secmech.hmacsha256,
54 server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
55 if (rc) {
56 cERROR(1, "%s: Could not update with response\n", __func__);
57 return rc;
58 }
59
60 rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
61 if (rc) {
62 cERROR(1, "%s: Could not init md5\n", __func__);
63 return rc;
64 }
65
66 for (i = 0; i < n_vec; i++) {
67 if (iov[i].iov_len == 0)
68 continue;
69 if (iov[i].iov_base == NULL) {
70 cERROR(1, "null iovec entry");
71 return -EIO;
72 }
73 /*
74 * The first entry includes a length field (which does not get
75 * signed that occupies the first 4 bytes before the header).
76 */
77 if (i == 0) {
78 if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
79 break; /* nothing to sign or corrupt header */
80 rc =
81 crypto_shash_update(
82 &server->secmech.sdeschmacsha256->shash,
83 iov[i].iov_base + 4, iov[i].iov_len - 4);
84 } else {
85 rc =
86 crypto_shash_update(
87 &server->secmech.sdeschmacsha256->shash,
88 iov[i].iov_base, iov[i].iov_len);
89 }
90 if (rc) {
91 cERROR(1, "%s: Could not update with payload\n",
92 __func__);
93 return rc;
94 }
95 }
96
97 rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
98 sigptr);
99 if (rc)
100 cERROR(1, "%s: Could not generate sha256 hash\n", __func__);
101
102 memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
103
104 return rc;
105}
106
107/* must be called with server->srv_mutex held */
108static int
109smb2_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server)
110{
111 int rc = 0;
112 struct smb2_hdr *smb2_pdu = iov[0].iov_base;
113
114 if (!(smb2_pdu->Flags & SMB2_FLAGS_SIGNED) ||
115 server->tcpStatus == CifsNeedNegotiate)
116 return rc;
117
118 if (!server->session_estab) {
119 strncpy(smb2_pdu->Signature, "BSRSPYL", 8);
120 return rc;
121 }
122
123 rc = smb2_calc_signature2(iov, n_vec, server);
124
125 return rc;
126}
127
128int
129smb2_verify_signature2(struct kvec *iov, unsigned int n_vec,
130 struct TCP_Server_Info *server)
131{
132 unsigned int rc;
133 char server_response_sig[16];
134 struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
135
136 if ((smb2_pdu->Command == SMB2_NEGOTIATE) ||
137 (smb2_pdu->Command == SMB2_OPLOCK_BREAK) ||
138 (!server->session_estab))
139 return 0;
140
141 /*
142 * BB what if signatures are supposed to be on for session but
143 * server does not send one? BB
144 */
145
146 /* Do not need to verify session setups with signature "BSRSPYL " */
147 if (memcmp(smb2_pdu->Signature, "BSRSPYL ", 8) == 0)
148 cFYI(1, "dummy signature received for smb command 0x%x",
149 smb2_pdu->Command);
150
151 /*
152 * Save off the origiginal signature so we can modify the smb and check
153 * our calculated signature against what the server sent.
154 */
155 memcpy(server_response_sig, smb2_pdu->Signature, SMB2_SIGNATURE_SIZE);
156
157 memset(smb2_pdu->Signature, 0, SMB2_SIGNATURE_SIZE);
158
159 mutex_lock(&server->srv_mutex);
160 rc = smb2_calc_signature2(iov, n_vec, server);
161 mutex_unlock(&server->srv_mutex);
162
163 if (rc)
164 return rc;
165
166 if (memcmp(server_response_sig, smb2_pdu->Signature,
167 SMB2_SIGNATURE_SIZE))
168 return -EACCES;
169 else
170 return 0;
171}
172
173static int
174smb2_verify_signature(struct smb2_hdr *smb2_pdu, struct TCP_Server_Info *server)
175{
176 struct kvec iov;
177
178 iov.iov_base = (char *)smb2_pdu;
179 iov.iov_len = get_rfc1002_length(smb2_pdu) + 4;
180 return smb2_verify_signature2(&iov, 1, server);
181}
39 182
40/* 183/*
41 * Set message id for the request. Should be called after wait_for_free_request 184 * Set message id for the request. Should be called after wait_for_free_request
@@ -118,12 +261,15 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
118 261
119 dump_smb(mid->resp_buf, min_t(u32, 80, len)); 262 dump_smb(mid->resp_buf, min_t(u32, 80, len));
120 /* convert the length into a more usable form */ 263 /* convert the length into a more usable form */
121 /* BB - uncomment with SMB2 signing implementation */ 264 if ((len > 24) &&
122 /* if ((len > 24) &&
123 (server->sec_mode & (SECMODE_SIGN_REQUIRED|SECMODE_SIGN_ENABLED))) { 265 (server->sec_mode & (SECMODE_SIGN_REQUIRED|SECMODE_SIGN_ENABLED))) {
124 if (smb2_verify_signature(mid->resp_buf, server)) 266 int rc;
125 cERROR(1, "Unexpected SMB signature"); 267
126 } */ 268 rc = smb2_verify_signature(mid->resp_buf, server);
269 if (rc)
270 cERROR(1, "SMB signature verification returned error = "
271 "%d", rc);
272 }
127 273
128 return map_smb2_to_linux_error(mid->resp_buf, log_error); 274 return map_smb2_to_linux_error(mid->resp_buf, log_error);
129} 275}
@@ -141,9 +287,9 @@ smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
141 rc = smb2_get_mid_entry(ses, hdr, &mid); 287 rc = smb2_get_mid_entry(ses, hdr, &mid);
142 if (rc) 288 if (rc)
143 return rc; 289 return rc;
144 /* rc = smb2_sign_smb2(iov, nvec, ses->server); 290 rc = smb2_sign_smb2(iov, nvec, ses->server);
145 if (rc) 291 if (rc)
146 delete_mid(mid); */ 292 cifs_delete_mid(mid);
147 *ret_mid = mid; 293 *ret_mid = mid;
148 return rc; 294 return rc;
149} 295}
@@ -162,11 +308,12 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
162 if (mid == NULL) 308 if (mid == NULL)
163 return -ENOMEM; 309 return -ENOMEM;
164 310
165 /* rc = smb2_sign_smb2(iov, nvec, server); 311 rc = smb2_sign_smb2(iov, nvec, server);
166 if (rc) { 312 if (rc) {
167 DeleteMidQEntry(mid); 313 DeleteMidQEntry(mid);
168 return rc; 314 return rc;
169 }*/ 315 }
316
170 *ret_mid = mid; 317 *ret_mid = mid;
171 return rc; 318 return rc;
172} 319}