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 | static void netsec_offset_and_sizes(struct schannel_state *state,
|
---|
28 | bool do_seal,
|
---|
29 | uint32_t *_min_sig_size,
|
---|
30 | uint32_t *_used_sig_size,
|
---|
31 | uint32_t *_checksum_length,
|
---|
32 | uint32_t *_confounder_ofs)
|
---|
33 | {
|
---|
34 | uint32_t min_sig_size = 24;
|
---|
35 | uint32_t used_sig_size = 32;
|
---|
36 | uint32_t checksum_length = 8;
|
---|
37 | uint32_t confounder_ofs = 24;
|
---|
38 |
|
---|
39 | if (do_seal) {
|
---|
40 | min_sig_size += 8;
|
---|
41 | }
|
---|
42 |
|
---|
43 | if (_min_sig_size) {
|
---|
44 | *_min_sig_size = min_sig_size;
|
---|
45 | }
|
---|
46 |
|
---|
47 | if (_used_sig_size) {
|
---|
48 | *_used_sig_size = used_sig_size;
|
---|
49 | }
|
---|
50 |
|
---|
51 | if (_checksum_length) {
|
---|
52 | *_checksum_length = checksum_length;
|
---|
53 | }
|
---|
54 |
|
---|
55 | if (_confounder_ofs) {
|
---|
56 | *_confounder_ofs = confounder_ofs;
|
---|
57 | }
|
---|
58 | }
|
---|
59 |
|
---|
60 | /*******************************************************************
|
---|
61 | Encode or Decode the sequence number (which is symmetric)
|
---|
62 | ********************************************************************/
|
---|
63 | static void netsec_do_seq_num(struct schannel_state *state,
|
---|
64 | const uint8_t *checksum,
|
---|
65 | uint32_t checksum_length,
|
---|
66 | uint8_t seq_num[8])
|
---|
67 | {
|
---|
68 | static const uint8_t zeros[4];
|
---|
69 | uint8_t sequence_key[16];
|
---|
70 | uint8_t digest1[16];
|
---|
71 |
|
---|
72 | hmac_md5(state->creds->session_key, zeros, sizeof(zeros), digest1);
|
---|
73 | hmac_md5(digest1, checksum, checksum_length, sequence_key);
|
---|
74 | arcfour_crypt(seq_num, sequence_key, 8);
|
---|
75 |
|
---|
76 | state->seq_num++;
|
---|
77 | }
|
---|
78 |
|
---|
79 | static void netsec_do_seal(struct schannel_state *state,
|
---|
80 | const uint8_t seq_num[8],
|
---|
81 | uint8_t confounder[8],
|
---|
82 | uint8_t *data, uint32_t length)
|
---|
83 | {
|
---|
84 | uint8_t sealing_key[16];
|
---|
85 | static const uint8_t zeros[4];
|
---|
86 | uint8_t digest2[16];
|
---|
87 | uint8_t sess_kf0[16];
|
---|
88 | int i;
|
---|
89 |
|
---|
90 | for (i = 0; i < 16; i++) {
|
---|
91 | sess_kf0[i] = state->creds->session_key[i] ^ 0xf0;
|
---|
92 | }
|
---|
93 |
|
---|
94 | hmac_md5(sess_kf0, zeros, 4, digest2);
|
---|
95 | hmac_md5(digest2, seq_num, 8, sealing_key);
|
---|
96 |
|
---|
97 | arcfour_crypt(confounder, sealing_key, 8);
|
---|
98 | arcfour_crypt(data, sealing_key, length);
|
---|
99 | }
|
---|
100 |
|
---|
101 | /*******************************************************************
|
---|
102 | Create a digest over the entire packet (including the data), and
|
---|
103 | MD5 it with the session key.
|
---|
104 | ********************************************************************/
|
---|
105 | static void netsec_do_sign(struct schannel_state *state,
|
---|
106 | const uint8_t *confounder,
|
---|
107 | const uint8_t *data, size_t data_len,
|
---|
108 | uint8_t header[8],
|
---|
109 | uint8_t *checksum)
|
---|
110 | {
|
---|
111 | uint8_t packet_digest[16];
|
---|
112 | static const uint8_t zeros[4];
|
---|
113 | struct MD5Context ctx;
|
---|
114 |
|
---|
115 | MD5Init(&ctx);
|
---|
116 | MD5Update(&ctx, zeros, 4);
|
---|
117 | if (confounder) {
|
---|
118 | SSVAL(header, 0, NL_SIGN_HMAC_MD5);
|
---|
119 | SSVAL(header, 2, NL_SEAL_RC4);
|
---|
120 | SSVAL(header, 4, 0xFFFF);
|
---|
121 | SSVAL(header, 6, 0x0000);
|
---|
122 |
|
---|
123 | MD5Update(&ctx, header, 8);
|
---|
124 | MD5Update(&ctx, confounder, 8);
|
---|
125 | } else {
|
---|
126 | SSVAL(header, 0, NL_SIGN_HMAC_MD5);
|
---|
127 | SSVAL(header, 2, NL_SEAL_NONE);
|
---|
128 | SSVAL(header, 4, 0xFFFF);
|
---|
129 | SSVAL(header, 6, 0x0000);
|
---|
130 |
|
---|
131 | MD5Update(&ctx, header, 8);
|
---|
132 | }
|
---|
133 | MD5Update(&ctx, data, data_len);
|
---|
134 | MD5Final(packet_digest, &ctx);
|
---|
135 |
|
---|
136 | hmac_md5(state->creds->session_key,
|
---|
137 | packet_digest, sizeof(packet_digest),
|
---|
138 | checksum);
|
---|
139 | }
|
---|
140 |
|
---|
141 | NTSTATUS netsec_incoming_packet(struct schannel_state *state,
|
---|
142 | TALLOC_CTX *mem_ctx,
|
---|
143 | bool do_unseal,
|
---|
144 | uint8_t *data, size_t length,
|
---|
145 | const DATA_BLOB *sig)
|
---|
146 | {
|
---|
147 | uint32_t min_sig_size = 0;
|
---|
148 | uint8_t header[8];
|
---|
149 | uint8_t checksum[32];
|
---|
150 | uint32_t checksum_length = sizeof(checksum_length);
|
---|
151 | uint8_t _confounder[8];
|
---|
152 | uint8_t *confounder = NULL;
|
---|
153 | uint32_t confounder_ofs = 0;
|
---|
154 | uint8_t seq_num[8];
|
---|
155 | int ret;
|
---|
156 |
|
---|
157 | netsec_offset_and_sizes(state,
|
---|
158 | do_unseal,
|
---|
159 | &min_sig_size,
|
---|
160 | NULL,
|
---|
161 | &checksum_length,
|
---|
162 | &confounder_ofs);
|
---|
163 |
|
---|
164 | if (sig->length < min_sig_size) {
|
---|
165 | return NT_STATUS_ACCESS_DENIED;
|
---|
166 | }
|
---|
167 |
|
---|
168 | if (do_unseal) {
|
---|
169 | confounder = _confounder;
|
---|
170 | memcpy(confounder, sig->data+confounder_ofs, 8);
|
---|
171 | } else {
|
---|
172 | confounder = NULL;
|
---|
173 | }
|
---|
174 |
|
---|
175 | RSIVAL(seq_num, 0, state->seq_num);
|
---|
176 | SIVAL(seq_num, 4, state->initiator?0:0x80);
|
---|
177 |
|
---|
178 | if (do_unseal) {
|
---|
179 | netsec_do_seal(state, seq_num,
|
---|
180 | confounder,
|
---|
181 | data, length);
|
---|
182 | }
|
---|
183 |
|
---|
184 | netsec_do_sign(state, confounder,
|
---|
185 | data, length,
|
---|
186 | header, checksum);
|
---|
187 |
|
---|
188 | ret = memcmp(checksum, sig->data+16, checksum_length);
|
---|
189 | if (ret != 0) {
|
---|
190 | dump_data_pw("calc digest:", checksum, checksum_length);
|
---|
191 | dump_data_pw("wire digest:", sig->data+16, checksum_length);
|
---|
192 | return NT_STATUS_ACCESS_DENIED;
|
---|
193 | }
|
---|
194 |
|
---|
195 | netsec_do_seq_num(state, checksum, checksum_length, seq_num);
|
---|
196 |
|
---|
197 | ret = memcmp(seq_num, sig->data+8, 8);
|
---|
198 | if (ret != 0) {
|
---|
199 | dump_data_pw("calc seq num:", seq_num, 8);
|
---|
200 | dump_data_pw("wire seq num:", sig->data+8, 8);
|
---|
201 | return NT_STATUS_ACCESS_DENIED;
|
---|
202 | }
|
---|
203 |
|
---|
204 | return NT_STATUS_OK;
|
---|
205 | }
|
---|
206 |
|
---|
207 | uint32_t netsec_outgoing_sig_size(struct schannel_state *state)
|
---|
208 | {
|
---|
209 | uint32_t sig_size = 0;
|
---|
210 |
|
---|
211 | netsec_offset_and_sizes(state,
|
---|
212 | true,
|
---|
213 | NULL,
|
---|
214 | &sig_size,
|
---|
215 | NULL,
|
---|
216 | NULL);
|
---|
217 |
|
---|
218 | return sig_size;
|
---|
219 | }
|
---|
220 |
|
---|
221 | NTSTATUS netsec_outgoing_packet(struct schannel_state *state,
|
---|
222 | TALLOC_CTX *mem_ctx,
|
---|
223 | bool do_seal,
|
---|
224 | uint8_t *data, size_t length,
|
---|
225 | DATA_BLOB *sig)
|
---|
226 | {
|
---|
227 | uint32_t min_sig_size = 0;
|
---|
228 | uint32_t used_sig_size = 0;
|
---|
229 | uint8_t header[8];
|
---|
230 | uint8_t checksum[32];
|
---|
231 | uint32_t checksum_length = sizeof(checksum_length);
|
---|
232 | uint8_t _confounder[8];
|
---|
233 | uint8_t *confounder = NULL;
|
---|
234 | uint32_t confounder_ofs = 0;
|
---|
235 | uint8_t seq_num[8];
|
---|
236 |
|
---|
237 | netsec_offset_and_sizes(state,
|
---|
238 | do_seal,
|
---|
239 | &min_sig_size,
|
---|
240 | &used_sig_size,
|
---|
241 | &checksum_length,
|
---|
242 | &confounder_ofs);
|
---|
243 |
|
---|
244 | RSIVAL(seq_num, 0, state->seq_num);
|
---|
245 | SIVAL(seq_num, 4, state->initiator?0x80:0);
|
---|
246 |
|
---|
247 | if (do_seal) {
|
---|
248 | confounder = _confounder;
|
---|
249 | generate_random_buffer(confounder, 8);
|
---|
250 | } else {
|
---|
251 | confounder = NULL;
|
---|
252 | }
|
---|
253 |
|
---|
254 | netsec_do_sign(state, confounder,
|
---|
255 | data, length,
|
---|
256 | header, checksum);
|
---|
257 |
|
---|
258 | if (do_seal) {
|
---|
259 | netsec_do_seal(state, seq_num,
|
---|
260 | confounder,
|
---|
261 | data, length);
|
---|
262 | }
|
---|
263 |
|
---|
264 | netsec_do_seq_num(state, checksum, checksum_length, seq_num);
|
---|
265 |
|
---|
266 | (*sig) = data_blob_talloc_zero(mem_ctx, used_sig_size);
|
---|
267 |
|
---|
268 | memcpy(sig->data, header, 8);
|
---|
269 | memcpy(sig->data+8, seq_num, 8);
|
---|
270 | memcpy(sig->data+16, checksum, checksum_length);
|
---|
271 |
|
---|
272 | if (confounder) {
|
---|
273 | memcpy(sig->data+confounder_ofs, confounder, 8);
|
---|
274 | }
|
---|
275 |
|
---|
276 | dump_data_pw("signature:", sig->data+ 0, 8);
|
---|
277 | dump_data_pw("seq_num :", sig->data+ 8, 8);
|
---|
278 | dump_data_pw("digest :", sig->data+16, checksum_length);
|
---|
279 | dump_data_pw("confound :", sig->data+confounder_ofs, 8);
|
---|
280 |
|
---|
281 | return NT_STATUS_OK;
|
---|
282 | }
|
---|