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