?? eap.c
字號:
/* * eap.c - Extensible Authentication Protocol for PPP (RFC 2284) * * Copyright (c) 2001 by Sun Microsystems, Inc. * All rights reserved. * * Non-exclusive rights to redistribute, modify, translate, and use * this software in source and binary forms, in whole or in part, is * hereby granted, provided that the above copyright notice is * duplicated in any source form, and that neither the name of the * copyright holder nor the author is used to endorse or promote * products derived from this software. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Original version by James Carlson * * This implementation of EAP supports MD5-Challenge and SRP-SHA1 * authentication styles. Note that support of MD5-Challenge is a * requirement of RFC 2284, and that it's essentially just a * reimplementation of regular RFC 1994 CHAP using EAP messages. * * As an authenticator ("server"), there are multiple phases for each * style. In the first phase of each style, the unauthenticated peer * name is queried using the EAP Identity request type. If the * "remotename" option is used, then this phase is skipped, because * the peer's name is presumed to be known. * * For MD5-Challenge, there are two phases, and the second phase * consists of sending the challenge itself and handling the * associated response. * * For SRP-SHA1, there are four phases. The second sends 's', 'N', * and 'g'. The reply contains 'A'. The third sends 'B', and the * reply contains 'M1'. The forth sends the 'M2' value. * * As an authenticatee ("client"), there's just a single phase -- * responding to the queries generated by the peer. EAP is an * authenticator-driven protocol. * * Based on draft-ietf-pppext-eap-srp-03.txt. */#define RCSID "$Id: eap.c,v 1.4 2004/11/09 22:39:25 paulus Exp $"/* * TODO: */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pwd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <assert.h>#include <errno.h>#include "pppd.h"#include "pathnames.h"#include "md5.h"#include "eap.h"#ifdef USE_SRP#include <t_pwd.h>#include <t_server.h>#include <t_client.h>#include "pppcrypt.h"#endif /* USE_SRP */#ifndef SHA_DIGESTSIZE#define SHA_DIGESTSIZE 20#endifstatic const char rcsid[] = RCSID;eap_state eap_states[NUM_PPP]; /* EAP state; one for each unit */#ifdef USE_SRPstatic char *pn_secret = NULL; /* Pseudonym generating secret */#endif/* * Command-line options. */static option_t eap_option_list[] = { { "eap-restart", o_int, &eap_states[0].es_server.ea_timeout, "Set retransmit timeout for EAP Requests (server)" }, { "eap-max-sreq", o_int, &eap_states[0].es_server.ea_maxrequests, "Set max number of EAP Requests sent (server)" }, { "eap-timeout", o_int, &eap_states[0].es_client.ea_timeout, "Set time limit for peer EAP authentication" }, { "eap-max-rreq", o_int, &eap_states[0].es_client.ea_maxrequests, "Set max number of EAP Requests allows (client)" }, { "eap-interval", o_int, &eap_states[0].es_rechallenge, "Set interval for EAP rechallenge" },#ifdef USE_SRP { "srp-interval", o_int, &eap_states[0].es_lwrechallenge, "Set interval for SRP lightweight rechallenge" }, { "srp-pn-secret", o_string, &pn_secret, "Long term pseudonym generation secret" }, { "srp-use-pseudonym", o_bool, &eap_states[0].es_usepseudo, "Use pseudonym if offered one by server", 1 },#endif { NULL }};/* * Protocol entry points. */static void eap_init __P((int unit));static void eap_input __P((int unit, u_char *inp, int inlen));static void eap_protrej __P((int unit));static void eap_lowerup __P((int unit));static void eap_lowerdown __P((int unit));static int eap_printpkt __P((u_char *inp, int inlen, void (*)(void *arg, char *fmt, ...), void *arg));struct protent eap_protent = { PPP_EAP, /* protocol number */ eap_init, /* initialization procedure */ eap_input, /* process a received packet */ eap_protrej, /* process a received protocol-reject */ eap_lowerup, /* lower layer has gone up */ eap_lowerdown, /* lower layer has gone down */ NULL, /* open the protocol */ NULL, /* close the protocol */ eap_printpkt, /* print a packet in readable form */ NULL, /* process a received data packet */ 1, /* protocol enabled */ "EAP", /* text name of protocol */ NULL, /* text name of corresponding data protocol */ eap_option_list, /* list of command-line options */ NULL, /* check requested options; assign defaults */ NULL, /* configure interface for demand-dial */ NULL /* say whether to bring up link for this pkt */};/* * A well-known 2048 bit modulus. */static const u_char wkmodulus[] = { 0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B, 0xF1, 0x66, 0xDE, 0x5E, 0x13, 0x89, 0x58, 0x2F, 0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07, 0xFC, 0x31, 0x92, 0x94, 0x3D, 0xB5, 0x60, 0x50, 0xA3, 0x73, 0x29, 0xCB, 0xB4, 0xA0, 0x99, 0xED, 0x81, 0x93, 0xE0, 0x75, 0x77, 0x67, 0xA1, 0x3D, 0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D, 0xCD, 0x7F, 0x48, 0xA9, 0xDA, 0x04, 0xFD, 0x50, 0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0, 0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3, 0x66, 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8, 0x29, 0x18, 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8, 0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA, 0xA8, 0x0D, 0x74, 0x0A, 0xDB, 0xF4, 0xFF, 0x74, 0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7, 0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14, 0x77, 0x3B, 0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80, 0x16, 0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81, 0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A, 0x5B, 0x9D, 0x32, 0xE6, 0x88, 0xF8, 0x77, 0x48, 0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D, 0x5E, 0xA7, 0x7A, 0x27, 0x75, 0xD2, 0xEC, 0xFA, 0x03, 0x2C, 0xFB, 0xDB, 0xF5, 0x2F, 0xB3, 0x78, 0x61, 0x60, 0x27, 0x90, 0x04, 0xE5, 0x7A, 0xE6, 0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29, 0x9C, 0xCC, 0x04, 0x1C, 0x7B, 0xC3, 0x08, 0xD8, 0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82, 0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6, 0x94, 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4, 0x35, 0xDE, 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75, 0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2, 0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73};/* Local forward declarations. */static void eap_server_timeout __P((void *arg));/* * Convert EAP state code to printable string for debug. */static const char *eap_state_name(esc)enum eap_state_code esc;{ static const char *state_names[] = { EAP_STATES }; return (state_names[(int)esc]);}/* * eap_init - Initialize state for an EAP user. This is currently * called once by main() during start-up. */static voideap_init(unit)int unit;{ eap_state *esp = &eap_states[unit]; BZERO(esp, sizeof (*esp)); esp->es_unit = unit; esp->es_server.ea_timeout = EAP_DEFTIMEOUT; esp->es_server.ea_maxrequests = EAP_DEFTRANSMITS; esp->es_server.ea_id = (u_char)(drand48() * 0x100); esp->es_client.ea_timeout = EAP_DEFREQTIME; esp->es_client.ea_maxrequests = EAP_DEFALLOWREQ;}/* * eap_client_timeout - Give up waiting for the peer to send any * Request messages. */static voideap_client_timeout(arg)void *arg;{ eap_state *esp = (eap_state *) arg; if (!eap_client_active(esp)) return; error("EAP: timeout waiting for Request from peer"); auth_withpeer_fail(esp->es_unit, PPP_EAP); esp->es_client.ea_state = eapBadAuth;}/* * eap_authwithpeer - Authenticate to our peer (behave as client). * * Start client state and wait for requests. This is called only * after eap_lowerup. */voideap_authwithpeer(unit, localname)int unit;char *localname;{ eap_state *esp = &eap_states[unit]; /* Save the peer name we're given */ esp->es_client.ea_name = localname; esp->es_client.ea_namelen = strlen(localname); esp->es_client.ea_state = eapListen; /* * Start a timer so that if the other end just goes * silent, we don't sit here waiting forever. */ if (esp->es_client.ea_timeout > 0) TIMEOUT(eap_client_timeout, (void *)esp, esp->es_client.ea_timeout);}/* * Format a standard EAP Failure message and send it to the peer. * (Server operation) */static voideap_send_failure(esp)eap_state *esp;{ u_char *outp; outp = outpacket_buf; MAKEHEADER(outp, PPP_EAP); PUTCHAR(EAP_FAILURE, outp); esp->es_server.ea_id++; PUTCHAR(esp->es_server.ea_id, outp); PUTSHORT(EAP_HEADERLEN, outp); output(esp->es_unit, outpacket_buf, EAP_HEADERLEN + PPP_HDRLEN); esp->es_server.ea_state = eapBadAuth; auth_peer_fail(esp->es_unit, PPP_EAP);}/* * Format a standard EAP Success message and send it to the peer. * (Server operation) */static voideap_send_success(esp)eap_state *esp;{ u_char *outp; outp = outpacket_buf; MAKEHEADER(outp, PPP_EAP); PUTCHAR(EAP_SUCCESS, outp); esp->es_server.ea_id++; PUTCHAR(esp->es_server.ea_id, outp); PUTSHORT(EAP_HEADERLEN, outp); output(esp->es_unit, outpacket_buf, PPP_HDRLEN + EAP_HEADERLEN); auth_peer_success(esp->es_unit, PPP_EAP, 0, esp->es_server.ea_peer, esp->es_server.ea_peerlen);}#ifdef USE_SRP/* * Set DES key according to pseudonym-generating secret and current * date. */static boolpncrypt_setkey(int timeoffs){ struct tm *tp; char tbuf[9]; SHA1_CTX ctxt; u_char dig[SHA_DIGESTSIZE]; time_t reftime; if (pn_secret == NULL) return (0); reftime = time(NULL) + timeoffs; tp = localtime(&reftime); SHA1Init(&ctxt); SHA1Update(&ctxt, pn_secret, strlen(pn_secret)); strftime(tbuf, sizeof (tbuf), "%Y%m%d", tp); SHA1Update(&ctxt, tbuf, strlen(tbuf)); SHA1Final(dig, &ctxt); return (DesSetkey(dig));}static char base64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";struct b64state { u_int32_t bs_bits; int bs_offs;};static intb64enc(bs, inp, inlen, outp)struct b64state *bs;u_char *inp;int inlen;u_char *outp;{ int outlen = 0; while (inlen > 0) { bs->bs_bits = (bs->bs_bits << 8) | *inp++; inlen--; bs->bs_offs += 8; if (bs->bs_offs >= 24) { *outp++ = base64[(bs->bs_bits >> 18) & 0x3F]; *outp++ = base64[(bs->bs_bits >> 12) & 0x3F]; *outp++ = base64[(bs->bs_bits >> 6) & 0x3F]; *outp++ = base64[bs->bs_bits & 0x3F]; outlen += 4; bs->bs_offs = 0; bs->bs_bits = 0; } } return (outlen);}static intb64flush(bs, outp)struct b64state *bs;u_char *outp;{ int outlen = 0; if (bs->bs_offs == 8) { *outp++ = base64[(bs->bs_bits >> 2) & 0x3F]; *outp++ = base64[(bs->bs_bits << 4) & 0x3F]; outlen = 2; } else if (bs->bs_offs == 16) { *outp++ = base64[(bs->bs_bits >> 10) & 0x3F]; *outp++ = base64[(bs->bs_bits >> 4) & 0x3F]; *outp++ = base64[(bs->bs_bits << 2) & 0x3F]; outlen = 3; } bs->bs_offs = 0; bs->bs_bits = 0; return (outlen);}static intb64dec(bs, inp, inlen, outp)struct b64state *bs;u_char *inp;int inlen;u_char *outp;{ int outlen = 0; char *cp; while (inlen > 0) { if ((cp = strchr(base64, *inp++)) == NULL) break; bs->bs_bits = (bs->bs_bits << 6) | (cp - base64); inlen--; bs->bs_offs += 6; if (bs->bs_offs >= 8) { *outp++ = bs->bs_bits >> (bs->bs_offs - 8); outlen++; bs->bs_offs -= 8; } } return (outlen);}#endif /* USE_SRP *//* * Assume that current waiting server state is complete and figure * next state to use based on available authentication data. 'status' * indicates if there was an error in handling the last query. It is * 0 for success and non-zero for failure. */static voideap_figure_next_state(esp, status)eap_state *esp;int status;{#ifdef USE_SRP unsigned char secbuf[MAXWORDLEN], clear[8], *sp, *dp; struct t_pw tpw; struct t_confent *tce, mytce; char *cp, *cp2; struct t_server *ts; int id, i, plen, toffs; u_char vals[2]; struct b64state bs;#endif /* USE_SRP */ esp->es_server.ea_timeout = esp->es_savedtime; switch (esp->es_server.ea_state) { case eapBadAuth: return; case eapIdentify:#ifdef USE_SRP /* Discard any previous session. */ ts = (struct t_server *)esp->es_server.ea_session; if (ts != NULL) { t_serverclose(ts); esp->es_server.ea_session = NULL; esp->es_server.ea_skey = NULL; }#endif /* USE_SRP */ if (status != 0) { esp->es_server.ea_state = eapBadAuth; break; }#ifdef USE_SRP /* If we've got a pseudonym, try to decode to real name. */ if (esp->es_server.ea_peerlen > SRP_PSEUDO_LEN && strncmp(esp->es_server.ea_peer, SRP_PSEUDO_ID, SRP_PSEUDO_LEN) == 0 && (esp->es_server.ea_peerlen - SRP_PSEUDO_LEN) * 3 / 4 < sizeof (secbuf)) { BZERO(&bs, sizeof (bs)); plen = b64dec(&bs, esp->es_server.ea_peer + SRP_PSEUDO_LEN, esp->es_server.ea_peerlen - SRP_PSEUDO_LEN, secbuf); toffs = 0; for (i = 0; i < 5; i++) { pncrypt_setkey(toffs); toffs -= 86400; if (!DesDecrypt(secbuf, clear)) { dbglog("no DES here; cannot decode " "pseudonym"); return; } id = *(unsigned char *)clear; if (id + 1 <= plen && id + 9 > plen) break; } if (plen % 8 == 0 && i < 5) { /* * Note that this is always shorter than the * original stored string, so there's no need * to realloc. */ if ((i = plen = *(unsigned char *)clear) > 7) i = 7; esp->es_server.ea_peerlen = plen; dp = (unsigned char *)esp->es_server.ea_peer; BCOPY(clear + 1, dp, i); plen -= i; dp += i; sp = secbuf + 8; while (plen > 0) { (void) DesDecrypt(sp, dp); sp += 8; dp += 8; plen -= 8; } esp->es_server.ea_peer[ esp->es_server.ea_peerlen] = '\0'; dbglog("decoded pseudonym to \"%.*q\"", esp->es_server.ea_peerlen, esp->es_server.ea_peer); } else { dbglog("failed to decode real name"); /* Stay in eapIdentfy state; requery */ break; } } /* Look up user in secrets database. */ if (get_srp_secret(esp->es_unit, esp->es_server.ea_peer, esp->es_server.ea_name, (char *)secbuf, 1) != 0) { /* Set up default in case SRP entry is bad */ esp->es_server.ea_state = eapMD5Chall; /* Get t_confent based on index in srp-secrets */ id = strtol((char *)secbuf, &cp, 10); if (*cp++ != ':' || id < 0) break; if (id == 0) { mytce.index = 0; mytce.modulus.data = (u_char *)wkmodulus; mytce.modulus.len = sizeof (wkmodulus); mytce.generator.data = (u_char *)"\002"; mytce.generator.len = 1; tce = &mytce; } else if ((tce = gettcid(id)) != NULL) { /* * Client will have to verify this modulus/ * generator combination, and that will take * a while. Lengthen the timeout here. */ if (esp->es_server.ea_timeout > 0 && esp->es_server.ea_timeout < 30) esp->es_server.ea_timeout = 30; } else { break; } if ((cp2 = strchr(cp, ':')) == NULL) break; *cp2++ = '\0'; tpw.pebuf.name = esp->es_server.ea_peer; tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf, cp); tpw.pebuf.password.data = tpw.pwbuf; tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf, cp2); tpw.pebuf.salt.data = tpw.saltbuf; if ((ts = t_serveropenraw(&tpw.pebuf, tce)) == NULL) break; esp->es_server.ea_session = (void *)ts; esp->es_server.ea_state = eapSRP1; vals[0] = esp->es_server.ea_id + 1; vals[1] = EAPT_SRP; t_serveraddexdata(ts, vals, 2); /* Generate B; must call before t_servergetkey() */ t_servergenexp(ts); break; }#endif /* USE_SRP */ esp->es_server.ea_state = eapMD5Chall; break; case eapSRP1:#ifdef USE_SRP ts = (struct t_server *)esp->es_server.ea_session; if (ts != NULL && status != 0) { t_serverclose(ts); esp->es_server.ea_session = NULL; esp->es_server.ea_skey = NULL; }#endif /* USE_SRP */ if (status == 1) { esp->es_server.ea_state = eapMD5Chall; } else if (status != 0 || esp->es_server.ea_session == NULL) { esp->es_server.ea_state = eapBadAuth; } else { esp->es_server.ea_state = eapSRP2; } break; case eapSRP2:#ifdef USE_SRP ts = (struct t_server *)esp->es_server.ea_session; if (ts != NULL && status != 0) { t_serverclose(ts); esp->es_server.ea_session = NULL; esp->es_server.ea_skey = NULL; }#endif /* USE_SRP */ if (status != 0 || esp->es_server.ea_session == NULL) { esp->es_server.ea_state = eapBadAuth; } else { esp->es_server.ea_state = eapSRP3; } break; case eapSRP3: case eapSRP4:#ifdef USE_SRP ts = (struct t_server *)esp->es_server.ea_session; if (ts != NULL && status != 0) { t_serverclose(ts); esp->es_server.ea_session = NULL;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -