Merge a trivial fix across from HEAD. Not that this
[Samba.git] / source / libsmb / smb_signing.c
blob9b473fa736111fa408150c398d8cd9cf05cf1757
1 /*
2 Unix SMB/CIFS implementation.
3 SMB Signing Code
4 Copyright (C) Jeremy Allison 2002.
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
24 struct smb_basic_signing_context {
25 DATA_BLOB mac_key;
26 uint32 send_seq_num;
27 uint32 reply_seq_num;
30 /***********************************************************
31 SMB signing - Common code before we set a new signing implementation
32 ************************************************************/
34 static BOOL set_smb_signing_common(struct cli_state *cli)
36 if (!cli->sign_info.negotiated_smb_signing
37 && !cli->sign_info.mandetory_signing) {
38 return False;
41 if (cli->sign_info.doing_signing) {
42 return False;
45 if (cli->sign_info.free_signing_context)
46 cli->sign_info.free_signing_context(cli);
48 /* These calls are INCOMPATIBLE with SMB signing */
49 cli->readbraw_supported = False;
50 cli->writebraw_supported = False;
52 return True;
55 /***********************************************************
56 SMB signing - Common code for 'real' implementations
57 ************************************************************/
59 static BOOL set_smb_signing_real_common(struct cli_state *cli)
61 if (cli->sign_info.mandetory_signing) {
62 DEBUG(5, ("Mandatory SMB signing enabled!\n"));
63 cli->sign_info.doing_signing = True;
66 DEBUG(5, ("SMB signing enabled!\n"));
68 return True;
71 static void mark_packet_signed(struct cli_state *cli)
73 uint16 flags2;
74 flags2 = SVAL(cli->outbuf,smb_flg2);
75 flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
76 SSVAL(cli->outbuf,smb_flg2, flags2);
79 static BOOL signing_good(struct cli_state *cli, BOOL good)
81 DEBUG(10, ("got SMB signature of\n"));
82 dump_data(10,&cli->inbuf[smb_ss_field] , 8);
84 if (good && !cli->sign_info.doing_signing) {
85 cli->sign_info.doing_signing = True;
88 if (!good) {
89 if (cli->sign_info.doing_signing) {
90 DEBUG(1, ("SMB signature check failed!\n"));
91 return False;
92 } else {
93 DEBUG(3, ("Server did not sign reply correctly\n"));
94 cli_free_signing_context(cli);
95 return False;
98 return True;
101 /***********************************************************
102 SMB signing - Simple implementation - calculate a MAC to send.
103 ************************************************************/
105 static void cli_simple_sign_outgoing_message(struct cli_state *cli)
107 unsigned char calc_md5_mac[16];
108 struct MD5Context md5_ctx;
109 struct smb_basic_signing_context *data = cli->sign_info.signing_context;
112 * Firstly put the sequence number into the first 4 bytes.
113 * and zero out the next 4 bytes.
115 SIVAL(cli->outbuf, smb_ss_field,
116 data->send_seq_num);
117 SIVAL(cli->outbuf, smb_ss_field + 4, 0);
119 /* mark the packet as signed - BEFORE we sign it...*/
120 mark_packet_signed(cli);
122 /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
123 MD5Init(&md5_ctx);
124 MD5Update(&md5_ctx, data->mac_key.data,
125 data->mac_key.length);
126 MD5Update(&md5_ctx, cli->outbuf + 4, smb_len(cli->outbuf));
127 MD5Final(calc_md5_mac, &md5_ctx);
129 DEBUG(10, ("sent SMB signature of\n"));
130 dump_data(10, calc_md5_mac, 8);
132 memcpy(&cli->outbuf[smb_ss_field], calc_md5_mac, 8);
134 /* cli->outbuf[smb_ss_field+2]=0;
135 Uncomment this to test if the remote server actually verifies signitures...*/
136 data->send_seq_num++;
137 data->reply_seq_num = data->send_seq_num;
138 data->send_seq_num++;
141 /***********************************************************
142 SMB signing - Simple implementation - check a MAC sent by server.
143 ************************************************************/
145 static BOOL cli_simple_check_incoming_message(struct cli_state *cli)
147 BOOL good;
148 unsigned char calc_md5_mac[16];
149 unsigned char server_sent_mac[8];
150 unsigned char sequence_buf[8];
151 struct MD5Context md5_ctx;
152 struct smb_basic_signing_context *data = cli->sign_info.signing_context;
153 const size_t offset_end_of_sig = (smb_ss_field + 8);
156 * Firstly put the sequence number into the first 4 bytes.
157 * and zero out the next 4 bytes.
160 SIVAL(sequence_buf, 0, data->reply_seq_num);
161 SIVAL(sequence_buf, 4, 0);
163 if (smb_len(cli->inbuf) < (offset_end_of_sig - 4)) {
164 DEBUG(1, ("Can't check signature on short packet! smb_len = %u\n", smb_len(cli->inbuf)));
165 return False;
168 /* get a copy of the server-sent mac */
169 memcpy(server_sent_mac, &cli->inbuf[smb_ss_field], sizeof(server_sent_mac));
171 /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
172 MD5Init(&md5_ctx);
173 MD5Update(&md5_ctx, data->mac_key.data,
174 data->mac_key.length);
175 MD5Update(&md5_ctx, cli->inbuf + 4, smb_ss_field - 4);
176 MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
178 MD5Update(&md5_ctx, cli->inbuf + offset_end_of_sig,
179 smb_len(cli->inbuf) - (offset_end_of_sig - 4));
180 MD5Final(calc_md5_mac, &md5_ctx);
182 good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
184 if (!good) {
185 DEBUG(5, ("BAD SIG: wanted SMB signature of\n"));
186 dump_data(5, calc_md5_mac, 8);
188 DEBUG(5, ("BAD SIG: got SMB signature of\n"));
189 dump_data(5, server_sent_mac, 8);
191 return signing_good(cli, good);
194 /***********************************************************
195 SMB signing - Simple implementation - free signing context
196 ************************************************************/
198 static void cli_simple_free_signing_context(struct cli_state *cli)
200 struct smb_basic_signing_context *data = cli->sign_info.signing_context;
202 data_blob_free(&data->mac_key);
203 SAFE_FREE(cli->sign_info.signing_context);
205 return;
208 /***********************************************************
209 SMB signing - Simple implementation - setup the MAC key.
210 ************************************************************/
212 BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response)
214 struct smb_basic_signing_context *data;
216 if (!set_smb_signing_common(cli)) {
217 return False;
220 if (!set_smb_signing_real_common(cli)) {
221 return False;
224 data = smb_xmalloc(sizeof(*data));
225 cli->sign_info.signing_context = data;
227 data->mac_key = data_blob(NULL, MIN(response.length + 16, 40));
229 memcpy(&data->mac_key.data[0], user_session_key, 16);
230 memcpy(&data->mac_key.data[16],response.data, MIN(response.length, 40 - 16));
232 /* Initialise the sequence number */
233 data->send_seq_num = 0;
235 cli->sign_info.sign_outgoing_message = cli_simple_sign_outgoing_message;
236 cli->sign_info.check_incoming_message = cli_simple_check_incoming_message;
237 cli->sign_info.free_signing_context = cli_simple_free_signing_context;
239 return True;
242 /***********************************************************
243 SMB signing - NTLMSSP implementation - calculate a MAC to send.
244 ************************************************************/
246 static void cli_ntlmssp_sign_outgoing_message(struct cli_state *cli)
248 NTSTATUS nt_status;
249 DATA_BLOB sig;
250 NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
252 /* mark the packet as signed - BEFORE we sign it...*/
253 mark_packet_signed(cli);
255 nt_status = ntlmssp_client_sign_packet(ntlmssp_state, cli->outbuf + 4,
256 smb_len(cli->outbuf), &sig);
258 if (!NT_STATUS_IS_OK(nt_status)) {
259 DEBUG(0, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
260 return;
263 DEBUG(10, ("sent SMB signature of\n"));
264 dump_data(10, sig.data, MIN(sig.length, 8));
265 memcpy(&cli->outbuf[smb_ss_field], sig.data, MIN(sig.length, 8));
267 data_blob_free(&sig);
270 /***********************************************************
271 SMB signing - NTLMSSP implementation - check a MAC sent by server.
272 ************************************************************/
274 static BOOL cli_ntlmssp_check_incoming_message(struct cli_state *cli)
276 BOOL good;
277 NTSTATUS nt_status;
278 DATA_BLOB sig = data_blob(&cli->inbuf[smb_ss_field], 8);
280 NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
282 nt_status = ntlmssp_client_check_packet(ntlmssp_state, cli->outbuf + 4,
283 smb_len(cli->outbuf), &sig);
285 data_blob_free(&sig);
287 good = NT_STATUS_IS_OK(nt_status);
288 if (!NT_STATUS_IS_OK(nt_status)) {
289 DEBUG(5, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
292 return signing_good(cli, good);
295 /***********************************************************
296 SMB signing - NTLMSSP implementation - free signing context
297 ************************************************************/
299 static void cli_ntlmssp_free_signing_context(struct cli_state *cli)
301 ntlmssp_client_end((NTLMSSP_CLIENT_STATE **)&cli->sign_info.signing_context);
304 /***********************************************************
305 SMB signing - NTLMSSP implementation - setup the MAC key.
306 ************************************************************/
308 BOOL cli_ntlmssp_set_signing(struct cli_state *cli,
309 NTLMSSP_CLIENT_STATE *ntlmssp_state)
311 if (!set_smb_signing_common(cli)) {
312 return False;
315 if (!NT_STATUS_IS_OK(ntlmssp_client_sign_init(ntlmssp_state))) {
316 return False;
319 if (!set_smb_signing_real_common(cli)) {
320 return False;
323 cli->sign_info.signing_context = ntlmssp_state;
324 ntlmssp_state->ref_count++;
326 cli->sign_info.sign_outgoing_message = cli_ntlmssp_sign_outgoing_message;
327 cli->sign_info.check_incoming_message = cli_ntlmssp_check_incoming_message;
328 cli->sign_info.free_signing_context = cli_ntlmssp_free_signing_context;
330 return True;
333 /***********************************************************
334 SMB signing - NULL implementation - calculate a MAC to send.
335 ************************************************************/
337 static void cli_null_sign_outgoing_message(struct cli_state *cli)
339 /* we can't zero out the sig, as we might be trying to send a
340 session request - which is NBT-level, not SMB level and doesn't
341 have the field */
342 return;
345 /***********************************************************
346 SMB signing - NULL implementation - check a MAC sent by server.
347 ************************************************************/
349 static BOOL cli_null_check_incoming_message(struct cli_state *cli)
351 return True;
354 /***********************************************************
355 SMB signing - NULL implementation - free signing context
356 ************************************************************/
358 static void cli_null_free_signing_context(struct cli_state *cli)
360 return;
364 SMB signing - NULL implementation - setup the MAC key.
366 @note Used as an initialisation only - it will not correctly
367 shut down a real signing mechanism
370 BOOL cli_null_set_signing(struct cli_state *cli)
372 cli->sign_info.signing_context = NULL;
374 cli->sign_info.sign_outgoing_message = cli_null_sign_outgoing_message;
375 cli->sign_info.check_incoming_message = cli_null_check_incoming_message;
376 cli->sign_info.free_signing_context = cli_null_free_signing_context;
378 return True;
381 /***********************************************************
382 SMB signing - TEMP implementation - calculate a MAC to send.
383 ************************************************************/
385 static void cli_temp_sign_outgoing_message(struct cli_state *cli)
387 /* mark the packet as signed - BEFORE we sign it...*/
388 mark_packet_signed(cli);
390 /* I wonder what BSRSPYL stands for - but this is what MS
391 actually sends! */
392 memcpy(&cli->outbuf[smb_ss_field], "BSRSPYL ", 8);
393 return;
396 /***********************************************************
397 SMB signing - TEMP implementation - check a MAC sent by server.
398 ************************************************************/
400 static BOOL cli_temp_check_incoming_message(struct cli_state *cli)
402 return True;
405 /***********************************************************
406 SMB signing - TEMP implementation - free signing context
407 ************************************************************/
409 static void cli_temp_free_signing_context(struct cli_state *cli)
411 return;
414 /***********************************************************
415 SMB signing - NULL implementation - setup the MAC key.
416 ************************************************************/
418 BOOL cli_temp_set_signing(struct cli_state *cli)
420 if (!set_smb_signing_common(cli)) {
421 return False;
424 cli->sign_info.signing_context = NULL;
426 cli->sign_info.sign_outgoing_message = cli_temp_sign_outgoing_message;
427 cli->sign_info.check_incoming_message = cli_temp_check_incoming_message;
428 cli->sign_info.free_signing_context = cli_temp_free_signing_context;
430 return True;
434 * Free the signing context
437 void cli_free_signing_context(struct cli_state *cli)
439 if (cli->sign_info.free_signing_context)
440 cli->sign_info.free_signing_context(cli);
442 cli_null_set_signing(cli);
446 * Sign a packet with the current mechanism
449 void cli_caclulate_sign_mac(struct cli_state *cli)
451 cli->sign_info.sign_outgoing_message(cli);
455 * Check a packet with the current mechanism
456 * @return False if we had an established signing connection
457 * which had a back checksum, True otherwise
460 BOOL cli_check_sign_mac(struct cli_state *cli)
462 BOOL good;
463 good = cli->sign_info.check_incoming_message(cli);
465 if (!good) {
466 if (cli->sign_info.doing_signing) {
467 return False;
468 } else {
469 cli_free_signing_context(cli);
473 return True;