1 /*
2 * ng_mppc.c
3 */
4
5 /*-
6 * Copyright (c) 1996-2000 Whistle Communications, Inc.
7 * All rights reserved.
8 *
9 * Subject to the following obligations and disclaimer of warranty, use and
10 * redistribution of this software, in source or object code forms, with or
11 * without modifications are expressly permitted by Whistle Communications;
12 * provided, however, that:
13 * 1. Any and all reproductions of the source or object code must include the
14 * copyright notice above and the following disclaimer of warranties; and
15 * 2. No rights are granted, in any manner or form, to use Whistle
16 * Communications, Inc. trademarks, including the mark "WHISTLE
17 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18 * such appears in the above copyright notice or in the software.
19 *
20 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36 * OF SUCH DAMAGE.
37 *
38 * Author: Archie Cobbs <archie@freebsd.org>
39 *
40 * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $
41 * $FreeBSD: releng/10.1/sys/netgraph/ng_mppc.c 267093 2014-06-05 05:36:55Z mav $
42 */
43
44 /*
45 * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type.
46 *
47 * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or
48 * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful.
49 */
50
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/kernel.h>
54 #include <sys/mbuf.h>
55 #include <sys/malloc.h>
56 #include <sys/endian.h>
57 #include <sys/errno.h>
58 #include <sys/sysctl.h>
59 #include <sys/syslog.h>
60
61 #include <netgraph/ng_message.h>
62 #include <netgraph/netgraph.h>
63 #include <netgraph/ng_mppc.h>
64
65 #include "opt_netgraph.h"
66
67 #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
68 #ifdef KLD_MODULE
69 /* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */
70 #define NETGRAPH_MPPC_ENCRYPTION
71 #else
72 /* This case is indicative of an error in sys/conf files */
73 #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
74 #endif
75 #endif
76
77 #ifdef NG_SEPARATE_MALLOC
78 static MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node");
79 #else
80 #define M_NETGRAPH_MPPC M_NETGRAPH
81 #endif
82
83 #ifdef NETGRAPH_MPPC_COMPRESSION
84 /* XXX this file doesn't exist yet, but hopefully someday it will... */
85 #include <net/mppc.h>
86 #endif
87 #ifdef NETGRAPH_MPPC_ENCRYPTION
88 #include <crypto/rc4/rc4.h>
89 #endif
90 #include <crypto/sha1.h>
91
92 /* Decompression blowup */
93 #define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */
94 #define MPPC_DECOMP_SAFETY 100 /* plus this much margin */
95
96 /* MPPC/MPPE header length */
97 #define MPPC_HDRLEN 2
98
99 /* Key length */
100 #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8)
101
102 /*
103 * When packets are lost with MPPE, we may have to re-key arbitrarily
104 * many times to 'catch up' to the new jumped-ahead sequence number.
105 * Since this can be expensive, we pose a limit on how many re-keyings
106 * we will do at one time to avoid a possible D.O.S. vulnerability.
107 * This should instead be a configurable parameter.
108 */
109 #define MPPE_MAX_REKEY 1000
110
111 SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW, 0, "MPPE");
112
113 static int mppe_block_on_max_rekey = 0;
114 TUNABLE_INT("net.graph.mppe.block_on_max_rekey", &mppe_block_on_max_rekey);
115 SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RW,
116 &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
117
118 static int mppe_log_max_rekey = 1;
119 TUNABLE_INT("net.graph.mppe.log_max_rekey", &mppe_log_max_rekey);
120 SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RW,
121 &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
122
123 static int mppe_max_rekey = MPPE_MAX_REKEY;
124 TUNABLE_INT("net.graph.mppe.max_rekey", &mppe_max_rekey);
125 SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RW,
126 &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
127
128 /* MPPC packet header bits */
129 #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
130 #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
131 #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
132 #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
133 #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
134
135 #define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
136
137 #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
138 #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
139
140 #define MPPC_COMP_OK 0x05
141 #define MPPC_DECOMP_OK 0x05
142
143 /* Per direction info */
144 struct ng_mppc_dir {
145 struct ng_mppc_config cfg; /* configuration */
146 hook_p hook; /* netgraph hook */
147 u_int16_t cc:12; /* coherency count */
148 u_char flushed; /* clean history (xmit only) */
149 #ifdef NETGRAPH_MPPC_COMPRESSION
150 u_char *history; /* compression history */
151 #endif
152 #ifdef NETGRAPH_MPPC_ENCRYPTION
153 u_char key[MPPE_KEY_LEN]; /* session key */
154 struct rc4_state rc4; /* rc4 state */
155 #endif
156 };
157
158 /* Node private data */
159 struct ng_mppc_private {
160 struct ng_mppc_dir xmit; /* compress/encrypt config */
161 struct ng_mppc_dir recv; /* decompress/decrypt config */
162 ng_ID_t ctrlnode; /* path to controlling node */
163 };
164 typedef struct ng_mppc_private *priv_p;
165
166 /* Netgraph node methods */
167 static ng_constructor_t ng_mppc_constructor;
168 static ng_rcvmsg_t ng_mppc_rcvmsg;
169 static ng_shutdown_t ng_mppc_shutdown;
170 static ng_newhook_t ng_mppc_newhook;
171 static ng_rcvdata_t ng_mppc_rcvdata;
172 static ng_disconnect_t ng_mppc_disconnect;
173
174 /* Helper functions */
175 static int ng_mppc_compress(node_p node,
176 struct mbuf **datap);
177 static int ng_mppc_decompress(node_p node,
178 struct mbuf **datap);
179 #ifdef NETGRAPH_MPPC_ENCRYPTION
180 static void ng_mppc_getkey(const u_char *h, u_char *h2, int len);
181 static void ng_mppc_updatekey(u_int32_t bits,
182 u_char *key0, u_char *key, struct rc4_state *rc4);
183 #endif
184 static void ng_mppc_reset_req(node_p node);
185
186 /* Node type descriptor */
187 static struct ng_type ng_mppc_typestruct = {
188 .version = NG_ABI_VERSION,
189 .name = NG_MPPC_NODE_TYPE,
190 .constructor = ng_mppc_constructor,
191 .rcvmsg = ng_mppc_rcvmsg,
192 .shutdown = ng_mppc_shutdown,
193 .newhook = ng_mppc_newhook,
194 .rcvdata = ng_mppc_rcvdata,
195 .disconnect = ng_mppc_disconnect,
196 };
197 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
198
199 #ifdef NETGRAPH_MPPC_ENCRYPTION
200 /* Depend on separate rc4 module */
201 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
202 #endif
203
204 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
205 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
206
207 #define ERROUT(x) do { error = (x); goto done; } while (0)
208
209 /************************************************************************
210 NETGRAPH NODE STUFF
211 ************************************************************************/
212
213 /*
214 * Node type constructor
215 */
216 static int
217 ng_mppc_constructor(node_p node)
218 {
219 priv_p priv;
220
221 /* Allocate private structure */
222 priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
223
224 NG_NODE_SET_PRIVATE(node, priv);
225
226 /* This node is not thread safe. */
227 NG_NODE_FORCE_WRITER(node);
228
229 /* Done */
230 return (0);
231 }
232
233 /*
234 * Give our OK for a hook to be added
235 */
236 static int
237 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
238 {
239 const priv_p priv = NG_NODE_PRIVATE(node);
240 hook_p *hookPtr;
241
242 /* Check hook name */
243 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
244 hookPtr = &priv->xmit.hook;
245 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
246 hookPtr = &priv->recv.hook;
247 else
248 return (EINVAL);
249
250 /* See if already connected */
251 if (*hookPtr != NULL)
252 return (EISCONN);
253
254 /* OK */
255 *hookPtr = hook;
256 return (0);
257 }
258
259 /*
260 * Receive a control message
261 */
262 static int
263 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
264 {
265 const priv_p priv = NG_NODE_PRIVATE(node);
266 struct ng_mesg *resp = NULL;
267 int error = 0;
268 struct ng_mesg *msg;
269
270 NGI_GET_MSG(item, msg);
271 switch (msg->header.typecookie) {
272 case NGM_MPPC_COOKIE:
273 switch (msg->header.cmd) {
274 case NGM_MPPC_CONFIG_COMP:
275 case NGM_MPPC_CONFIG_DECOMP:
276 {
277 struct ng_mppc_config *const cfg
278 = (struct ng_mppc_config *)msg->data;
279 const int isComp =
280 msg->header.cmd == NGM_MPPC_CONFIG_COMP;
281 struct ng_mppc_dir *const d = isComp ?
282 &priv->xmit : &priv->recv;
283
284 /* Check configuration */
285 if (msg->header.arglen != sizeof(*cfg))
286 ERROUT(EINVAL);
287 if (cfg->enable) {
288 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
289 ERROUT(EINVAL);
290 #ifndef NETGRAPH_MPPC_COMPRESSION
291 if ((cfg->bits & MPPC_BIT) != 0)
292 ERROUT(EPROTONOSUPPORT);
293 #endif
294 #ifndef NETGRAPH_MPPC_ENCRYPTION
295 if ((cfg->bits & MPPE_BITS) != 0)
296 ERROUT(EPROTONOSUPPORT);
297 #endif
298 } else
299 cfg->bits = 0;
300
301 /* Save return address so we can send reset-req's */
302 if (!isComp)
303 priv->ctrlnode = NGI_RETADDR(item);
304
305 /* Configuration is OK, reset to it */
306 d->cfg = *cfg;
307
308 #ifdef NETGRAPH_MPPC_COMPRESSION
309 /* Initialize state buffers for compression */
310 if (d->history != NULL) {
311 free(d->history, M_NETGRAPH_MPPC);
312 d->history = NULL;
313 }
314 if ((cfg->bits & MPPC_BIT) != 0) {
315 d->history = malloc(isComp ?
316 MPPC_SizeOfCompressionHistory() :
317 MPPC_SizeOfDecompressionHistory(),
318 M_NETGRAPH_MPPC, M_NOWAIT);
319 if (d->history == NULL)
320 ERROUT(ENOMEM);
321 if (isComp)
322 MPPC_InitCompressionHistory(d->history);
323 else {
324 MPPC_InitDecompressionHistory(
325 d->history);
326 }
327 }
328 #endif
329
330 #ifdef NETGRAPH_MPPC_ENCRYPTION
331 /* Generate initial session keys for encryption */
332 if ((cfg->bits & MPPE_BITS) != 0) {
333 const int keylen = KEYLEN(cfg->bits);
334
335 bcopy(cfg->startkey, d->key, keylen);
336 ng_mppc_getkey(cfg->startkey, d->key, keylen);
337 if ((cfg->bits & MPPE_40) != 0)
338 bcopy(&ng_mppe_weakenkey, d->key, 3);
339 else if ((cfg->bits & MPPE_56) != 0)
340 bcopy(&ng_mppe_weakenkey, d->key, 1);
341 rc4_init(&d->rc4, d->key, keylen);
342 }
343 #endif
344
345 /* Initialize other state */
346 d->cc = 0;
347 d->flushed = 0;
348 break;
349 }
350
351 case NGM_MPPC_RESETREQ:
352 ng_mppc_reset_req(node);
353 break;
354
355 default:
356 error = EINVAL;
357 break;
358 }
359 break;
360 default:
361 error = EINVAL;
362 break;
363 }
364 done:
365 NG_RESPOND_MSG(error, node, item, resp);
366 NG_FREE_MSG(msg);
367 return (error);
368 }
369
370 /*
371 * Receive incoming data on our hook.
372 */
373 static int
374 ng_mppc_rcvdata(hook_p hook, item_p item)
375 {
376 const node_p node = NG_HOOK_NODE(hook);
377 const priv_p priv = NG_NODE_PRIVATE(node);
378 int error;
379 struct mbuf *m;
380
381 NGI_GET_M(item, m);
382 /* Compress and/or encrypt */
383 if (hook == priv->xmit.hook) {
384 if (!priv->xmit.cfg.enable) {
385 NG_FREE_M(m);
386 NG_FREE_ITEM(item);
387 return (ENXIO);
388 }
389 if ((error = ng_mppc_compress(node, &m)) != 0) {
390 NG_FREE_ITEM(item);
391 return(error);
392 }
393 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
394 return (error);
395 }
396
397 /* Decompress and/or decrypt */
398 if (hook == priv->recv.hook) {
399 if (!priv->recv.cfg.enable) {
400 NG_FREE_M(m);
401 NG_FREE_ITEM(item);
402 return (ENXIO);
403 }
404 if ((error = ng_mppc_decompress(node, &m)) != 0) {
405 NG_FREE_ITEM(item);
406 if (error == EINVAL && priv->ctrlnode != 0) {
407 struct ng_mesg *msg;
408
409 /* Need to send a reset-request */
410 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
411 NGM_MPPC_RESETREQ, 0, M_NOWAIT);
412 if (msg == NULL)
413 return (error);
414 NG_SEND_MSG_ID(error, node, msg,
415 priv->ctrlnode, 0);
416 }
417 return (error);
418 }
419 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
420 return (error);
421 }
422
423 /* Oops */
424 panic("%s: unknown hook", __func__);
425 }
426
427 /*
428 * Destroy node
429 */
430 static int
431 ng_mppc_shutdown(node_p node)
432 {
433 const priv_p priv = NG_NODE_PRIVATE(node);
434
435 /* Take down netgraph node */
436 #ifdef NETGRAPH_MPPC_COMPRESSION
437 if (priv->xmit.history != NULL)
438 free(priv->xmit.history, M_NETGRAPH_MPPC);
439 if (priv->recv.history != NULL)
440 free(priv->recv.history, M_NETGRAPH_MPPC);
441 #endif
442 bzero(priv, sizeof(*priv));
443 free(priv, M_NETGRAPH_MPPC);
444 NG_NODE_SET_PRIVATE(node, NULL);
445 NG_NODE_UNREF(node); /* let the node escape */
446 return (0);
447 }
448
449 /*
450 * Hook disconnection
451 */
452 static int
453 ng_mppc_disconnect(hook_p hook)
454 {
455 const node_p node = NG_HOOK_NODE(hook);
456 const priv_p priv = NG_NODE_PRIVATE(node);
457
458 /* Zero out hook pointer */
459 if (hook == priv->xmit.hook)
460 priv->xmit.hook = NULL;
461 if (hook == priv->recv.hook)
462 priv->recv.hook = NULL;
463
464 /* Go away if no longer connected */
465 if ((NG_NODE_NUMHOOKS(node) == 0)
466 && NG_NODE_IS_VALID(node))
467 ng_rmnode_self(node);
468 return (0);
469 }
470
471 /************************************************************************
472 HELPER STUFF
473 ************************************************************************/
474
475 /*
476 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
477 * The original mbuf is not free'd.
478 */
479 static int
480 ng_mppc_compress(node_p node, struct mbuf **datap)
481 {
482 const priv_p priv = NG_NODE_PRIVATE(node);
483 struct ng_mppc_dir *const d = &priv->xmit;
484 u_int16_t header;
485 struct mbuf *m = *datap;
486
487 /* We must own the mbuf chain exclusively to modify it. */
488 m = m_unshare(m, M_NOWAIT);
489 if (m == NULL)
490 return (ENOMEM);
491
492 /* Initialize */
493 header = d->cc;
494
495 /* Always set the flushed bit in stateless mode */
496 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
497 header |= MPPC_FLAG_FLUSHED;
498 d->flushed = 0;
499 }
500
501 /* Compress packet (if compression enabled) */
502 #ifdef NETGRAPH_MPPC_COMPRESSION
503 if ((d->cfg.bits & MPPC_BIT) != 0) {
504 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
505 u_char *inbuf, *outbuf;
506 int outlen, inlen, ina;
507 u_char *source, *dest;
508 u_long sourceCnt, destCnt;
509 int rtn;
510
511 /* Work with contiguous regions of memory. */
512 inlen = m->m_pkthdr.len;
513 if (m->m_next == NULL) {
514 inbuf = mtod(m, u_char *);
515 ina = 0;
516 } else {
517 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
518 if (inbuf == NULL)
519 goto err1;
520 m_copydata(m, 0, inlen, (caddr_t)inbuf);
521 ina = 1;
522 }
523
524 outlen = MPPC_MAX_BLOWUP(inlen);
525 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
526 if (outbuf == NULL) {
527 if (ina)
528 free(inbuf, M_NETGRAPH_MPPC);
529 err1:
530 m_freem(m);
531 MPPC_InitCompressionHistory(d->history);
532 d->flushed = 1;
533 return (ENOMEM);
534 }
535
536 /* Prepare to compress */
537 source = inbuf;
538 sourceCnt = inlen;
539 dest = outbuf;
540 destCnt = outlen;
541 if ((d->cfg.bits & MPPE_STATELESS) == 0)
542 flags |= MPPC_SAVE_HISTORY;
543
544 /* Compress */
545 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
546 &destCnt, d->history, flags, 0);
547
548 /* Check return value */
549 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
550 if ((rtn & MPPC_EXPANDED) == 0
551 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
552 outlen -= destCnt;
553 header |= MPPC_FLAG_COMPRESSED;
554 if ((rtn & MPPC_RESTART_HISTORY) != 0)
555 header |= MPPC_FLAG_RESTART;
556
557 /* Replace m by the compresed one. */
558 m_copyback(m, 0, outlen, (caddr_t)outbuf);
559 if (m->m_pkthdr.len < outlen) {
560 m_freem(m);
561 m = NULL;
562 } else if (outlen < m->m_pkthdr.len)
563 m_adj(m, outlen - m->m_pkthdr.len);
564 }
565 d->flushed = (rtn & MPPC_EXPANDED) != 0
566 || (flags & MPPC_SAVE_HISTORY) == 0;
567
568 if (ina)
569 free(inbuf, M_NETGRAPH_MPPC);
570 free(outbuf, M_NETGRAPH_MPPC);
571
572 /* Check mbuf chain reload result. */
573 if (m == NULL) {
574 if (!d->flushed) {
575 MPPC_InitCompressionHistory(d->history);
576 d->flushed = 1;
577 }
578 return (ENOMEM);
579 }
580 }
581 #endif
582
583 /* Now encrypt packet (if encryption enabled) */
584 #ifdef NETGRAPH_MPPC_ENCRYPTION
585 if ((d->cfg.bits & MPPE_BITS) != 0) {
586 struct mbuf *m1;
587
588 /* Set header bits */
589 header |= MPPC_FLAG_ENCRYPTED;
590
591 /* Update key if it's time */
592 if ((d->cfg.bits & MPPE_STATELESS) != 0
593 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
594 ng_mppc_updatekey(d->cfg.bits,
595 d->cfg.startkey, d->key, &d->rc4);
596 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
597 /* Need to reset key if we say we did
598 and ng_mppc_updatekey wasn't called to do it also. */
599 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
600 }
601
602 /* Encrypt packet */
603 m1 = m;
604 while (m1) {
605 rc4_crypt(&d->rc4, mtod(m1, u_char *),
606 mtod(m1, u_char *), m1->m_len);
607 m1 = m1->m_next;
608 }
609 }
610 #endif
611
612 /* Update coherency count for next time (12 bit arithmetic) */
613 MPPC_CCOUNT_INC(d->cc);
614
615 /* Install header */
616 M_PREPEND(m, MPPC_HDRLEN, M_NOWAIT);
617 if (m != NULL)
618 be16enc(mtod(m, void *), header);
619
620 *datap = m;
621 return (*datap == NULL ? ENOBUFS : 0);
622 }
623
624 /*
625 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
626 * The original mbuf is not free'd.
627 */
628 static int
629 ng_mppc_decompress(node_p node, struct mbuf **datap)
630 {
631 const priv_p priv = NG_NODE_PRIVATE(node);
632 struct ng_mppc_dir *const d = &priv->recv;
633 u_int16_t header, cc;
634 u_int numLost;
635 struct mbuf *m = *datap;
636
637 /* We must own the mbuf chain exclusively to modify it. */
638 m = m_unshare(m, M_NOWAIT);
639 if (m == NULL)
640 return (ENOMEM);
641
642 /* Pull off header */
643 if (m->m_pkthdr.len < MPPC_HDRLEN) {
644 m_freem(m);
645 return (EINVAL);
646 }
647 header = be16dec(mtod(m, void *));
648 cc = (header & MPPC_CCOUNT_MASK);
649 m_adj(m, MPPC_HDRLEN);
650
651 /* Check for an unexpected jump in the sequence number */
652 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
653
654 /* If flushed bit set, we can always handle packet */
655 if ((header & MPPC_FLAG_FLUSHED) != 0) {
656 #ifdef NETGRAPH_MPPC_COMPRESSION
657 if (d->history != NULL)
658 MPPC_InitDecompressionHistory(d->history);
659 #endif
660 #ifdef NETGRAPH_MPPC_ENCRYPTION
661 if ((d->cfg.bits & MPPE_BITS) != 0) {
662 u_int rekey;
663
664 /* How many times are we going to have to re-key? */
665 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
666 numLost : (numLost / (MPPE_UPDATE_MASK + 1));
667 if (rekey > mppe_max_rekey) {
668 if (mppe_block_on_max_rekey) {
669 if (mppe_log_max_rekey) {
670 log(LOG_ERR, "%s: too many (%d) packets"
671 " dropped, disabling node %p!\n",
672 __func__, numLost, node);
673 }
674 priv->recv.cfg.enable = 0;
675 goto failed;
676 } else {
677 if (mppe_log_max_rekey) {
678 log(LOG_ERR, "%s: %d packets"
679 " dropped, node %p\n",
680 __func__, numLost, node);
681 }
682 goto failed;
683 }
684 }
685
686 /* Re-key as necessary to catch up to peer */
687 while (d->cc != cc) {
688 if ((d->cfg.bits & MPPE_STATELESS) != 0
689 || (d->cc & MPPE_UPDATE_MASK)
690 == MPPE_UPDATE_FLAG) {
691 ng_mppc_updatekey(d->cfg.bits,
692 d->cfg.startkey, d->key, &d->rc4);
693 }
694 MPPC_CCOUNT_INC(d->cc);
695 }
696
697 /* Reset key (except in stateless mode, see below) */
698 if ((d->cfg.bits & MPPE_STATELESS) == 0)
699 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
700 }
701 #endif
702 d->cc = cc; /* skip over lost seq numbers */
703 numLost = 0; /* act like no packets were lost */
704 }
705
706 /* Can't decode non-sequential packets without a flushed bit */
707 if (numLost != 0)
708 goto failed;
709
710 /* Decrypt packet */
711 if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
712 #ifdef NETGRAPH_MPPC_ENCRYPTION
713 struct mbuf *m1;
714 #endif
715
716 /* Are we not expecting encryption? */
717 if ((d->cfg.bits & MPPE_BITS) == 0) {
718 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
719 __func__, "encrypted");
720 goto failed;
721 }
722
723 #ifdef NETGRAPH_MPPC_ENCRYPTION
724 /* Update key if it's time (always in stateless mode) */
725 if ((d->cfg.bits & MPPE_STATELESS) != 0
726 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
727 ng_mppc_updatekey(d->cfg.bits,
728 d->cfg.startkey, d->key, &d->rc4);
729 }
730
731 /* Decrypt packet */
732 m1 = m;
733 while (m1 != NULL) {
734 rc4_crypt(&d->rc4, mtod(m1, u_char *),
735 mtod(m1, u_char *), m1->m_len);
736 m1 = m1->m_next;
737 }
738 #endif
739 } else {
740
741 /* Are we expecting encryption? */
742 if ((d->cfg.bits & MPPE_BITS) != 0) {
743 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
744 __func__, "unencrypted");
745 goto failed;
746 }
747 }
748
749 /* Update coherency count for next time (12 bit arithmetic) */
750 MPPC_CCOUNT_INC(d->cc);
751
752 /* Check for unexpected compressed packet */
753 if ((header & MPPC_FLAG_COMPRESSED) != 0
754 && (d->cfg.bits & MPPC_BIT) == 0) {
755 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
756 __func__, "compressed");
757 failed:
758 m_freem(m);
759 return (EINVAL);
760 }
761
762 #ifdef NETGRAPH_MPPC_COMPRESSION
763 /* Decompress packet */
764 if ((header & MPPC_FLAG_COMPRESSED) != 0) {
765 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
766 u_char *inbuf, *outbuf;
767 int inlen, outlen, ina;
768 u_char *source, *dest;
769 u_long sourceCnt, destCnt;
770 int rtn;
771
772 /* Copy payload into a contiguous region of memory. */
773 inlen = m->m_pkthdr.len;
774 if (m->m_next == NULL) {
775 inbuf = mtod(m, u_char *);
776 ina = 0;
777 } else {
778 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
779 if (inbuf == NULL) {
780 m_freem(m);
781 return (ENOMEM);
782 }
783 m_copydata(m, 0, inlen, (caddr_t)inbuf);
784 ina = 1;
785 }
786
787 /* Allocate a buffer for decompressed data */
788 outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
789 M_NETGRAPH_MPPC, M_NOWAIT);
790 if (outbuf == NULL) {
791 m_freem(m);
792 if (ina)
793 free(inbuf, M_NETGRAPH_MPPC);
794 return (ENOMEM);
795 }
796 outlen = MPPC_DECOMP_BUFSIZE;
797
798 /* Prepare to decompress */
799 source = inbuf;
800 sourceCnt = inlen;
801 dest = outbuf;
802 destCnt = outlen;
803 if ((header & MPPC_FLAG_RESTART) != 0)
804 flags |= MPPC_RESTART_HISTORY;
805
806 /* Decompress */
807 rtn = MPPC_Decompress(&source, &dest,
808 &sourceCnt, &destCnt, d->history, flags);
809
810 /* Check return value */
811 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
812 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
813 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
814 log(LOG_ERR, "%s: decomp returned 0x%x",
815 __func__, rtn);
816 if (ina)
817 free(inbuf, M_NETGRAPH_MPPC);
818 free(outbuf, M_NETGRAPH_MPPC);
819 goto failed;
820 }
821
822 /* Replace compressed data with decompressed data */
823 if (ina)
824 free(inbuf, M_NETGRAPH_MPPC);
825 outlen -= destCnt;
826
827 m_copyback(m, 0, outlen, (caddr_t)outbuf);
828 if (m->m_pkthdr.len < outlen) {
829 m_freem(m);
830 m = NULL;
831 } else if (outlen < m->m_pkthdr.len)
832 m_adj(m, outlen - m->m_pkthdr.len);
833 free(outbuf, M_NETGRAPH_MPPC);
834 }
835 #endif
836
837 /* Return result in an mbuf */
838 *datap = m;
839 return (*datap == NULL ? ENOBUFS : 0);
840 }
841
842 /*
843 * The peer has sent us a CCP ResetRequest, so reset our transmit state.
844 */
845 static void
846 ng_mppc_reset_req(node_p node)
847 {
848 const priv_p priv = NG_NODE_PRIVATE(node);
849 struct ng_mppc_dir *const d = &priv->xmit;
850
851 #ifdef NETGRAPH_MPPC_COMPRESSION
852 if (d->history != NULL)
853 MPPC_InitCompressionHistory(d->history);
854 #endif
855 #ifdef NETGRAPH_MPPC_ENCRYPTION
856 if ((d->cfg.bits & MPPE_STATELESS) == 0)
857 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
858 #endif
859 d->flushed = 1;
860 }
861
862 #ifdef NETGRAPH_MPPC_ENCRYPTION
863 /*
864 * Generate a new encryption key
865 */
866 static void
867 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
868 {
869 static const u_char pad1[40] =
870 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
871 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
872 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
873 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
874 static const u_char pad2[40] =
875 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
876 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
877 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
878 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
879 u_char hash[20];
880 SHA1_CTX c;
881
882 SHA1Init(&c);
883 SHA1Update(&c, h, len);
884 SHA1Update(&c, pad1, sizeof(pad1));
885 SHA1Update(&c, h2, len);
886 SHA1Update(&c, pad2, sizeof(pad2));
887 SHA1Final(hash, &c);
888 bcopy(hash, h2, len);
889 }
890
891 /*
892 * Update the encryption key
893 */
894 static void
895 ng_mppc_updatekey(u_int32_t bits,
896 u_char *key0, u_char *key, struct rc4_state *rc4)
897 {
898 const int keylen = KEYLEN(bits);
899
900 ng_mppc_getkey(key0, key, keylen);
901 rc4_init(rc4, key, keylen);
902 rc4_crypt(rc4, key, key, keylen);
903 if ((bits & MPPE_40) != 0)
904 bcopy(&ng_mppe_weakenkey, key, 3);
905 else if ((bits & MPPE_56) != 0)
906 bcopy(&ng_mppe_weakenkey, key, 1);
907 rc4_init(rc4, key, keylen);
908 }
909 #endif
910
Cache object: b73ec37d1464d5b1812f7888f91dcf36
|