root/source4/auth/gensec/schannel_sign.c

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

DEFINITIONS

This source file includes following definitions.
  1. netsec_deal_with_seq_num
  2. netsec_get_sealing_key
  3. schannel_digest
  4. schannel_unseal_packet
  5. schannel_check_packet
  6. schannel_seal_packet
  7. schannel_sign_packet

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    schannel library code
   5 
   6    Copyright (C) Andrew Tridgell 2004
   7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
   8    
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 3 of the License, or
  12    (at your option) any later version.
  13    
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18    
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22 
  23 #include "includes.h"
  24 #include "../lib/crypto/crypto.h"
  25 #include "auth/auth.h"
  26 #include "auth/gensec/schannel.h"
  27 #include "auth/credentials/credentials.h"
  28 #include "auth/gensec/gensec.h"
  29 #include "auth/gensec/schannel_proto.h"
  30 
  31 #define NETSEC_SIGN_SIGNATURE { 0x77, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 }
  32 #define NETSEC_SEAL_SIGNATURE { 0x77, 0x00, 0x7a, 0x00, 0xff, 0xff, 0x00, 0x00 }
  33 
  34 /*******************************************************************
  35  Encode or Decode the sequence number (which is symmetric)
  36  ********************************************************************/
  37 static void netsec_deal_with_seq_num(struct schannel_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
  38                                      const uint8_t packet_digest[8],
  39                                      uint8_t seq_num[8])
  40 {
  41         static const uint8_t zeros[4];
  42         uint8_t sequence_key[16];
  43         uint8_t digest1[16];
  44 
  45         hmac_md5(state->creds->session_key, zeros, sizeof(zeros), digest1);
  46         hmac_md5(digest1, packet_digest, 8, sequence_key);
  47         arcfour_crypt(seq_num, sequence_key, 8);
  48 
  49         state->seq_num++;
  50 }
  51 
  52 
  53 /*******************************************************************
  54  Calculate the key with which to encode the data payload 
  55  ********************************************************************/
  56 static void netsec_get_sealing_key(const uint8_t session_key[16],
     /* [<][>][^][v][top][bottom][index][help] */
  57                                    const uint8_t seq_num[8],
  58                                    uint8_t sealing_key[16]) 
  59 {
  60         static const uint8_t zeros[4];
  61         uint8_t digest2[16];
  62         uint8_t sess_kf0[16];
  63         int i;
  64 
  65         for (i = 0; i < 16; i++) {
  66                 sess_kf0[i] = session_key[i] ^ 0xf0;
  67         }
  68         
  69         hmac_md5(sess_kf0, zeros, 4, digest2);
  70         hmac_md5(digest2, seq_num, 8, sealing_key);
  71 }
  72 
  73 
  74 /*******************************************************************
  75  Create a digest over the entire packet (including the data), and 
  76  MD5 it with the session key.
  77  ********************************************************************/
  78 static void schannel_digest(const uint8_t sess_key[16],
     /* [<][>][^][v][top][bottom][index][help] */
  79                             const uint8_t netsec_sig[8],
  80                             const uint8_t *confounder,
  81                             const uint8_t *data, size_t data_len,
  82                             uint8_t digest_final[16]) 
  83 {
  84         uint8_t packet_digest[16];
  85         static const uint8_t zeros[4];
  86         struct MD5Context ctx;
  87         
  88         MD5Init(&ctx);
  89         MD5Update(&ctx, zeros, 4);
  90         MD5Update(&ctx, netsec_sig, 8);
  91         if (confounder) {
  92                 MD5Update(&ctx, confounder, 8);
  93         }
  94         MD5Update(&ctx, data, data_len);
  95         MD5Final(packet_digest, &ctx);
  96         
  97         hmac_md5(sess_key, packet_digest, sizeof(packet_digest), digest_final);
  98 }
  99 
 100 
 101 /*
 102   unseal a packet
 103 */
 104 NTSTATUS schannel_unseal_packet(struct gensec_security *gensec_security, 
     /* [<][>][^][v][top][bottom][index][help] */
 105                                 TALLOC_CTX *mem_ctx, 
 106                                 uint8_t *data, size_t length, 
 107                                 const uint8_t *whole_pdu, size_t pdu_length, 
 108                                 const DATA_BLOB *sig)
 109 {
 110         struct schannel_state *state = talloc_get_type(gensec_security->private_data, struct schannel_state);
 111         
 112         uint8_t digest_final[16];
 113         uint8_t confounder[8];
 114         uint8_t seq_num[8];
 115         uint8_t sealing_key[16];
 116         static const uint8_t netsec_sig[8] = NETSEC_SEAL_SIGNATURE;
 117 
 118         if (sig->length != 32) {
 119                 return NT_STATUS_ACCESS_DENIED;
 120         }
 121 
 122         memcpy(confounder, sig->data+24, 8);
 123 
 124         RSIVAL(seq_num, 0, state->seq_num);
 125         SIVAL(seq_num, 4, state->initiator?0:0x80);
 126 
 127         netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key);
 128         arcfour_crypt(confounder, sealing_key, 8);
 129         arcfour_crypt(data, sealing_key, length);
 130 
 131         schannel_digest(state->creds->session_key, 
 132                         netsec_sig, confounder, 
 133                         data, length, digest_final);
 134 
 135         if (memcmp(digest_final, sig->data+16, 8) != 0) {
 136                 dump_data_pw("calc digest:", digest_final, 8);
 137                 dump_data_pw("wire digest:", sig->data+16, 8);
 138                 return NT_STATUS_ACCESS_DENIED;
 139         }
 140 
 141         netsec_deal_with_seq_num(state, digest_final, seq_num);
 142 
 143         if (memcmp(seq_num, sig->data+8, 8) != 0) {
 144                 dump_data_pw("calc seq num:", seq_num, 8);
 145                 dump_data_pw("wire seq num:", sig->data+8, 8);
 146                 return NT_STATUS_ACCESS_DENIED;
 147         }
 148 
 149         return NT_STATUS_OK;
 150 }
 151 
 152 /*
 153   check the signature on a packet
 154 */
 155 NTSTATUS schannel_check_packet(struct gensec_security *gensec_security, 
     /* [<][>][^][v][top][bottom][index][help] */
 156                                TALLOC_CTX *mem_ctx, 
 157                                const uint8_t *data, size_t length, 
 158                                const uint8_t *whole_pdu, size_t pdu_length, 
 159                                const DATA_BLOB *sig)
 160 {
 161         struct schannel_state *state = talloc_get_type(gensec_security->private_data, struct schannel_state);
 162 
 163         uint8_t digest_final[16];
 164         uint8_t seq_num[8];
 165         static const uint8_t netsec_sig[8] = NETSEC_SIGN_SIGNATURE;
 166 
 167         /* w2k sends just 24 bytes and skip the confounder */
 168         if (sig->length != 32 && sig->length != 24) {
 169                 return NT_STATUS_ACCESS_DENIED;
 170         }
 171 
 172         RSIVAL(seq_num, 0, state->seq_num);
 173         SIVAL(seq_num, 4, state->initiator?0:0x80);
 174 
 175         dump_data_pw("seq_num:\n", seq_num, 8);
 176         dump_data_pw("sess_key:\n", state->creds->session_key, 16);
 177 
 178         schannel_digest(state->creds->session_key, 
 179                         netsec_sig, NULL, 
 180                         data, length, digest_final);
 181 
 182         netsec_deal_with_seq_num(state, digest_final, seq_num);
 183 
 184         if (memcmp(seq_num, sig->data+8, 8) != 0) {
 185                 dump_data_pw("calc seq num:", seq_num, 8);
 186                 dump_data_pw("wire seq num:", sig->data+8, 8);
 187                 return NT_STATUS_ACCESS_DENIED;
 188         }
 189 
 190         if (memcmp(digest_final, sig->data+16, 8) != 0) {
 191                 dump_data_pw("calc digest:", digest_final, 8);
 192                 dump_data_pw("wire digest:", sig->data+16, 8);
 193                 return NT_STATUS_ACCESS_DENIED;
 194         }
 195 
 196         return NT_STATUS_OK;
 197 }
 198 
 199 
 200 /*
 201   seal a packet
 202 */
 203 NTSTATUS schannel_seal_packet(struct gensec_security *gensec_security, 
     /* [<][>][^][v][top][bottom][index][help] */
 204                               TALLOC_CTX *mem_ctx, 
 205                               uint8_t *data, size_t length, 
 206                               const uint8_t *whole_pdu, size_t pdu_length, 
 207                               DATA_BLOB *sig)
 208 {
 209         struct schannel_state *state = talloc_get_type(gensec_security->private_data, struct schannel_state);
 210 
 211         uint8_t digest_final[16];
 212         uint8_t confounder[8];
 213         uint8_t seq_num[8];
 214         uint8_t sealing_key[16];
 215         static const uint8_t netsec_sig[8] = NETSEC_SEAL_SIGNATURE;
 216 
 217         generate_random_buffer(confounder, 8);
 218 
 219         RSIVAL(seq_num, 0, state->seq_num);
 220         SIVAL(seq_num, 4, state->initiator?0x80:0);
 221 
 222         schannel_digest(state->creds->session_key, 
 223                         netsec_sig, confounder, 
 224                         data, length, digest_final);
 225 
 226         netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key);
 227         arcfour_crypt(confounder, sealing_key, 8);
 228         arcfour_crypt(data, sealing_key, length);
 229 
 230         netsec_deal_with_seq_num(state, digest_final, seq_num);
 231 
 232         (*sig) = data_blob_talloc(mem_ctx, NULL, 32);
 233 
 234         memcpy(sig->data, netsec_sig, 8);
 235         memcpy(sig->data+8, seq_num, 8);
 236         memcpy(sig->data+16, digest_final, 8);
 237         memcpy(sig->data+24, confounder, 8);
 238 
 239         dump_data_pw("signature:", sig->data+ 0, 8);
 240         dump_data_pw("seq_num  :", sig->data+ 8, 8);
 241         dump_data_pw("digest   :", sig->data+16, 8);
 242         dump_data_pw("confound :", sig->data+24, 8);
 243 
 244         return NT_STATUS_OK;
 245 }
 246 
 247 
 248 /*
 249   sign a packet
 250 */
 251 NTSTATUS schannel_sign_packet(struct gensec_security *gensec_security, 
     /* [<][>][^][v][top][bottom][index][help] */
 252                               TALLOC_CTX *mem_ctx, 
 253                               const uint8_t *data, size_t length, 
 254                               const uint8_t *whole_pdu, size_t pdu_length, 
 255                               DATA_BLOB *sig)
 256 {
 257         struct schannel_state *state = talloc_get_type(gensec_security->private_data, struct schannel_state);
 258 
 259         uint8_t digest_final[16];
 260         uint8_t seq_num[8];
 261         static const uint8_t netsec_sig[8] = NETSEC_SIGN_SIGNATURE;
 262 
 263         RSIVAL(seq_num, 0, state->seq_num);
 264         SIVAL(seq_num, 4, state->initiator?0x80:0);
 265 
 266         schannel_digest(state->creds->session_key, 
 267                         netsec_sig, NULL, 
 268                         data, length, digest_final);
 269 
 270         netsec_deal_with_seq_num(state, digest_final, seq_num);
 271 
 272         (*sig) = data_blob_talloc(mem_ctx, NULL, 32);
 273 
 274         memcpy(sig->data, netsec_sig, 8);
 275         memcpy(sig->data+8, seq_num, 8);
 276         memcpy(sig->data+16, digest_final, 8);
 277         memset(sig->data+24, 0, 8);
 278 
 279         dump_data_pw("signature:", sig->data+ 0, 8);
 280         dump_data_pw("seq_num  :", sig->data+ 8, 8);
 281         dump_data_pw("digest   :", sig->data+16, 8);
 282         dump_data_pw("confound :", sig->data+24, 8);
 283 
 284         return NT_STATUS_OK;
 285 }

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