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