xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c (revision 8329232e00f1048795bae53acb230316243aadb5)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 /*
28  * Support for SMB "signing" (message integrity)
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/conf.h>
34 #include <sys/proc.h>
35 #include <sys/fcntl.h>
36 #include <sys/socket.h>
37 #include <sys/md4.h>
38 #include <sys/md5.h>
39 #include <sys/des.h>
40 #include <sys/kmem.h>
41 #include <sys/cmn_err.h>
42 #include <sys/stream.h>
43 #include <sys/strsun.h>
44 #include <sys/sdt.h>
45 
46 #include <netsmb/smb_osdep.h>
47 #include <netsmb/smb.h>
48 #include <netsmb/smb_conn.h>
49 #include <netsmb/smb_subr.h>
50 #include <netsmb/smb_dev.h>
51 #include <netsmb/smb_rq.h>
52 #include <netsmb/smb_signing.h>
53 
54 #ifdef DEBUG
55 /*
56  * Set this to a small number to debug sequence numbers
57  * that seem to get out of step.
58  */
59 int nsmb_signing_fudge = 0;
60 #endif
61 
62 /* Mechanism definitions */
63 static  smb_sign_mech_t smb_mech_md5;
64 
65 void
66 smb_crypto_mech_init(void)
67 {
68 	if (smb_md5_getmech(&smb_mech_md5) != 0)
69 		cmn_err(CE_NOTE, "nsmb can't get md5 mech");
70 }
71 
72 
73 #define	SMBSIGLEN	8	/* SMB signature length */
74 #define	SMBSIGOFF	14	/* SMB signature offset */
75 
76 /*
77  * Compute HMAC-MD5 of packet data, using the stored MAC key.
78  *
79  * See similar code for the server side:
80  * uts/common/fs/smbsrv/smb_signing.c : smb_sign_calc
81  */
82 static int
83 smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
84 	uint32_t seqno, uchar_t *signature)
85 {
86 	uchar_t digest[MD5_DIGEST_LENGTH];
87 	smb_sign_ctx_t ctx = 0;
88 	mblk_t *m = mp;
89 	int size;
90 	int rc;
91 
92 	/*
93 	 * This union is a little bit of trickery to:
94 	 * (1) get the sequence number int aligned, and
95 	 * (2) reduce the number of digest calls, at the
96 	 * cost of a copying 32 bytes instead of 8.
97 	 * Both sides of this union are 2+32 bytes.
98 	 */
99 	union {
100 		struct {
101 			uint8_t skip[2]; /* not used - just alignment */
102 			uint8_t raw[SMB_HDRLEN];  /* header length (32) */
103 		} r;
104 		struct {
105 			uint8_t skip[2]; /* not used - just alignment */
106 			uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
107 			uint32_t sig[2]; /* MAC signature, aligned! */
108 			uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
109 		} s;
110 	} smbhdr;
111 
112 	/* Later: check vcp->sign_mech == NULL */
113 	if (vcp->vc_mackey == NULL)
114 		return (-1);
115 
116 	if ((rc = smb_md5_init(&ctx, &smb_mech_md5)) != 0)
117 		return (rc);
118 
119 	/* Digest the MAC Key */
120 	rc = smb_md5_update(ctx, vcp->vc_mackey, vcp->vc_mackeylen);
121 	if (rc != 0)
122 		return (rc);
123 
124 	ASSERT(m != NULL);
125 	ASSERT(MBLKL(m) >= SMB_HDRLEN);
126 
127 	/*
128 	 * Make an aligned copy of the SMB header,
129 	 * fill in the sequence number, and digest.
130 	 */
131 	size = SMB_HDRLEN;
132 	if (MBLKL(m) < size)
133 		(void) pullupmsg(m, size);
134 	bcopy(m->b_rptr, smbhdr.r.raw, size);
135 	smbhdr.s.sig[0] = htolel(seqno);
136 	smbhdr.s.sig[1] = 0;
137 
138 	rc = smb_md5_update(ctx, &smbhdr.r.raw, size);
139 	if (rc != 0)
140 		return (rc);
141 
142 	/*
143 	 * Digest the rest of the SMB header packet, starting at
144 	 * the data just after the SMB header.
145 	 */
146 	size = MBLKL(m) - SMB_HDRLEN;
147 	rc = smb_md5_update(ctx, m->b_rptr + SMB_HDRLEN, size);
148 	if (rc != 0)
149 		return (rc);
150 	m = m->b_cont;
151 
152 	/* Digest rest of the SMB message. */
153 	while (m != NULL) {
154 		size = MBLKL(m);
155 		if (size > 0) {
156 			rc = smb_md5_update(ctx, m->b_rptr, size);
157 			if (rc != 0)
158 				return (rc);
159 		}
160 		m = m->b_cont;
161 	}
162 	rc = smb_md5_final(ctx, digest);
163 	if (rc != 0)
164 		return (rc);
165 
166 	/*
167 	 * Finally, store the signature.
168 	 * (first 8 bytes of the mac)
169 	 */
170 	if (signature)
171 		bcopy(digest, signature, SMBSIGLEN);
172 
173 	return (0);
174 }
175 
176 /*
177  * Sign a request with HMAC-MD5.
178  */
179 void
180 smb_rq_sign(struct smb_rq *rqp)
181 {
182 	struct smb_vc *vcp = rqp->sr_vc;
183 	mblk_t *mp = rqp->sr_rq.mb_top;
184 	uint8_t *sigloc;
185 	int status;
186 
187 	/*
188 	 * Our mblk allocation ensures this,
189 	 * but just in case...
190 	 */
191 	if (MBLKL(mp) < SMB_HDRLEN) {
192 		if (!pullupmsg(mp, SMB_HDRLEN))
193 			return;
194 	}
195 	sigloc = mp->b_rptr + SMBSIGOFF;
196 
197 	if (vcp->vc_mackey == NULL) {
198 		/*
199 		 * Signing is required, but we have no key yet
200 		 * fill in with the magic fake signing value.
201 		 * This happens with SPNEGO, NTLMSSP, ...
202 		 */
203 		bcopy("BSRSPLY", sigloc, 8);
204 		return;
205 	}
206 
207 	/*
208 	 * This will compute the MAC and store it
209 	 * directly into the message at sigloc.
210 	 */
211 	status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
212 	if (status != 0) {
213 		SMBSDEBUG("Crypto error %d", status);
214 		bzero(sigloc, SMBSIGLEN);
215 	}
216 }
217 
218 /*
219  * Verify reply signature.
220  */
221 int
222 smb_rq_verify(struct smb_rq *rqp)
223 {
224 	struct smb_vc *vcp = rqp->sr_vc;
225 	mblk_t *mp = rqp->sr_rp.md_top;
226 	uint8_t sigbuf[SMBSIGLEN];
227 	uint8_t *sigloc;
228 	int fudge, rsn, status;
229 
230 	/*
231 	 * Note vc_mackey and vc_mackeylen gets filled in by
232 	 * smb_usr_iod_work as the connection comes in.
233 	 */
234 	if (vcp->vc_mackey == NULL) {
235 		SMBSDEBUG("no mac key\n");
236 		return (0);
237 	}
238 
239 	/*
240 	 * Let caller deal with empty reply or short messages by
241 	 * returning zero.  Caller will fail later, in parsing.
242 	 */
243 	if (mp == NULL) {
244 		SMBSDEBUG("empty reply\n");
245 		return (0);
246 	}
247 	if (MBLKL(mp) < SMB_HDRLEN) {
248 		if (!pullupmsg(mp, SMB_HDRLEN))
249 			return (0);
250 	}
251 	sigloc = mp->b_rptr + SMBSIGOFF;
252 
253 	/*
254 	 * Compute the expected signature in sigbuf.
255 	 */
256 	rsn = rqp->sr_rseqno;
257 	status = smb_compute_MAC(vcp, mp, rsn, sigbuf);
258 	if (status != 0) {
259 		SMBSDEBUG("Crypto error %d", status);
260 		/*
261 		 * If we can't compute a MAC, then there's
262 		 * no point trying other seqno values.
263 		 */
264 		return (EBADRPC);
265 	}
266 
267 	/*
268 	 * Compare the computed signature with the
269 	 * one found in the message (at sigloc)
270 	 */
271 	if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
272 		return (0);
273 
274 	SMBERROR("BAD signature, Server=%s MID=0x%x Seq=%d\n",
275 	    vcp->vc_srvname, rqp->sr_mid, rsn);
276 
277 #ifdef DEBUG
278 	/*
279 	 * For diag purposes, we check whether the client/server idea
280 	 * of the sequence # has gotten a bit out of sync.
281 	 */
282 	for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
283 		(void) smb_compute_MAC(vcp, mp, rsn + fudge, sigbuf);
284 		if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
285 			break;
286 		(void) smb_compute_MAC(vcp, mp, rsn - fudge, sigbuf);
287 		if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
288 			fudge = -fudge;
289 			break;
290 		}
291 	}
292 	if (fudge <= nsmb_signing_fudge) {
293 		SMBERROR("MID=0x%x, Seq=%d, but %d would have worked\n",
294 		    rqp->sr_mid, rsn, rsn + fudge);
295 	}
296 #endif
297 	return (EBADRPC);
298 }
299