File: | src/usr.sbin/npppd/npppd/mppe.c |
Warning: | line 325, column 2 Value stored to 'pktp0' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: mppe.c,v 1.15 2019/02/27 04:52:19 denis Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2009 Internet Initiative Japan Inc. |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. |
27 | */ |
28 | /* $Id: mppe.c,v 1.15 2019/02/27 04:52:19 denis Exp $ */ |
29 | /**@file |
30 | * |
31 | * The implementation of MPPE(Microsoft Point-To-Point Encryption Protocol) |
32 | */ |
33 | /* |
34 | * To avoid the PPP packet out of sequence problem. |
35 | * It may avoid if it reconstruct the frame order in L2TP/IPsec. |
36 | */ |
37 | #define WORKAROUND_OUT_OF_SEQUENCE_PPP_FRAMING1 1 |
38 | |
39 | #include <sys/types.h> |
40 | #include <sys/socket.h> |
41 | #include <sys/time.h> |
42 | #include <net/if_dl.h> |
43 | #include <netinet/in.h> |
44 | #include <endian.h> |
45 | #include <stdlib.h> |
46 | #include <stdio.h> |
47 | #include <stdarg.h> |
48 | #include <syslog.h> |
49 | #include <string.h> |
50 | #include <event.h> |
51 | #ifdef WITH_OPENSSL |
52 | #include <openssl/sha.h> |
53 | #include <openssl/rc4.h> |
54 | #endif |
55 | |
56 | #include "npppd.h" |
57 | #include "debugutil.h" |
58 | |
59 | #ifdef MPPE_DEBUG |
60 | #define MPPE_DBG(x) mppe_log x |
61 | #define MPPE_ASSERT(x) \ |
62 | if (!(x)) { \ |
63 | fprintf(stderr(&__sF[2]), \ |
64 | "\nASSERT(%s) failed on %s() at %s:%d.\n" \ |
65 | , #x, __func__, __FILE__"/usr/src/usr.sbin/npppd/npppd/mppe.c", __LINE__65); \ |
66 | abort(); \ |
67 | } |
68 | #else |
69 | #define MPPE_DBG(x) |
70 | #define MPPE_ASSERT(x) |
71 | #endif |
72 | |
73 | #define SESS_KEY_LEN(len)(len < 16)? 8 : 16 (len < 16)? 8 : 16 |
74 | |
75 | #define COHER_EQ(a, b)((((a) - (b)) & 0xfff) == 0) ((((a) - (b)) & 0xfff) == 0) |
76 | #define COHER_LT(a, b)(((int16_t)(((a) - (b)) << 4)) < 0) (((int16_t)(((a) - (b)) << 4)) < 0) |
77 | #define COHER_GT(a, b)(((int16_t)((((b)) - ((a))) << 4)) < 0) COHER_LT((b), (a))(((int16_t)((((b)) - ((a))) << 4)) < 0) |
78 | #define COHER_NE(a, b)(!(((((a)) - ((b))) & 0xfff) == 0)) (!COHER_EQ((a), (b))(((((a)) - ((b))) & 0xfff) == 0)) |
79 | #define COHER_LE(a, b)(!(!(((int16_t)(((((b))) - (((a)))) << 4)) < 0))) (!COHER_GE((b), (a))(!(((int16_t)(((((b))) - (((a)))) << 4)) < 0))) |
80 | #define COHER_GE(a, b)(!(((int16_t)((((a)) - ((b))) << 4)) < 0)) (!COHER_LT((a), (b))(((int16_t)((((a)) - ((b))) << 4)) < 0)) |
81 | |
82 | |
83 | static const char *mppe_bits_to_string(uint32_t); |
84 | static void mppe_log(mppe *, uint32_t, const char *, ...) __printflike(3,4)__attribute__((__format__ (__printf__, 3, 4))); |
85 | static int mppe_rc4_init(mppe *, mppe_rc4_t *, int); |
86 | static int mppe_rc4_setkey(mppe *, mppe_rc4_t *); |
87 | static int mppe_rc4_setoldkey(mppe *, mppe_rc4_t *, uint16_t); |
88 | static void mppe_rc4_destroy(mppe *, mppe_rc4_t *); |
89 | static void mppe_rc4_encrypt(mppe *, mppe_rc4_t *, int, u_char *, u_char *); |
90 | static void *rc4_create_ctx(void); |
91 | static int rc4_key(void *, int, u_char *); |
92 | static void rc4(void *, int, u_char *, u_char *); |
93 | static void GetNewKeyFromSHA(u_char *, u_char *, int, u_char *); |
94 | |
95 | /** |
96 | * initializing mppe context. |
97 | * - reading configuration. |
98 | */ |
99 | void |
100 | mppe_init(mppe *_this, npppd_ppp *ppp) |
101 | { |
102 | struct tunnconf *conf; |
103 | |
104 | MPPE_ASSERT(ppp != NULL); |
105 | MPPE_ASSERT(_this != NULL); |
106 | |
107 | memset(_this, 0, sizeof(mppe)); |
108 | |
109 | _this->ppp = ppp; |
110 | |
111 | _this->mode_auto = 1; |
112 | _this->mode_stateless = 0; |
113 | |
114 | conf = ppp_get_tunnconf(ppp); |
115 | _this->enabled = conf->mppe_yesno; |
116 | if (_this->enabled == 0) |
117 | goto mppe_config_done; |
118 | |
119 | _this->required = conf->mppe_required; |
120 | |
121 | if (conf->mppe_keystate == (NPPPD_MPPE_STATEFUL0x0001|NPPPD_MPPE_STATELESS0x0002)) { |
122 | /* no need to change from default. */ |
123 | } else if (conf->mppe_keystate == NPPPD_MPPE_STATELESS0x0002) { |
124 | _this->mode_auto = 0; |
125 | _this->mode_stateless = 1; |
126 | } else if (conf->mppe_keystate == NPPPD_MPPE_STATEFUL0x0001) { |
127 | _this->mode_auto = 0; |
128 | _this->mode_stateless = 0; |
129 | } |
130 | |
131 | _this->keylenbits = 0; |
132 | if ((conf->mppe_keylen & NPPPD_MPPE_40BIT0x0001) != 0) |
133 | _this->keylenbits |= CCP_MPPE_NT_40bit0x00000020; |
134 | if ((conf->mppe_keylen & NPPPD_MPPE_56BIT0x0002) != 0) |
135 | _this->keylenbits |= CCP_MPPE_NT_56bit0x00000080; |
136 | if ((conf->mppe_keylen & NPPPD_MPPE_128BIT0x0004) != 0) |
137 | _this->keylenbits |= CCP_MPPE_NT_128bit0x00000040; |
138 | |
139 | mppe_config_done: |
140 | /* nothing */; |
141 | } |
142 | |
143 | void |
144 | mppe_fini(mppe *_this) |
145 | { |
146 | mppe_rc4_destroy(_this, &_this->send); |
147 | mppe_rc4_destroy(_this, &_this->recv); |
148 | } |
149 | |
150 | static void |
151 | mppe_reduce_key(mppe_rc4_t *_this) |
152 | { |
153 | switch (_this->keybits) { |
154 | case 40: |
155 | _this->session_key[1] = 0x26; |
156 | _this->session_key[2] = 0x9e; |
157 | case 56: |
158 | _this->session_key[0] = 0xd1; |
159 | } |
160 | } |
161 | |
162 | static void |
163 | mppe_key_change(mppe *_mppe, mppe_rc4_t *_this) |
164 | { |
165 | u_char interim[16]; |
166 | void *keychg; |
167 | |
168 | keychg = rc4_create_ctx(); |
169 | |
170 | GetNewKeyFromSHA(_this->master_key, _this->session_key, |
171 | _this->keylen, interim); |
172 | |
173 | rc4_key(keychg, _this->keylen, interim); |
174 | rc4(keychg, _this->keylen, interim, _this->session_key); |
175 | mppe_reduce_key(_this); |
176 | |
177 | if (_this->old_session_keys) { |
178 | int idx = _this->coher_cnt % MPPE_NOLDKEY64; |
179 | memcpy(_this->old_session_keys[idx], |
180 | _this->session_key, MPPE_KEYLEN16); |
181 | } |
182 | |
183 | free(keychg); |
184 | } |
185 | |
186 | /** |
187 | * starting mppe protocol. |
188 | */ |
189 | void |
190 | mppe_start(mppe *_this) |
191 | { |
192 | char buf[256]; |
193 | |
194 | strlcpy(buf, mppe_bits_to_string(_this->ppp->ccp.mppe_o_bits), |
195 | sizeof(buf)); |
196 | |
197 | mppe_log(_this, LOG_INFO6, "logtype=Opened our=%s peer=%s", buf, |
198 | mppe_bits_to_string(_this->ppp->ccp.mppe_p_bits)); |
199 | |
200 | _this->ppp->mppe_started = 1; |
201 | |
202 | _this->send.stateless = |
203 | ((_this->ppp->ccp.mppe_o_bits & CCP_MPPE_STATELESS0x01000000) != 0)? 1 : 0; |
204 | |
205 | if ((_this->ppp->ccp.mppe_o_bits & CCP_MPPE_NT_40bit0x00000020) != 0) { |
206 | _this->send.keylen = 8; |
207 | _this->send.keybits = 40; |
208 | } else if ((_this->ppp->ccp.mppe_o_bits & CCP_MPPE_NT_56bit0x00000080) != 0) { |
209 | _this->send.keylen = 8; |
210 | _this->send.keybits = 56; |
211 | } else if ((_this->ppp->ccp.mppe_o_bits & CCP_MPPE_NT_128bit0x00000040) != 0) { |
212 | _this->send.keylen = 16; |
213 | _this->send.keybits = 128; |
214 | } |
215 | |
216 | _this->recv.stateless = |
217 | ((_this->ppp->ccp.mppe_p_bits & CCP_MPPE_STATELESS0x01000000) != 0)? 1 : 0; |
218 | if ((_this->ppp->ccp.mppe_p_bits & CCP_MPPE_NT_40bit0x00000020) != 0) { |
219 | _this->recv.keylen = 8; |
220 | _this->recv.keybits = 40; |
221 | } else if ((_this->ppp->ccp.mppe_p_bits & CCP_MPPE_NT_56bit0x00000080) != 0) { |
222 | _this->recv.keylen = 8; |
223 | _this->recv.keybits = 56; |
224 | } else if ((_this->ppp->ccp.mppe_p_bits & CCP_MPPE_NT_128bit0x00000040) != 0) { |
225 | _this->recv.keylen = 16; |
226 | _this->recv.keybits = 128; |
227 | } |
228 | |
229 | if (_this->send.keybits > 0) { |
230 | mppe_rc4_init(_this, &_this->send, 0); |
231 | GetNewKeyFromSHA(_this->send.master_key, _this->send.master_key, |
232 | _this->send.keylen, _this->send.session_key); |
233 | mppe_reduce_key(&_this->send); |
234 | mppe_rc4_setkey(_this, &_this->send); |
235 | } |
236 | if (_this->recv.keybits > 0) { |
237 | mppe_rc4_init(_this, &_this->recv, _this->recv.stateless); |
238 | GetNewKeyFromSHA(_this->recv.master_key, _this->recv.master_key, |
239 | _this->recv.keylen, _this->recv.session_key); |
240 | mppe_reduce_key(&_this->recv); |
241 | mppe_rc4_setkey(_this, &_this->recv); |
242 | } |
243 | } |
244 | |
245 | /** |
246 | * creating the mppe bits. In case of first proposal, it specifies the |
247 | * peer_bits as 0 value. If it specifies the peer_bits, it returns the |
248 | * value as peer's proposal. |
249 | */ |
250 | uint32_t |
251 | mppe_create_our_bits(mppe *_this, uint32_t peer_bits) |
252 | { |
253 | uint32_t our_bits; |
254 | |
255 | /* default proposal */ |
256 | our_bits = _this->keylenbits; |
257 | if (peer_bits != 0 && (peer_bits & our_bits) != 0) { |
258 | if ((peer_bits & CCP_MPPE_NT_128bit0x00000040) != 0) |
259 | our_bits = CCP_MPPE_NT_128bit0x00000040; |
260 | else if ((peer_bits & CCP_MPPE_NT_56bit0x00000080) != 0) |
261 | our_bits = CCP_MPPE_NT_56bit0x00000080; |
262 | else if ((peer_bits & CCP_MPPE_NT_40bit0x00000020) != 0) |
263 | our_bits = CCP_MPPE_NT_40bit0x00000020; |
264 | } |
265 | |
266 | if (_this->mode_auto != 0) { |
267 | /* in case of auto_mode */ |
268 | if (peer_bits == 0) { |
269 | /* |
270 | * It proposes stateless mode in first time. Windows 9x has |
271 | * a bug that it is reverse to stateful and stateless in |
272 | * sending and receiving packets. |
273 | * Windows 9x is prior to negotiate in stateless mode, so |
274 | * it will avoid the Windows bug to be prior to negotiate |
275 | * in stateless mode. |
276 | * |
277 | * Even if this bug doesn't exists, the stateful mode is high |
278 | * cost from user's viewpoint when packets may loss more than a |
279 | * certain rate, so it is not good choice to use via Internet or |
280 | * wireless LAN. |
281 | */ |
282 | our_bits |= CCP_MPPE_STATELESS0x01000000; |
283 | } else { |
284 | /* giving up */ |
285 | our_bits |= peer_bits & CCP_MPPE_STATELESS0x01000000; |
286 | } |
287 | } else { |
288 | /* it doesn't give up in case of setting non-auto value. */ |
289 | if (_this->mode_stateless != 0) |
290 | our_bits |= CCP_MPPE_STATELESS0x01000000; |
291 | } |
292 | if (peer_bits != 0 && our_bits != peer_bits) { |
293 | char obuf[128], pbuf[128]; |
294 | |
295 | /* in case of failure, it puts a log. */ |
296 | strlcpy(obuf, mppe_bits_to_string(our_bits), sizeof(obuf)); |
297 | strlcpy(pbuf, mppe_bits_to_string(peer_bits), sizeof(pbuf)); |
298 | mppe_log(_this, LOG_INFO6, |
299 | "mismatch our=%s peer=%s", obuf, pbuf); |
300 | } |
301 | |
302 | return our_bits; |
303 | } |
304 | |
305 | #define COHERENCY_CNT_MASK0x0fff; 0x0fff; |
306 | |
307 | /** |
308 | * receiving packets via MPPE. |
309 | * len must be 4 at least. |
310 | */ |
311 | void |
312 | mppe_input(mppe *_this, u_char *pktp, int len) |
313 | { |
314 | int pktloss, encrypt, flushed, m, n; |
315 | uint16_t coher_cnt; |
316 | u_char *pktp0, *opktp, *opktp0; |
317 | uint16_t proto; |
318 | int delayed = 0; |
319 | |
320 | encrypt = 0; |
321 | flushed = 0; |
322 | |
323 | MPPE_ASSERT(len >= 4); |
324 | |
325 | pktp0 = pktp; |
Value stored to 'pktp0' is never read | |
326 | GETSHORT(coher_cnt, pktp){ (coher_cnt) = *(pktp)++ << 8; (coher_cnt) |= *(pktp)++ ; }; |
327 | |
328 | flushed = (coher_cnt & 0x8000)? 1 : 0; |
329 | encrypt = (coher_cnt & 0x1000)? 1 : 0; |
330 | coher_cnt &= COHERENCY_CNT_MASK0x0fff;; |
331 | pktloss = 0; |
332 | |
333 | MPPE_DBG((_this, DEBUG_LEVEL_2, "in coher_cnt=%03x/%03x %s%s", |
334 | _this->recv.coher_cnt, coher_cnt, (flushed)? "[flushed]" : "", |
335 | (encrypt)? "[encrypt]" : "")); |
336 | |
337 | if (encrypt == 0) { |
338 | mppe_log(_this, LOG_WARNING4, |
339 | "Received unexpected MPPE packet. (no encrypt)"); |
340 | return; |
341 | } |
342 | |
343 | /* |
344 | * In L2TP/IPsec implementation, in case that the ppp frame sequence |
345 | * is not able to reconstruct and the ppp frame is out of sequence, it |
346 | * is unable to identify with many packets losing. If it does so, MPPE |
347 | * key is out of place. |
348 | * To avoid this problem, when it seems that more than 4096-256 packets |
349 | * drops, it assumes that the packet doesn't lose but the packet is out |
350 | * of sequence. |
351 | */ |
352 | { |
353 | int coher_cnt0; |
354 | |
355 | coher_cnt0 = coher_cnt; |
356 | if (coher_cnt < _this->recv.coher_cnt) |
357 | coher_cnt0 += 0x1000; |
358 | if (coher_cnt0 - _this->recv.coher_cnt > 0x0f00) { |
359 | if (!_this->recv.stateless || |
360 | coher_cnt0 - _this->recv.coher_cnt |
361 | <= 0x1000 - MPPE_NOLDKEY64) { |
362 | mppe_log(_this, LOG_INFO6, |
363 | "Workaround the out-of-sequence PPP framing problem: " |
364 | "%d => %d", _this->recv.coher_cnt, coher_cnt); |
365 | return; |
366 | } |
367 | delayed = 1; |
368 | } |
369 | } |
370 | |
371 | if (_this->recv.stateless != 0) { |
372 | if (!delayed) { |
373 | mppe_key_change(_this, &_this->recv); |
374 | while (_this->recv.coher_cnt != coher_cnt) { |
375 | _this->recv.coher_cnt++; |
376 | _this->recv.coher_cnt &= COHERENCY_CNT_MASK0x0fff;; |
377 | mppe_key_change(_this, &_this->recv); |
378 | pktloss++; |
379 | } |
380 | } |
381 | mppe_rc4_setoldkey(_this, &_this->recv, coher_cnt); |
382 | flushed = 1; |
383 | } else { |
384 | if (flushed) { |
385 | if (coher_cnt < _this->recv.coher_cnt) { |
386 | /* in case of carrying up. */ |
387 | coher_cnt += 0x1000; |
388 | } |
389 | pktloss += coher_cnt - _this->recv.coher_cnt; |
390 | m = _this->recv.coher_cnt / 256; |
391 | n = coher_cnt / 256; |
392 | while (m++ < n) |
393 | mppe_key_change(_this, &_this->recv); |
394 | |
395 | coher_cnt &= COHERENCY_CNT_MASK0x0fff;; |
396 | _this->recv.coher_cnt = coher_cnt; |
397 | } else if (_this->recv.coher_cnt != coher_cnt) { |
398 | _this->recv.resetreq = 1; |
399 | |
400 | opktp0 = ppp_packetbuf(_this->ppp, |
401 | PPP_PROTO_NCP0x8000 | NCP_CCP0xfd); |
402 | opktp = opktp0; |
403 | |
404 | PUTLONG(_this->ppp->ccp.mppe_p_bits, opktp){ *(opktp)++ = (u_char) ((_this->ppp->ccp.mppe_p_bits) >> 24); *(opktp)++ = (u_char) ((_this->ppp->ccp.mppe_p_bits ) >> 16); *(opktp)++ = (u_char) ((_this->ppp->ccp .mppe_p_bits) >> 8); *(opktp)++ = (u_char) (_this->ppp ->ccp.mppe_p_bits); }; |
405 | |
406 | ppp_output(_this->ppp, PPP_PROTO_NCP0x8000 | NCP_CCP0xfd, |
407 | RESETREQ14, _this->recv.resetreq, opktp0, |
408 | opktp - opktp0); |
409 | return; |
410 | } |
411 | if ((coher_cnt & 0xff) == 0xff) { |
412 | mppe_key_change(_this, &_this->recv); |
413 | flushed = 1; |
414 | } |
415 | if (flushed) { |
416 | mppe_rc4_setkey(_this, &_this->recv); |
417 | } |
418 | } |
419 | |
420 | if (pktloss > 1000) { |
421 | /* |
422 | * In case of many packets losing or out of sequence. |
423 | * The latter is not able to communicate because the key is |
424 | * out of place soon. |
425 | * |
426 | */ |
427 | mppe_log(_this, LOG_WARNING4, "%d packets loss", pktloss); |
428 | } |
429 | |
430 | mppe_rc4_encrypt(_this, &_this->recv, len - 2, pktp, pktp); |
431 | |
432 | if (!delayed) { |
433 | _this->recv.coher_cnt++; |
434 | _this->recv.coher_cnt &= COHERENCY_CNT_MASK0x0fff;; |
435 | } |
436 | |
437 | if (pktp[0] & 1) |
438 | proto = pktp[0]; |
439 | else |
440 | proto = pktp[0] << 8 | pktp[1]; |
441 | /* |
442 | * According to RFC3078 section 3, |
443 | * MPPE only accept protocol number 0021-00FA. |
444 | * If decrypted protocol number is out of range, |
445 | * it indicates loss of coherency. |
446 | */ |
447 | if (!(proto & 1) || proto < 0x21 || proto > 0xfa) { |
448 | mppe_log(_this, LOG_INFO6, "MPPE coherency is lost"); |
449 | return; /* drop frame */ |
450 | } |
451 | |
452 | _this->ppp->recv_packet(_this->ppp, pktp, len - 2, |
453 | PPP_IO_FLAGS_MPPE_ENCRYPTED0x0001); |
454 | } |
455 | |
456 | /** |
457 | * The call out function in case of receiving CCP Reset (key reset in case |
458 | * of MPPE). |
459 | */ |
460 | void |
461 | mppe_recv_ccp_reset(mppe *_this) |
462 | { |
463 | MPPE_DBG((_this, DEBUG_LEVEL_2, "%s() is called.", __func__)); |
464 | _this->send.resetreq = 1; |
465 | } |
466 | |
467 | /** |
468 | * sending packet via MPPE. |
469 | */ |
470 | void |
471 | mppe_pkt_output(mppe *_this, uint16_t proto, u_char *pktp, int len) |
472 | { |
473 | int encrypt, flushed; |
474 | uint16_t coher_cnt; |
475 | u_char *outp, *outp0; |
476 | |
477 | MPPE_ASSERT(proto == PPP_PROTO_IP); |
478 | |
479 | flushed = 0; |
480 | encrypt = 1; |
481 | |
482 | outp = ppp_packetbuf(_this->ppp, PPP_PROTO_MPPE0x00FD); |
483 | outp0 = outp; |
484 | |
485 | if (_this->send.stateless != 0) { |
486 | flushed = 1; |
487 | mppe_key_change(_this, &_this->send); |
488 | } else { |
489 | if ((_this->send.coher_cnt % 0x100) == 0xff) { |
490 | flushed = 1; |
491 | mppe_key_change(_this, &_this->send); |
492 | } else if (_this->send.resetreq != 0) { |
493 | flushed = 1; |
494 | _this->send.resetreq = 0; |
495 | } |
496 | } |
497 | |
498 | if (flushed) { |
499 | mppe_rc4_setkey(_this, &_this->send); |
500 | } |
501 | |
502 | MPPE_DBG((_this, DEBUG_LEVEL_2, "out coher_cnt=%03x %s%s", |
503 | _this->send.coher_cnt, (flushed)? "[flushed]" : "", |
504 | (encrypt)? "[encrypt]" : "")); |
505 | |
506 | coher_cnt = _this->send.coher_cnt & COHERENCY_CNT_MASK0x0fff;; |
507 | if (flushed) |
508 | coher_cnt |= 0x8000; |
509 | if (encrypt) |
510 | coher_cnt |= 0x1000; |
511 | |
512 | PUTSHORT(coher_cnt, outp){ *(outp)++ = (u_char) ((coher_cnt) >> 8); *(outp)++ = ( u_char) (coher_cnt); }; |
513 | proto = htons(proto)(__uint16_t)(__builtin_constant_p(proto) ? (__uint16_t)(((__uint16_t )(proto) & 0xffU) << 8 | ((__uint16_t)(proto) & 0xff00U) >> 8) : __swap16md(proto)); |
514 | mppe_rc4_encrypt(_this, &_this->send, 2, (u_char *)&proto, outp); |
515 | mppe_rc4_encrypt(_this, &_this->send, len, pktp, outp + 2); |
516 | |
517 | ppp_output(_this->ppp, PPP_PROTO_MPPE0x00FD, 0, 0, outp0, len + 4); |
518 | _this->send.coher_cnt++; |
519 | _this->send.coher_cnt &= COHERENCY_CNT_MASK0x0fff;; |
520 | } |
521 | |
522 | static void |
523 | mppe_log(mppe *_this, uint32_t prio, const char *fmt, ...) |
524 | { |
525 | char logbuf[BUFSIZ1024]; |
526 | va_list ap; |
527 | |
528 | va_start(ap, fmt)__builtin_va_start(ap, fmt); |
529 | snprintf(logbuf, sizeof(logbuf), "ppp id=%u layer=mppe %s", |
530 | _this->ppp->id, fmt); |
531 | vlog_printf(prio, logbuf, ap); |
532 | va_end(ap)__builtin_va_end(ap); |
533 | } |
534 | |
535 | static const char * |
536 | mppe_bits_to_string(uint32_t bits) |
537 | { |
538 | static char buf[128]; |
539 | |
540 | snprintf(buf, sizeof(buf), "%s%s%s%s%s%s" |
541 | , ((CCP_MPPC_ALONE0x00000001 & bits) != 0)? ",mppc" : "" |
542 | , ((CCP_MPPE_LM_40bit0x00000010& bits) != 0)? ",40bit(LM)" : "" |
543 | , ((CCP_MPPE_NT_40bit0x00000020& bits) != 0)? ",40bit" : "" |
544 | , ((CCP_MPPE_NT_128bit0x00000040& bits) != 0)? ",128bit" : "" |
545 | , ((CCP_MPPE_NT_56bit0x00000080& bits) != 0)? ",56bit" : "" |
546 | , ((CCP_MPPE_STATELESS0x01000000& bits) != 0)? ",stateless" : ",stateful"); |
547 | |
548 | if (buf[0] == '\0') |
549 | return ""; |
550 | |
551 | return buf + 1; |
552 | } |
553 | |
554 | /************************************************************************ |
555 | * implementations of authentication/cipher algorism. |
556 | ************************************************************************/ |
557 | static u_char SHAPad1[] = { |
558 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
559 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
560 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
561 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
562 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
563 | }, SHAPad2[] = { |
564 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
565 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
566 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
567 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
568 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
569 | }; |
570 | #define ZeroMemory(dst, len)memset(dst, 0, len) memset(dst, 0, len) |
571 | #define MoveMemory(dst, src, len)memcpy(dst, src, len) memcpy(dst, src, len) |
572 | |
573 | #include <openssl/rc4.h> |
574 | #include <openssl/sha.h> |
575 | |
576 | #define SHA_CTXSHA_CTX SHA_CTXSHA_CTX |
577 | #define SHAInitSHA1_Init SHA1_Init |
578 | #define SHAUpdateSHA1_Update SHA1_Update |
579 | #define SHAFinal(ctx,digest)SHA1_Final(digest, ctx) SHA1_Final(digest, ctx) |
580 | |
581 | /************************************************************************ |
582 | * implementations of OpenSSL version |
583 | ************************************************************************/ |
584 | static void * |
585 | rc4_create_ctx(void) |
586 | { |
587 | return malloc(sizeof(RC4_KEY)); |
588 | } |
589 | |
590 | static int |
591 | rc4_key(void *rc4ctx, int lkey, u_char *key) |
592 | { |
593 | |
594 | RC4_set_key(rc4ctx, lkey, key); |
595 | |
596 | return 0; |
597 | } |
598 | |
599 | static void |
600 | rc4(void *rc4ctx, int len, u_char *indata, u_char *outdata) |
601 | { |
602 | RC4(rc4ctx, len, indata, outdata); |
603 | } |
604 | |
605 | static void |
606 | GetNewKeyFromSHA(u_char *StartKey, u_char *SessionKey, int SessionKeyLength, |
607 | u_char *InterimKey) |
608 | { |
609 | u_char Digest[20]; |
610 | SHA_CTXSHA_CTX Context; |
611 | |
612 | ZeroMemory(Digest, 20)memset(Digest, 0, 20); |
613 | |
614 | SHAInitSHA1_Init(&Context); |
615 | SHAUpdateSHA1_Update(&Context, StartKey, SessionKeyLength); |
616 | SHAUpdateSHA1_Update(&Context, SHAPad1, 40); |
617 | SHAUpdateSHA1_Update(&Context, SessionKey, SessionKeyLength); |
618 | SHAUpdateSHA1_Update(&Context, SHAPad2, 40); |
619 | SHAFinal(&Context, Digest)SHA1_Final(Digest, &Context); |
620 | |
621 | MoveMemory(InterimKey, Digest, SessionKeyLength)memcpy(InterimKey, Digest, SessionKeyLength); |
622 | } |
623 | |
624 | static int |
625 | mppe_rc4_init(mppe *_mppe, mppe_rc4_t *_this, int has_oldkey) |
626 | { |
627 | if ((_this->rc4ctx = rc4_create_ctx()) == NULL((void*)0)) { |
628 | mppe_log(_mppe, LOG_ERR3, "malloc() failed at %s: %m", |
629 | __func__); |
630 | return 1; |
631 | } |
632 | |
633 | if (has_oldkey) |
634 | _this->old_session_keys = reallocarray(NULL((void*)0), |
635 | MPPE_KEYLEN16, MPPE_NOLDKEY64); |
636 | else |
637 | _this->old_session_keys = NULL((void*)0); |
638 | |
639 | return 0; |
640 | } |
641 | |
642 | static int |
643 | mppe_rc4_setkey(mppe *_mppe, mppe_rc4_t *_this) |
644 | { |
645 | return rc4_key(_this->rc4ctx, _this->keylen, _this->session_key); |
646 | } |
647 | |
648 | static int |
649 | mppe_rc4_setoldkey(mppe *_mppe, mppe_rc4_t *_this, uint16_t coher_cnt) |
650 | { |
651 | return rc4_key(_this->rc4ctx, _this->keylen, |
652 | _this->old_session_keys[coher_cnt % MPPE_NOLDKEY64]); |
653 | } |
654 | |
655 | static void |
656 | mppe_rc4_encrypt(mppe *_mppe, mppe_rc4_t *_this, int len, u_char *indata, u_char *outdata) |
657 | { |
658 | rc4(_this->rc4ctx, len, indata, outdata); |
659 | } |
660 | |
661 | static void |
662 | mppe_rc4_destroy(mppe *_mppe, mppe_rc4_t *_this) |
663 | { |
664 | free(_this->rc4ctx); |
665 | free(_this->old_session_keys); |
666 | _this->rc4ctx = NULL((void*)0); |
667 | } |