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.
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.
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]
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Support for SMB "signing" (message integrity)
30 #include <sys/param.h>
31 #include <sys/systm.h>
34 #include <sys/fcntl.h>
35 #include <sys/socket.h>
40 #include <sys/crypto/api.h>
41 #include <sys/crypto/common.h>
42 #include <sys/cmn_err.h>
43 #include <sys/stream.h>
44 #include <sys/strsun.h>
47 #include <netsmb/smb_osdep.h>
48 #include <netsmb/smb.h>
49 #include <netsmb/smb_conn.h>
50 #include <netsmb/smb_subr.h>
51 #include <netsmb/smb_dev.h>
52 #include <netsmb/smb_rq.h>
56 * Set this to a small number to debug sequence numbers
57 * that seem to get out of step.
59 int nsmb_signing_fudge
= 0;
62 /* Mechanism definitions */
63 static crypto_mechanism_t crypto_mech_md5
= { CRYPTO_MECH_INVALID
};
66 smb_crypto_mech_init(void)
68 crypto_mech_md5
.cm_type
= crypto_mech2id(SUN_CKM_MD5
);
73 #define SMBSIGLEN 8 /* SMB signature length */
74 #define SMBSIGOFF 14 /* SMB signature offset */
77 * Compute HMAC-MD5 of packet data, using the stored MAC key.
79 * See similar code for the server side:
80 * uts/common/fs/smbsrv/smb_signing.c : smb_sign_calc
83 smb_compute_MAC(struct smb_vc
*vcp
, mblk_t
*mp
,
84 uint32_t seqno
, uchar_t
*signature
)
86 crypto_context_t crypto_ctx
;
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.
101 uint8_t skip
[2]; /* not used - just alignment */
102 uint8_t raw
[SMB_HDRLEN
]; /* header length (32) */
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 */
113 ASSERT(MBLKL(mp
) >= SMB_HDRLEN
);
114 ASSERT(vcp
->vc_mackey
!= NULL
);
117 * Make an aligned copy of the SMB header
118 * and fill in the sequence number.
120 bcopy(mp
->b_rptr
, smbhdr
.r
.raw
, SMB_HDRLEN
);
121 smbhdr
.s
.sig
[0] = htolel(seqno
);
125 * Compute the MAC: MD5(concat(Key, message))
127 if (crypto_mech_md5
.cm_type
== CRYPTO_MECH_INVALID
) {
128 SMBSDEBUG("crypto_mech_md5 invalid\n");
129 return (CRYPTO_MECHANISM_INVALID
);
131 status
= crypto_digest_init(&crypto_mech_md5
, &crypto_ctx
, 0);
132 if (status
!= CRYPTO_SUCCESS
)
135 /* Digest the MAC Key */
136 key
.cd_format
= CRYPTO_DATA_RAW
;
138 key
.cd_length
= vcp
->vc_mackeylen
;
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
)
146 /* Digest the (copied) SMB header */
147 data
.cd_format
= CRYPTO_DATA_RAW
;
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
)
157 /* 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;
163 status
= crypto_digest_update(crypto_ctx
, &data
, 0);
164 if (status
!= CRYPTO_SUCCESS
)
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
)
179 * Finally, store the signature.
180 * (first 8 bytes of the mac)
183 bcopy(mac
, signature
, SMBSIGLEN
);
189 * Sign a request with HMAC-MD5.
192 smb_rq_sign(struct smb_rq
*rqp
)
194 struct smb_vc
*vcp
= rqp
->sr_vc
;
195 mblk_t
*mp
= rqp
->sr_rq
.mb_top
;
200 * Our mblk allocation ensures this,
201 * but just in case...
203 if (MBLKL(mp
) < SMB_HDRLEN
) {
204 if (!pullupmsg(mp
, SMB_HDRLEN
))
207 sigloc
= mp
->b_rptr
+ SMBSIGOFF
;
209 if (vcp
->vc_mackey
== NULL
) {
211 * Signing is required, but we have no key yet
212 * fill in with the magic fake signing value.
213 * This happens with SPNEGO, NTLMSSP, ...
215 bcopy("BSRSPLY", sigloc
, 8);
220 * This will compute the MAC and store it
221 * directly into the message at sigloc.
223 status
= smb_compute_MAC(vcp
, mp
, rqp
->sr_seqno
, sigloc
);
224 if (status
!= CRYPTO_SUCCESS
) {
225 SMBSDEBUG("Crypto error %d", status
);
226 bzero(sigloc
, SMBSIGLEN
);
231 * Verify reply signature.
234 smb_rq_verify(struct smb_rq
*rqp
)
236 struct smb_vc
*vcp
= rqp
->sr_vc
;
237 mblk_t
*mp
= rqp
->sr_rp
.md_top
;
238 uint8_t sigbuf
[SMBSIGLEN
];
240 int fudge
, rsn
, status
;
243 * Note vc_mackey and vc_mackeylen gets filled in by
244 * smb_usr_iod_work as the connection comes in.
246 if (vcp
->vc_mackey
== NULL
) {
247 SMBSDEBUG("no mac key\n");
252 * Let caller deal with empty reply or short messages by
253 * returning zero. Caller will fail later, in parsing.
256 SMBSDEBUG("empty reply\n");
259 if (MBLKL(mp
) < SMB_HDRLEN
) {
260 if (!pullupmsg(mp
, SMB_HDRLEN
))
263 sigloc
= mp
->b_rptr
+ SMBSIGOFF
;
266 * Compute the expected signature in sigbuf.
268 rsn
= rqp
->sr_rseqno
;
269 status
= smb_compute_MAC(vcp
, mp
, rsn
, sigbuf
);
270 if (status
!= CRYPTO_SUCCESS
) {
271 SMBSDEBUG("Crypto error %d", status
);
273 * If we can't compute a MAC, then there's
274 * no point trying other seqno values.
280 * Compare the computed signature with the
281 * one found in the message (at sigloc)
283 if (bcmp(sigbuf
, sigloc
, SMBSIGLEN
) == 0)
286 SMBERROR("BAD signature, Server=%s MID=0x%x Seq=%d\n",
287 vcp
->vc_srvname
, rqp
->sr_mid
, rsn
);
291 * For diag purposes, we check whether the client/server idea
292 * of the sequence # has gotten a bit out of sync.
294 for (fudge
= 1; fudge
<= nsmb_signing_fudge
; fudge
++) {
295 (void) smb_compute_MAC(vcp
, mp
, rsn
+ fudge
, sigbuf
);
296 if (bcmp(sigbuf
, sigloc
, SMBSIGLEN
) == 0)
298 (void) smb_compute_MAC(vcp
, mp
, rsn
- fudge
, sigbuf
);
299 if (bcmp(sigbuf
, sigloc
, SMBSIGLEN
) == 0) {
304 if (fudge
<= nsmb_signing_fudge
) {
305 SMBERROR("MID=0x%x, Seq=%d, but %d would have worked\n",
306 rqp
->sr_mid
, rsn
, rsn
+ fudge
);