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