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 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24 /*
25 * These routines provide the SMB MAC signing for the SMB server.
26 * The routines calculate the signature of a SMB message in an mbuf chain.
27 *
28 * The following table describes the client server
29 * signing registry relationship
30 *
31 * | Required | Enabled | Disabled
32 * -------------+---------------+------------ +--------------
33 * Required | Signed | Signed | Fail
34 * -------------+---------------+-------------+-----------------
35 * Enabled | Signed | Signed | Not Signed
36 * -------------+---------------+-------------+----------------
37 * Disabled | Fail | Not Signed | Not Signed
38 */
39
40 #include <sys/uio.h>
41 #include <smbsrv/smb_kproto.h>
42 #include <smbsrv/msgbuf.h>
43 #include <sys/crypto/api.h>
44
45 #define SMBAUTH_SESSION_KEY_SZ 16
46 #define SMB_SIG_SIZE 8
47 #define SMB_SIG_OFFS 14
48
49 int
50 smb_sign_calc(struct mbuf_chain *mbc,
51 struct smb_sign *sign,
52 uint32_t seqnum,
53 unsigned char *mac_sign);
54
55 #ifdef DEBUG
56 void smb_sign_find_seqnum(
57 uint32_t seqnum,
58 struct smb_sign *sign,
59 struct mbuf_chain *command,
60 unsigned char *mac_sig,
61 unsigned char *sr_sig,
62 boolean_t *found);
63 #define SMB_CHECK_SEQNUM(seqnum, sign, command, mac_sig, sr_sig, found) \
64 { \
65 if (smb_sign_debug) \
66 smb_sign_find_seqnum(seqnum, sign, \
67 command, mac_sig, sr_sig, found); \
68 }
69 #else
70 #define SMB_CHECK_SEQNUM(seqnum, sign, command, mac_sig, sr_sig, found) \
71 { \
72 *found = 0; \
73 }
74 #endif
75
76 #ifdef DEBUG
77 void
smb_sign_find_seqnum(uint32_t seqnum,struct smb_sign * sign,struct mbuf_chain * command,unsigned char * mac_sig,unsigned char * sr_sig,boolean_t * found)78 smb_sign_find_seqnum(
79 uint32_t seqnum,
80 struct smb_sign *sign,
81 struct mbuf_chain *command,
82 unsigned char *mac_sig,
83 unsigned char *sr_sig,
84 boolean_t *found)
85 {
86 int start_seqnum;
87 int i;
88
89 /* Debug code to hunt for the sequence number */
90 *found = B_FALSE;
91 start_seqnum = seqnum - 10;
92 if (start_seqnum < 0)
93 start_seqnum = 0;
94 for (i = start_seqnum; i <= start_seqnum + 20; i++) {
95 (void) smb_sign_calc(command, sign, i, mac_sig);
96 if (memcmp(mac_sig, sr_sig, SMB_SIG_SIZE) == 0) {
97 sign->seqnum = i;
98 *found = B_TRUE;
99 break;
100 }
101 cmn_err(CE_WARN, "smb_sign_find_seqnum: seqnum:%d mismatch", i);
102 }
103 cmn_err(CE_WARN, "smb_sign_find_seqnum: found=%d", *found);
104 }
105 #endif
106
107 /* This holds the MD5 mechanism */
108 static crypto_mechanism_t crypto_mech = {CRYPTO_MECHANISM_INVALID, 0, 0};
109
110 /*
111 * smb_sign_init
112 *
113 * Intializes MAC key based on the user session key and
114 * NTLM response and store it in the signing structure.
115 */
116 void
smb_sign_init(smb_request_t * sr,smb_session_key_t * session_key,char * resp,int resp_len)117 smb_sign_init(smb_request_t *sr, smb_session_key_t *session_key,
118 char *resp, int resp_len)
119 {
120 struct smb_sign *sign = &sr->session->signing;
121
122 /*
123 * Initialise the crypto mechanism to MD5 if it not
124 * already initialised.
125 */
126 if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) {
127 crypto_mech.cm_type = crypto_mech2id(SUN_CKM_MD5);
128 if (crypto_mech.cm_type == CRYPTO_MECHANISM_INVALID) {
129 /*
130 * There is no MD5 crypto mechanism
131 * so turn off signing
132 */
133 sr->sr_cfg->skc_signing_enable = 0;
134 sr->session->secmode &=
135 (~NEGOTIATE_SECURITY_SIGNATURES_ENABLED);
136 cmn_err(CE_WARN,
137 "SmbSignInit: signing disabled (no MD5)");
138 return;
139 }
140 }
141
142 /* MAC key = concat (SessKey, NTLMResponse) */
143
144 bcopy(session_key, sign->mackey, sizeof (smb_session_key_t));
145 bcopy(resp, &(sign->mackey[sizeof (smb_session_key_t)]),
146 resp_len);
147 sign->mackey_len = sizeof (smb_session_key_t) + resp_len;
148
149 sr->session->signing.seqnum = 0;
150 sr->sr_seqnum = 2;
151 sr->reply_seqnum = 1;
152 sign->flags = SMB_SIGNING_ENABLED;
153
154 }
155
156 /*
157 * smb_sign_calc
158 *
159 * Calculates MAC signature for the given buffer and returns
160 * it in the mac_sign parameter.
161 *
162 * The sequence number is placed in the first four bytes of the signature
163 * field of the signature and the other 4 bytes are zeroed.
164 * The signature is the first 8 bytes of the MD5 result of the
165 * concatenated MAC key and the SMB message.
166 *
167 * MACsig = head(MD5(concat(MACKey, SMBMsg)), 8)
168 *
169 * where
170 *
171 * MACKey = concat( UserSessionKey, NTLMResp )
172 *
173 * and
174 *
175 * SMBMsg is the SMB message containing the sequence number.
176 *
177 * Return 0 if success else -1
178 *
179 */
180 int
smb_sign_calc(struct mbuf_chain * mbc,struct smb_sign * sign,uint32_t seqnum,unsigned char * mac_sign)181 smb_sign_calc(struct mbuf_chain *mbc,
182 struct smb_sign *sign,
183 uint32_t seqnum,
184 unsigned char *mac_sign)
185 {
186 uint32_t seq_buf[2] = {0, 0};
187 unsigned char mac[16];
188 struct mbuf *mbuf = mbc->chain;
189 int offset = mbc->chain_offset;
190 int size;
191 int status;
192
193 crypto_data_t data;
194 crypto_data_t digest;
195 crypto_context_t crypto_ctx;
196
197 data.cd_format = CRYPTO_DATA_RAW;
198 data.cd_offset = 0;
199 data.cd_length = (size_t)-1;
200 data.cd_miscdata = 0;
201
202 digest.cd_format = CRYPTO_DATA_RAW;
203 digest.cd_offset = 0;
204 digest.cd_length = (size_t)-1;
205 digest.cd_miscdata = 0;
206 digest.cd_raw.iov_base = (char *)mac;
207 digest.cd_raw.iov_len = sizeof (mac);
208
209 status = crypto_digest_init(&crypto_mech, &crypto_ctx, 0);
210 if (status != CRYPTO_SUCCESS)
211 goto error;
212
213 /*
214 * Put the sequence number into the first 4 bytes
215 * of the signature field in little endian format.
216 * We are using a buffer to represent the signature
217 * rather than modifying the SMB message.
218 */
219 #ifdef __sparc
220 {
221 uint32_t temp;
222 ((uint8_t *)&temp)[0] = ((uint8_t *)&seqnum)[3];
223 ((uint8_t *)&temp)[1] = ((uint8_t *)&seqnum)[2];
224 ((uint8_t *)&temp)[2] = ((uint8_t *)&seqnum)[1];
225 ((uint8_t *)&temp)[3] = ((uint8_t *)&seqnum)[0];
226
227 seq_buf[0] = temp;
228 }
229 #else
230 seq_buf[0] = seqnum;
231 #endif
232
233 /* Digest the MACKey */
234 data.cd_raw.iov_base = (char *)sign->mackey;
235 data.cd_raw.iov_len = sign->mackey_len;
236 data.cd_length = sign->mackey_len;
237 status = crypto_digest_update(crypto_ctx, &data, 0);
238 if (status != CRYPTO_SUCCESS)
239 goto error;
240
241 /* Find start of data in chain */
242 while (offset >= mbuf->m_len) {
243 offset -= mbuf->m_len;
244 mbuf = mbuf->m_next;
245 }
246
247 /* Digest the SMB packet up to the signature field */
248 size = SMB_SIG_OFFS;
249 while (size >= mbuf->m_len - offset) {
250 data.cd_raw.iov_base = &mbuf->m_data[offset];
251 data.cd_raw.iov_len = mbuf->m_len - offset;
252 data.cd_length = mbuf->m_len - offset;
253 status = crypto_digest_update(crypto_ctx, &data, 0);
254 if (status != CRYPTO_SUCCESS)
255 goto error;
256
257 size -= mbuf->m_len - offset;
258 mbuf = mbuf->m_next;
259 offset = 0;
260 }
261 if (size > 0) {
262 data.cd_raw.iov_base = &mbuf->m_data[offset];
263 data.cd_raw.iov_len = size;
264 data.cd_length = size;
265 status = crypto_digest_update(crypto_ctx, &data, 0);
266 if (status != CRYPTO_SUCCESS)
267 goto error;
268 offset += size;
269 }
270
271 /*
272 * Digest in the seq_buf instead of the signature
273 * which has the sequence number
274 */
275
276 data.cd_raw.iov_base = (char *)seq_buf;
277 data.cd_raw.iov_len = SMB_SIG_SIZE;
278 data.cd_length = SMB_SIG_SIZE;
279 status = crypto_digest_update(crypto_ctx, &data, 0);
280 if (status != CRYPTO_SUCCESS)
281 goto error;
282
283 /* Find the end of the signature field */
284 offset += SMB_SIG_SIZE;
285 while (offset >= mbuf->m_len) {
286 offset -= mbuf->m_len;
287 mbuf = mbuf->m_next;
288 }
289 /* Digest the rest of the SMB packet */
290 while (mbuf) {
291 data.cd_raw.iov_base = &mbuf->m_data[offset];
292 data.cd_raw.iov_len = mbuf->m_len - offset;
293 data.cd_length = mbuf->m_len - offset;
294 status = crypto_digest_update(crypto_ctx, &data, 0);
295 if (status != CRYPTO_SUCCESS)
296 goto error;
297 mbuf = mbuf->m_next;
298 offset = 0;
299 }
300 digest.cd_length = SMBAUTH_SESSION_KEY_SZ;
301 status = crypto_digest_final(crypto_ctx, &digest, 0);
302 if (status != CRYPTO_SUCCESS)
303 goto error;
304 bcopy(mac, mac_sign, SMB_SIG_SIZE);
305 return (0);
306 error:
307 cmn_err(CE_WARN, "SmbSignCalc: crypto error %d", status);
308 return (-1);
309
310 }
311
312
313 /*
314 * smb_sign_check_request
315 *
316 * Calculates MAC signature for the request mbuf chain
317 * using the next expected sequence number and compares
318 * it to the given signature.
319 *
320 * Note it does not check the signature for secondary transactions
321 * as their sequence number is the same as the original request.
322 *
323 * Return 0 if the signature verifies, otherwise, returns -1;
324 *
325 */
326 int
smb_sign_check_request(smb_request_t * sr)327 smb_sign_check_request(smb_request_t *sr)
328 {
329 struct mbuf_chain command = sr->command;
330 unsigned char mac_sig[SMB_SIG_SIZE];
331 struct smb_sign *sign = &sr->session->signing;
332 int rtn = 0;
333 boolean_t found = B_TRUE;
334
335 /*
336 * Don't check secondary transactions - we dont know the sequence
337 * number.
338 */
339 if (sr->smb_com == SMB_COM_TRANSACTION_SECONDARY ||
340 sr->smb_com == SMB_COM_TRANSACTION2_SECONDARY ||
341 sr->smb_com == SMB_COM_NT_TRANSACT_SECONDARY)
342 return (0);
343
344 /* Reset the offset to begining of header */
345 command.chain_offset = sr->orig_request_hdr;
346
347 /* calculate mac signature */
348 if (smb_sign_calc(&command, sign, sr->sr_seqnum, mac_sig) != 0)
349 return (-1);
350
351 /* compare the signatures */
352 if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) {
353 DTRACE_PROBE2(smb__signing__req, smb_request_t, sr,
354 smb_sign_t *, sr->smb_sig);
355 cmn_err(CE_NOTE, "smb_sign_check_request: bad signature");
356 /*
357 * check nearby sequence numbers in debug mode
358 */
359 SMB_CHECK_SEQNUM(sr->sr_seqnum, sign, &command,
360 mac_sig, sr->smb_sig, &found);
361 if (found == B_FALSE)
362 rtn = -1;
363 }
364 return (rtn);
365 }
366
367 /*
368 * smb_sign_check_secondary
369 *
370 * Calculates MAC signature for the secondary transaction mbuf chain
371 * and compares it to the given signature.
372 * Return 0 if the signature verifies, otherwise, returns -1;
373 *
374 */
375 int
smb_sign_check_secondary(smb_request_t * sr,unsigned int reply_seqnum)376 smb_sign_check_secondary(smb_request_t *sr, unsigned int reply_seqnum)
377 {
378 struct mbuf_chain command = sr->command;
379 unsigned char mac_sig[SMB_SIG_SIZE];
380 struct smb_sign *sign = &sr->session->signing;
381 int rtn = 0;
382
383 /* Reset the offset to begining of header */
384 command.chain_offset = sr->orig_request_hdr;
385
386 /* calculate mac signature */
387 if (smb_sign_calc(&command, sign, reply_seqnum - 1,
388 mac_sig) != 0)
389 return (-1);
390
391
392 /* compare the signatures */
393 if (memcmp(mac_sig, sr->smb_sig, SMB_SIG_SIZE) != 0) {
394 cmn_err(CE_WARN, "SmbSignCheckSecond: bad signature");
395 rtn = -1;
396 }
397 /* Save the reply sequence number */
398 sr->reply_seqnum = reply_seqnum;
399
400 return (rtn);
401 }
402
403 /*
404 * smb_sign_reply
405 *
406 * Calculates MAC signature for the given mbuf chain,
407 * and write it to the signature field in the mbuf.
408 *
409 */
410 void
smb_sign_reply(smb_request_t * sr,struct mbuf_chain * reply)411 smb_sign_reply(smb_request_t *sr, struct mbuf_chain *reply)
412 {
413 struct mbuf_chain resp;
414 struct smb_sign *sign = &sr->session->signing;
415 unsigned char signature[SMB_SIG_SIZE];
416 struct mbuf *mbuf;
417 int size = SMB_SIG_SIZE;
418 unsigned char *sig_ptr = signature;
419 int offset = 0;
420
421 if (reply)
422 resp = *reply;
423 else
424 resp = sr->reply;
425
426 /* Reset offset to start of reply */
427 resp.chain_offset = 0;
428 mbuf = resp.chain;
429
430 /*
431 * Calculate MAC signature
432 */
433 if (smb_sign_calc(&resp, sign, sr->reply_seqnum, signature) != 0) {
434 cmn_err(CE_WARN, "smb_sign_reply: error in smb_sign_calc");
435 return;
436 }
437
438 /*
439 * Put signature in the response
440 *
441 * First find start of signature in chain (offset + signature offset)
442 */
443 offset += SMB_SIG_OFFS;
444 while (offset >= mbuf->m_len) {
445 offset -= mbuf->m_len;
446 mbuf = mbuf->m_next;
447 }
448
449 while (size >= mbuf->m_len - offset) {
450 (void) memcpy(&mbuf->m_data[offset],
451 sig_ptr, mbuf->m_len - offset);
452 offset = 0;
453 sig_ptr += mbuf->m_len - offset;
454 size -= mbuf->m_len - offset;
455 mbuf = mbuf->m_next;
456 }
457 if (size > 0) {
458 (void) memcpy(&mbuf->m_data[offset], sig_ptr, size);
459 }
460 }
461