5d2f92874797539f26a5d4aa4f8d41d4863de195
[metze/samba/wip.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 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 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "../lib/crypto/crypto.h"
26
27 /***********************************************************
28  SMB signing - Common code before we set a new signing implementation
29 ************************************************************/
30 bool set_smb_signing_common(struct smb_signing_context *sign_info)
31 {
32         if (sign_info->doing_signing) {
33                 DEBUG(5, ("SMB Signing already in progress, so we don't start it again\n"));
34                 return false;
35         }
36
37         if (!sign_info->allow_smb_signing) {
38                 DEBUG(5, ("SMB Signing has been locally disabled\n"));
39                 return false;
40         }
41
42         return true;
43 }
44
45 void mark_packet_signed(struct smb_request_buffer *out) 
46 {
47         uint16_t flags2;
48         flags2 = SVAL(out->hdr, HDR_FLG2);
49         flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
50         SSVAL(out->hdr, HDR_FLG2, flags2);
51 }
52
53 bool signing_good(struct smb_signing_context *sign_info, 
54                          unsigned int seq, bool good) 
55 {
56         if (good) {
57                 if (!sign_info->doing_signing) {
58                         DEBUG(5, ("Seen valid packet, so turning signing on\n"));
59                         sign_info->doing_signing = true;
60                 }
61                 if (!sign_info->seen_valid) {
62                         DEBUG(5, ("Seen valid packet, so marking signing as 'seen valid'\n"));
63                         sign_info->seen_valid = true;
64                 }
65         } else {
66                 if (!sign_info->seen_valid) {
67                         /* If we have never seen a good packet, just turn it off */
68                         DEBUG(5, ("signing_good: signing negotiated but not required and peer\n"
69                                   "isn't sending correct signatures. Turning off.\n"));
70                         smbcli_set_signing_off(sign_info);
71                         return true;
72                 } else {
73                         /* bad packet after signing started - fail and disconnect. */
74                         DEBUG(0, ("signing_good: BAD SIG: seq %u\n", seq));
75                         return false;
76                 }
77         }
78         return true;
79 }
80
81 void sign_outgoing_message(struct smb_request_buffer *out, DATA_BLOB *mac_key, unsigned int seq_num) 
82 {
83         uint8_t calc_md5_mac[16];
84         struct MD5Context md5_ctx;
85
86         /*
87          * Firstly put the sequence number into the first 4 bytes.
88          * and zero out the next 4 bytes.
89          */
90         SIVAL(out->hdr, HDR_SS_FIELD, seq_num);
91         SIVAL(out->hdr, HDR_SS_FIELD + 4, 0);
92
93         /* mark the packet as signed - BEFORE we sign it...*/
94         mark_packet_signed(out);
95
96         /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
97         MD5Init(&md5_ctx);
98         MD5Update(&md5_ctx, mac_key->data, mac_key->length);
99         MD5Update(&md5_ctx, 
100                   out->buffer + NBT_HDR_SIZE, 
101                   out->size - NBT_HDR_SIZE);
102         MD5Final(calc_md5_mac, &md5_ctx);
103
104         memcpy(&out->hdr[HDR_SS_FIELD], calc_md5_mac, 8);
105
106         DEBUG(5, ("sign_outgoing_message: SENT SIG (seq: %d): sent SMB signature of\n", 
107                   seq_num));
108         dump_data(5, calc_md5_mac, 8);
109 /*      req->out.hdr[HDR_SS_FIELD+2]=0; 
110         Uncomment this to test if the remote server actually verifies signitures...*/
111 }
112
113 bool check_signed_incoming_message(struct smb_request_buffer *in, DATA_BLOB *mac_key, unsigned int seq_num)
114 {
115         bool good;
116         uint8_t calc_md5_mac[16];
117         uint8_t *server_sent_mac;
118         uint8_t sequence_buf[8];
119         struct MD5Context md5_ctx;
120         const size_t offset_end_of_sig = (HDR_SS_FIELD + 8);
121         int i;
122         const int sign_range = 0;
123
124         /* room enough for the signature? */
125         if (in->size < NBT_HDR_SIZE + HDR_SS_FIELD + 8) {
126                 return false;
127         }
128
129         if (!mac_key->length) {
130                 /* NO key yet */
131                 return false;
132         }
133
134         /* its quite bogus to be guessing sequence numbers, but very useful
135            when debugging signing implementations */
136         for (i = 0-sign_range; i <= 0+sign_range; i++) {
137                 /*
138                  * Firstly put the sequence number into the first 4 bytes.
139                  * and zero out the next 4 bytes.
140                  */
141                 SIVAL(sequence_buf, 0, seq_num + i);
142                 SIVAL(sequence_buf, 4, 0);
143                 
144                 /* get a copy of the server-sent mac */
145                 server_sent_mac = &in->hdr[HDR_SS_FIELD];
146                 
147                 /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
148                 MD5Init(&md5_ctx);
149                 MD5Update(&md5_ctx, mac_key->data, 
150                           mac_key->length); 
151                 MD5Update(&md5_ctx, in->hdr, HDR_SS_FIELD);
152                 MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
153                 
154                 MD5Update(&md5_ctx, in->hdr + offset_end_of_sig, 
155                           in->size - NBT_HDR_SIZE - (offset_end_of_sig));
156                 MD5Final(calc_md5_mac, &md5_ctx);
157                 
158                 good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
159
160                 if (i == 0) {
161                         if (!good) {
162                                 DEBUG(5, ("check_signed_incoming_message: BAD SIG (seq: %d): wanted SMB signature of\n", seq_num + i));
163                                 dump_data(5, calc_md5_mac, 8);
164                                 
165                                 DEBUG(5, ("check_signed_incoming_message: BAD SIG (seq: %d): got SMB signature of\n", seq_num + i));
166                                 dump_data(5, server_sent_mac, 8);
167                         } else {
168                                 DEBUG(15, ("check_signed_incoming_message: GOOD SIG (seq: %d): got SMB signature of\n", seq_num + i));
169                                 dump_data(5, server_sent_mac, 8);
170                         }
171                 }
172
173                 if (good) break;
174         }
175
176         if (good && i != 0) {
177                 DEBUG(0,("SIGNING OFFSET %d (should be %d)\n", i, seq_num));
178         }
179
180         return good;
181 }
182
183 /**
184  SMB signing - NULL implementation
185
186  @note Used as an initialisation only - it will not correctly
187        shut down a real signing mechanism
188 */
189 bool smbcli_set_signing_off(struct smb_signing_context *sign_info)
190 {
191         DEBUG(5, ("Shutdown SMB signing\n"));
192         sign_info->doing_signing = false;
193         data_blob_free(&sign_info->mac_key);
194         sign_info->signing_state = SMB_SIGNING_ENGINE_OFF;
195         return true;
196 }
197
198 /***********************************************************
199  SMB signing - Simple implementation - setup the MAC key.
200 ************************************************************/
201 bool smbcli_simple_set_signing(TALLOC_CTX *mem_ctx,
202                                struct smb_signing_context *sign_info,
203                                const DATA_BLOB *user_session_key, 
204                                const DATA_BLOB *response)
205 {
206         if (sign_info->mandatory_signing) {
207                 DEBUG(5, ("Mandatory SMB signing enabled!\n"));
208         }
209
210         DEBUG(5, ("SMB signing enabled!\n"));
211
212         if (response && response->length) {
213                 sign_info->mac_key = data_blob_talloc(mem_ctx, NULL, response->length + user_session_key->length);
214         } else {
215                 sign_info->mac_key = data_blob_talloc(mem_ctx, NULL, user_session_key->length);
216         }
217                 
218         memcpy(&sign_info->mac_key.data[0], user_session_key->data, user_session_key->length);
219
220         if (response && response->length) {
221                 memcpy(&sign_info->mac_key.data[user_session_key->length],response->data, response->length);
222         }
223
224         dump_data_pw("Started Signing with key:\n", sign_info->mac_key.data, sign_info->mac_key.length);
225
226         sign_info->signing_state = SMB_SIGNING_ENGINE_ON;
227         sign_info->next_seq_num = 2;
228
229         return true;
230 }
231