s3:libsmb: add a much simplified smb_siging infrastructure
[metze/samba/wip.git] / source3 / libsmb / smb_signing.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB Signing Code
4    Copyright (C) Jeremy Allison 2003.
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
6    Copyright (C) Stefan Metzmacher 2009
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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23
24 /* Used by the SMB signing functions. */
25
26 struct smb_signing_state {
27         /* is signing localy allowed */
28         bool allowed;
29
30         /* is signing localy mandatory */
31         bool mandatory;
32
33         /* is signing negotiated by the peer */
34         bool negotiated;
35
36         /* send BSRSPYL signatures */
37         bool bsrspyl;
38
39         bool active; /* Have I ever seen a validly signed packet? */
40
41         /* mac_key.length > 0 means signing is started */
42         DATA_BLOB mac_key;
43
44         /* the next expected seqnum */
45         uint32_t seqnum;
46 };
47
48 static void smb_signing_reset_info(struct smb_signing_state *si)
49 {
50         si->active = false;
51         si->bsrspyl = false;
52         data_blob_free(&si->mac_key);
53         si->seqnum = 0;
54 }
55
56 struct smb_signing_state *smb_signing_init(TALLOC_CTX *mem_ctx,
57                                            bool allowed,
58                                            bool mandatory)
59 {
60         struct smb_signing_state *si;
61
62         si = talloc_zero(mem_ctx, struct smb_signing_state);
63         if (si == NULL) {
64                 return NULL;
65         }
66
67         if (mandatory) {
68                 allowed = true;
69         }
70
71         si->allowed = allowed;
72         si->mandatory = mandatory;
73
74         return si;
75 }
76
77 static bool smb_signing_good(struct smb_signing_state *si,
78                              bool good, uint32_t seq)
79 {
80         if (good) {
81                 if (!si->active) {
82                         si->active = true;
83                 }
84                 return true;
85         }
86
87         if (!si->mandatory && !si->active) {
88                 /* Non-mandatory signing - just turn off if this is the first bad packet.. */
89                 DEBUG(5, ("smb_signing_good: signing negotiated but not required and peer\n"
90                           "isn't sending correct signatures. Turning off.\n"));
91                 smb_signing_reset_info(si);
92                 return true;
93         }
94
95         /* Mandatory signing or bad packet after signing started - fail and disconnect. */
96         DEBUG(0, ("smb_signing_good: BAD SIG: seq %u\n", (unsigned int)seq));
97         return false;
98 }
99
100 static void smb_signing_md5(const DATA_BLOB *mac_key,
101                             const uint8_t *buf, uint32_t seq_number,
102                             uint8_t calc_md5_mac[16])
103 {
104         const size_t offset_end_of_sig = (smb_ss_field + 8);
105         uint8_t sequence_buf[8];
106         struct MD5Context md5_ctx;
107
108         /*
109          * Firstly put the sequence number into the first 4 bytes.
110          * and zero out the next 4 bytes.
111          *
112          * We do this here, to avoid modifying the packet.
113          */
114
115         DEBUG(10,("smb_signing_md5: sequence number %u\n", seq_number ));
116
117         SIVAL(sequence_buf, 0, seq_number);
118         SIVAL(sequence_buf, 4, 0);
119
120         /* Calculate the 16 byte MAC - but don't alter the data in the
121            incoming packet.
122
123            This makes for a bit of fussing about, but it's not too bad.
124         */
125         MD5Init(&md5_ctx);
126
127         /* intialise with the key */
128         MD5Update(&md5_ctx, mac_key->data, mac_key->length);
129
130         /* copy in the first bit of the SMB header */
131         MD5Update(&md5_ctx, buf + 4, smb_ss_field - 4);
132
133         /* copy in the sequence number, instead of the signature */
134         MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
135
136         /* copy in the rest of the packet in, skipping the signature */
137         MD5Update(&md5_ctx, buf + offset_end_of_sig, 
138                   smb_len(buf) - (offset_end_of_sig - 4));
139
140         /* calculate the MD5 sig */
141         MD5Final(calc_md5_mac, &md5_ctx);
142 }
143
144 uint32_t smb_signing_next_seqnum(struct smb_signing_state *si, bool oneway)
145 {
146         uint32_t seqnum;
147
148         if (si->mac_key.length == 0) {
149                 return 0;
150         }
151
152         seqnum = si->seqnum;
153         if (oneway) {
154                 si->seqnum += 1;
155         } else {
156                 si->seqnum += 2;
157         }
158
159         return seqnum;
160 }
161
162 void smb_signing_cancel_reply(struct smb_signing_state *si, bool oneway)
163 {
164         if (si->mac_key.length == 0) {
165                 return;
166         }
167
168         if (oneway) {
169                 si->seqnum -= 1;
170         } else {
171                 si->seqnum -= 2;
172         }
173 }
174
175 void smb_signing_sign_pdu(struct smb_signing_state *si,
176                           uint8_t *outbuf, uint32_t seqnum)
177 {
178         uint8_t calc_md5_mac[16];
179         uint16_t flags2;
180
181         if (si->mac_key.length == 0) {
182                 if (!si->bsrspyl) {
183                         return;
184                 }
185         }
186
187         /* JRA Paranioa test - we should be able to get rid of this... */
188         if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) {
189                 DEBUG(1,("smb_signing_sign_pdu: Logic error. "
190                          "Can't check signature on short packet! smb_len = %u\n",
191                          smb_len(outbuf)));
192                 abort();
193         }
194
195         /* mark the packet as signed - BEFORE we sign it...*/
196         flags2 = SVAL(outbuf,smb_flg2);
197         flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
198         SSVAL(outbuf, smb_flg2, flags2);
199
200         if (si->bsrspyl) {
201                 /* I wonder what BSRSPYL stands for - but this is what MS
202                    actually sends! */
203                 memcpy(calc_md5_mac, "BSRSPYL ", 8);
204         } else {
205                 smb_signing_md5(&si->mac_key, outbuf,
206                                 seqnum, calc_md5_mac);
207         }
208
209         DEBUG(10, ("smb_signing_sign_pdu: sent SMB signature of\n"));
210         dump_data(10, calc_md5_mac, 8);
211
212         memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8);
213
214 /*      outbuf[smb_ss_field+2]=0;
215         Uncomment this to test if the remote server actually verifies signatures...*/
216 }
217
218 bool smb_signing_check_pdu(struct smb_signing_state *si,
219                            const uint8_t *inbuf, uint32_t seqnum)
220 {
221         bool good;
222         uint8_t calc_md5_mac[16];
223         const uint8_t *reply_sent_mac;
224
225         if (si->mac_key.length == 0) {
226                 return true;
227         }
228
229         if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) {
230                 DEBUG(1,("smb_signing_check_pdu: Can't check signature "
231                          "on short packet! smb_len = %u\n",
232                          smb_len(inbuf)));
233                 return False;
234         }
235
236         smb_signing_md5(&si->mac_key, inbuf,
237                         seqnum, calc_md5_mac);
238
239         reply_sent_mac = &inbuf[smb_ss_field];
240         good = (memcmp(reply_sent_mac, calc_md5_mac, 8) == 0);
241
242         if (!good) {
243                 int i;
244                 const int sign_range = 5;
245
246                 DEBUG(5, ("smb_signing_check_pdu: BAD SIG: wanted SMB signature of\n"));
247                 dump_data(5, calc_md5_mac, 8);
248
249                 DEBUG(5, ("smb_signing_check_pdu: BAD SIG: got SMB signature of\n"));
250                 dump_data(5, reply_sent_mac, 8);
251
252                 for (i = -sign_range; i < sign_range; i++) {
253                         smb_signing_md5(&si->mac_key, inbuf,
254                                         seqnum+i, calc_md5_mac);
255                         if (memcmp(reply_sent_mac, calc_md5_mac, 8) == 0) {
256                                 DEBUG(0,("smb_signing_check_pdu: "
257                                          "out of seq. seq num %u matches. "
258                                          "We were expecting seq %u\n",
259                                          (unsigned int)seqnum+i,
260                                          (unsigned int)seqnum));
261                                 break;
262                         }
263                 }
264         } else {
265                 DEBUG(10, ("smb_signing_check_pdu: seq %u: "
266                            "got good SMB signature of\n",
267                            (unsigned int)seqnum));
268                 dump_data(10, reply_sent_mac, 8);
269         }
270
271         return smb_signing_good(si, good, seqnum);
272 }
273
274 bool smb_signing_set_bsrspyl(struct smb_signing_state *si)
275 {
276         if (!si->negotiated) {
277                 return false;
278         }
279
280         if (si->active) {
281                 return false;
282         }
283
284         si->bsrspyl = true;
285
286         return true;
287 }
288
289 bool smb_signing_activate(struct smb_signing_state *si,
290                           const DATA_BLOB user_session_key,
291                           const DATA_BLOB response)
292 {
293         size_t len;
294         off_t ofs;
295
296         if (!user_session_key.length) {
297                 return false;
298         }
299
300         if (!si->negotiated) {
301                 return false;
302         }
303
304         if (si->active) {
305                 return false;
306         }
307
308         if (si->mac_key.length > 0) {
309                 return false;
310         }
311
312         smb_signing_reset_info(si);
313
314         len = response.length + user_session_key.length;
315         si->mac_key = data_blob_talloc(si, NULL, len);
316
317         ofs = 0;
318         memcpy(&si->mac_key.data[ofs], user_session_key.data, user_session_key.length);
319
320         DEBUG(10, ("smb_signing_activate: user_session_key\n"));
321         dump_data(10, user_session_key.data, user_session_key.length);
322
323         if (response.length) {
324                 ofs = user_session_key.length;
325                 memcpy(&si->mac_key.data[ofs], response.data, response.length);
326                 DEBUG(10, ("smb_signing_activate: response_data\n"));
327                 dump_data(10, response.data, response.length);
328         } else {
329                 DEBUG(10, ("smb_signing_activate: NULL response_data\n"));
330         }
331
332         dump_data_pw("smb_signing_activate: mac key is:\n",
333                      si->mac_key.data, si->mac_key.length);
334
335         /* Initialise the sequence number */
336         si->seqnum = 2;
337
338         return true;
339 }
340
341 bool smb_signing_is_active(struct smb_signing_state *si)
342 {
343         return si->active;
344 }
345
346 bool smb_signing_is_allowed(struct smb_signing_state *si)
347 {
348         return si->allowed;
349 }
350
351 bool smb_signing_is_mandatory(struct smb_signing_state *si)
352 {
353         return si->mandatory;
354 }
355
356 bool smb_signing_set_negotiated(struct smb_signing_state *si)
357 {
358         if (!si->allowed) {
359                 return false;
360         }
361
362         si->negotiated = true;
363
364         return true;
365 }
366
367 bool smb_signing_is_negotiated(struct smb_signing_state *si)
368 {
369         return si->negotiated;
370 }