xref: /freebsd/usr.sbin/ppp/mppe.c (revision c678bc4f13a340ad88debe321afd0097db2590cb)
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 <stdio.h>
32 #include <stdlib.h>
33 #include <termios.h>
34 #ifdef __FreeBSD__
35 #include <sha.h>
36 #else
37 #include <openssl/sha.h>
38 #endif
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 
57 /*
58  * Documentation:
59  *
60  * draft-ietf-pppext-mppe-04.txt
61  * draft-ietf-pppext-mppe-keys-02.txt
62  */
63 
64 struct mppe_state {
65 	int	cohnum;
66 	int	keylen;			/* 8 or 16 bytes */
67 	int 	keybits;		/* 40, 56 or 128 bits */
68 	char	sesskey[MPPE_KEY_LEN];
69 	char	mastkey[MPPE_KEY_LEN];
70 	RC4_KEY	rc4key;
71 };
72 
73 int MPPE_MasterKeyValid = 0;
74 int MPPE_IsServer = 0;
75 char MPPE_MasterKey[MPPE_KEY_LEN];
76 
77 static void
78 MPPEResetOutput(void *v)
79 {
80   log_Printf(LogCCP, "MPPE: Output channel reset\n");
81 }
82 
83 static void
84 MPPEReduceSessionKey(struct mppe_state *mp)
85 {
86   switch(mp->keybits) {
87   case 40:
88     mp->sesskey[2] = 0x9e;
89     mp->sesskey[1] = 0x26;
90   case 56:
91     mp->sesskey[0] = 0xd1;
92   case 128:
93   }
94 }
95 
96 static void
97 MPPEKeyChange(struct mppe_state *mp)
98 {
99   char InterimKey[MPPE_KEY_LEN];
100   RC4_KEY RC4Key;
101 
102   GetNewKeyFromSHA(mp->mastkey, mp->sesskey, mp->keylen, InterimKey);
103   RC4_set_key(&RC4Key, mp->keylen, InterimKey);
104   RC4(&RC4Key, mp->keylen, InterimKey, mp->sesskey);
105 
106   MPPEReduceSessionKey(mp);
107 }
108 
109 static struct mbuf *
110 MPPEOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short *proto,
111            struct mbuf *mp)
112 {
113   struct mppe_state *mop = (struct mppe_state *)v;
114   struct mbuf *mo;
115   u_short nproto;
116   int ilen;
117   char *rp;
118 
119   log_Printf(LogCCP, "MPPE: Output\n");
120 
121   ilen = m_length(mp);
122 
123   log_Printf(LogDEBUG, "MPPE: Output: Proto %02x (%d bytes)\n", *proto, ilen);
124   if (*proto < 0x21 && *proto > 0xFA) {
125     log_Printf(LogDEBUG, "MPPE: Output: Not encrypting\n");
126     return mp;
127   }
128 
129   log_DumpBp(LogDEBUG, "MPPE: Output: Encrypt packet:", mp);
130 
131   /* Get mbuf for prefixes */
132   mo = m_get(4, MB_CCPOUT);
133   mo->m_next = mp;
134 
135   /* Init RC4 keys */
136   RC4_set_key(&mop->rc4key, mop->keylen, mop->sesskey);
137 
138   /* Set MPPE packet prefix */
139   rp = MBUF_CTOP(mo);
140   *(u_short *)rp = htons(0x9000 | mop->cohnum);
141 
142   /* Save encrypted protocol number */
143   nproto = htons(*proto);
144   RC4(&mop->rc4key, 2, (char *)&nproto, rp + 2);
145 
146   /* Encrypt main packet */
147   rp = MBUF_CTOP(mp);
148   RC4(&mop->rc4key, ilen, rp, rp);
149 
150   /* Rotate keys */
151   MPPEKeyChange(mop);
152   mop->cohnum ++; mop->cohnum &= 0xFFF;
153 
154   /* Chage protocol number */
155   *proto = ccp_Proto(ccp);
156 
157   log_Printf(LogDEBUG, "MPPE: Output: Encrypted: Proto %02x (%d bytes)\n",
158              *proto, m_length(mo));
159 
160   return mo;
161 }
162 
163 static void
164 MPPEResetInput(void *v)
165 {
166   log_Printf(LogCCP, "MPPE: Input channel reset\n");
167 }
168 
169 static struct mbuf *
170 MPPEInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mp)
171 {
172   struct mppe_state *mip = (struct mppe_state *)v;
173   u_short prefix;
174   char *rp;
175   int ilen;
176 
177   log_Printf(LogCCP, "MPPE: Input\n");
178 
179   ilen = m_length(mp);
180 
181   log_Printf(LogDEBUG, "MPPE: Input: Proto %02x (%d bytes)\n", *proto, ilen);
182 
183   log_DumpBp(LogDEBUG, "MPPE: Input: Packet:", mp);
184 
185   mp = mbuf_Read(mp, &prefix, 2);
186   prefix = ntohs(prefix);
187   if ((prefix & 0xF000) != 0x9000) {
188     log_Printf(LogERROR, "MPPE: Input: Invalid packet\n");
189     m_freem(mp);
190     return NULL;
191   }
192 
193   prefix &= 0xFFF;
194   while (prefix != mip->cohnum) {
195     MPPEKeyChange(mip);
196     mip->cohnum ++; mip->cohnum &= 0xFFF;
197   }
198 
199   RC4_set_key(&mip->rc4key, mip->keylen, mip->sesskey);
200 
201   mp = mbuf_Read(mp, proto, 2);
202   RC4(&mip->rc4key, 2, (char *)proto, (char *)proto);
203   *proto = ntohs(*proto);
204 
205   rp = MBUF_CTOP(mp);
206   RC4(&mip->rc4key, m_length(mp), rp, rp);
207 
208   log_Printf(LogDEBUG, "MPPE: Input: Decrypted: Proto %02x (%d bytes)\n",
209              *proto, m_length(mp));
210 
211   log_DumpBp(LogDEBUG, "MPPE: Input: Decrypted: Packet:", mp);
212 
213   return mp;
214 }
215 
216 static void
217 MPPEDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi)
218 {
219   log_Printf(LogCCP, "MPPE: DictSetup\n");
220 }
221 
222 static const char *
223 MPPEDispOpts(struct lcp_opt *o)
224 {
225   static char buf[32];
226   sprintf(buf, "value 0x%08x", (int)ntohl(*(u_int32_t *)(o->data)));
227   return buf;
228 }
229 
230 static int
231 MPPEUsable(struct fsm *fp)
232 {
233   struct lcp *lcp;
234   int ok;
235 
236   lcp = &fp->link->lcp;
237   ok = (lcp->want_auth == PROTO_CHAP && lcp->want_authtype == 0x81) ||
238        (lcp->his_auth == PROTO_CHAP && lcp->his_authtype == 0x81);
239   if (!ok)
240     log_Printf(LogCCP, "MPPE: Not usable without CHAP81\n");
241 
242   return ok;
243 }
244 
245 static void
246 MPPEInitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg)
247 {
248   u_long val;
249 
250   o->len = 6;
251 
252   log_Printf(LogCCP, "MPPE: InitOptsOutput\n");
253 
254   if (!MPPE_MasterKeyValid) {
255     log_Printf(LogCCP, "MPPE: MasterKey is invalid,"
256                " MPPE is available only with CHAP81 authentication\n");
257     *(u_int32_t *)o->data = htonl(0x0);
258     return;
259   }
260 
261   val = 0x1000000;
262   switch(cfg->mppe.keybits) {
263   case 128:
264     val |= 0x40; break;
265   case 56:
266     val |= 0x80; break;
267   case 40:
268     val |= 0x20; break;
269   }
270   *(u_int32_t *)o->data = htonl(val);
271 }
272 
273 static int
274 MPPESetOptsOutput(struct lcp_opt *o)
275 {
276   u_long *p = (u_long *)(o->data);
277   u_long val = ntohl(*p);
278 
279   log_Printf(LogCCP, "MPPE: SetOptsOutput\n");
280 
281   if (!MPPE_MasterKeyValid) {
282     if (*p != 0x0) {
283       *p = 0x0;
284       return MODE_NAK;
285     } else {
286       return MODE_ACK;
287     }
288   }
289 
290   if (val == 0x01000020 ||
291       val == 0x01000040 ||
292       val == 0x01000080)
293     return MODE_ACK;
294 
295   return MODE_NAK;
296 }
297 
298 static int
299 MPPESetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg)
300 {
301   u_long *p = (u_long *)(o->data);
302   u_long val = ntohl(*p);
303   u_long mval;
304 
305   log_Printf(LogCCP, "MPPE: SetOptsInput\n");
306 
307   if (!MPPE_MasterKeyValid) {
308     if (*p != 0x0) {
309       *p = 0x0;
310       return MODE_NAK;
311     } else {
312       return MODE_ACK;
313     }
314   }
315 
316   mval = 0x01000000;
317   switch(cfg->mppe.keybits) {
318   case 128:
319     mval |= 0x40; break;
320   case 56:
321     mval |= 0x80; break;
322   case 40:
323     mval |= 0x20; break;
324   }
325 
326   if (val == mval)
327     return MODE_ACK;
328 
329   *p = htonl(mval);
330 
331   return MODE_NAK;
332 }
333 
334 static void *
335 MPPEInitInput(struct lcp_opt *o)
336 {
337   struct mppe_state *mip;
338   u_int32_t val = ntohl(*(unsigned long *)o->data);
339 
340   log_Printf(LogCCP, "MPPE: InitInput\n");
341 
342   if (!MPPE_MasterKeyValid) {
343     log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
344     return NULL;
345   }
346 
347   mip = malloc(sizeof(*mip));
348   memset(mip, 0, sizeof(*mip));
349 
350   if (val & 0x20) {		/* 40-bits */
351     mip->keylen = 8;
352     mip->keybits = 40;
353   } else if (val & 0x80) {	/* 56-bits */
354     mip->keylen = 8;
355     mip->keybits = 56;
356   } else {			/* 128-bits */
357     mip->keylen = 16;
358     mip->keybits = 128;
359   }
360 
361   log_Printf(LogDEBUG, "MPPE: InitInput: %d-bits\n", mip->keybits);
362 
363   GetAsymetricStartKey(MPPE_MasterKey, mip->mastkey, mip->keylen, 0,
364                        MPPE_IsServer);
365   GetNewKeyFromSHA(mip->mastkey, mip->mastkey, mip->keylen, mip->sesskey);
366 
367   MPPEReduceSessionKey(mip);
368 
369   MPPEKeyChange(mip);
370 
371   mip->cohnum = 0;
372 
373   return mip;
374 }
375 
376 static void *
377 MPPEInitOutput(struct lcp_opt *o)
378 {
379   struct mppe_state *mop;
380   u_int32_t val = ntohl(*(unsigned long *)o->data);
381 
382   log_Printf(LogCCP, "MPPE: InitOutput\n");
383 
384   if (!MPPE_MasterKeyValid) {
385     log_Printf(LogWARN, "MPPE: Cannot initialise without CHAP81\n");
386     return NULL;
387   }
388 
389   mop = malloc(sizeof(*mop));
390   memset(mop, 0, sizeof(*mop));
391 
392   if (val & 0x20) {		/* 40-bits */
393     mop->keylen = 8;
394     mop->keybits = 40;
395   } else if (val & 0x80) {	/* 56-bits */
396     mop->keylen = 8;
397     mop->keybits = 56;
398   } else {			/* 128-bits */
399     mop->keylen = 16;
400     mop->keybits = 128;
401   }
402 
403   log_Printf(LogDEBUG, "MPPE: InitOutput: %d-bits\n", mop->keybits);
404 
405   GetAsymetricStartKey(MPPE_MasterKey, mop->mastkey, mop->keylen, 1,
406                        MPPE_IsServer);
407   GetNewKeyFromSHA(mop->mastkey, mop->mastkey, mop->keylen, mop->sesskey);
408 
409   MPPEReduceSessionKey(mop);
410 
411   MPPEKeyChange(mop);
412 
413   mop->cohnum = 0;
414 
415   return mop;
416 }
417 
418 static void
419 MPPETermInput(void *v)
420 {
421   log_Printf(LogCCP, "MPPE: TermInput\n");
422   free(v);
423 }
424 
425 static void
426 MPPETermOutput(void *v)
427 {
428   log_Printf(LogCCP, "MPPE: TermOutput\n");
429   free(v);
430 }
431 
432 const struct ccp_algorithm MPPEAlgorithm = {
433   TY_MPPE,
434   CCP_NEG_MPPE,
435   MPPEDispOpts,
436   MPPEUsable,
437   {
438     MPPESetOptsInput,
439     MPPEInitInput,
440     MPPETermInput,
441     MPPEResetInput,
442     MPPEInput,
443     MPPEDictSetup
444   },
445   {
446     MPPEInitOptsOutput,
447     MPPESetOptsOutput,
448     MPPEInitOutput,
449     MPPETermOutput,
450     MPPEResetOutput,
451     MPPEOutput
452   },
453 };
454