aboutsummaryrefslogtreecommitdiffstats
path: root/src/pluto/ipsec_doi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pluto/ipsec_doi.c')
-rw-r--r--src/pluto/ipsec_doi.c279
1 files changed, 134 insertions, 145 deletions
diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c
index 9d5b1cfc9..45538b13f 100644
--- a/src/pluto/ipsec_doi.c
+++ b/src/pluto/ipsec_doi.c
@@ -35,12 +35,14 @@
#include <crypto/rngs/rng.h>
#include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h>
+#include <utils/identification.h>
#include "constants.h"
#include "defs.h"
+#include "myid.h"
#include "state.h"
-#include "id.h"
#include "x509.h"
+#include "ac.h"
#include "crl.h"
#include "ca.h"
#include "certs.h"
@@ -1569,7 +1571,7 @@ static bool take_a_crack(struct tac_state *s, pubkey_t *kr)
}
}
-static stf_status check_signature(key_type_t key_type, const struct id* peer,
+static stf_status check_signature(key_type_t key_type, identification_t* peer,
struct state *st, chunk_t hash,
const pb_stream *sig_pbs,
#ifdef USE_KEYRR
@@ -1593,7 +1595,8 @@ static stf_status check_signature(key_type_t key_type, const struct id* peer,
for (gw = c->gw_info; gw != NULL; gw = gw->next)
{
/* only consider entries that have a key and are for our peer */
- if (gw->gw_key_present && same_id(&gw->gw_id, &c->spd.that.id)&&
+ if (gw->gw_key_present &&
+ gw->gw_id->equals(gw->gw_id, c->spd.that.id) &&
take_a_crack(&s, gw->key))
{
return STF_OK;
@@ -1611,11 +1614,8 @@ static stf_status check_signature(key_type_t key_type, const struct id* peer,
{
pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_key);
- struct id key_id;
- id_from_identification(&key_id, key->id);
-
- if (type == key_type && same_id(peer, &key_id))
+ if (type == key_type && peer->equals(peer, key->id))
{
time_t now = time(NULL);
@@ -1678,31 +1678,27 @@ static stf_status check_signature(key_type_t key_type, const struct id* peer,
/* no acceptable key was found: diagnose */
{
- char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */
-
- idtoa(peer, id_buf, sizeof(id_buf));
-
if (s.tried_cnt == 0)
{
- loglog(RC_LOG_SERIOUS, "no public key known for '%s'", id_buf);
+ loglog(RC_LOG_SERIOUS, "no public key known for '%Y'", peer);
}
else if (s.tried_cnt == 1)
{
- loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: "
- " wrong key?; tried %d", id_buf, s.tried_cnt);
+ loglog(RC_LOG_SERIOUS, "signature check for '%Y' failed: "
+ " wrong key?; tried %d", peer, s.tried_cnt);
DBG(DBG_CONTROL,
- DBG_log("public key for '%s' failed: "
- "decrypted SIG payload into a malformed ECB", id_buf)
+ DBG_log("public key for '%Y' failed: "
+ "decrypted SIG payload into a malformed ECB", peer)
)
}
else
{
- loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: "
- "tried %d keys but none worked.", id_buf, s.tried_cnt);
+ loglog(RC_LOG_SERIOUS, "signature check for '%Y' failed: "
+ "tried %d keys but none worked.", peer, s.tried_cnt);
DBG(DBG_CONTROL,
- DBG_log("all %d public keys for '%s' failed: "
+ DBG_log("all %d public keys for '%Y' failed: "
"best decrypted SIG payload into a malformed ECB",
- s.tried_cnt, id_buf)
+ s.tried_cnt, peer)
)
}
return STF_FAIL + INVALID_KEY_INFORMATION;
@@ -2198,16 +2194,17 @@ static void decode_cert(struct msg_digest *md)
}
else if (cert->isacert_type == CERT_PKCS7_WRAPPED_X509)
{
- x509cert_t *x509cert = NULL;
+ linked_list_t *certs = linked_list_create();
- if (pkcs7_parse_signedData(blob, NULL, &x509cert, NULL, NULL))
+ if (pkcs7_parse_signedData(blob, NULL, certs, NULL, NULL))
{
- store_x509certs(&x509cert, strict_crl_policy);
+ store_x509certs(certs, strict_crl_policy);
}
else
{
plog("Syntax error in PKCS#7 wrapped X.509 certificates");
}
+ certs->destroy_offset(certs, offsetof(certificate_t, destroy));
}
else
{
@@ -2276,12 +2273,13 @@ static void decode_cr(struct msg_digest *md, connection_t *c)
* We must be called before SIG or HASH are decoded since we
* may change the peer's public key or ID.
*/
-static bool decode_peer_id(struct msg_digest *md, struct id *peer)
+static bool decode_peer_id(struct msg_digest *md, identification_t **peer)
{
struct state *const st = md->st;
struct payload_digest *const id_pld = md->chain[ISAKMP_NEXT_ID];
const pb_stream *const id_pbs = &id_pld->pbs;
struct isakmp_id *const id = &id_pld->payload.id;
+ chunk_t id_payload;
/* I think that RFC2407 (IPSEC DOI) 4.6.2 is confused.
* It talks about the protocol ID and Port fields of the ID
@@ -2310,74 +2308,50 @@ static bool decode_peer_id(struct msg_digest *md, struct id *peer)
return FALSE;
}
- peer->kind = id->isaid_idtype;
+ id_payload = chunk_create(id_pbs->cur, pbs_left(id_pbs));
- switch (peer->kind)
+ switch (id->isaid_idtype)
{
- case ID_IPV4_ADDR:
- case ID_IPV6_ADDR:
- /* failure mode for initaddr is probably inappropriate address length */
- {
- err_t ugh = initaddr(id_pbs->cur, pbs_left(id_pbs)
- , peer->kind == ID_IPV4_ADDR? AF_INET : AF_INET6
- , &peer->ip_addr);
-
- if (ugh != NULL)
+ case ID_IPV4_ADDR:
+ if (id_payload.len != 4)
{
- loglog(RC_LOG_SERIOUS, "improper %s identification payload: %s"
- , enum_show(&ident_names, peer->kind), ugh);
- /* XXX Could send notification back */
+ loglog(RC_LOG_SERIOUS, "improper %s Phase 1 ID payload",
+ enum_show(&ident_names, id->isaid_idtype));
return FALSE;
}
- }
- break;
-
- case ID_USER_FQDN:
- if (memchr(id_pbs->cur, '@', pbs_left(id_pbs)) == NULL)
- {
- loglog(RC_LOG_SERIOUS, "peer's ID_USER_FQDN contains no @");
- return FALSE;
- }
- /* FALLTHROUGH */
- case ID_FQDN:
- if (memchr(id_pbs->cur, '\0', pbs_left(id_pbs)) != NULL)
- {
- loglog(RC_LOG_SERIOUS, "Phase 1 ID Payload of type %s contains a NUL"
- , enum_show(&ident_names, peer->kind));
+ break;
+ case ID_IPV6_ADDR:
+ if (id_payload.len != 16)
+ {
+ loglog(RC_LOG_SERIOUS, "improper %s Phase 1 ID payload",
+ enum_show(&ident_names, id->isaid_idtype));
+ return FALSE;
+ }
+ break;
+ case ID_USER_FQDN:
+ case ID_FQDN:
+ if (memchr(id_payload.ptr, '\0', id_payload.len) != NULL)
+ {
+ loglog(RC_LOG_SERIOUS, "%s Phase 1 ID payload contains "
+ "a NUL character",
+ enum_show(&ident_names, id->isaid_idtype));
+ return FALSE;
+ }
+ break;
+ case ID_KEY_ID:
+ case ID_DER_ASN1_DN:
+ break;
+ default:
+ /* XXX Could send notification back */
+ loglog(RC_LOG_SERIOUS, "unacceptable identity type (%s) "
+ "in Phase 1 ID payload",
+ enum_show(&ident_names, id->isaid_idtype));
return FALSE;
- }
-
- /* ??? ought to do some more sanity check, but what? */
-
- peer->name = chunk_create(id_pbs->cur, pbs_left(id_pbs));
- break;
-
- case ID_KEY_ID:
- peer->name = chunk_create(id_pbs->cur, pbs_left(id_pbs));
- DBG(DBG_PARSING,
- DBG_dump_chunk("KEY ID:", peer->name));
- break;
-
- case ID_DER_ASN1_DN:
- peer->name = chunk_create(id_pbs->cur, pbs_left(id_pbs));
- DBG(DBG_PARSING,
- DBG_dump_chunk("DER ASN1 DN:", peer->name));
- break;
-
- default:
- /* XXX Could send notification back */
- loglog(RC_LOG_SERIOUS, "Unacceptable identity type (%s) in Phase 1 ID Payload"
- , enum_show(&ident_names, peer->kind));
- return FALSE;
}
+ *peer = identification_create_from_encoding(id->isaid_idtype, id_payload);
- {
- char buf[BUF_LEN];
-
- idtoa(peer, buf, sizeof(buf));
- plog("Peer ID is %s: '%s'",
- enum_show(&ident_names, id->isaid_idtype), buf);
- }
+ plog("Peer ID is %s: '%Y'", enum_show(&ident_names, id->isaid_idtype),
+ *peer);
/* check for certificates */
decode_cert(md);
@@ -2390,7 +2364,7 @@ static bool decode_peer_id(struct msg_digest *md, struct id *peer)
* - if the initiation was explicit, we'd be ignoring user's intent
* - if opportunistic, we'll lose our HOLD info
*/
-static bool switch_connection(struct msg_digest *md, struct id *peer,
+static bool switch_connection(struct msg_digest *md, identification_t *peer,
bool initiator)
{
struct state *const st = md->st;
@@ -2415,16 +2389,11 @@ static bool switch_connection(struct msg_digest *md, struct id *peer,
{
int pathlen;
- if (!same_id(&c->spd.that.id, peer))
+ if (!peer->equals(peer, c->spd.that.id))
{
- char expect[BUF_LEN]
- , found[BUF_LEN];
-
- idtoa(&c->spd.that.id, expect, sizeof(expect));
- idtoa(peer, found, sizeof(found));
- loglog(RC_LOG_SERIOUS
- , "we require peer to have ID '%s', but peer declares '%s'"
- , expect, found);
+ loglog(RC_LOG_SERIOUS,
+ "we require peer to have ID '%Y', but peer declares '%Y'",
+ c->spd.that.id, peer);
return FALSE;
}
@@ -2467,10 +2436,7 @@ static bool switch_connection(struct msg_digest *md, struct id *peer,
if (r == NULL)
{
- char buf[BUF_LEN];
-
- idtoa(peer, buf, sizeof(buf));
- loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%s'", buf);
+ loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%Y'", peer);
return FALSE;
}
@@ -2509,10 +2475,9 @@ static bool switch_connection(struct msg_digest *md, struct id *peer,
}
else if (c->spd.that.has_id_wildcards)
{
- free_id_content(&c->spd.that.id);
- c->spd.that.id = *peer;
+ c->spd.that.id->destroy(c->spd.that.id);
+ c->spd.that.id = peer->clone(peer);
c->spd.that.has_id_wildcards = FALSE;
- unshare_id_content(&c->spd.that.id);
}
}
return TRUE;
@@ -2736,10 +2701,9 @@ static bool has_preloaded_public_key(struct state *st)
{
pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_key);
- struct id key_id;
- id_from_identification(&key_id, key->id);
- if (type == KEY_RSA && same_id(&c->spd.that.id, &key_id) &&
+ if (type == KEY_RSA &&
+ c->spd.that.id->equals(c->spd.that.id, key->id) &&
key->until_time == UNDEFINED_TIME)
{
/* found a preloaded public key */
@@ -2937,6 +2901,38 @@ static bool uses_pubkey_auth(int auth)
}
}
+/* build an ID payload
+ * Note: no memory is allocated for the body of the payload (tl->ptr).
+ * We assume it will end up being a pointer into a sufficiently
+ * stable datastructure. It only needs to last a short time.
+ */
+static void build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end)
+{
+ identification_t *id = resolve_myid(end->id);
+
+ zero(hd);
+ hd->isaiid_idtype = id->get_type(id);
+
+ switch (id->get_type(id))
+ {
+ case ID_ANY:
+ hd->isaiid_idtype = aftoinfo(addrtypeof(&end->host_addr))->id_addr;
+ tl->len = addrbytesptr(&end->host_addr,
+ (const unsigned char **)&tl->ptr); /* sets tl->ptr too */
+ break;
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ case ID_FQDN:
+ case ID_USER_FQDN:
+ case ID_DER_ASN1_DN:
+ case ID_KEY_ID:
+ *tl = id->get_encoding(id);
+ break;
+ default:
+ bad_case(id->get_type(id));
+ }
+}
+
/* State Transition Functions.
*
* The definition of state_microcode_table in demux.c is a good
@@ -3066,7 +3062,7 @@ stf_status main_inI1_outR1(struct msg_digest *md)
/* 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);
+ c = rw_instantiate(c, &md->sender, md->sender_port, NULL, c->spd.that.id);
}
/* Set up state */
@@ -3727,13 +3723,10 @@ struct key_continuation {
typedef stf_status (key_tail_fn)(struct msg_digest *md
, struct key_continuation *kc);
-static void report_key_dns_failure(struct id *id, err_t ugh)
+static void report_key_dns_failure(identification_t *id, err_t ugh)
{
- char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */
-
- (void) idtoa(id, id_buf, sizeof(id_buf));
- loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'"
- "; DNS search for KEY failed (%s)", id_buf, ugh);
+ loglog(RC_LOG_SERIOUS, "no RSA public key known for '%Y'"
+ "; DNS search for KEY failed (%s)", id, ugh);
}
@@ -3753,12 +3746,14 @@ main_id_and_auth(struct msg_digest *md
{
chunk_t hash = chunk_alloca(MAX_DIGEST_LEN);
struct state *st = md->st;
- struct id peer;
+ identification_t *peer;
stf_status r = STF_OK;
/* ID Payload in */
if (!decode_peer_id(md, &peer))
+ {
return STF_FAIL + INVALID_ID_INFORMATION;
+ }
/* Hash the ID Payload.
* main_mode_hash requires idpl->cur to be at end of payload
@@ -3796,12 +3791,12 @@ main_id_and_auth(struct msg_digest *md
case OAKLEY_RSA_SIG:
case XAUTHInitRSA:
case XAUTHRespRSA:
- r = check_signature(KEY_RSA, &peer, st, hash,
- &md->chain[ISAKMP_NEXT_SIG]->pbs,
+ r = check_signature(KEY_RSA, peer, st, hash,
+ &md->chain[ISAKMP_NEXT_SIG]->pbs,
#ifdef USE_KEYRR
- kc == NULL? NULL : kc->ac.keys_from_dns,
+ kc == NULL ? NULL : kc->ac.keys_from_dns,
#endif /* USE_KEYRR */
- kc == NULL? NULL : kc->ac.gateways_from_dns
+ kc == NULL ? NULL : kc->ac.gateways_from_dns
);
if (r == STF_SUSPEND)
@@ -3826,22 +3821,14 @@ main_id_and_auth(struct msg_digest *md
#ifdef USE_KEYRR
nkc->failure_ok = TRUE;
#endif
- ugh = start_adns_query(&peer
- , &peer /* SG itself */
- , T_TXT
- , cont_fn
- , &nkc->ac);
+ ugh = start_adns_query(peer, peer, T_TXT, cont_fn, &nkc->ac);
break;
#ifdef USE_KEYRR
case kos_his_txt:
/* second try: look for the KEY records */
nkc->step = kos_his_key;
- ugh = start_adns_query(&peer
- , NULL /* no sgw for KEY */
- , T_KEY
- , cont_fn
- , &nkc->ac);
+ ugh = start_adns_query(peer, NULL, T_KEY, cont_fn, &nkc->ac);
break;
#endif /* USE_KEYRR */
@@ -3851,7 +3838,7 @@ main_id_and_auth(struct msg_digest *md
if (ugh != NULL)
{
- report_key_dns_failure(&peer, ugh);
+ report_key_dns_failure(peer, ugh);
st->st_suspended_md = NULL;
r = STF_FAIL + INVALID_KEY_INFORMATION;
}
@@ -3861,7 +3848,7 @@ main_id_and_auth(struct msg_digest *md
case OAKLEY_ECDSA_256:
case OAKLEY_ECDSA_384:
case OAKLEY_ECDSA_521:
- r = check_signature(KEY_ECDSA, &peer, st, hash,
+ r = check_signature(KEY_ECDSA, peer, st, hash,
&md->chain[ISAKMP_NEXT_SIG]->pbs,
#ifdef USE_KEYRR
NULL,
@@ -3874,6 +3861,7 @@ main_id_and_auth(struct msg_digest *md
}
if (r != STF_OK)
{
+ peer->destroy(peer);
return r;
}
DBG(DBG_CRYPT, DBG_log("authentication succeeded"));
@@ -3881,10 +3869,11 @@ main_id_and_auth(struct msg_digest *md
/*
* With the peer ID known, let's see if we need to switch connections.
*/
- if (!switch_connection(md, &peer, initiator))
+ if (!switch_connection(md, peer, initiator))
{
- return STF_FAIL + INVALID_ID_INFORMATION;
+ r = STF_FAIL + INVALID_ID_INFORMATION;
}
+ peer->destroy(peer);
return r;
}
@@ -3928,7 +3917,7 @@ static void key_continue(struct adns_continuation *cr, err_t ugh,
if (!kc->failure_ok && ugh != NULL)
{
- report_key_dns_failure(&st->st_connection->spd.that.id, ugh);
+ report_key_dns_failure(st->st_connection->spd.that.id, ugh);
r = STF_FAIL + INVALID_KEY_INFORMATION;
}
else
@@ -4468,9 +4457,9 @@ static stf_status quick_inI1_outR1_start_query(struct verify_oppo_bundle *b,
struct state *p1st = md->st;
connection_t *c = p1st->st_connection;
struct verify_oppo_continuation *vc = malloc_thing(struct verify_oppo_continuation);
- struct id id /* subject of query */
- , *our_id /* needed for myid playing */
- , our_id_space; /* ephemeral: no need for unshare_id_content */
+ identification_t *id; /* subject of query */
+ identification_t *our_id; /* needed for myid playing */
+ identification_t *our_id_space; /* ephemeral: no need for unshare_id_content */
ip_address client;
err_t ugh = NULL;
@@ -4506,20 +4495,20 @@ static stf_status quick_inI1_outR1_start_query(struct verify_oppo_bundle *b,
* %myid makes no sense for the other side (but it is syntactically
* legal).
*/
- our_id = resolve_myid(&c->spd.this.id);
- if (our_id->kind == ID_ANY)
+ our_id = resolve_myid(c->spd.this.id);
+ if (our_id->get_type(our_id) == ID_ANY)
{
- iptoid(&c->spd.this.host_addr, &our_id_space);
- our_id = &our_id_space;
+ our_id_space = identification_create_from_sockaddr((sockaddr_t*)&c->spd.this.host_addr);
+ our_id = our_id_space;
}
switch (next_step)
{
case vos_our_client:
networkof(&b->my.net, &client);
- iptoid(&client, &id);
+ id = identification_create_from_sockaddr((sockaddr_t*)&client);
vc->b.failure_ok = b->failure_ok = FALSE;
- ugh = start_adns_query(&id
+ ugh = start_adns_query(id
, our_id
, T_TXT
, quick_inI1_outR1_continue
@@ -4548,10 +4537,10 @@ static stf_status quick_inI1_outR1_start_query(struct verify_oppo_bundle *b,
case vos_his_client:
networkof(&b->his.net, &client);
- iptoid(&client, &id);
+ id = identification_create_from_sockaddr((sockaddr_t*)&client);
vc->b.failure_ok = b->failure_ok = FALSE;
- ugh = start_adns_query(&id
- , &c->spd.that.id
+ ugh = start_adns_query(id
+ , c->spd.that.id
, T_TXT
, quick_inI1_outR1_continue
, &vc->ac);
@@ -4869,7 +4858,7 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b,
* We should record DNS sec use, if any -- belongs in
* state during perhaps.
*/
- p = oppo_instantiate(p, &c->spd.that.host_addr, &c->spd.that.id
+ p = oppo_instantiate(p, &c->spd.that.host_addr, c->spd.that.id
, NULL, &our_client, &his_client);
}
else
@@ -4878,7 +4867,7 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b,
* instantiate, carrying over authenticated peer ID
*/
p = rw_instantiate(p, &c->spd.that.host_addr, md->sender_port
- , his_net, &c->spd.that.id);
+ , his_net, c->spd.that.id);
}
}
#ifdef DEBUG