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 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 */
25 /*
26 * These routines provide the SMB MAC signing for the SMB server.
27 * The routines calculate the signature of a SMB message in an mbuf chain.
28 *
29 * The following table describes the client server
30 * signing registry relationship
31 *
32 * | Required | Enabled | Disabled
33 * -------------+---------------+------------ +--------------
34 * Required | Signed | Signed | Fail
35 * -------------+---------------+-------------+-----------------
36 * Enabled | Signed | Signed | Not Signed
37 * -------------+---------------+-------------+----------------
38 * Disabled | Fail | Not Signed | Not Signed
39 */
40
41 #include <sys/uio.h>
42 #include <smbsrv/smb_kproto.h>
43 #include <smbsrv/smb_signing.h>
44 #include <sys/isa_defs.h>
45 #include <sys/byteorder.h>
46
47 #define SMB_SIG_SIZE 8
48 #define SMB_SIG_OFFS 14
49 #define SMB_HDRLEN 32
50
51 #ifdef _LITTLE_ENDIAN
52 #define htolel(x) ((uint32_t)(x))
53 #else
54 #define htolel(x) BSWAP_32(x)
55 #endif
56
57 static int
58 smb_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc,
59 uint32_t seqnum, unsigned char *sig);
60
61 #ifdef DEBUG
62 uint32_t smb_sign_debug_search = 10;
63
87 goto found;
88 }
89 }
90 cmn_err(CE_WARN, "smb_sign_find_seqnum: failed after %d", i);
91 return (-1);
92
93 found:
94 cmn_err(CE_WARN, "smb_sign_find_seqnum: found! %d <- %d",
95 sign->seqnum, t);
96 sign->seqnum = t;
97 return (0);
98 }
99 #endif
100
101 /*
102 * Called during session destroy.
103 */
104 static void
105 smb_sign_fini(smb_session_t *s)
106 {
107 smb_sign_mech_t *mech;
108
109 if ((mech = s->sign_mech) != NULL) {
110 kmem_free(mech, sizeof (*mech));
111 s->sign_mech = NULL;
112 }
113 }
114
115 /*
116 * smb_sign_begin
117 *
118 * Intializes MAC key based on the user session key and
119 * NTLM response and store it in the signing structure.
120 * This is what begins SMB signing.
121 */
122 int
123 smb_sign_begin(smb_request_t *sr, smb_token_t *token)
124 {
125 smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
126 smb_session_t *session = sr->session;
127 struct smb_sign *sign = &session->signing;
128 smb_sign_mech_t *mech;
129 int rc;
130
131 /*
132 * We should normally have a session key here because
133 * our caller filters out Anonymous and Guest logons.
134 * However, buggy clients could get us here without a
135 * session key, in which case: just don't sign.
136 */
137 if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0)
138 return (0);
139
140 /*
141 * Session-level initialization (once per session)
142 */
143 smb_rwx_rwenter(&session->s_lock, RW_WRITER);
144
145 /*
146 * Signing may already have been setup by a prior logon,
147 * in which case we're done here.
148 */
149 if (sign->mackey != NULL) {
150 smb_rwx_rwexit(&session->s_lock);
151 return (0);
152 }
153
154 /*
155 * Get the mech handle
156 */
157 if (session->sign_mech == NULL) {
158 mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
159 rc = smb_md5_getmech(mech);
160 if (rc != 0) {
161 kmem_free(mech, sizeof (*mech));
162 smb_rwx_rwexit(&session->s_lock);
163 return (rc);
164 }
165 session->sign_mech = mech;
166 session->sign_fini = smb_sign_fini;
167 }
168
169 /*
170 * Compute and store the signing (MAC) key.
171 *
172 * With extended security, the MAC key is the same as the
173 * session key (and we'll have sinfo->ssi_ntpwlen == 0).
174 * With non-extended security, it's the concatenation of
175 * the session key and the "NT response" we received.
176 */
177 sign->mackey_len = token->tkn_ssnkey.len + sinfo->ssi_ntpwlen;
178 sign->mackey = kmem_alloc(sign->mackey_len, KM_SLEEP);
179 bcopy(token->tkn_ssnkey.val, sign->mackey, token->tkn_ssnkey.len);
180 if (sinfo->ssi_ntpwlen > 0) {
181 bcopy(sinfo->ssi_ntpwd, sign->mackey + token->tkn_ssnkey.len,
182 sinfo->ssi_ntpwlen);
183 }
184
185 session->signing.seqnum = 0;
186 sr->sr_seqnum = 2;
187 sr->reply_seqnum = 1;
188 sign->flags = 0;
189
190 if (session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
191 sign->flags |= SMB_SIGNING_ENABLED;
192 if (session->secmode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)
193 sign->flags |= SMB_SIGNING_CHECK;
194 }
195
196 smb_rwx_rwexit(&session->s_lock);
197 return (0);
198 }
199
200 /*
201 * smb_sign_calc
202 *
203 * Calculates MAC signature for the given buffer and returns
204 * it in the mac_sign parameter.
205 *
206 * The sequence number is placed in the first four bytes of the signature
207 * field of the signature and the other 4 bytes are zeroed.
208 * The signature is the first 8 bytes of the MD5 result of the
209 * concatenated MAC key and the SMB message.
210 *
211 * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8)
212 *
213 * where
214 *
215 * MACKey = concat( UserSessionKey, NTLMResp )
216 *
217 * and
|
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 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
24 */
25 /*
26 * These routines provide the SMB MAC signing for the SMB server.
27 * The routines calculate the signature of a SMB message in an mbuf chain.
28 *
29 * The following table describes the client server
30 * signing registry relationship
31 *
32 * | Required | Enabled | Disabled
33 * -------------+---------------+------------ +--------------
34 * Required | Signed | Signed | Fail
35 * -------------+---------------+-------------+-----------------
36 * Enabled | Signed | Signed | Not Signed
37 * -------------+---------------+-------------+----------------
38 * Disabled | Fail | Not Signed | Not Signed
39 */
40
41 #include <sys/uio.h>
42 #include <smbsrv/smb_kproto.h>
43 #include <smbsrv/smb_kcrypt.h>
44 #include <sys/isa_defs.h>
45 #include <sys/byteorder.h>
46
47 #define SMB_SIG_SIZE 8
48 #define SMB_SIG_OFFS 14
49 #define SMB_HDRLEN 32
50
51 #ifdef _LITTLE_ENDIAN
52 #define htolel(x) ((uint32_t)(x))
53 #else
54 #define htolel(x) BSWAP_32(x)
55 #endif
56
57 static int
58 smb_sign_calc(smb_request_t *sr, struct mbuf_chain *mbc,
59 uint32_t seqnum, unsigned char *sig);
60
61 #ifdef DEBUG
62 uint32_t smb_sign_debug_search = 10;
63
87 goto found;
88 }
89 }
90 cmn_err(CE_WARN, "smb_sign_find_seqnum: failed after %d", i);
91 return (-1);
92
93 found:
94 cmn_err(CE_WARN, "smb_sign_find_seqnum: found! %d <- %d",
95 sign->seqnum, t);
96 sign->seqnum = t;
97 return (0);
98 }
99 #endif
100
101 /*
102 * Called during session destroy.
103 */
104 static void
105 smb_sign_fini(smb_session_t *s)
106 {
107 smb_crypto_mech_t *mech;
108
109 if ((mech = s->sign_mech) != NULL) {
110 kmem_free(mech, sizeof (*mech));
111 s->sign_mech = NULL;
112 }
113 }
114
115 /*
116 * smb_sign_begin
117 *
118 * Intializes MAC key based on the user session key and
119 * NTLM response and store it in the signing structure.
120 * This is what begins SMB signing.
121 */
122 void
123 smb_sign_begin(smb_request_t *sr, smb_token_t *token)
124 {
125 smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
126 smb_session_t *session = sr->session;
127 struct smb_sign *sign = &session->signing;
128 smb_crypto_mech_t *mech;
129 int rc;
130
131 /*
132 * We should normally have a session key here because
133 * our caller filters out Anonymous and Guest logons.
134 * However, buggy clients could get us here without a
135 * session key, in which case: just don't sign.
136 */
137 if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0)
138 return;
139
140 /*
141 * Session-level initialization (once per session)
142 */
143 smb_rwx_rwenter(&session->s_lock, RW_WRITER);
144
145 /*
146 * Signing may already have been setup by a prior logon,
147 * in which case we're done here.
148 */
149 if (sign->mackey != NULL) {
150 smb_rwx_rwexit(&session->s_lock);
151 return;
152 }
153
154 /*
155 * Get the mech handle
156 */
157 if (session->sign_mech == NULL) {
158 mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
159 rc = smb_md5_getmech(mech);
160 if (rc != 0) {
161 kmem_free(mech, sizeof (*mech));
162 smb_rwx_rwexit(&session->s_lock);
163 return;
164 }
165 session->sign_mech = mech;
166 session->sign_fini = smb_sign_fini;
167 }
168
169 /*
170 * Compute and store the signing (MAC) key.
171 *
172 * With extended security, the MAC key is the same as the
173 * session key (and we'll have sinfo->ssi_ntpwlen == 0).
174 * With non-extended security, it's the concatenation of
175 * the session key and the "NT response" we received.
176 */
177 sign->mackey_len = token->tkn_ssnkey.len + sinfo->ssi_ntpwlen;
178 sign->mackey = kmem_alloc(sign->mackey_len, KM_SLEEP);
179 bcopy(token->tkn_ssnkey.val, sign->mackey, token->tkn_ssnkey.len);
180 if (sinfo->ssi_ntpwlen > 0) {
181 bcopy(sinfo->ssi_ntpwd, sign->mackey + token->tkn_ssnkey.len,
182 sinfo->ssi_ntpwlen);
183 }
184
185 session->signing.seqnum = 0;
186 sr->sr_seqnum = 2;
187 sr->reply_seqnum = 1;
188 sign->flags = 0;
189
190 if (session->srv_secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
191 sign->flags |= SMB_SIGNING_ENABLED;
192 if (session->srv_secmode &
193 NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)
194 sign->flags |= SMB_SIGNING_CHECK;
195 }
196
197 smb_rwx_rwexit(&session->s_lock);
198 }
199
200 /*
201 * smb_sign_calc
202 *
203 * Calculates MAC signature for the given buffer and returns
204 * it in the mac_sign parameter.
205 *
206 * The sequence number is placed in the first four bytes of the signature
207 * field of the signature and the other 4 bytes are zeroed.
208 * The signature is the first 8 bytes of the MD5 result of the
209 * concatenated MAC key and the SMB message.
210 *
211 * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8)
212 *
213 * where
214 *
215 * MACKey = concat( UserSessionKey, NTLMResp )
216 *
217 * and
|