1613a2f6bSGordon Ross /*
2613a2f6bSGordon Ross * CDDL HEADER START
3613a2f6bSGordon Ross *
4613a2f6bSGordon Ross * The contents of this file are subject to the terms of the
5613a2f6bSGordon Ross * Common Development and Distribution License (the "License").
6613a2f6bSGordon Ross * You may not use this file except in compliance with the License.
7613a2f6bSGordon Ross *
8613a2f6bSGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9613a2f6bSGordon Ross * or http://www.opensolaris.org/os/licensing.
10613a2f6bSGordon Ross * See the License for the specific language governing permissions
11613a2f6bSGordon Ross * and limitations under the License.
12613a2f6bSGordon Ross *
13613a2f6bSGordon Ross * When distributing Covered Code, include this CDDL HEADER in each
14613a2f6bSGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15613a2f6bSGordon Ross * If applicable, add the following below this CDDL HEADER, with the
16613a2f6bSGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
17613a2f6bSGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
18613a2f6bSGordon Ross *
19613a2f6bSGordon Ross * CDDL HEADER END
20613a2f6bSGordon Ross */
21613a2f6bSGordon Ross
22613a2f6bSGordon Ross /*
23a547be5dSGordon Ross * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2440c0e231SGordon Ross * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
25*48e11a6eSGordon Ross * Copyright 2024 RackTop Systems, Inc.
26613a2f6bSGordon Ross */
27613a2f6bSGordon Ross
28613a2f6bSGordon Ross /*
29613a2f6bSGordon Ross * Support for SMB "signing" (message integrity)
30613a2f6bSGordon Ross */
31613a2f6bSGordon Ross
32613a2f6bSGordon Ross #include <sys/param.h>
33613a2f6bSGordon Ross #include <sys/systm.h>
34613a2f6bSGordon Ross #include <sys/conf.h>
35613a2f6bSGordon Ross #include <sys/proc.h>
36613a2f6bSGordon Ross #include <sys/fcntl.h>
37613a2f6bSGordon Ross #include <sys/socket.h>
38613a2f6bSGordon Ross #include <sys/md4.h>
39613a2f6bSGordon Ross #include <sys/md5.h>
40613a2f6bSGordon Ross #include <sys/des.h>
41613a2f6bSGordon Ross #include <sys/kmem.h>
42613a2f6bSGordon Ross #include <sys/cmn_err.h>
43613a2f6bSGordon Ross #include <sys/stream.h>
44613a2f6bSGordon Ross #include <sys/strsun.h>
45613a2f6bSGordon Ross #include <sys/sdt.h>
46613a2f6bSGordon Ross
47*48e11a6eSGordon Ross #include <netsmb/nsmb_kcrypt.h>
48*48e11a6eSGordon Ross
49613a2f6bSGordon Ross #include <netsmb/smb_osdep.h>
50613a2f6bSGordon Ross #include <netsmb/smb.h>
51613a2f6bSGordon Ross #include <netsmb/smb_conn.h>
52613a2f6bSGordon Ross #include <netsmb/smb_subr.h>
53613a2f6bSGordon Ross #include <netsmb/smb_dev.h>
54613a2f6bSGordon Ross #include <netsmb/smb_rq.h>
55613a2f6bSGordon Ross
56613a2f6bSGordon Ross #ifdef DEBUG
57613a2f6bSGordon Ross /*
58613a2f6bSGordon Ross * Set this to a small number to debug sequence numbers
59613a2f6bSGordon Ross * that seem to get out of step.
60613a2f6bSGordon Ross */
61613a2f6bSGordon Ross int nsmb_signing_fudge = 0;
62613a2f6bSGordon Ross #endif
63613a2f6bSGordon Ross
6440c0e231SGordon Ross /*
6540c0e231SGordon Ross * This is called just after session setup completes,
6640c0e231SGordon Ross * at the top of smb_iod_vc_work(). Initialize signing.
6740c0e231SGordon Ross */
6840c0e231SGordon Ross int
smb_sign_init(smb_vc_t * vcp)6940c0e231SGordon Ross smb_sign_init(smb_vc_t *vcp)
7040c0e231SGordon Ross {
71adee6784SGordon Ross int rc;
7240c0e231SGordon Ross
7340c0e231SGordon Ross ASSERT(vcp->vc_ssnkey != NULL);
7440c0e231SGordon Ross ASSERT(vcp->vc_mackey == NULL);
7540c0e231SGordon Ross
76*48e11a6eSGordon Ross rc = nsmb_md5_getmech(&vcp->vc_signmech);
77adee6784SGordon Ross if (rc != 0) {
78adee6784SGordon Ross cmn_err(CE_NOTE, "smb can't get signing mechanism");
79adee6784SGordon Ross return (EAUTH);
80adee6784SGordon Ross }
81adee6784SGordon Ross
8240c0e231SGordon Ross /*
8340c0e231SGordon Ross * Convert the session key to the MAC key.
8440c0e231SGordon Ross * SMB1 uses the whole session key.
8540c0e231SGordon Ross */
8640c0e231SGordon Ross vcp->vc_mackeylen = vcp->vc_ssnkeylen;
8740c0e231SGordon Ross vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
8840c0e231SGordon Ross bcopy(vcp->vc_ssnkey, vcp->vc_mackey, vcp->vc_mackeylen);
8940c0e231SGordon Ross
9040c0e231SGordon Ross /* The initial sequence number is two. */
9140c0e231SGordon Ross vcp->vc_next_seq = 2;
9240c0e231SGordon Ross
9340c0e231SGordon Ross return (0);
9440c0e231SGordon Ross }
9540c0e231SGordon Ross
96613a2f6bSGordon Ross
97613a2f6bSGordon Ross #define SMBSIGLEN 8 /* SMB signature length */
98613a2f6bSGordon Ross #define SMBSIGOFF 14 /* SMB signature offset */
99613a2f6bSGordon Ross
100613a2f6bSGordon Ross /*
101613a2f6bSGordon Ross * Compute HMAC-MD5 of packet data, using the stored MAC key.
102613a2f6bSGordon Ross *
103613a2f6bSGordon Ross * See similar code for the server side:
104613a2f6bSGordon Ross * uts/common/fs/smbsrv/smb_signing.c : smb_sign_calc
105613a2f6bSGordon Ross */
106613a2f6bSGordon Ross static int
smb_compute_MAC(struct smb_vc * vcp,mblk_t * mp,uint32_t seqno,uchar_t * signature)107613a2f6bSGordon Ross smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
108613a2f6bSGordon Ross uint32_t seqno, uchar_t *signature)
109613a2f6bSGordon Ross {
1108329232eSGordon Ross uchar_t digest[MD5_DIGEST_LENGTH];
1118329232eSGordon Ross smb_sign_ctx_t ctx = 0;
1128329232eSGordon Ross mblk_t *m = mp;
1138329232eSGordon Ross int size;
1148329232eSGordon Ross int rc;
1158329232eSGordon Ross
116613a2f6bSGordon Ross /*
117613a2f6bSGordon Ross * This union is a little bit of trickery to:
118613a2f6bSGordon Ross * (1) get the sequence number int aligned, and
119613a2f6bSGordon Ross * (2) reduce the number of digest calls, at the
120613a2f6bSGordon Ross * cost of a copying 32 bytes instead of 8.
121613a2f6bSGordon Ross * Both sides of this union are 2+32 bytes.
122613a2f6bSGordon Ross */
123613a2f6bSGordon Ross union {
124613a2f6bSGordon Ross struct {
125613a2f6bSGordon Ross uint8_t skip[2]; /* not used - just alignment */
126613a2f6bSGordon Ross uint8_t raw[SMB_HDRLEN]; /* header length (32) */
127613a2f6bSGordon Ross } r;
128613a2f6bSGordon Ross struct {
129613a2f6bSGordon Ross uint8_t skip[2]; /* not used - just alignment */
130613a2f6bSGordon Ross uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
131613a2f6bSGordon Ross uint32_t sig[2]; /* MAC signature, aligned! */
132613a2f6bSGordon Ross uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
133613a2f6bSGordon Ross } s;
134613a2f6bSGordon Ross } smbhdr;
135613a2f6bSGordon Ross
1368329232eSGordon Ross if (vcp->vc_mackey == NULL)
1378329232eSGordon Ross return (-1);
1388329232eSGordon Ross
139*48e11a6eSGordon Ross if ((rc = nsmb_md5_init(&ctx, &vcp->vc_signmech)) != 0)
1408329232eSGordon Ross return (rc);
1418329232eSGordon Ross
1428329232eSGordon Ross /* Digest the MAC Key */
143*48e11a6eSGordon Ross rc = nsmb_md5_update(ctx, vcp->vc_mackey, vcp->vc_mackeylen);
1448329232eSGordon Ross if (rc != 0)
1458329232eSGordon Ross return (rc);
1468329232eSGordon Ross
147adee6784SGordon Ross /* Our caller should ensure mp has a contiguous header */
1488329232eSGordon Ross ASSERT(m != NULL);
1498329232eSGordon Ross ASSERT(MBLKL(m) >= SMB_HDRLEN);
150613a2f6bSGordon Ross
151613a2f6bSGordon Ross /*
1528329232eSGordon Ross * Make an aligned copy of the SMB header,
1538329232eSGordon Ross * fill in the sequence number, and digest.
154613a2f6bSGordon Ross */
1558329232eSGordon Ross size = SMB_HDRLEN;
1568329232eSGordon Ross bcopy(m->b_rptr, smbhdr.r.raw, size);
157613a2f6bSGordon Ross smbhdr.s.sig[0] = htolel(seqno);
158613a2f6bSGordon Ross smbhdr.s.sig[1] = 0;
159613a2f6bSGordon Ross
160*48e11a6eSGordon Ross rc = nsmb_md5_update(ctx, &smbhdr.r.raw, size);
1618329232eSGordon Ross if (rc != 0)
1628329232eSGordon Ross return (rc);
1638329232eSGordon Ross
164613a2f6bSGordon Ross /*
1658329232eSGordon Ross * Digest the rest of the SMB header packet, starting at
1668329232eSGordon Ross * the data just after the SMB header.
167613a2f6bSGordon Ross */
1688329232eSGordon Ross size = MBLKL(m) - SMB_HDRLEN;
169*48e11a6eSGordon Ross rc = nsmb_md5_update(ctx, m->b_rptr + SMB_HDRLEN, size);
1708329232eSGordon Ross if (rc != 0)
1718329232eSGordon Ross return (rc);
1728329232eSGordon Ross m = m->b_cont;
173613a2f6bSGordon Ross
174613a2f6bSGordon Ross /* Digest rest of the SMB message. */
1758329232eSGordon Ross while (m != NULL) {
1768329232eSGordon Ross size = MBLKL(m);
1778329232eSGordon Ross if (size > 0) {
178*48e11a6eSGordon Ross rc = nsmb_md5_update(ctx, m->b_rptr, size);
1798329232eSGordon Ross if (rc != 0)
1808329232eSGordon Ross return (rc);
1818329232eSGordon Ross }
1828329232eSGordon Ross m = m->b_cont;
1838329232eSGordon Ross }
184*48e11a6eSGordon Ross rc = nsmb_md5_final(ctx, digest);
1858329232eSGordon Ross if (rc != 0)
1868329232eSGordon Ross return (rc);
187613a2f6bSGordon Ross
188613a2f6bSGordon Ross /*
189613a2f6bSGordon Ross * Finally, store the signature.
190613a2f6bSGordon Ross * (first 8 bytes of the mac)
191613a2f6bSGordon Ross */
192adee6784SGordon Ross if (signature != NULL)
1938329232eSGordon Ross bcopy(digest, signature, SMBSIGLEN);
194613a2f6bSGordon Ross
195613a2f6bSGordon Ross return (0);
196613a2f6bSGordon Ross }
197613a2f6bSGordon Ross
198613a2f6bSGordon Ross /*
199613a2f6bSGordon Ross * Sign a request with HMAC-MD5.
200613a2f6bSGordon Ross */
20102d09e03SGordon Ross void
smb_rq_sign(struct smb_rq * rqp)202613a2f6bSGordon Ross smb_rq_sign(struct smb_rq *rqp)
203613a2f6bSGordon Ross {
204613a2f6bSGordon Ross struct smb_vc *vcp = rqp->sr_vc;
205613a2f6bSGordon Ross mblk_t *mp = rqp->sr_rq.mb_top;
206613a2f6bSGordon Ross uint8_t *sigloc;
207613a2f6bSGordon Ross int status;
208613a2f6bSGordon Ross
209613a2f6bSGordon Ross /*
210adee6784SGordon Ross * smb_rq_new() ensures this,
211adee6784SGordon Ross * but just in case..
212613a2f6bSGordon Ross */
213adee6784SGordon Ross ASSERT(MBLKL(mp) >= SMB_HDRLEN);
214613a2f6bSGordon Ross sigloc = mp->b_rptr + SMBSIGOFF;
215613a2f6bSGordon Ross
216613a2f6bSGordon Ross if (vcp->vc_mackey == NULL) {
217613a2f6bSGordon Ross /*
218613a2f6bSGordon Ross * Signing is required, but we have no key yet
219613a2f6bSGordon Ross * fill in with the magic fake signing value.
220613a2f6bSGordon Ross * This happens with SPNEGO, NTLMSSP, ...
221613a2f6bSGordon Ross */
222613a2f6bSGordon Ross bcopy("BSRSPLY", sigloc, 8);
22302d09e03SGordon Ross return;
224613a2f6bSGordon Ross }
225613a2f6bSGordon Ross
226613a2f6bSGordon Ross /*
227613a2f6bSGordon Ross * This will compute the MAC and store it
228613a2f6bSGordon Ross * directly into the message at sigloc.
229613a2f6bSGordon Ross */
230613a2f6bSGordon Ross status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
2318329232eSGordon Ross if (status != 0) {
232613a2f6bSGordon Ross SMBSDEBUG("Crypto error %d", status);
233613a2f6bSGordon Ross bzero(sigloc, SMBSIGLEN);
234613a2f6bSGordon Ross }
235613a2f6bSGordon Ross }
236613a2f6bSGordon Ross
237613a2f6bSGordon Ross /*
238613a2f6bSGordon Ross * Verify reply signature.
239613a2f6bSGordon Ross */
240613a2f6bSGordon Ross int
smb_rq_verify(struct smb_rq * rqp)241613a2f6bSGordon Ross smb_rq_verify(struct smb_rq *rqp)
242613a2f6bSGordon Ross {
243613a2f6bSGordon Ross struct smb_vc *vcp = rqp->sr_vc;
244613a2f6bSGordon Ross mblk_t *mp = rqp->sr_rp.md_top;
245613a2f6bSGordon Ross uint8_t sigbuf[SMBSIGLEN];
246613a2f6bSGordon Ross uint8_t *sigloc;
24702d09e03SGordon Ross int fudge, rsn, status;
248613a2f6bSGordon Ross
249613a2f6bSGordon Ross /*
250613a2f6bSGordon Ross * Note vc_mackey and vc_mackeylen gets filled in by
251613a2f6bSGordon Ross * smb_usr_iod_work as the connection comes in.
252613a2f6bSGordon Ross */
253613a2f6bSGordon Ross if (vcp->vc_mackey == NULL) {
254613a2f6bSGordon Ross SMBSDEBUG("no mac key\n");
255613a2f6bSGordon Ross return (0);
256613a2f6bSGordon Ross }
257613a2f6bSGordon Ross
258613a2f6bSGordon Ross /*
259613a2f6bSGordon Ross * Let caller deal with empty reply or short messages by
260613a2f6bSGordon Ross * returning zero. Caller will fail later, in parsing.
261613a2f6bSGordon Ross */
262613a2f6bSGordon Ross if (mp == NULL) {
263613a2f6bSGordon Ross SMBSDEBUG("empty reply\n");
264613a2f6bSGordon Ross return (0);
265613a2f6bSGordon Ross }
266adee6784SGordon Ross
267adee6784SGordon Ross ASSERT(MBLKL(mp) >= SMB_HDRLEN);
268613a2f6bSGordon Ross sigloc = mp->b_rptr + SMBSIGOFF;
269613a2f6bSGordon Ross
27002d09e03SGordon Ross /*
27102d09e03SGordon Ross * Compute the expected signature in sigbuf.
27202d09e03SGordon Ross */
27302d09e03SGordon Ross rsn = rqp->sr_rseqno;
27402d09e03SGordon Ross status = smb_compute_MAC(vcp, mp, rsn, sigbuf);
2758329232eSGordon Ross if (status != 0) {
276613a2f6bSGordon Ross SMBSDEBUG("Crypto error %d", status);
277613a2f6bSGordon Ross /*
278613a2f6bSGordon Ross * If we can't compute a MAC, then there's
279613a2f6bSGordon Ross * no point trying other seqno values.
280613a2f6bSGordon Ross */
281613a2f6bSGordon Ross return (EBADRPC);
282613a2f6bSGordon Ross }
283613a2f6bSGordon Ross
284613a2f6bSGordon Ross /*
285613a2f6bSGordon Ross * Compare the computed signature with the
286613a2f6bSGordon Ross * one found in the message (at sigloc)
287613a2f6bSGordon Ross */
288613a2f6bSGordon Ross if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
289613a2f6bSGordon Ross return (0);
290613a2f6bSGordon Ross
291a547be5dSGordon Ross SMBERROR("BAD signature, Server=%s MID=0x%x Seq=%d\n",
292a547be5dSGordon Ross vcp->vc_srvname, rqp->sr_mid, rsn);
293613a2f6bSGordon Ross
294613a2f6bSGordon Ross #ifdef DEBUG
295613a2f6bSGordon Ross /*
296613a2f6bSGordon Ross * For diag purposes, we check whether the client/server idea
297613a2f6bSGordon Ross * of the sequence # has gotten a bit out of sync.
298613a2f6bSGordon Ross */
299613a2f6bSGordon Ross for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
30002d09e03SGordon Ross (void) smb_compute_MAC(vcp, mp, rsn + fudge, sigbuf);
301613a2f6bSGordon Ross if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
302613a2f6bSGordon Ross break;
30302d09e03SGordon Ross (void) smb_compute_MAC(vcp, mp, rsn - fudge, sigbuf);
304613a2f6bSGordon Ross if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
305613a2f6bSGordon Ross fudge = -fudge;
306613a2f6bSGordon Ross break;
307613a2f6bSGordon Ross }
308613a2f6bSGordon Ross }
309613a2f6bSGordon Ross if (fudge <= nsmb_signing_fudge) {
310a547be5dSGordon Ross SMBERROR("MID=0x%x, Seq=%d, but %d would have worked\n",
311a547be5dSGordon Ross rqp->sr_mid, rsn, rsn + fudge);
312613a2f6bSGordon Ross }
313613a2f6bSGordon Ross #endif
314613a2f6bSGordon Ross return (EBADRPC);
315613a2f6bSGordon Ross }
316