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$
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 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_NOWAIT | M_ZERO);
223 if (priv == NULL)
224 return (ENOMEM);
225
226 NG_NODE_SET_PRIVATE(node, priv);
227
228 /* This node is not thread safe. */
229 NG_NODE_FORCE_WRITER(node);
230
231 /* Done */
232 return (0);
233 }
234
235 /*
236 * Give our OK for a hook to be added
237 */
238 static int
239 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
240 {
241 const priv_p priv = NG_NODE_PRIVATE(node);
242 hook_p *hookPtr;
243
244 /* Check hook name */
245 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
246 hookPtr = &priv->xmit.hook;
247 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
248 hookPtr = &priv->recv.hook;
249 else
250 return (EINVAL);
251
252 /* See if already connected */
253 if (*hookPtr != NULL)
254 return (EISCONN);
255
256 /* OK */
257 *hookPtr = hook;
258 return (0);
259 }
260
261 /*
262 * Receive a control message
263 */
264 static int
265 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
266 {
267 const priv_p priv = NG_NODE_PRIVATE(node);
268 struct ng_mesg *resp = NULL;
269 int error = 0;
270 struct ng_mesg *msg;
271
272 NGI_GET_MSG(item, msg);
273 switch (msg->header.typecookie) {
274 case NGM_MPPC_COOKIE:
275 switch (msg->header.cmd) {
276 case NGM_MPPC_CONFIG_COMP:
277 case NGM_MPPC_CONFIG_DECOMP:
278 {
279 struct ng_mppc_config *const cfg
280 = (struct ng_mppc_config *)msg->data;
281 const int isComp =
282 msg->header.cmd == NGM_MPPC_CONFIG_COMP;
283 struct ng_mppc_dir *const d = isComp ?
284 &priv->xmit : &priv->recv;
285
286 /* Check configuration */
287 if (msg->header.arglen != sizeof(*cfg))
288 ERROUT(EINVAL);
289 if (cfg->enable) {
290 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
291 ERROUT(EINVAL);
292 #ifndef NETGRAPH_MPPC_COMPRESSION
293 if ((cfg->bits & MPPC_BIT) != 0)
294 ERROUT(EPROTONOSUPPORT);
295 #endif
296 #ifndef NETGRAPH_MPPC_ENCRYPTION
297 if ((cfg->bits & MPPE_BITS) != 0)
298 ERROUT(EPROTONOSUPPORT);
299 #endif
300 } else
301 cfg->bits = 0;
302
303 /* Save return address so we can send reset-req's */
304 if (!isComp)
305 priv->ctrlnode = NGI_RETADDR(item);
306
307 /* Configuration is OK, reset to it */
308 d->cfg = *cfg;
309
310 #ifdef NETGRAPH_MPPC_COMPRESSION
311 /* Initialize state buffers for compression */
312 if (d->history != NULL) {
313 free(d->history, M_NETGRAPH_MPPC);
314 d->history = NULL;
315 }
316 if ((cfg->bits & MPPC_BIT) != 0) {
317 d->history = malloc(isComp ?
318 MPPC_SizeOfCompressionHistory() :
319 MPPC_SizeOfDecompressionHistory(),
320 M_NETGRAPH_MPPC, M_NOWAIT);
321 if (d->history == NULL)
322 ERROUT(ENOMEM);
323 if (isComp)
324 MPPC_InitCompressionHistory(d->history);
325 else {
326 MPPC_InitDecompressionHistory(
327 d->history);
328 }
329 }
330 #endif
331
332 #ifdef NETGRAPH_MPPC_ENCRYPTION
333 /* Generate initial session keys for encryption */
334 if ((cfg->bits & MPPE_BITS) != 0) {
335 const int keylen = KEYLEN(cfg->bits);
336
337 bcopy(cfg->startkey, d->key, keylen);
338 ng_mppc_getkey(cfg->startkey, d->key, keylen);
339 if ((cfg->bits & MPPE_40) != 0)
340 bcopy(&ng_mppe_weakenkey, d->key, 3);
341 else if ((cfg->bits & MPPE_56) != 0)
342 bcopy(&ng_mppe_weakenkey, d->key, 1);
343 rc4_init(&d->rc4, d->key, keylen);
344 }
345 #endif
346
347 /* Initialize other state */
348 d->cc = 0;
349 d->flushed = 0;
350 break;
351 }
352
353 case NGM_MPPC_RESETREQ:
354 ng_mppc_reset_req(node);
355 break;
356
357 default:
358 error = EINVAL;
359 break;
360 }
361 break;
362 default:
363 error = EINVAL;
364 break;
365 }
366 done:
367 NG_RESPOND_MSG(error, node, item, resp);
368 NG_FREE_MSG(msg);
369 return (error);
370 }
371
372 /*
373 * Receive incoming data on our hook.
374 */
375 static int
376 ng_mppc_rcvdata(hook_p hook, item_p item)
377 {
378 const node_p node = NG_HOOK_NODE(hook);
379 const priv_p priv = NG_NODE_PRIVATE(node);
380 int error;
381 struct mbuf *m;
382
383 NGI_GET_M(item, m);
384 /* Compress and/or encrypt */
385 if (hook == priv->xmit.hook) {
386 if (!priv->xmit.cfg.enable) {
387 NG_FREE_M(m);
388 NG_FREE_ITEM(item);
389 return (ENXIO);
390 }
391 if ((error = ng_mppc_compress(node, &m)) != 0) {
392 NG_FREE_ITEM(item);
393 return(error);
394 }
395 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
396 return (error);
397 }
398
399 /* Decompress and/or decrypt */
400 if (hook == priv->recv.hook) {
401 if (!priv->recv.cfg.enable) {
402 NG_FREE_M(m);
403 NG_FREE_ITEM(item);
404 return (ENXIO);
405 }
406 if ((error = ng_mppc_decompress(node, &m)) != 0) {
407 NG_FREE_ITEM(item);
408 if (error == EINVAL && priv->ctrlnode != 0) {
409 struct ng_mesg *msg;
410
411 /* Need to send a reset-request */
412 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
413 NGM_MPPC_RESETREQ, 0, M_NOWAIT);
414 if (msg == NULL)
415 return (error);
416 NG_SEND_MSG_ID(error, node, msg,
417 priv->ctrlnode, 0);
418 }
419 return (error);
420 }
421 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
422 return (error);
423 }
424
425 /* Oops */
426 panic("%s: unknown hook", __func__);
427 #ifdef RESTARTABLE_PANICS
428 return (EINVAL);
429 #endif
430 }
431
432 /*
433 * Destroy node
434 */
435 static int
436 ng_mppc_shutdown(node_p node)
437 {
438 const priv_p priv = NG_NODE_PRIVATE(node);
439
440 /* Take down netgraph node */
441 #ifdef NETGRAPH_MPPC_COMPRESSION
442 if (priv->xmit.history != NULL)
443 free(priv->xmit.history, M_NETGRAPH_MPPC);
444 if (priv->recv.history != NULL)
445 free(priv->recv.history, M_NETGRAPH_MPPC);
446 #endif
447 bzero(priv, sizeof(*priv));
448 free(priv, M_NETGRAPH_MPPC);
449 NG_NODE_SET_PRIVATE(node, NULL);
450 NG_NODE_UNREF(node); /* let the node escape */
451 return (0);
452 }
453
454 /*
455 * Hook disconnection
456 */
457 static int
458 ng_mppc_disconnect(hook_p hook)
459 {
460 const node_p node = NG_HOOK_NODE(hook);
461 const priv_p priv = NG_NODE_PRIVATE(node);
462
463 /* Zero out hook pointer */
464 if (hook == priv->xmit.hook)
465 priv->xmit.hook = NULL;
466 if (hook == priv->recv.hook)
467 priv->recv.hook = NULL;
468
469 /* Go away if no longer connected */
470 if ((NG_NODE_NUMHOOKS(node) == 0)
471 && NG_NODE_IS_VALID(node))
472 ng_rmnode_self(node);
473 return (0);
474 }
475
476 /************************************************************************
477 HELPER STUFF
478 ************************************************************************/
479
480 /*
481 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
482 * The original mbuf is not free'd.
483 */
484 static int
485 ng_mppc_compress(node_p node, struct mbuf **datap)
486 {
487 const priv_p priv = NG_NODE_PRIVATE(node);
488 struct ng_mppc_dir *const d = &priv->xmit;
489 u_int16_t header;
490 struct mbuf *m = *datap;
491
492 /* We must own the mbuf chain exclusively to modify it. */
493 m = m_unshare(m, M_DONTWAIT);
494 if (m == NULL)
495 return (ENOMEM);
496
497 /* Initialize */
498 header = d->cc;
499
500 /* Always set the flushed bit in stateless mode */
501 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
502 header |= MPPC_FLAG_FLUSHED;
503 d->flushed = 0;
504 }
505
506 /* Compress packet (if compression enabled) */
507 #ifdef NETGRAPH_MPPC_COMPRESSION
508 if ((d->cfg.bits & MPPC_BIT) != 0) {
509 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
510 u_char *inbuf, *outbuf;
511 int outlen, inlen, ina;
512 u_char *source, *dest;
513 u_long sourceCnt, destCnt;
514 int rtn;
515
516 /* Work with contiguous regions of memory. */
517 inlen = m->m_pkthdr.len;
518 if (m->m_next == NULL) {
519 inbuf = mtod(m, u_char *);
520 ina = 0;
521 } else {
522 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
523 if (inbuf == NULL)
524 goto err1;
525 m_copydata(m, 0, inlen, (caddr_t)inbuf);
526 ina = 1;
527 }
528
529 outlen = MPPC_MAX_BLOWUP(inlen);
530 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
531 if (outbuf == NULL) {
532 if (ina)
533 free(inbuf, M_NETGRAPH_MPPC);
534 err1:
535 m_freem(m);
536 MPPC_InitCompressionHistory(d->history);
537 d->flushed = 1;
538 return (ENOMEM);
539 }
540
541 /* Prepare to compress */
542 source = inbuf;
543 sourceCnt = inlen;
544 dest = outbuf;
545 destCnt = outlen;
546 if ((d->cfg.bits & MPPE_STATELESS) == 0)
547 flags |= MPPC_SAVE_HISTORY;
548
549 /* Compress */
550 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
551 &destCnt, d->history, flags, 0);
552
553 /* Check return value */
554 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
555 if ((rtn & MPPC_EXPANDED) == 0
556 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
557 outlen -= destCnt;
558 header |= MPPC_FLAG_COMPRESSED;
559 if ((rtn & MPPC_RESTART_HISTORY) != 0)
560 header |= MPPC_FLAG_RESTART;
561
562 /* Replace m by the compresed one. */
563 m_copyback(m, 0, outlen, (caddr_t)outbuf);
564 if (m->m_pkthdr.len < outlen) {
565 m_freem(m);
566 m = NULL;
567 } else if (outlen < m->m_pkthdr.len)
568 m_adj(m, outlen - m->m_pkthdr.len);
569 }
570 d->flushed = (rtn & MPPC_EXPANDED) != 0
571 || (flags & MPPC_SAVE_HISTORY) == 0;
572
573 if (ina)
574 free(inbuf, M_NETGRAPH_MPPC);
575 free(outbuf, M_NETGRAPH_MPPC);
576
577 /* Check mbuf chain reload result. */
578 if (m == NULL) {
579 if (!d->flushed) {
580 MPPC_InitCompressionHistory(d->history);
581 d->flushed = 1;
582 }
583 return (ENOMEM);
584 }
585 }
586 #endif
587
588 /* Now encrypt packet (if encryption enabled) */
589 #ifdef NETGRAPH_MPPC_ENCRYPTION
590 if ((d->cfg.bits & MPPE_BITS) != 0) {
591 struct mbuf *m1;
592
593 /* Set header bits */
594 header |= MPPC_FLAG_ENCRYPTED;
595
596 /* Update key if it's time */
597 if ((d->cfg.bits & MPPE_STATELESS) != 0
598 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
599 ng_mppc_updatekey(d->cfg.bits,
600 d->cfg.startkey, d->key, &d->rc4);
601 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
602 /* Need to reset key if we say we did
603 and ng_mppc_updatekey wasn't called to do it also. */
604 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
605 }
606
607 /* Encrypt packet */
608 m1 = m;
609 while (m1) {
610 rc4_crypt(&d->rc4, mtod(m1, u_char *),
611 mtod(m1, u_char *), m1->m_len);
612 m1 = m1->m_next;
613 }
614 }
615 #endif
616
617 /* Update coherency count for next time (12 bit arithmetic) */
618 MPPC_CCOUNT_INC(d->cc);
619
620 /* Install header */
621 M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT);
622 if (m != NULL)
623 be16enc(mtod(m, void *), header);
624
625 *datap = m;
626 return (*datap == NULL ? ENOBUFS : 0);
627 }
628
629 /*
630 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
631 * The original mbuf is not free'd.
632 */
633 static int
634 ng_mppc_decompress(node_p node, struct mbuf **datap)
635 {
636 const priv_p priv = NG_NODE_PRIVATE(node);
637 struct ng_mppc_dir *const d = &priv->recv;
638 u_int16_t header, cc;
639 u_int numLost;
640 struct mbuf *m = *datap;
641
642 /* We must own the mbuf chain exclusively to modify it. */
643 m = m_unshare(m, M_DONTWAIT);
644 if (m == NULL)
645 return (ENOMEM);
646
647 /* Pull off header */
648 if (m->m_pkthdr.len < MPPC_HDRLEN) {
649 m_freem(m);
650 return (EINVAL);
651 }
652 header = be16dec(mtod(m, void *));
653 cc = (header & MPPC_CCOUNT_MASK);
654 m_adj(m, MPPC_HDRLEN);
655
656 /* Check for an unexpected jump in the sequence number */
657 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
658
659 /* If flushed bit set, we can always handle packet */
660 if ((header & MPPC_FLAG_FLUSHED) != 0) {
661 #ifdef NETGRAPH_MPPC_COMPRESSION
662 if (d->history != NULL)
663 MPPC_InitDecompressionHistory(d->history);
664 #endif
665 #ifdef NETGRAPH_MPPC_ENCRYPTION
666 if ((d->cfg.bits & MPPE_BITS) != 0) {
667 u_int rekey;
668
669 /* How many times are we going to have to re-key? */
670 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
671 numLost : (numLost / (MPPE_UPDATE_MASK + 1));
672 if (rekey > mppe_max_rekey) {
673 if (mppe_block_on_max_rekey) {
674 if (mppe_log_max_rekey) {
675 log(LOG_ERR, "%s: too many (%d) packets"
676 " dropped, disabling node %p!\n",
677 __func__, numLost, node);
678 }
679 priv->recv.cfg.enable = 0;
680 goto failed;
681 } else {
682 if (mppe_log_max_rekey) {
683 log(LOG_ERR, "%s: %d packets"
684 " dropped, node %p\n",
685 __func__, numLost, node);
686 }
687 goto failed;
688 }
689 }
690
691 /* Re-key as necessary to catch up to peer */
692 while (d->cc != cc) {
693 if ((d->cfg.bits & MPPE_STATELESS) != 0
694 || (d->cc & MPPE_UPDATE_MASK)
695 == MPPE_UPDATE_FLAG) {
696 ng_mppc_updatekey(d->cfg.bits,
697 d->cfg.startkey, d->key, &d->rc4);
698 }
699 MPPC_CCOUNT_INC(d->cc);
700 }
701
702 /* Reset key (except in stateless mode, see below) */
703 if ((d->cfg.bits & MPPE_STATELESS) == 0)
704 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
705 }
706 #endif
707 d->cc = cc; /* skip over lost seq numbers */
708 numLost = 0; /* act like no packets were lost */
709 }
710
711 /* Can't decode non-sequential packets without a flushed bit */
712 if (numLost != 0)
713 goto failed;
714
715 /* Decrypt packet */
716 if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
717 #ifdef NETGRAPH_MPPC_ENCRYPTION
718 struct mbuf *m1;
719 #endif
720
721 /* Are we not expecting encryption? */
722 if ((d->cfg.bits & MPPE_BITS) == 0) {
723 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
724 __func__, "encrypted");
725 goto failed;
726 }
727
728 #ifdef NETGRAPH_MPPC_ENCRYPTION
729 /* Update key if it's time (always in stateless mode) */
730 if ((d->cfg.bits & MPPE_STATELESS) != 0
731 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
732 ng_mppc_updatekey(d->cfg.bits,
733 d->cfg.startkey, d->key, &d->rc4);
734 }
735
736 /* Decrypt packet */
737 m1 = m;
738 while (m1 != NULL) {
739 rc4_crypt(&d->rc4, mtod(m1, u_char *),
740 mtod(m1, u_char *), m1->m_len);
741 m1 = m1->m_next;
742 }
743 #endif
744 } else {
745
746 /* Are we expecting encryption? */
747 if ((d->cfg.bits & MPPE_BITS) != 0) {
748 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
749 __func__, "unencrypted");
750 goto failed;
751 }
752 }
753
754 /* Update coherency count for next time (12 bit arithmetic) */
755 MPPC_CCOUNT_INC(d->cc);
756
757 /* Check for unexpected compressed packet */
758 if ((header & MPPC_FLAG_COMPRESSED) != 0
759 && (d->cfg.bits & MPPC_BIT) == 0) {
760 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
761 __func__, "compressed");
762 failed:
763 m_freem(m);
764 return (EINVAL);
765 }
766
767 #ifdef NETGRAPH_MPPC_COMPRESSION
768 /* Decompress packet */
769 if ((header & MPPC_FLAG_COMPRESSED) != 0) {
770 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
771 u_char *inbuf, *outbuf;
772 int inlen, outlen, ina;
773 u_char *source, *dest;
774 u_long sourceCnt, destCnt;
775 int rtn;
776
777 /* Copy payload into a contiguous region of memory. */
778 inlen = m->m_pkthdr.len;
779 if (m->m_next == NULL) {
780 inbuf = mtod(m, u_char *);
781 ina = 0;
782 } else {
783 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
784 if (inbuf == NULL) {
785 m_freem(m);
786 return (ENOMEM);
787 }
788 m_copydata(m, 0, inlen, (caddr_t)inbuf);
789 ina = 1;
790 }
791
792 /* Allocate a buffer for decompressed data */
793 outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
794 M_NETGRAPH_MPPC, M_NOWAIT);
795 if (outbuf == NULL) {
796 m_freem(m);
797 if (ina)
798 free(inbuf, M_NETGRAPH_MPPC);
799 return (ENOMEM);
800 }
801 outlen = MPPC_DECOMP_BUFSIZE;
802
803 /* Prepare to decompress */
804 source = inbuf;
805 sourceCnt = inlen;
806 dest = outbuf;
807 destCnt = outlen;
808 if ((header & MPPC_FLAG_RESTART) != 0)
809 flags |= MPPC_RESTART_HISTORY;
810
811 /* Decompress */
812 rtn = MPPC_Decompress(&source, &dest,
813 &sourceCnt, &destCnt, d->history, flags);
814
815 /* Check return value */
816 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
817 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
818 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
819 log(LOG_ERR, "%s: decomp returned 0x%x",
820 __func__, rtn);
821 if (ina)
822 free(inbuf, M_NETGRAPH_MPPC);
823 free(outbuf, M_NETGRAPH_MPPC);
824 goto failed;
825 }
826
827 /* Replace compressed data with decompressed data */
828 if (ina)
829 free(inbuf, M_NETGRAPH_MPPC);
830 outlen -= destCnt;
831
832 m_copyback(m, 0, outlen, (caddr_t)outbuf);
833 if (m->m_pkthdr.len < outlen) {
834 m_freem(m);
835 m = NULL;
836 } else if (outlen < m->m_pkthdr.len)
837 m_adj(m, outlen - m->m_pkthdr.len);
838 free(outbuf, M_NETGRAPH_MPPC);
839 }
840 #endif
841
842 /* Return result in an mbuf */
843 *datap = m;
844 return (*datap == NULL ? ENOBUFS : 0);
845 }
846
847 /*
848 * The peer has sent us a CCP ResetRequest, so reset our transmit state.
849 */
850 static void
851 ng_mppc_reset_req(node_p node)
852 {
853 const priv_p priv = NG_NODE_PRIVATE(node);
854 struct ng_mppc_dir *const d = &priv->xmit;
855
856 #ifdef NETGRAPH_MPPC_COMPRESSION
857 if (d->history != NULL)
858 MPPC_InitCompressionHistory(d->history);
859 #endif
860 #ifdef NETGRAPH_MPPC_ENCRYPTION
861 if ((d->cfg.bits & MPPE_STATELESS) == 0)
862 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
863 #endif
864 d->flushed = 1;
865 }
866
867 #ifdef NETGRAPH_MPPC_ENCRYPTION
868 /*
869 * Generate a new encryption key
870 */
871 static void
872 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
873 {
874 static const u_char pad1[40] =
875 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
876 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
877 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
878 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
879 static const u_char pad2[40] =
880 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
881 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
882 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
883 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
884 u_char hash[20];
885 SHA1_CTX c;
886
887 SHA1Init(&c);
888 SHA1Update(&c, h, len);
889 SHA1Update(&c, pad1, sizeof(pad1));
890 SHA1Update(&c, h2, len);
891 SHA1Update(&c, pad2, sizeof(pad2));
892 SHA1Final(hash, &c);
893 bcopy(hash, h2, len);
894 }
895
896 /*
897 * Update the encryption key
898 */
899 static void
900 ng_mppc_updatekey(u_int32_t bits,
901 u_char *key0, u_char *key, struct rc4_state *rc4)
902 {
903 const int keylen = KEYLEN(bits);
904
905 ng_mppc_getkey(key0, key, keylen);
906 rc4_init(rc4, key, keylen);
907 rc4_crypt(rc4, key, key, keylen);
908 if ((bits & MPPE_40) != 0)
909 bcopy(&ng_mppe_weakenkey, key, 3);
910 else if ((bits & MPPE_56) != 0)
911 bcopy(&ng_mppe_weakenkey, key, 1);
912 rc4_init(rc4, key, keylen);
913 }
914 #endif
915
Cache object: dffa007575555d2a4587e2aaa72d1d3a
|