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