ca066b102d867145dc2d8f0aae6cb2bf1c6fab1e
[ira/wip.git] / source4 / auth / gensec / schannel_sign.c
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/gensec/gensec.h"
26 #include "auth/gensec/gensec_proto.h"
27 #include "auth/gensec/schannel.h"
28
29 #define NETSEC_SIGN_SIGNATURE { 0x77, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 }
30 #define NETSEC_SEAL_SIGNATURE { 0x77, 0x00, 0x7a, 0x00, 0xff, 0xff, 0x00, 0x00 }
31
32 /*******************************************************************
33  Encode or Decode the sequence number (which is symmetric)
34  ********************************************************************/
35 static void netsec_deal_with_seq_num(struct schannel_state *state,
36                                      const uint8_t packet_digest[8],
37                                      uint8_t seq_num[8])
38 {
39         static const uint8_t zeros[4];
40         uint8_t sequence_key[16];
41         uint8_t digest1[16];
42
43         hmac_md5(state->creds->session_key, zeros, sizeof(zeros), digest1);
44         hmac_md5(digest1, packet_digest, 8, sequence_key);
45         arcfour_crypt(seq_num, sequence_key, 8);
46
47         state->seq_num++;
48 }
49
50
51 /*******************************************************************
52  Calculate the key with which to encode the data payload
53  ********************************************************************/
54 static void netsec_get_sealing_key(const uint8_t session_key[16],
55                                    const uint8_t seq_num[8],
56                                    uint8_t sealing_key[16])
57 {
58         static const uint8_t zeros[4];
59         uint8_t digest2[16];
60         uint8_t sess_kf0[16];
61         int i;
62
63         for (i = 0; i < 16; i++) {
64                 sess_kf0[i] = session_key[i] ^ 0xf0;
65         }
66
67         hmac_md5(sess_kf0, zeros, 4, digest2);
68         hmac_md5(digest2, seq_num, 8, sealing_key);
69 }
70
71
72 /*******************************************************************
73  Create a digest over the entire packet (including the data), and
74  MD5 it with the session key.
75  ********************************************************************/
76 static void schannel_digest(const uint8_t sess_key[16],
77                             const uint8_t netsec_sig[8],
78                             const uint8_t *confounder,
79                             const uint8_t *data, size_t data_len,
80                             uint8_t digest_final[16])
81 {
82         uint8_t packet_digest[16];
83         static const uint8_t zeros[4];
84         struct MD5Context ctx;
85
86         MD5Init(&ctx);
87         MD5Update(&ctx, zeros, 4);
88         MD5Update(&ctx, netsec_sig, 8);
89         if (confounder) {
90                 MD5Update(&ctx, confounder, 8);
91         }
92         MD5Update(&ctx, data, data_len);
93         MD5Final(packet_digest, &ctx);
94
95         hmac_md5(sess_key, packet_digest, sizeof(packet_digest), digest_final);
96 }
97
98
99 /*
100   unseal a packet
101 */
102 NTSTATUS schannel_unseal_packet(struct schannel_state *state,
103                                 TALLOC_CTX *mem_ctx,
104                                 uint8_t *data, size_t length,
105                                 const DATA_BLOB *sig)
106 {
107         uint8_t digest_final[16];
108         uint8_t confounder[8];
109         uint8_t seq_num[8];
110         uint8_t sealing_key[16];
111         static const uint8_t netsec_sig[8] = NETSEC_SEAL_SIGNATURE;
112
113         if (sig->length != 32) {
114                 return NT_STATUS_ACCESS_DENIED;
115         }
116
117         memcpy(confounder, sig->data+24, 8);
118
119         RSIVAL(seq_num, 0, state->seq_num);
120         SIVAL(seq_num, 4, state->initiator?0:0x80);
121
122         netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key);
123         arcfour_crypt(confounder, sealing_key, 8);
124         arcfour_crypt(data, sealing_key, length);
125
126         schannel_digest(state->creds->session_key,
127                         netsec_sig, confounder,
128                         data, length, digest_final);
129
130         if (memcmp(digest_final, sig->data+16, 8) != 0) {
131                 dump_data_pw("calc digest:", digest_final, 8);
132                 dump_data_pw("wire digest:", sig->data+16, 8);
133                 return NT_STATUS_ACCESS_DENIED;
134         }
135
136         netsec_deal_with_seq_num(state, digest_final, seq_num);
137
138         if (memcmp(seq_num, sig->data+8, 8) != 0) {
139                 dump_data_pw("calc seq num:", seq_num, 8);
140                 dump_data_pw("wire seq num:", sig->data+8, 8);
141                 return NT_STATUS_ACCESS_DENIED;
142         }
143
144         return NT_STATUS_OK;
145 }
146
147 /*
148   check the signature on a packet
149 */
150 NTSTATUS schannel_check_packet(struct schannel_state *state,
151                                TALLOC_CTX *mem_ctx,
152                                const uint8_t *data, size_t length,
153                                const DATA_BLOB *sig)
154 {
155         uint8_t digest_final[16];
156         uint8_t seq_num[8];
157         static const uint8_t netsec_sig[8] = NETSEC_SIGN_SIGNATURE;
158
159         /* w2k sends just 24 bytes and skip the confounder */
160         if (sig->length != 32 && sig->length != 24) {
161                 return NT_STATUS_ACCESS_DENIED;
162         }
163
164         RSIVAL(seq_num, 0, state->seq_num);
165         SIVAL(seq_num, 4, state->initiator?0:0x80);
166
167         dump_data_pw("seq_num:\n", seq_num, 8);
168         dump_data_pw("sess_key:\n", state->creds->session_key, 16);
169
170         schannel_digest(state->creds->session_key,
171                         netsec_sig, NULL,
172                         data, length, digest_final);
173
174         netsec_deal_with_seq_num(state, digest_final, seq_num);
175
176         if (memcmp(seq_num, sig->data+8, 8) != 0) {
177                 dump_data_pw("calc seq num:", seq_num, 8);
178                 dump_data_pw("wire seq num:", sig->data+8, 8);
179                 return NT_STATUS_ACCESS_DENIED;
180         }
181
182         if (memcmp(digest_final, sig->data+16, 8) != 0) {
183                 dump_data_pw("calc digest:", digest_final, 8);
184                 dump_data_pw("wire digest:", sig->data+16, 8);
185                 return NT_STATUS_ACCESS_DENIED;
186         }
187
188         return NT_STATUS_OK;
189 }
190
191
192 /*
193   seal a packet
194 */
195 NTSTATUS schannel_seal_packet(struct schannel_state *state,
196                               TALLOC_CTX *mem_ctx,
197                               uint8_t *data, size_t length,
198                               DATA_BLOB *sig)
199 {
200         uint8_t digest_final[16];
201         uint8_t confounder[8];
202         uint8_t seq_num[8];
203         uint8_t sealing_key[16];
204         static const uint8_t netsec_sig[8] = NETSEC_SEAL_SIGNATURE;
205
206         generate_random_buffer(confounder, 8);
207
208         RSIVAL(seq_num, 0, state->seq_num);
209         SIVAL(seq_num, 4, state->initiator?0x80:0);
210
211         schannel_digest(state->creds->session_key,
212                         netsec_sig, confounder,
213                         data, length, digest_final);
214
215         netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key);
216         arcfour_crypt(confounder, sealing_key, 8);
217         arcfour_crypt(data, sealing_key, length);
218
219         netsec_deal_with_seq_num(state, digest_final, seq_num);
220
221         (*sig) = data_blob_talloc(mem_ctx, NULL, 32);
222
223         memcpy(sig->data, netsec_sig, 8);
224         memcpy(sig->data+8, seq_num, 8);
225         memcpy(sig->data+16, digest_final, 8);
226         memcpy(sig->data+24, confounder, 8);
227
228         dump_data_pw("signature:", sig->data+ 0, 8);
229         dump_data_pw("seq_num  :", sig->data+ 8, 8);
230         dump_data_pw("digest   :", sig->data+16, 8);
231         dump_data_pw("confound :", sig->data+24, 8);
232
233         return NT_STATUS_OK;
234 }
235
236
237 /*
238   sign a packet
239 */
240 NTSTATUS schannel_sign_packet(struct schannel_state *state,
241                               TALLOC_CTX *mem_ctx,
242                               const uint8_t *data, size_t length,
243                               DATA_BLOB *sig)
244 {
245         uint8_t digest_final[16];
246         uint8_t seq_num[8];
247         static const uint8_t netsec_sig[8] = NETSEC_SIGN_SIGNATURE;
248
249         RSIVAL(seq_num, 0, state->seq_num);
250         SIVAL(seq_num, 4, state->initiator?0x80:0);
251
252         schannel_digest(state->creds->session_key,
253                         netsec_sig, NULL,
254                         data, length, digest_final);
255
256         netsec_deal_with_seq_num(state, digest_final, seq_num);
257
258         (*sig) = data_blob_talloc(mem_ctx, NULL, 32);
259
260         memcpy(sig->data, netsec_sig, 8);
261         memcpy(sig->data+8, seq_num, 8);
262         memcpy(sig->data+16, digest_final, 8);
263         memset(sig->data+24, 0, 8);
264
265         dump_data_pw("signature:", sig->data+ 0, 8);
266         dump_data_pw("seq_num  :", sig->data+ 8, 8);
267         dump_data_pw("digest   :", sig->data+16, 8);
268         dump_data_pw("confound :", sig->data+24, 8);
269
270         return NT_STATUS_OK;
271 }