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