r1768: Add some debugs to assist in SMB signing debugging.
[samba.git] / source4 / libcli / raw / 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    Copyright (C) James J Myers <myersjj@samba.org> 2003
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 static BOOL smbcli_set_signing_off(struct smb_signing_context *sign_info);
25
26 /***********************************************************
27  SMB signing - Common code before we set a new signing implementation
28 ************************************************************/
29 static BOOL set_smb_signing_common(struct smbcli_transport *transport)
30 {
31         if (!(transport->negotiate.sec_mode & 
32               (NEGOTIATE_SECURITY_SIGNATURES_REQUIRED|NEGOTIATE_SECURITY_SIGNATURES_ENABLED))) {
33                 DEBUG(5, ("SMB Signing is not negotiated by the peer\n"));
34                 return False;
35         }
36
37         if (transport->negotiate.sign_info.doing_signing) {
38                 DEBUG(5, ("SMB Signing already in progress, so we don't start it again\n"));
39                 return False;
40         }
41
42         if (!transport->negotiate.sign_info.allow_smb_signing) {
43                 DEBUG(5, ("SMB Signing has been locally disabled\n"));
44                 return False;
45         }
46
47         /* These calls are INCOMPATIBLE with SMB signing */
48         transport->negotiate.readbraw_supported = False;
49         transport->negotiate.writebraw_supported = False;
50
51         return True;
52 }
53
54 static void mark_packet_signed(struct request_buffer *out) 
55 {
56         uint16_t flags2;
57         flags2 = SVAL(out->hdr, HDR_FLG2);
58         flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
59         SSVAL(out->hdr, HDR_FLG2, flags2);
60 }
61
62 static BOOL signing_good(struct smb_signing_context *sign_info, 
63                          unsigned int seq, BOOL good) 
64 {
65         if (good) {
66                 if (!sign_info->doing_signing) {
67                         DEBUG(5, ("Seen valid packet, so turning signing on\n"));
68                         sign_info->doing_signing = True;
69                 }
70                 if (!sign_info->seen_valid) {
71                         DEBUG(5, ("Seen valid packet, so marking signing as 'seen valid'\n"));
72                         sign_info->seen_valid = True;
73                 }
74         } else {
75                 if (!sign_info->seen_valid) {
76                         /* If we have never seen a good packet, just turn it off */
77                         DEBUG(5, ("signing_good: signing negotiated but not required and peer\n"
78                                   "isn't sending correct signatures. Turning off.\n"));
79                         smbcli_set_signing_off(sign_info);
80                         return True;
81                 } else {
82                         /* bad packet after signing started - fail and disconnect. */
83                         DEBUG(0, ("signing_good: BAD SIG: seq %u\n", seq));
84                         return False;
85                 }
86         }
87         return True;
88 }
89
90 void sign_outgoing_message(struct request_buffer *out, DATA_BLOB *mac_key, uint_t seq_num) 
91 {
92         uint8_t calc_md5_mac[16];
93         struct MD5Context md5_ctx;
94         /*
95          * Firstly put the sequence number into the first 4 bytes.
96          * and zero out the next 4 bytes.
97          */
98         SIVAL(out->hdr, HDR_SS_FIELD, seq_num);
99         SIVAL(out->hdr, HDR_SS_FIELD + 4, 0);
100
101         /* mark the packet as signed - BEFORE we sign it...*/
102         mark_packet_signed(out);
103
104         /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
105         MD5Init(&md5_ctx);
106         MD5Update(&md5_ctx, mac_key->data, 
107                   mac_key->length); 
108         MD5Update(&md5_ctx, 
109                   out->buffer + NBT_HDR_SIZE, 
110                   out->size - NBT_HDR_SIZE);
111         MD5Final(calc_md5_mac, &md5_ctx);
112
113         memcpy(&out->hdr[HDR_SS_FIELD], calc_md5_mac, 8);
114
115         DEBUG(5, ("sign_outgoing_message: SENT SIG (seq: %d): sent SMB signature of\n", 
116                   seq_num));
117         dump_data(5, calc_md5_mac, 8);
118 /*      req->out.hdr[HDR_SS_FIELD+2]=0; 
119         Uncomment this to test if the remote server actually verifies signitures...*/
120 }
121
122 BOOL check_signed_incoming_message(struct request_buffer *in, DATA_BLOB *mac_key, uint_t seq_num) 
123 {
124         BOOL good;
125         uint8_t calc_md5_mac[16];
126         uint8_t *server_sent_mac;
127         uint8_t sequence_buf[8];
128         struct MD5Context md5_ctx;
129         const size_t offset_end_of_sig = (HDR_SS_FIELD + 8);
130         int i;
131         const int sign_range = 0;
132
133         /* room enough for the signature? */
134         if (in->size < NBT_HDR_SIZE + HDR_SS_FIELD + 8) {
135                 return False;
136         }
137
138         if (!mac_key->length) {
139                 /* NO key yet */
140                 return False;
141         }
142
143         /* its quite bogus to be guessing sequence numbers, but very useful
144            when debugging signing implementations */
145         for (i = 0-sign_range; i <= 0+sign_range; i++) {
146                 /*
147                  * Firstly put the sequence number into the first 4 bytes.
148                  * and zero out the next 4 bytes.
149                  */
150                 SIVAL(sequence_buf, 0, seq_num + i);
151                 SIVAL(sequence_buf, 4, 0);
152                 
153                 /* get a copy of the server-sent mac */
154                 server_sent_mac = &in->hdr[HDR_SS_FIELD];
155                 
156                 /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
157                 MD5Init(&md5_ctx);
158                 MD5Update(&md5_ctx, mac_key->data, 
159                           mac_key->length); 
160                 MD5Update(&md5_ctx, in->hdr, HDR_SS_FIELD);
161                 MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
162                 
163                 MD5Update(&md5_ctx, in->hdr + offset_end_of_sig, 
164                           in->size - NBT_HDR_SIZE - (offset_end_of_sig));
165                 MD5Final(calc_md5_mac, &md5_ctx);
166                 
167                 good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
168
169                 if (good) break;
170         }
171
172         if (good && i != 0) {
173                 DEBUG(0,("SIGNING OFFSET %d (should be %d)\n", i, seq_num));
174         }
175
176         if (!good) {
177                 DEBUG(5, ("check_signed_incoming_message: BAD SIG (seq: %d): wanted SMB signature of\n", seq_num + i));
178                 dump_data(5, calc_md5_mac, 8);
179                 
180                 DEBUG(5, ("check_signed_incoming_message: BAD SIG (seq: %d): got SMB signature of\n", seq_num + i));
181                 dump_data(5, server_sent_mac, 8);
182         } else {
183                 DEBUG(15, ("check_signed_incoming_message: GOOD SIG (seq: %d): got SMB signature of\n", seq_num + i));
184                 dump_data(5, server_sent_mac, 8);
185         }
186         return good;
187 }
188
189 /***********************************************************
190  SMB signing - Simple implementation - calculate a MAC to send.
191 ************************************************************/
192 void smbcli_request_calculate_sign_mac(struct smbcli_request *req)
193 {
194 #if 0
195         /* enable this when packet signing is preventing you working out why valgrind 
196            says that data is uninitialised */
197         file_save("pkt.dat", req->out.buffer, req->out.size);
198 #endif
199
200         switch (req->transport->negotiate.sign_info.signing_state) {
201         case SMB_SIGNING_ENGINE_OFF:
202                 break;
203
204         case SMB_SIGNING_ENGINE_BSRSPYL:
205                 /* mark the packet as signed - BEFORE we sign it...*/
206                 mark_packet_signed(&req->out);
207                 
208                 /* I wonder what BSRSPYL stands for - but this is what MS 
209                    actually sends! */
210                 memcpy((req->out.hdr + HDR_SS_FIELD), "BSRSPYL ", 8);
211                 break;
212
213         case SMB_SIGNING_ENGINE_ON:
214                         
215                 req->seq_num = req->transport->negotiate.sign_info.next_seq_num;
216                 
217                 /* some requests (eg. NTcancel) are one way, and the sequence number
218                    should be increased by 1 not 2 */
219                 if (req->sign_single_increment) {
220                         req->transport->negotiate.sign_info.next_seq_num += 1;
221                 } else {
222                         req->transport->negotiate.sign_info.next_seq_num += 2;
223                 }
224                 
225                 sign_outgoing_message(&req->out, 
226                                       &req->transport->negotiate.sign_info.mac_key, 
227                                       req->seq_num);
228                 break;
229         }
230         return;
231 }
232
233
234 /**
235  SMB signing - NULL implementation
236
237  @note Used as an initialisation only - it will not correctly
238        shut down a real signing mechanism
239 */
240 static BOOL smbcli_set_signing_off(struct smb_signing_context *sign_info)
241 {
242         DEBUG(5, ("Shutdown SMB signing\n"));
243         sign_info->doing_signing = False;
244         data_blob_free(&sign_info->mac_key);
245         sign_info->signing_state = SMB_SIGNING_ENGINE_OFF;
246         return True;
247 }
248
249 /**
250  SMB signing - TEMP implementation - setup the MAC key.
251
252 */
253 BOOL smbcli_temp_set_signing(struct smbcli_transport *transport)
254 {
255         if (!set_smb_signing_common(transport)) {
256                 return False;
257         }
258         DEBUG(5, ("BSRSPYL SMB signing enabled\n"));
259         smbcli_set_signing_off(&transport->negotiate.sign_info);
260
261         transport->negotiate.sign_info.mac_key = data_blob(NULL, 0);
262         transport->negotiate.sign_info.signing_state = SMB_SIGNING_ENGINE_BSRSPYL;
263
264         return True;
265 }
266
267 /***********************************************************
268  SMB signing - Simple implementation - check a MAC sent by server.
269 ************************************************************/
270 /**
271  * Check a packet supplied by the server.
272  * @return False if we had an established signing connection
273  *         which had a back checksum, True otherwise
274  */
275 BOOL smbcli_request_check_sign_mac(struct smbcli_request *req) 
276 {
277         BOOL good;
278
279         switch (req->transport->negotiate.sign_info.signing_state) 
280         {
281         case SMB_SIGNING_ENGINE_OFF:
282                 return True;
283         case SMB_SIGNING_ENGINE_BSRSPYL:
284         case SMB_SIGNING_ENGINE_ON:
285         {                       
286                 if (req->in.size < (HDR_SS_FIELD + 8)) {
287                         return False;
288                 } else {
289                         good = check_signed_incoming_message(&req->in, 
290                                                              &req->transport->negotiate.sign_info.mac_key, 
291                                                              req->seq_num+1);
292                         
293                         return signing_good(&req->transport->negotiate.sign_info, 
294                                             req->seq_num+1, good);
295                 }
296         }
297         }
298         return False;
299 }
300
301
302 /***********************************************************
303  SMB signing - Simple implementation - setup the MAC key.
304 ************************************************************/
305 static BOOL smbcli_simple_set_signing(struct smb_signing_context *sign_info,
306                                       const DATA_BLOB user_session_key, 
307                                       const DATA_BLOB response)
308 {
309         if (sign_info->mandatory_signing) {
310                 DEBUG(5, ("Mandatory SMB signing enabled!\n"));
311         }
312
313         DEBUG(5, ("SMB signing enabled!\n"));
314
315         sign_info->mac_key = data_blob(NULL, response.length + user_session_key.length);
316
317         memcpy(&sign_info->mac_key.data[0], user_session_key.data, user_session_key.length);
318
319         if (response.length) {
320                 memcpy(&sign_info->mac_key.data[user_session_key.length],response.data, response.length);
321         }
322
323         dump_data_pw("Started Signing with key:\n", sign_info->mac_key.data, sign_info->mac_key.length);
324
325         /* Initialise the sequence number */
326         sign_info->next_seq_num = 0;
327
328         sign_info->signing_state = SMB_SIGNING_ENGINE_ON;
329
330         return True;
331 }
332
333
334 /***********************************************************
335  SMB signing - Simple implementation - setup the MAC key.
336 ************************************************************/
337 BOOL smbcli_transport_simple_set_signing(struct smbcli_transport *transport,
338                                          const DATA_BLOB user_session_key, 
339                                          const DATA_BLOB response)
340 {
341         if (!set_smb_signing_common(transport)) {
342                 return False;
343         }
344
345         return smbcli_simple_set_signing(&transport->negotiate.sign_info,
346                                          user_session_key,
347                                          response);
348 }
349
350
351 BOOL smbcli_init_signing(struct smbcli_transport *transport) 
352 {
353         transport->negotiate.sign_info.mac_key = data_blob(NULL, 0);
354         if (!smbcli_set_signing_off(&transport->negotiate.sign_info)) {
355                 return False;
356         }
357         
358         switch (lp_client_signing()) {
359         case SMB_SIGNING_OFF:
360                 transport->negotiate.sign_info.allow_smb_signing = False;
361                 break;
362         case SMB_SIGNING_SUPPORTED:
363                 transport->negotiate.sign_info.allow_smb_signing = True;
364                 break;
365         case SMB_SIGNING_REQUIRED:
366                 transport->negotiate.sign_info.allow_smb_signing = True;
367                 transport->negotiate.sign_info.mandatory_signing = True;
368                 break;
369         }
370         return True;
371 }