root/source4/libcli/raw/smb_signing.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_smb_signing_common
  2. smbcli_set_smb_signing_common
  3. mark_packet_signed
  4. signing_good
  5. sign_outgoing_message
  6. check_signed_incoming_message
  7. smbcli_req_allocate_seq_num
  8. smbcli_request_calculate_sign_mac
  9. smbcli_set_signing_off
  10. smbcli_temp_set_signing
  11. smbcli_request_check_sign_mac
  12. smbcli_simple_set_signing
  13. smbcli_transport_simple_set_signing
  14. smbcli_init_signing

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

/* [<][>][^][v][top][bottom][index][help] */