xref: /freebsd/usr.sbin/ppp/mppe.c (revision c11e094d96120a2e0e726ed9705ae0ec08db49b6)
1 /*-
2  * Copyright (c) 2000 Semen Ustimenko <semenu@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #include <sys/types.h>
30 
31 #ifdef __FreeBSD__
32 #include <netinet/in.h>
33 #endif
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <termios.h>
39 #include <openssl/rc4.h>
40 
41 #include "defs.h"
42 #include "mbuf.h"
43 #include "log.h"
44 #include "timer.h"
45 #include "fsm.h"
46 #include "lqr.h"
47 #include "hdlc.h"
48 #include "lcp.h"
49 #include "ccp.h"
50 #include "throughput.h"
51 #include "layer.h"
52 #include "link.h"
53 #include "chap_ms.h"
54 #include "proto.h"
55 #include "mppe.h"
56 #include "ua.h"
57 
58 /*
59  * Documentation:
60  *
61  * draft-ietf-pppext-mppe-04.txt
62  * draft-ietf-pppext-mppe-keys-02.txt
63  */
64 
65 #define	MPPE_OPT_STATELESS	0x1000000
66 #define	MPPE_OPT_COMPRESSED	0x01
67 #define	MPPE_OPT_40BIT		0x20
68 #define	MPPE_OPT_56BIT		0x80
69 #define	MPPE_OPT_128BIT		0x40
70 #define	MPPE_OPT_BITMASK	0xe0
71 #define	MPPE_OPT_MASK		(MPPE_OPT_STATELESS | MPPE_OPT_BITMASK)
72 
73 #define	MPPE_FLUSHED			0x8000
74 #define	MPPE_ENCRYPTED			0x1000
75 #define	MPPE_HEADER_BITMASK		0xf000
76 #define	MPPE_HEADER_FLAG		0x00ff
77 #define	MPPE_HEADER_FLAGMASK		0x00ff
78 #define	MPPE_HEADER_FLAGSHIFT		8
79 #define	MPPE_HEADER_STATEFUL_KEYCHANGES	16
80 
81 struct mppe_state {
82   unsigned	stateless : 1;
83   unsigned	flushnext : 1;
84   unsigned	flushrequired : 1;
85   int		cohnum;
86   int		keylen;			/* 8 or 16 bytes */
87   int 		keybits;		/* 40, 56 or 128 bits */
88   char		sesskey[MPPE_KEY_LEN];
89   char		mastkey[MPPE_KEY_LEN];
90   RC4_KEY	rc4key;
91 };
92 
93 int MPPE_MasterKeyValid = 0;
94 int MPPE_IsServer = 0;
95 char MPPE_MasterKey[MPPE_KEY_LEN];
96 
97 /*
98  * The peer has missed a packet.  Mark the next output frame to be FLUSHED
99  */
100 static int
101 MPPEResetOutput(void *v)
102 {
103   struct mppe_state *mop = (struct mppe_state *)v;
104 
105   if (mop->stateless)
106     log_Printf(LogCCP, "MPPE: Unexpected output channel reset\n");
107   else {
108     log_Printf(LogCCP, "MPPE: Output channel reset\n");
109     mop->flushnext = 1;
110   }
111 
112   return 0;		/* Ask FSM not to ACK */
113 }
114 
115 static void
116 MPPEReduceSessionKey(struct mppe_state *mp)
117 {
118   switch(mp->keybits) {
119   case 40:
120     mp->sesskey[2] = 0x9e;
121     mp->sesskey[1] = 0x26;
122   case 56:
123     mp->sesskey[0] = 0xd1;
124   case 128:
125     break;
126   }
127 }
128 
129 static void
130 MPPEKeyChange(struct mppe_state *mp)
131 {
132   char InterimKey[MPPE_KEY_LEN];
133   RC4_KEY RC4Key;
134 
135   GetNewKeyFromSHA(mp->mastkey, mp->sesskey, mp->keylen, InterimKey);
136   RC4_set_key(&RC4Key, mp->keylen, InterimKey);
137   RC4(&RC4Key, mp->keylen, InterimKey, mp->sesskey);
138 
139   MPPEReduceSessionKey(mp);
140 }
141 
142 static struct mbuf *
143 MPPEOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short *proto,
144            struct mbuf *mp)
145 {
146   struct mppe_state *mop = (struct mppe_state *)v;
147   struct mbuf *mo;
148   u_short nproto, prefix;
149   int dictinit, ilen, len;
150   char *rp;
151 
152   ilen = m_length(mp);
153   dictinit = 0;
154 
155   log_Printf(LogDEBUG, "MPPE: Output: Proto %02x (%d bytes)\n", *proto, ilen);
156   if (*proto < 0x21 && *proto > 0xFA) {
157     log_Printf(LogDEBUG, "MPPE: Output: Not encrypting\n");
158     ccp->compout += ilen;
159     ccp->uncompout += ilen;
160     return mp;
161   }
162 
163   log_DumpBp(LogDEBUG, "MPPE: Output: Encrypt packet:", mp);
164 
165   /* Get mbuf for prefixes */
166   mo = m_get(4, MB_CCPOUT);
167   mo->m_next = mp;
168 
169   rp = MBUF_CTOP(mo);
170   prefix = MPPE_ENCRYPTED | mop->cohnum;
171 
172   if (mop->stateless ||
173       (mop->cohnum & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG) {
174     /* Change our key */
175     log_Printf(LogDEBUG, "MPPEOutput: Key changed [%d]\n", mop->cohnum);
176     MPPEKeyChange(mop);
177     dictinit = 1;
178   }
179 
180   if (mop->stateless || mop->flushnext) {
181     prefix |= MPPE_FLUSHED;
182     dictinit = 1;
183     mop->flushnext = 0;
184   }
185 
186   if (dictinit) {
187     /* Initialise our dictionary */
188     log_Printf(LogDEBUG, "MPPEOutput: Dictionary initialised [%d]\n",
189                mop->cohnum);
190     RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey);
191   }
192 
193   /* Set MPPE packet prefix */
194   ua_htons(&prefix, rp);
195 
196   /* Save encrypted protocol number */
197   nproto = htons(*proto);
198   RC4(&mop->rc4key, 2, (char *)&nproto, rp + 2);
199 
200   /* Encrypt main packet */
201   rp = MBUF_CTOP(mp);
202   RC4(&mop->rc4key, ilen, rp, rp);
203 
204   mop->cohnum++;
205   mop->cohnum &= ~MPPE_HEADER_BITMASK;
206 
207   /* Set the protocol number */
208   *proto = ccp_Proto(ccp);
209   len = m_length(mo);
210   ccp->uncompout += ilen;
211   ccp->compout += len;
212 
213   log_Printf(LogDEBUG, "MPPE: Output: Encrypted: Proto %02x (%d bytes)\n",
214              *proto, len);
215 
216   return mo;
217 }
218 
219 static void
220 MPPEResetInput(void *v)
221 {
222   log_Printf(LogCCP, "MPPE: Unexpected input channel ack\n");
223 }
224 
225 static struct mbuf *
226 MPPEInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mp)
227 {
228   struct mppe_state *mip = (struct mppe_state *)v;
229   u_short prefix;
230   char *rp;
231   int dictinit, flushed, ilen, len, n;
232 
233   ilen = m_length(mp);
234   dictinit = 0;
235   ccp->compin += ilen;
236 
237   log_Printf(LogDEBUG, "MPPE: Input: Proto %02x (%d bytes)\n", *proto, ilen);
238   log_DumpBp(LogDEBUG, "MPPE: Input: Packet:", mp);
239 
240   mp = mbuf_Read(mp, &prefix, 2);
241   prefix = ntohs(prefix);
242   flushed = prefix & MPPE_FLUSHED;
243   prefix &= ~flushed;
244   if ((prefix & MPPE_HEADER_BITMASK) != MPPE_ENCRYPTED) {
245     log_Printf(LogERROR, "MPPE: Input: Invalid packet (flags = 0x%x)\n",
246                (prefix & MPPE_HEADER_BITMASK) | flushed);
247     m_freem(mp);
248     return NULL;
249   }
250 
251   prefix &= ~MPPE_HEADER_BITMASK;
252 
253   if (!flushed && mip->stateless) {
254     log_Printf(LogCCP, "MPPEInput: Packet without MPPE_FLUSHED set"
255                " in stateless mode\n");
256     flushed = MPPE_FLUSHED;
257     /* Should we really continue ? */
258   }
259 
260   if (mip->stateless) {
261     /* Change our key for each missed packet in stateless mode */
262     while (prefix != mip->cohnum) {
263       log_Printf(LogDEBUG, "MPPEInput: Key changed [%u]\n", prefix);
264       MPPEKeyChange(mip);
265       /*
266        * mip->cohnum contains what we received last time in stateless
267        * mode.
268        */
269       mip->cohnum++;
270       mip->cohnum &= ~MPPE_HEADER_BITMASK;
271     }
272     dictinit = 1;
273   } else {
274     if (flushed) {
275       /*
276        * We can always process a flushed packet.
277        * Catch up on any outstanding key changes.
278        */
279       n = (prefix >> MPPE_HEADER_FLAGSHIFT) -
280           (mip->cohnum >> MPPE_HEADER_FLAGSHIFT);
281       if (n < 0)
282         n += MPPE_HEADER_STATEFUL_KEYCHANGES;
283       while (n--) {
284         log_Printf(LogDEBUG, "MPPEInput: Key changed during catchup [%u]\n",
285                    prefix);
286         MPPEKeyChange(mip);
287       }
288       mip->flushrequired = 0;
289       mip->cohnum = prefix;
290       dictinit = 1;
291     }
292 
293     if (mip->flushrequired) {
294       /*
295        * Perhaps we should be lenient if
296        * (prefix & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG
297        * The spec says that we shouldn't be though....
298        */
299       log_Printf(LogDEBUG, "MPPE: Not flushed - discarded\n");
300       fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->fsm.reqid++, NULL, 0,
301                  MB_CCPOUT);
302       m_freem(mp);
303       return NULL;
304     }
305 
306     if (prefix != mip->cohnum) {
307       /*
308        * We're in stateful mode and didn't receive the expected
309        * packet.  Send a reset request, but don't tell the CCP layer
310        * about it as we don't expect to receive a Reset ACK !
311        * Guess what... M$ invented this !
312        */
313       log_Printf(LogCCP, "MPPE: Input: Got seq %u, not %u\n",
314                  prefix, mip->cohnum);
315       fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->fsm.reqid++, NULL, 0,
316                  MB_CCPOUT);
317       mip->flushrequired = 1;
318       m_freem(mp);
319       return NULL;
320     }
321 
322     if ((prefix & MPPE_HEADER_FLAGMASK) == MPPE_HEADER_FLAG) {
323       log_Printf(LogDEBUG, "MPPEInput: Key changed [%u]\n", prefix);
324       MPPEKeyChange(mip);
325       dictinit = 1;
326     } else if (flushed)
327       dictinit = 1;
328 
329     /*
330      * mip->cohnum contains what we expect to receive next time in stateful
331      * mode.
332      */
333     mip->cohnum++;
334     mip->cohnum &= ~MPPE_HEADER_BITMASK;
335   }
336 
337   if (dictinit) {
338     log_Printf(LogDEBUG, "MPPEInput: Dictionary initialised [%u]\n", prefix);
339     RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey);
340   }
341 
342   mp = mbuf_Read(mp, proto, 2);
343   RC4(&mip->rc4key, 2, (char *)proto, (char *)proto);
344   *proto = ntohs(*proto);
345 
346   rp = MBUF_CTOP(mp);
347   len = m_length(mp);
348   RC4(&mip->rc4key, len, rp, rp);
349 
350   log_Printf(LogDEBUG, "MPPEInput: Decrypted: Proto %02x (%d bytes)\n",
351              *proto, len);
352   log_DumpBp(LogDEBUG, "MPPEInput: Decrypted: Packet:", mp);
353 
354   ccp->uncompin += len;
355 
356   return mp;
357 }
358 
359 static void
360 MPPEDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi)
361 {
362 }
363 
364 static const char *
365 MPPEDispOpts(struct fsm_opt *o)
366 {
367   static char buf[70];
368   u_int32_t val;
369   char ch;
370   int len, n;
371 
372   ua_ntohl(o->data, &val);
373   len = 0;
374   if ((n = snprintf(buf, sizeof buf, "value 0x%08x ", (unsigned)val)) > 0)
375     len += n;
376   if (!(val & MPPE_OPT_BITMASK)) {
377     if ((n = snprintf(buf + len, sizeof buf - len, "(0")) > 0)
378       len += n;
379   } else {
380     ch = '(';
381     if (val & MPPE_OPT_128BIT) {
382       if ((n = snprintf(buf + len, sizeof buf - len, "%c128", ch)) > 0)
383         len += n;
384       ch = '/';
385     }
386     if (val & MPPE_OPT_56BIT) {
387       if ((n = snprintf(buf + len, sizeof buf - len, "%c56", ch)) > 0)
388         len += n;
389       ch = '/';
390     }
391     if (val & MPPE_OPT_40BIT) {
392       if ((n = snprintf(buf + len, sizeof buf - len, "%c40", ch)) > 0)
393         len += n;
394       ch = '/';
395     }
396   }
397 
398   if ((n = snprintf(buf + len, sizeof buf - len, " bits, state%s",
399                     (val & MPPE_OPT_STATELESS) ? "less" : "ful")) > 0)
400     len += n;
401 
402   if (val & MPPE_OPT_COMPRESSED) {
403     if ((n = snprintf(buf + len, sizeof buf - len, ", compressed")) > 0)
404       len += n;
405   }
406 
407   snprintf(buf + len, sizeof buf - len, ")");
408 
409   return buf;
410 }
411 
412 static int
413 MPPEUsable(struct fsm *fp)
414 {
415   struct lcp *lcp;
416   int ok;
417 
418   lcp = &fp->link->lcp;
419   ok = (lcp->want_auth == PROTO_CHAP && lcp->want_authtype == 0x81) ||
420        (lcp->his_auth == PROTO_CHAP && lcp->his_authtype == 0x81);
421   if (!ok)
422     log_Printf(LogCCP, "MPPE: Not usable without CHAP81\n");
423 
424   return ok;
425 }
426 
427 static int
428 MPPERequired(struct fsm *fp)
429 {
430   return fp->link->ccp.cfg.mppe.required;
431 }
432 
433 static u_int32_t
434 MPPE_ConfigVal(const struct ccp_config *cfg)
435 {
436   u_int32_t val;
437 
438   val = cfg->mppe.state == MPPE_STATELESS ? MPPE_OPT_STATELESS : 0;
439   switch(cfg->mppe.keybits) {
440   case 128:
441     val |= MPPE_OPT_128BIT;
442     break;
443   case 56:
444     val |= MPPE_OPT_56BIT;
445     break;
446   case 40:
447     val |= MPPE_OPT_40BIT;
448     break;
449   case 0:
450     val |= MPPE_OPT_128BIT | MPPE_OPT_56BIT | MPPE_OPT_40BIT;
451     break;
452   }
453 
454   return val;
455 }
456 
457 /*
458  * What options should we use for our first configure request
459  */
460 static void
461 MPPEInitOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
462 {
463   u_int32_t mval;
464 
465   o->hdr.len = 6;
466 
467   if (!MPPE_MasterKeyValid) {
468     log_Printf(LogCCP, "MPPE: MasterKey is invalid,"
469                " MPPE is available only with CHAP81 authentication\n");
470     ua_htonl(0x0, o->data);
471     return;
472   }
473 
474   mval = MPPE_ConfigVal(cfg);
475   ua_htonl(&mval, o->data);
476 }
477 
478 /*
479  * Our CCP request was NAK'd with the given options
480  */
481 static int
482 MPPESetOptsOutput(struct fsm_opt *o, const struct ccp_config *cfg)
483 {
484   u_int32_t mval, peer;
485 
486   ua_ntohl(o->data, &peer);
487 
488   if (!MPPE_MasterKeyValid)
489     /* Treat their NAK as a REJ */
490     return MODE_NAK;
491 
492   mval = MPPE_ConfigVal(cfg);
493 
494   /*
495    * If we haven't been configured with a specific number of keybits, allow
496    * whatever the peer asks for.
497    */
498   if (!cfg->mppe.keybits) {
499     mval &= ~MPPE_OPT_BITMASK;
500     mval |= (peer & MPPE_OPT_BITMASK);
501     if (!(mval & MPPE_OPT_BITMASK))
502       mval |= MPPE_OPT_128BIT;
503   }
504 
505   /* Adjust our statelessness */
506   if (cfg->mppe.state == MPPE_ANYSTATE) {
507     mval &= ~MPPE_OPT_STATELESS;
508     mval |= (peer & MPPE_OPT_STATELESS);
509   }
510 
511   ua_htonl(&mval, o->data);
512 
513   return MODE_ACK;
514 }
515 
516 /*
517  * The peer has requested the given options
518  */
519 static int
520 MPPESetOptsInput(struct fsm_opt *o, const struct ccp_config *cfg)
521 {
522   u_int32_t mval, peer;
523   int res = MODE_ACK;
524 
525   ua_ntohl(o->data, &peer);
526   if (!MPPE_MasterKeyValid) {
527     if (peer != 0) {
528       peer = 0;
529       ua_htonl(&peer, o->data);
530       return MODE_NAK;
531     } else
532       return MODE_ACK;
533   }
534 
535   mval = MPPE_ConfigVal(cfg);
536 
537   if (peer & ~MPPE_OPT_MASK)
538     /* He's asking for bits we don't know about */
539     res = MODE_NAK;
540 
541   if (peer & MPPE_OPT_STATELESS) {
542     if (cfg->mppe.state == MPPE_STATEFUL)
543       /* Peer can't have stateless */
544       res = MODE_NAK;
545     else
546       /* Peer wants stateless, that's ok */
547       mval |= MPPE_OPT_STATELESS;
548   } else {
549     if (cfg->mppe.state == MPPE_STATELESS)
550       /* Peer must have stateless */
551       res = MODE_NAK;
552     else
553       /* Peer doesn't want stateless, that's ok */
554       mval &= ~MPPE_OPT_STATELESS;
555   }
556 
557   /* If we've got a configured number of keybits - the peer must use that */
558   if (cfg->mppe.keybits) {
559     ua_htonl(&mval, o->data);
560     return peer == mval ? res : MODE_NAK;
561   }
562 
563   /* If a specific number of bits hasn't been requested, we'll need to NAK */
564   switch (peer & MPPE_OPT_BITMASK) {
565   case MPPE_OPT_128BIT:
566   case MPPE_OPT_56BIT:
567   case MPPE_OPT_40BIT:
568     break;
569   default:
570     res = MODE_NAK;
571   }
572 
573   /* Suggest the best number of bits */
574   mval &= ~MPPE_OPT_BITMASK;
575   if (peer & MPPE_OPT_128BIT)
576     mval |= MPPE_OPT_128BIT;
577   else if (peer & MPPE_OPT_56BIT)
578     mval |= MPPE_OPT_56BIT;
579   else if (peer & MPPE_OPT_40BIT)
580     mval |= MPPE_OPT_40BIT;
581   else
582     mval |= MPPE_OPT_128BIT;
583   ua_htonl(&mval, o->data);
584 
585   return res;
586 }
587 
588 static struct mppe_state *
589 MPPE_InitState(struct fsm_opt *o)
590 {
591   struct mppe_state *mp;
592   u_int32_t val;
593 
594   if ((mp = calloc(1, sizeof *mp)) != NULL) {
595     ua_ntohl(o->data, &val);
596 
597     switch (val & MPPE_OPT_BITMASK) {
598     case MPPE_OPT_128BIT:
599       mp->keylen = 16;
600       mp->keybits = 128;
601       break;
602     case MPPE_OPT_56BIT:
603       mp->keylen = 8;
604       mp->keybits = 56;
605       break;
606     case MPPE_OPT_40BIT:
607       mp->keylen = 8;
608       mp->keybits = 40;
609       break;
610     default:
611       log_Printf(LogWARN, "Unexpected MPPE options 0x%08x\n", val);
612       free(mp);
613       return NULL;
614     }
615 
616     mp->stateless = !!(val & MPPE_OPT_STATELESS);
617   }
618 
619   return mp;
620 }
621 
622 static void *
623 MPPEInitInput(struct fsm_opt *o)
624 {
625   struct mppe_state *mip;
626 
627   if (!MPPE_MasterKeyValid) {
628     log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
629     return NULL;
630   }
631 
632   if ((mip = MPPE_InitState(o)) == NULL) {
633     log_Printf(LogWARN, "MPPEInput: Cannot initialise - unexpected options\n");
634     return NULL;
635   }
636 
637   log_Printf(LogDEBUG, "MPPE: InitInput: %d-bits\n", mip->keybits);
638 
639   GetAsymetricStartKey(MPPE_MasterKey, mip->mastkey, mip->keylen, 0,
640                        MPPE_IsServer);
641   GetNewKeyFromSHA(mip->mastkey, mip->mastkey, mip->keylen, mip->sesskey);
642 
643   MPPEReduceSessionKey(mip);
644 
645   log_Printf(LogCCP, "MPPE: Input channel initiated\n");
646 
647   if (!mip->stateless) {
648     /*
649      * We need to initialise our dictionary here as the first packet we
650      * receive is unlikely to have the FLUSHED bit set.
651      */
652     log_Printf(LogDEBUG, "MPPEInitInput: Dictionary initialised [%d]\n",
653                mip->cohnum);
654     RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey);
655   } else {
656     /*
657      * We do the first key change here as the first packet is expected
658      * to have a sequence number of 0 and we'll therefore not expect
659      * to have to change the key at that point.
660      */
661     log_Printf(LogDEBUG, "MPPEInitInput: Key changed [%d]\n", mip->cohnum);
662     MPPEKeyChange(mip);
663   }
664 
665   return mip;
666 }
667 
668 static void *
669 MPPEInitOutput(struct fsm_opt *o)
670 {
671   struct mppe_state *mop;
672 
673   if (!MPPE_MasterKeyValid) {
674     log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
675     return NULL;
676   }
677 
678   if ((mop = MPPE_InitState(o)) == NULL) {
679     log_Printf(LogWARN, "MPPEOutput: Cannot initialise - unexpected options\n");
680     return NULL;
681   }
682 
683   log_Printf(LogDEBUG, "MPPE: InitOutput: %d-bits\n", mop->keybits);
684 
685   GetAsymetricStartKey(MPPE_MasterKey, mop->mastkey, mop->keylen, 1,
686                        MPPE_IsServer);
687   GetNewKeyFromSHA(mop->mastkey, mop->mastkey, mop->keylen, mop->sesskey);
688 
689   MPPEReduceSessionKey(mop);
690 
691   log_Printf(LogCCP, "MPPE: Output channel initiated\n");
692 
693   if (!mop->stateless) {
694     /*
695      * We need to initialise our dictionary now as the first packet we
696      * send won't have the FLUSHED bit set.
697      */
698     log_Printf(LogDEBUG, "MPPEInitOutput: Dictionary initialised [%d]\n",
699                mop->cohnum);
700     RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey);
701   }
702 
703   return mop;
704 }
705 
706 static void
707 MPPETermInput(void *v)
708 {
709   free(v);
710 }
711 
712 static void
713 MPPETermOutput(void *v)
714 {
715   free(v);
716 }
717 
718 const struct ccp_algorithm MPPEAlgorithm = {
719   TY_MPPE,
720   CCP_NEG_MPPE,
721   MPPEDispOpts,
722   MPPEUsable,
723   MPPERequired,
724   {
725     MPPESetOptsInput,
726     MPPEInitInput,
727     MPPETermInput,
728     MPPEResetInput,
729     MPPEInput,
730     MPPEDictSetup
731   },
732   {
733     2,
734     MPPEInitOptsOutput,
735     MPPESetOptsOutput,
736     MPPEInitOutput,
737     MPPETermOutput,
738     MPPEResetOutput,
739     MPPEOutput
740   },
741 };
742