diff options
Diffstat (limited to 'programs/pluto')
-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 |
21 files changed, 1351 insertions, 488 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 */ |