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