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