xref: /openbsd/usr.sbin/npppd/npppd/mppe.c (revision bcb159da)
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_FRAMING	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, \
64 		"\nASSERT(%s) failed on %s() at %s:%d.\n" \
65 		, #x, __func__, __FILE__, __LINE__); \
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
74 
75 #define COHER_EQ(a, b) ((((a) - (b)) & 0xfff) == 0)
76 #define COHER_LT(a, b) (((int16_t)(((a) - (b)) << 4)) < 0)
77 #define COHER_GT(a, b) COHER_LT((b), (a))
78 #define COHER_NE(a, b) (!COHER_EQ((a), (b)))
79 #define COHER_LE(a, b) (!COHER_GE((b), (a)))
80 #define COHER_GE(a, b) (!COHER_LT((a), (b)))
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);
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
mppe_init(mppe * _this,npppd_ppp * ppp)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_STATEFUL|NPPPD_MPPE_STATELESS)) {
122 		/* no need to change from default. */
123 	} else if (conf->mppe_keystate == NPPPD_MPPE_STATELESS) {
124 		_this->mode_auto = 0;
125 		_this->mode_stateless = 1;
126 	} else if (conf->mppe_keystate == NPPPD_MPPE_STATEFUL) {
127 		_this->mode_auto = 0;
128 		_this->mode_stateless = 0;
129 	}
130 
131 	_this->keylenbits = 0;
132 	if ((conf->mppe_keylen & NPPPD_MPPE_40BIT) != 0)
133 		_this->keylenbits |= CCP_MPPE_NT_40bit;
134 	if ((conf->mppe_keylen & NPPPD_MPPE_56BIT) != 0)
135 		_this->keylenbits |= CCP_MPPE_NT_56bit;
136 	if ((conf->mppe_keylen & NPPPD_MPPE_128BIT) != 0)
137 		_this->keylenbits |= CCP_MPPE_NT_128bit;
138 
139 mppe_config_done:
140 	/* nothing */;
141 }
142 
143 void
mppe_fini(mppe * _this)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
mppe_reduce_key(mppe_rc4_t * _this)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
mppe_key_change(mppe * _mppe,mppe_rc4_t * _this)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_NOLDKEY;
179 		memcpy(_this->old_session_keys[idx],
180 		    _this->session_key, MPPE_KEYLEN);
181 	}
182 
183 	free(keychg);
184 }
185 
186 /**
187  * starting mppe protocol.
188  */
189 void
mppe_start(mppe * _this)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_INFO, "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_STATELESS) != 0)? 1 : 0;
204 
205 	if ((_this->ppp->ccp.mppe_o_bits & CCP_MPPE_NT_40bit) != 0) {
206 		_this->send.keylen = 8;
207 		_this->send.keybits = 40;
208 	} else if ((_this->ppp->ccp.mppe_o_bits & CCP_MPPE_NT_56bit) != 0) {
209 		_this->send.keylen = 8;
210 		_this->send.keybits = 56;
211 	} else if ((_this->ppp->ccp.mppe_o_bits & CCP_MPPE_NT_128bit) != 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_STATELESS) != 0)? 1 : 0;
218 	if ((_this->ppp->ccp.mppe_p_bits & CCP_MPPE_NT_40bit) != 0) {
219 		_this->recv.keylen = 8;
220 		_this->recv.keybits = 40;
221 	} else if ((_this->ppp->ccp.mppe_p_bits & CCP_MPPE_NT_56bit) != 0) {
222 		_this->recv.keylen = 8;
223 		_this->recv.keybits = 56;
224 	} else if ((_this->ppp->ccp.mppe_p_bits & CCP_MPPE_NT_128bit) != 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
mppe_create_our_bits(mppe * _this,uint32_t peer_bits)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_128bit) != 0)
259 			our_bits = CCP_MPPE_NT_128bit;
260 		else if ((peer_bits & CCP_MPPE_NT_56bit) != 0)
261 			our_bits = CCP_MPPE_NT_56bit;
262 		else if ((peer_bits & CCP_MPPE_NT_40bit) != 0)
263 			our_bits = CCP_MPPE_NT_40bit;
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_STATELESS;
283 		} else {
284 			/* giving up */
285 			our_bits |= peer_bits & CCP_MPPE_STATELESS;
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_STATELESS;
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_INFO,
299 		    "mismatch our=%s peer=%s", obuf, pbuf);
300 	}
301 
302 	return our_bits;
303 }
304 
305 #define	COHERENCY_CNT_MASK	0x0fff;
306 
307 /**
308  * receiving packets via MPPE.
309  * len must be 4 at least.
310  */
311 void
mppe_input(mppe * _this,u_char * pktp,int len)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;
326 	GETSHORT(coher_cnt, pktp);
327 
328 	flushed = (coher_cnt & 0x8000)? 1 : 0;
329 	encrypt = (coher_cnt & 0x1000)? 1 : 0;
330 	coher_cnt &= COHERENCY_CNT_MASK;
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_WARNING,
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_NOLDKEY) {
362 			mppe_log(_this, LOG_INFO,
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_MASK;
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_MASK;
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_NCP | NCP_CCP);
402 			opktp = opktp0;
403 
404 			PUTLONG(_this->ppp->ccp.mppe_p_bits, opktp);
405 
406 			ppp_output(_this->ppp, PPP_PROTO_NCP | NCP_CCP,
407 			    RESETREQ, _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_WARNING, "%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_MASK;
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_INFO, "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_ENCRYPTED);
454 }
455 
456 /**
457  * The call out function in case of receiving CCP Reset (key reset in case
458  * of MPPE).
459  */
460 void
mppe_recv_ccp_reset(mppe * _this)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
mppe_pkt_output(mppe * _this,uint16_t proto,u_char * pktp,int len)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_MPPE);
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_MASK;
507 	if (flushed)
508 		coher_cnt |= 0x8000;
509 	if (encrypt)
510 		coher_cnt |= 0x1000;
511 
512 	PUTSHORT(coher_cnt, outp);
513 	proto = htons(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_MPPE, 0, 0, outp0, len + 4);
518 	_this->send.coher_cnt++;
519 	_this->send.coher_cnt &= COHERENCY_CNT_MASK;
520 }
521 
522 static void
mppe_log(mppe * _this,uint32_t prio,const char * fmt,...)523 mppe_log(mppe *_this, uint32_t prio, const char *fmt, ...)
524 {
525 	char logbuf[BUFSIZ];
526 	va_list ap;
527 
528 	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);
533 }
534 
535 static const char *
mppe_bits_to_string(uint32_t bits)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_ALONE & bits) != 0)?	",mppc" : ""
542 	, ((CCP_MPPE_LM_40bit& bits) != 0)?	",40bit(LM)" : ""
543 	, ((CCP_MPPE_NT_40bit& bits) != 0)?	",40bit" : ""
544 	, ((CCP_MPPE_NT_128bit& bits) != 0)?	",128bit" : ""
545 	, ((CCP_MPPE_NT_56bit& bits) != 0)?	",56bit" : ""
546 	, ((CCP_MPPE_STATELESS& 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)
571 #define	MoveMemory(dst, src, len)	memcpy(dst, src, len)
572 
573 #include <openssl/rc4.h>
574 #include <openssl/sha.h>
575 
576 #define	SHA_CTX			SHA_CTX
577 #define	SHAInit			SHA1_Init
578 #define	SHAUpdate		SHA1_Update
579 #define	SHAFinal(ctx,digest)	SHA1_Final(digest, ctx)
580 
581 /************************************************************************
582  * implementations of OpenSSL version
583  ************************************************************************/
584 static void *
rc4_create_ctx(void)585 rc4_create_ctx(void)
586 {
587 	return malloc(sizeof(RC4_KEY));
588 }
589 
590 static int
rc4_key(void * rc4ctx,int lkey,u_char * key)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
rc4(void * rc4ctx,int len,u_char * indata,u_char * outdata)600 rc4(void *rc4ctx, int len, u_char *indata, u_char *outdata)
601 {
602 	RC4(rc4ctx, len, indata, outdata);
603 }
604 
605 static void
GetNewKeyFromSHA(u_char * StartKey,u_char * SessionKey,int SessionKeyLength,u_char * InterimKey)606 GetNewKeyFromSHA(u_char *StartKey, u_char *SessionKey, int SessionKeyLength,
607     u_char *InterimKey)
608 {
609 	u_char Digest[20];
610 	SHA_CTX Context;
611 
612 	ZeroMemory(Digest, 20);
613 
614 	SHAInit(&Context);
615 	SHAUpdate(&Context, StartKey, SessionKeyLength);
616 	SHAUpdate(&Context, SHAPad1, 40);
617 	SHAUpdate(&Context, SessionKey, SessionKeyLength);
618 	SHAUpdate(&Context, SHAPad2, 40);
619 	SHAFinal(&Context, Digest);
620 
621 	MoveMemory(InterimKey, Digest, SessionKeyLength);
622 }
623 
624 static int
mppe_rc4_init(mppe * _mppe,mppe_rc4_t * _this,int has_oldkey)625 mppe_rc4_init(mppe *_mppe, mppe_rc4_t *_this, int has_oldkey)
626 {
627 	if ((_this->rc4ctx = rc4_create_ctx()) == NULL) {
628 		mppe_log(_mppe, LOG_ERR, "malloc() failed at %s: %m",
629 		    __func__);
630 		return 1;
631 	}
632 
633 	if (has_oldkey)
634 		_this->old_session_keys = reallocarray(NULL,
635 		    MPPE_KEYLEN, MPPE_NOLDKEY);
636 	else
637 		_this->old_session_keys = NULL;
638 
639 	return 0;
640 }
641 
642 static int
mppe_rc4_setkey(mppe * _mppe,mppe_rc4_t * _this)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
mppe_rc4_setoldkey(mppe * _mppe,mppe_rc4_t * _this,uint16_t coher_cnt)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_NOLDKEY]);
653 }
654 
655 static void
mppe_rc4_encrypt(mppe * _mppe,mppe_rc4_t * _this,int len,u_char * indata,u_char * outdata)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
mppe_rc4_destroy(mppe * _mppe,mppe_rc4_t * _this)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;
667 }
668