xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb2_sign.c (revision b1e2e3fb17324e9ddf43db264a0c64da7756d9e6)
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 2018 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 /*
28  * Support for SMB2 "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/smb2.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 #define	SMB2_SIG_OFF	48
55 #define	SMB2_SIG_LEN	16
56 
57 /*
58  * smb2_sign_init
59  *
60  * Get the mechanism info and initilize SMB2 signing.
61  */
62 int
63 smb2_sign_init(smb_vc_t *vcp)
64 {
65 	uint_t copysize;
66 	int rc;
67 
68 	ASSERT(vcp->vc_ssnkey != NULL);
69 	ASSERT(vcp->vc_mackey == NULL);
70 
71 	rc = smb2_hmac_getmech(&vcp->vc_signmech);
72 	if (rc != 0) {
73 		cmn_err(CE_NOTE, "smb2 can't get signing mechanism");
74 		return (EAUTH);
75 	}
76 
77 	/*
78 	 * Convert the session key to the MAC key.
79 	 *
80 	 * For SMB2, the signing key is just the first 16 bytes
81 	 * of the session key (truncated or padded with zeros).
82 	 * [MS-SMB2] 3.2.5.3.1
83 	 *
84 	 * SMB3 would do KDF here.
85 	 */
86 	vcp->vc_mackeylen = SMB2_SIG_LEN;
87 	vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
88 	copysize = vcp->vc_ssnkeylen;
89 	if (copysize > vcp->vc_mackeylen)
90 		copysize = vcp->vc_mackeylen;
91 	bcopy(vcp->vc_ssnkey, vcp->vc_mackey, copysize);
92 
93 	return (0);
94 }
95 
96 
97 /*
98  * Compute MAC signature of packet data, using the stored MAC key.
99  *
100  * The signature is in the last 16 bytes of the SMB2 header.
101  * The signature algorighm is to compute HMAC SHA256 over the
102  * entire command, with the signature field set to zeros.
103  *
104  * See similar code for the server side:
105  * uts/common/fs/smbsrv/smb2_signing.c : smb2_sign_calc
106  */
107 static int
108 smb2_compute_MAC(struct smb_vc *vcp, mblk_t *mp, uchar_t *signature)
109 {
110 	uint8_t tmp_hdr[SMB2_HDR_SIZE];
111 	smb_sign_ctx_t ctx = 0;
112 	mblk_t *m = mp;
113 	int size;
114 	int rc;
115 
116 	if (vcp->vc_mackey == NULL)
117 		return (-1);
118 
119 	rc = smb2_hmac_init(&ctx, &vcp->vc_signmech,
120 	    vcp->vc_mackey, vcp->vc_mackeylen);
121 	if (rc != 0)
122 		return (rc);
123 
124 	/* Our caller should ensure mp has a contiguous header */
125 	ASSERT(m != NULL);
126 	ASSERT(MBLKL(m) >= SMB2_HDRLEN);
127 
128 	/*
129 	 * Copy of the SMB2 header, zero out the signature, and digest.
130 	 */
131 	size = SMB2_HDRLEN;
132 	bcopy(m->b_rptr, tmp_hdr, size);
133 	bzero(tmp_hdr + SMB2_SIG_OFF, SMB2_SIG_LEN);
134 	rc = smb2_hmac_update(ctx, tmp_hdr, size);
135 	if (rc != 0)
136 		return (rc);
137 
138 	/*
139 	 * Digest the rest of the SMB2 header packet, starting at
140 	 * the data just after the SMB2 header.
141 	 */
142 	size = MBLKL(m) - SMB2_HDRLEN;
143 	rc = smb2_hmac_update(ctx, m->b_rptr + SMB2_HDRLEN, size);
144 	if (rc != 0)
145 		return (rc);
146 	m = m->b_cont;
147 
148 	/* Digest rest of the SMB2 message. */
149 	while (m != NULL) {
150 		size = MBLKL(m);
151 		if (size > 0) {
152 			rc = smb2_hmac_update(ctx, m->b_rptr, size);
153 			if (rc != 0)
154 				return (rc);
155 		}
156 		m = m->b_cont;
157 	}
158 	rc = smb2_hmac_final(ctx, signature);
159 
160 	return (rc);
161 }
162 
163 /*
164  * Sign a request with HMAC-MD5.
165  */
166 void
167 smb2_rq_sign(struct smb_rq *rqp)
168 {
169 	struct smb_vc *vcp = rqp->sr_vc;
170 	mblk_t *mp = rqp->sr_rq.mb_top;
171 	uint8_t *sigloc;
172 	int rc;
173 
174 	/*
175 	 * smb_rq_new() ensures this,
176 	 * but just in case..
177 	 */
178 	ASSERT(MBLKL(mp) >= SMB2_HDRLEN);
179 	sigloc = mp->b_rptr + SMB2_SIG_OFF;
180 
181 	if (vcp->vc_mackey == NULL)
182 		return;
183 
184 	/*
185 	 * This will compute the MAC and store it
186 	 * directly into the message at sigloc.
187 	 */
188 	rc = smb2_compute_MAC(vcp, mp, sigloc);
189 	if (rc != 0) {
190 		SMBSDEBUG("Crypto error %d", rc);
191 		bzero(sigloc, SMB2_SIG_LEN);
192 	}
193 }
194 
195 /*
196  * Verify reply signature.
197  */
198 int
199 smb2_rq_verify(struct smb_rq *rqp)
200 {
201 	struct smb_vc *vcp = rqp->sr_vc;
202 	mblk_t *mp = rqp->sr_rp.md_top;
203 	uint8_t sigbuf[SMB2_SIG_LEN];
204 	uint8_t *sigloc;
205 	int rc;
206 
207 	/*
208 	 * Note vc_mackey and vc_mackeylen gets filled in by
209 	 * smb_usr_iod_work as the connection comes in.
210 	 */
211 	if (vcp->vc_mackey == NULL) {
212 		SMBSDEBUG("no mac key\n");
213 		return (0);
214 	}
215 
216 	/*
217 	 * Let caller deal with empty reply or short messages by
218 	 * returning zero.  Caller will fail later, in parsing.
219 	 */
220 	if (mp == NULL) {
221 		SMBSDEBUG("empty reply\n");
222 		return (0);
223 	}
224 
225 	/* smb2_iod_process ensures this */
226 	ASSERT(MBLKL(mp) >= SMB2_HDRLEN);
227 	sigloc = mp->b_rptr + SMB2_SIG_OFF;
228 
229 	/*
230 	 * Compute the expected signature in sigbuf.
231 	 */
232 	rc = smb2_compute_MAC(vcp, mp, sigbuf);
233 	if (rc != 0) {
234 		SMBSDEBUG("Crypto error %d", rc);
235 		/*
236 		 * If we can't compute a MAC, then there's
237 		 * no point trying other seqno values.
238 		 */
239 		return (EBADRPC);
240 	}
241 
242 	/*
243 	 * Compare the computed signature with the
244 	 * one found in the message (at sigloc)
245 	 */
246 	if (bcmp(sigbuf, sigloc, SMB2_SIG_LEN) == 0)
247 		return (0);
248 
249 	SMBERROR("BAD signature, Server=%s MID=0x%llx\n",
250 	    vcp->vc_srvname, (long long)rqp->sr2_messageid);
251 
252 	return (EBADRPC);
253 }
254