Print this page
NEX-19225 SMB client 2.1 hits redzone panic
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
+++ new/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
24 25 */
25 26
26 27 /*
27 28 * Support for SMB "signing" (message integrity)
28 29 */
29 30
30 31 #include <sys/param.h>
31 32 #include <sys/systm.h>
32 33 #include <sys/conf.h>
33 34 #include <sys/proc.h>
34 35 #include <sys/fcntl.h>
35 36 #include <sys/socket.h>
36 37 #include <sys/md4.h>
37 38 #include <sys/md5.h>
38 39 #include <sys/des.h>
39 40 #include <sys/kmem.h>
40 -#include <sys/crypto/api.h>
41 -#include <sys/crypto/common.h>
42 41 #include <sys/cmn_err.h>
43 42 #include <sys/stream.h>
44 43 #include <sys/strsun.h>
45 44 #include <sys/sdt.h>
46 45
47 46 #include <netsmb/smb_osdep.h>
48 47 #include <netsmb/smb.h>
49 48 #include <netsmb/smb_conn.h>
50 49 #include <netsmb/smb_subr.h>
51 50 #include <netsmb/smb_dev.h>
52 51 #include <netsmb/smb_rq.h>
52 +#include <netsmb/smb_signing.h>
53 53
54 54 #ifdef DEBUG
55 55 /*
56 56 * Set this to a small number to debug sequence numbers
57 57 * that seem to get out of step.
58 58 */
59 59 int nsmb_signing_fudge = 0;
60 60 #endif
61 61
62 -/* Mechanism definitions */
63 -static crypto_mechanism_t crypto_mech_md5 = { CRYPTO_MECH_INVALID };
64 -
65 -void
66 -smb_crypto_mech_init(void)
62 +/*
63 + * This is called just after session setup completes,
64 + * at the top of smb_iod_vc_work(). Initialize signing.
65 + */
66 +int
67 +smb_sign_init(smb_vc_t *vcp)
67 68 {
68 - crypto_mech_md5.cm_type = crypto_mech2id(SUN_CKM_MD5);
69 -}
69 + int rc;
70 70
71 + ASSERT(vcp->vc_ssnkey != NULL);
72 + ASSERT(vcp->vc_mackey == NULL);
71 73
74 + rc = smb_md5_getmech(&vcp->vc_signmech);
75 + if (rc != 0) {
76 + cmn_err(CE_NOTE, "smb can't get signing mechanism");
77 + return (EAUTH);
78 + }
72 79
80 + /*
81 + * Convert the session key to the MAC key.
82 + * SMB1 uses the whole session key.
83 + */
84 + vcp->vc_mackeylen = vcp->vc_ssnkeylen;
85 + vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
86 + bcopy(vcp->vc_ssnkey, vcp->vc_mackey, vcp->vc_mackeylen);
87 +
88 + /* The initial sequence number is two. */
89 + vcp->vc_next_seq = 2;
90 +
91 + return (0);
92 +}
93 +
94 +
73 95 #define SMBSIGLEN 8 /* SMB signature length */
74 96 #define SMBSIGOFF 14 /* SMB signature offset */
75 97
76 98 /*
77 99 * Compute HMAC-MD5 of packet data, using the stored MAC key.
78 100 *
79 101 * See similar code for the server side:
80 102 * uts/common/fs/smbsrv/smb_signing.c : smb_sign_calc
81 103 */
82 104 static int
83 105 smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
84 106 uint32_t seqno, uchar_t *signature)
85 107 {
86 - crypto_context_t crypto_ctx;
87 - crypto_data_t key;
88 - crypto_data_t data;
89 - crypto_data_t digest;
90 - uchar_t mac[16];
91 - int status;
108 + uchar_t digest[MD5_DIGEST_LENGTH];
109 + smb_sign_ctx_t ctx = 0;
110 + mblk_t *m = mp;
111 + int size;
112 + int rc;
113 +
92 114 /*
93 115 * This union is a little bit of trickery to:
94 116 * (1) get the sequence number int aligned, and
95 117 * (2) reduce the number of digest calls, at the
96 118 * cost of a copying 32 bytes instead of 8.
97 119 * Both sides of this union are 2+32 bytes.
98 120 */
99 121 union {
100 122 struct {
101 123 uint8_t skip[2]; /* not used - just alignment */
102 124 uint8_t raw[SMB_HDRLEN]; /* header length (32) */
103 125 } r;
104 126 struct {
105 127 uint8_t skip[2]; /* not used - just alignment */
106 128 uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
107 129 uint32_t sig[2]; /* MAC signature, aligned! */
108 130 uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
109 131 } s;
110 132 } smbhdr;
111 133
112 - ASSERT(mp != NULL);
113 - ASSERT(MBLKL(mp) >= SMB_HDRLEN);
114 - ASSERT(vcp->vc_mackey != NULL);
134 + if (vcp->vc_mackey == NULL)
135 + return (-1);
115 136
137 + if ((rc = smb_md5_init(&ctx, &vcp->vc_signmech)) != 0)
138 + return (rc);
139 +
140 + /* Digest the MAC Key */
141 + rc = smb_md5_update(ctx, vcp->vc_mackey, vcp->vc_mackeylen);
142 + if (rc != 0)
143 + return (rc);
144 +
145 + /* Our caller should ensure mp has a contiguous header */
146 + ASSERT(m != NULL);
147 + ASSERT(MBLKL(m) >= SMB_HDRLEN);
148 +
116 149 /*
117 - * Make an aligned copy of the SMB header
118 - * and fill in the sequence number.
150 + * Make an aligned copy of the SMB header,
151 + * fill in the sequence number, and digest.
119 152 */
120 - bcopy(mp->b_rptr, smbhdr.r.raw, SMB_HDRLEN);
153 + size = SMB_HDRLEN;
154 + bcopy(m->b_rptr, smbhdr.r.raw, size);
121 155 smbhdr.s.sig[0] = htolel(seqno);
122 156 smbhdr.s.sig[1] = 0;
123 157
158 + rc = smb_md5_update(ctx, &smbhdr.r.raw, size);
159 + if (rc != 0)
160 + return (rc);
161 +
124 162 /*
125 - * Compute the MAC: MD5(concat(Key, message))
163 + * Digest the rest of the SMB header packet, starting at
164 + * the data just after the SMB header.
126 165 */
127 - if (crypto_mech_md5.cm_type == CRYPTO_MECH_INVALID) {
128 - SMBSDEBUG("crypto_mech_md5 invalid\n");
129 - return (CRYPTO_MECHANISM_INVALID);
130 - }
131 - status = crypto_digest_init(&crypto_mech_md5, &crypto_ctx, 0);
132 - if (status != CRYPTO_SUCCESS)
133 - return (status);
166 + size = MBLKL(m) - SMB_HDRLEN;
167 + rc = smb_md5_update(ctx, m->b_rptr + SMB_HDRLEN, size);
168 + if (rc != 0)
169 + return (rc);
170 + m = m->b_cont;
134 171
135 - /* Digest the MAC Key */
136 - key.cd_format = CRYPTO_DATA_RAW;
137 - key.cd_offset = 0;
138 - key.cd_length = vcp->vc_mackeylen;
139 - key.cd_miscdata = 0;
140 - key.cd_raw.iov_base = (char *)vcp->vc_mackey;
141 - key.cd_raw.iov_len = vcp->vc_mackeylen;
142 - status = crypto_digest_update(crypto_ctx, &key, 0);
143 - if (status != CRYPTO_SUCCESS)
144 - return (status);
145 -
146 - /* Digest the (copied) SMB header */
147 - data.cd_format = CRYPTO_DATA_RAW;
148 - data.cd_offset = 0;
149 - data.cd_length = SMB_HDRLEN;
150 - data.cd_miscdata = 0;
151 - data.cd_raw.iov_base = (char *)smbhdr.r.raw;
152 - data.cd_raw.iov_len = SMB_HDRLEN;
153 - status = crypto_digest_update(crypto_ctx, &data, 0);
154 - if (status != CRYPTO_SUCCESS)
155 - return (status);
156 -
157 172 /* Digest rest of the SMB message. */
158 - data.cd_format = CRYPTO_DATA_MBLK;
159 - data.cd_offset = SMB_HDRLEN;
160 - data.cd_length = msgdsize(mp) - SMB_HDRLEN;
161 - data.cd_miscdata = 0;
162 - data.cd_mp = mp;
163 - status = crypto_digest_update(crypto_ctx, &data, 0);
164 - if (status != CRYPTO_SUCCESS)
165 - return (status);
173 + while (m != NULL) {
174 + size = MBLKL(m);
175 + if (size > 0) {
176 + rc = smb_md5_update(ctx, m->b_rptr, size);
177 + if (rc != 0)
178 + return (rc);
179 + }
180 + m = m->b_cont;
181 + }
182 + rc = smb_md5_final(ctx, digest);
183 + if (rc != 0)
184 + return (rc);
166 185
167 - /* Final */
168 - digest.cd_format = CRYPTO_DATA_RAW;
169 - digest.cd_offset = 0;
170 - digest.cd_length = sizeof (mac);
171 - digest.cd_miscdata = 0;
172 - digest.cd_raw.iov_base = (char *)mac;
173 - digest.cd_raw.iov_len = sizeof (mac);
174 - status = crypto_digest_final(crypto_ctx, &digest, 0);
175 - if (status != CRYPTO_SUCCESS)
176 - return (status);
177 -
178 186 /*
179 187 * Finally, store the signature.
180 188 * (first 8 bytes of the mac)
181 189 */
182 - if (signature)
183 - bcopy(mac, signature, SMBSIGLEN);
190 + if (signature != NULL)
191 + bcopy(digest, signature, SMBSIGLEN);
184 192
185 193 return (0);
186 194 }
187 195
188 196 /*
189 197 * Sign a request with HMAC-MD5.
190 198 */
191 199 void
192 200 smb_rq_sign(struct smb_rq *rqp)
193 201 {
194 202 struct smb_vc *vcp = rqp->sr_vc;
195 203 mblk_t *mp = rqp->sr_rq.mb_top;
196 204 uint8_t *sigloc;
197 205 int status;
198 206
199 207 /*
200 - * Our mblk allocation ensures this,
201 - * but just in case...
208 + * smb_rq_new() ensures this,
209 + * but just in case..
202 210 */
203 - if (MBLKL(mp) < SMB_HDRLEN) {
204 - if (!pullupmsg(mp, SMB_HDRLEN))
205 - return;
206 - }
211 + ASSERT(MBLKL(mp) >= SMB_HDRLEN);
207 212 sigloc = mp->b_rptr + SMBSIGOFF;
208 213
209 214 if (vcp->vc_mackey == NULL) {
210 215 /*
211 216 * Signing is required, but we have no key yet
212 217 * fill in with the magic fake signing value.
213 218 * This happens with SPNEGO, NTLMSSP, ...
214 219 */
215 220 bcopy("BSRSPLY", sigloc, 8);
216 221 return;
217 222 }
218 223
219 224 /*
220 225 * This will compute the MAC and store it
221 226 * directly into the message at sigloc.
222 227 */
223 228 status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
224 - if (status != CRYPTO_SUCCESS) {
229 + if (status != 0) {
225 230 SMBSDEBUG("Crypto error %d", status);
226 231 bzero(sigloc, SMBSIGLEN);
227 232 }
228 233 }
229 234
230 235 /*
231 236 * Verify reply signature.
232 237 */
233 238 int
234 239 smb_rq_verify(struct smb_rq *rqp)
235 240 {
236 241 struct smb_vc *vcp = rqp->sr_vc;
237 242 mblk_t *mp = rqp->sr_rp.md_top;
238 243 uint8_t sigbuf[SMBSIGLEN];
239 244 uint8_t *sigloc;
240 245 int fudge, rsn, status;
241 246
242 247 /*
243 248 * Note vc_mackey and vc_mackeylen gets filled in by
244 249 * smb_usr_iod_work as the connection comes in.
245 250 */
246 251 if (vcp->vc_mackey == NULL) {
247 252 SMBSDEBUG("no mac key\n");
248 253 return (0);
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
249 254 }
250 255
251 256 /*
252 257 * Let caller deal with empty reply or short messages by
253 258 * returning zero. Caller will fail later, in parsing.
254 259 */
255 260 if (mp == NULL) {
256 261 SMBSDEBUG("empty reply\n");
257 262 return (0);
258 263 }
259 - if (MBLKL(mp) < SMB_HDRLEN) {
260 - if (!pullupmsg(mp, SMB_HDRLEN))
261 - return (0);
262 - }
264 +
265 + ASSERT(MBLKL(mp) >= SMB_HDRLEN);
263 266 sigloc = mp->b_rptr + SMBSIGOFF;
264 267
265 268 /*
266 269 * Compute the expected signature in sigbuf.
267 270 */
268 271 rsn = rqp->sr_rseqno;
269 272 status = smb_compute_MAC(vcp, mp, rsn, sigbuf);
270 - if (status != CRYPTO_SUCCESS) {
273 + if (status != 0) {
271 274 SMBSDEBUG("Crypto error %d", status);
272 275 /*
273 276 * If we can't compute a MAC, then there's
274 277 * no point trying other seqno values.
275 278 */
276 279 return (EBADRPC);
277 280 }
278 281
279 282 /*
280 283 * Compare the computed signature with the
281 284 * one found in the message (at sigloc)
282 285 */
283 286 if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
284 287 return (0);
285 288
286 289 SMBERROR("BAD signature, Server=%s MID=0x%x Seq=%d\n",
287 290 vcp->vc_srvname, rqp->sr_mid, rsn);
288 291
289 292 #ifdef DEBUG
290 293 /*
291 294 * For diag purposes, we check whether the client/server idea
292 295 * of the sequence # has gotten a bit out of sync.
293 296 */
294 297 for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
295 298 (void) smb_compute_MAC(vcp, mp, rsn + fudge, sigbuf);
296 299 if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
297 300 break;
298 301 (void) smb_compute_MAC(vcp, mp, rsn - fudge, sigbuf);
299 302 if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
300 303 fudge = -fudge;
301 304 break;
302 305 }
303 306 }
304 307 if (fudge <= nsmb_signing_fudge) {
305 308 SMBERROR("MID=0x%x, Seq=%d, but %d would have worked\n",
306 309 rqp->sr_mid, rsn, rsn + fudge);
307 310 }
308 311 #endif
309 312 return (EBADRPC);
310 313 }
|
↓ open down ↓ |
30 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX