~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/auth/gensec/schannel_sign.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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,
 
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],
 
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],
 
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, 
 
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, 
 
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, 
 
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, 
 
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
}