SMB Signing with NTLMv2 works!
[tprouty/samba.git] / source / 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          * We put the sequence into the packet, becouse we are going
116          * to copy over it anyway.
117          */
118         SIVAL(cli->outbuf, smb_ss_field, 
119               data->send_seq_num);
120         SIVAL(cli->outbuf, smb_ss_field + 4, 0);
121
122         /* mark the packet as signed - BEFORE we sign it...*/
123         mark_packet_signed(cli);
124
125         /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
126         MD5Init(&md5_ctx);
127         MD5Update(&md5_ctx, data->mac_key.data, 
128                   data->mac_key.length); 
129         MD5Update(&md5_ctx, cli->outbuf + 4, smb_len(cli->outbuf));
130         MD5Final(calc_md5_mac, &md5_ctx);
131
132         DEBUG(10, ("sent SMB signature of\n"));
133         dump_data(10, calc_md5_mac, 8);
134
135         memcpy(&cli->outbuf[smb_ss_field], calc_md5_mac, 8);
136
137 /*      cli->outbuf[smb_ss_field+2]=0; 
138         Uncomment this to test if the remote server actually verifies signatures...*/
139         data->send_seq_num++;
140         data->reply_seq_num = data->send_seq_num;
141         data->send_seq_num++;
142 }
143
144 /***********************************************************
145  SMB signing - Simple implementation - check a MAC sent by server.
146 ************************************************************/
147
148 static BOOL cli_simple_check_incoming_message(struct cli_state *cli)
149 {
150         BOOL good;
151         unsigned char calc_md5_mac[16];
152         unsigned char server_sent_mac[8];
153         unsigned char sequence_buf[8];
154         struct MD5Context md5_ctx;
155         struct smb_basic_signing_context *data = cli->sign_info.signing_context;
156         const size_t offset_end_of_sig = (smb_ss_field + 8);
157
158         /*
159          * Firstly put the sequence number into the first 4 bytes.
160          * and zero out the next 4 bytes.
161          *
162          * We do this here, to avoid modifying the packet.
163          */
164
165         SIVAL(sequence_buf, 0, data->reply_seq_num);
166         SIVAL(sequence_buf, 4, 0);
167
168         /* get a copy of the server-sent mac */
169         memcpy(server_sent_mac, &cli->inbuf[smb_ss_field], sizeof(server_sent_mac));
170         
171         /* Calculate the 16 byte MAC - but don't alter the data in the
172            incoming packet.
173            
174            This makes for a bit for fussing about, but it's not too bad.
175         */
176         MD5Init(&md5_ctx);
177
178         /* intialise with the key */
179         MD5Update(&md5_ctx, data->mac_key.data, 
180                   data->mac_key.length); 
181
182         /* copy in the first bit of the SMB header */
183         MD5Update(&md5_ctx, cli->inbuf + 4, smb_ss_field - 4);
184
185         /* copy in the sequence number, instead of the signature */
186         MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
187
188         /* copy in the rest of the packet in, skipping the signature */
189         MD5Update(&md5_ctx, cli->inbuf + offset_end_of_sig, 
190                   smb_len(cli->inbuf) - (offset_end_of_sig - 4));
191
192         /* caclulate the MD5 sig */ 
193         MD5Final(calc_md5_mac, &md5_ctx);
194
195         good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
196         
197         if (!good) {
198                 DEBUG(5, ("BAD SIG: wanted SMB signature of\n"));
199                 dump_data(5, calc_md5_mac, 8);
200                 
201                 DEBUG(5, ("BAD SIG: got SMB signature of\n"));
202                 dump_data(5, server_sent_mac, 8);
203         }
204         return signing_good(cli, good);
205 }
206
207 /***********************************************************
208  SMB signing - Simple implementation - free signing context
209 ************************************************************/
210
211 static void cli_simple_free_signing_context(struct cli_state *cli)
212 {
213         struct smb_basic_signing_context *data = cli->sign_info.signing_context;
214
215         data_blob_free(&data->mac_key);
216         SAFE_FREE(cli->sign_info.signing_context);
217
218         return;
219 }
220
221 /***********************************************************
222  SMB signing - Simple implementation - setup the MAC key.
223 ************************************************************/
224
225 BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response)
226 {
227         struct smb_basic_signing_context *data;
228
229         if (!set_smb_signing_common(cli)) {
230                 return False;
231         }
232
233         if (!set_smb_signing_real_common(cli)) {
234                 return False;
235         }
236
237         data = smb_xmalloc(sizeof(*data));
238         cli->sign_info.signing_context = data;
239         
240         data->mac_key = data_blob(NULL, response.length + 16);
241
242         memcpy(&data->mac_key.data[0], user_session_key, 16);
243         memcpy(&data->mac_key.data[16],response.data, response.length);
244
245         /* Initialise the sequence number */
246         data->send_seq_num = 0;
247
248         cli->sign_info.sign_outgoing_message = cli_simple_sign_outgoing_message;
249         cli->sign_info.check_incoming_message = cli_simple_check_incoming_message;
250         cli->sign_info.free_signing_context = cli_simple_free_signing_context;
251
252         return True;
253 }
254
255 /***********************************************************
256  SMB signing - NTLMSSP implementation - calculate a MAC to send.
257 ************************************************************/
258
259 static void cli_ntlmssp_sign_outgoing_message(struct cli_state *cli)
260 {
261         NTSTATUS nt_status;
262         DATA_BLOB sig;
263         NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
264
265         /* mark the packet as signed - BEFORE we sign it...*/
266         mark_packet_signed(cli);
267         
268         nt_status = ntlmssp_client_sign_packet(ntlmssp_state, cli->outbuf + 4, 
269                                                smb_len(cli->outbuf), &sig);
270         
271         if (!NT_STATUS_IS_OK(nt_status)) {
272                 DEBUG(0, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
273                 return;
274         }
275
276         DEBUG(10, ("sent SMB signature of\n"));
277         dump_data(10, sig.data, MIN(sig.length, 8));
278         memcpy(&cli->outbuf[smb_ss_field], sig.data, MIN(sig.length, 8));
279         
280         data_blob_free(&sig);
281 }
282
283 /***********************************************************
284  SMB signing - NTLMSSP implementation - check a MAC sent by server.
285 ************************************************************/
286
287 static BOOL cli_ntlmssp_check_incoming_message(struct cli_state *cli)
288 {
289         BOOL good;
290         NTSTATUS nt_status;
291         DATA_BLOB sig = data_blob(&cli->inbuf[smb_ss_field], 8);
292
293         NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
294
295         nt_status = ntlmssp_client_check_packet(ntlmssp_state, cli->outbuf + 4, 
296                                                 smb_len(cli->outbuf), &sig);
297         
298         data_blob_free(&sig);
299         
300         good = NT_STATUS_IS_OK(nt_status);
301         if (!NT_STATUS_IS_OK(nt_status)) {
302                 DEBUG(5, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
303         }
304
305         return signing_good(cli, good);
306 }
307
308 /***********************************************************
309  SMB signing - NTLMSSP implementation - free signing context
310 ************************************************************/
311
312 static void cli_ntlmssp_free_signing_context(struct cli_state *cli)
313 {
314         ntlmssp_client_end((NTLMSSP_CLIENT_STATE **)&cli->sign_info.signing_context);
315 }
316
317 /***********************************************************
318  SMB signing - NTLMSSP implementation - setup the MAC key.
319 ************************************************************/
320
321 BOOL cli_ntlmssp_set_signing(struct cli_state *cli,
322                              NTLMSSP_CLIENT_STATE *ntlmssp_state)
323 {
324         if (!set_smb_signing_common(cli)) {
325                 return False;
326         }
327
328         if (!NT_STATUS_IS_OK(ntlmssp_client_sign_init(ntlmssp_state))) {
329                 return False;
330         }
331
332         if (!set_smb_signing_real_common(cli)) {
333                 return False;
334         }
335
336         cli->sign_info.signing_context = ntlmssp_state;
337         ntlmssp_state->ref_count++;
338
339         cli->sign_info.sign_outgoing_message = cli_ntlmssp_sign_outgoing_message;
340         cli->sign_info.check_incoming_message = cli_ntlmssp_check_incoming_message;
341         cli->sign_info.free_signing_context = cli_ntlmssp_free_signing_context;
342
343         return True;
344 }
345
346 /***********************************************************
347  SMB signing - NULL implementation - calculate a MAC to send.
348 ************************************************************/
349
350 static void cli_null_sign_outgoing_message(struct cli_state *cli)
351 {
352         /* we can't zero out the sig, as we might be trying to send a
353            session request - which is NBT-level, not SMB level and doesn't
354            have the field */
355         return;
356 }
357
358 /***********************************************************
359  SMB signing - NULL implementation - check a MAC sent by server.
360 ************************************************************/
361
362 static BOOL cli_null_check_incoming_message(struct cli_state *cli)
363 {
364         return True;
365 }
366
367 /***********************************************************
368  SMB signing - NULL implementation - free signing context
369 ************************************************************/
370
371 static void cli_null_free_signing_context(struct cli_state *cli)
372 {
373         return;
374 }
375
376 /**
377  SMB signing - NULL implementation - setup the MAC key.
378
379  @note Used as an initialisation only - it will not correctly
380        shut down a real signing mechanism
381 */
382
383 BOOL cli_null_set_signing(struct cli_state *cli)
384 {
385         cli->sign_info.signing_context = NULL;
386         
387         cli->sign_info.sign_outgoing_message = cli_null_sign_outgoing_message;
388         cli->sign_info.check_incoming_message = cli_null_check_incoming_message;
389         cli->sign_info.free_signing_context = cli_null_free_signing_context;
390
391         return True;
392 }
393
394 /***********************************************************
395  SMB signing - TEMP implementation - calculate a MAC to send.
396 ************************************************************/
397
398 static void cli_temp_sign_outgoing_message(struct cli_state *cli)
399 {
400         /* mark the packet as signed - BEFORE we sign it...*/
401         mark_packet_signed(cli);
402
403         /* I wonder what BSRSPYL stands for - but this is what MS 
404            actually sends! */
405         memcpy(&cli->outbuf[smb_ss_field], "BSRSPYL ", 8);
406         return;
407 }
408
409 /***********************************************************
410  SMB signing - TEMP implementation - check a MAC sent by server.
411 ************************************************************/
412
413 static BOOL cli_temp_check_incoming_message(struct cli_state *cli)
414 {
415         return True;
416 }
417
418 /***********************************************************
419  SMB signing - TEMP implementation - free signing context
420 ************************************************************/
421
422 static void cli_temp_free_signing_context(struct cli_state *cli)
423 {
424         return;
425 }
426
427 /***********************************************************
428  SMB signing - NULL implementation - setup the MAC key.
429 ************************************************************/
430
431 BOOL cli_temp_set_signing(struct cli_state *cli)
432 {
433         if (!set_smb_signing_common(cli)) {
434                 return False;
435         }
436
437         cli->sign_info.signing_context = NULL;
438         
439         cli->sign_info.sign_outgoing_message = cli_temp_sign_outgoing_message;
440         cli->sign_info.check_incoming_message = cli_temp_check_incoming_message;
441         cli->sign_info.free_signing_context = cli_temp_free_signing_context;
442
443         return True;
444 }
445
446 /**
447  * Free the signing context
448  */
449  
450 void cli_free_signing_context(struct cli_state *cli) 
451 {
452         if (cli->sign_info.free_signing_context) 
453                 cli->sign_info.free_signing_context(cli);
454
455         cli_null_set_signing(cli);
456 }
457
458 /**
459  * Sign a packet with the current mechanism
460  */
461  
462 void cli_caclulate_sign_mac(struct cli_state *cli)
463 {
464         cli->sign_info.sign_outgoing_message(cli);
465 }
466
467 /**
468  * Check a packet with the current mechanism
469  * @return False if we had an established signing connection
470  *         which had a back checksum, True otherwise
471  */
472  
473 BOOL cli_check_sign_mac(struct cli_state *cli) 
474 {
475         BOOL good;
476
477         if (smb_len(cli->inbuf) < (smb_ss_field + 8 - 4)) {
478                 DEBUG(cli->sign_info.doing_signing ? 1 : 10, ("Can't check signature on short packet! smb_len = %u\n", smb_len(cli->inbuf)));
479                 good = False;
480         } else {
481                 good = cli->sign_info.check_incoming_message(cli);
482         }
483
484         if (!good) {
485                 if (cli->sign_info.doing_signing) {
486                         return False;
487                 } else {
488                         cli_free_signing_context(cli);  
489                 }
490         }
491
492         return True;
493 }
494