replaced struct id by identification_t
This commit is contained in:
@@ -20,7 +20,6 @@ demux.c demux.h \
|
||||
dnskey.c dnskey.h \
|
||||
fetch.c fetch.h \
|
||||
foodgroups.c foodgroups.h \
|
||||
id.c id.h \
|
||||
ike_alg.c ike_alg.h \
|
||||
ipsec_doi.c ipsec_doi.h \
|
||||
kameipsec.h \
|
||||
@@ -32,6 +31,7 @@ kernel_pfkey.c kernel_pfkey.h \
|
||||
keys.c keys.h \
|
||||
lex.c lex.h \
|
||||
log.c log.h \
|
||||
myid.c myid.h \
|
||||
modecfg.c modecfg.h \
|
||||
nat_traversal.c nat_traversal.h \
|
||||
ocsp.c ocsp.h \
|
||||
|
||||
+13
-5
@@ -461,12 +461,16 @@ struct alg_info_esp *alg_info_esp_create_from_str(char *alg_str)
|
||||
status = alg_info_parse_str((struct alg_info *)alg_info_esp, alg_str);
|
||||
|
||||
out:
|
||||
if (status != SUCCESS)
|
||||
if (status == SUCCESS)
|
||||
{
|
||||
alg_info_esp->ref_cnt = 1;
|
||||
return alg_info_esp;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(alg_info_esp);
|
||||
alg_info_esp = NULL;
|
||||
return NULL;
|
||||
}
|
||||
return alg_info_esp;
|
||||
}
|
||||
|
||||
struct alg_info_ike *alg_info_ike_create_from_str(char *alg_str)
|
||||
@@ -481,12 +485,16 @@ struct alg_info_ike *alg_info_ike_create_from_str(char *alg_str)
|
||||
zero(alg_info_ike);
|
||||
alg_info_ike->alg_info_protoid = PROTO_ISAKMP;
|
||||
|
||||
if (alg_info_parse_str((struct alg_info *)alg_info_ike, alg_str) != SUCCESS)
|
||||
if (alg_info_parse_str((struct alg_info *)alg_info_ike, alg_str) == SUCCESS)
|
||||
{
|
||||
alg_info_ike->ref_cnt = 1;
|
||||
return alg_info_ike;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(alg_info_ike);
|
||||
return NULL;
|
||||
}
|
||||
return alg_info_ike;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "log.h"
|
||||
#include "id.h"
|
||||
#include "certs.h"
|
||||
#include "ac.h"
|
||||
#include "crl.h"
|
||||
|
||||
+4
-7
@@ -28,7 +28,6 @@
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "log.h"
|
||||
#include "id.h"
|
||||
#include "certs.h"
|
||||
#include "whack.h"
|
||||
#include "builder.h"
|
||||
@@ -228,10 +227,9 @@ void share_cert(cert_t cert)
|
||||
}
|
||||
|
||||
/* release of a certificate decreases the count by one
|
||||
" the certificate is freed when the counter reaches zero
|
||||
* the certificate is freed when the counter reaches zero
|
||||
*/
|
||||
void
|
||||
release_cert(cert_t cert)
|
||||
void release_cert(cert_t cert)
|
||||
{
|
||||
switch (cert.type)
|
||||
{
|
||||
@@ -246,11 +244,10 @@ release_cert(cert_t cert)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* list all X.509 and OpenPGP end certificates
|
||||
*/
|
||||
void
|
||||
list_certs(bool utc)
|
||||
void list_certs(bool utc)
|
||||
{
|
||||
list_x509_end_certs(utc);
|
||||
list_pgp_end_certs(utc);
|
||||
|
||||
+295
-284
File diff suppressed because it is too large
Load Diff
+27
-33
@@ -1,5 +1,6 @@
|
||||
/* information about connections between hosts and clients
|
||||
* Copyright (C) 1998-2001 D. Hugh Redelmeier
|
||||
* Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* 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
|
||||
@@ -19,10 +20,9 @@
|
||||
|
||||
#include <utils/linked_list.h>
|
||||
#include <utils/identification.h>
|
||||
#include <credentials/ietf_attributes/ietf_attributes.h>
|
||||
|
||||
#include "id.h"
|
||||
#include "certs.h"
|
||||
#include "ac.h"
|
||||
#include "smartcard.h"
|
||||
#include "whack.h"
|
||||
|
||||
@@ -130,7 +130,7 @@ extern void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]);
|
||||
struct virtual_t;
|
||||
|
||||
struct end {
|
||||
struct id id;
|
||||
identification_t *id;
|
||||
ip_address
|
||||
host_addr,
|
||||
host_nexthop,
|
||||
@@ -231,7 +231,7 @@ struct connection {
|
||||
extern bool orient(connection_t *c);
|
||||
|
||||
extern bool same_peer_ids(const connection_t *c, const connection_t *d,
|
||||
const struct id *his_id);
|
||||
identification_t *his_id);
|
||||
|
||||
/* Format the topology of a connection end, leaving out defaults.
|
||||
* Largest left end looks like: client === host : port [ host_id ] --- hop
|
||||
@@ -262,9 +262,9 @@ extern connection_t *shunt_owner(const ip_subnet *ours, const ip_subnet *his);
|
||||
extern bool uniqueIDs; /* --uniqueids? */
|
||||
extern void ISAKMP_SA_established(connection_t *c, so_serial_t serial);
|
||||
|
||||
#define his_id_was_instantiated(c) ((c)->kind == CK_INSTANCE \
|
||||
&& (id_is_ipaddr(&(c)->spd.that.id)? \
|
||||
sameaddr(&(c)->spd.that.id.ip_addr, &(c)->spd.that.host_addr) : TRUE))
|
||||
#define id_is_ipaddr(id) ((id)->get_type(id) == ID_IPV4_ADDR || \
|
||||
(id)->get_type(id) == ID_IPV6_ADDR)
|
||||
extern bool his_id_was_instantiated(const connection_t *c);
|
||||
|
||||
struct state; /* forward declaration of tag (defined in state.h) */
|
||||
|
||||
@@ -274,7 +274,7 @@ extern connection_t* find_host_connection(const ip_address *me,
|
||||
const ip_address *him,
|
||||
u_int16_t his_port, lset_t policy);
|
||||
extern connection_t* refine_host_connection(const struct state *st,
|
||||
const struct id *id,
|
||||
identification_t *id,
|
||||
identification_t *peer_ca);
|
||||
extern connection_t* find_client_connection(connection_t *c,
|
||||
const ip_subnet *our_net,
|
||||
@@ -298,30 +298,27 @@ extern void get_peer_ca_and_groups(connection_t *c,
|
||||
*/
|
||||
struct gw_info; /* forward declaration of tag (defined in dnskey.h) */
|
||||
struct alg_info; /* forward declaration of tag (defined in alg_info.h) */
|
||||
extern connection_t *rw_instantiate(connection_t *c
|
||||
, const ip_address *him
|
||||
, u_int16_t his_port
|
||||
, const ip_subnet *his_net
|
||||
, const struct id *his_id);
|
||||
extern connection_t *rw_instantiate(connection_t *c,
|
||||
const ip_address *him,
|
||||
u_int16_t his_port,
|
||||
const ip_subnet *his_net,
|
||||
identification_t *his_id);
|
||||
|
||||
extern connection_t *oppo_instantiate(connection_t *c
|
||||
, const ip_address *him
|
||||
, const struct id *his_id
|
||||
, struct gw_info *gw
|
||||
, const ip_address *our_client
|
||||
, const ip_address *peer_client);
|
||||
extern connection_t *oppo_instantiate(connection_t *c,
|
||||
const ip_address *him,
|
||||
identification_t *his_id,
|
||||
struct gw_info *gw,
|
||||
const ip_address *our_client,
|
||||
const ip_address *peer_client);
|
||||
|
||||
extern connection_t
|
||||
*build_outgoing_opportunistic_connection(struct gw_info *gw
|
||||
, const ip_address *our_client
|
||||
, const ip_address *peer_client);
|
||||
*build_outgoing_opportunistic_connection(struct gw_info *gw,
|
||||
const ip_address *our_client,
|
||||
const ip_address *peer_client);
|
||||
|
||||
/* worst case: "[" serial "] " myclient "=== ..." peer "===" hisclient '\0' */
|
||||
#define CONN_INST_BUF \
|
||||
(2 + 10 + 1 + SUBNETTOT_BUF + 7 + ADDRTOT_BUF + 3 + SUBNETTOT_BUF + 1)
|
||||
#define CONN_INST_BUF BUF_LEN
|
||||
|
||||
extern void fmt_conn_instance(const connection_t *c
|
||||
, char buf[CONN_INST_BUF]);
|
||||
extern void fmt_conn_instance(const connection_t *c, char buf[CONN_INST_BUF]);
|
||||
|
||||
/* operations on "pending", the structure representing Quick Mode
|
||||
* negotiations delayed until a Keying Channel has been negotiated.
|
||||
@@ -329,12 +326,9 @@ extern void fmt_conn_instance(const connection_t *c
|
||||
|
||||
struct pending; /* forward declaration (opaque outside connections.c) */
|
||||
|
||||
extern void add_pending(int whack_sock
|
||||
, struct state *isakmp_sa
|
||||
, connection_t *c
|
||||
, lset_t policy
|
||||
, unsigned long try
|
||||
, so_serial_t replacing);
|
||||
extern void add_pending(int whack_sock, struct state *isakmp_sa,
|
||||
connection_t *c, lset_t policy, unsigned long try,
|
||||
so_serial_t replacing);
|
||||
|
||||
extern void release_pending_whacks(struct state *st, err_t story);
|
||||
extern void unpend(struct state *st);
|
||||
|
||||
+103
-177
@@ -36,7 +36,7 @@
|
||||
#include "adns.h" /* needs <resolv.h> */
|
||||
#include "defs.h"
|
||||
#include "log.h"
|
||||
#include "id.h"
|
||||
#include "myid.h"
|
||||
#include "connections.h"
|
||||
#include "keys.h" /* needs connections.h */
|
||||
#include "dnskey.h"
|
||||
@@ -238,62 +238,30 @@ stop_adns(void)
|
||||
#define our_TXT_attr_string "X-IPsec-Server"
|
||||
static const char our_TXT_attr[] = our_TXT_attr_string;
|
||||
|
||||
static err_t
|
||||
decode_iii(u_char **pp, struct id *gw_id)
|
||||
identification_t* decode_iii(u_char **pp)
|
||||
{
|
||||
identification_t *gw_id;
|
||||
u_char *p = *pp + strspn(*pp, " \t");
|
||||
u_char *e = p + strcspn(p, " \t");
|
||||
u_char under = *e;
|
||||
|
||||
if (p == e)
|
||||
{
|
||||
return "TXT " our_TXT_attr_string " badly formed (no gateway specified)";
|
||||
return NULL;
|
||||
}
|
||||
*e = '\0';
|
||||
if (*p == '@')
|
||||
{
|
||||
/* gateway specification in this record is @FQDN */
|
||||
err_t ugh = atoid(p, gw_id, FALSE);
|
||||
|
||||
if (ugh != NULL)
|
||||
{
|
||||
return builddiag("malformed FQDN in TXT " our_TXT_attr_string ": %s"
|
||||
, ugh);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* gateway specification is numeric */
|
||||
ip_address ip;
|
||||
err_t ugh = tnatoaddr(p, e-p
|
||||
, strchr(p, ':') == NULL? AF_INET : AF_INET6
|
||||
, &ip);
|
||||
|
||||
if (ugh != NULL)
|
||||
{
|
||||
return builddiag("malformed IP address in TXT " our_TXT_attr_string ": %s"
|
||||
, ugh);
|
||||
}
|
||||
if (isanyaddr(&ip))
|
||||
{
|
||||
return "gateway address must not be 0.0.0.0 or 0::0";
|
||||
}
|
||||
iptoid(&ip, gw_id);
|
||||
}
|
||||
|
||||
gw_id = identification_create_from_string(p);
|
||||
*e = under;
|
||||
*pp = e + strspn(e, " \t");
|
||||
|
||||
return NULL;
|
||||
return gw_id;
|
||||
}
|
||||
|
||||
static err_t
|
||||
process_txt_rr_body(u_char *str
|
||||
, bool doit /* should we capture information? */
|
||||
, enum dns_auth_level dns_auth_level
|
||||
, struct adns_continuation *const cr)
|
||||
static err_t process_txt_rr_body(u_char *str, bool doit,
|
||||
enum dns_auth_level dns_auth_level,
|
||||
struct adns_continuation *const cr)
|
||||
{
|
||||
const struct id *client_id = &cr->id; /* subject of query */
|
||||
identification_t *client_id = cr->id; /* subject of query */
|
||||
u_char *p = str;
|
||||
unsigned long pref = 0;
|
||||
struct gw_info gi;
|
||||
@@ -349,10 +317,13 @@ process_txt_rr_body(u_char *str
|
||||
p += strspn(p, " \t");
|
||||
|
||||
/* Decode iii (Security Gateway ID). */
|
||||
|
||||
zero(&gi); /* before first use */
|
||||
|
||||
TRY(decode_iii(&p, &gi.gw_id)); /* will need to unshare_id_content */
|
||||
gi.gw_id = decode_iii(&p);
|
||||
if (gi.gw_id == NULL)
|
||||
{
|
||||
return "TXT " our_TXT_attr_string " badly formed (no gateway specified)";
|
||||
}
|
||||
|
||||
if (!cr->sgw_specified)
|
||||
{
|
||||
@@ -360,19 +331,14 @@ process_txt_rr_body(u_char *str
|
||||
* and we don't know who to initiate with.
|
||||
* So we're looking for gateway specs with an IP address
|
||||
*/
|
||||
if (!id_is_ipaddr(&gi.gw_id))
|
||||
if (gi.gw_id->get_type(gi.gw_id) != ID_IPV4_ADDR &&
|
||||
gi.gw_id->get_type(gi.gw_id) != ID_IPV6_ADDR)
|
||||
{
|
||||
DBG(DBG_DNS,
|
||||
{
|
||||
char cidb[BUF_LEN];
|
||||
char gwidb[BUF_LEN];
|
||||
|
||||
idtoa(client_id, cidb, sizeof(cidb));
|
||||
idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
|
||||
DBG_log("TXT %s record for %s: security gateway %s;"
|
||||
" ignored because gateway's IP is unspecified"
|
||||
, our_TXT_attr, cidb, gwidb);
|
||||
});
|
||||
DBG_log("TXT %s record for '%Y': security gateway '%Y';"
|
||||
" ignored because gateway's IP is unspecified",
|
||||
our_TXT_attr, client_id, gi.gw_id);
|
||||
)
|
||||
return NULL; /* we cannot use this record, but it isn't wrong */
|
||||
}
|
||||
}
|
||||
@@ -381,23 +347,15 @@ process_txt_rr_body(u_char *str
|
||||
/* We do know the peer's ID (because we are responding)
|
||||
* So we're looking for gateway specs specifying this known ID.
|
||||
*/
|
||||
const struct id *peer_id = &cr->sgw_id;
|
||||
identification_t *peer_id = cr->sgw_id;
|
||||
|
||||
if (!same_id(peer_id, &gi.gw_id))
|
||||
if (!peer_id->equals(peer_id, gi.gw_id))
|
||||
{
|
||||
DBG(DBG_DNS,
|
||||
{
|
||||
char cidb[BUF_LEN];
|
||||
char gwidb[BUF_LEN];
|
||||
char pidb[BUF_LEN];
|
||||
|
||||
idtoa(client_id, cidb, sizeof(cidb));
|
||||
idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
|
||||
idtoa(peer_id, pidb, sizeof(pidb));
|
||||
DBG_log("TXT %s record for %s: security gateway %s;"
|
||||
" ignored -- looking to confirm %s as gateway"
|
||||
, our_TXT_attr, cidb, gwidb, pidb);
|
||||
});
|
||||
DBG_log("TXT %s record for '%Y': security gateway '%Y';"
|
||||
" ignored -- looking to confirm '%Y' as gateway",
|
||||
our_TXT_attr, client_id, gi.gw_id, peer_id);
|
||||
)
|
||||
return NULL; /* we cannot use this record, but it isn't wrong */
|
||||
}
|
||||
}
|
||||
@@ -407,7 +365,7 @@ process_txt_rr_body(u_char *str
|
||||
/* really accept gateway */
|
||||
struct gw_info **gwip; /* gateway insertion point */
|
||||
|
||||
gi.client_id = *client_id; /* will need to unshare_id_content */
|
||||
gi.client_id = client_id; /* will need to unshare_id_content */
|
||||
|
||||
/* decode optional kkk: base 64 encoding of key */
|
||||
|
||||
@@ -462,32 +420,26 @@ process_txt_rr_body(u_char *str
|
||||
|
||||
DBG(DBG_DNS,
|
||||
{
|
||||
char cidb[BUF_LEN];
|
||||
char gwidb[BUF_LEN];
|
||||
chunk_t keyid;
|
||||
public_key_t *key;
|
||||
|
||||
idtoa(client_id, cidb, sizeof(cidb));
|
||||
idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
|
||||
key = gi.key->public_key;
|
||||
public_key_t *key = gi.key->public_key;
|
||||
|
||||
if (gi.gw_key_present &&
|
||||
key->get_fingerprint(key, KEY_ID_PUBKEY_SHA1, &keyid))
|
||||
{
|
||||
DBG_log("gateway for %s is %s with key %#B"
|
||||
, cidb, gwidb, &keyid);
|
||||
DBG_log("gateway for %s is %s with key %#B",
|
||||
client_id, gi.gw_id, &keyid);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG_log("gateway for %s is %s; no key specified"
|
||||
, cidb, gwidb);
|
||||
DBG_log("gateway for '%Y' is '%Y'; no key specified",
|
||||
client_id, gi.gw_id);
|
||||
}
|
||||
});
|
||||
|
||||
gi.next = *gwip;
|
||||
*gwip = clone_thing(gi);
|
||||
unshare_id_content(&(*gwip)->gw_id);
|
||||
unshare_id_content(&(*gwip)->client_id);
|
||||
(*gwip)->gw_id = (*gwip)->gw_id->clone((*gwip)->gw_id);
|
||||
(*gwip)->client_id = (*gwip)->client_id->clone((*gwip)->client_id);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -1271,75 +1223,62 @@ process_dns_answer(struct adns_continuation *const cr
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
static err_t
|
||||
build_dns_name(u_char name_buf[NS_MAXDNAME + 2]
|
||||
, unsigned long serial USED_BY_DEBUG
|
||||
, const struct id *id
|
||||
, const char *typename USED_BY_DEBUG
|
||||
, const char *gwname USED_BY_DEBUG)
|
||||
static err_t build_dns_name(u_char name_buf[NS_MAXDNAME + 2],
|
||||
unsigned long serial USED_BY_DEBUG,
|
||||
identification_t *id,
|
||||
const char *typename USED_BY_DEBUG,
|
||||
identification_t *gw USED_BY_DEBUG)
|
||||
{
|
||||
/* note: all end in "." to suppress relative searches */
|
||||
id = resolve_myid(id);
|
||||
switch (id->kind)
|
||||
{
|
||||
case ID_IPV4_ADDR:
|
||||
{
|
||||
/* XXX: this is really ugly and only temporary until addrtot can
|
||||
* generate the correct format
|
||||
*/
|
||||
const unsigned char *b;
|
||||
size_t bl USED_BY_DEBUG = addrbytesptr(&id->ip_addr, &b);
|
||||
|
||||
passert(bl == 4);
|
||||
snprintf(name_buf, NS_MAXDNAME + 2, "%d.%d.%d.%d.in-addr.arpa."
|
||||
, b[3], b[2], b[1], b[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_IPV6_ADDR:
|
||||
switch (id->get_type(id))
|
||||
{
|
||||
/* ??? is this correct? */
|
||||
const unsigned char *b;
|
||||
size_t bl;
|
||||
u_char *op = name_buf;
|
||||
static const char suffix[] = "IP6.INT.";
|
||||
|
||||
for (bl = addrbytesptr(&id->ip_addr, &b); bl-- != 0; )
|
||||
case ID_IPV4_ADDR:
|
||||
{
|
||||
if (op + 4 + sizeof(suffix) >= name_buf + NS_MAXDNAME + 1)
|
||||
return "IPv6 reverse name too long";
|
||||
op += sprintf(op, "%x.%x.", b[bl] & 0xF, b[bl] >> 4);
|
||||
chunk_t b = id->get_encoding(id);
|
||||
|
||||
snprintf(name_buf, NS_MAXDNAME + 2, "%d.%d.%d.%d.in-addr.arpa.",
|
||||
b.ptr[3], b.ptr[2], b.ptr[1], b.ptr[0]);
|
||||
break;
|
||||
}
|
||||
strcpy(op, suffix);
|
||||
break;
|
||||
}
|
||||
|
||||
case ID_FQDN:
|
||||
/* strip trailing "." characters, then add one */
|
||||
case ID_IPV6_ADDR:
|
||||
{
|
||||
size_t il = id->name.len;
|
||||
chunk_t b = id->get_encoding(id);
|
||||
size_t bl;
|
||||
u_char *op = name_buf;
|
||||
static const char suffix[] = "IP6.INT.";
|
||||
|
||||
while (il > 0 && id->name.ptr[il - 1] == '.')
|
||||
il--;
|
||||
if (il > NS_MAXDNAME)
|
||||
for (bl = b.len; bl-- != 0; )
|
||||
{
|
||||
if (op + 4 + sizeof(suffix) >= name_buf + NS_MAXDNAME + 1)
|
||||
{
|
||||
return "IPv6 reverse name too long";
|
||||
}
|
||||
op += sprintf(op, "%x.%x.", b.ptr[bl] & 0xF, b.ptr[bl] >> 4);
|
||||
}
|
||||
strcpy(op, suffix);
|
||||
break;
|
||||
}
|
||||
case ID_FQDN:
|
||||
{
|
||||
if (snprintf(name_buf, NS_MAXDNAME + 2, "%Y.", id) > NS_MAXDNAME + 1)
|
||||
{
|
||||
return "FQDN too long for domain name";
|
||||
|
||||
memcpy(name_buf, id->name.ptr, il);
|
||||
strcpy(name_buf + il, ".");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return "can only query DNS for key for ID that is a FQDN, IPV4_ADDR, or IPV6_ADDR";
|
||||
default:
|
||||
return "can only query DNS for key for ID that is a FQDN, IPV4_ADDR, or IPV6_ADDR";
|
||||
}
|
||||
|
||||
DBG(DBG_CONTROL | DBG_DNS, DBG_log("DNS query %lu for %s for %s (gw: %s)"
|
||||
, serial, typename, name_buf, gwname));
|
||||
DBG(DBG_CONTROL | DBG_DNS,
|
||||
DBG_log("DNS query %lu for %s for %s (gw: %Y)", serial, typename, name_buf, gw)
|
||||
)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
gw_addref(struct gw_info *gw)
|
||||
void gw_addref(struct gw_info *gw)
|
||||
{
|
||||
if (gw != NULL)
|
||||
{
|
||||
@@ -1348,8 +1287,7 @@ gw_addref(struct gw_info *gw)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gw_delref(struct gw_info **gwp)
|
||||
void gw_delref(struct gw_info **gwp)
|
||||
{
|
||||
struct gw_info *gw = *gwp;
|
||||
|
||||
@@ -1361,10 +1299,12 @@ gw_delref(struct gw_info **gwp)
|
||||
gw->refcnt--;
|
||||
if (gw->refcnt == 0)
|
||||
{
|
||||
free_id_content(&gw->client_id);
|
||||
free_id_content(&gw->gw_id);
|
||||
DESTROY_IF(gw->client_id);
|
||||
DESTROY_IF(gw->gw_id);
|
||||
if (gw->gw_key_present)
|
||||
{
|
||||
unreference_key(&gw->key);
|
||||
}
|
||||
gw_delref(&gw->next);
|
||||
free(gw); /* trickery could make this a tail-call */
|
||||
}
|
||||
@@ -1414,68 +1354,61 @@ static int adns_in_flight = 0; /* queries outstanding */
|
||||
static struct adns_continuation *continuations = NULL; /* newest of queue */
|
||||
static struct adns_continuation *next_query = NULL; /* oldest not sent */
|
||||
|
||||
static struct adns_continuation *
|
||||
continuation_for_qtid(unsigned long qtid)
|
||||
static struct adns_continuation *continuation_for_qtid(unsigned long qtid)
|
||||
{
|
||||
struct adns_continuation *cr = NULL;
|
||||
|
||||
if (qtid != 0)
|
||||
{
|
||||
for (cr = continuations; cr != NULL && cr->qtid != qtid; cr = cr->previous)
|
||||
;
|
||||
}
|
||||
return cr;
|
||||
}
|
||||
|
||||
static void
|
||||
release_adns_continuation(struct adns_continuation *cr)
|
||||
static void release_adns_continuation(struct adns_continuation *cr)
|
||||
{
|
||||
passert(cr != next_query);
|
||||
gw_delref(&cr->gateways_from_dns);
|
||||
#ifdef USE_KEYRR
|
||||
free_public_keys(&cr->keys_from_dns);
|
||||
#endif /* USE_KEYRR */
|
||||
unshare_id_content(&cr->id);
|
||||
unshare_id_content(&cr->sgw_id);
|
||||
cr->id = cr->id->clone(cr->id);
|
||||
cr->sgw_id = cr->sgw_id->clone(cr->sgw_id);
|
||||
|
||||
/* unlink from doubly-linked list */
|
||||
if (cr->next == NULL)
|
||||
{
|
||||
passert(continuations == cr);
|
||||
continuations = cr->previous;
|
||||
}
|
||||
else
|
||||
{
|
||||
passert(cr->next->previous == cr);
|
||||
cr->next->previous = cr->previous;
|
||||
}
|
||||
|
||||
if (cr->previous != NULL)
|
||||
{
|
||||
passert(cr->previous->next == cr);
|
||||
cr->previous->next = cr->next;
|
||||
}
|
||||
|
||||
free(cr);
|
||||
}
|
||||
|
||||
err_t
|
||||
start_adns_query(const struct id *id /* domain to query */
|
||||
, const struct id *sgw_id /* if non-null, any accepted gw_info must match */
|
||||
, int type /* T_TXT or T_KEY, selecting rr type of interest */
|
||||
, cont_fn_t cont_fn
|
||||
, struct adns_continuation *cr)
|
||||
err_t start_adns_query(identification_t *id, /* domain to query */
|
||||
identification_t *sgw_id, /* if non-null, any accepted gw_info must match */
|
||||
int type, /* T_TXT or T_KEY, selecting rr type of interest */
|
||||
cont_fn_t cont_fn,
|
||||
struct adns_continuation *cr)
|
||||
{
|
||||
static unsigned long qtid = 1; /* query transaction id; NOTE: static */
|
||||
const char *typename = rr_typename(type);
|
||||
char gwidb[BUF_LEN];
|
||||
|
||||
if(adns_pid == 0
|
||||
&& adns_restart_count < ADNS_RESTART_MAX)
|
||||
if(adns_pid == 0 && adns_restart_count < ADNS_RESTART_MAX)
|
||||
{
|
||||
plog("ADNS helper was not running. Restarting attempt %d",adns_restart_count);
|
||||
init_adns();
|
||||
}
|
||||
|
||||
|
||||
/* Splice this in at head of doubly-linked list of continuations.
|
||||
* Note: this must be done before any release_adns_continuation().
|
||||
*/
|
||||
@@ -1483,7 +1416,6 @@ start_adns_query(const struct id *id /* domain to query */
|
||||
cr->previous = continuations;
|
||||
if (continuations != NULL)
|
||||
{
|
||||
passert(continuations->next == NULL);
|
||||
continuations->next = cr;
|
||||
}
|
||||
continuations = cr;
|
||||
@@ -1491,11 +1423,11 @@ start_adns_query(const struct id *id /* domain to query */
|
||||
cr->qtid = qtid++;
|
||||
cr->type = type;
|
||||
cr->cont_fn = cont_fn;
|
||||
cr->id = *id;
|
||||
unshare_id_content(&cr->id);
|
||||
cr->sgw_specified = sgw_id != NULL;
|
||||
cr->sgw_id = cr->sgw_specified? *sgw_id : empty_id;
|
||||
unshare_id_content(&cr->sgw_id);
|
||||
cr->id = id->clone(id);
|
||||
cr->sgw_specified = (sgw_id != NULL);
|
||||
cr->sgw_id = cr->sgw_specified ?
|
||||
sgw_id->clone(sgw_id) :
|
||||
identification_create_from_string("%any");
|
||||
cr->gateways_from_dns = NULL;
|
||||
#ifdef USE_KEYRR
|
||||
cr->keys_from_dns = NULL;
|
||||
@@ -1507,15 +1439,12 @@ start_adns_query(const struct id *id /* domain to query */
|
||||
cr->debugging = LEMPTY;
|
||||
#endif
|
||||
|
||||
idtoa(&cr->sgw_id, gwidb, sizeof(gwidb));
|
||||
|
||||
zero(&cr->query);
|
||||
|
||||
{
|
||||
err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid
|
||||
, id, typename, gwidb);
|
||||
err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid, id,
|
||||
typename, cr->sgw_id);
|
||||
|
||||
if (ugh != NULL)
|
||||
if (ugh)
|
||||
{
|
||||
release_adns_continuation(cr);
|
||||
return ugh;
|
||||
@@ -1620,8 +1549,7 @@ send_unsent_ADNS_queries(void)
|
||||
* Returns with error message iff lwdnsq result is malformed.
|
||||
* Most errors will be in DNS data and will be handled by cr->cont_fn.
|
||||
*/
|
||||
static err_t
|
||||
process_lwdnsq_answer(char *ts)
|
||||
static err_t process_lwdnsq_answer(char *ts)
|
||||
{
|
||||
err_t ugh = NULL;
|
||||
char *rest;
|
||||
@@ -1813,8 +1741,7 @@ process_lwdnsq_answer(char *ts)
|
||||
}
|
||||
#endif /* USE_LWRES */
|
||||
|
||||
static void
|
||||
recover_adns_die(void)
|
||||
static void recover_adns_die(void)
|
||||
{
|
||||
struct adns_continuation *cr = NULL;
|
||||
|
||||
@@ -1848,8 +1775,7 @@ void reset_adns_restart_count(void)
|
||||
adns_restart_count=0;
|
||||
}
|
||||
|
||||
void
|
||||
handle_adns_answer(void)
|
||||
void handle_adns_answer(void)
|
||||
{
|
||||
/* These are retained across calls to handle_adns_answer. */
|
||||
static size_t buflen = 0; /* bytes in answer buffer */
|
||||
|
||||
+20
-20
@@ -12,9 +12,10 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
extern int
|
||||
adns_qfd, /* file descriptor for sending queries to adns */
|
||||
adns_afd; /* file descriptor for receiving answers from adns */
|
||||
#include <utils/identification.h>
|
||||
|
||||
extern int adns_qfd; /* file descriptor for sending queries to adns */
|
||||
extern int adns_afd; /* file descriptor for receiving answers from adns */
|
||||
extern const char *pluto_adns_option; /* path from --pluto_adns */
|
||||
extern void init_adns(void);
|
||||
extern void stop_adns(void);
|
||||
@@ -33,13 +34,13 @@ struct adns_continuation; /* forward declaration (not far!) */
|
||||
typedef void (*cont_fn_t)(struct adns_continuation *cr, err_t ugh);
|
||||
|
||||
struct adns_continuation {
|
||||
unsigned long qtid; /* query transaction id number */
|
||||
int type; /* T_TXT or T_KEY, selecting rr type of interest */
|
||||
cont_fn_t cont_fn; /* function to carry on suspended work */
|
||||
struct id id; /* subject of query */
|
||||
unsigned long qtid; /* query transaction id number */
|
||||
int type; /* T_TXT or T_KEY, selecting rr type of interest */
|
||||
cont_fn_t cont_fn; /* function to carry on suspended work */
|
||||
identification_t *id; /* subject of query */
|
||||
bool sgw_specified;
|
||||
struct id sgw_id; /* peer, if constrained */
|
||||
lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */
|
||||
identification_t *sgw_id; /* peer, if constrained */
|
||||
lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */
|
||||
struct gw_info *gateways_from_dns; /* answer, if looking for our TXT rrs */
|
||||
#ifdef USE_KEYRR
|
||||
struct pubkey_list *keys_from_dns; /* answer, if looking for KEY rrs */
|
||||
@@ -47,7 +48,7 @@ struct adns_continuation {
|
||||
struct adns_continuation *previous, *next;
|
||||
struct pubkey *last_info; /* the last structure we accumulated */
|
||||
#ifdef USE_LWRES
|
||||
bool used; /* have we called the cont_fn yet? */
|
||||
bool used; /* have we called the cont_fn yet? */
|
||||
struct {
|
||||
u_char name_buf[NS_MAXDNAME + 2];
|
||||
} query;
|
||||
@@ -56,8 +57,8 @@ struct adns_continuation {
|
||||
#endif /* ! USE_LWRES */
|
||||
};
|
||||
|
||||
extern err_t start_adns_query(const struct id *id /* domain to query */
|
||||
, const struct id *sgw_id /* if non-null, any accepted gw_info must match */
|
||||
extern err_t start_adns_query(identification_t *id /* domain to query */
|
||||
, identification_t *sgw_id /* if non-null, any accepted gw_info must match */
|
||||
, int type /* T_TXT or T_KEY, selecting rr type of interest */
|
||||
, cont_fn_t cont_fn /* continuation function */
|
||||
, struct adns_continuation *cr);
|
||||
@@ -65,18 +66,17 @@ extern err_t start_adns_query(const struct id *id /* domain to query */
|
||||
|
||||
/* Gateway info gleaned from reverse DNS of client */
|
||||
struct gw_info {
|
||||
unsigned refcnt; /* reference counted! */
|
||||
unsigned pref; /* preference: lower is better */
|
||||
#define NO_TIME ((time_t) -2) /* time_t value meaning "not_yet" */
|
||||
struct id client_id; /* id of client of peer */
|
||||
struct id gw_id; /* id of peer (if id_is_ipaddr, .ip_addr is address) */
|
||||
unsigned refcnt; /* reference counted! */
|
||||
unsigned pref; /* preference: lower is better */
|
||||
#define NO_TIME ((time_t) -2) /* time_t value meaning "not_yet" */
|
||||
identification_t* client_id; /* id of client of peer */
|
||||
identification_t* gw_id; /* id of peer (if id_is_ipaddr, .ip_addr is address) */
|
||||
bool gw_key_present;
|
||||
struct pubkey *key;
|
||||
struct gw_info *next;
|
||||
};
|
||||
|
||||
extern void gw_addref(struct gw_info *gw)
|
||||
, gw_delref(struct gw_info **gwp);
|
||||
|
||||
extern void gw_addref(struct gw_info *gw);
|
||||
extern void gw_delref(struct gw_info **gwp);
|
||||
extern void reset_adns_restart_count(void);
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "log.h"
|
||||
#include "id.h"
|
||||
#include "x509.h"
|
||||
#include "ca.h"
|
||||
#include "whack.h"
|
||||
|
||||
-537
@@ -1,537 +0,0 @@
|
||||
/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1)
|
||||
* Copyright (C) 1999-2001 D. Hugh Redelmeier
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says <unistd.h> defines this */
|
||||
# define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */
|
||||
#endif
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <freeswan.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "id.h"
|
||||
#include "log.h"
|
||||
#include "connections.h"
|
||||
#include "packet.h"
|
||||
#include "whack.h"
|
||||
|
||||
const struct id empty_id; /* ID_ANY */
|
||||
|
||||
enum myid_state myid_state = MYID_UNKNOWN;
|
||||
struct id myids[MYID_SPECIFIED+1]; /* %myid */
|
||||
char *myid_str[MYID_SPECIFIED+1]; /* string form of IDs */
|
||||
|
||||
/* initialize id module
|
||||
* Fills in myid from environment variable IPSECmyid or defaultrouteaddr
|
||||
*/
|
||||
void init_id(void)
|
||||
{
|
||||
passert(empty_id.kind == ID_ANY);
|
||||
myid_state = MYID_UNKNOWN;
|
||||
{
|
||||
enum myid_state s;
|
||||
|
||||
for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++)
|
||||
{
|
||||
myids[s] = empty_id;
|
||||
myid_str[s] = NULL;
|
||||
}
|
||||
}
|
||||
set_myid(MYID_SPECIFIED, getenv("IPSECmyid"));
|
||||
set_myid(MYID_IP, getenv("defaultrouteaddr"));
|
||||
set_myFQDN();
|
||||
}
|
||||
|
||||
/*
|
||||
* free id module
|
||||
*/
|
||||
void free_id(void)
|
||||
{
|
||||
enum myid_state s;
|
||||
|
||||
for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++)
|
||||
{
|
||||
free_id_content(&myids[s]);
|
||||
free(myid_str[s]);
|
||||
}
|
||||
}
|
||||
|
||||
static void calc_myid_str(enum myid_state s)
|
||||
{
|
||||
/* preformat the ID name */
|
||||
char buf[BUF_LEN];
|
||||
|
||||
idtoa(&myids[s], buf, BUF_LEN);
|
||||
replace(myid_str[s], clone_str(buf));
|
||||
}
|
||||
|
||||
|
||||
void set_myid(enum myid_state s, char *idstr)
|
||||
{
|
||||
if (idstr != NULL)
|
||||
{
|
||||
struct id id;
|
||||
err_t ugh = atoid(idstr, &id, FALSE);
|
||||
|
||||
if (ugh != NULL)
|
||||
{
|
||||
loglog(RC_BADID, "myid malformed: %s \"%s\"", ugh, idstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
free_id_content(&myids[s]);
|
||||
unshare_id_content(&id);
|
||||
myids[s] = id;
|
||||
if (s == MYID_SPECIFIED)
|
||||
myid_state = MYID_SPECIFIED;
|
||||
|
||||
calc_myid_str(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_myFQDN(void)
|
||||
{
|
||||
char FQDN[HOST_NAME_MAX + 1];
|
||||
int r = gethostname(FQDN, sizeof(FQDN));
|
||||
|
||||
free_id_content(&myids[MYID_HOSTNAME]);
|
||||
myids[MYID_HOSTNAME] = empty_id;
|
||||
if (r != 0)
|
||||
{
|
||||
log_errno((e, "gethostname() failed in set_myFQDN"));
|
||||
}
|
||||
else
|
||||
{
|
||||
FQDN[sizeof(FQDN) - 1] = '\0'; /* insurance */
|
||||
|
||||
{
|
||||
size_t len = strlen(FQDN);
|
||||
|
||||
if (len > 0 && FQDN[len-1] == '.')
|
||||
{
|
||||
/* nuke trailing . */
|
||||
FQDN[len-1]='\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcaseeq(FQDN, "localhost.localdomain"))
|
||||
{
|
||||
chunk_t myid_name = { FQDN, strlen(FQDN) };
|
||||
|
||||
myids[MYID_HOSTNAME].name = chunk_clone(myid_name);
|
||||
myids[MYID_HOSTNAME].kind = ID_FQDN;
|
||||
calc_myid_str(MYID_HOSTNAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void show_myid_status(void)
|
||||
{
|
||||
char idstr[BUF_LEN];
|
||||
|
||||
(void)idtoa(&myids[myid_state], idstr, sizeof(idstr));
|
||||
whack_log(RC_COMMENT, "%%myid = %s", idstr);
|
||||
}
|
||||
|
||||
/* Convert textual form of id into a (temporary) struct id.
|
||||
* Note that if the id is to be kept, unshare_id_content will be necessary.
|
||||
*/
|
||||
err_t atoid(char *src, struct id *id, bool myid_ok)
|
||||
{
|
||||
err_t ugh = NULL;
|
||||
|
||||
*id = empty_id;
|
||||
|
||||
if (myid_ok && streq("%myid", src))
|
||||
{
|
||||
id->kind = ID_MYID;
|
||||
}
|
||||
else if (strchr(src, '=') != NULL)
|
||||
{
|
||||
/* we interpret this as an ASCII X.501 ID_DER_ASN1_DN */
|
||||
id->kind = ID_DER_ASN1_DN;
|
||||
id->name.ptr = temporary_cyclic_buffer(); /* assign temporary buffer */
|
||||
id->name.len = 0;
|
||||
/* convert from LDAP style or openssl x509 -subject style to ASN.1 DN
|
||||
* discard optional @ character in front of DN
|
||||
*/
|
||||
ugh = atodn((*src == '@')?src+1:src, &id->name);
|
||||
}
|
||||
else if (strchr(src, '@') == NULL)
|
||||
{
|
||||
if (streq(src, "%any") || streq(src, "0.0.0.0"))
|
||||
{
|
||||
/* any ID will be accepted */
|
||||
id->kind = ID_ANY;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* !!! this test is not sufficient for distinguishing address families.
|
||||
* We need a notation to specify that a FQDN is to be resolved to IPv6.
|
||||
*/
|
||||
const struct af_info *afi = strchr(src, ':') == NULL
|
||||
? &af_inet4_info: &af_inet6_info;
|
||||
|
||||
id->kind = afi->id_addr;
|
||||
ugh = ttoaddr(src, 0, afi->af, &id->ip_addr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*src == '@')
|
||||
{
|
||||
if (*(src+1) == '#')
|
||||
{
|
||||
/* if there is a second specifier (#) on the line
|
||||
* we interprete this as ID_KEY_ID
|
||||
*/
|
||||
id->kind = ID_KEY_ID;
|
||||
id->name.ptr = src;
|
||||
/* discard @~, convert from hex to bin */
|
||||
ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len);
|
||||
}
|
||||
else if (*(src+1) == '~')
|
||||
{
|
||||
/* if there is a second specifier (~) on the line
|
||||
* we interprete this as a binary ID_DER_ASN1_DN
|
||||
*/
|
||||
id->kind = ID_DER_ASN1_DN;
|
||||
id->name.ptr = src;
|
||||
/* discard @~, convert from hex to bin */
|
||||
ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len);
|
||||
}
|
||||
else
|
||||
{
|
||||
id->kind = ID_FQDN;
|
||||
id->name.ptr = src+1; /* discard @ */
|
||||
id->name.len = strlen(src)-1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We leave in @, as per DOI 4.6.2.4
|
||||
* (but DNS wants . instead).
|
||||
*/
|
||||
id->kind = ID_USER_FQDN;
|
||||
id->name.ptr = src;
|
||||
id->name.len = strlen(src);
|
||||
}
|
||||
}
|
||||
return ugh;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Converts a binary key ID into hexadecimal format
|
||||
*/
|
||||
int keyidtoa(char *dst, size_t dstlen, chunk_t keyid)
|
||||
{
|
||||
int n = datatot(keyid.ptr, keyid.len, 'x', dst, dstlen);
|
||||
return (((size_t)n < dstlen)? n : dstlen) - 1;
|
||||
}
|
||||
|
||||
void iptoid(const ip_address *ip, struct id *id)
|
||||
{
|
||||
*id = empty_id;
|
||||
|
||||
switch (addrtypeof(ip))
|
||||
{
|
||||
case AF_INET:
|
||||
id->kind = ID_IPV4_ADDR;
|
||||
break;
|
||||
case AF_INET6:
|
||||
id->kind = ID_IPV6_ADDR;
|
||||
break;
|
||||
default:
|
||||
bad_case(addrtypeof(ip));
|
||||
}
|
||||
id->ip_addr = *ip;
|
||||
}
|
||||
|
||||
int idtoa(const struct id *id, char *dst, size_t dstlen)
|
||||
{
|
||||
int n;
|
||||
|
||||
id = resolve_myid(id);
|
||||
switch (id->kind)
|
||||
{
|
||||
case ID_ANY:
|
||||
n = snprintf(dst, dstlen, "(none)");
|
||||
break;
|
||||
case ID_IPV4_ADDR:
|
||||
case ID_IPV6_ADDR:
|
||||
n = (int)addrtot(&id->ip_addr, 0, dst, dstlen) - 1;
|
||||
break;
|
||||
case ID_FQDN:
|
||||
n = snprintf(dst, dstlen, "@%.*s", (int)id->name.len, id->name.ptr);
|
||||
break;
|
||||
case ID_USER_FQDN:
|
||||
n = snprintf(dst, dstlen, "%.*s", (int)id->name.len, id->name.ptr);
|
||||
break;
|
||||
case ID_DER_ASN1_DN:
|
||||
n = dntoa(dst, dstlen, id->name);
|
||||
break;
|
||||
case ID_KEY_ID:
|
||||
n = keyidtoa(dst, dstlen, id->name);
|
||||
break;
|
||||
default:
|
||||
n = snprintf(dst, dstlen, "unknown id kind %d", id->kind);
|
||||
break;
|
||||
}
|
||||
|
||||
/* "Sanitize" string so that log isn't endangered:
|
||||
* replace unprintable characters with '?'.
|
||||
*/
|
||||
if (n > 0)
|
||||
{
|
||||
for ( ; *dst != '\0'; dst++)
|
||||
if (!isprint(*dst))
|
||||
*dst = '?';
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Replace the shell metacharacters ', \, ", `, and $ in a character string
|
||||
* by escape sequences consisting of their octal values
|
||||
*/
|
||||
void escape_metachar(const char *src, char *dst, size_t dstlen)
|
||||
{
|
||||
while (*src != '\0' && dstlen > 4)
|
||||
{
|
||||
switch (*src)
|
||||
{
|
||||
case '\'':
|
||||
case '\\':
|
||||
case '"':
|
||||
case '`':
|
||||
case '$':
|
||||
sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src);
|
||||
dst += 4;
|
||||
dstlen -= 4;
|
||||
break;
|
||||
default:
|
||||
*dst++ = *src;
|
||||
dstlen--;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
|
||||
/* Make private copy of string in struct id.
|
||||
* This is needed if the result of atoid is to be kept.
|
||||
*/
|
||||
void unshare_id_content(struct id *id)
|
||||
{
|
||||
switch (id->kind)
|
||||
{
|
||||
case ID_FQDN:
|
||||
case ID_USER_FQDN:
|
||||
case ID_DER_ASN1_DN:
|
||||
case ID_KEY_ID:
|
||||
id->name = chunk_clone(id->name);
|
||||
break;
|
||||
case ID_MYID:
|
||||
case ID_ANY:
|
||||
case ID_IPV4_ADDR:
|
||||
case ID_IPV6_ADDR:
|
||||
break;
|
||||
default:
|
||||
bad_case(id->kind);
|
||||
}
|
||||
}
|
||||
|
||||
void free_id_content(struct id *id)
|
||||
{
|
||||
switch (id->kind)
|
||||
{
|
||||
case ID_FQDN:
|
||||
case ID_USER_FQDN:
|
||||
case ID_DER_ASN1_DN:
|
||||
case ID_KEY_ID:
|
||||
free(id->name.ptr);
|
||||
break;
|
||||
case ID_MYID:
|
||||
case ID_ANY:
|
||||
case ID_IPV4_ADDR:
|
||||
case ID_IPV6_ADDR:
|
||||
break;
|
||||
default:
|
||||
bad_case(id->kind);
|
||||
}
|
||||
}
|
||||
|
||||
/* compare two struct id values */
|
||||
bool same_id(const struct id *a, const struct id *b)
|
||||
{
|
||||
a = resolve_myid(a);
|
||||
b = resolve_myid(b);
|
||||
if (a->kind != b->kind)
|
||||
return FALSE;
|
||||
switch (a->kind)
|
||||
{
|
||||
case ID_ANY:
|
||||
return TRUE; /* kind of vacuous */
|
||||
|
||||
case ID_IPV4_ADDR:
|
||||
case ID_IPV6_ADDR:
|
||||
return sameaddr(&a->ip_addr, &b->ip_addr);
|
||||
|
||||
case ID_FQDN:
|
||||
case ID_USER_FQDN:
|
||||
/* assumptions:
|
||||
* - case should be ignored
|
||||
* - trailing "." should be ignored (even if the only character?)
|
||||
*/
|
||||
{
|
||||
size_t al = a->name.len
|
||||
, bl = b->name.len;
|
||||
|
||||
while (al > 0 && a->name.ptr[al - 1] == '.')
|
||||
al--;
|
||||
while (bl > 0 && b->name.ptr[bl - 1] == '.')
|
||||
bl--;
|
||||
return al == bl
|
||||
&& strncasecmp(a->name.ptr, b->name.ptr, al) == 0;
|
||||
}
|
||||
|
||||
case ID_DER_ASN1_DN:
|
||||
return same_dn(a->name, b->name);
|
||||
|
||||
case ID_KEY_ID:
|
||||
return a->name.len == b->name.len
|
||||
&& memeq(a->name.ptr, b->name.ptr, a->name.len);
|
||||
|
||||
default:
|
||||
bad_case(a->kind);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* compare two struct id values, DNs can contain wildcards */
|
||||
bool match_id(const struct id *a, const struct id *b, int *wildcards)
|
||||
{
|
||||
if (b->kind == ID_ANY)
|
||||
{
|
||||
*wildcards = MAX_WILDCARDS;
|
||||
return TRUE;
|
||||
}
|
||||
if (a->kind != b->kind)
|
||||
return FALSE;
|
||||
if (a->kind == ID_DER_ASN1_DN)
|
||||
return match_dn(a->name, b->name, wildcards);
|
||||
else
|
||||
{
|
||||
*wildcards = 0;
|
||||
return same_id(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/* count the numer of wildcards in an id */
|
||||
int id_count_wildcards(const struct id *id)
|
||||
{
|
||||
switch (id->kind)
|
||||
{
|
||||
case ID_ANY:
|
||||
return MAX_WILDCARDS;
|
||||
case ID_DER_ASN1_DN:
|
||||
return dn_count_wildcards(id->name);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
void build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end)
|
||||
{
|
||||
const struct id *id = resolve_myid(&end->id);
|
||||
|
||||
zero(hd);
|
||||
hd->isaiid_idtype = id->kind;
|
||||
switch (id->kind)
|
||||
{
|
||||
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_FQDN:
|
||||
case ID_USER_FQDN:
|
||||
case ID_DER_ASN1_DN:
|
||||
case ID_KEY_ID:
|
||||
*tl = id->name;
|
||||
break;
|
||||
case ID_IPV4_ADDR:
|
||||
case ID_IPV6_ADDR:
|
||||
tl->len = addrbytesptr(&id->ip_addr
|
||||
, (const unsigned char **)&tl->ptr); /* sets tl->ptr too */
|
||||
break;
|
||||
default:
|
||||
bad_case(id->kind);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts libstrongswan's identification_t type into pluto's struct id
|
||||
*/
|
||||
void id_from_identification(struct id *id, identification_t *identification)
|
||||
{
|
||||
chunk_t encoding;
|
||||
|
||||
encoding = identification->get_encoding(identification);
|
||||
id->kind = identification->get_type(identification);
|
||||
|
||||
switch (id->kind)
|
||||
{
|
||||
case ID_FQDN:
|
||||
case ID_USER_FQDN:
|
||||
case ID_DER_ASN1_DN:
|
||||
case ID_KEY_ID:
|
||||
id->name = encoding;
|
||||
break;
|
||||
case ID_IPV4_ADDR:
|
||||
case ID_IPV6_ADDR:
|
||||
initaddr(encoding.ptr, encoding.len,
|
||||
(id->kind == ID_IPV4_ADDR) ? AF_INET : AF_INET6,
|
||||
&id->ip_addr);
|
||||
break;
|
||||
case ID_ANY:
|
||||
default:
|
||||
id->kind = ID_ANY;
|
||||
id->name = chunk_empty;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* c-basic-offset:4
|
||||
* c-style: pluto
|
||||
* End:
|
||||
*/
|
||||
@@ -1,68 +0,0 @@
|
||||
/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1)
|
||||
* Copyright (C) 1999-2001 D. Hugh Redelmeier
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _ID_H
|
||||
#define _ID_H
|
||||
|
||||
#include <utils/identification.h>
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
struct id {
|
||||
int kind; /* ID_* value */
|
||||
ip_address ip_addr; /* ID_IPV4_ADDR, ID_IPV6_ADDR */
|
||||
chunk_t name; /* ID_FQDN, ID_USER_FQDN (with @) */
|
||||
/* ID_KEY_ID, ID_DER_ASN_DN */
|
||||
};
|
||||
|
||||
extern void init_id(void);
|
||||
extern void free_id(void);
|
||||
extern const struct id empty_id; /* ID_ANY */
|
||||
|
||||
enum myid_state {
|
||||
MYID_UNKNOWN, /* not yet figured out */
|
||||
MYID_HOSTNAME, /* our current hostname */
|
||||
MYID_IP, /* our default IP address */
|
||||
MYID_SPECIFIED /* as specified by ipsec.conf */
|
||||
};
|
||||
|
||||
extern enum myid_state myid_state;
|
||||
extern struct id myids[MYID_SPECIFIED+1]; /* %myid */
|
||||
extern char *myid_str[MYID_SPECIFIED+1]; /* strings */
|
||||
extern void set_myid(enum myid_state s, char *);
|
||||
extern void show_myid_status(void);
|
||||
#define resolve_myid(id) ((id)->kind == ID_MYID? &myids[myid_state] : (id))
|
||||
extern void set_myFQDN(void);
|
||||
|
||||
extern err_t atoid(char *src, struct id *id, bool myid_ok);
|
||||
extern int keyidtoa(char *dst, size_t dstlen, chunk_t keyid);
|
||||
extern void iptoid(const ip_address *ip, struct id *id);
|
||||
extern int idtoa(const struct id *id, char *dst, size_t dstlen);
|
||||
#define IDTOA_BUF 512
|
||||
extern void escape_metachar(const char *src, char *dst, size_t dstlen);
|
||||
struct end; /* forward declaration of tag (defined in connections.h) */
|
||||
extern void unshare_id_content(struct id *id);
|
||||
extern void free_id_content(struct id *id);
|
||||
extern bool same_id(const struct id *a, const struct id *b);
|
||||
#define MAX_WILDCARDS 15
|
||||
extern bool match_id(const struct id *a, const struct id *b, int *wildcards);
|
||||
extern int id_count_wildcards(const struct id *id);
|
||||
#define id_is_ipaddr(id) ((id)->kind == ID_IPV4_ADDR || (id)->kind == ID_IPV6_ADDR)
|
||||
|
||||
struct isakmp_ipsec_id; /* forward declaration of tag (defined in packet.h) */
|
||||
extern void build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl,
|
||||
struct end *end);
|
||||
extern void id_from_identification(struct id *id, identification_t *identification);
|
||||
|
||||
#endif /* _ID_H */
|
||||
+134
-145
@@ -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 @");
|
||||
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;
|
||||
}
|
||||
/* 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));
|
||||
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
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef _IPSEC_DOI_H
|
||||
#define _IPSEC_DOI_H
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
extern void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np);
|
||||
|
||||
extern void ipsecdoi_initiate(int whack_sock, struct connection *c
|
||||
@@ -99,4 +104,5 @@ extern void dpd_timeout(struct state *st);
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* _IPSEC_DOI_H */
|
||||
|
||||
|
||||
+31
-7
@@ -45,7 +45,6 @@
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "id.h"
|
||||
#include "connections.h"
|
||||
#include "state.h"
|
||||
#include "timer.h"
|
||||
@@ -357,6 +356,33 @@ ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel)
|
||||
return htonl((ipsec_spi_t)latest_cpi);
|
||||
}
|
||||
|
||||
/* Replace the shell metacharacters ', \, ", `, and $ in a character string
|
||||
* by escape sequences consisting of their octal values
|
||||
*/
|
||||
static void escape_metachar(const char *src, char *dst, size_t dstlen)
|
||||
{
|
||||
while (*src != '\0' && dstlen > 4)
|
||||
{
|
||||
switch (*src)
|
||||
{
|
||||
case '\'':
|
||||
case '\\':
|
||||
case '"':
|
||||
case '`':
|
||||
case '$':
|
||||
sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src);
|
||||
dst += 4;
|
||||
dstlen -= 4;
|
||||
break;
|
||||
default:
|
||||
*dst++ = *src;
|
||||
dstlen--;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
/* invoke the updown script to do the routing and firewall commands required
|
||||
*
|
||||
* The user-specified updown script is run. Parameters are fed to it in
|
||||
@@ -471,7 +497,7 @@ static bool do_command(connection_t *c, struct spd_route *sr,
|
||||
}
|
||||
|
||||
addrtot(&sr->this.host_addr, 0, me_str, sizeof(me_str));
|
||||
idtoa(&sr->this.id, myid_str, sizeof(myid_str));
|
||||
snprintf(myid_str, sizeof(myid_str), "%Y", sr->this.id);
|
||||
escape_metachar(myid_str, secure_myid_str, sizeof(secure_myid_str));
|
||||
subnettot(&sr->this.client, 0, myclient_str, sizeof(myclientnet_str));
|
||||
networkof(&sr->this.client, &ta);
|
||||
@@ -480,7 +506,7 @@ static bool do_command(connection_t *c, struct spd_route *sr,
|
||||
addrtot(&ta, 0, myclientmask_str, sizeof(myclientmask_str));
|
||||
|
||||
addrtot(&sr->that.host_addr, 0, peer_str, sizeof(peer_str));
|
||||
idtoa(&sr->that.id, peerid_str, sizeof(peerid_str));
|
||||
snprintf(peerid_str, sizeof(peerid_str), "%Y", sr->that.id);
|
||||
escape_metachar(peerid_str, secure_peerid_str, sizeof(secure_peerid_str));
|
||||
subnettot(&sr->that.client, 0, peerclient_str, sizeof(peerclientnet_str));
|
||||
networkof(&sr->that.client, &ta);
|
||||
@@ -492,12 +518,10 @@ static bool do_command(connection_t *c, struct spd_route *sr,
|
||||
{
|
||||
pubkey_t *key = p->key;
|
||||
key_type_t type = key->public_key->get_type(key->public_key);
|
||||
struct id key_id;
|
||||
int pathlen;
|
||||
|
||||
id_from_identification(&key_id, key->id);
|
||||
|
||||
if (type == KEY_RSA && same_id(&sr->that.id, &key_id) &&
|
||||
if (type == KEY_RSA &&
|
||||
sr->that.id->equals(sr->that.id, key->id) &&
|
||||
trusted_ca(key->issuer, sr->that.ca, &pathlen))
|
||||
{
|
||||
if (key->issuer)
|
||||
|
||||
+25
-60
@@ -39,7 +39,6 @@
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "id.h"
|
||||
#include "x509.h"
|
||||
#include "pgpcert.h"
|
||||
#include "certs.h"
|
||||
@@ -61,7 +60,7 @@ const char *shared_secrets_file = SHARED_SECRETS_FILE;
|
||||
typedef struct id_list id_list_t;
|
||||
|
||||
struct id_list {
|
||||
struct id id;
|
||||
identification_t *id;
|
||||
id_list_t *next;
|
||||
};
|
||||
|
||||
@@ -109,9 +108,7 @@ static const secret_t* get_secret(const connection_t *c,
|
||||
unsigned int best_match = 0;
|
||||
secret_t *best = NULL;
|
||||
secret_t *s;
|
||||
const struct id *my_id = &c->spd.this.id
|
||||
, *his_id = &c->spd.that.id;
|
||||
struct id rw_id;
|
||||
identification_t *my_id, *his_id;
|
||||
|
||||
/* is there a certificate assigned to this connection? */
|
||||
if (kind == PPK_PUBKEY && c->spd.this.cert.type != CERT_NONE)
|
||||
@@ -131,23 +128,24 @@ static const secret_t* get_secret(const connection_t *c,
|
||||
return best;
|
||||
}
|
||||
|
||||
my_id = c->spd.this.id;
|
||||
|
||||
if (his_id_was_instantiated(c))
|
||||
{
|
||||
/* roadwarrior: replace him with 0.0.0.0 */
|
||||
rw_id.kind = c->spd.that.id.kind;
|
||||
rw_id.name = chunk_empty;
|
||||
happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr));
|
||||
his_id = &rw_id;
|
||||
his_id = identification_create_from_string("%any");
|
||||
}
|
||||
else if (kind == PPK_PSK
|
||||
&& (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK))
|
||||
&& ((c->kind == CK_TEMPLATE && c->spd.that.id.kind == ID_ANY) ||
|
||||
(c->kind == CK_INSTANCE && id_is_ipaddr(&c->spd.that.id))))
|
||||
else if (kind == PPK_PSK && (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK)) &&
|
||||
((c->kind == CK_TEMPLATE &&
|
||||
c->spd.that.id->get_type(c->spd.that.id) == ID_ANY) ||
|
||||
(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;
|
||||
his_id = identification_create_from_string("%any");
|
||||
}
|
||||
else
|
||||
{
|
||||
his_id = c->spd.that.id->clone(c->spd.that.id);
|
||||
}
|
||||
|
||||
for (s = secrets; s != NULL; s = s->next)
|
||||
@@ -170,11 +168,11 @@ static const secret_t* get_secret(const connection_t *c,
|
||||
|
||||
for (i = s->ids; i != NULL; i = i->next)
|
||||
{
|
||||
if (same_id(my_id, &i->id))
|
||||
if (my_id->equals(my_id, i->id))
|
||||
{
|
||||
match |= match_me;
|
||||
}
|
||||
if (same_id(his_id, &i->id))
|
||||
if (his_id->equals(his_id, i->id))
|
||||
{
|
||||
match |= match_him;
|
||||
}
|
||||
@@ -240,6 +238,7 @@ static const secret_t* get_secret(const connection_t *c,
|
||||
}
|
||||
}
|
||||
}
|
||||
his_id->destroy(his_id);
|
||||
return best;
|
||||
}
|
||||
|
||||
@@ -761,16 +760,12 @@ static void log_psk(secret_t *s)
|
||||
{
|
||||
do
|
||||
{
|
||||
n += idtoa(&id_list->id, buf + n, BUF_LEN - n);
|
||||
n += snprintf(buf + n, BUF_LEN - n, "%Y ", id_list->id);
|
||||
if (n >= BUF_LEN)
|
||||
{
|
||||
n = BUF_LEN - 1;
|
||||
break;
|
||||
}
|
||||
else if (n < BUF_LEN - 1)
|
||||
{
|
||||
n += snprintf(buf + n, BUF_LEN - n, " ");
|
||||
}
|
||||
id_list = id_list->next;
|
||||
}
|
||||
while (id_list);
|
||||
@@ -947,42 +942,12 @@ static void process_secret_records(int whackfd)
|
||||
/* an id
|
||||
* See RFC2407 IPsec Domain of Interpretation 4.6.2
|
||||
*/
|
||||
struct id id;
|
||||
err_t ugh;
|
||||
id_list_t *i = malloc_thing(id_list_t);
|
||||
|
||||
if (tokeq("%any"))
|
||||
{
|
||||
id = empty_id;
|
||||
id.kind = ID_IPV4_ADDR;
|
||||
ugh = anyaddr(AF_INET, &id.ip_addr);
|
||||
}
|
||||
else if (tokeq("%any6"))
|
||||
{
|
||||
id = empty_id;
|
||||
id.kind = ID_IPV6_ADDR;
|
||||
ugh = anyaddr(AF_INET6, &id.ip_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ugh = atoid(tok, &id, FALSE);
|
||||
}
|
||||
i->id = identification_create_from_string(tok);
|
||||
i->next = s->ids;
|
||||
s->ids = i;
|
||||
|
||||
if (ugh != NULL)
|
||||
{
|
||||
loglog(RC_LOG_SERIOUS
|
||||
, "ERROR \"%s\" line %d: index \"%s\" %s"
|
||||
, flp->filename, flp->lino, tok, ugh);
|
||||
}
|
||||
else
|
||||
{
|
||||
id_list_t *i = malloc_thing(id_list_t);
|
||||
|
||||
i->id = id;
|
||||
unshare_id_content(&i->id);
|
||||
i->next = s->ids;
|
||||
s->ids = i;
|
||||
/* DBG_log("id type %d: %s %.*s", i->kind, ip_str(&i->ip_addr), (int)i->name.len, i->name.ptr); */
|
||||
}
|
||||
if (!shift())
|
||||
{
|
||||
/* unexpected Record Boundary or EOF */
|
||||
@@ -1070,11 +1035,11 @@ void free_preshared_secrets(void)
|
||||
{
|
||||
id_list_t *i, *ni;
|
||||
|
||||
ns = s->next; /* grab before freeing s */
|
||||
ns = s->next;
|
||||
for (i = s->ids; i != NULL; i = ni)
|
||||
{
|
||||
ni = i->next; /* grab before freeing i */
|
||||
free_id_content(&i->id);
|
||||
ni = i->next;
|
||||
i->id->destroy(i->id);
|
||||
free(i);
|
||||
}
|
||||
switch (s->kind)
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "server.h"
|
||||
#include "state.h"
|
||||
#include "connections.h"
|
||||
#include "myid.h"
|
||||
#include "kernel.h"
|
||||
#include "whack.h" /* needs connections.h */
|
||||
#include "timer.h"
|
||||
|
||||
+2
-1
@@ -1154,7 +1154,8 @@ xauth_inR1(struct msg_digest *md)
|
||||
|
||||
peer.conn_name = st->st_connection->name;
|
||||
addrtot(&md->sender, 0, peer.ip_address, sizeof(peer.ip_address));
|
||||
idtoa(&md->st->st_connection->spd.that.id, peer.id, sizeof(peer.id));
|
||||
snprintf(peer.id, sizeof(peer.id), "%Y",
|
||||
md->st->st_connection->spd.that.id);
|
||||
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_log("peer xauth user name is '%.*s'"
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1)
|
||||
* Copyright (C) 1999-2001 D. Hugh Redelmeier
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says <unistd.h> defines this */
|
||||
# define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */
|
||||
#endif
|
||||
|
||||
#include <utils/identification.h>
|
||||
|
||||
#include <freeswan.h>
|
||||
|
||||
#include "myid.h"
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "log.h"
|
||||
#include "connections.h"
|
||||
#include "packet.h"
|
||||
#include "whack.h"
|
||||
|
||||
enum myid_state myid_state = MYID_UNKNOWN;
|
||||
|
||||
identification_t *myids[MYID_SPECIFIED+1]; /* %myid */
|
||||
|
||||
/**
|
||||
* Fills in myid from environment variable IPSECmyid or defaultrouteaddr
|
||||
*/
|
||||
void init_myid(void)
|
||||
{
|
||||
myid_state = MYID_UNKNOWN;
|
||||
{
|
||||
enum myid_state s;
|
||||
|
||||
for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++)
|
||||
{
|
||||
myids[s] = identification_create_from_string("%any");
|
||||
}
|
||||
}
|
||||
set_myid(MYID_SPECIFIED, getenv("IPSECmyid"));
|
||||
set_myid(MYID_IP, getenv("defaultrouteaddr"));
|
||||
set_myFQDN();
|
||||
}
|
||||
|
||||
/**
|
||||
* Free myid module
|
||||
*/
|
||||
void free_myid(void)
|
||||
{
|
||||
enum myid_state s;
|
||||
|
||||
for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++)
|
||||
{
|
||||
myids[s]->destroy(myids[s]);
|
||||
}
|
||||
}
|
||||
|
||||
void set_myid(enum myid_state s, char *idstr)
|
||||
{
|
||||
if (idstr)
|
||||
{
|
||||
myids[s]->destroy(myids[s]);
|
||||
myids[s] = identification_create_from_string(idstr);
|
||||
if (s == MYID_SPECIFIED)
|
||||
{
|
||||
myid_state = MYID_SPECIFIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_myFQDN(void)
|
||||
{
|
||||
char FQDN[HOST_NAME_MAX + 1];
|
||||
int r = gethostname(FQDN, sizeof(FQDN));
|
||||
size_t len;
|
||||
|
||||
if (r != 0)
|
||||
{
|
||||
log_errno((e, "gethostname() failed in set_myFQDN"));
|
||||
}
|
||||
else
|
||||
{
|
||||
FQDN[sizeof(FQDN) - 1] = '\0'; /* insurance */
|
||||
len = strlen(FQDN);
|
||||
|
||||
if (len > 0 && FQDN[len-1] == '.')
|
||||
{
|
||||
/* nuke trailing . */
|
||||
FQDN[len-1] = '\0';
|
||||
}
|
||||
if (!strcaseeq(FQDN, "localhost.localdomain"))
|
||||
{
|
||||
myids[MYID_HOSTNAME]->destroy(myids[MYID_HOSTNAME]);
|
||||
myids[MYID_HOSTNAME] = identification_create_from_string(FQDN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void show_myid_status(void)
|
||||
{
|
||||
whack_log(RC_COMMENT, "%%myid = '%Y'", myids[myid_state]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* c-basic-offset:4
|
||||
* c-style: pluto
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,38 @@
|
||||
/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1)
|
||||
* Copyright (C) 1999-2001 D. Hugh Redelmeier
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _MYID_H
|
||||
#define _MYID_H
|
||||
|
||||
#include <utils/identification.h>
|
||||
|
||||
extern void init_myid(void);
|
||||
extern void free_myid(void);
|
||||
|
||||
enum myid_state {
|
||||
MYID_UNKNOWN, /* not yet figured out */
|
||||
MYID_HOSTNAME, /* our current hostname */
|
||||
MYID_IP, /* our default IP address */
|
||||
MYID_SPECIFIED /* as specified by ipsec.conf */
|
||||
};
|
||||
|
||||
extern enum myid_state myid_state;
|
||||
extern identification_t* myids[MYID_SPECIFIED+1]; /* %myid */
|
||||
extern void set_myid(enum myid_state s, char *);
|
||||
extern void show_myid_status(void);
|
||||
extern void set_myFQDN(void);
|
||||
|
||||
#define resolve_myid(id) ((id)->get_type(id) == ID_MYID? myids[myid_state] : (id))
|
||||
|
||||
#endif /* _MYID_H */
|
||||
+4
-5
@@ -27,13 +27,11 @@
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "log.h"
|
||||
#include "id.h"
|
||||
#include "pgpcert.h"
|
||||
#include "certs.h"
|
||||
#include "whack.h"
|
||||
#include "keys.h"
|
||||
|
||||
|
||||
typedef enum pgp_packet_tag_t pgp_packet_tag_t;
|
||||
|
||||
/**
|
||||
@@ -399,10 +397,11 @@ void share_pgpcert(pgpcert_t *cert)
|
||||
/**
|
||||
* Select the OpenPGP keyid as ID
|
||||
*/
|
||||
void select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
|
||||
identification_t* select_pgpcert_id(pgpcert_t *cert, identification_t *id)
|
||||
{
|
||||
end_id->kind = ID_KEY_ID;
|
||||
end_id->name = cert->fingerprint->get_encoding(cert->fingerprint);
|
||||
id->destroy(id);
|
||||
|
||||
return cert->fingerprint->clone(cert->fingerprint);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@
|
||||
#ifndef _PGPCERT_H
|
||||
#define _PGPCERT_H
|
||||
|
||||
#include <utils/identification.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
#include <credentials/keys/private_key.h>
|
||||
#include <credentials/keys/public_key.h>
|
||||
@@ -46,7 +47,7 @@ struct pgpcert {
|
||||
extern const pgpcert_t pgpcert_empty;
|
||||
extern bool parse_pgp(chunk_t blob, pgpcert_t *cert);
|
||||
extern void share_pgpcert(pgpcert_t *cert);
|
||||
extern void select_pgpcert_id(pgpcert_t *cert, struct id *end_id);
|
||||
extern identification_t* select_pgpcert_id(pgpcert_t *cert, identification_t *id);
|
||||
extern pgpcert_t* add_pgpcert(pgpcert_t *cert);
|
||||
extern void list_pgp_end_certs(bool utc);
|
||||
extern void release_pgpcert(pgpcert_t *cert);
|
||||
|
||||
+26
-32
@@ -19,8 +19,6 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <freeswan.h>
|
||||
|
||||
#include <library.h>
|
||||
#include <debug.h>
|
||||
#include <asn1/asn1.h>
|
||||
@@ -28,11 +26,8 @@
|
||||
#include <asn1/oid.h>
|
||||
#include <crypto/rngs/rng.h>
|
||||
#include <crypto/crypters/crypter.h>
|
||||
#include <credentials/certificates/x509.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "x509.h"
|
||||
#include "certs.h"
|
||||
#include "pkcs7.h"
|
||||
|
||||
const contentInfo_t empty_contentInfo = {
|
||||
@@ -170,7 +165,8 @@ end:
|
||||
/**
|
||||
* Parse a PKCS#7 signedData object
|
||||
*/
|
||||
bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert,
|
||||
bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data,
|
||||
linked_list_t *certs,
|
||||
chunk_t *attributes, certificate_t *cacert)
|
||||
{
|
||||
asn1_parser_t *parser;
|
||||
@@ -218,24 +214,17 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
|
||||
}
|
||||
break;
|
||||
case PKCS7_SIGNED_CERT:
|
||||
if (cert != NULL)
|
||||
{
|
||||
x509cert_t *newcert = malloc_thing(x509cert_t);
|
||||
certificate_t *cert;
|
||||
|
||||
DBG2(" parsing pkcs7-wrapped certificate");
|
||||
*newcert = empty_x509cert;
|
||||
newcert->cert = lib->creds->create(lib->creds,
|
||||
CRED_CERTIFICATE, CERT_X509,
|
||||
BUILD_BLOB_ASN1_DER, object,
|
||||
BUILD_END);
|
||||
if (newcert->cert)
|
||||
cert = lib->creds->create(lib->creds,
|
||||
CRED_CERTIFICATE, CERT_X509,
|
||||
BUILD_BLOB_ASN1_DER, object,
|
||||
BUILD_END);
|
||||
if (cert)
|
||||
{
|
||||
newcert->next = *cert;
|
||||
*cert = newcert;
|
||||
}
|
||||
else
|
||||
{
|
||||
free_x509cert(newcert);
|
||||
certs->insert_last(certs, cert);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -600,22 +589,27 @@ chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
|
||||
private_key_t *key)
|
||||
{
|
||||
contentInfo_t pkcs7Data, signedData;
|
||||
chunk_t authenticatedAttributes, encryptedDigest, signerInfo, cInfo;
|
||||
chunk_t authenticatedAttributes = chunk_empty;
|
||||
chunk_t encryptedDigest = chunk_empty;
|
||||
chunk_t signerInfo, cInfo, signature;
|
||||
signature_scheme_t scheme = signature_scheme_from_oid(digest_alg);
|
||||
|
||||
if (attributes.ptr != NULL)
|
||||
if (attributes.ptr)
|
||||
{
|
||||
encryptedDigest = x509_build_signature(attributes, digest_alg, key,
|
||||
FALSE);
|
||||
authenticatedAttributes = chunk_clone(attributes);
|
||||
*authenticatedAttributes.ptr = ASN1_CONTEXT_C_0;
|
||||
if (key->sign(key, scheme, attributes, &signature))
|
||||
{
|
||||
encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature);
|
||||
authenticatedAttributes = chunk_clone(attributes);
|
||||
*authenticatedAttributes.ptr = ASN1_CONTEXT_C_0;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (data.ptr)
|
||||
{
|
||||
encryptedDigest = (data.ptr == NULL)? chunk_empty
|
||||
: x509_build_signature(data, digest_alg, key, FALSE);
|
||||
authenticatedAttributes = chunk_empty;
|
||||
if (key->sign(key, scheme, data, &signature))
|
||||
{
|
||||
encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature);
|
||||
}
|
||||
}
|
||||
|
||||
signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm"
|
||||
, ASN1_INTEGER_1
|
||||
, pkcs7_build_issuerAndSerialNumber(cert)
|
||||
|
||||
+2
-3
@@ -18,11 +18,10 @@
|
||||
#ifndef _PKCS7_H
|
||||
#define _PKCS7_H
|
||||
|
||||
#include <utils/linked_list.h>
|
||||
#include <crypto/crypters/crypter.h>
|
||||
#include <credentials/keys/private_key.h>
|
||||
#include <credentials/certificates/certificate.h>
|
||||
#include "defs.h"
|
||||
#include "x509.h"
|
||||
|
||||
/* Access structure for a PKCS#7 ContentInfo object */
|
||||
|
||||
@@ -38,7 +37,7 @@ extern const contentInfo_t empty_contentInfo;
|
||||
extern bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0,
|
||||
contentInfo_t *cInfo);
|
||||
extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data,
|
||||
x509cert_t **cert, chunk_t *attributes,
|
||||
linked_list_t *cert, chunk_t *attributes,
|
||||
certificate_t *cacert);
|
||||
extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
|
||||
chunk_t serialNumber, private_key_t *key);
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "id.h"
|
||||
#include "myid.h"
|
||||
#include "ca.h"
|
||||
#include "certs.h"
|
||||
#include "ac.h"
|
||||
@@ -673,7 +673,7 @@ int main(int argc, char **argv)
|
||||
init_demux();
|
||||
init_kernel();
|
||||
init_adns();
|
||||
init_id();
|
||||
init_myid();
|
||||
init_fetch();
|
||||
|
||||
/* drop unneeded capabilities and change UID/GID */
|
||||
@@ -762,7 +762,7 @@ void exit_pluto(int status)
|
||||
stop_adns();
|
||||
free_md_pool();
|
||||
free_crypto();
|
||||
free_id(); /* free myids */
|
||||
free_myid(); /* free myids */
|
||||
free_events(); /* free remaining events */
|
||||
free_vendorid(); /* free all vendor id records */
|
||||
free_builder();
|
||||
|
||||
+56
-67
@@ -33,7 +33,6 @@
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "id.h"
|
||||
#include "ca.h"
|
||||
#include "certs.h"
|
||||
#include "ac.h"
|
||||
@@ -55,9 +54,10 @@
|
||||
#include "fetch.h"
|
||||
#include "ocsp.h"
|
||||
#include "crl.h"
|
||||
|
||||
#include "myid.h"
|
||||
#include "kernel_alg.h"
|
||||
#include "ike_alg.h"
|
||||
|
||||
/* helper variables and function to decode strings from whack message */
|
||||
|
||||
static char *next_str
|
||||
@@ -102,17 +102,13 @@ struct key_add_continuation {
|
||||
enum key_add_attempt lookingfor;
|
||||
};
|
||||
|
||||
static void key_add_ugh(const struct id *keyid, err_t ugh)
|
||||
static void key_add_ugh(identification_t *keyid, err_t ugh)
|
||||
{
|
||||
char name[BUF_LEN]; /* longer IDs will be truncated in message */
|
||||
|
||||
(void)idtoa(keyid, name, sizeof(name));
|
||||
loglog(RC_NOKEY
|
||||
, "failure to fetch key for %s from DNS: %s", name, ugh);
|
||||
loglog(RC_NOKEY, "failure to fetch key for %'Y' from DNS: %s", keyid, ugh);
|
||||
}
|
||||
|
||||
/* last one out: turn out the lights */
|
||||
static void key_add_merge(struct key_add_common *oc, const struct id *keyid)
|
||||
static void key_add_merge(struct key_add_common *oc, identification_t *keyid)
|
||||
{
|
||||
if (oc->refCount == 0)
|
||||
{
|
||||
@@ -120,9 +116,12 @@ static void key_add_merge(struct key_add_common *oc, const struct id *keyid)
|
||||
|
||||
/* if no success, print all diagnostics */
|
||||
if (!oc->success)
|
||||
{
|
||||
for (kaa = ka_TXT; kaa != ka_roof; kaa++)
|
||||
{
|
||||
key_add_ugh(keyid, oc->diag[kaa]);
|
||||
|
||||
}
|
||||
}
|
||||
for (kaa = ka_TXT; kaa != ka_roof; kaa++)
|
||||
{
|
||||
free(oc->diag[kaa]);
|
||||
@@ -155,91 +154,81 @@ static void key_add_continue(struct adns_continuation *ac, err_t ugh)
|
||||
}
|
||||
|
||||
oc->refCount--;
|
||||
key_add_merge(oc, &ac->id);
|
||||
key_add_merge(oc, ac->id);
|
||||
whack_log_fd = NULL_FD;
|
||||
}
|
||||
|
||||
static void key_add_request(const whack_message_t *msg)
|
||||
{
|
||||
identification_t *key_id;
|
||||
struct id keyid;
|
||||
err_t ugh = atoid(msg->keyid, &keyid, FALSE);
|
||||
|
||||
if (ugh != NULL)
|
||||
key_id = identification_create_from_string(msg->keyid);
|
||||
|
||||
if (!msg->whack_addkey)
|
||||
{
|
||||
loglog(RC_BADID, "bad --keyid \"%s\": %s", msg->keyid, ugh);
|
||||
delete_public_keys(key_id, msg->pubkey_alg, NULL, chunk_empty);
|
||||
}
|
||||
else
|
||||
if (msg->keyval.len == 0)
|
||||
{
|
||||
key_id = identification_create_from_string(msg->keyid);
|
||||
struct key_add_common *oc = malloc_thing(struct key_add_common);
|
||||
enum key_add_attempt kaa;
|
||||
err_t ugh;
|
||||
|
||||
if (!msg->whack_addkey)
|
||||
/* initialize state shared by queries */
|
||||
oc->refCount = 0;
|
||||
oc->whack_fd = dup_any(whack_log_fd);
|
||||
oc->success = FALSE;
|
||||
|
||||
for (kaa = ka_TXT; kaa != ka_roof; kaa++)
|
||||
{
|
||||
delete_public_keys(key_id, msg->pubkey_alg, NULL, chunk_empty);
|
||||
}
|
||||
if (msg->keyval.len == 0)
|
||||
{
|
||||
struct key_add_common *oc = malloc_thing(struct key_add_common);
|
||||
enum key_add_attempt kaa;
|
||||
struct key_add_continuation *kc;
|
||||
|
||||
/* initialize state shared by queries */
|
||||
oc->refCount = 0;
|
||||
oc->whack_fd = dup_any(whack_log_fd);
|
||||
oc->success = FALSE;
|
||||
oc->diag[kaa] = NULL;
|
||||
oc->refCount++;
|
||||
kc = malloc_thing(struct key_add_continuation);
|
||||
kc->common = oc;
|
||||
kc->lookingfor = kaa;
|
||||
|
||||
for (kaa = ka_TXT; kaa != ka_roof; kaa++)
|
||||
switch (kaa)
|
||||
{
|
||||
struct key_add_continuation *kc;
|
||||
|
||||
oc->diag[kaa] = NULL;
|
||||
oc->refCount++;
|
||||
kc = malloc_thing(struct key_add_continuation);
|
||||
kc->common = oc;
|
||||
kc->lookingfor = kaa;
|
||||
|
||||
switch (kaa)
|
||||
{
|
||||
case ka_TXT:
|
||||
ugh = start_adns_query(&keyid
|
||||
, &keyid /* same */
|
||||
, T_TXT
|
||||
, key_add_continue
|
||||
, &kc->ac);
|
||||
ugh = start_adns_query(key_id
|
||||
, key_id /* same */
|
||||
, T_TXT
|
||||
, key_add_continue
|
||||
, &kc->ac);
|
||||
break;
|
||||
#ifdef USE_KEYRR
|
||||
case ka_KEY:
|
||||
ugh = start_adns_query(&keyid
|
||||
, NULL
|
||||
, T_KEY
|
||||
, key_add_continue
|
||||
, &kc->ac);
|
||||
ugh = start_adns_query(key_id
|
||||
, NULL
|
||||
, T_KEY
|
||||
, key_add_continue
|
||||
, &kc->ac);
|
||||
break;
|
||||
#endif /* USE_KEYRR */
|
||||
default:
|
||||
bad_case(kaa); /* suppress gcc warning */
|
||||
}
|
||||
if (ugh != NULL)
|
||||
{
|
||||
oc->diag[kaa] = clone_str(ugh);
|
||||
oc->refCount--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Done launching queries.
|
||||
* Handle total failure case.
|
||||
*/
|
||||
key_add_merge(oc, &keyid);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!add_public_key(key_id, DAL_LOCAL, msg->pubkey_alg, msg->keyval,
|
||||
&pubkeys))
|
||||
if (ugh)
|
||||
{
|
||||
loglog(RC_LOG_SERIOUS, "failed to add public key");
|
||||
oc->diag[kaa] = clone_str(ugh);
|
||||
oc->refCount--;
|
||||
}
|
||||
}
|
||||
key_id->destroy(key_id);
|
||||
|
||||
/* Done launching queries. Handle total failure case. */
|
||||
key_add_merge(oc, key_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!add_public_key(key_id, DAL_LOCAL, msg->pubkey_alg, msg->keyval,
|
||||
&pubkeys))
|
||||
{
|
||||
loglog(RC_LOG_SERIOUS, "failed to add public key");
|
||||
}
|
||||
}
|
||||
key_id->destroy(key_id);
|
||||
}
|
||||
|
||||
/* Handle a kernel request. Supposedly, there's a message in
|
||||
|
||||
+4
-6
@@ -24,7 +24,6 @@
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "id.h"
|
||||
#include "connections.h"
|
||||
#include "state.h"
|
||||
#include "packet.h"
|
||||
@@ -835,19 +834,18 @@ static err_t find_preshared_key(struct state* st)
|
||||
|
||||
if (get_preshared_secret(c) == NULL)
|
||||
{
|
||||
char my_id[BUF_LEN], his_id[BUF_LEN];
|
||||
char 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));
|
||||
snprintf(his_id, sizeof(his_id), "%Y", c->spd.that.id);
|
||||
}
|
||||
ugh = builddiag("Can't authenticate: no preshared key found for `%s' and `%s'"
|
||||
, my_id, his_id);
|
||||
ugh = builddiag("Can't authenticate: no preshared key found "
|
||||
"for '%Y' and '%s'", c->spd.this.id, his_id);
|
||||
}
|
||||
return ugh;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <crypto/diffie_hellman.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include "connections.h"
|
||||
|
||||
/* Message ID mechanism.
|
||||
|
||||
+50
-735
@@ -26,8 +26,6 @@
|
||||
#include <freeswan.h>
|
||||
|
||||
#include <asn1/asn1.h>
|
||||
#include <asn1/asn1_parser.h>
|
||||
#include <asn1/oid.h>
|
||||
#include <crypto/hashers/hasher.h>
|
||||
#include <utils/enumerator.h>
|
||||
#include <utils/identification.h>
|
||||
@@ -35,7 +33,6 @@
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "log.h"
|
||||
#include "id.h"
|
||||
#include "x509.h"
|
||||
#include "crl.h"
|
||||
#include "ca.h"
|
||||
@@ -50,23 +47,6 @@
|
||||
*/
|
||||
static x509cert_t *x509certs = NULL;
|
||||
|
||||
/**
|
||||
* ASN.1 definition of a authorityKeyIdentifier extension
|
||||
*/
|
||||
static const asn1Object_t authKeyIdentifierObjects[] = {
|
||||
{ 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT|ASN1_BODY }, /* 1 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
|
||||
{ 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_OBJ }, /* 3 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */
|
||||
{ 1, "authorityCertSerialNumber", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 5 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
#define AUTH_KEY_ID_KEY_ID 1
|
||||
#define AUTH_KEY_ID_CERT_ISSUER 3
|
||||
#define AUTH_KEY_ID_CERT_SERIAL 5
|
||||
|
||||
const x509cert_t empty_x509cert = {
|
||||
NULL , /* cert */
|
||||
NULL , /* *next */
|
||||
@@ -76,666 +56,6 @@ const x509cert_t empty_x509cert = {
|
||||
|
||||
/* coding of X.501 distinguished name */
|
||||
|
||||
typedef struct {
|
||||
const u_char *name;
|
||||
chunk_t oid;
|
||||
u_char type;
|
||||
} x501rdn_t;
|
||||
|
||||
/* X.501 acronyms for well known object identifiers (OIDs) */
|
||||
|
||||
static u_char oid_ND[] = {0x02, 0x82, 0x06, 0x01,
|
||||
0x0A, 0x07, 0x14};
|
||||
static u_char oid_UID[] = {0x09, 0x92, 0x26, 0x89, 0x93,
|
||||
0xF2, 0x2C, 0x64, 0x01, 0x01};
|
||||
static u_char oid_DC[] = {0x09, 0x92, 0x26, 0x89, 0x93,
|
||||
0xF2, 0x2C, 0x64, 0x01, 0x19};
|
||||
static u_char oid_CN[] = {0x55, 0x04, 0x03};
|
||||
static u_char oid_S[] = {0x55, 0x04, 0x04};
|
||||
static u_char oid_SN[] = {0x55, 0x04, 0x05};
|
||||
static u_char oid_C[] = {0x55, 0x04, 0x06};
|
||||
static u_char oid_L[] = {0x55, 0x04, 0x07};
|
||||
static u_char oid_ST[] = {0x55, 0x04, 0x08};
|
||||
static u_char oid_O[] = {0x55, 0x04, 0x0A};
|
||||
static u_char oid_OU[] = {0x55, 0x04, 0x0B};
|
||||
static u_char oid_T[] = {0x55, 0x04, 0x0C};
|
||||
static u_char oid_D[] = {0x55, 0x04, 0x0D};
|
||||
static u_char oid_N[] = {0x55, 0x04, 0x29};
|
||||
static u_char oid_G[] = {0x55, 0x04, 0x2A};
|
||||
static u_char oid_I[] = {0x55, 0x04, 0x2B};
|
||||
static u_char oid_ID[] = {0x55, 0x04, 0x2D};
|
||||
static u_char oid_EN[] = {0x60, 0x86, 0x48, 0x01, 0x86,
|
||||
0xF8, 0x42, 0x03, 0x01, 0x03};
|
||||
static u_char oid_E[] = {0x2A, 0x86, 0x48, 0x86, 0xF7,
|
||||
0x0D, 0x01, 0x09, 0x01};
|
||||
static u_char oid_UN[] = {0x2A, 0x86, 0x48, 0x86, 0xF7,
|
||||
0x0D, 0x01, 0x09, 0x02};
|
||||
static u_char oid_TCGID[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x89,
|
||||
0x31, 0x01, 0x01, 0x02, 0x02, 0x4B};
|
||||
|
||||
static const x501rdn_t x501rdns[] = {
|
||||
{"ND" , {oid_ND, 7}, ASN1_PRINTABLESTRING},
|
||||
{"UID" , {oid_UID, 10}, ASN1_PRINTABLESTRING},
|
||||
{"DC" , {oid_DC, 10}, ASN1_PRINTABLESTRING},
|
||||
{"CN" , {oid_CN, 3}, ASN1_PRINTABLESTRING},
|
||||
{"S" , {oid_S, 3}, ASN1_PRINTABLESTRING},
|
||||
{"SN" , {oid_SN, 3}, ASN1_PRINTABLESTRING},
|
||||
{"serialNumber" , {oid_SN, 3}, ASN1_PRINTABLESTRING},
|
||||
{"C" , {oid_C, 3}, ASN1_PRINTABLESTRING},
|
||||
{"L" , {oid_L, 3}, ASN1_PRINTABLESTRING},
|
||||
{"ST" , {oid_ST, 3}, ASN1_PRINTABLESTRING},
|
||||
{"O" , {oid_O, 3}, ASN1_PRINTABLESTRING},
|
||||
{"OU" , {oid_OU, 3}, ASN1_PRINTABLESTRING},
|
||||
{"T" , {oid_T, 3}, ASN1_PRINTABLESTRING},
|
||||
{"D" , {oid_D, 3}, ASN1_PRINTABLESTRING},
|
||||
{"N" , {oid_N, 3}, ASN1_PRINTABLESTRING},
|
||||
{"G" , {oid_G, 3}, ASN1_PRINTABLESTRING},
|
||||
{"I" , {oid_I, 3}, ASN1_PRINTABLESTRING},
|
||||
{"ID" , {oid_ID, 3}, ASN1_PRINTABLESTRING},
|
||||
{"EN" , {oid_EN, 10}, ASN1_PRINTABLESTRING},
|
||||
{"employeeNumber" , {oid_EN, 10}, ASN1_PRINTABLESTRING},
|
||||
{"E" , {oid_E, 9}, ASN1_IA5STRING},
|
||||
{"Email" , {oid_E, 9}, ASN1_IA5STRING},
|
||||
{"emailAddress" , {oid_E, 9}, ASN1_IA5STRING},
|
||||
{"UN" , {oid_UN, 9}, ASN1_IA5STRING},
|
||||
{"unstructuredName", {oid_UN, 9}, ASN1_IA5STRING},
|
||||
{"TCGID" , {oid_TCGID, 12}, ASN1_PRINTABLESTRING}
|
||||
};
|
||||
|
||||
#define X501_RDN_ROOF 26
|
||||
|
||||
static void update_chunk(chunk_t *ch, int n)
|
||||
{
|
||||
n = (n > -1 && n < (int)ch->len)? n : (int)ch->len-1;
|
||||
ch->ptr += n; ch->len -= n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pointer is set to the first RDN in a DN
|
||||
*/
|
||||
static err_t init_rdn(chunk_t dn, chunk_t *rdn, chunk_t *attribute, bool *next)
|
||||
{
|
||||
*rdn = chunk_empty;
|
||||
*attribute = chunk_empty;
|
||||
|
||||
/* a DN is a SEQUENCE OF RDNs */
|
||||
|
||||
if (*dn.ptr != ASN1_SEQUENCE)
|
||||
{
|
||||
return "DN is not a SEQUENCE";
|
||||
}
|
||||
|
||||
rdn->len = asn1_length(&dn);
|
||||
|
||||
if (rdn->len == ASN1_INVALID_LENGTH)
|
||||
{
|
||||
return "Invalid RDN length";
|
||||
}
|
||||
rdn->ptr = dn.ptr;
|
||||
|
||||
/* are there any RDNs ? */
|
||||
*next = rdn->len > 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the next RDN in a DN
|
||||
*/
|
||||
static err_t get_next_rdn(chunk_t *rdn, chunk_t * attribute, chunk_t *oid,
|
||||
chunk_t *value, asn1_t *type, bool *next)
|
||||
{
|
||||
chunk_t body;
|
||||
|
||||
/* initialize return values */
|
||||
*oid = chunk_empty;
|
||||
*value = chunk_empty;
|
||||
|
||||
/* if all attributes have been parsed, get next rdn */
|
||||
if (attribute->len <= 0)
|
||||
{
|
||||
/* an RDN is a SET OF attributeTypeAndValue */
|
||||
if (*rdn->ptr != ASN1_SET)
|
||||
{
|
||||
return "RDN is not a SET";
|
||||
}
|
||||
attribute->len = asn1_length(rdn);
|
||||
|
||||
if (attribute->len == ASN1_INVALID_LENGTH)
|
||||
{
|
||||
return "Invalid attribute length";
|
||||
}
|
||||
attribute->ptr = rdn->ptr;
|
||||
|
||||
/* advance to start of next RDN */
|
||||
rdn->ptr += attribute->len;
|
||||
rdn->len -= attribute->len;
|
||||
}
|
||||
|
||||
/* an attributeTypeAndValue is a SEQUENCE */
|
||||
if (*attribute->ptr != ASN1_SEQUENCE)
|
||||
{
|
||||
return "attributeTypeAndValue is not a SEQUENCE";
|
||||
}
|
||||
|
||||
/* extract the attribute body */
|
||||
body.len = asn1_length(attribute);
|
||||
|
||||
if (body.len == ASN1_INVALID_LENGTH)
|
||||
{
|
||||
return "Invalid attribute body length";
|
||||
}
|
||||
body.ptr = attribute->ptr;
|
||||
|
||||
/* advance to start of next attribute */
|
||||
attribute->ptr += body.len;
|
||||
attribute->len -= body.len;
|
||||
|
||||
/* attribute type is an OID */
|
||||
if (*body.ptr != ASN1_OID)
|
||||
{
|
||||
return "attributeType is not an OID";
|
||||
}
|
||||
|
||||
/* extract OID */
|
||||
oid->len = asn1_length(&body);
|
||||
|
||||
if (oid->len == ASN1_INVALID_LENGTH)
|
||||
{
|
||||
return "Invalid attribute OID length";
|
||||
}
|
||||
oid->ptr = body.ptr;
|
||||
|
||||
/* advance to the attribute value */
|
||||
body.ptr += oid->len;
|
||||
body.len -= oid->len;
|
||||
|
||||
/* extract string type */
|
||||
*type = *body.ptr;
|
||||
|
||||
/* extract string value */
|
||||
value->len = asn1_length(&body);
|
||||
|
||||
if (value->len == ASN1_INVALID_LENGTH)
|
||||
{
|
||||
return "Invalid attribute string length";
|
||||
}
|
||||
value->ptr = body.ptr;
|
||||
|
||||
/* are there any RDNs left? */
|
||||
*next = rdn->len > 0 || attribute->len > 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a binary string in hexadecimal form
|
||||
*/
|
||||
static void hex_str(chunk_t bin, chunk_t *str)
|
||||
{
|
||||
u_int i;
|
||||
update_chunk(str, snprintf(str->ptr,str->len,"0x"));
|
||||
for (i=0; i < bin.len; i++)
|
||||
update_chunk(str, snprintf(str->ptr,str->len,"%02X",*bin.ptr++));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an ASN.1 distinguished name int its OID/value pairs
|
||||
*/
|
||||
static err_t dn_parse(chunk_t dn, chunk_t *str)
|
||||
{
|
||||
chunk_t rdn, oid, attribute, value;
|
||||
asn1_t type;
|
||||
int oid_code;
|
||||
bool next;
|
||||
bool first = TRUE;
|
||||
|
||||
err_t ugh = init_rdn(dn, &rdn, &attribute, &next);
|
||||
|
||||
if (ugh) /* a parsing error has occured */
|
||||
{
|
||||
return ugh;
|
||||
}
|
||||
|
||||
while (next)
|
||||
{
|
||||
ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
|
||||
|
||||
if (ugh) /* a parsing error has occured */
|
||||
{
|
||||
return ugh;
|
||||
}
|
||||
|
||||
if (first) /* first OID/value pair */
|
||||
{
|
||||
first = FALSE;
|
||||
}
|
||||
else /* separate OID/value pair by a comma */
|
||||
{
|
||||
update_chunk(str, snprintf(str->ptr,str->len,", "));
|
||||
}
|
||||
|
||||
/* print OID */
|
||||
oid_code = asn1_known_oid(oid);
|
||||
if (oid_code == OID_UNKNOWN) /* OID not found in list */
|
||||
{
|
||||
hex_str(oid, str);
|
||||
}
|
||||
else
|
||||
{
|
||||
update_chunk(str, snprintf(str->ptr,str->len,"%s",
|
||||
oid_names[oid_code].name));
|
||||
}
|
||||
|
||||
/* print value */
|
||||
update_chunk(str, snprintf(str->ptr,str->len,"=%.*s",
|
||||
(int)value.len,value.ptr));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of wildcard RDNs in a distinguished name
|
||||
*/
|
||||
int dn_count_wildcards(chunk_t dn)
|
||||
{
|
||||
chunk_t rdn, attribute, oid, value;
|
||||
asn1_t type;
|
||||
bool next;
|
||||
int wildcards = 0;
|
||||
|
||||
err_t ugh = init_rdn(dn, &rdn, &attribute, &next);
|
||||
|
||||
if (ugh) /* a parsing error has occured */
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (next)
|
||||
{
|
||||
ugh = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
|
||||
|
||||
if (ugh) /* a parsing error has occured */
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (value.len == 1 && *value.ptr == '*')
|
||||
{
|
||||
wildcards++; /* we have found a wildcard RDN */
|
||||
}
|
||||
}
|
||||
return wildcards;
|
||||
}
|
||||
|
||||
/** Converts a binary DER-encoded ASN.1 distinguished name
|
||||
* into LDAP-style human-readable ASCII format
|
||||
*/
|
||||
int dntoa(char *dst, size_t dstlen, chunk_t dn)
|
||||
{
|
||||
err_t ugh = NULL;
|
||||
chunk_t str;
|
||||
|
||||
str.ptr = dst;
|
||||
str.len = dstlen;
|
||||
ugh = dn_parse(dn, &str);
|
||||
|
||||
if (ugh) /* error, print DN as hex string */
|
||||
{
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("error in DN parsing: %s", ugh)
|
||||
)
|
||||
str.ptr = dst;
|
||||
str.len = dstlen;
|
||||
hex_str(dn, &str);
|
||||
}
|
||||
return (int)(dstlen - str.len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Codes ASN.1 lengths up to a size of 16'777'215 bytes
|
||||
*/
|
||||
static void code_asn1_length(size_t length, chunk_t *code)
|
||||
{
|
||||
if (length < 128)
|
||||
{
|
||||
code->ptr[0] = length;
|
||||
code->len = 1;
|
||||
}
|
||||
else if (length < 256)
|
||||
{
|
||||
code->ptr[0] = 0x81;
|
||||
code->ptr[1] = (u_char) length;
|
||||
code->len = 2;
|
||||
}
|
||||
else if (length < 65536)
|
||||
{
|
||||
code->ptr[0] = 0x82;
|
||||
code->ptr[1] = length >> 8;
|
||||
code->ptr[2] = length & 0x00ff;
|
||||
code->len = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
code->ptr[0] = 0x83;
|
||||
code->ptr[1] = length >> 16;
|
||||
code->ptr[2] = (length >> 8) & 0x00ff;
|
||||
code->ptr[3] = length & 0x0000ff;
|
||||
code->len = 4;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an LDAP-style human-readable ASCII-encoded
|
||||
* ASN.1 distinguished name into binary DER-encoded format
|
||||
*/
|
||||
err_t atodn(char *src, chunk_t *dn)
|
||||
{
|
||||
/* finite state machine for atodn */
|
||||
|
||||
typedef enum {
|
||||
SEARCH_OID = 0,
|
||||
READ_OID = 1,
|
||||
SEARCH_NAME = 2,
|
||||
READ_NAME = 3,
|
||||
UNKNOWN_OID = 4
|
||||
} state_t;
|
||||
|
||||
u_char oid_len_buf[3];
|
||||
u_char name_len_buf[3];
|
||||
u_char rdn_seq_len_buf[3];
|
||||
u_char rdn_set_len_buf[3];
|
||||
u_char dn_seq_len_buf[3];
|
||||
|
||||
chunk_t asn1_oid_len = { oid_len_buf, 0 };
|
||||
chunk_t asn1_name_len = { name_len_buf, 0 };
|
||||
chunk_t asn1_rdn_seq_len = { rdn_seq_len_buf, 0 };
|
||||
chunk_t asn1_rdn_set_len = { rdn_set_len_buf, 0 };
|
||||
chunk_t asn1_dn_seq_len = { dn_seq_len_buf, 0 };
|
||||
chunk_t oid = chunk_empty;
|
||||
chunk_t name = chunk_empty;
|
||||
|
||||
int whitespace = 0;
|
||||
int rdn_seq_len = 0;
|
||||
int rdn_set_len = 0;
|
||||
int dn_seq_len = 0;
|
||||
int pos = 0;
|
||||
|
||||
err_t ugh = NULL;
|
||||
|
||||
u_char *dn_ptr = dn->ptr + 4;
|
||||
|
||||
state_t state = SEARCH_OID;
|
||||
|
||||
do
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case SEARCH_OID:
|
||||
if (*src != ' ' && *src != '/' && *src != ',')
|
||||
{
|
||||
oid.ptr = src;
|
||||
oid.len = 1;
|
||||
state = READ_OID;
|
||||
}
|
||||
break;
|
||||
case READ_OID:
|
||||
if (*src != ' ' && *src != '=')
|
||||
{
|
||||
oid.len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (pos = 0; pos < X501_RDN_ROOF; pos++)
|
||||
{
|
||||
if (strlen(x501rdns[pos].name) == oid.len &&
|
||||
strncasecmp(x501rdns[pos].name, oid.ptr, oid.len) == 0)
|
||||
{
|
||||
break; /* found a valid OID */
|
||||
}
|
||||
}
|
||||
if (pos == X501_RDN_ROOF)
|
||||
{
|
||||
ugh = "unknown OID in distinguished name";
|
||||
state = UNKNOWN_OID;
|
||||
break;
|
||||
}
|
||||
code_asn1_length(x501rdns[pos].oid.len, &asn1_oid_len);
|
||||
|
||||
/* reset oid and change state */
|
||||
oid = chunk_empty;
|
||||
state = SEARCH_NAME;
|
||||
}
|
||||
break;
|
||||
case SEARCH_NAME:
|
||||
if (*src != ' ' && *src != '=')
|
||||
{
|
||||
name.ptr = src;
|
||||
name.len = 1;
|
||||
whitespace = 0;
|
||||
state = READ_NAME;
|
||||
}
|
||||
break;
|
||||
case READ_NAME:
|
||||
if (*src != ',' && *src != '/' && *src != '\0')
|
||||
{
|
||||
name.len++;
|
||||
if (*src == ' ')
|
||||
{
|
||||
whitespace++;
|
||||
}
|
||||
else
|
||||
{
|
||||
whitespace = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name.len -= whitespace;
|
||||
code_asn1_length(name.len, &asn1_name_len);
|
||||
|
||||
/* compute the length of the relative distinguished name sequence */
|
||||
rdn_seq_len = 1 + asn1_oid_len.len + x501rdns[pos].oid.len +
|
||||
1 + asn1_name_len.len + name.len;
|
||||
code_asn1_length(rdn_seq_len, &asn1_rdn_seq_len);
|
||||
|
||||
/* compute the length of the relative distinguished name set */
|
||||
rdn_set_len = 1 + asn1_rdn_seq_len.len + rdn_seq_len;
|
||||
code_asn1_length(rdn_set_len, &asn1_rdn_set_len);
|
||||
|
||||
/* encode the relative distinguished name */
|
||||
*dn_ptr++ = ASN1_SET;
|
||||
chunkcpy(dn_ptr, asn1_rdn_set_len);
|
||||
*dn_ptr++ = ASN1_SEQUENCE;
|
||||
chunkcpy(dn_ptr, asn1_rdn_seq_len);
|
||||
*dn_ptr++ = ASN1_OID;
|
||||
chunkcpy(dn_ptr, asn1_oid_len);
|
||||
chunkcpy(dn_ptr, x501rdns[pos].oid);
|
||||
/* encode the ASN.1 character string type of the name */
|
||||
*dn_ptr++ = (x501rdns[pos].type == ASN1_PRINTABLESTRING
|
||||
&& !asn1_is_printablestring(name))? ASN1_T61STRING : x501rdns[pos].type;
|
||||
chunkcpy(dn_ptr, asn1_name_len);
|
||||
chunkcpy(dn_ptr, name);
|
||||
|
||||
/* accumulate the length of the distinguished name sequence */
|
||||
dn_seq_len += 1 + asn1_rdn_set_len.len + rdn_set_len;
|
||||
|
||||
/* reset name and change state */
|
||||
name = chunk_empty;
|
||||
state = SEARCH_OID;
|
||||
}
|
||||
break;
|
||||
case UNKNOWN_OID:
|
||||
break;
|
||||
}
|
||||
} while (*src++ != '\0');
|
||||
|
||||
/* complete the distinguished name sequence*/
|
||||
code_asn1_length(dn_seq_len, &asn1_dn_seq_len);
|
||||
dn->ptr += 3 - asn1_dn_seq_len.len;
|
||||
dn->len = 1 + asn1_dn_seq_len.len + dn_seq_len;
|
||||
dn_ptr = dn->ptr;
|
||||
*dn_ptr++ = ASN1_SEQUENCE;
|
||||
chunkcpy(dn_ptr, asn1_dn_seq_len);
|
||||
return ugh;
|
||||
}
|
||||
|
||||
/**
|
||||
* compare two distinguished names by comparing the individual RDNs
|
||||
*/
|
||||
bool same_dn(chunk_t a, chunk_t b)
|
||||
{
|
||||
chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
|
||||
chunk_t oid_a, oid_b, value_a, value_b;
|
||||
asn1_t type_a, type_b;
|
||||
bool next_a, next_b;
|
||||
|
||||
/* same lengths for the DNs */
|
||||
if (a.len != b.len)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* try a binary comparison first */
|
||||
if (memeq(a.ptr, b.ptr, b.len))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* initialize DN parsing */
|
||||
if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL
|
||||
|| init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* fetch next RDN pair */
|
||||
while (next_a && next_b)
|
||||
{
|
||||
/* parse next RDNs and check for errors */
|
||||
if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL
|
||||
|| get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* OIDs must agree */
|
||||
if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* same lengths for values */
|
||||
if (value_a.len != value_b.len)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* printableStrings and email RDNs require uppercase comparison */
|
||||
if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING ||
|
||||
(type_a == ASN1_IA5STRING && asn1_known_oid(oid_a) == OID_EMAIL_ADDRESS)))
|
||||
{
|
||||
if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* both DNs must have same number of RDNs */
|
||||
if (next_a || next_b)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* the two DNs are equal! */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare two distinguished names by comparing the individual RDNs.
|
||||
* A single'*' character designates a wildcard RDN in DN b.
|
||||
*/
|
||||
bool match_dn(chunk_t a, chunk_t b, int *wildcards)
|
||||
{
|
||||
chunk_t rdn_a, rdn_b, attribute_a, attribute_b;
|
||||
chunk_t oid_a, oid_b, value_a, value_b;
|
||||
asn1_t type_a, type_b;
|
||||
bool next_a, next_b;
|
||||
|
||||
/* initialize wildcard counter */
|
||||
*wildcards = 0;
|
||||
|
||||
/* initialize DN parsing */
|
||||
if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != NULL
|
||||
|| init_rdn(b, &rdn_b, &attribute_b, &next_b) != NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* fetch next RDN pair */
|
||||
while (next_a && next_b)
|
||||
{
|
||||
/* parse next RDNs and check for errors */
|
||||
if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != NULL
|
||||
|| get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* OIDs must agree */
|
||||
if (oid_a.len != oid_b.len || memcmp(oid_a.ptr, oid_b.ptr, oid_b.len) != 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* does rdn_b contain a wildcard? */
|
||||
if (value_b.len == 1 && *value_b.ptr == '*')
|
||||
{
|
||||
(*wildcards)++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* same lengths for values */
|
||||
if (value_a.len != value_b.len)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* printableStrings and email RDNs require uppercase comparison */
|
||||
if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING ||
|
||||
(type_a == ASN1_IA5STRING && asn1_known_oid(oid_a) == OID_EMAIL_ADDRESS)))
|
||||
{
|
||||
if (strncasecmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strncmp(value_a.ptr, value_b.ptr, value_b.len) != 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* both DNs must have same number of RDNs */
|
||||
if (next_a || next_b)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* the two DNs match! */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* For each link pointing to the certificate increase the count by one
|
||||
*/
|
||||
@@ -779,25 +99,22 @@ x509cert_t* add_x509cert(x509cert_t *cert)
|
||||
/**
|
||||
* Choose either subject DN or a subjectAltName as connection end ID
|
||||
*/
|
||||
void select_x509cert_id(x509cert_t *cert, struct id *end_id)
|
||||
identification_t* select_x509cert_id(x509cert_t *cert, identification_t *id)
|
||||
{
|
||||
certificate_t *certificate = cert->cert;
|
||||
x509_t *x509 = (x509_t*)certificate;
|
||||
identification_t *subjectAltName;
|
||||
identification_t *subject, *subjectAltName;
|
||||
|
||||
bool copy_subject_dn = TRUE; /* ID is subject DN */
|
||||
bool copy_subject_dn = TRUE; /* ID is subject DN */
|
||||
|
||||
if (end_id->kind != ID_ANY) /* check for matching subjectAltName */
|
||||
if (id->get_type(id) != ID_ANY) /* check for a matching subjectAltName */
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
|
||||
enumerator = x509->create_subjectAltName_enumerator(x509);
|
||||
while (enumerator->enumerate(enumerator, &subjectAltName))
|
||||
{
|
||||
struct id id = empty_id;
|
||||
|
||||
id_from_identification(&id, subjectAltName);
|
||||
if (same_id(&id, end_id))
|
||||
if (id->equals(id, subjectAltName))
|
||||
{
|
||||
copy_subject_dn = FALSE; /* take subjectAltName instead */
|
||||
break;
|
||||
@@ -805,23 +122,17 @@ void select_x509cert_id(x509cert_t *cert, struct id *end_id)
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
if (copy_subject_dn)
|
||||
{
|
||||
identification_t *subject = certificate->get_subject(certificate);
|
||||
chunk_t subject_dn = subject->get_encoding(subject);
|
||||
id->destroy(id);
|
||||
subject = certificate->get_subject(certificate);
|
||||
plog(" no subjectAltName matches ID '%Y', replaced by subject DN", id);
|
||||
|
||||
if (end_id->kind != ID_ANY && end_id->kind != ID_DER_ASN1_DN)
|
||||
{
|
||||
char buf[BUF_LEN];
|
||||
|
||||
idtoa(end_id, buf, BUF_LEN);
|
||||
plog(" no subjectAltName matches ID '%s', replaced by subject DN", buf);
|
||||
}
|
||||
end_id->kind = ID_DER_ASN1_DN;
|
||||
end_id->name.len = subject_dn.len;
|
||||
end_id->name.ptr = temporary_cyclic_buffer();
|
||||
memcpy(end_id->name.ptr, subject_dn.ptr, subject_dn.len);
|
||||
return subject->clone(subject);
|
||||
}
|
||||
else
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,42 +210,40 @@ void release_x509cert(x509cert_t *cert)
|
||||
/**
|
||||
* Stores a chained list of end certs and CA certs
|
||||
*/
|
||||
void store_x509certs(x509cert_t **firstcert, bool strict)
|
||||
void store_x509certs(linked_list_t *certs, bool strict)
|
||||
{
|
||||
x509cert_t *cacerts = NULL;
|
||||
x509cert_t **pp = firstcert;
|
||||
x509cert_t *x509cert, *cacerts = NULL;
|
||||
certificate_t *cert;
|
||||
enumerator_t *enumerator;
|
||||
|
||||
/* first extract CA certs, discarding root CA certs */
|
||||
/* first extract CA certs, ignoring self-signed root CA certs */
|
||||
|
||||
while (*pp)
|
||||
enumerator = certs->create_enumerator(certs);
|
||||
while (enumerator->enumerate(enumerator, &cert))
|
||||
{
|
||||
x509cert_t *cert = *pp;
|
||||
certificate_t *certificate = cert->cert;
|
||||
x509_t *x509 = (x509_t*)certificate;
|
||||
x509_flag_t flags = x509->get_flags(x509);
|
||||
x509_t *x509 = (x509_t*)cert;
|
||||
x509_flag_t flags;
|
||||
|
||||
flags = x509->get_flags(x509);
|
||||
if (flags & X509_CA)
|
||||
{
|
||||
*pp = cert->next;
|
||||
|
||||
/* we don't accept self-signed CA certs */
|
||||
if (flags & X509_SELF_SIGNED)
|
||||
{
|
||||
plog("self-signed cacert rejected");
|
||||
free_x509cert(cert);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* insertion into temporary chain of candidate CA certs */
|
||||
cert->next = cacerts;
|
||||
cacerts = cert;
|
||||
x509cert = malloc_thing(x509cert_t);
|
||||
*x509cert = empty_x509cert;
|
||||
x509cert->cert = cert->get_ref(cert);
|
||||
x509cert->next = cacerts;
|
||||
cacerts = x509cert;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pp = &cert->next;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
/* now verify the candidate CA certs */
|
||||
|
||||
@@ -957,27 +266,33 @@ void store_x509certs(x509cert_t **firstcert, bool strict)
|
||||
|
||||
/* now verify the end certificates */
|
||||
|
||||
pp = firstcert;
|
||||
|
||||
while (*pp)
|
||||
enumerator = certs->create_enumerator(certs);
|
||||
while (enumerator->enumerate(enumerator, &cert))
|
||||
{
|
||||
time_t valid_until;
|
||||
x509cert_t *cert = *pp;
|
||||
x509_t *x509 = (x509_t*)cert;
|
||||
|
||||
if (verify_x509cert(cert, strict, &valid_until))
|
||||
if (!(x509->get_flags(x509) & X509_CA))
|
||||
{
|
||||
DBG(DBG_CONTROL | DBG_PARSING,
|
||||
DBG_log("public key validated")
|
||||
)
|
||||
add_x509_public_key(cert, valid_until, DAL_SIGNED);
|
||||
x509cert = malloc_thing(x509cert_t);
|
||||
*x509cert = empty_x509cert;
|
||||
x509cert->cert = cert->get_ref(cert);
|
||||
|
||||
if (verify_x509cert(x509cert, strict, &valid_until))
|
||||
{
|
||||
DBG(DBG_CONTROL | DBG_PARSING,
|
||||
DBG_log("public key validated")
|
||||
)
|
||||
add_x509_public_key(x509cert, valid_until, DAL_SIGNED);
|
||||
}
|
||||
else
|
||||
{
|
||||
plog("X.509 certificate rejected");
|
||||
free_x509cert(x509cert);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
plog("X.509 certificate rejected");
|
||||
}
|
||||
*pp = cert->next;
|
||||
free_x509cert(cert);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-8
@@ -19,12 +19,12 @@
|
||||
#define _X509_H
|
||||
|
||||
#include <utils/identification.h>
|
||||
#include <utils/linked_list.h>
|
||||
#include <credentials/keys/public_key.h>
|
||||
#include <credentials/keys/private_key.h>
|
||||
#include <credentials/certificates/x509.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "id.h"
|
||||
|
||||
/* access structure for an X.509v3 certificate */
|
||||
|
||||
@@ -41,12 +41,7 @@ struct x509cert {
|
||||
extern const x509cert_t empty_x509cert;
|
||||
|
||||
extern bool same_keyid(chunk_t a, chunk_t b);
|
||||
extern bool same_dn(chunk_t a, chunk_t b);
|
||||
extern bool match_dn(chunk_t a, chunk_t b, int *wildcards);
|
||||
extern int dn_count_wildcards(chunk_t dn);
|
||||
extern int dntoa(char *dst, size_t dstlen, chunk_t dn);
|
||||
extern err_t atodn(char *src, chunk_t *dn);
|
||||
extern void select_x509cert_id(x509cert_t *cert, struct id *end_id);
|
||||
extern identification_t* select_x509cert_id(x509cert_t *cert, identification_t *id);
|
||||
extern void parse_authorityKeyIdentifier(chunk_t blob, int level0,
|
||||
chunk_t *authKeyID,
|
||||
chunk_t *authKeySerialNumber);
|
||||
@@ -60,7 +55,7 @@ extern x509cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, x509cer
|
||||
extern void share_x509cert(x509cert_t *cert);
|
||||
extern void release_x509cert(x509cert_t *cert);
|
||||
extern void free_x509cert(x509cert_t *cert);
|
||||
extern void store_x509certs(x509cert_t **firstcert, bool strict);
|
||||
extern void store_x509certs(linked_list_t *certs, bool strict);
|
||||
extern void list_x509cert_chain(const char *caption, x509cert_t* cert,
|
||||
x509_flag_t flags, bool utc);
|
||||
extern void list_x509_end_certs(bool utc);
|
||||
|
||||
@@ -24,8 +24,7 @@ LIBSTRONGSWANBUILDDIR=$(top_builddir)/src/libstrongswan
|
||||
LIBFREESWANBUILDDIR=$(top_builddir)/src/libfreeswan
|
||||
|
||||
scepclient_LDADD = \
|
||||
ca.o crl.o certs.o constants.o defs.o fetch.o id.o keys.o lex.o \
|
||||
ocsp.o pgpcert.o pkcs7.o smartcard.o x509.o \
|
||||
constants.o defs.o lex.o pkcs7.o \
|
||||
$(LIBSTRONGSWANBUILDDIR)/libstrongswan.la \
|
||||
$(LIBFREESWANBUILDDIR)/libfreeswan.a
|
||||
|
||||
@@ -37,44 +36,15 @@ endif
|
||||
|
||||
dist_man_MANS = scepclient.8
|
||||
|
||||
ca.o : $(PLUTODIR)/ca.c $(PLUTODIR)/ca.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
certs.o : $(PLUTODIR)/certs.c $(PLUTODIR)/certs.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
constants.o : $(PLUTODIR)/constants.c $(PLUTODIR)/constants.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
crl.o : $(PLUTODIR)/crl.c $(PLUTODIR)/crl.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
defs.o : $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
fetch.o : $(PLUTODIR)/fetch.c $(PLUTODIR)/fetch.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
id.o : $(PLUTODIR)/id.c $(PLUTODIR)/id.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
keys.o : $(PLUTODIR)/keys.c $(PLUTODIR)/keys.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
lex.o : $(PLUTODIR)/lex.c $(PLUTODIR)/lex.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
ocsp.o : $(PLUTODIR)/ocsp.c $(PLUTODIR)/ocsp.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
pgpcert.o : $(PLUTODIR)/pgpcert.c $(PLUTODIR)/pgpcert.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
pkcs7.o : $(PLUTODIR)/pkcs7.c $(PLUTODIR)/pkcs7.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
smartcard.o : $(PLUTODIR)/smartcard.c $(PLUTODIR)/smartcard.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
x509.o : $(PLUTODIR)/x509.c $(PLUTODIR)/x509.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
+13
-11
@@ -54,8 +54,8 @@
|
||||
#include "../pluto/constants.h"
|
||||
#include "../pluto/defs.h"
|
||||
#include "../pluto/log.h"
|
||||
#include "../pluto/pkcs7.h"
|
||||
#include "../pluto/certs.h"
|
||||
#include "../pluto/pkcs7.h"
|
||||
|
||||
#include "scep.h"
|
||||
|
||||
@@ -789,10 +789,10 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
if (filetype_in & PKCS1) /* load an RSA key pair from file */
|
||||
{
|
||||
prompt_pass_t pass = { "", FALSE, STDIN_FILENO };
|
||||
char *path = concatenate_paths(PRIVATE_KEY_PATH, file_in_pkcs1);
|
||||
|
||||
private_key = load_private_key(path, &pass, KEY_RSA);
|
||||
private_key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
||||
BUILD_FROM_FILE, path, BUILD_END);
|
||||
}
|
||||
else /* generate an RSA key pair */
|
||||
{
|
||||
@@ -1020,10 +1020,12 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
if (filetype_out & CERT)
|
||||
{
|
||||
certificate_t *cert;
|
||||
enumerator_t *enumerator;
|
||||
char *path = concatenate_paths(CA_CERT_PATH, file_in_cacert_sig);
|
||||
time_t poll_start = 0;
|
||||
|
||||
x509cert_t *certs = NULL;
|
||||
linked_list_t *certs = linked_list_create();
|
||||
chunk_t envelopedData = chunk_empty;
|
||||
chunk_t certData = chunk_empty;
|
||||
contentInfo_t data = empty_contentInfo;
|
||||
@@ -1115,7 +1117,7 @@ int main(int argc, char **argv)
|
||||
{
|
||||
exit_scepclient("could not decrypt envelopedData");
|
||||
}
|
||||
if (!pkcs7_parse_signedData(certData, NULL, &certs, NULL, NULL))
|
||||
if (!pkcs7_parse_signedData(certData, NULL, certs, NULL, NULL))
|
||||
{
|
||||
exit_scepclient("error parsing the scep response");
|
||||
}
|
||||
@@ -1123,11 +1125,12 @@ int main(int argc, char **argv)
|
||||
|
||||
/* store the end entity certificate */
|
||||
path = concatenate_paths(HOST_CERT_PATH, file_out_cert);
|
||||
while (certs != NULL)
|
||||
|
||||
enumerator = certs->create_enumerator(certs);
|
||||
while (enumerator->enumerate(enumerator, &cert))
|
||||
{
|
||||
bool stored = FALSE;
|
||||
x509cert_t *cert = certs;
|
||||
x509_t *x509 = (x509_t*)cert->cert;
|
||||
x509_t *x509 = (x509_t*)cert;
|
||||
|
||||
if (!(x509->get_flags(x509) & X509_CA))
|
||||
{
|
||||
@@ -1135,7 +1138,7 @@ int main(int argc, char **argv)
|
||||
{
|
||||
exit_scepclient("multiple certs received, only first stored");
|
||||
}
|
||||
encoding = cert->cert->get_encoding(cert->cert);
|
||||
encoding = cert->get_encoding(cert);
|
||||
if (!chunk_write(encoding, path, "requested cert", 0022, force))
|
||||
{
|
||||
exit_scepclient("could not write cert file '%s'", path);
|
||||
@@ -1143,9 +1146,8 @@ int main(int argc, char **argv)
|
||||
chunk_free(&encoding);
|
||||
stored = TRUE;
|
||||
}
|
||||
certs = certs->next;
|
||||
free_x509cert(cert);
|
||||
}
|
||||
certs->destroy_offset(certs, offsetof(certificate_t, destroy));
|
||||
filetype_out &= ~CERT; /* delete CERT flag */
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
#include <freeswan.h>
|
||||
|
||||
#include <defs.h>
|
||||
|
||||
/* copy of smartcard operations, defined in smartcard.h */
|
||||
#ifndef SC_OP_T
|
||||
#define SC_OP_T
|
||||
|
||||
Reference in New Issue
Block a user