SMB signing updates - this gets NTLMSSP signing workin to the point where I
[ira/wip.git] / source3 / libsmb / smb_signing.c
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
6    
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.
11    
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.
16    
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.
20 */
21
22 #include "includes.h"
23
24 struct smb_basic_signing_context {
25         DATA_BLOB mac_key;
26         uint32 send_seq_num;
27         uint32 reply_seq_num;
28 };
29
30 /***********************************************************
31  SMB signing - Common code before we set a new signing implementation
32 ************************************************************/
33
34 static BOOL set_smb_signing_common(struct cli_state *cli) 
35 {
36         if (!cli->sign_info.negotiated_smb_signing 
37             && !cli->sign_info.mandetory_signing) {
38                 return False;
39         }
40
41         if (cli->sign_info.doing_signing) {
42                 return False;
43         }
44         
45         if (cli->sign_info.free_signing_context)
46                 cli->sign_info.free_signing_context(cli);
47
48         /* These calls are INCOMPATIBLE with SMB signing */
49         cli->readbraw_supported = False;
50         cli->writebraw_supported = False;
51         
52         return True;
53 }
54
55 /***********************************************************
56  SMB signing - Common code for 'real' implementations
57 ************************************************************/
58
59 static BOOL set_smb_signing_real_common(struct cli_state *cli) 
60 {
61         if (cli->sign_info.mandetory_signing) {
62                 DEBUG(5, ("Mandatory SMB signing enabled!\n"));
63                 cli->sign_info.doing_signing = True;
64         }
65
66         DEBUG(5, ("SMB signing enabled!\n"));
67
68         return True;
69 }
70
71 static void mark_packet_signed(struct cli_state *cli) 
72 {
73         uint16 flags2;
74         flags2 = SVAL(cli->outbuf,smb_flg2);
75         flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
76         SSVAL(cli->outbuf,smb_flg2, flags2);
77 }
78
79 static BOOL signing_good(struct cli_state *cli, BOOL good) 
80 {
81         DEBUG(10, ("got SMB signature of\n"));
82         dump_data(10,&cli->inbuf[smb_ss_field] , 8);
83
84         if (good && !cli->sign_info.doing_signing) {
85                 cli->sign_info.doing_signing = True;
86         }
87
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;
96                 }
97         }
98         return True;
99 }       
100
101 /***********************************************************
102  SMB signing - Simple implementation - calculate a MAC to send.
103 ************************************************************/
104
105 static void cli_simple_sign_outgoing_message(struct cli_state *cli)
106 {
107         unsigned char calc_md5_mac[16];
108         struct MD5Context md5_ctx;
109         struct smb_basic_signing_context *data = cli->sign_info.signing_context;
110
111         /*
112          * Firstly put the sequence number into the first 4 bytes.
113          * and zero out the next 4 bytes.
114          */
115         SIVAL(cli->outbuf, smb_ss_field, 
116               data->send_seq_num);
117         SIVAL(cli->outbuf, smb_ss_field + 4, 0);
118
119         /* mark the packet as signed - BEFORE we sign it...*/
120         mark_packet_signed(cli);
121
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);
128
129         DEBUG(10, ("sent SMB signature of\n"));
130         dump_data(10, calc_md5_mac, 8);
131
132         memcpy(&cli->outbuf[smb_ss_field], calc_md5_mac, 8);
133
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++;
139 }
140
141 /***********************************************************
142  SMB signing - Simple implementation - check a MAC sent by server.
143 ************************************************************/
144
145 static BOOL cli_simple_check_incoming_message(struct cli_state *cli)
146 {
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);
154
155         /*
156          * Firstly put the sequence number into the first 4 bytes.
157          * and zero out the next 4 bytes.
158          */
159
160         SIVAL(sequence_buf, 0, data->reply_seq_num);
161         SIVAL(sequence_buf, 4, 0);
162
163         /* get a copy of the server-sent mac */
164         memcpy(server_sent_mac, &cli->inbuf[smb_ss_field], sizeof(server_sent_mac));
165         
166         /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
167         MD5Init(&md5_ctx);
168         MD5Update(&md5_ctx, data->mac_key.data, 
169                   data->mac_key.length); 
170         MD5Update(&md5_ctx, cli->inbuf + 4, smb_ss_field - 4);
171         MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
172         
173         MD5Update(&md5_ctx, cli->inbuf + offset_end_of_sig, 
174                   smb_len(cli->inbuf) - (offset_end_of_sig - 4));
175         MD5Final(calc_md5_mac, &md5_ctx);
176
177         good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
178         
179         if (!good) {
180                 DEBUG(5, ("BAD SIG: wanted SMB signature of\n"));
181                 dump_data(5, calc_md5_mac, 8);
182                 
183                 DEBUG(5, ("BAD SIG: got SMB signature of\n"));
184                 dump_data(5, server_sent_mac, 8);
185         }
186         return signing_good(cli, good);
187 }
188
189 /***********************************************************
190  SMB signing - Simple implementation - free signing context
191 ************************************************************/
192
193 static void cli_simple_free_signing_context(struct cli_state *cli)
194 {
195         struct smb_basic_signing_context *data = cli->sign_info.signing_context;
196
197         data_blob_free(&data->mac_key);
198         SAFE_FREE(cli->sign_info.signing_context);
199
200         return;
201 }
202
203 /***********************************************************
204  SMB signing - Simple implementation - setup the MAC key.
205 ************************************************************/
206
207 BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response)
208 {
209         struct smb_basic_signing_context *data;
210
211         if (!set_smb_signing_common(cli)) {
212                 return False;
213         }
214
215         if (!set_smb_signing_real_common(cli)) {
216                 return False;
217         }
218
219         data = smb_xmalloc(sizeof(*data));
220         cli->sign_info.signing_context = data;
221         
222         data->mac_key = data_blob(NULL, MIN(response.length + 16, 40));
223
224         memcpy(&data->mac_key.data[0], user_session_key, 16);
225         memcpy(&data->mac_key.data[16],response.data, MIN(response.length, 40 - 16));
226
227         /* Initialise the sequence number */
228         data->send_seq_num = 0;
229
230         cli->sign_info.sign_outgoing_message = cli_simple_sign_outgoing_message;
231         cli->sign_info.check_incoming_message = cli_simple_check_incoming_message;
232         cli->sign_info.free_signing_context = cli_simple_free_signing_context;
233
234         return True;
235 }
236
237 /***********************************************************
238  SMB signing - NTLMSSP implementation - calculate a MAC to send.
239 ************************************************************/
240
241 static void cli_ntlmssp_sign_outgoing_message(struct cli_state *cli)
242 {
243         NTSTATUS nt_status;
244         DATA_BLOB sig;
245         NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
246
247         /* mark the packet as signed - BEFORE we sign it...*/
248         mark_packet_signed(cli);
249         
250         nt_status = ntlmssp_client_sign_packet(ntlmssp_state, cli->outbuf + 4, 
251                                                smb_len(cli->outbuf), &sig);
252         
253         if (!NT_STATUS_IS_OK(nt_status)) {
254                 DEBUG(0, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
255                 return;
256         }
257
258         DEBUG(10, ("sent SMB signature of\n"));
259         dump_data(10, sig.data, MIN(sig.length, 8));
260         memcpy(&cli->outbuf[smb_ss_field], sig.data, MIN(sig.length, 8));
261         
262         data_blob_free(&sig);
263 }
264
265 /***********************************************************
266  SMB signing - NTLMSSP implementation - check a MAC sent by server.
267 ************************************************************/
268
269 static BOOL cli_ntlmssp_check_incoming_message(struct cli_state *cli)
270 {
271         BOOL good;
272         NTSTATUS nt_status;
273         DATA_BLOB sig = data_blob(&cli->inbuf[smb_ss_field], 8);
274
275         NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
276
277         nt_status = ntlmssp_client_check_packet(ntlmssp_state, cli->outbuf + 4, 
278                                                 smb_len(cli->outbuf), &sig);
279         
280         data_blob_free(&sig);
281         
282         good = NT_STATUS_IS_OK(nt_status);
283         if (!NT_STATUS_IS_OK(nt_status)) {
284                 DEBUG(5, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
285         }
286
287         return signing_good(cli, good);
288 }
289
290 /***********************************************************
291  SMB signing - NTLMSSP implementation - free signing context
292 ************************************************************/
293
294 static void cli_ntlmssp_free_signing_context(struct cli_state *cli)
295 {
296         ntlmssp_client_end((NTLMSSP_CLIENT_STATE **)&cli->sign_info.signing_context);
297 }
298
299 /***********************************************************
300  SMB signing - NTLMSSP implementation - setup the MAC key.
301 ************************************************************/
302
303 BOOL cli_ntlmssp_set_signing(struct cli_state *cli,
304                              NTLMSSP_CLIENT_STATE *ntlmssp_state)
305 {
306         if (!set_smb_signing_common(cli)) {
307                 return False;
308         }
309
310         if (!NT_STATUS_IS_OK(ntlmssp_client_sign_init(ntlmssp_state))) {
311                 return False;
312         }
313
314         if (!set_smb_signing_real_common(cli)) {
315                 return False;
316         }
317
318         cli->sign_info.signing_context = ntlmssp_state;
319         ntlmssp_state->ref_count++;
320
321         cli->sign_info.sign_outgoing_message = cli_ntlmssp_sign_outgoing_message;
322         cli->sign_info.check_incoming_message = cli_ntlmssp_check_incoming_message;
323         cli->sign_info.free_signing_context = cli_ntlmssp_free_signing_context;
324
325         return True;
326 }
327
328 /***********************************************************
329  SMB signing - NULL implementation - calculate a MAC to send.
330 ************************************************************/
331
332 static void cli_null_sign_outgoing_message(struct cli_state *cli)
333 {
334         /* we can't zero out the sig, as we might be trying to send a
335            session request - which is NBT-level, not SMB level and doesn't
336            have the field */
337         return;
338 }
339
340 /***********************************************************
341  SMB signing - NULL implementation - check a MAC sent by server.
342 ************************************************************/
343
344 static BOOL cli_null_check_incoming_message(struct cli_state *cli)
345 {
346         return True;
347 }
348
349 /***********************************************************
350  SMB signing - NULL implementation - free signing context
351 ************************************************************/
352
353 static void cli_null_free_signing_context(struct cli_state *cli)
354 {
355         return;
356 }
357
358 /**
359  SMB signing - NULL implementation - setup the MAC key.
360
361  @note Used as an initialisation only - it will not correctly
362        shut down a real signing mechanism
363 */
364
365 BOOL cli_null_set_signing(struct cli_state *cli)
366 {
367         cli->sign_info.signing_context = NULL;
368         
369         cli->sign_info.sign_outgoing_message = cli_null_sign_outgoing_message;
370         cli->sign_info.check_incoming_message = cli_null_check_incoming_message;
371         cli->sign_info.free_signing_context = cli_null_free_signing_context;
372
373         return True;
374 }
375
376 /***********************************************************
377  SMB signing - TEMP implementation - calculate a MAC to send.
378 ************************************************************/
379
380 static void cli_temp_sign_outgoing_message(struct cli_state *cli)
381 {
382         /* mark the packet as signed - BEFORE we sign it...*/
383         mark_packet_signed(cli);
384
385         /* I wonder what BSRSPYL stands for - but this is what MS 
386            actually sends! */
387         memcpy(&cli->outbuf[smb_ss_field], "BSRSPYL ", 8);
388         return;
389 }
390
391 /***********************************************************
392  SMB signing - TEMP implementation - check a MAC sent by server.
393 ************************************************************/
394
395 static BOOL cli_temp_check_incoming_message(struct cli_state *cli)
396 {
397         return True;
398 }
399
400 /***********************************************************
401  SMB signing - TEMP implementation - free signing context
402 ************************************************************/
403
404 static void cli_temp_free_signing_context(struct cli_state *cli)
405 {
406         return;
407 }
408
409 /***********************************************************
410  SMB signing - NULL implementation - setup the MAC key.
411 ************************************************************/
412
413 BOOL cli_temp_set_signing(struct cli_state *cli)
414 {
415         if (!set_smb_signing_common(cli)) {
416                 return False;
417         }
418
419         cli->sign_info.signing_context = NULL;
420         
421         cli->sign_info.sign_outgoing_message = cli_temp_sign_outgoing_message;
422         cli->sign_info.check_incoming_message = cli_temp_check_incoming_message;
423         cli->sign_info.free_signing_context = cli_temp_free_signing_context;
424
425         return True;
426 }
427
428 /**
429  * Free the signing context
430  */
431  
432 void cli_free_signing_context(struct cli_state *cli) 
433 {
434         if (cli->sign_info.free_signing_context) 
435                 cli->sign_info.free_signing_context(cli);
436
437         cli_null_set_signing(cli);
438 }
439
440 /**
441  * Sign a packet with the current mechanism
442  */
443  
444 void cli_caclulate_sign_mac(struct cli_state *cli)
445 {
446         cli->sign_info.sign_outgoing_message(cli);
447 }
448
449 /**
450  * Check a packet with the current mechanism
451  * @return False if we had an established signing connection
452  *         which had a back checksum, True otherwise
453  */
454  
455 BOOL cli_check_sign_mac(struct cli_state *cli) 
456 {
457         BOOL good;
458
459         if (smb_len(cli->inbuf) < (smb_ss_field + 8 - 4)) {
460                 DEBUG(1, ("Can't check signature on short packet! smb_len = %u\n", smb_len(cli->inbuf)));
461                 good = False;
462         } else {
463                 good = cli->sign_info.check_incoming_message(cli);
464         }
465
466         if (!good) {
467                 if (cli->sign_info.doing_signing) {
468                         return False;
469                 } else {
470                         cli_free_signing_context(cli);  
471                 }
472         }
473
474         return True;
475 }
476