2 Unix SMB/CIFS implementation.
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
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.
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.
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/>.
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "../lib/crypto/crypto.h"
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
)
32 if (sign_info
->doing_signing
) {
33 DEBUG(5, ("SMB Signing already in progress, so we don't start it again\n"));
37 if (!sign_info
->allow_smb_signing
) {
38 DEBUG(5, ("SMB Signing has been locally disabled\n"));
45 /***********************************************************
46 SMB signing - Common code before we set a new signing implementation
47 ************************************************************/
48 static bool smbcli_set_smb_signing_common(struct smbcli_transport
*transport
)
50 if (!set_smb_signing_common(&transport
->negotiate
.sign_info
)) {
54 if (!(transport
->negotiate
.sec_mode
&
55 (NEGOTIATE_SECURITY_SIGNATURES_REQUIRED
|NEGOTIATE_SECURITY_SIGNATURES_ENABLED
))) {
56 DEBUG(5, ("SMB Signing is not negotiated by the peer\n"));
60 /* These calls are INCOMPATIBLE with SMB signing */
61 transport
->negotiate
.readbraw_supported
= false;
62 transport
->negotiate
.writebraw_supported
= false;
67 void mark_packet_signed(struct smb_request_buffer
*out
)
70 flags2
= SVAL(out
->hdr
, HDR_FLG2
);
71 flags2
|= FLAGS2_SMB_SECURITY_SIGNATURES
;
72 SSVAL(out
->hdr
, HDR_FLG2
, flags2
);
75 bool signing_good(struct smb_signing_context
*sign_info
,
76 unsigned int seq
, bool good
)
79 if (!sign_info
->doing_signing
) {
80 DEBUG(5, ("Seen valid packet, so turning signing on\n"));
81 sign_info
->doing_signing
= true;
83 if (!sign_info
->seen_valid
) {
84 DEBUG(5, ("Seen valid packet, so marking signing as 'seen valid'\n"));
85 sign_info
->seen_valid
= true;
88 if (!sign_info
->seen_valid
) {
89 /* If we have never seen a good packet, just turn it off */
90 DEBUG(5, ("signing_good: signing negotiated but not required and peer\n"
91 "isn't sending correct signatures. Turning off.\n"));
92 smbcli_set_signing_off(sign_info
);
95 /* bad packet after signing started - fail and disconnect. */
96 DEBUG(0, ("signing_good: BAD SIG: seq %u\n", seq
));
103 void sign_outgoing_message(struct smb_request_buffer
*out
, DATA_BLOB
*mac_key
, unsigned int seq_num
)
105 uint8_t calc_md5_mac
[16];
106 struct MD5Context md5_ctx
;
109 * Firstly put the sequence number into the first 4 bytes.
110 * and zero out the next 4 bytes.
112 SIVAL(out
->hdr
, HDR_SS_FIELD
, seq_num
);
113 SIVAL(out
->hdr
, HDR_SS_FIELD
+ 4, 0);
115 /* mark the packet as signed - BEFORE we sign it...*/
116 mark_packet_signed(out
);
118 /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
120 MD5Update(&md5_ctx
, mac_key
->data
, mac_key
->length
);
122 out
->buffer
+ NBT_HDR_SIZE
,
123 out
->size
- NBT_HDR_SIZE
);
124 MD5Final(calc_md5_mac
, &md5_ctx
);
126 memcpy(&out
->hdr
[HDR_SS_FIELD
], calc_md5_mac
, 8);
128 DEBUG(5, ("sign_outgoing_message: SENT SIG (seq: %d): sent SMB signature of\n",
130 dump_data(5, calc_md5_mac
, 8);
131 /* req->out.hdr[HDR_SS_FIELD+2]=0;
132 Uncomment this to test if the remote server actually verifies signitures...*/
135 bool check_signed_incoming_message(struct smb_request_buffer
*in
, DATA_BLOB
*mac_key
, unsigned int seq_num
)
138 uint8_t calc_md5_mac
[16];
139 uint8_t *server_sent_mac
;
140 uint8_t sequence_buf
[8];
141 struct MD5Context md5_ctx
;
142 const size_t offset_end_of_sig
= (HDR_SS_FIELD
+ 8);
144 const int sign_range
= 0;
146 /* room enough for the signature? */
147 if (in
->size
< NBT_HDR_SIZE
+ HDR_SS_FIELD
+ 8) {
151 if (!mac_key
->length
) {
156 /* its quite bogus to be guessing sequence numbers, but very useful
157 when debugging signing implementations */
158 for (i
= 0-sign_range
; i
<= 0+sign_range
; i
++) {
160 * Firstly put the sequence number into the first 4 bytes.
161 * and zero out the next 4 bytes.
163 SIVAL(sequence_buf
, 0, seq_num
+ i
);
164 SIVAL(sequence_buf
, 4, 0);
166 /* get a copy of the server-sent mac */
167 server_sent_mac
= &in
->hdr
[HDR_SS_FIELD
];
169 /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
171 MD5Update(&md5_ctx
, mac_key
->data
,
173 MD5Update(&md5_ctx
, in
->hdr
, HDR_SS_FIELD
);
174 MD5Update(&md5_ctx
, sequence_buf
, sizeof(sequence_buf
));
176 MD5Update(&md5_ctx
, in
->hdr
+ offset_end_of_sig
,
177 in
->size
- NBT_HDR_SIZE
- (offset_end_of_sig
));
178 MD5Final(calc_md5_mac
, &md5_ctx
);
180 good
= (memcmp(server_sent_mac
, calc_md5_mac
, 8) == 0);
184 DEBUG(5, ("check_signed_incoming_message: BAD SIG (seq: %d): wanted SMB signature of\n", seq_num
+ i
));
185 dump_data(5, calc_md5_mac
, 8);
187 DEBUG(5, ("check_signed_incoming_message: BAD SIG (seq: %d): got SMB signature of\n", seq_num
+ i
));
188 dump_data(5, server_sent_mac
, 8);
190 DEBUG(15, ("check_signed_incoming_message: GOOD SIG (seq: %d): got SMB signature of\n", seq_num
+ i
));
191 dump_data(5, server_sent_mac
, 8);
198 if (good
&& i
!= 0) {
199 DEBUG(0,("SIGNING OFFSET %d (should be %d)\n", i
, seq_num
));
205 static void smbcli_req_allocate_seq_num(struct smbcli_request
*req
)
207 req
->seq_num
= req
->transport
->negotiate
.sign_info
.next_seq_num
;
209 /* some requests (eg. NTcancel) are one way, and the sequence number
210 should be increased by 1 not 2 */
211 if (req
->sign_single_increment
) {
212 req
->transport
->negotiate
.sign_info
.next_seq_num
+= 1;
214 req
->transport
->negotiate
.sign_info
.next_seq_num
+= 2;
218 /***********************************************************
219 SMB signing - Simple implementation - calculate a MAC to send.
220 ************************************************************/
221 void smbcli_request_calculate_sign_mac(struct smbcli_request
*req
)
224 /* enable this when packet signing is preventing you working out why valgrind
225 says that data is uninitialised */
226 file_save("pkt.dat", req
->out
.buffer
, req
->out
.size
);
229 switch (req
->transport
->negotiate
.sign_info
.signing_state
) {
230 case SMB_SIGNING_ENGINE_OFF
:
233 case SMB_SIGNING_ENGINE_BSRSPYL
:
234 /* mark the packet as signed - BEFORE we sign it...*/
235 mark_packet_signed(&req
->out
);
237 /* I wonder what BSRSPYL stands for - but this is what MS
239 memcpy((req
->out
.hdr
+ HDR_SS_FIELD
), "BSRSPYL ", 8);
242 case SMB_SIGNING_ENGINE_ON
:
244 smbcli_req_allocate_seq_num(req
);
245 sign_outgoing_message(&req
->out
,
246 &req
->transport
->negotiate
.sign_info
.mac_key
,
255 SMB signing - NULL implementation
257 @note Used as an initialisation only - it will not correctly
258 shut down a real signing mechanism
260 bool smbcli_set_signing_off(struct smb_signing_context
*sign_info
)
262 DEBUG(5, ("Shutdown SMB signing\n"));
263 sign_info
->doing_signing
= false;
264 data_blob_free(&sign_info
->mac_key
);
265 sign_info
->signing_state
= SMB_SIGNING_ENGINE_OFF
;
270 SMB signing - TEMP implementation - setup the MAC key.
273 bool smbcli_temp_set_signing(struct smbcli_transport
*transport
)
275 if (!smbcli_set_smb_signing_common(transport
)) {
278 DEBUG(5, ("BSRSPYL SMB signing enabled\n"));
279 smbcli_set_signing_off(&transport
->negotiate
.sign_info
);
281 transport
->negotiate
.sign_info
.mac_key
= data_blob(NULL
, 0);
282 transport
->negotiate
.sign_info
.signing_state
= SMB_SIGNING_ENGINE_BSRSPYL
;
287 /***********************************************************
288 SMB signing - Simple implementation - check a MAC sent by server.
289 ************************************************************/
291 * Check a packet supplied by the server.
292 * @return false if we had an established signing connection
293 * which had a back checksum, true otherwise
295 bool smbcli_request_check_sign_mac(struct smbcli_request
*req
)
299 if (!req
->transport
->negotiate
.sign_info
.doing_signing
&&
300 req
->sign_caller_checks
) {
304 req
->sign_caller_checks
= false;
306 switch (req
->transport
->negotiate
.sign_info
.signing_state
)
308 case SMB_SIGNING_ENGINE_OFF
:
310 case SMB_SIGNING_ENGINE_BSRSPYL
:
313 case SMB_SIGNING_ENGINE_ON
:
315 if (req
->in
.size
< (HDR_SS_FIELD
+ 8)) {
318 good
= check_signed_incoming_message(&req
->in
,
319 &req
->transport
->negotiate
.sign_info
.mac_key
,
322 return signing_good(&req
->transport
->negotiate
.sign_info
,
323 req
->seq_num
+1, good
);
331 /***********************************************************
332 SMB signing - Simple implementation - setup the MAC key.
333 ************************************************************/
334 bool smbcli_simple_set_signing(TALLOC_CTX
*mem_ctx
,
335 struct smb_signing_context
*sign_info
,
336 const DATA_BLOB
*user_session_key
,
337 const DATA_BLOB
*response
)
339 if (sign_info
->mandatory_signing
) {
340 DEBUG(5, ("Mandatory SMB signing enabled!\n"));
343 DEBUG(5, ("SMB signing enabled!\n"));
345 if (response
&& response
->length
) {
346 sign_info
->mac_key
= data_blob_talloc(mem_ctx
, NULL
, response
->length
+ user_session_key
->length
);
348 sign_info
->mac_key
= data_blob_talloc(mem_ctx
, NULL
, user_session_key
->length
);
351 memcpy(&sign_info
->mac_key
.data
[0], user_session_key
->data
, user_session_key
->length
);
353 if (response
&& response
->length
) {
354 memcpy(&sign_info
->mac_key
.data
[user_session_key
->length
],response
->data
, response
->length
);
357 dump_data_pw("Started Signing with key:\n", sign_info
->mac_key
.data
, sign_info
->mac_key
.length
);
359 sign_info
->signing_state
= SMB_SIGNING_ENGINE_ON
;
360 sign_info
->next_seq_num
= 2;
366 /***********************************************************
367 SMB signing - Simple implementation - setup the MAC key.
368 ************************************************************/
369 bool smbcli_transport_simple_set_signing(struct smbcli_transport
*transport
,
370 const DATA_BLOB user_session_key
,
371 const DATA_BLOB response
)
373 if (!smbcli_set_smb_signing_common(transport
)) {
377 return smbcli_simple_set_signing(transport
,
378 &transport
->negotiate
.sign_info
,
384 bool smbcli_init_signing(struct smbcli_transport
*transport
)
386 transport
->negotiate
.sign_info
.next_seq_num
= 0;
387 transport
->negotiate
.sign_info
.mac_key
= data_blob(NULL
, 0);
388 if (!smbcli_set_signing_off(&transport
->negotiate
.sign_info
)) {
392 switch (transport
->options
.signing
) {
393 case SMB_SIGNING_OFF
:
394 transport
->negotiate
.sign_info
.allow_smb_signing
= false;
396 case SMB_SIGNING_SUPPORTED
:
397 case SMB_SIGNING_AUTO
:
398 transport
->negotiate
.sign_info
.allow_smb_signing
= true;
400 case SMB_SIGNING_REQUIRED
:
401 transport
->negotiate
.sign_info
.allow_smb_signing
= true;
402 transport
->negotiate
.sign_info
.mandatory_signing
= true;