diff options
Diffstat (limited to 'programs')
-rw-r--r-- | programs/pluto/Makefile | 18 | ||||
-rw-r--r-- | programs/pluto/connections.c | 41 | ||||
-rw-r--r-- | programs/pluto/constants.c | 91 | ||||
-rw-r--r-- | programs/pluto/constants.h | 90 | ||||
-rw-r--r-- | programs/pluto/defs.h | 4 | ||||
-rw-r--r-- | programs/pluto/demux.c | 168 | ||||
-rw-r--r-- | programs/pluto/demux.h | 4 | ||||
-rw-r--r-- | programs/pluto/ike_alg.c | 33 | ||||
-rw-r--r-- | programs/pluto/ipsec_doi.c | 137 | ||||
-rw-r--r-- | programs/pluto/keys.c | 162 | ||||
-rw-r--r-- | programs/pluto/keys.h | 10 | ||||
-rw-r--r-- | programs/pluto/modecfg.c | 509 | ||||
-rw-r--r-- | programs/pluto/modecfg.h | 31 | ||||
-rw-r--r-- | programs/pluto/plutomain.c | 5 | ||||
-rw-r--r-- | programs/pluto/spdb.c | 299 | ||||
-rw-r--r-- | programs/pluto/spdb.h | 13 | ||||
-rw-r--r-- | programs/pluto/state.h | 10 | ||||
-rw-r--r-- | programs/pluto/vendor.c | 18 | ||||
-rw-r--r-- | programs/pluto/vendor.h | 78 | ||||
-rw-r--r-- | programs/pluto/xauth.c | 77 | ||||
-rw-r--r-- | programs/pluto/xauth.h | 41 | ||||
-rw-r--r-- | programs/starter/args.c | 3 | ||||
-rw-r--r-- | programs/starter/confread.c | 13 | ||||
-rw-r--r-- | programs/starter/keywords.c | 14 | ||||
-rw-r--r-- | programs/starter/keywords.h | 5 | ||||
-rw-r--r-- | programs/starter/keywords.txt | 3 |
26 files changed, 1376 insertions, 501 deletions
diff --git a/programs/pluto/Makefile b/programs/pluto/Makefile index 908060038..a11a755c0 100644 --- a/programs/pluto/Makefile +++ b/programs/pluto/Makefile @@ -12,7 +12,7 @@ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # -# RCSID $Id: Makefile,v 1.45 2006/07/06 12:33:08 as Exp $ +# RCSID $Id: Makefile,v 1.47 2007/01/11 21:47:13 as Exp $ # relative path to top directory of FreeS/WAN source # Note: referenced in ${FREESWANSRCDIR}/Makefile.inc @@ -137,8 +137,8 @@ ifeq ($(USE_VENDORID),true) DEFINES+= -DVENDORID endif -ifeq ($(USE_XAUTH_VID),true) - DEFINES+= -DXAUTH_VID +ifeq ($(USE_CISCO_QUIRKS),true) + DEFINES+= -DCISCO_QUIRKS endif # This compile option activates dynamic URL fetching using libcurl @@ -262,6 +262,7 @@ DISTSRC = \ spdb.c spdb.h \ state.c state.h \ timer.c timer.h \ + xauth.c xauth.h \ x509.c x509.h \ $(DISTGCRYPT) \ vendor.c nat_traversal.c virtual.c \ @@ -280,7 +281,7 @@ OBJSPLUTO = asn1.o connections.o constants.o cookie.o crypto.o defs.o fetch.o fo ca.o certs.o id.o ipsec_doi.o kernel.o $(KERNEL26_OBJS) kernel_pfkey.o mp_defs.o \ kernel_noklips.o rcv_whack.o ${IPSECPOLICY_OBJS} demux.o packet.o lex.o keys.o \ dnskey.o smartcard.o ac.o rnd.o spdb.o sha1.o md5.o md2.o modecfg.o ocsp.o crl.o \ - vendor.o nat_traversal.o virtual.o + vendor.o nat_traversal.o virtual.o xauth.o OBJSADNS = adns.o @@ -477,6 +478,7 @@ vendor.o: vendor.c virtual.o: virtual.c whack.o: whack.c x509.o: x509.c +xauth.o: xauth.c ac.o: constants.h ac.o: defs.h @@ -794,7 +796,7 @@ keys.o: log.h keys.o: whack.h keys.o: timer.h keys.o: fetch.h -keys.o: nat_traversal.h +keys.o: xauth.h lex.o: constants.h lex.o: defs.h lex.o: log.h @@ -823,6 +825,7 @@ modecfg.o: sha1.h modecfg.o: crypto.h modecfg.o: modecfg.h modecfg.o: whack.h +modecfg.o: xauth.h mp_defs.o: constants.h mp_defs.o: defs.h mp_defs.o: mp_defs.h @@ -1088,3 +1091,8 @@ x509.o: whack.h x509.o: fetch.h x509.o: ocsp.h x509.o: sha1.h +xauth.o: constants.h +xauth.o: defs.h +xauth.o: xauth.h +xauth.o: keys.h +xauth.o: log.h diff --git a/programs/pluto/connections.c b/programs/pluto/connections.c index 1ea6ac5fa..93b3bd2b6 100644 --- a/programs/pluto/connections.c +++ b/programs/pluto/connections.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: connections.c,v 1.46 2006/10/19 15:40:52 as Exp $ + * RCSID $Id: connections.c,v 1.47 2007/01/10 00:36:19 as Exp $ */ #include <string.h> @@ -3254,13 +3254,17 @@ find_host_connection(const ip_address *me, u_int16_t my_port if (policy != LEMPTY) { + lset_t auth_requested = policy & POLICY_ID_AUTH_MASK; + /* if we have requirements for the policy, * choose the first matching connection. */ while (c != NULL) { - if ((c->policy & policy) == policy) - break; + if (c->policy & auth_requested) + { + break; + } c = c->hp_next; } } @@ -3367,11 +3371,20 @@ refine_host_connection(const struct state *st, const struct id *peer_id if (psk == NULL) return NULL; /* cannot determine PSK! */ break; - + case XAUTHInitPreShared: + case XAUTHRespPreShared: + auth_policy = POLICY_XAUTH_PSK; + psk = get_preshared_secret(c); + if (psk == NULL) + return NULL; /* cannot determine PSK! */ + break; case OAKLEY_RSA_SIG: auth_policy = POLICY_RSASIG; break; - + case XAUTHInitRSA: + case XAUTHRespRSA: + auth_policy = POLICY_XAUTH_RSASIG; + break; default: bad_case(auth); } @@ -3394,17 +3407,21 @@ refine_host_connection(const struct state *st, const struct id *peer_id bool matching_id = match_id(peer_id , &d->spd.that.id, &wildcards); + bool matching_auth = (d->policy & auth_policy) != LEMPTY; + bool matching_trust = trusted_ca(peer_ca , d->spd.that.ca, &peer_pathlen); bool matching_request = match_requested_ca(c->requested_ca , d->spd.this.ca, &our_pathlen); - bool match = matching_id && matching_trust && matching_request; - + bool match = matching_id && matching_auth && + matching_trust && matching_request; + DBG(DBG_CONTROLMORE, - DBG_log("%s: %s match (id: %s, trust: %s, request: %s)" + DBG_log("%s: %s match (id: %s, auth: %s, trust: %s, request: %s)" , d->name , match ? "full":" no" , match_name[matching_id] + , match_name[matching_auth] , match_name[matching_trust] , match_name[matching_request]) ) @@ -3423,13 +3440,11 @@ refine_host_connection(const struct state *st, const struct id *peer_id continue; #endif - /* authentication used must fit policy of this connection */ - if ((d->policy & auth_policy) == LEMPTY) - continue; /* our auth isn't OK for this connection */ - switch (auth) { case OAKLEY_PRESHARED_KEY: + case XAUTHInitPreShared: + case XAUTHRespPreShared: /* secret must match the one we already used */ { const chunk_t *dpsk = get_preshared_secret(d); @@ -3445,6 +3460,8 @@ refine_host_connection(const struct state *st, const struct id *peer_id break; case OAKLEY_RSA_SIG: + case XAUTHInitRSA: + case XAUTHRespRSA: /* * We must at least be able to find our private key .*/ diff --git a/programs/pluto/constants.c b/programs/pluto/constants.c index 5ca7b65ce..f4aa9d5d1 100644 --- a/programs/pluto/constants.c +++ b/programs/pluto/constants.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: constants.c,v 1.22 2006/10/19 21:07:40 as Exp $ + * RCSID $Id: constants.c,v 1.23 2007/01/10 00:36:19 as Exp $ */ /* @@ -54,8 +54,8 @@ const char compile_time_interop_options[] = "" #ifdef VENDORID " VENDORID" #endif -#ifdef XAUTH_VID - " XAUTH_VID" +#ifdef CISCO_QUIRKS + " CISCO_QUIRKS" #endif #ifdef USE_KEYRR " KEYRR" @@ -183,12 +183,22 @@ static const char *const state_name[] = { "STATE_INFO", "STATE_INFO_PROTECTED", + "STATE_XAUTH_I0", + "STATE_XAUTH_R1", + "STATE_XAUTH_I1", + "STATE_XAUTH_R2", + "STATE_XAUTH_I2", + "STATE_XAUTH_R3", + "STATE_MODE_CFG_R0", - "STATE_MODE_CFG_R1", - "STATE_MODE_CFG_R2", "STATE_MODE_CFG_I1", + "STATE_MODE_CFG_R1", "STATE_MODE_CFG_I2", + + "STATE_MODE_CFG_I0", + "STATE_MODE_CFG_R3", "STATE_MODE_CFG_I3", + "STATE_MODE_CFG_R4", "STATE_IKE_ROOF" }; @@ -216,13 +226,23 @@ const char *const state_story[] = { "got Informational Message in clear", /* STATE_INFO */ "got encrypted Informational Message", /* STATE_INFO_PROTECTED */ - - "sent ModeCfg reply", /* STATE_MODE_CFG_R0 */ - "sent ModeCfg reply", /* STATE_MODE_CFG_R1 */ - "received ModeCfg ack", /* STATE_MODE_CFG_R2 */ + + "expecting XAUTH request", /* STATE_XAUTH_I0 */ + "sent XAUTH request, expecting reply", /* STATE_XAUTH_R1 */ + "sent XAUTH reply, expecting status", /* STATE_XAUTH_I1 */ + "sent XAUTH status, expecting ack", /* STATE_XAUTH_R2 */ + "sent XAUTH ack, established", /* STATE_XAUTH_I2 */ + "received XAUTH ack, established", /* STATE_XAUTH_R3 */ + + "expecting ModeCfg request", /* STATE_MODE_CFG_R0 */ "sent ModeCfg request, expecting reply", /* STATE_MODE_CFG_I1 */ - "received ModeCfg reply", /* STATE_MODE_CFG_I2 */ - "received ModeCfg set, sent ack", /* STATE_MODE_CFG_I3 */ + "sent ModeCfg reply, established", /* STATE_MODE_CFG_R1 */ + "received ModeCfg reply, established", /* STATE_MODE_CFG_I2 */ + + "expecting ModeCfg set", /* STATE_MODE_CFG_I0 */ + "sent ModeCfg set, expecting ack", /* STATE_MODE_CFG_R3 */ + "sent ModeCfg ack, established", /* STATE_MODE_CFG_I3 */ + "received ModeCfg ack, established", /* STATE_MODE_CFG_R4 */ }; /* kind of struct connection */ @@ -487,6 +507,9 @@ const char *const sa_policy_bit_names[] = { "GROUTED", "UP", "MODECFGPUSH", + "XAUTHPSK", + "XAUTHRSASIG", + "XAUTHSERVER", NULL }; @@ -675,7 +698,49 @@ enum_names auth_alg_names = { AUTH_ALGORITHM_HMAC_MD5, AUTH_ALGORITHM_HMAC_RIPEMD, auth_alg_name , &extended_auth_alg_names }; -const char *const modecfg_attr_name[] = { +/* From draft-beaulieu-ike-xauth */ +static const char *const xauth_type_name[] = { + "Generic", + "RADIUS-CHAP", + "OTP", + "S/KEY", +}; + +enum_names xauth_type_names = + { XAUTH_TYPE_GENERIC, XAUTH_TYPE_SKEY, xauth_type_name, NULL}; + +/* From draft-beaulieu-ike-xauth */ +static const char *const xauth_attr_tv_name[] = { + "XAUTH_TYPE", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "XAUTH_STATUS", + }; + +enum_names xauth_attr_tv_names = { + XAUTH_TYPE + ISAKMP_ATTR_AF_TV, + XAUTH_STATUS + ISAKMP_ATTR_AF_TV, xauth_attr_tv_name, NULL }; + +static const char *const xauth_attr_name[] = { + "XAUTH_USER_NAME", + "XAUTH_USER_PASSWORD", + "XAUTH_PASSCODE", + "XAUTH_MESSAGE", + "XAUTH_CHALLENGE", + "XAUTH_DOMAIN", + "XAUTH_STATUS (wrong TLV syntax, should be TV)", + "XAUTH_NEXT_PIN", + "XAUTH_ANSWER", + }; + +enum_names xauth_attr_names = + { XAUTH_USER_NAME , XAUTH_ANSWER, xauth_attr_name , &xauth_attr_tv_names }; + +static const char *const modecfg_attr_name[] = { "INTERNAL_IP4_ADDRESS", "INTERNAL_IP4_NETMASK", "INTERNAL_IP4_DNS", @@ -695,7 +760,7 @@ const char *const modecfg_attr_name[] = { }; enum_names modecfg_attr_names = - { INTERNAL_IP4_ADDRESS , INTERNAL_IP6_SUBNET, modecfg_attr_name , NULL }; + { INTERNAL_IP4_ADDRESS, INTERNAL_IP6_SUBNET, modecfg_attr_name , &xauth_attr_names }; /* Oakley Lifetime Type attribute */ diff --git a/programs/pluto/constants.h b/programs/pluto/constants.h index bad162898..f18e93fed 100644 --- a/programs/pluto/constants.h +++ b/programs/pluto/constants.h @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: constants.h,v 1.22 2006/10/19 21:07:40 as Exp $ + * RCSID $Id: constants.h,v 1.23 2007/01/10 00:36:19 as Exp $ */ #ifndef _CONSTANTS_H @@ -504,13 +504,28 @@ enum state_kind { STATE_INFO, STATE_INFO_PROTECTED, - STATE_MODE_CFG_R0, /* these states are used on the responder */ - STATE_MODE_CFG_R1, - STATE_MODE_CFG_R2, + /* XAUTH states */ + + STATE_XAUTH_I0, /* initiator state (client) */ + STATE_XAUTH_R1, /* responder state (server) */ + STATE_XAUTH_I1, + STATE_XAUTH_R2, + STATE_XAUTH_I2, + STATE_XAUTH_R3, + + /* Mode Config pull states */ - STATE_MODE_CFG_I1, /* this is used on the initiator */ + STATE_MODE_CFG_R0, /* responder state (server) */ + STATE_MODE_CFG_I1, /* initiator state (client) */ + STATE_MODE_CFG_R1, STATE_MODE_CFG_I2, + + /* Mode Config push states */ + + STATE_MODE_CFG_I0, /* initiator state (client) */ + STATE_MODE_CFG_R3, /* responder state (server) */ STATE_MODE_CFG_I3, + STATE_MODE_CFG_R4, STATE_IKE_ROOF }; @@ -519,22 +534,30 @@ enum state_kind { #define PHASE1_INITIATOR_STATES (LELEM(STATE_MAIN_I1) | LELEM(STATE_MAIN_I2) \ | LELEM(STATE_MAIN_I3) | LELEM(STATE_MAIN_I4)) -#define ISAKMP_SA_ESTABLISHED_STATES (LELEM(STATE_MAIN_R3) | LELEM(STATE_MAIN_I4) \ - | LELEM(STATE_MODE_CFG_R1) | LELEM(STATE_MODE_CFG_R2) \ - | LELEM(STATE_MODE_CFG_I2) | LELEM(STATE_MODE_CFG_I3)) +#define ISAKMP_SA_ESTABLISHED_STATES ( \ + LELEM(STATE_MAIN_R3) | LELEM(STATE_MAIN_I4) \ + | LELEM(STATE_XAUTH_R1) | LELEM(STATE_XAUTH_R2) | LELEM(STATE_XAUTH_R3) \ + | LELEM(STATE_XAUTH_I1) | LELEM(STATE_XAUTH_I2) \ + | LELEM(STATE_MODE_CFG_I1) | LELEM(STATE_MODE_CFG_R1) | LELEM(STATE_MODE_CFG_I2) \ + | LELEM(STATE_MODE_CFG_R3) | LELEM(STATE_MODE_CFG_I3) | LELEM(STATE_MODE_CFG_R4)) #define IS_PHASE1(s) ((STATE_MAIN_R0 <= (s) && (s) <= STATE_MAIN_I4) \ - || (STATE_MODE_CFG_R0 <= (s) && (s) <= STATE_MODE_CFG_I3)) + || (STATE_XAUTH_I0 <= (s) && (s) <= STATE_XAUTH_R3) \ + || (STATE_MODE_CFG_R0 <= (s) && (s) <= STATE_MODE_CFG_R4)) + #define IS_QUICK(s) (STATE_QUICK_R0 <= (s) && (s) <= STATE_QUICK_R2) #define IS_ISAKMP_ENCRYPTED(s) (STATE_MAIN_I2 <= (s)) -#define IS_ISAKMP_SA_ESTABLISHED(s) ( \ - (s) == STATE_MAIN_R3 \ - || (s) == STATE_MAIN_I4 \ - || (s) == STATE_MODE_CFG_R0 \ - || (s) == STATE_MODE_CFG_R1 \ - || (s) == STATE_MODE_CFG_R2 \ - || (s) == STATE_MODE_CFG_I2 \ - || (s) == STATE_MODE_CFG_I3) + +#define IS_ISAKMP_SA_ESTABLISHED(s) ( \ + (s) == STATE_MAIN_R3 \ + || (s) == STATE_MAIN_I4 \ + || (s) == STATE_XAUTH_R3 \ + || (s) == STATE_XAUTH_I2 \ + || (s) == STATE_MODE_CFG_R1 \ + || (s) == STATE_MODE_CFG_I2 \ + || (s) == STATE_MODE_CFG_I3 \ + || (s) == STATE_MODE_CFG_R4) + #define IS_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_I2 || (s) == STATE_QUICK_R2) #define IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_R1) @@ -638,7 +661,32 @@ extern enum_names attr_msg_type_names; #define SUPPORTED_ATTRIBUTES 14 #define INTERNAL_IP6_SUBNET 15 +#define MODECFG_ROOF 16 + extern enum_names modecfg_attr_names; +/* XAUTH attribute values */ +#define XAUTH_TYPE 16520 +#define XAUTH_USER_NAME 16521 +#define XAUTH_USER_PASSWORD 16522 +#define XAUTH_PASSCODE 16523 +#define XAUTH_MESSAGE 16524 +#define XAUTH_CHALLENGE 16525 +#define XAUTH_DOMAIN 16526 +#define XAUTH_STATUS 16527 +#define XAUTH_NEXT_PIN 16528 +#define XAUTH_ANSWER 16529 + +#define XAUTH_BASE XAUTH_TYPE + +extern enum_names xauth_attr_names; + +/* XAUTH authentication types */ +#define XAUTH_TYPE_GENERIC 0 +#define XAUTH_TYPE_CHAP 1 +#define XAUTH_TYPE_OTP 2 +#define XAUTH_TYPE_SKEY 3 + +extern enum_names xauth_type_names; /* Exchange types * RFC2408 "Internet Security Association and Key Management Protocol (ISAKMP)" @@ -752,7 +800,7 @@ extern const char *prettypolicy(lset_t policy); #define POLICY_RSASIG LELEM(1) #define POLICY_ISAKMP_SHIFT 0 /* log2(POLICY_PSK) */ -#define POLICY_ID_AUTH_MASK LRANGES(POLICY_PSK, POLICY_RSASIG) +#define POLICY_ID_AUTH_MASK (POLICY_PSK | POLICY_RSASIG | POLICY_XAUTH_PSK | POLICY_XAUTH_RSASIG) #define POLICY_ISAKMP_MASK POLICY_ID_AUTH_MASK /* all so far */ /* Quick Mode (IPSEC) attributes */ @@ -794,7 +842,9 @@ extern const char *prettypolicy(lset_t policy); #define POLICY_GROUTED LELEM(15) /* do we want this group routed? */ #define POLICY_UP LELEM(16) /* do we want this up? */ #define POLICY_MODECFG_PUSH LELEM(17) /* is modecfg pushed by server? */ - +#define POLICY_XAUTH_PSK LELEM(18) /* do we support XAUTH????PreShared? */ +#define POLICY_XAUTH_RSASIG LELEM(19) /* do we support XAUTH????RSA? */ +#define POLICY_XAUTH_SERVER LELEM(20) /* are we an XAUTH server? */ /* Any IPsec policy? If not, a connection description * is only for ISAKMP SA, not IPSEC SA. (A pun, I admit.) @@ -804,7 +854,7 @@ extern const char *prettypolicy(lset_t policy); #define HAS_IPSEC_POLICY(p) (((p) & POLICY_IPSEC_MASK) != 0) /* Don't allow negotiation? */ -#define NEVER_NEGOTIATE(p) (LDISJOINT((p), POLICY_PSK | POLICY_RSASIG)) +#define NEVER_NEGOTIATE(p) (LDISJOINT((p), POLICY_ID_AUTH_MASK)) /* Oakley transform attributes diff --git a/programs/pluto/defs.h b/programs/pluto/defs.h index 7e92ea540..3fe5053d1 100644 --- a/programs/pluto/defs.h +++ b/programs/pluto/defs.h @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: defs.h,v 1.10 2006/01/04 21:00:43 as Exp $ + * RCSID $Id: defs.h,v 1.11 2007/01/09 21:59:06 as Exp $ */ #ifndef _DEFS_H @@ -82,7 +82,7 @@ typedef struct chunk chunk_t; #define chunkcpy(dst, chunk) \ { memcpy(dst, chunk.ptr, chunk.len); dst += chunk.len;} #define same_chunk(a, b) \ - (a).len == (b).len && memcmp((a).ptr, (b).ptr, (b).len) == 0 + ( (a).len == (b).len && memcmp((a).ptr, (b).ptr, (b).len) == 0 ) extern char* temporary_cyclic_buffer(void); extern const char* concatenate_paths(const char *a, const char *b); diff --git a/programs/pluto/demux.c b/programs/pluto/demux.c index 3146b3d40..304d790e3 100644 --- a/programs/pluto/demux.c +++ b/programs/pluto/demux.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: demux.c,v 1.16 2006/10/19 21:07:40 as Exp $ + * RCSID $Id: demux.c,v 1.17 2007/01/10 00:36:19 as Exp $ */ /* Ordering Constraints on Payloads @@ -454,45 +454,81 @@ static const struct state_microcode state_microcode_table[] = { , P(HASH), LEMPTY, PT(NONE) , EVENT_NULL, informational }, - /* MODE_CFG_x: - * Case R0: Responder -> Initiator - * <- Req(addr=0) - * Reply(ad=x) -> - * - * Case R1: Set(addr=x) -> - * <- Ack(ok) - */ + /* XAUTH state transitions */ + { STATE_XAUTH_I0, STATE_XAUTH_I1 + , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY + , P(ATTR) | P(HASH), P(VID), PT(HASH) + , EVENT_RETRANSMIT, xauth_inI0 }, - { STATE_MODE_CFG_R0, STATE_MODE_CFG_R1 + { STATE_XAUTH_R1, STATE_XAUTH_R2 , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inR0 }, + , EVENT_RETRANSMIT, xauth_inR1 }, - { STATE_MODE_CFG_R1, STATE_MODE_CFG_R2 - , SMF_ALL_AUTH | SMF_ENCRYPTED + { STATE_XAUTH_I1, STATE_XAUTH_I2 + , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2 , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inR1 }, + , EVENT_SA_REPLACE, xauth_inI1 }, + + { STATE_XAUTH_R2, STATE_XAUTH_R3 + , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 + , P(ATTR) | P(HASH), P(VID), PT(NONE) + , EVENT_SA_REPLACE, xauth_inR2 }, + + { STATE_XAUTH_I2, STATE_UNDEFINED + , SMF_ALL_AUTH | SMF_ENCRYPTED + , LEMPTY, LEMPTY, PT(NONE) + , EVENT_NULL, unexpected }, - { STATE_MODE_CFG_R2, STATE_UNDEFINED + { STATE_XAUTH_R3, STATE_UNDEFINED , SMF_ALL_AUTH | SMF_ENCRYPTED , LEMPTY, LEMPTY, PT(NONE) , EVENT_NULL, unexpected }, + /* ModeCfg pull mode state transitions */ + + { STATE_MODE_CFG_R0, STATE_MODE_CFG_R1 + , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2 + , P(ATTR) | P(HASH), P(VID), PT(HASH) + , EVENT_SA_REPLACE, modecfg_inR0 }, + { STATE_MODE_CFG_I1, STATE_MODE_CFG_I2 , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 , P(ATTR) | P(HASH), P(VID), PT(HASH) , EVENT_SA_REPLACE, modecfg_inI1 }, - { STATE_MODE_CFG_I2, STATE_MODE_CFG_I3 + { STATE_MODE_CFG_R1, STATE_UNDEFINED + , SMF_ALL_AUTH | SMF_ENCRYPTED + , LEMPTY, LEMPTY, PT(NONE) + , EVENT_NULL, unexpected }, + + { STATE_MODE_CFG_I2, STATE_UNDEFINED + , SMF_ALL_AUTH | SMF_ENCRYPTED + , LEMPTY, LEMPTY, PT(NONE) + , EVENT_NULL, unexpected }, + + /* ModeCfg push mode state transitions */ + + { STATE_MODE_CFG_I0, STATE_MODE_CFG_I3 , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2 , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inI2 }, + , EVENT_SA_REPLACE, modecfg_inI0 }, + + { STATE_MODE_CFG_R3, STATE_MODE_CFG_R4 + , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 + , P(ATTR) | P(HASH), P(VID), PT(HASH) + , EVENT_SA_REPLACE, modecfg_inR3 }, { STATE_MODE_CFG_I3, STATE_UNDEFINED , SMF_ALL_AUTH | SMF_ENCRYPTED , LEMPTY, LEMPTY, PT(NONE) , EVENT_NULL, unexpected }, + { STATE_MODE_CFG_R4, STATE_UNDEFINED + , SMF_ALL_AUTH | SMF_ENCRYPTED + , LEMPTY, LEMPTY, PT(NONE) + , EVENT_NULL, unexpected }, + #undef P #undef PT }; @@ -1258,6 +1294,11 @@ process_packet(struct msg_digest **mdp) { plog("size (%u) differs from size specified in ISAKMP HDR (%u)" , (unsigned) pbs_room(&md->packet_pbs), md->hdr.isa_length); +#ifdef CISCO_QUIRKS + if (pbs_room(&md->packet_pbs) - md->hdr.isa_length == 16) + plog("Cisco VPN client appends 16 surplus NULL bytes"); + else +#endif return; } @@ -1447,11 +1488,6 @@ process_packet(struct msg_digest **mdp) return; } - if (st->st_state == STATE_MODE_CFG_R2) /* Have we just give an IP address to peer? */ - { - st->st_state = STATE_MAIN_R3; /* ISAKMP is up... */ - } - set_cur_state(st); if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) @@ -1490,7 +1526,7 @@ process_packet(struct msg_digest **mdp) case ISAKMP_XCHG_MODE_CFG: if (is_zero_cookie(md->hdr.isa_icookie)) { - plog("Mode Config message is invalid because" + plog("ModeCfg message is invalid because" " it has an Initiator Cookie of 0"); /* XXX Could send notification back */ return; @@ -1498,7 +1534,7 @@ process_packet(struct msg_digest **mdp) if (is_zero_cookie(md->hdr.isa_rcookie)) { - plog("Mode Config message is invalid because" + plog("ModeCfg message is invalid because" " it has a Responder Cookie of 0"); /* XXX Could send notification back */ return; @@ -1506,7 +1542,7 @@ process_packet(struct msg_digest **mdp) if (md->hdr.isa_msgid == 0) { - plog("Mode Config message is invalid because" + plog("ModeCfg message is invalid because" " it has a Message ID of 0"); /* XXX Could send notification back */ return; @@ -1517,7 +1553,9 @@ process_packet(struct msg_digest **mdp) if (st == NULL) { - /* No appropriate Mode Config state. + bool has_xauth_policy; + + /* No appropriate ModeCfg state. * See if we have a Main Mode state. * ??? what if this is a duplicate of another message? */ @@ -1526,7 +1564,7 @@ process_packet(struct msg_digest **mdp) if (st == NULL) { - plog("Mode Config message is for a non-existent (expired?)" + plog("ModeCfg message is for a non-existent (expired?)" " ISAKMP SA"); /* XXX Could send notification back */ return; @@ -1536,7 +1574,7 @@ process_packet(struct msg_digest **mdp) if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) { - loglog(RC_LOG_SERIOUS, "Mode Config message is unacceptable because" + loglog(RC_LOG_SERIOUS, "ModeCfg message is unacceptable because" " it is for an incomplete ISAKMP SA (state=%s)" , enum_name(&state_names, st->st_state)); /* XXX Could send notification back */ @@ -1565,7 +1603,16 @@ process_packet(struct msg_digest **mdp) * */ - if (st->st_connection->spd.that.modecfg + has_xauth_policy = (st->st_connection->policy + & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK)) + != LEMPTY; + + if (has_xauth_policy && !st->st_xauth.started + && IS_PHASE1(st->st_state)) + { + from_state = STATE_XAUTH_I0; + } + else if (st->st_connection->spd.that.modecfg && IS_PHASE1(st->st_state)) { from_state = STATE_MODE_CFG_R0; @@ -1573,12 +1620,12 @@ process_packet(struct msg_digest **mdp) else if (st->st_connection->spd.this.modecfg && IS_PHASE1(st->st_state)) { - from_state = STATE_MODE_CFG_I2; + from_state = STATE_MODE_CFG_I0; } else { /* XXX check if we are being a mode config server here */ - plog("received MODECFG message when in state %s, and we aren't mode config client" + plog("received ModeCfg message when in state %s, and we aren't mode config client" , enum_name(&state_names, st->st_state)); return; } @@ -1588,7 +1635,6 @@ process_packet(struct msg_digest **mdp) set_cur_state(st); from_state = st->st_state; } - break; #ifdef NOTYET @@ -1630,7 +1676,23 @@ process_packet(struct msg_digest **mdp) if (st != NULL) { - while (!LHAS(smc->flags, st->st_oakley.auth)) + u_int16_t auth; + + switch (st->st_oakley.auth) + { + case XAUTHInitPreShared: + case XAUTHRespPreShared: + auth = OAKLEY_PRESHARED_KEY; + break; + case XAUTHInitRSA: + case XAUTHRespRSA: + auth = OAKLEY_RSA_SIG; + break; + default: + auth = st->st_oakley.auth; + } + + while (!LHAS(smc->flags, auth)) { smc++; passert(smc->state == from_state); @@ -2046,6 +2108,8 @@ process_packet(struct msg_digest **mdp) void complete_state_transition(struct msg_digest **mdp, stf_status result) { + bool has_xauth_policy; + bool is_xauth_server; struct msg_digest *md = *mdp; const struct state_microcode *smc = md->smc; enum state_kind from_state = md->from_state; @@ -2263,7 +2327,7 @@ complete_state_transition(struct msg_digest **mdp, stf_status result) } /* advance b to end of string */ b = b + strlen(b); - + if (st->st_ah.present) { snprintf(b, sizeof(sadetails)-(b-sadetails)-1 @@ -2276,7 +2340,7 @@ complete_state_transition(struct msg_digest **mdp, stf_status result) } /* advance b to end of string */ b = b + strlen(b); - + if (st->st_ipcomp.present) { snprintf(b, sizeof(sadetails)-(b-sadetails)-1 @@ -2319,7 +2383,7 @@ complete_state_transition(struct msg_digest **mdp, stf_status result) } if (IS_ISAKMP_SA_ESTABLISHED(st->st_state) - || IS_IPSEC_SA_ESTABLISHED(st->st_state)) + || IS_IPSEC_SA_ESTABLISHED(st->st_state)) { /* log our success */ plog("%s%s", story, sadetails); @@ -2333,6 +2397,36 @@ complete_state_transition(struct msg_digest **mdp, stf_status result) , story, sadetails); } + has_xauth_policy = (st->st_connection->policy + & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK)) + != LEMPTY; + is_xauth_server = (st->st_connection->policy + & POLICY_XAUTH_SERVER) + != LEMPTY; + + /* Should we start XAUTH as a server */ + if (has_xauth_policy && is_xauth_server + && IS_ISAKMP_SA_ESTABLISHED(st->st_state) + && !st->st_xauth.started) + { + DBG(DBG_CONTROL, + DBG_log("starting XAUTH server") + ) + xauth_send_request(st); + break; + } + + /* Wait for XAUTH request from server */ + if (has_xauth_policy && !is_xauth_server + && IS_ISAKMP_SA_ESTABLISHED(st->st_state) + && !st->st_xauth.started) + { + DBG(DBG_CONTROL, + DBG_log("waiting for XAUTH request from server") + ) + break; + } + /* Should we start ModeConfig as a client? */ if (st->st_connection->spd.this.modecfg && IS_ISAKMP_SA_ESTABLISHED(st->st_state) @@ -2384,7 +2478,7 @@ complete_state_transition(struct msg_digest **mdp, stf_status result) } if (IS_ISAKMP_SA_ESTABLISHED(st->st_state) - || IS_IPSEC_SA_ESTABLISHED(st->st_state)) + || IS_IPSEC_SA_ESTABLISHED(st->st_state)) release_whack(st); break; diff --git a/programs/pluto/demux.h b/programs/pluto/demux.h index 7adac44f3..dc38e4cfc 100644 --- a/programs/pluto/demux.h +++ b/programs/pluto/demux.h @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: demux.h,v 1.4 2004/07/22 22:57:25 as Exp $ + * RCSID $Id: demux.h,v 1.5 2007/01/11 05:44:02 as Exp $ */ #include "packet.h" @@ -69,7 +69,7 @@ struct msg_digest { bool dpd; /* peer supports RFC 3706 DPD */ bool openpgp; /* peer supports OpenPGP certificates */ -# define PAYLIMIT 20 +# define PAYLIMIT 40 struct payload_digest digest[PAYLIMIT], *digest_roof, diff --git a/programs/pluto/ike_alg.c b/programs/pluto/ike_alg.c index 47393079a..456ca3a96 100644 --- a/programs/pluto/ike_alg.c +++ b/programs/pluto/ike_alg.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: ike_alg.c,v 1.6 2004/09/17 21:29:50 as Exp $ + * RCSID $Id: ike_alg.c,v 1.7 2007/01/10 00:36:19 as Exp $ */ #include <stdio.h> @@ -233,6 +233,7 @@ ike_alg_db_new(struct alg_info_ike *ai , lset_t policy) struct ike_info *ike_info; u_int ealg, halg, modp, eklen = 0; struct encrypt_desc *enc_desc; + bool is_xauth_server; int i; if (!ai) @@ -298,11 +299,37 @@ ike_alg_db_new(struct alg_info_ike *ai , lset_t policy) db_trans_add(db_ctx, KEY_IKE); db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (ike_info->ike_eklen) - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, ike_info->ike_eklen); + if (eklen) + db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY); db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); } + + is_xauth_server = (policy & POLICY_XAUTH_SERVER) != LEMPTY; + + if (policy & POLICY_XAUTH_RSASIG) + { + db_trans_add(db_ctx, KEY_IKE); + db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); + db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); + if (eklen) + db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); + db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD + , is_xauth_server ? XAUTHRespRSA : XAUTHInitRSA); + db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); + } + + if (policy & POLICY_XAUTH_PSK) + { + db_trans_add(db_ctx, KEY_IKE); + db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); + db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); + if (eklen) + db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); + db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD + , is_xauth_server ? XAUTHRespPreShared : XAUTHInitPreShared); + db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); + } } fail: return db_ctx; diff --git a/programs/pluto/ipsec_doi.c b/programs/pluto/ipsec_doi.c index fe5c846a7..e627f98b2 100644 --- a/programs/pluto/ipsec_doi.c +++ b/programs/pluto/ipsec_doi.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: ipsec_doi.c,v 1.39 2006/04/22 21:59:20 as Exp $ + * RCSID $Id: ipsec_doi.c,v 1.42 2007/01/10 00:36:19 as Exp $ */ #include <stdio.h> @@ -84,13 +84,13 @@ #endif /* !VENDORID */ /* - * are we sending an XAUTH VID (Cisco Mode Config Interoperability)? + * are we sending a Cisco Unity VID? */ -#ifdef XAUTH_VID -#define SEND_XAUTH_VID 1 -#else /* !XAUTH_VID */ -#define SEND_XAUTH_VID 0 -#endif /* !XAUTH_VID */ +#ifdef CISCO_QUIRKS +#define SEND_CISCO_UNITY_VID 1 +#else /* !CISCO_QUIRKS */ +#define SEND_CISCO_UNITY_VID 0 +#endif /* !CISCO_QUIRKS */ /* MAGIC: perform f, a function that returns notification_t * and return from the ENCLOSING stf_status returning function if it fails. @@ -896,10 +896,12 @@ main_outI1(int whack_sock, struct connection *c, struct state *predecessor /* determine how many Vendor ID payloads we will be sending */ if (SEND_PLUTO_VID) vids_to_send++; - if (SEND_XAUTH_VID) + if (SEND_CISCO_UNITY_VID) vids_to_send++; if (c->spd.this.cert.type == CERT_PGP) vids_to_send++; + /* always send XAUTH Vendor ID */ + vids_to_send++; /* always send DPD Vendor ID */ vids_to_send++; #ifdef NAT_TRAVERSAL @@ -946,8 +948,8 @@ main_outI1(int whack_sock, struct connection *c, struct state *predecessor u_char *sa_start = rbody.cur; lset_t auth_policy = policy & POLICY_ID_AUTH_MASK; - if (!out_sa(&rbody, &oakley_sadb[auth_policy >> POLICY_ISAKMP_SHIFT] - , st, TRUE, vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE)) + if (!out_sa(&rbody, &oakley_sadb, st, TRUE + , vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE)) { reset_cur_state(); return STF_INTERNAL_ERROR; @@ -970,17 +972,16 @@ main_outI1(int whack_sock, struct connection *c, struct state *predecessor } } - /* if enabled send XAUTH Vendor ID */ - if (SEND_XAUTH_VID) + /* if enabled send Cisco Unity Vendor ID */ + if (SEND_CISCO_UNITY_VID) { if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_MISC_XAUTH)) + , &rbody, VID_CISCO_UNITY)) { reset_cur_state(); return STF_INTERNAL_ERROR; } } - /* if we have an OpenPGP certificate we assume an * OpenPGP peer and have to send the Vendor ID */ @@ -994,6 +995,14 @@ main_outI1(int whack_sock, struct connection *c, struct state *predecessor } } + /* Announce our ability to do eXtended AUTHentication to the peer */ + if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE + , &rbody, VID_MISC_XAUTH)) + { + reset_cur_state(); + return STF_INTERNAL_ERROR; + } + /* Announce our ability to do Dead Peer Detection to the peer */ { if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE @@ -1199,11 +1208,15 @@ generate_skeyids_iv(struct state *st) switch (st->st_oakley.auth) { case OAKLEY_PRESHARED_KEY: + case XAUTHInitPreShared: + case XAUTHRespPreShared: if (!skeyid_preshared(st)) return FALSE; break; case OAKLEY_RSA_SIG: + case XAUTHInitRSA: + case XAUTHRespRSA: if (!skeyid_digisig(st)) return FALSE; break; @@ -2972,8 +2985,7 @@ main_inI1_outR1(struct msg_digest *md) { struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; struct state *st; - struct connection *c = find_host_connection(&md->iface->addr, pluto_port - , &md->sender, md->sender_port, LEMPTY); + struct connection *c; struct isakmp_proposal proposal; pb_stream proposal_pbs; pb_stream r_sa_pbs; @@ -2981,14 +2993,28 @@ main_inI1_outR1(struct msg_digest *md) lset_t policy = LEMPTY; int vids_to_send = 0; + /* We preparse the peer's proposal in order to determine + * the requested authentication policy (RSA or PSK) + */ RETURN_STF_FAILURE(preparse_isakmp_sa_body(&sa_pd->payload.sa , &sa_pd->pbs, &ipsecdoisit, &proposal_pbs, &proposal)); + backup_pbs(&proposal_pbs); + RETURN_STF_FAILURE(parse_isakmp_policy(&proposal_pbs + , proposal.isap_notrans, &policy)); + restore_pbs(&proposal_pbs); + + /* We are only considering candidate connections that match + * the requested authentication policy (RSA or PSK) + */ + c = find_host_connection(&md->iface->addr, pluto_port + , &md->sender, md->sender_port, policy); + #ifdef NAT_TRAVERSAL if (c == NULL && md->iface->ike_float) { c = find_host_connection(&md->iface->addr, NAT_T_IKE_FLOAT_PORT - , &md->sender, md->sender_port, LEMPTY); + , &md->sender, md->sender_port, policy); } #endif @@ -3007,11 +3033,6 @@ main_inI1_outR1(struct msg_digest *md) { struct connection *d; - backup_pbs(&proposal_pbs); - RETURN_STF_FAILURE(parse_isakmp_policy(&proposal_pbs - , proposal.isap_notrans, &policy)); - restore_pbs(&proposal_pbs); - d = find_host_connection(&md->iface->addr , pluto_port, (ip_address*)NULL, md->sender_port, policy); @@ -3071,6 +3092,13 @@ main_inI1_outR1(struct msg_digest *md) NULL); } } + else if (c->kind == CK_TEMPLATE) + { + /* Create an instance + * This is a rare case: wildcard peer ID but static peer IP address + */ + c = rw_instantiate(c, &md->sender, md->sender_port, NULL, &c->spd.that.id); + } /* Set up state */ md->st = st = new_state(); @@ -3109,10 +3137,12 @@ main_inI1_outR1(struct msg_digest *md) /* determine how many Vendor ID payloads we will be sending */ if (SEND_PLUTO_VID) vids_to_send++; - if (SEND_XAUTH_VID) + if (SEND_CISCO_UNITY_VID) vids_to_send++; if (md->openpgp) vids_to_send++; + /* always send XAUTH Vendor ID */ + vids_to_send++; /* always send DPD Vendor ID */ vids_to_send++; #ifdef NAT_TRAVERSAL @@ -3146,7 +3176,7 @@ main_inI1_outR1(struct msg_digest *md) /* SA body in and out */ RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit, &proposal_pbs - ,&proposal, &r_sa_pbs, st)); + ,&proposal, &r_sa_pbs, st, FALSE)); /* if enabled send Pluto Vendor ID */ if (SEND_PLUTO_VID) @@ -3158,11 +3188,11 @@ main_inI1_outR1(struct msg_digest *md) } } - /* if enabled send XAUTH Vendor ID */ - if (SEND_XAUTH_VID) + /* if enabled send Cisco Unity Vendor ID */ + if (SEND_CISCO_UNITY_VID) { if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_MISC_XAUTH)) + , &md->rbody, VID_CISCO_UNITY)) { return STF_INTERNAL_ERROR; } @@ -3180,13 +3210,18 @@ main_inI1_outR1(struct msg_digest *md) } } + /* Announce our ability to do eXtended AUTHentication to the peer */ + if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE + , &md->rbody, VID_MISC_XAUTH)) + { + return STF_INTERNAL_ERROR; + } + /* Announce our ability to do Dead Peer Detection to the peer */ + if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE + , &md->rbody, VID_MISC_DPD)) { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_MISC_DPD)) - { - return STF_INTERNAL_ERROR; - } + return STF_INTERNAL_ERROR; } #ifdef NAT_TRAVERSAL @@ -3249,7 +3284,7 @@ main_inR1_outI2(struct msg_digest *md) RETURN_STF_FAILURE(BAD_PROPOSAL_SYNTAX); } RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit - , &proposal_pbs, &proposal, NULL, st)); + , &proposal_pbs, &proposal, NULL, st, TRUE)); } #ifdef NAT_TRAVERSAL @@ -3342,9 +3377,11 @@ main_inI2_outR2(struct msg_digest *md) pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs; /* send CR if auth is RSA and no preloaded RSA public key exists*/ - bool send_cr = !no_cr_send && (st->st_oakley.auth == OAKLEY_RSA_SIG) && - !has_preloaded_public_key(st); - + bool RSA_auth = st->st_oakley.auth == OAKLEY_RSA_SIG + || st->st_oakley.auth == XAUTHInitRSA + || st->st_oakley.auth == XAUTHRespRSA; + bool send_cr = !no_cr_send && RSA_auth && !has_preloaded_public_key(st); + u_int8_t np = ISAKMP_NEXT_NONE; /* KE in */ @@ -3487,14 +3524,18 @@ main_inR2_outI3(struct msg_digest *md) { struct state *const st = md->st; pb_stream *const keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs; - int auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY - ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG; pb_stream id_pbs; /* ID Payload; also used for hash calculation */ certpolicy_t cert_policy = st->st_connection->spd.this.sendcert; cert_t mycert = st->st_connection->spd.this.cert; bool requested, send_cert, send_cr; + bool RSA_auth = st->st_oakley.auth == OAKLEY_RSA_SIG + || st->st_oakley.auth == XAUTHInitRSA + || st->st_oakley.auth == XAUTHRespRSA; + + int auth_payload = RSA_auth ? ISAKMP_NEXT_SIG : ISAKMP_NEXT_HASH; + /* KE in */ RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", st->st_oakley.group, keyex_pbs)); @@ -3516,8 +3557,7 @@ main_inR2_outI3(struct msg_digest *md) */ requested = cert_policy == CERT_SEND_IF_ASKED && st->st_connection->got_certrequest; - send_cert = st->st_oakley.auth == OAKLEY_RSA_SIG - && mycert.type != CERT_NONE + send_cert = RSA_auth && mycert.type != CERT_NONE && (cert_policy == CERT_ALWAYS_SEND || requested); /* send certificate request if we don't have a preloaded RSA public key */ @@ -3560,7 +3600,7 @@ main_inR2_outI3(struct msg_digest *md) } /* CERT out */ - if ( st->st_oakley.auth == OAKLEY_RSA_SIG) + if (RSA_auth) { DBG(DBG_CONTROL, DBG_log("our certificate policy is %s" @@ -3716,6 +3756,8 @@ main_id_and_auth(struct msg_digest *md switch (st->st_oakley.auth) { case OAKLEY_PRESHARED_KEY: + case XAUTHInitPreShared: + case XAUTHRespPreShared: { pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; @@ -3732,6 +3774,8 @@ main_id_and_auth(struct msg_digest *md break; case OAKLEY_RSA_SIG: + case XAUTHInitRSA: + case XAUTHRespRSA: r = RSA_check_signature(&peer, st, hash_val, hash_len , &md->chain[ISAKMP_NEXT_SIG]->pbs #ifdef USE_KEYRR @@ -3909,6 +3953,7 @@ main_inI3_outR3_tail(struct msg_digest *md pb_stream r_id_pbs; /* ID Payload; also used for hash calculation */ certpolicy_t cert_policy; cert_t mycert; + bool RSA_auth; bool send_cert; bool requested; @@ -3931,7 +3976,10 @@ main_inI3_outR3_tail(struct msg_digest *md mycert = st->st_connection->spd.this.cert; requested = cert_policy == CERT_SEND_IF_ASKED && st->st_connection->got_certrequest; - send_cert = st->st_oakley.auth == OAKLEY_RSA_SIG + RSA_auth = st->st_oakley.auth == OAKLEY_RSA_SIG + || st->st_oakley.auth == XAUTHInitRSA + || st->st_oakley.auth == XAUTHRespRSA; + send_cert = RSA_auth && mycert.type != CERT_NONE && (cert_policy == CERT_ALWAYS_SEND || requested); @@ -3949,8 +3997,7 @@ main_inI3_outR3_tail(struct msg_digest *md */ echo_hdr(md, TRUE, ISAKMP_NEXT_ID); - auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY - ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG; + auth_payload = RSA_auth ? ISAKMP_NEXT_SIG : ISAKMP_NEXT_HASH; /* IDir out */ { @@ -3969,7 +4016,7 @@ main_inI3_outR3_tail(struct msg_digest *md } /* CERT out */ - if (st->st_oakley.auth == OAKLEY_RSA_SIG) + if (RSA_auth) { DBG(DBG_CONTROL, DBG_log("our certificate policy is %s" diff --git a/programs/pluto/keys.c b/programs/pluto/keys.c index 55d13282c..39726f424 100644 --- a/programs/pluto/keys.c +++ b/programs/pluto/keys.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: keys.c,v 1.25 2006/07/06 19:23:28 as Exp $ + * RCSID $Id: keys.c,v 1.26 2007/01/10 00:36:19 as Exp $ */ #include <stddef.h> @@ -54,6 +54,7 @@ #include "whack.h" /* for RC_LOG_SERIOUS */ #include "timer.h" #include "fetch.h" +#include "xauth.h" const char *shared_secrets_file = SHARED_SECRETS_FILE; @@ -72,6 +73,7 @@ struct secret { union { chunk_t preshared_secret; RSA_private_key_t RSA_private_key; + xauth_t xauth_secret; smartcard_t *smartcard; } u; secret_t *next; @@ -96,11 +98,11 @@ allocate_RSA_public_key(const cert_t cert) default: plog("RSA public key allocation error"); } - init_RSA_public_key(&pk->u.rsa, e, n); -#ifdef DEBUG - DBG(DBG_PRIVATE, RSA_show_public_key(&pk->u.rsa)); -#endif + init_RSA_public_key(&pk->u.rsa, e, n); + DBG(DBG_RAW, + RSA_show_public_key(&pk->u.rsa) + ) pk->alg = PUBKEY_ALG_RSA; pk->id = empty_id; @@ -182,14 +184,14 @@ get_secret(const struct connection *c, enum PrivateKeyKind kind, bool asym) } #ifdef NAT_TRAVERSAL else if (kind == PPK_PSK - && (c->policy & POLICY_PSK) + && (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK)) && ((c->kind == CK_TEMPLATE && c->spd.that.id.kind == ID_NONE) || (c->kind == CK_INSTANCE && id_is_ipaddr(&c->spd.that.id)))) { - /* roadwarrior: replace him with 0.0.0.0 */ - rw_id.kind = ID_IPV4_ADDR; - happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr)); - his_id = &rw_id; + /* roadwarrior: replace him with 0.0.0.0 */ + rw_id.kind = ID_IPV4_ADDR; + happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr)); + his_id = &rw_id; } #endif @@ -295,14 +297,12 @@ get_preshared_secret(const struct connection *c) { const secret_t *s = get_secret(c, PPK_PSK, FALSE); -#ifdef DEBUG DBG(DBG_PRIVATE, if (s == NULL) DBG_log("no Preshared Key Found"); else DBG_dump_chunk("Preshared Key", s->u.preshared_secret); - ); -#endif + ) return s == NULL? NULL : &s->u.preshared_secret; } @@ -417,7 +417,7 @@ process_psk_secret(chunk_t *psk) } else { - char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */ + char buf[BUF_LEN]; /* limit on size of binary representation of key */ size_t sz; ugh = ttodatav(tok, flp->cur - tok, 0, buf, sizeof(buf), &sz @@ -586,6 +586,119 @@ process_rsa_keyfile(RSA_private_key_t *rsak, int whackfd) } /* + * process xauth secret read from ipsec.secrets + */ +static err_t +process_xauth(secret_t *s) +{ + chunk_t user_name; + + s->kind = PPK_XAUTH; + + if (!shift()) + return "missing xauth user name"; + if (*tok == '"' || *tok == '\'') /* quoted user name */ + { + user_name.ptr = tok + 1; + user_name.len = flp->cur - tok - 2; + } + else + { + user_name.ptr = tok; + user_name.len = flp->cur - tok; + } + plog(" loaded xauth credentials of user '%.*s'" + , user_name.len + , user_name.ptr); + clonetochunk(s->u.xauth_secret.user_name + , user_name.ptr, user_name.len, "xauth user name"); + + if (!shift()) + return "missing xauth user password"; + return process_psk_secret(&s->u.xauth_secret.user_password); +} + +/* get XAUTH secret from chained secrets lists + * only one entry is currently supported + */ +static bool +xauth_get_secret(xauth_t *xauth_secret) +{ + secret_t *s; + bool found = FALSE; + + for (s = secrets; s != NULL; s = s->next) + { + if (s->kind == PPK_XAUTH) + { + if (found) + { + plog("found multiple xauth secrets - first selected"); + } + else + { + found = TRUE; + *xauth_secret = s->u.xauth_secret; + } + } + } + return found; +} + +/* + * find a matching secret + */ +static bool +xauth_verify_secret(const xauth_t *xauth_secret) +{ + bool found = FALSE; + secret_t *s; + + for (s = secrets; s != NULL; s = s->next) + { + if (s->kind == PPK_XAUTH) + { + if (!same_chunk(xauth_secret->user_name, s->u.xauth_secret.user_name)) + continue; + found = TRUE; + if (same_chunk(xauth_secret->user_password, s->u.xauth_secret.user_password)) + return TRUE; + } + } + plog("xauth user '%.*s' %s" + , xauth_secret->user_name.len, xauth_secret->user_name.ptr + , found? "sent wrong password":"not found"); + return FALSE; +} + +/* + * the global xauth_module struct is defined here + */ +xauth_module_t xauth_module; + +/* + * assign the default xauth functions to any null function pointers + */ +void +xauth_defaults(void) +{ + if (xauth_module.get_secret == NULL) + { + DBG(DBG_CONTROL, + DBG_log("xauth module: using default get_secret() function") + ) + xauth_module.get_secret = xauth_get_secret; + } + if (xauth_module.verify_secret == NULL) + { + DBG(DBG_CONTROL, + DBG_log("xauth module: using default verify_secret() function") + ) + xauth_module.verify_secret = xauth_verify_secret; + } +}; + +/* * process pin read from ipsec.secrets or prompted for it using whack */ static err_t @@ -696,6 +809,10 @@ process_secret(secret_t *s, int whackfd) ugh = process_rsa_keyfile(&s->u.RSA_private_key, whackfd); } } + else if (tokeqword("xauth")) + { + ugh = process_xauth(s); + } else if (tokeqword("pin")) { ugh = process_pin(s, whackfd); @@ -925,7 +1042,7 @@ void free_preshared_secrets(void) { lock_certs_and_keys("free_preshared_secrets"); - + if (secrets != NULL) { secret_t *s, *ns; @@ -951,6 +1068,10 @@ free_preshared_secrets(void) case PPK_RSA: free_RSA_private_content(&s->u.RSA_private_key); break; + case PPK_XAUTH: + pfree(s->u.xauth_secret.user_name.ptr); + pfree(s->u.xauth_secret.user_password.ptr); + break; case PPK_PIN: scx_release(s->u.smartcard); break; @@ -961,7 +1082,7 @@ free_preshared_secrets(void) } secrets = NULL; } - + unlock_certs_and_keys("free_preshard_secrets"); } @@ -1105,14 +1226,11 @@ unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey) return RSA_MAX_OCTETS_UGH; init_RSA_public_key(rsa, exp, mod); - -#ifdef DEBUG - DBG(DBG_PRIVATE, RSA_show_public_key(rsa)); -#endif - - rsa->k = mpz_sizeinbase(&rsa->n, 2); /* size in bits, for a start */ rsa->k = (rsa->k + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* now octets */ + DBG(DBG_RAW, + RSA_show_public_key(rsa) + ) if (rsa->k != mod.len) { diff --git a/programs/pluto/keys.h b/programs/pluto/keys.h index d47d8b0a2..2f6216b93 100644 --- a/programs/pluto/keys.h +++ b/programs/pluto/keys.h @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: keys.h,v 1.7 2006/01/26 20:10:34 as Exp $ + * RCSID $Id: keys.h,v 1.8 2007/01/10 00:36:19 as Exp $ */ #ifndef _KEYS_H @@ -31,15 +31,19 @@ const char *shared_secrets_file; extern void load_preshared_secrets(int whackfd); extern void free_preshared_secrets(void); -struct state; /* forward declaration */ - enum PrivateKeyKind { PPK_PSK, /* PPK_DSS, */ /* not implemented */ PPK_RSA, + PPK_XAUTH, PPK_PIN }; +extern void xauth_defaults(void); + +/* forward declaration */ +struct connection; + extern const chunk_t *get_preshared_secret(const struct connection *c); extern err_t unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey); extern const RSA_private_key_t *get_RSA_private_key(const struct connection *c); diff --git a/programs/pluto/modecfg.c b/programs/pluto/modecfg.c index ec334aaf5..01bab8c6e 100644 --- a/programs/pluto/modecfg.c +++ b/programs/pluto/modecfg.c @@ -14,7 +14,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: modecfg.c,v 1.9 2006/10/21 17:11:13 as Exp $ + * RCSID $Id: modecfg.c,v 1.10 2007/01/10 00:36:19 as Exp $ * * This code originally written by Colubris Networks, Inc. * Extraction of patch and porting to 1.99 codebases by Xelerance Corporation @@ -39,6 +39,9 @@ #include "crypto.h" #include "modecfg.h" #include "whack.h" +#include "xauth.h" + +#define MAX_XAUTH_TRIES 3 #define SUPPORTED_ATTR_SET ( LELEM(INTERNAL_IP4_ADDRESS) \ | LELEM(INTERNAL_IP4_NETMASK) \ @@ -53,10 +56,17 @@ typedef struct internal_addr internal_addr_t; struct internal_addr { - lset_t attr_set; - ip_address ipaddr; - ip_address dns[2]; - ip_address wins[2]; + lset_t attr_set; + + /* ModeCfg variables */ + ip_address ipaddr; + ip_address dns[2]; + ip_address wins[2]; + + /* XAUTH variables */ + u_int16_t xauth_type; + xauth_t xauth_secret; + bool xauth_status; }; /* @@ -66,6 +76,10 @@ static void init_internal_addr(internal_addr_t *ia) { ia->attr_set = LEMPTY; + ia->xauth_secret.user_name = empty_chunk; + ia->xauth_secret.user_password = empty_chunk; + ia->xauth_status = FALSE; + anyaddr(AF_INET, &ia->ipaddr); anyaddr(AF_INET, &ia->dns[0]); anyaddr(AF_INET, &ia->dns[1]); @@ -218,7 +232,20 @@ modecfg_build_msg(struct state *st, pb_stream *rbody u_int len; /* ISAKMP attr out */ - attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TLV; + if (attr_type == XAUTH_TYPE) + { + attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TV; + attr.isaat_lv = ia->xauth_type; + } + else if (attr_type == XAUTH_STATUS) + { + attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TV; + attr.isaat_lv = ia->xauth_status; + } + else + { + attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TLV; + } out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval); switch (attr_type) @@ -288,14 +315,34 @@ modecfg_build_msg(struct state *st, pb_stream *rbody case INTERNAL_IP4_NBNS: if (!isanyaddr(&ia->wins[wins_idx])) { - len = addrbytesptr(&ia->wins[wins_idx++], &byte_ptr); - out_raw(byte_ptr, len, &attrval, "IP4_wins"); + len = addrbytesptr(&ia->wins[wins_idx++], &byte_ptr); + out_raw(byte_ptr, len, &attrval, "IP4_wins"); } if (wins_idx < 2 && !isanyaddr(&ia->wins[wins_idx])) { dont_advance = TRUE; } - break; + break; + case XAUTH_TYPE: + break; + case XAUTH_USER_NAME: + if (ia->xauth_secret.user_name.ptr != NULL) + { + out_raw(ia->xauth_secret.user_name.ptr + , ia->xauth_secret.user_name.len + , &attrval, "xauth_user_name"); + } + break; + case XAUTH_USER_PASSWORD: + if (ia->xauth_secret.user_password.ptr != NULL) + { + out_raw(ia->xauth_secret.user_password.ptr + , ia->xauth_secret.user_password.len + , &attrval, "xauth_user_password"); + } + break; + case XAUTH_STATUS: + break; default: plog("attempt to send unsupported mode cfg attribute %s." , enum_show(&modecfg_attr_names, attr_type)); @@ -306,13 +353,17 @@ modecfg_build_msg(struct state *st, pb_stream *rbody if (!dont_advance) { attr_type++; + if (attr_type == MODECFG_ROOF) + { + attr_type = XAUTH_BASE; + } attr_set >>= 1; } } close_message(&strattr); } - modecfg_hash(r_hashval, r_hash_start, rbody->cur,st); + modecfg_hash(r_hashval, r_hash_start, rbody->cur, st); close_message(rbody); encrypt_message(rbody, st); return STF_OK; @@ -361,6 +412,7 @@ modecfg_send_msg(struct state *st, int isama_type, internal_addr_t *ia) , 0 /* XXX isama_id */ ); + freeanychunk(st->st_tpacket); clonetochunk(st->st_tpacket, msg.start, pbs_offset(&msg), "ModeCfg msg"); /* Transmit */ @@ -371,43 +423,10 @@ modecfg_send_msg(struct state *st, int isama_type, internal_addr_t *ia) delete_event(st); event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); } - st->st_modecfg.started = TRUE; return STF_OK; } /* - * Send ModeCfg request message from client to server in pull mode - */ -stf_status -modecfg_send_request(struct state *st) -{ - internal_addr_t ia; - - init_internal_addr(&ia); - ia.attr_set = LELEM(INTERNAL_IP4_ADDRESS) - | LELEM(INTERNAL_IP4_NETMASK); - - plog("sending ModeCfg request"); - st->st_state = STATE_MODE_CFG_I1; - return modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia); -} - -/* - * Send ModeCfg set message from server to client in push mode - */ -stf_status -modecfg_send_set(struct state *st) -{ - internal_addr_t ia; - - get_internal_addr(st->st_connection, &ia); - - plog("sending ModeCfg set"); - st->st_state = STATE_MODE_CFG_R1; - return modecfg_send_msg(st, ISAKMP_CFG_SET, &ia); -} - -/* * Parse a ModeCfg attribute payload */ static stf_status @@ -442,6 +461,22 @@ modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia) case INTERNAL_IP4_NBNS: ia->attr_set |= LELEM(attr_type); break; + case XAUTH_TYPE: + ia->xauth_type = attr.isaat_lv; + ia->attr_set |= LELEM(attr_type - XAUTH_BASE + MODECFG_ROOF); + break; + case XAUTH_USER_NAME: + setchunk(ia->xauth_secret.user_name, strattr.cur, attr_len); + ia->attr_set |= LELEM(attr_type - XAUTH_BASE + MODECFG_ROOF); + break; + case XAUTH_USER_PASSWORD: + setchunk(ia->xauth_secret.user_password, strattr.cur, attr_len); + ia->attr_set |= LELEM(attr_type - XAUTH_BASE + MODECFG_ROOF); + break; + case XAUTH_STATUS: + ia->xauth_status = attr.isaat_lv; + ia->attr_set |= LELEM(attr_type - XAUTH_BASE + MODECFG_ROOF); + break; default: plog("unsupported ModeCfg attribute %s received." , enum_show(&modecfg_attr_names, attr_type)); @@ -483,7 +518,7 @@ modecfg_parse_msg(struct msg_digest *md, int isama_type, u_int16_t *isama_id stat = modecfg_parse_attributes(&p->pbs, &ia_candidate); if (stat == STF_OK) { - /* retrun with a valid set of attributes */ + /* return with a valid set of attributes */ *ia = ia_candidate; return STF_OK; } @@ -502,6 +537,27 @@ modecfg_parse_msg(struct msg_digest *md, int isama_type, u_int16_t *isama_id return STF_IGNORE; } +/* + * Send ModeCfg request message from client to server in pull mode + */ +stf_status +modecfg_send_request(struct state *st) +{ + stf_status stat; + internal_addr_t ia; + + init_internal_addr(&ia); + ia.attr_set = LELEM(INTERNAL_IP4_ADDRESS) + | LELEM(INTERNAL_IP4_NETMASK); + + plog("sending ModeCfg request"); + st->st_state = STATE_MODE_CFG_I1; + stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia); + if (stat == STF_OK) + st->st_modecfg.started = TRUE; + return stat; +} + /* STATE_MODE_CFG_R0: * HDR*, HASH, ATTR(REQ=IP) --> HDR*, HASH, ATTR(REPLY=IP) * @@ -513,37 +569,118 @@ modecfg_inR0(struct msg_digest *md) struct state *const st = md->st; u_int16_t isama_id; internal_addr_t ia; - stf_status stat; + stf_status stat, stat_build; stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia); if (stat != STF_OK) return stat; + + get_internal_addr(st->st_connection, &ia); + + plog("sending ModeCfg reply"); + + stat_build = modecfg_build_msg(st, &md->rbody + , ISAKMP_CFG_REPLY + , &ia + , isama_id); + if (stat_build != STF_OK) + return stat_build; + + st->st_msgid = 0; + return STF_OK; +} + +/* STATE_MODE_CFG_I1: + * HDR*, HASH, ATTR(REPLY=IP) + * + * used in ModeCfg pull mode, on the client (initiator) + */ +stf_status +modecfg_inI1(struct msg_digest *md) +{ + struct state *const st = md->st; + u_int16_t isama_id; + internal_addr_t ia; + stf_status stat; + + plog("parsing ModeCfg reply"); + + stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia); + if (stat != STF_OK) + return stat; + + st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia); + st->st_msgid = 0; + return STF_OK; +} + + +/* + * Send ModeCfg set message from server to client in push mode + */ +stf_status +modecfg_send_set(struct state *st) +{ + stf_status stat; + internal_addr_t ia; get_internal_addr(st->st_connection, &ia); - /* build ISAKMP_CFG_REPLY */ - stat = modecfg_build_msg(st, &md->rbody - , ISAKMP_CFG_REPLY - , &ia - , isama_id); + plog("sending ModeCfg set"); + st->st_state = STATE_MODE_CFG_R3; + stat = modecfg_send_msg(st, ISAKMP_CFG_SET, &ia); + if (stat == STF_OK) + st->st_modecfg.started = TRUE; + return stat; +} + +/* STATE_MODE_CFG_I0: + * HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK) + * + * used in ModeCfg push mode, on the client (initiator). + */ +stf_status +modecfg_inI0(struct msg_digest *md) +{ + struct state *const st = md->st; + u_int16_t isama_id; + internal_addr_t ia; + lset_t attr_set; + stf_status stat, stat_build; + + plog("parsing ModeCfg set"); + + stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia); if (stat != STF_OK) - { - /* notification payload - not exactly the right choice, but okay */ - md->note = ATTRIBUTES_NOT_SUPPORTED; return stat; - } + + st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia); + + /* prepare ModeCfg ack which sends zero length attributes */ + attr_set = ia.attr_set; + init_internal_addr(&ia); + ia.attr_set = attr_set & SUPPORTED_ATTR_SET; + + plog("sending ModeCfg ack"); + + stat_build = modecfg_build_msg(st, &md->rbody + , ISAKMP_CFG_ACK + , &ia + , isama_id); + if (stat_build != STF_OK) + return stat_build; st->st_msgid = 0; return STF_OK; } -/* STATE_MODE_CFG_R1: +/* STATE_MODE_CFG_R3: * HDR*, HASH, ATTR(ACK,OK) * * used in ModeCfg push mode, on the server (responder) */ stf_status -modecfg_inR1(struct msg_digest *md) +modecfg_inR3(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; @@ -560,61 +697,211 @@ modecfg_inR1(struct msg_digest *md) return STF_OK; } -/* STATE_MODE_CFG_I1: - * HDR*, HASH, ATTR(REPLY=IP) +/* + * Send XAUTH credentials request (username + password) + */ +stf_status +xauth_send_request(struct state *st) +{ + stf_status stat; + internal_addr_t ia; + + init_internal_addr(&ia); + ia.attr_set = LELEM(XAUTH_USER_NAME - XAUTH_BASE + MODECFG_ROOF) + | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE + MODECFG_ROOF); + + plog("sending XAUTH request"); + st->st_state = STATE_XAUTH_R1; + stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia); + if (stat == STF_OK) + st->st_xauth.started = TRUE; + return stat; +} + +/* STATE_XAUTH_I0: + * HDR*, HASH, ATTR(REQ) --> HDR*, HASH, ATTR(REPLY=USERNAME/PASSWORD) * - * used in ModeCfg pull mode, on the client (initiator) + * used on the XAUTH client (initiator) */ stf_status -modecfg_inI1(struct msg_digest *md) +xauth_inI0(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; internal_addr_t ia; - stf_status stat; + stf_status stat, stat_build; - plog("parsing ModeCfg reply"); + plog("parsing XAUTH request"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia); + stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia); if (stat != STF_OK) return stat; + + /* check XAUTH attributes */ + if ((ia.attr_set & LELEM(XAUTH_TYPE - XAUTH_BASE + MODECFG_ROOF)) != LEMPTY + && ia.xauth_type != XAUTH_TYPE_GENERIC) + { + plog("xauth type %s is not supported", enum_name(&xauth_type_names, ia.xauth_type)); + stat = STF_FAIL; + } + else if ((ia.attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE + MODECFG_ROOF)) == LEMPTY) + { + plog("user name attribute is missing in XAUTH request"); + stat = STF_FAIL; + } + else if ((ia.attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE + MODECFG_ROOF)) == LEMPTY) + { + plog("user password attribute is missing in XAUTH request"); + stat = STF_FAIL; + } - st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia); - st->st_msgid = 0; - return STF_OK; + /* prepare XAUTH reply */ + init_internal_addr(&ia); + + if (stat == STF_OK) + { + /* get user credentials using a plugin function */ + if (!xauth_module.get_secret(&ia.xauth_secret)) + { + plog("xauth user credentials not found"); + stat = STF_FAIL; + } + } + if (stat == STF_OK) + { + DBG(DBG_CONTROL, + DBG_log("my xauth user name is '%.*s'" + , ia.xauth_secret.user_name.len + , ia.xauth_secret.user_name.ptr) + ) + DBG(DBG_PRIVATE, + DBG_log("my xauth user password is '%.*s'" + , ia.xauth_secret.user_password.len + , ia.xauth_secret.user_password.ptr) + ) + ia.attr_set = LELEM(XAUTH_USER_NAME - XAUTH_BASE + MODECFG_ROOF) + | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE + MODECFG_ROOF); + } + else + { + ia.attr_set = LELEM(XAUTH_STATUS - XAUTH_BASE + MODECFG_ROOF); + ia.xauth_status = FALSE; + } + + plog("sending XAUTH reply"); + + stat_build = modecfg_build_msg(st, &md->rbody + , ISAKMP_CFG_REPLY + , &ia + , isama_id); + if (stat_build != STF_OK) + return stat_build; + + if (stat == STF_OK) + { + st->st_xauth.started = TRUE; + return STF_OK; + } + else + { + /* send XAUTH reply msg and then delete ISAKMP SA */ + freeanychunk(st->st_tpacket); + clonetochunk(st->st_tpacket, md->reply.start + , pbs_offset(&md->reply), "XAUTH reply msg"); + send_packet(st, "XAUTH reply msg"); + delete_state(st); + return STF_IGNORE; + } } -/* STATE_MODE_CFG_I2: - * HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK) +/* STATE_XAUTH_R1: + * HDR*, HASH, ATTR(REPLY=USERNAME/PASSWORD) --> HDR*, HASH, ATTR(STATUS) * - * used in ModeCfg push mode, on the client (initiator). + * used on the XAUTH server (responder) */ stf_status -modecfg_inI2(struct msg_digest *md) +xauth_inR1(struct msg_digest *md) { struct state *const st = md->st; u_int16_t isama_id; internal_addr_t ia; - lset_t attr_set; - stf_status stat; + stf_status stat, stat_build; - plog("parsing ModeCfg set"); + plog("parsing XAUTH reply"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia); + stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia); if (stat != STF_OK) return stat; + + /* did the client return an XAUTH FAIL status? */ + if ((ia.attr_set & LELEM(XAUTH_STATUS - XAUTH_BASE + MODECFG_ROOF)) != LEMPTY) + { + plog("received FAIL status in XAUTH reply"); - st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia); + /* client is not able to do XAUTH, delete ISAKMP SA */ + delete_state(st); + return STF_IGNORE; + } - /* prepare ModeCfg ack which sends zero length attributes */ - attr_set = ia.attr_set; + /* check XAUTH reply */ + if ((ia.attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE + MODECFG_ROOF)) == LEMPTY) + { + plog("user name attribute is missing in XAUTH reply"); + st->st_xauth.status = FALSE; + } + else if ((ia.attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE + MODECFG_ROOF)) == LEMPTY) + { + plog("user password attribute is missing in XAUTH reply"); + st->st_xauth.status = FALSE; + } + else + { + DBG(DBG_CONTROL, + DBG_log("peer xauth user name is '%.*s'" + , ia.xauth_secret.user_name.len + , ia.xauth_secret.user_name.ptr) + ) + DBG(DBG_PRIVATE, + DBG_log("peer xauth user password is '%.*s'" + , ia.xauth_secret.user_password.len + , ia.xauth_secret.user_password.ptr) + ) + /* verify the user credentials using a plugn function */ + st->st_xauth.status = xauth_module.verify_secret(&ia.xauth_secret); + plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); + } + + /* prepare XAUTH set which sends the authentication status */ init_internal_addr(&ia); - ia.attr_set = attr_set & SUPPORTED_ATTR_SET; + ia.attr_set = LELEM(XAUTH_STATUS - XAUTH_BASE + MODECFG_ROOF); + ia.xauth_status = st->st_xauth.status; + + plog("sending XAUTH status:"); + + stat_build = modecfg_build_msg(st, &md->rbody + , ISAKMP_CFG_SET + , &ia + , isama_id); + if (stat_build != STF_OK) + return stat_build; + return STF_OK; +} - stat = modecfg_build_msg(st, &md->rbody - , ISAKMP_CFG_ACK - , &ia - , isama_id); +/* STATE_XAUTH_I1: + * HDR*, HASH, ATTR(STATUS) --> HDR*, HASH, ATTR(ACK) + * + * used on the XAUTH client (initiator) + */ +stf_status +xauth_inI1(struct msg_digest *md) +{ + struct state *const st = md->st; + u_int16_t isama_id; + internal_addr_t ia; + stf_status stat, stat_build; + + plog("parsing XAUTH status"); + stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia); if (stat != STF_OK) { /* notification payload - not exactly the right choice, but okay */ @@ -622,6 +909,62 @@ modecfg_inI2(struct msg_digest *md) return stat; } + st->st_xauth.status = ia.xauth_status; + plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); + + plog("sending XAUTH ack"); + init_internal_addr(&ia); + stat_build = modecfg_build_msg(st, &md->rbody + , ISAKMP_CFG_ACK + , &ia + , isama_id); + if (stat_build != STF_OK) + return stat_build; + + if (st->st_xauth.status) + { + st->st_msgid = 0; + return STF_OK; + } + else + { + /* send XAUTH ack msg and then delete ISAKMP SA */ + freeanychunk(st->st_tpacket); + clonetochunk(st->st_tpacket, md->reply.start + , pbs_offset(&md->reply), "XAUTH ack msg"); + send_packet(st, "XAUTH ack msg"); + delete_state(st); + return STF_IGNORE; + } +} + +/* STATE_XAUTH_R2: + * HDR*, ATTR(STATUS), HASH --> Done + * + * used on the XAUTH server (responder) + */ +stf_status +xauth_inR2(struct msg_digest *md) +{ + struct state *const st = md->st; + u_int16_t isama_id; + internal_addr_t ia; + stf_status stat; + + plog("parsing XAUTH ack"); + + stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia); + if (stat != STF_OK) + return stat; + st->st_msgid = 0; - return STF_OK; + if (st->st_xauth.status) + { + return STF_OK; + } + else + { + delete_state(st); + return STF_IGNORE; + } } diff --git a/programs/pluto/modecfg.h b/programs/pluto/modecfg.h index 1f8259ca8..4fce75aef 100644 --- a/programs/pluto/modecfg.h +++ b/programs/pluto/modecfg.h @@ -12,17 +12,36 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: modecfg.h,v 1.3 2006/10/19 21:07:40 as Exp $ + * RCSID $Id: modecfg.h,v 1.4 2007/01/10 00:36:19 as Exp $ */ +#ifndef _MODECFG_H +#define _MODECFG_H + struct state; +struct msg_digest; -/* ModeConfig starting functions */ +/* ModeConfig pull mode start function */ extern stf_status modecfg_send_request(struct state *st); -extern stf_status modecfg_send_set(struct state *st); -/* ModeConfig state transition functions */ +/* ModeConfig pull mode state transition functions */ extern stf_status modecfg_inR0(struct msg_digest *md); -extern stf_status modecfg_inR1(struct msg_digest *md); extern stf_status modecfg_inI1(struct msg_digest *md); -extern stf_status modecfg_inI2(struct msg_digest *md); + +/* ModeConfig push mode start function */ +extern stf_status modecfg_send_set(struct state *st); + +/* ModeConfig push mode state transition functions */ +extern stf_status modecfg_inI0(struct msg_digest *md); +extern stf_status modecfg_inR3(struct msg_digest *md); + +/* XAUTH start function */ +extern stf_status xauth_send_request(struct state *st); + +/* XAUTH state transition funcgtions */ +extern stf_status xauth_inI0(struct msg_digest *md); +extern stf_status xauth_inR1(struct msg_digest *md); +extern stf_status xauth_inI1(struct msg_digest *md); +extern stf_status xauth_inR2(struct msg_digest *md); + +#endif /* _MODECFG_H */ diff --git a/programs/pluto/plutomain.c b/programs/pluto/plutomain.c index f9badbae3..613f8d50f 100644 --- a/programs/pluto/plutomain.c +++ b/programs/pluto/plutomain.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: plutomain.c,v 1.16 2005/09/25 21:30:52 as Exp $ + * RCSID $Id: plutomain.c,v 1.18 2007/01/14 10:11:56 as Exp $ */ #include <stdio.h> @@ -57,6 +57,7 @@ #include "ocsp.h" #include "crl.h" #include "fetch.h" +#include "xauth.h" #include "sha1.h" #include "md5.h" @@ -628,6 +629,7 @@ main(int argc, char **argv) init_virtual_ip(virtual_private); #endif scx_init(pkcs11_module_path); /* load and initialize PKCS #11 module */ + xauth_init(); /* load and initialize XAUTH module */ init_rnd_pool(); init_secret(); init_states(); @@ -678,6 +680,7 @@ exit_pluto(int status) free_ocsp(); /* free ocsp cache */ free_ifaces(); scx_finalize(); /* finalize and unload PKCS #11 module */ + xauth_finalize(); /* finalize and unload XAUTH module */ stop_adns(); free_md_pool(); delete_lock(); diff --git a/programs/pluto/spdb.c b/programs/pluto/spdb.c index 0544a1da2..ab976511e 100644 --- a/programs/pluto/spdb.c +++ b/programs/pluto/spdb.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: spdb.c,v 1.9 2006/04/22 21:59:20 as Exp $ + * RCSID $Id: spdb.c,v 1.10 2007/01/10 00:36:19 as Exp $ */ #include <stdio.h> @@ -54,158 +54,26 @@ /**************** Oakely (main mode) SA database ****************/ -/* arrays of attributes for transforms, preshared key */ - -static struct db_attr otpsk1024des3md5[] = { - { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, - { OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 }, - { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY }, - { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 }, - }; - -static struct db_attr otpsk1536des3md5[] = { - { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, - { OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 }, - { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY }, - { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536 }, - }; - -static struct db_attr otpsk1024des3sha[] = { - { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, - { OAKLEY_HASH_ALGORITHM, OAKLEY_SHA }, - { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY }, - { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 }, - }; - -static struct db_attr otpsk1536des3sha[] = { - { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, - { OAKLEY_HASH_ALGORITHM, OAKLEY_SHA }, - { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY }, - { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536 }, - }; - -/* arrays of attributes for transforms, RSA signatures */ - -static struct db_attr otrsasig1024des3md5[] = { - { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, - { OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 }, - { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG }, - { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 }, - }; - -static struct db_attr otrsasig1536des3md5[] = { - { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, - { OAKLEY_HASH_ALGORITHM, OAKLEY_MD5 }, - { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG }, - { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536 }, - }; - -static struct db_attr otrsasig1024des3sha[] = { - { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, - { OAKLEY_HASH_ALGORITHM, OAKLEY_SHA }, - { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG }, - { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 }, - }; - -static struct db_attr otrsasig1536des3sha[] = { - { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, - { OAKLEY_HASH_ALGORITHM, OAKLEY_SHA }, - { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG }, - { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536 }, - }; - -/* We won't accept this, but by proposing it, we get to test - * our rejection. We better not propose it to an IKE daemon - * that will accept it! - */ -#ifdef TEST_INDECENT_PROPOSAL -static struct db_attr otpsk1024des3tiger[] = { - { OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC }, - { OAKLEY_HASH_ALGORITHM, OAKLEY_TIGER }, - { OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY }, - { OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024 }, - }; -#endif /* TEST_INDECENT_PROPOSAL */ - -/* tables of transforms, in preference order (select based on AUTH) */ - -static struct db_trans oakley_trans_psk[] = { -#ifdef TEST_INDECENT_PROPOSAL - { KEY_IKE, AD(otpsk1024des3tiger) }, -#endif - { KEY_IKE, AD(otpsk1536des3md5) }, - { KEY_IKE, AD(otpsk1536des3sha) }, - { KEY_IKE, AD(otpsk1024des3sha) }, - { KEY_IKE, AD(otpsk1024des3md5) }, - }; - -static struct db_trans oakley_trans_rsasig[] = { - { KEY_IKE, AD(otrsasig1536des3md5) }, - { KEY_IKE, AD(otrsasig1536des3sha) }, - { KEY_IKE, AD(otrsasig1024des3sha) }, - { KEY_IKE, AD(otrsasig1024des3md5) }, - }; - -/* In this table, either PSK or RSA sig is accepted. - * The order matters, but I don't know what would be best. - */ -static struct db_trans oakley_trans_pskrsasig[] = { -#ifdef TEST_INDECENT_PROPOSAL - { KEY_IKE, AD(otpsk1024des3tiger) }, -#endif - { KEY_IKE, AD(otrsasig1536des3md5) }, - { KEY_IKE, AD(otpsk1536des3md5) }, - { KEY_IKE, AD(otrsasig1536des3sha) }, - { KEY_IKE, AD(otpsk1536des3sha) }, - { KEY_IKE, AD(otrsasig1024des3sha) }, - { KEY_IKE, AD(otpsk1024des3sha) }, - { KEY_IKE, AD(otrsasig1024des3md5) }, - { KEY_IKE, AD(otpsk1024des3md5) }, - }; - /* array of proposals to be conjoined (can only be one for Oakley) */ -static struct db_prop oakley_pc_psk[] = - { { PROTO_ISAKMP, AD(oakley_trans_psk) } }; - -static struct db_prop oakley_pc_rsasig[] = - { { PROTO_ISAKMP, AD(oakley_trans_rsasig) } }; - -static struct db_prop oakley_pc_pskrsasig[] = - { { PROTO_ISAKMP, AD(oakley_trans_pskrsasig) } }; +static struct db_prop oakley_pc[] = + { { PROTO_ISAKMP, AD_NULL } }; /* array of proposal conjuncts (can only be one) */ -static struct db_prop_conj oakley_props_psk[] = { { AD(oakley_pc_psk) } }; +static struct db_prop_conj oakley_props[] = { { AD(oakley_pc) } }; -static struct db_prop_conj oakley_props_rsasig[] = { { AD(oakley_pc_rsasig) } }; - -static struct db_prop_conj oakley_props_pskrsasig[] = { { AD(oakley_pc_pskrsasig) } }; - -/* the sadb entry, subscripted by POLICY_PSK and POLICY_RSASIG bits */ -struct db_sa oakley_sadb[] = { - { AD_NULL }, /* none */ - { AD(oakley_props_psk) }, /* POLICY_PSK */ - { AD(oakley_props_rsasig) }, /* POLICY_RSASIG */ - { AD(oakley_props_pskrsasig) }, /* POLICY_PSK + POLICY_RSASIG */ - }; +/* the sadb entry */ +struct db_sa oakley_sadb = { AD(oakley_props) }; /**************** IPsec (quick mode) SA database ****************/ /* arrays of attributes for transforms */ -static struct db_attr espmd5_attr[] = { - { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_MD5 }, - }; - static struct db_attr espsha1_attr[] = { { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 }, }; -static struct db_attr ah_HMAC_MD5_attr[] = { - { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_MD5 }, - }; - static struct db_attr ah_HMAC_SHA1_attr[] = { { AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1 }, }; @@ -213,7 +81,6 @@ static struct db_attr ah_HMAC_SHA1_attr[] = { /* arrays of transforms, each in in preference order */ static struct db_trans espa_trans[] = { - { ESP_3DES, AD(espmd5_attr) }, { ESP_3DES, AD(espsha1_attr) }, }; @@ -223,13 +90,11 @@ static struct db_trans esp_trans[] = { #ifdef SUPPORT_ESP_NULL static struct db_trans espnull_trans[] = { - { ESP_NULL, AD(espmd5_attr) }, { ESP_NULL, AD(espsha1_attr) }, }; #endif /* SUPPORT_ESP_NULL */ static struct db_trans ah_trans[] = { - { AH_MD5, AD(ah_HMAC_MD5_attr) }, { AH_SHA, AD(ah_HMAC_SHA1_attr) }, }; @@ -452,7 +317,7 @@ out_sa(pb_stream *outs proposal.isap_spisize = oakley_mode ? 0 : p->protoid == PROTO_IPCOMP ? IPCOMP_CPI_SIZE : IPSEC_DOI_SPI_SIZE; - + /* In quick mode ONLY, create proposal for runtime kernel algos. * Replace ESP proposals with runtime created one */ @@ -503,7 +368,7 @@ out_sa(pb_stream *outs return_on(ret, FALSE); } } - + proposal.isap_notrans = p->trans_cnt; if (!out_struct(&proposal, &isakmp_proposal_desc, &sa_pbs, &proposal_pbs)) return_on(ret, FALSE); @@ -888,7 +753,9 @@ restore_pbs(pb_stream *pbs) * Parse an ISAKMP Proposal Payload for RSA and PSK authentication policies */ notification_t -parse_isakmp_policy(pb_stream *proposal_pbs, u_int notrans, lset_t *policy) +parse_isakmp_policy(pb_stream *proposal_pbs + , u_int notrans + , lset_t *policy) { int last_transnum = -1; @@ -945,6 +812,18 @@ parse_isakmp_policy(pb_stream *proposal_pbs, u_int notrans, lset_t *policy) case OAKLEY_RSA_SIG: *policy |= POLICY_RSASIG; break; + case XAUTHInitPreShared: + *policy |= POLICY_XAUTH_SERVER; + /* fall through */ + case XAUTHRespPreShared: + *policy |= POLICY_XAUTH_PSK; + break; + case XAUTHInitRSA: + *policy |= POLICY_XAUTH_SERVER; + /* fall through */ + case XAUTHRespRSA: + *policy |= POLICY_XAUTH_RSASIG; + break; default: break; } @@ -954,23 +833,35 @@ parse_isakmp_policy(pb_stream *proposal_pbs, u_int notrans, lset_t *policy) } } } + DBG(DBG_CONTROL|DBG_PARSING, + DBG_log("preparse_isakmp_policy: peer requests %s authentication" + , prettypolicy(*policy)) + ) + return NOTHING_WRONG; +} - if ((*policy & POLICY_PSK) && (*policy & POLICY_RSASIG)) - { - DBG(DBG_CONTROL|DBG_PARSING, - DBG_log("preparse_isakmp_policy: " - "peer supports both PSK and RSASIG authentication") - ) - *policy = LEMPTY; - } - else +/* + * check that we can find a preshared secret + */ +static err_t +find_preshared_key(struct state* st) +{ + err_t ugh = NULL; + struct connection *c = st->st_connection; + + if (get_preshared_secret(c) == NULL) { - DBG(DBG_CONTROL|DBG_PARSING, - DBG_log("preparse_isakmp_policy: peer requests %s authentication" - , (*policy & POLICY_PSK) ? "PSK":"RSASIG") - ) + char my_id[BUF_LEN], his_id[BUF_LEN]; + + idtoa(&c->spd.this.id, my_id, sizeof(my_id)); + if (his_id_was_instantiated(c)) + strcpy(his_id, "%any"); + else + idtoa(&c->spd.that.id, his_id, sizeof(his_id)); + ugh = builddiag("Can't authenticate: no preshared key found for `%s' and `%s'" + , my_id, his_id); } - return NOTHING_WRONG; + return ugh; } /* Parse the body of an ISAKMP SA Payload (i.e. Phase 1 / Main Mode). @@ -987,7 +878,8 @@ parse_isakmp_sa_body(u_int32_t ipsecdoisit , pb_stream *proposal_pbs , struct isakmp_proposal *proposal , pb_stream *r_sa_pbs - , struct state *st) + , struct state *st + , bool initiator) { struct connection *c = st->st_connection; unsigned no_trans_left; @@ -1093,6 +985,10 @@ parse_isakmp_sa_body(u_int32_t ipsecdoisit /* check that authentication method is acceptable */ lset_t iap = st->st_policy & POLICY_ID_AUTH_MASK; + /* is the initiator the XAUTH client? */ + bool xauth_init = initiator && (st->st_policy & POLICY_XAUTH_SERVER) == LEMPTY + || !initiator && (st->st_policy & POLICY_XAUTH_SERVER) != LEMPTY; + switch (val) { case OAKLEY_PRESHARED_KEY: @@ -1102,23 +998,30 @@ parse_isakmp_sa_body(u_int32_t ipsecdoisit } else { - /* check that we can find a preshared secret */ - struct connection *c = st->st_connection; - - if (get_preshared_secret(c) == NULL) - { - char mid[BUF_LEN] - , hid[BUF_LEN]; - - idtoa(&c->spd.this.id, mid, sizeof(mid)); - if (his_id_was_instantiated(c)) - strcpy(hid, "%any"); - else - idtoa(&c->spd.that.id, hid, sizeof(hid)); - ugh = builddiag("Can't authenticate: no preshared key found for `%s' and `%s'" - , mid, hid); - } - ta.auth = val; + ugh = find_preshared_key(st); + ta.auth = OAKLEY_PRESHARED_KEY; + } + break; + case XAUTHInitPreShared: + if ((iap & POLICY_XAUTH_PSK) == LEMPTY || !xauth_init) + { + ugh = "policy does not allow XAUTHInitPreShared authentication"; + } + else + { + ugh = find_preshared_key(st); + ta.auth = XAUTHInitPreShared; + } + break; + case XAUTHRespPreShared: + if ((iap & POLICY_XAUTH_PSK) == LEMPTY || xauth_init) + { + ugh = "policy does not allow XAUTHRespPreShared authentication"; + } + else + { + ugh = find_preshared_key(st); + ta.auth = XAUTHRespPreShared; } break; case OAKLEY_RSA_SIG: @@ -1129,18 +1032,29 @@ parse_isakmp_sa_body(u_int32_t ipsecdoisit } else { - /* We'd like to check that we can find a public - * key for him and a private key for us that is - * suitable, but we don't yet have his - * Id Payload, so it seems futile to try. - * We can assume that if he proposes it, he - * thinks we've got it. If we proposed it, - * perhaps we know what we're doing. - */ - ta.auth = val; + ta.auth = OAKLEY_RSA_SIG; + } + break; + case XAUTHInitRSA: + if ((iap & POLICY_XAUTH_RSASIG) == LEMPTY || !xauth_init) + { + ugh = "policy does not allow XAUTHInitRSA authentication"; + } + else + { + ta.auth = XAUTHInitRSA; + } + break; + case XAUTHRespRSA: + if ((iap & POLICY_XAUTH_RSASIG) == LEMPTY || xauth_init) + { + ugh = "policy does not allow XAUTHRespRSA authentication"; + } + else + { + ta.auth = XAUTHRespRSA; } break; - default: ugh = builddiag("Pluto does not support %s authentication" , enum_show(&oakley_auth_names, val)); @@ -1194,10 +1108,23 @@ parse_isakmp_sa_body(u_int32_t ipsecdoisit { case OAKLEY_LIFE_SECONDS: if (val > OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM) + { +#ifdef CISCO_QUIRKS + plog("peer requested %lu seconds" + " which exceeds our limit %d seconds" + , (long) val + , OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM); + plog("lifetime reduced to %d seconds " + "(todo: IPSEC_RESPONDER_LIFETIME notification)" + , OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM); + val = OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM; +#else ugh = builddiag("peer requested %lu seconds" " which exceeds our limit %d seconds" , (long) val , OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM); +#endif + } ta.life_seconds = val; break; case OAKLEY_LIFE_KILOBYTES: diff --git a/programs/pluto/spdb.h b/programs/pluto/spdb.h index 5eebf86cf..6cb92f036 100644 --- a/programs/pluto/spdb.h +++ b/programs/pluto/spdb.h @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: spdb.h,v 1.4 2006/04/22 21:59:20 as Exp $ + * RCSID $Id: spdb.h,v 1.5 2007/01/10 00:36:19 as Exp $ */ #ifndef _SPDB_H @@ -60,10 +60,8 @@ struct db_sa { */ }; -/* The oakley sadb is subscripted by a bitset with members - * from POLICY_PSK and POLICY_RSASIG. - */ -extern struct db_sa oakley_sadb[1 << 2]; +/* The oakley sadb */ +extern struct db_sa oakley_sadb; /* The ipsec sadb is subscripted by a bitset with members * from POLICY_ENCRYPT, POLICY_AUTHENTICATE, POLICY_COMPRESS @@ -90,14 +88,15 @@ extern notification_t preparse_isakmp_sa_body( extern notification_t parse_isakmp_policy( pb_stream *proposal_pbs, /* body of proposal Payload */ u_int notrans, /* number of transforms */ - lset_t *policy); /* RSA or PSK policy */ + lset_t *policy); /* RSA, PSK or XAUTH policy */ extern notification_t parse_isakmp_sa_body( u_int32_t ipsecdoisit, /* IPsec DOI SIT bitset */ pb_stream *proposal_pbs, /* body of proposal Payload */ struct isakmp_proposal *proposal, pb_stream *r_sa_pbs, /* if non-NULL, where to emit winning SA */ - struct state *st); /* current state object */ + struct state *st, /* current state object */ + bool initiator); /* is caller initiator? */ extern notification_t parse_ipsec_sa_body( pb_stream *sa_pbs, /* body of input SA Payload */ diff --git a/programs/pluto/state.h b/programs/pluto/state.h index c7212fd1a..d885d145d 100644 --- a/programs/pluto/state.h +++ b/programs/pluto/state.h @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: state.h,v 1.12 2006/10/17 10:30:54 as Exp $ + * RCSID $Id: state.h,v 1.13 2007/01/10 00:36:19 as Exp $ */ #include <sys/types.h> @@ -212,7 +212,13 @@ struct state bool vars_set; bool started; } st_modecfg; - + + struct { + int attempt; + bool started; + bool status; + } st_xauth; + #ifdef NAT_TRAVERSAL u_int32_t nat_traversal; ip_address nat_oa; diff --git a/programs/pluto/vendor.c b/programs/pluto/vendor.c index cbb26a5ef..3e2e0768a 100644 --- a/programs/pluto/vendor.c +++ b/programs/pluto/vendor.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: vendor.c,v 1.41 2006/10/19 15:21:08 as Exp $ + * RCSID $Id: vendor.c,v 1.43 2007/01/10 00:31:36 as Exp $ */ #include <stdlib.h> @@ -164,6 +164,9 @@ static struct vid_struct _vid_tab[] = { { VID_CISCO3K, VID_KEEP | VID_SUBSTRING_MATCH, NULL, "Cisco VPN 3000 Series" , "\x1f\x07\xf7\x0e\xaa\x65\x14\xd3\xb0\xfa\x96\x54\x2a\x50", 14}, + { VID_CISCO_IOS, VID_KEEP | VID_SUBSTRING_MATCH, + NULL, "Cisco IOS Device", "\x3e\x98\x40\x48", 4}, + /* * Timestep VID seen: * - 54494d455354455020312053475720313532302033313520322e303145303133 @@ -204,8 +207,10 @@ static struct vid_struct _vid_tab[] = { DEC_MD5_VID(STRONGSWAN_4_0_3, "strongSwan 4.0.3") DEC_MD5_VID(STRONGSWAN_4_0_4, "strongSwan 4.0.4") DEC_MD5_VID(STRONGSWAN_4_0_5, "strongSwan 4.0.5") + DEC_MD5_VID(STRONGSWAN_4_0_6, "strongSwan 4.0.6") - DEC_MD5_VID(STRONGSWAN, "strongSwan 2.8.0") + DEC_MD5_VID(STRONGSWAN, "strongSwan 2.8.1") + DEC_MD5_VID(STRONGSWAN_2_8_0, "strongSwan 2.8.0") DEC_MD5_VID(STRONGSWAN_2_7_3, "strongSwan 2.7.3") DEC_MD5_VID(STRONGSWAN_2_7_2, "strongSwan 2.7.2") DEC_MD5_VID(STRONGSWAN_2_7_1, "strongSwan 2.7.1") @@ -260,6 +265,12 @@ static struct vid_struct _vid_tab[] = { DEC_MD5_VID(INITIAL_CONTACT, "Vid-Initial-Contact") + /** + * Cisco VPN 3000 + */ + { VID_MISC_FRAGMENTATION, VID_MD5HASH | VID_SUBSTRING_DUMPHEXA, + "FRAGMENTATION", NULL, NULL, 0 }, + /* -- */ { 0, 0, NULL, NULL, NULL, 0 } @@ -386,6 +397,9 @@ handle_known_vendorid (struct msg_digest *md md->dpd = TRUE; vid_useful = TRUE; break; + case VID_MISC_XAUTH: + vid_useful = TRUE; + break; default: break; } diff --git a/programs/pluto/vendor.h b/programs/pluto/vendor.h index c7f70a480..060311b92 100644 --- a/programs/pluto/vendor.h +++ b/programs/pluto/vendor.h @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: vendor.h,v 1.36 2006/10/19 15:21:08 as Exp $ + * RCSID $Id: vendor.h,v 1.38 2007/01/10 00:31:36 as Exp $ */ #ifndef _VENDOR_H_ @@ -45,41 +45,43 @@ enum known_vendorid { VID_SSH_IPSEC_4_2_0 = 24, VID_CISCO_UNITY = 25, VID_CISCO3K = 26, - VID_TIMESTEP = 27, - VID_SAFENET = 28, - VID_MACOSX = 29, - VID_OPENSWAN2 = 30, - VID_NCP_SERVER = 31, - VID_NCP_CLIENT = 32, - VID_STRONGSWAN = 33, - VID_STRONGSWAN_2_2_0 = 34, - VID_STRONGSWAN_2_2_1 = 35, - VID_STRONGSWAN_2_2_2 = 36, - VID_STRONGSWAN_2_3_0 = 37, - VID_STRONGSWAN_2_3_1 = 38, - VID_STRONGSWAN_2_3_2 = 39, - VID_STRONGSWAN_2_4_0 = 40, - VID_STRONGSWAN_2_4_1 = 41, - VID_STRONGSWAN_2_4_2 = 42, - VID_STRONGSWAN_2_4_3 = 43, - VID_STRONGSWAN_2_4_4 = 44, - VID_STRONGSWAN_2_5_0 = 45, - VID_STRONGSWAN_2_5_1 = 46, - VID_STRONGSWAN_2_5_2 = 47, - VID_STRONGSWAN_2_5_3 = 48, - VID_STRONGSWAN_2_5_4 = 49, - VID_STRONGSWAN_2_5_5 = 50, - VID_STRONGSWAN_2_5_6 = 51, - VID_STRONGSWAN_2_5_7 = 52, - VID_STRONGSWAN_2_6_0 = 53, - VID_STRONGSWAN_2_6_1 = 54, - VID_STRONGSWAN_2_6_2 = 55, - VID_STRONGSWAN_2_6_3 = 56, - VID_STRONGSWAN_2_6_4 = 57, - VID_STRONGSWAN_2_7_0 = 58, - VID_STRONGSWAN_2_7_1 = 59, - VID_STRONGSWAN_2_7_2 = 60, - VID_STRONGSWAN_2_7_3 = 61, + VID_CISCO_IOS = 27, + VID_TIMESTEP = 28, + VID_SAFENET = 29, + VID_MACOSX = 30, + VID_OPENSWAN2 = 31, + VID_NCP_SERVER = 32, + VID_NCP_CLIENT = 33, + VID_STRONGSWAN = 34, + VID_STRONGSWAN_2_2_0 = 35, + VID_STRONGSWAN_2_2_1 = 36, + VID_STRONGSWAN_2_2_2 = 37, + VID_STRONGSWAN_2_3_0 = 38, + VID_STRONGSWAN_2_3_1 = 39, + VID_STRONGSWAN_2_3_2 = 40, + VID_STRONGSWAN_2_4_0 = 41, + VID_STRONGSWAN_2_4_1 = 42, + VID_STRONGSWAN_2_4_2 = 43, + VID_STRONGSWAN_2_4_3 = 44, + VID_STRONGSWAN_2_4_4 = 45, + VID_STRONGSWAN_2_5_0 = 46, + VID_STRONGSWAN_2_5_1 = 47, + VID_STRONGSWAN_2_5_2 = 48, + VID_STRONGSWAN_2_5_3 = 49, + VID_STRONGSWAN_2_5_4 = 50, + VID_STRONGSWAN_2_5_5 = 51, + VID_STRONGSWAN_2_5_6 = 52, + VID_STRONGSWAN_2_5_7 = 53, + VID_STRONGSWAN_2_6_0 = 54, + VID_STRONGSWAN_2_6_1 = 55, + VID_STRONGSWAN_2_6_2 = 56, + VID_STRONGSWAN_2_6_3 = 57, + VID_STRONGSWAN_2_6_4 = 58, + VID_STRONGSWAN_2_7_0 = 59, + VID_STRONGSWAN_2_7_1 = 60, + VID_STRONGSWAN_2_7_2 = 61, + VID_STRONGSWAN_2_7_3 = 62, + VID_STRONGSWAN_2_8_0 = 63, VID_STRONGSWAN_4_0_0 = 70, VID_STRONGSWAN_4_0_1 = 71, @@ -87,6 +89,7 @@ enum known_vendorid { VID_STRONGSWAN_4_0_3 = 73, VID_STRONGSWAN_4_0_4 = 74, VID_STRONGSWAN_4_0_5 = 75, + VID_STRONGSWAN_4_0_6 = 76, /* 101 - 200 : NAT-Traversal */ VID_NATT_STENBERG_01 =101, @@ -104,7 +107,8 @@ enum known_vendorid { VID_MISC_DPD =202, VID_MISC_HEARTBEAT_NOTIFY =203, VID_MISC_FRAGMENTATION =204, - VID_INITIAL_CONTACT =205 + VID_INITIAL_CONTACT =205, + VID_CISCO3K_FRAGMENTATION =206 }; void init_vendorid(void); diff --git a/programs/pluto/xauth.c b/programs/pluto/xauth.c new file mode 100644 index 000000000..c33ad9b3d --- /dev/null +++ b/programs/pluto/xauth.c @@ -0,0 +1,77 @@ +/* Initialization and finalization of the dynamic XAUTH module + * Copyright (C) 2006 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * RCSID $Id: xauth.c,v 1.1 2007/01/11 21:48:41 as Exp $ + */ + +#include <dlfcn.h> + +#include <freeswan.h> + +#include "constants.h" +#include "defs.h" +#include "xauth.h" +#include "keys.h" +#include "log.h" + +void +xauth_init(void) +{ +#ifdef XAUTH_DEFAULT_LIB + xauth_module.handle = dlopen(XAUTH_DEFAULT_LIB, RTLD_NOW); + + if (xauth_module.handle != NULL) + { + DBG(DBG_CONTROL, + DBG_log("xauth module '%s' loading'", XAUTH_DEFAULT_LIB) + ) + xauth_module.get_secret = (bool (*) (const xauth_t*)) + dlsym(xauth_module.handle, "get_secret"); + DBG(DBG_CONTROL, + if (xauth_module.get_secret != NULL) + { + DBG_log("xauth module: found get_secret() function"); + } + ) + xauth_module.verify_secret = (bool (*) (const xauth_t*)) + dlsym(xauth_module.handle, "verify_secret"); + DBG(DBG_CONTROL, + if (xauth_module.verify_secret != NULL) + { + DBG_log("xauth module: found verify_secret() function"); + } + ) + } +#endif + /* any null function pointers will be filled in by default functions */ + xauth_defaults(); +} + +void +xauth_finalize(void) +{ + if (xauth_module.handle != NULL) + { + if (dlclose(xauth_module.handle)) + { + plog("failed to unload xauth module"); + } + else + { + DBG(DBG_CONTROL, + DBG_log("xauth module unloaded") + ) + } + } +} diff --git a/programs/pluto/xauth.h b/programs/pluto/xauth.h new file mode 100644 index 000000000..371e443ef --- /dev/null +++ b/programs/pluto/xauth.h @@ -0,0 +1,41 @@ +/* Interface definition of the XAUTH server and|or client module + * Copyright (C) 2006 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * RCSID $Id: xauth.h,v 1.1 2007/01/11 21:48:41 as Exp $ + */ + +#ifndef _XAUTH_H +#define _XAUTH_H + +/* XAUTH credentials */ + +struct chunk_t; + +typedef struct { + chunk_t user_name; + chunk_t user_password; +} xauth_t; + +typedef struct { + void *handle; + bool (*get_secret) (xauth_t *xauth_secret); + bool (*verify_secret) (const xauth_t *xauth_secret); +} xauth_module_t; + +extern xauth_module_t xauth_module; + +extern void xauth_init(void); +extern void xauth_finalize(void); + +#endif /* _XAUTH_H */ diff --git a/programs/starter/args.c b/programs/starter/args.c index 2b2853a20..9dece2dfb 100644 --- a/programs/starter/args.c +++ b/programs/starter/args.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: args.c,v 1.10 2006/10/19 14:58:30 as Exp $ + * RCSID $Id: args.c,v 1.11 2007/01/11 21:27:27 as Exp $ */ #include <stddef.h> @@ -192,6 +192,7 @@ static const token_info_t token_info[] = { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL }, { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action }, { ARG_MISC, 0, NULL /* KW_MODECONFIG */ }, + { ARG_MISC, 0, NULL /* KW_XAUTH */ }, /* ca section keywords */ { ARG_STR, offsetof(starter_ca_t, name), NULL }, diff --git a/programs/starter/confread.c b/programs/starter/confread.c index edd041ab4..63010685b 100644 --- a/programs/starter/confread.c +++ b/programs/starter/confread.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: confread.c,v 1.39 2006/10/19 14:58:30 as Exp $ + * RCSID $Id: confread.c,v 1.40 2007/01/11 21:27:27 as Exp $ */ #include <stddef.h> @@ -418,7 +418,7 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) KW_POLICY_FLAG("ah", "esp", POLICY_AUTHENTICATE) break; case KW_AUTHBY: - conn->policy &= ~(POLICY_RSASIG | POLICY_PSK | POLICY_ENCRYPT); + conn->policy &= ~(POLICY_ID_AUTH_MASK | POLICY_ENCRYPT); if (strcmp(kw->value, "never") != 0) { @@ -433,8 +433,12 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) { if (streq(value, "rsasig")) conn->policy |= POLICY_RSASIG | POLICY_ENCRYPT; - else if (streq(value, "secret")) + else if (streq(value, "secret") || streq(value, "psk")) conn->policy |= POLICY_PSK | POLICY_ENCRYPT; + else if (streq(value, "xauthrsasig")) + conn->policy |= POLICY_XAUTH_RSASIG | POLICY_ENCRYPT; + else if (streq(value, "xauthpsk")) + conn->policy |= POLICY_XAUTH_PSK | POLICY_ENCRYPT; else { plog("# bad policy value: %s=%s", kw->entry->name, kw->value); @@ -454,6 +458,9 @@ load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg) case KW_MODECONFIG: KW_POLICY_FLAG("push", "pull", POLICY_MODECFG_PUSH) break; + case KW_XAUTH: + KW_POLICY_FLAG("server", "client", POLICY_XAUTH_SERVER) + break; default: break; } diff --git a/programs/starter/keywords.c b/programs/starter/keywords.c index 75be0a542..b06ee3c0c 100644 --- a/programs/starter/keywords.c +++ b/programs/starter/keywords.c @@ -44,7 +44,7 @@ error "gperf generated tables don't work with this execution character set. Plea * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: keywords.c,v 1.8 2006/10/19 14:58:30 as Exp $ + * RCSID $Id: keywords.c,v 1.9 2007/01/11 21:29:28 as Exp $ */ #include <string.h> @@ -56,7 +56,7 @@ struct kw_entry { kw_token_t token; }; -#define TOTAL_KEYWORDS 80 +#define TOTAL_KEYWORDS 81 #define MIN_WORD_LENGTH 3 #define MAX_WORD_LENGTH 17 #define MIN_HASH_VALUE 9 @@ -87,7 +87,7 @@ hash (str, len) 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 90, 157, 60, - 50, 25, 0, 10, 5, 65, 157, 65, 70, 5, + 50, 25, 0, 10, 30, 65, 157, 65, 70, 5, 0, 75, 35, 157, 10, 20, 5, 70, 157, 157, 157, 55, 0, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, @@ -114,7 +114,7 @@ static const struct kw_entry wordlist[] = {"leftupdown", KW_LEFTUPDOWN}, {""}, {""}, {"leftcert", KW_LEFTCERT,}, - {"auth", KW_AUTH}, + {""}, {"leftsubnet", KW_LEFTSUBNET}, {"leftsubnetwithin", KW_LEFTSUBNETWITHIN}, {"leftsendcert", KW_LEFTSENDCERT}, @@ -135,7 +135,9 @@ static const struct kw_entry wordlist[] = {"compress", KW_COMPRESS}, {"lefthostaccess", KW_LEFTHOSTACCESS}, {"interfaces", KW_INTERFACES}, - {""}, {""}, {""}, {""}, {""}, + {""}, {""}, {""}, + {"auth", KW_AUTH}, + {""}, {"rightgroups", KW_RIGHTGROUPS}, {""}, {"pfs", KW_PFS}, @@ -198,7 +200,7 @@ static const struct kw_entry wordlist[] = {"crluri2", KW_CRLURI2}, {"ldaphost", KW_LDAPHOST}, {"postpluto", KW_POSTPLUTO}, - {""}, + {"xauth", KW_XAUTH}, {"overridemtu", KW_OVERRIDEMTU}, {"rightca", KW_RIGHTCA}, {"prepluto", KW_PREPLUTO}, diff --git a/programs/starter/keywords.h b/programs/starter/keywords.h index be3aabf3b..4356b4947 100644 --- a/programs/starter/keywords.h +++ b/programs/starter/keywords.h @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: keywords.h,v 1.9 2006/10/19 14:57:56 as Exp $ + * RCSID $Id: keywords.h,v 1.10 2007/01/11 21:27:27 as Exp $ */ #ifndef _KEYWORDS_H_ @@ -77,9 +77,10 @@ typedef enum { KW_DPDTIMEOUT, KW_DPDACTION, KW_MODECONFIG, + KW_XAUTH, #define KW_CONN_FIRST KW_CONN_SETUP -#define KW_CONN_LAST KW_MODECONFIG +#define KW_CONN_LAST KW_XAUTH /* ca section keywords */ KW_CA_NAME, diff --git a/programs/starter/keywords.txt b/programs/starter/keywords.txt index fc9e49e47..6ad2d5fce 100644 --- a/programs/starter/keywords.txt +++ b/programs/starter/keywords.txt @@ -13,7 +13,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: keywords.txt,v 1.7 2006/10/19 14:57:56 as Exp $ + * RCSID $Id: keywords.txt,v 1.8 2007/01/11 21:27:51 as Exp $ */ #include <string.h> @@ -66,6 +66,7 @@ dpddelay, KW_DPDDELAY dpdtimeout, KW_DPDTIMEOUT dpdaction, KW_DPDACTION modeconfig, KW_MODECONFIG +xauth, KW_XAUTH cacert, KW_CACERT ldaphost, KW_LDAPHOST ldapbase, KW_LDAPBASE |