replaced struct id by identification_t

This commit is contained in:
Andreas Steffen
2009-10-10 21:19:38 +02:00
parent 55b045abb5
commit 17722d4489
32 changed files with 988 additions and 2249 deletions
+1 -1
View File
@@ -20,7 +20,6 @@ demux.c demux.h \
dnskey.c dnskey.h \ dnskey.c dnskey.h \
fetch.c fetch.h \ fetch.c fetch.h \
foodgroups.c foodgroups.h \ foodgroups.c foodgroups.h \
id.c id.h \
ike_alg.c ike_alg.h \ ike_alg.c ike_alg.h \
ipsec_doi.c ipsec_doi.h \ ipsec_doi.c ipsec_doi.h \
kameipsec.h \ kameipsec.h \
@@ -32,6 +31,7 @@ kernel_pfkey.c kernel_pfkey.h \
keys.c keys.h \ keys.c keys.h \
lex.c lex.h \ lex.c lex.h \
log.c log.h \ log.c log.h \
myid.c myid.h \
modecfg.c modecfg.h \ modecfg.c modecfg.h \
nat_traversal.c nat_traversal.h \ nat_traversal.c nat_traversal.h \
ocsp.c ocsp.h \ ocsp.c ocsp.h \
+13 -5
View File
@@ -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); status = alg_info_parse_str((struct alg_info *)alg_info_esp, alg_str);
out: out:
if (status != SUCCESS) if (status == SUCCESS)
{
alg_info_esp->ref_cnt = 1;
return alg_info_esp;
}
else
{ {
free(alg_info_esp); 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) 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); zero(alg_info_ike);
alg_info_ike->alg_info_protoid = PROTO_ISAKMP; 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); free(alg_info_ike);
return NULL; return NULL;
} }
return alg_info_ike;
} }
/* /*
-1
View File
@@ -30,7 +30,6 @@
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "log.h" #include "log.h"
#include "id.h"
#include "certs.h" #include "certs.h"
#include "ac.h" #include "ac.h"
#include "crl.h" #include "crl.h"
+4 -7
View File
@@ -28,7 +28,6 @@
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "log.h" #include "log.h"
#include "id.h"
#include "certs.h" #include "certs.h"
#include "whack.h" #include "whack.h"
#include "builder.h" #include "builder.h"
@@ -228,10 +227,9 @@ void share_cert(cert_t cert)
} }
/* release of a certificate decreases the count by one /* 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 void release_cert(cert_t cert)
release_cert(cert_t cert)
{ {
switch (cert.type) switch (cert.type)
{ {
@@ -246,11 +244,10 @@ release_cert(cert_t cert)
} }
} }
/* /**
* list all X.509 and OpenPGP end certificates * list all X.509 and OpenPGP end certificates
*/ */
void void list_certs(bool utc)
list_certs(bool utc)
{ {
list_x509_end_certs(utc); list_x509_end_certs(utc);
list_pgp_end_certs(utc); list_pgp_end_certs(utc);
+295 -284
View File
File diff suppressed because it is too large Load Diff
+27 -33
View File
@@ -1,5 +1,6 @@
/* information about connections between hosts and clients /* information about connections between hosts and clients
* Copyright (C) 1998-2001 D. Hugh Redelmeier * 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 * 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 * under the terms of the GNU General Public License as published by the
@@ -19,10 +20,9 @@
#include <utils/linked_list.h> #include <utils/linked_list.h>
#include <utils/identification.h> #include <utils/identification.h>
#include <credentials/ietf_attributes/ietf_attributes.h>
#include "id.h"
#include "certs.h" #include "certs.h"
#include "ac.h"
#include "smartcard.h" #include "smartcard.h"
#include "whack.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 virtual_t;
struct end { struct end {
struct id id; identification_t *id;
ip_address ip_address
host_addr, host_addr,
host_nexthop, host_nexthop,
@@ -231,7 +231,7 @@ struct connection {
extern bool orient(connection_t *c); extern bool orient(connection_t *c);
extern bool same_peer_ids(const connection_t *c, const connection_t *d, 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. /* Format the topology of a connection end, leaving out defaults.
* Largest left end looks like: client === host : port [ host_id ] --- hop * 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 bool uniqueIDs; /* --uniqueids? */
extern void ISAKMP_SA_established(connection_t *c, so_serial_t serial); extern void ISAKMP_SA_established(connection_t *c, so_serial_t serial);
#define his_id_was_instantiated(c) ((c)->kind == CK_INSTANCE \ #define id_is_ipaddr(id) ((id)->get_type(id) == ID_IPV4_ADDR || \
&& (id_is_ipaddr(&(c)->spd.that.id)? \ (id)->get_type(id) == ID_IPV6_ADDR)
sameaddr(&(c)->spd.that.id.ip_addr, &(c)->spd.that.host_addr) : TRUE)) extern bool his_id_was_instantiated(const connection_t *c);
struct state; /* forward declaration of tag (defined in state.h) */ 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, const ip_address *him,
u_int16_t his_port, lset_t policy); u_int16_t his_port, lset_t policy);
extern connection_t* refine_host_connection(const struct state *st, extern connection_t* refine_host_connection(const struct state *st,
const struct id *id, identification_t *id,
identification_t *peer_ca); identification_t *peer_ca);
extern connection_t* find_client_connection(connection_t *c, extern connection_t* find_client_connection(connection_t *c,
const ip_subnet *our_net, 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 gw_info; /* forward declaration of tag (defined in dnskey.h) */
struct alg_info; /* forward declaration of tag (defined in alg_info.h) */ struct alg_info; /* forward declaration of tag (defined in alg_info.h) */
extern connection_t *rw_instantiate(connection_t *c extern connection_t *rw_instantiate(connection_t *c,
, const ip_address *him const ip_address *him,
, u_int16_t his_port u_int16_t his_port,
, const ip_subnet *his_net const ip_subnet *his_net,
, const struct id *his_id); identification_t *his_id);
extern connection_t *oppo_instantiate(connection_t *c extern connection_t *oppo_instantiate(connection_t *c,
, const ip_address *him const ip_address *him,
, const struct id *his_id identification_t *his_id,
, struct gw_info *gw struct gw_info *gw,
, const ip_address *our_client const ip_address *our_client,
, const ip_address *peer_client); const ip_address *peer_client);
extern connection_t extern connection_t
*build_outgoing_opportunistic_connection(struct gw_info *gw *build_outgoing_opportunistic_connection(struct gw_info *gw,
, const ip_address *our_client const ip_address *our_client,
, const ip_address *peer_client); const ip_address *peer_client);
/* worst case: "[" serial "] " myclient "=== ..." peer "===" hisclient '\0' */ #define CONN_INST_BUF BUF_LEN
#define CONN_INST_BUF \
(2 + 10 + 1 + SUBNETTOT_BUF + 7 + ADDRTOT_BUF + 3 + SUBNETTOT_BUF + 1)
extern void fmt_conn_instance(const connection_t *c extern void fmt_conn_instance(const connection_t *c, char buf[CONN_INST_BUF]);
, char buf[CONN_INST_BUF]);
/* operations on "pending", the structure representing Quick Mode /* operations on "pending", the structure representing Quick Mode
* negotiations delayed until a Keying Channel has been negotiated. * 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) */ struct pending; /* forward declaration (opaque outside connections.c) */
extern void add_pending(int whack_sock extern void add_pending(int whack_sock, struct state *isakmp_sa,
, struct state *isakmp_sa connection_t *c, lset_t policy, unsigned long try,
, connection_t *c so_serial_t replacing);
, lset_t policy
, unsigned long try
, so_serial_t replacing);
extern void release_pending_whacks(struct state *st, err_t story); extern void release_pending_whacks(struct state *st, err_t story);
extern void unpend(struct state *st); extern void unpend(struct state *st);
+103 -177
View File
@@ -36,7 +36,7 @@
#include "adns.h" /* needs <resolv.h> */ #include "adns.h" /* needs <resolv.h> */
#include "defs.h" #include "defs.h"
#include "log.h" #include "log.h"
#include "id.h" #include "myid.h"
#include "connections.h" #include "connections.h"
#include "keys.h" /* needs connections.h */ #include "keys.h" /* needs connections.h */
#include "dnskey.h" #include "dnskey.h"
@@ -238,62 +238,30 @@ stop_adns(void)
#define our_TXT_attr_string "X-IPsec-Server" #define our_TXT_attr_string "X-IPsec-Server"
static const char our_TXT_attr[] = our_TXT_attr_string; static const char our_TXT_attr[] = our_TXT_attr_string;
static err_t identification_t* decode_iii(u_char **pp)
decode_iii(u_char **pp, struct id *gw_id)
{ {
identification_t *gw_id;
u_char *p = *pp + strspn(*pp, " \t"); u_char *p = *pp + strspn(*pp, " \t");
u_char *e = p + strcspn(p, " \t"); u_char *e = p + strcspn(p, " \t");
u_char under = *e; u_char under = *e;
if (p == e) if (p == e)
{ {
return "TXT " our_TXT_attr_string " badly formed (no gateway specified)"; return NULL;
} }
*e = '\0'; *e = '\0';
if (*p == '@') gw_id = identification_create_from_string(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);
}
*e = under; *e = under;
*pp = e + strspn(e, " \t"); *pp = e + strspn(e, " \t");
return NULL; return gw_id;
} }
static err_t static err_t process_txt_rr_body(u_char *str, bool doit,
process_txt_rr_body(u_char *str enum dns_auth_level dns_auth_level,
, bool doit /* should we capture information? */ struct adns_continuation *const cr)
, 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; u_char *p = str;
unsigned long pref = 0; unsigned long pref = 0;
struct gw_info gi; struct gw_info gi;
@@ -349,10 +317,13 @@ process_txt_rr_body(u_char *str
p += strspn(p, " \t"); p += strspn(p, " \t");
/* Decode iii (Security Gateway ID). */ /* Decode iii (Security Gateway ID). */
zero(&gi); /* before first use */ 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) if (!cr->sgw_specified)
{ {
@@ -360,19 +331,14 @@ process_txt_rr_body(u_char *str
* and we don't know who to initiate with. * and we don't know who to initiate with.
* So we're looking for gateway specs with an IP address * 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, DBG(DBG_DNS,
{ DBG_log("TXT %s record for '%Y': security gateway '%Y';"
char cidb[BUF_LEN]; " ignored because gateway's IP is unspecified",
char gwidb[BUF_LEN]; our_TXT_attr, client_id, gi.gw_id);
)
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);
});
return NULL; /* we cannot use this record, but it isn't wrong */ 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) /* We do know the peer's ID (because we are responding)
* So we're looking for gateway specs specifying this known ID. * 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, DBG(DBG_DNS,
{ DBG_log("TXT %s record for '%Y': security gateway '%Y';"
char cidb[BUF_LEN]; " ignored -- looking to confirm '%Y' as gateway",
char gwidb[BUF_LEN]; our_TXT_attr, client_id, gi.gw_id, peer_id);
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);
});
return NULL; /* we cannot use this record, but it isn't wrong */ 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 */ /* really accept gateway */
struct gw_info **gwip; /* gateway insertion point */ 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 */ /* decode optional kkk: base 64 encoding of key */
@@ -462,32 +420,26 @@ process_txt_rr_body(u_char *str
DBG(DBG_DNS, DBG(DBG_DNS,
{ {
char cidb[BUF_LEN];
char gwidb[BUF_LEN];
chunk_t keyid; chunk_t keyid;
public_key_t *key; public_key_t *key = gi.key->public_key;
idtoa(client_id, cidb, sizeof(cidb));
idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
key = gi.key->public_key;
if (gi.gw_key_present && if (gi.gw_key_present &&
key->get_fingerprint(key, KEY_ID_PUBKEY_SHA1, &keyid)) key->get_fingerprint(key, KEY_ID_PUBKEY_SHA1, &keyid))
{ {
DBG_log("gateway for %s is %s with key %#B" DBG_log("gateway for %s is %s with key %#B",
, cidb, gwidb, &keyid); client_id, gi.gw_id, &keyid);
} }
else else
{ {
DBG_log("gateway for %s is %s; no key specified" DBG_log("gateway for '%Y' is '%Y'; no key specified",
, cidb, gwidb); client_id, gi.gw_id);
} }
}); });
gi.next = *gwip; gi.next = *gwip;
*gwip = clone_thing(gi); *gwip = clone_thing(gi);
unshare_id_content(&(*gwip)->gw_id); (*gwip)->gw_id = (*gwip)->gw_id->clone((*gwip)->gw_id);
unshare_id_content(&(*gwip)->client_id); (*gwip)->client_id = (*gwip)->client_id->clone((*gwip)->client_id);
} }
return NULL; return NULL;
@@ -1271,75 +1223,62 @@ process_dns_answer(struct adns_continuation *const cr
/****************************************************************/ /****************************************************************/
static err_t static err_t build_dns_name(u_char name_buf[NS_MAXDNAME + 2],
build_dns_name(u_char name_buf[NS_MAXDNAME + 2] unsigned long serial USED_BY_DEBUG,
, unsigned long serial USED_BY_DEBUG identification_t *id,
, const struct id *id const char *typename USED_BY_DEBUG,
, const char *typename USED_BY_DEBUG identification_t *gw USED_BY_DEBUG)
, const char *gwname USED_BY_DEBUG)
{ {
/* note: all end in "." to suppress relative searches */ /* note: all end in "." to suppress relative searches */
id = resolve_myid(id); 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); switch (id->get_type(id))
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:
{ {
/* ??? is this correct? */ case ID_IPV4_ADDR:
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; )
{ {
if (op + 4 + sizeof(suffix) >= name_buf + NS_MAXDNAME + 1) chunk_t b = id->get_encoding(id);
return "IPv6 reverse name too long";
op += sprintf(op, "%x.%x.", b[bl] & 0xF, b[bl] >> 4); 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); case ID_IPV6_ADDR:
break;
}
case ID_FQDN:
/* strip trailing "." characters, then add one */
{ {
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] == '.') for (bl = b.len; bl-- != 0; )
il--; {
if (il > NS_MAXDNAME) 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"; return "FQDN too long for domain name";
}
memcpy(name_buf, id->name.ptr, il); break;
strcpy(name_buf + il, ".");
} }
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)" DBG(DBG_CONTROL | DBG_DNS,
, serial, typename, name_buf, gwname)); DBG_log("DNS query %lu for %s for %s (gw: %Y)", serial, typename, name_buf, gw)
)
return NULL; return NULL;
} }
void void gw_addref(struct gw_info *gw)
gw_addref(struct gw_info *gw)
{ {
if (gw != NULL) if (gw != NULL)
{ {
@@ -1348,8 +1287,7 @@ gw_addref(struct gw_info *gw)
} }
} }
void void gw_delref(struct gw_info **gwp)
gw_delref(struct gw_info **gwp)
{ {
struct gw_info *gw = *gwp; struct gw_info *gw = *gwp;
@@ -1361,10 +1299,12 @@ gw_delref(struct gw_info **gwp)
gw->refcnt--; gw->refcnt--;
if (gw->refcnt == 0) if (gw->refcnt == 0)
{ {
free_id_content(&gw->client_id); DESTROY_IF(gw->client_id);
free_id_content(&gw->gw_id); DESTROY_IF(gw->gw_id);
if (gw->gw_key_present) if (gw->gw_key_present)
{
unreference_key(&gw->key); unreference_key(&gw->key);
}
gw_delref(&gw->next); gw_delref(&gw->next);
free(gw); /* trickery could make this a tail-call */ 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 *continuations = NULL; /* newest of queue */
static struct adns_continuation *next_query = NULL; /* oldest not sent */ static struct adns_continuation *next_query = NULL; /* oldest not sent */
static struct adns_continuation * static struct adns_continuation *continuation_for_qtid(unsigned long qtid)
continuation_for_qtid(unsigned long qtid)
{ {
struct adns_continuation *cr = NULL; struct adns_continuation *cr = NULL;
if (qtid != 0) if (qtid != 0)
{
for (cr = continuations; cr != NULL && cr->qtid != qtid; cr = cr->previous) for (cr = continuations; cr != NULL && cr->qtid != qtid; cr = cr->previous)
; ;
}
return cr; return cr;
} }
static void static void release_adns_continuation(struct adns_continuation *cr)
release_adns_continuation(struct adns_continuation *cr)
{ {
passert(cr != next_query); passert(cr != next_query);
gw_delref(&cr->gateways_from_dns); gw_delref(&cr->gateways_from_dns);
#ifdef USE_KEYRR #ifdef USE_KEYRR
free_public_keys(&cr->keys_from_dns); free_public_keys(&cr->keys_from_dns);
#endif /* USE_KEYRR */ #endif /* USE_KEYRR */
unshare_id_content(&cr->id); cr->id = cr->id->clone(cr->id);
unshare_id_content(&cr->sgw_id); cr->sgw_id = cr->sgw_id->clone(cr->sgw_id);
/* unlink from doubly-linked list */ /* unlink from doubly-linked list */
if (cr->next == NULL) if (cr->next == NULL)
{ {
passert(continuations == cr);
continuations = cr->previous; continuations = cr->previous;
} }
else else
{ {
passert(cr->next->previous == cr);
cr->next->previous = cr->previous; cr->next->previous = cr->previous;
} }
if (cr->previous != NULL) if (cr->previous != NULL)
{ {
passert(cr->previous->next == cr);
cr->previous->next = cr->next; cr->previous->next = cr->next;
} }
free(cr); free(cr);
} }
err_t err_t start_adns_query(identification_t *id, /* domain to query */
start_adns_query(const struct id *id /* domain to query */ identification_t *sgw_id, /* if non-null, any accepted gw_info must match */
, 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 */
, int type /* T_TXT or T_KEY, selecting rr type of interest */ cont_fn_t cont_fn,
, cont_fn_t cont_fn struct adns_continuation *cr)
, struct adns_continuation *cr)
{ {
static unsigned long qtid = 1; /* query transaction id; NOTE: static */ static unsigned long qtid = 1; /* query transaction id; NOTE: static */
const char *typename = rr_typename(type); const char *typename = rr_typename(type);
char gwidb[BUF_LEN];
if(adns_pid == 0 if(adns_pid == 0 && adns_restart_count < ADNS_RESTART_MAX)
&& adns_restart_count < ADNS_RESTART_MAX)
{ {
plog("ADNS helper was not running. Restarting attempt %d",adns_restart_count); plog("ADNS helper was not running. Restarting attempt %d",adns_restart_count);
init_adns(); init_adns();
} }
/* Splice this in at head of doubly-linked list of continuations. /* Splice this in at head of doubly-linked list of continuations.
* Note: this must be done before any release_adns_continuation(). * 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; cr->previous = continuations;
if (continuations != NULL) if (continuations != NULL)
{ {
passert(continuations->next == NULL);
continuations->next = cr; continuations->next = cr;
} }
continuations = cr; continuations = cr;
@@ -1491,11 +1423,11 @@ start_adns_query(const struct id *id /* domain to query */
cr->qtid = qtid++; cr->qtid = qtid++;
cr->type = type; cr->type = type;
cr->cont_fn = cont_fn; cr->cont_fn = cont_fn;
cr->id = *id; cr->id = id->clone(id);
unshare_id_content(&cr->id); cr->sgw_specified = (sgw_id != NULL);
cr->sgw_specified = sgw_id != NULL; cr->sgw_id = cr->sgw_specified ?
cr->sgw_id = cr->sgw_specified? *sgw_id : empty_id; sgw_id->clone(sgw_id) :
unshare_id_content(&cr->sgw_id); identification_create_from_string("%any");
cr->gateways_from_dns = NULL; cr->gateways_from_dns = NULL;
#ifdef USE_KEYRR #ifdef USE_KEYRR
cr->keys_from_dns = NULL; cr->keys_from_dns = NULL;
@@ -1507,15 +1439,12 @@ start_adns_query(const struct id *id /* domain to query */
cr->debugging = LEMPTY; cr->debugging = LEMPTY;
#endif #endif
idtoa(&cr->sgw_id, gwidb, sizeof(gwidb));
zero(&cr->query); zero(&cr->query);
{ {
err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid, id,
, id, typename, gwidb); typename, cr->sgw_id);
if (ugh != NULL) if (ugh)
{ {
release_adns_continuation(cr); release_adns_continuation(cr);
return ugh; return ugh;
@@ -1620,8 +1549,7 @@ send_unsent_ADNS_queries(void)
* Returns with error message iff lwdnsq result is malformed. * Returns with error message iff lwdnsq result is malformed.
* Most errors will be in DNS data and will be handled by cr->cont_fn. * Most errors will be in DNS data and will be handled by cr->cont_fn.
*/ */
static err_t static err_t process_lwdnsq_answer(char *ts)
process_lwdnsq_answer(char *ts)
{ {
err_t ugh = NULL; err_t ugh = NULL;
char *rest; char *rest;
@@ -1813,8 +1741,7 @@ process_lwdnsq_answer(char *ts)
} }
#endif /* USE_LWRES */ #endif /* USE_LWRES */
static void static void recover_adns_die(void)
recover_adns_die(void)
{ {
struct adns_continuation *cr = NULL; struct adns_continuation *cr = NULL;
@@ -1848,8 +1775,7 @@ void reset_adns_restart_count(void)
adns_restart_count=0; adns_restart_count=0;
} }
void void handle_adns_answer(void)
handle_adns_answer(void)
{ {
/* These are retained across calls to handle_adns_answer. */ /* These are retained across calls to handle_adns_answer. */
static size_t buflen = 0; /* bytes in answer buffer */ static size_t buflen = 0; /* bytes in answer buffer */
+20 -20
View File
@@ -12,9 +12,10 @@
* for more details. * for more details.
*/ */
extern int #include <utils/identification.h>
adns_qfd, /* file descriptor for sending queries to adns */
adns_afd; /* file descriptor for receiving answers from adns */ 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 const char *pluto_adns_option; /* path from --pluto_adns */
extern void init_adns(void); extern void init_adns(void);
extern void stop_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); typedef void (*cont_fn_t)(struct adns_continuation *cr, err_t ugh);
struct adns_continuation { struct adns_continuation {
unsigned long qtid; /* query transaction id number */ unsigned long qtid; /* query transaction id number */
int type; /* T_TXT or T_KEY, selecting rr type of interest */ int type; /* T_TXT or T_KEY, selecting rr type of interest */
cont_fn_t cont_fn; /* function to carry on suspended work */ cont_fn_t cont_fn; /* function to carry on suspended work */
struct id id; /* subject of query */ identification_t *id; /* subject of query */
bool sgw_specified; bool sgw_specified;
struct id sgw_id; /* peer, if constrained */ identification_t *sgw_id; /* peer, if constrained */
lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */ 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 */ struct gw_info *gateways_from_dns; /* answer, if looking for our TXT rrs */
#ifdef USE_KEYRR #ifdef USE_KEYRR
struct pubkey_list *keys_from_dns; /* answer, if looking for KEY rrs */ 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 adns_continuation *previous, *next;
struct pubkey *last_info; /* the last structure we accumulated */ struct pubkey *last_info; /* the last structure we accumulated */
#ifdef USE_LWRES #ifdef USE_LWRES
bool used; /* have we called the cont_fn yet? */ bool used; /* have we called the cont_fn yet? */
struct { struct {
u_char name_buf[NS_MAXDNAME + 2]; u_char name_buf[NS_MAXDNAME + 2];
} query; } query;
@@ -56,8 +57,8 @@ struct adns_continuation {
#endif /* ! USE_LWRES */ #endif /* ! USE_LWRES */
}; };
extern err_t start_adns_query(const struct id *id /* domain to query */ extern err_t start_adns_query(identification_t *id /* domain to query */
, const struct id *sgw_id /* if non-null, any accepted gw_info must match */ , 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 */ , int type /* T_TXT or T_KEY, selecting rr type of interest */
, cont_fn_t cont_fn /* continuation function */ , cont_fn_t cont_fn /* continuation function */
, struct adns_continuation *cr); , 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 */ /* Gateway info gleaned from reverse DNS of client */
struct gw_info { struct gw_info {
unsigned refcnt; /* reference counted! */ unsigned refcnt; /* reference counted! */
unsigned pref; /* preference: lower is better */ unsigned pref; /* preference: lower is better */
#define NO_TIME ((time_t) -2) /* time_t value meaning "not_yet" */ #define NO_TIME ((time_t) -2) /* time_t value meaning "not_yet" */
struct id client_id; /* id of client of peer */ identification_t* client_id; /* id of client of peer */
struct id gw_id; /* id of peer (if id_is_ipaddr, .ip_addr is address) */ identification_t* gw_id; /* id of peer (if id_is_ipaddr, .ip_addr is address) */
bool gw_key_present; bool gw_key_present;
struct pubkey *key; struct pubkey *key;
struct gw_info *next; struct gw_info *next;
}; };
extern void gw_addref(struct gw_info *gw) extern void gw_addref(struct gw_info *gw);
, gw_delref(struct gw_info **gwp); extern void gw_delref(struct gw_info **gwp);
extern void reset_adns_restart_count(void); extern void reset_adns_restart_count(void);
-1
View File
@@ -33,7 +33,6 @@
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "log.h" #include "log.h"
#include "id.h"
#include "x509.h" #include "x509.h"
#include "ca.h" #include "ca.h"
#include "whack.h" #include "whack.h"
-537
View File
@@ -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:
*/
-68
View File
@@ -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
View File
@@ -35,12 +35,14 @@
#include <crypto/rngs/rng.h> #include <crypto/rngs/rng.h>
#include <credentials/keys/private_key.h> #include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h> #include <credentials/keys/public_key.h>
#include <utils/identification.h>
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "myid.h"
#include "state.h" #include "state.h"
#include "id.h"
#include "x509.h" #include "x509.h"
#include "ac.h"
#include "crl.h" #include "crl.h"
#include "ca.h" #include "ca.h"
#include "certs.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, struct state *st, chunk_t hash,
const pb_stream *sig_pbs, const pb_stream *sig_pbs,
#ifdef USE_KEYRR #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) for (gw = c->gw_info; gw != NULL; gw = gw->next)
{ {
/* only consider entries that have a key and are for our peer */ /* 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)) take_a_crack(&s, gw->key))
{ {
return STF_OK; 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; pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_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 && peer->equals(peer, key->id))
if (type == key_type && same_id(peer, &key_id))
{ {
time_t now = time(NULL); 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 */ /* 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) 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) else if (s.tried_cnt == 1)
{ {
loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: " loglog(RC_LOG_SERIOUS, "signature check for '%Y' failed: "
" wrong key?; tried %d", id_buf, s.tried_cnt); " wrong key?; tried %d", peer, s.tried_cnt);
DBG(DBG_CONTROL, DBG(DBG_CONTROL,
DBG_log("public key for '%s' failed: " DBG_log("public key for '%Y' failed: "
"decrypted SIG payload into a malformed ECB", id_buf) "decrypted SIG payload into a malformed ECB", peer)
) )
} }
else else
{ {
loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: " loglog(RC_LOG_SERIOUS, "signature check for '%Y' failed: "
"tried %d keys but none worked.", id_buf, s.tried_cnt); "tried %d keys but none worked.", peer, s.tried_cnt);
DBG(DBG_CONTROL, 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", "best decrypted SIG payload into a malformed ECB",
s.tried_cnt, id_buf) s.tried_cnt, peer)
) )
} }
return STF_FAIL + INVALID_KEY_INFORMATION; 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) 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 else
{ {
plog("Syntax error in PKCS#7 wrapped X.509 certificates"); plog("Syntax error in PKCS#7 wrapped X.509 certificates");
} }
certs->destroy_offset(certs, offsetof(certificate_t, destroy));
} }
else 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 * We must be called before SIG or HASH are decoded since we
* may change the peer's public key or ID. * 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 state *const st = md->st;
struct payload_digest *const id_pld = md->chain[ISAKMP_NEXT_ID]; struct payload_digest *const id_pld = md->chain[ISAKMP_NEXT_ID];
const pb_stream *const id_pbs = &id_pld->pbs; const pb_stream *const id_pbs = &id_pld->pbs;
struct isakmp_id *const id = &id_pld->payload.id; struct isakmp_id *const id = &id_pld->payload.id;
chunk_t id_payload;
/* I think that RFC2407 (IPSEC DOI) 4.6.2 is confused. /* I think that RFC2407 (IPSEC DOI) 4.6.2 is confused.
* It talks about the protocol ID and Port fields of the ID * 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; 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_IPV4_ADDR:
case ID_IPV6_ADDR: if (id_payload.len != 4)
/* 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)
{ {
loglog(RC_LOG_SERIOUS, "improper %s identification payload: %s" loglog(RC_LOG_SERIOUS, "improper %s Phase 1 ID payload",
, enum_show(&ident_names, peer->kind), ugh); enum_show(&ident_names, id->isaid_idtype));
/* XXX Could send notification back */
return FALSE; return FALSE;
} }
} break;
break; case ID_IPV6_ADDR:
if (id_payload.len != 16)
case ID_USER_FQDN: {
if (memchr(id_pbs->cur, '@', pbs_left(id_pbs)) == NULL) loglog(RC_LOG_SERIOUS, "improper %s Phase 1 ID payload",
{ enum_show(&ident_names, id->isaid_idtype));
loglog(RC_LOG_SERIOUS, "peer's ID_USER_FQDN contains no @"); 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; 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);
{ plog("Peer ID is %s: '%Y'", enum_show(&ident_names, id->isaid_idtype),
char buf[BUF_LEN]; *peer);
idtoa(peer, buf, sizeof(buf));
plog("Peer ID is %s: '%s'",
enum_show(&ident_names, id->isaid_idtype), buf);
}
/* check for certificates */ /* check for certificates */
decode_cert(md); 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 the initiation was explicit, we'd be ignoring user's intent
* - if opportunistic, we'll lose our HOLD info * - 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) bool initiator)
{ {
struct state *const st = md->st; struct state *const st = md->st;
@@ -2415,16 +2389,11 @@ static bool switch_connection(struct msg_digest *md, struct id *peer,
{ {
int pathlen; int pathlen;
if (!same_id(&c->spd.that.id, peer)) if (!peer->equals(peer, c->spd.that.id))
{ {
char expect[BUF_LEN] loglog(RC_LOG_SERIOUS,
, found[BUF_LEN]; "we require peer to have ID '%Y', but peer declares '%Y'",
c->spd.that.id, peer);
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);
return FALSE; return FALSE;
} }
@@ -2467,10 +2436,7 @@ static bool switch_connection(struct msg_digest *md, struct id *peer,
if (r == NULL) if (r == NULL)
{ {
char buf[BUF_LEN]; loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%Y'", peer);
idtoa(peer, buf, sizeof(buf));
loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%s'", buf);
return FALSE; 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) else if (c->spd.that.has_id_wildcards)
{ {
free_id_content(&c->spd.that.id); c->spd.that.id->destroy(c->spd.that.id);
c->spd.that.id = *peer; c->spd.that.id = peer->clone(peer);
c->spd.that.has_id_wildcards = FALSE; c->spd.that.has_id_wildcards = FALSE;
unshare_id_content(&c->spd.that.id);
} }
} }
return TRUE; return TRUE;
@@ -2736,10 +2701,9 @@ static bool has_preloaded_public_key(struct state *st)
{ {
pubkey_t *key = p->key; pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_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 &&
if (type == KEY_RSA && same_id(&c->spd.that.id, &key_id) && c->spd.that.id->equals(c->spd.that.id, key->id) &&
key->until_time == UNDEFINED_TIME) key->until_time == UNDEFINED_TIME)
{ {
/* found a preloaded public key */ /* 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. /* State Transition Functions.
* *
* The definition of state_microcode_table in demux.c is a good * 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 /* Create an instance
* This is a rare case: wildcard peer ID but static peer IP address * 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 */ /* Set up state */
@@ -3727,13 +3723,10 @@ struct key_continuation {
typedef stf_status (key_tail_fn)(struct msg_digest *md typedef stf_status (key_tail_fn)(struct msg_digest *md
, struct key_continuation *kc); , 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 */ loglog(RC_LOG_SERIOUS, "no RSA public key known for '%Y'"
"; DNS search for KEY failed (%s)", id, ugh);
(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);
} }
@@ -3753,12 +3746,14 @@ main_id_and_auth(struct msg_digest *md
{ {
chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); chunk_t hash = chunk_alloca(MAX_DIGEST_LEN);
struct state *st = md->st; struct state *st = md->st;
struct id peer; identification_t *peer;
stf_status r = STF_OK; stf_status r = STF_OK;
/* ID Payload in */ /* ID Payload in */
if (!decode_peer_id(md, &peer)) if (!decode_peer_id(md, &peer))
{
return STF_FAIL + INVALID_ID_INFORMATION; return STF_FAIL + INVALID_ID_INFORMATION;
}
/* Hash the ID Payload. /* Hash the ID Payload.
* main_mode_hash requires idpl->cur to be at end of 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 OAKLEY_RSA_SIG:
case XAUTHInitRSA: case XAUTHInitRSA:
case XAUTHRespRSA: case XAUTHRespRSA:
r = check_signature(KEY_RSA, &peer, st, hash, r = check_signature(KEY_RSA, peer, st, hash,
&md->chain[ISAKMP_NEXT_SIG]->pbs, &md->chain[ISAKMP_NEXT_SIG]->pbs,
#ifdef USE_KEYRR #ifdef USE_KEYRR
kc == NULL? NULL : kc->ac.keys_from_dns, kc == NULL ? NULL : kc->ac.keys_from_dns,
#endif /* USE_KEYRR */ #endif /* USE_KEYRR */
kc == NULL? NULL : kc->ac.gateways_from_dns kc == NULL ? NULL : kc->ac.gateways_from_dns
); );
if (r == STF_SUSPEND) if (r == STF_SUSPEND)
@@ -3826,22 +3821,14 @@ main_id_and_auth(struct msg_digest *md
#ifdef USE_KEYRR #ifdef USE_KEYRR
nkc->failure_ok = TRUE; nkc->failure_ok = TRUE;
#endif #endif
ugh = start_adns_query(&peer ugh = start_adns_query(peer, peer, T_TXT, cont_fn, &nkc->ac);
, &peer /* SG itself */
, T_TXT
, cont_fn
, &nkc->ac);
break; break;
#ifdef USE_KEYRR #ifdef USE_KEYRR
case kos_his_txt: case kos_his_txt:
/* second try: look for the KEY records */ /* second try: look for the KEY records */
nkc->step = kos_his_key; nkc->step = kos_his_key;
ugh = start_adns_query(&peer ugh = start_adns_query(peer, NULL, T_KEY, cont_fn, &nkc->ac);
, NULL /* no sgw for KEY */
, T_KEY
, cont_fn
, &nkc->ac);
break; break;
#endif /* USE_KEYRR */ #endif /* USE_KEYRR */
@@ -3851,7 +3838,7 @@ main_id_and_auth(struct msg_digest *md
if (ugh != NULL) if (ugh != NULL)
{ {
report_key_dns_failure(&peer, ugh); report_key_dns_failure(peer, ugh);
st->st_suspended_md = NULL; st->st_suspended_md = NULL;
r = STF_FAIL + INVALID_KEY_INFORMATION; 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_256:
case OAKLEY_ECDSA_384: case OAKLEY_ECDSA_384:
case OAKLEY_ECDSA_521: 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, &md->chain[ISAKMP_NEXT_SIG]->pbs,
#ifdef USE_KEYRR #ifdef USE_KEYRR
NULL, NULL,
@@ -3874,6 +3861,7 @@ main_id_and_auth(struct msg_digest *md
} }
if (r != STF_OK) if (r != STF_OK)
{ {
peer->destroy(peer);
return r; return r;
} }
DBG(DBG_CRYPT, DBG_log("authentication succeeded")); 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. * 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; return r;
} }
@@ -3928,7 +3917,7 @@ static void key_continue(struct adns_continuation *cr, err_t ugh,
if (!kc->failure_ok && ugh != NULL) 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; r = STF_FAIL + INVALID_KEY_INFORMATION;
} }
else else
@@ -4468,9 +4457,9 @@ static stf_status quick_inI1_outR1_start_query(struct verify_oppo_bundle *b,
struct state *p1st = md->st; struct state *p1st = md->st;
connection_t *c = p1st->st_connection; connection_t *c = p1st->st_connection;
struct verify_oppo_continuation *vc = malloc_thing(struct verify_oppo_continuation); struct verify_oppo_continuation *vc = malloc_thing(struct verify_oppo_continuation);
struct id id /* subject of query */ identification_t *id; /* subject of query */
, *our_id /* needed for myid playing */ identification_t *our_id; /* needed for myid playing */
, our_id_space; /* ephemeral: no need for unshare_id_content */ identification_t *our_id_space; /* ephemeral: no need for unshare_id_content */
ip_address client; ip_address client;
err_t ugh = NULL; 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 * %myid makes no sense for the other side (but it is syntactically
* legal). * legal).
*/ */
our_id = resolve_myid(&c->spd.this.id); our_id = resolve_myid(c->spd.this.id);
if (our_id->kind == ID_ANY) if (our_id->get_type(our_id) == ID_ANY)
{ {
iptoid(&c->spd.this.host_addr, &our_id_space); our_id_space = identification_create_from_sockaddr((sockaddr_t*)&c->spd.this.host_addr);
our_id = &our_id_space; our_id = our_id_space;
} }
switch (next_step) switch (next_step)
{ {
case vos_our_client: case vos_our_client:
networkof(&b->my.net, &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; vc->b.failure_ok = b->failure_ok = FALSE;
ugh = start_adns_query(&id ugh = start_adns_query(id
, our_id , our_id
, T_TXT , T_TXT
, quick_inI1_outR1_continue , 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: case vos_his_client:
networkof(&b->his.net, &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; vc->b.failure_ok = b->failure_ok = FALSE;
ugh = start_adns_query(&id ugh = start_adns_query(id
, &c->spd.that.id , c->spd.that.id
, T_TXT , T_TXT
, quick_inI1_outR1_continue , quick_inI1_outR1_continue
, &vc->ac); , &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 * We should record DNS sec use, if any -- belongs in
* state during perhaps. * 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); , NULL, &our_client, &his_client);
} }
else else
@@ -4878,7 +4867,7 @@ static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b,
* instantiate, carrying over authenticated peer ID * instantiate, carrying over authenticated peer ID
*/ */
p = rw_instantiate(p, &c->spd.that.host_addr, md->sender_port 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 #ifdef DEBUG
+6
View File
@@ -12,6 +12,11 @@
* for more details. * 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 echo_hdr(struct msg_digest *md, bool enc, u_int8_t np);
extern void ipsecdoi_initiate(int whack_sock, struct connection *c 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
View File
@@ -45,7 +45,6 @@
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "id.h"
#include "connections.h" #include "connections.h"
#include "state.h" #include "state.h"
#include "timer.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); 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 /* 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 * 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)); 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)); escape_metachar(myid_str, secure_myid_str, sizeof(secure_myid_str));
subnettot(&sr->this.client, 0, myclient_str, sizeof(myclientnet_str)); subnettot(&sr->this.client, 0, myclient_str, sizeof(myclientnet_str));
networkof(&sr->this.client, &ta); 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(&ta, 0, myclientmask_str, sizeof(myclientmask_str));
addrtot(&sr->that.host_addr, 0, peer_str, sizeof(peer_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)); escape_metachar(peerid_str, secure_peerid_str, sizeof(secure_peerid_str));
subnettot(&sr->that.client, 0, peerclient_str, sizeof(peerclientnet_str)); subnettot(&sr->that.client, 0, peerclient_str, sizeof(peerclientnet_str));
networkof(&sr->that.client, &ta); 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; pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_key); key_type_t type = key->public_key->get_type(key->public_key);
struct id key_id;
int pathlen; int pathlen;
id_from_identification(&key_id, key->id); if (type == KEY_RSA &&
sr->that.id->equals(sr->that.id, key->id) &&
if (type == KEY_RSA && same_id(&sr->that.id, &key_id) &&
trusted_ca(key->issuer, sr->that.ca, &pathlen)) trusted_ca(key->issuer, sr->that.ca, &pathlen))
{ {
if (key->issuer) if (key->issuer)
+25 -60
View File
@@ -39,7 +39,6 @@
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "id.h"
#include "x509.h" #include "x509.h"
#include "pgpcert.h" #include "pgpcert.h"
#include "certs.h" #include "certs.h"
@@ -61,7 +60,7 @@ const char *shared_secrets_file = SHARED_SECRETS_FILE;
typedef struct id_list id_list_t; typedef struct id_list id_list_t;
struct id_list { struct id_list {
struct id id; identification_t *id;
id_list_t *next; id_list_t *next;
}; };
@@ -109,9 +108,7 @@ static const secret_t* get_secret(const connection_t *c,
unsigned int best_match = 0; unsigned int best_match = 0;
secret_t *best = NULL; secret_t *best = NULL;
secret_t *s; secret_t *s;
const struct id *my_id = &c->spd.this.id identification_t *my_id, *his_id;
, *his_id = &c->spd.that.id;
struct id rw_id;
/* is there a certificate assigned to this connection? */ /* is there a certificate assigned to this connection? */
if (kind == PPK_PUBKEY && c->spd.this.cert.type != CERT_NONE) 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; return best;
} }
my_id = c->spd.this.id;
if (his_id_was_instantiated(c)) if (his_id_was_instantiated(c))
{ {
/* roadwarrior: replace him with 0.0.0.0 */ /* roadwarrior: replace him with 0.0.0.0 */
rw_id.kind = c->spd.that.id.kind; his_id = identification_create_from_string("%any");
rw_id.name = chunk_empty;
happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr));
his_id = &rw_id;
} }
else if (kind == PPK_PSK else if (kind == PPK_PSK && (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK)) &&
&& (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK)) ((c->kind == CK_TEMPLATE &&
&& ((c->kind == CK_TEMPLATE && c->spd.that.id.kind == ID_ANY) || c->spd.that.id->get_type(c->spd.that.id) == ID_ANY) ||
(c->kind == CK_INSTANCE && id_is_ipaddr(&c->spd.that.id)))) (c->kind == CK_INSTANCE && id_is_ipaddr(c->spd.that.id))))
{ {
/* roadwarrior: replace him with 0.0.0.0 */ /* roadwarrior: replace him with 0.0.0.0 */
rw_id.kind = ID_IPV4_ADDR; his_id = identification_create_from_string("%any");
happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr)); }
his_id = &rw_id; else
{
his_id = c->spd.that.id->clone(c->spd.that.id);
} }
for (s = secrets; s != NULL; s = s->next) 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) 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; match |= match_me;
} }
if (same_id(his_id, &i->id)) if (his_id->equals(his_id, i->id))
{ {
match |= match_him; match |= match_him;
} }
@@ -240,6 +238,7 @@ static const secret_t* get_secret(const connection_t *c,
} }
} }
} }
his_id->destroy(his_id);
return best; return best;
} }
@@ -761,16 +760,12 @@ static void log_psk(secret_t *s)
{ {
do 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) if (n >= BUF_LEN)
{ {
n = BUF_LEN - 1; n = BUF_LEN - 1;
break; break;
} }
else if (n < BUF_LEN - 1)
{
n += snprintf(buf + n, BUF_LEN - n, " ");
}
id_list = id_list->next; id_list = id_list->next;
} }
while (id_list); while (id_list);
@@ -947,42 +942,12 @@ static void process_secret_records(int whackfd)
/* an id /* an id
* See RFC2407 IPsec Domain of Interpretation 4.6.2 * See RFC2407 IPsec Domain of Interpretation 4.6.2
*/ */
struct id id; id_list_t *i = malloc_thing(id_list_t);
err_t ugh;
if (tokeq("%any")) i->id = identification_create_from_string(tok);
{ i->next = s->ids;
id = empty_id; s->ids = i;
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);
}
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()) if (!shift())
{ {
/* unexpected Record Boundary or EOF */ /* unexpected Record Boundary or EOF */
@@ -1070,11 +1035,11 @@ void free_preshared_secrets(void)
{ {
id_list_t *i, *ni; id_list_t *i, *ni;
ns = s->next; /* grab before freeing s */ ns = s->next;
for (i = s->ids; i != NULL; i = ni) for (i = s->ids; i != NULL; i = ni)
{ {
ni = i->next; /* grab before freeing i */ ni = i->next;
free_id_content(&i->id); i->id->destroy(i->id);
free(i); free(i);
} }
switch (s->kind) switch (s->kind)
+1
View File
@@ -38,6 +38,7 @@
#include "server.h" #include "server.h"
#include "state.h" #include "state.h"
#include "connections.h" #include "connections.h"
#include "myid.h"
#include "kernel.h" #include "kernel.h"
#include "whack.h" /* needs connections.h */ #include "whack.h" /* needs connections.h */
#include "timer.h" #include "timer.h"
+2 -1
View File
@@ -1154,7 +1154,8 @@ xauth_inR1(struct msg_digest *md)
peer.conn_name = st->st_connection->name; peer.conn_name = st->st_connection->name;
addrtot(&md->sender, 0, peer.ip_address, sizeof(peer.ip_address)); 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(DBG_CONTROL,
DBG_log("peer xauth user name is '%.*s'" DBG_log("peer xauth user name is '%.*s'"
+121
View File
@@ -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:
*/
+38
View File
@@ -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
View File
@@ -27,13 +27,11 @@
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "log.h" #include "log.h"
#include "id.h"
#include "pgpcert.h" #include "pgpcert.h"
#include "certs.h" #include "certs.h"
#include "whack.h" #include "whack.h"
#include "keys.h" #include "keys.h"
typedef enum pgp_packet_tag_t pgp_packet_tag_t; 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 * 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; id->destroy(id);
end_id->name = cert->fingerprint->get_encoding(cert->fingerprint);
return cert->fingerprint->clone(cert->fingerprint);
} }
/** /**
+2 -1
View File
@@ -17,6 +17,7 @@
#ifndef _PGPCERT_H #ifndef _PGPCERT_H
#define _PGPCERT_H #define _PGPCERT_H
#include <utils/identification.h>
#include <crypto/hashers/hasher.h> #include <crypto/hashers/hasher.h>
#include <credentials/keys/private_key.h> #include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h> #include <credentials/keys/public_key.h>
@@ -46,7 +47,7 @@ struct pgpcert {
extern const pgpcert_t pgpcert_empty; extern const pgpcert_t pgpcert_empty;
extern bool parse_pgp(chunk_t blob, pgpcert_t *cert); extern bool parse_pgp(chunk_t blob, pgpcert_t *cert);
extern void share_pgpcert(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 pgpcert_t* add_pgpcert(pgpcert_t *cert);
extern void list_pgp_end_certs(bool utc); extern void list_pgp_end_certs(bool utc);
extern void release_pgpcert(pgpcert_t *cert); extern void release_pgpcert(pgpcert_t *cert);
+26 -32
View File
@@ -19,8 +19,6 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <freeswan.h>
#include <library.h> #include <library.h>
#include <debug.h> #include <debug.h>
#include <asn1/asn1.h> #include <asn1/asn1.h>
@@ -28,11 +26,8 @@
#include <asn1/oid.h> #include <asn1/oid.h>
#include <crypto/rngs/rng.h> #include <crypto/rngs/rng.h>
#include <crypto/crypters/crypter.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" #include "pkcs7.h"
const contentInfo_t empty_contentInfo = { const contentInfo_t empty_contentInfo = {
@@ -170,7 +165,8 @@ end:
/** /**
* Parse a PKCS#7 signedData object * 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) chunk_t *attributes, certificate_t *cacert)
{ {
asn1_parser_t *parser; asn1_parser_t *parser;
@@ -218,24 +214,17 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
} }
break; break;
case PKCS7_SIGNED_CERT: case PKCS7_SIGNED_CERT:
if (cert != NULL)
{ {
x509cert_t *newcert = malloc_thing(x509cert_t); certificate_t *cert;
DBG2(" parsing pkcs7-wrapped certificate"); DBG2(" parsing pkcs7-wrapped certificate");
*newcert = empty_x509cert; cert = lib->creds->create(lib->creds,
newcert->cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
CRED_CERTIFICATE, CERT_X509, BUILD_BLOB_ASN1_DER, object,
BUILD_BLOB_ASN1_DER, object, BUILD_END);
BUILD_END); if (cert)
if (newcert->cert)
{ {
newcert->next = *cert; certs->insert_last(certs, cert);
*cert = newcert;
}
else
{
free_x509cert(newcert);
} }
} }
break; break;
@@ -600,22 +589,27 @@ chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
private_key_t *key) private_key_t *key)
{ {
contentInfo_t pkcs7Data, signedData; 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, if (key->sign(key, scheme, attributes, &signature))
FALSE); {
authenticatedAttributes = chunk_clone(attributes); encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature);
*authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; authenticatedAttributes = chunk_clone(attributes);
*authenticatedAttributes.ptr = ASN1_CONTEXT_C_0;
}
} }
else else if (data.ptr)
{ {
encryptedDigest = (data.ptr == NULL)? chunk_empty if (key->sign(key, scheme, data, &signature))
: x509_build_signature(data, digest_alg, key, FALSE); {
authenticatedAttributes = chunk_empty; encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature);
}
} }
signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm" signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm"
, ASN1_INTEGER_1 , ASN1_INTEGER_1
, pkcs7_build_issuerAndSerialNumber(cert) , pkcs7_build_issuerAndSerialNumber(cert)
+2 -3
View File
@@ -18,11 +18,10 @@
#ifndef _PKCS7_H #ifndef _PKCS7_H
#define _PKCS7_H #define _PKCS7_H
#include <utils/linked_list.h>
#include <crypto/crypters/crypter.h> #include <crypto/crypters/crypter.h>
#include <credentials/keys/private_key.h> #include <credentials/keys/private_key.h>
#include <credentials/certificates/certificate.h> #include <credentials/certificates/certificate.h>
#include "defs.h"
#include "x509.h"
/* Access structure for a PKCS#7 ContentInfo object */ /* 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, extern bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0,
contentInfo_t *cInfo); contentInfo_t *cInfo);
extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, 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); certificate_t *cacert);
extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
chunk_t serialNumber, private_key_t *key); chunk_t serialNumber, private_key_t *key);
+3 -3
View File
@@ -48,7 +48,7 @@
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "id.h" #include "myid.h"
#include "ca.h" #include "ca.h"
#include "certs.h" #include "certs.h"
#include "ac.h" #include "ac.h"
@@ -673,7 +673,7 @@ int main(int argc, char **argv)
init_demux(); init_demux();
init_kernel(); init_kernel();
init_adns(); init_adns();
init_id(); init_myid();
init_fetch(); init_fetch();
/* drop unneeded capabilities and change UID/GID */ /* drop unneeded capabilities and change UID/GID */
@@ -762,7 +762,7 @@ void exit_pluto(int status)
stop_adns(); stop_adns();
free_md_pool(); free_md_pool();
free_crypto(); free_crypto();
free_id(); /* free myids */ free_myid(); /* free myids */
free_events(); /* free remaining events */ free_events(); /* free remaining events */
free_vendorid(); /* free all vendor id records */ free_vendorid(); /* free all vendor id records */
free_builder(); free_builder();
+56 -67
View File
@@ -33,7 +33,6 @@
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "id.h"
#include "ca.h" #include "ca.h"
#include "certs.h" #include "certs.h"
#include "ac.h" #include "ac.h"
@@ -55,9 +54,10 @@
#include "fetch.h" #include "fetch.h"
#include "ocsp.h" #include "ocsp.h"
#include "crl.h" #include "crl.h"
#include "myid.h"
#include "kernel_alg.h" #include "kernel_alg.h"
#include "ike_alg.h" #include "ike_alg.h"
/* helper variables and function to decode strings from whack message */ /* helper variables and function to decode strings from whack message */
static char *next_str static char *next_str
@@ -102,17 +102,13 @@ struct key_add_continuation {
enum key_add_attempt lookingfor; 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 */ loglog(RC_NOKEY, "failure to fetch key for %'Y' from DNS: %s", keyid, ugh);
(void)idtoa(keyid, name, sizeof(name));
loglog(RC_NOKEY
, "failure to fetch key for %s from DNS: %s", name, ugh);
} }
/* last one out: turn out the lights */ /* 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) 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 no success, print all diagnostics */
if (!oc->success) if (!oc->success)
{
for (kaa = ka_TXT; kaa != ka_roof; kaa++) for (kaa = ka_TXT; kaa != ka_roof; kaa++)
{
key_add_ugh(keyid, oc->diag[kaa]); key_add_ugh(keyid, oc->diag[kaa]);
}
}
for (kaa = ka_TXT; kaa != ka_roof; kaa++) for (kaa = ka_TXT; kaa != ka_roof; kaa++)
{ {
free(oc->diag[kaa]); free(oc->diag[kaa]);
@@ -155,91 +154,81 @@ static void key_add_continue(struct adns_continuation *ac, err_t ugh)
} }
oc->refCount--; oc->refCount--;
key_add_merge(oc, &ac->id); key_add_merge(oc, ac->id);
whack_log_fd = NULL_FD; whack_log_fd = NULL_FD;
} }
static void key_add_request(const whack_message_t *msg) static void key_add_request(const whack_message_t *msg)
{ {
identification_t *key_id; 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); struct key_add_continuation *kc;
}
if (msg->keyval.len == 0)
{
struct key_add_common *oc = malloc_thing(struct key_add_common);
enum key_add_attempt kaa;
/* initialize state shared by queries */ oc->diag[kaa] = NULL;
oc->refCount = 0; oc->refCount++;
oc->whack_fd = dup_any(whack_log_fd); kc = malloc_thing(struct key_add_continuation);
oc->success = FALSE; 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: case ka_TXT:
ugh = start_adns_query(&keyid ugh = start_adns_query(key_id
, &keyid /* same */ , key_id /* same */
, T_TXT , T_TXT
, key_add_continue , key_add_continue
, &kc->ac); , &kc->ac);
break; break;
#ifdef USE_KEYRR #ifdef USE_KEYRR
case ka_KEY: case ka_KEY:
ugh = start_adns_query(&keyid ugh = start_adns_query(key_id
, NULL , NULL
, T_KEY , T_KEY
, key_add_continue , key_add_continue
, &kc->ac); , &kc->ac);
break; break;
#endif /* USE_KEYRR */ #endif /* USE_KEYRR */
default: default:
bad_case(kaa); /* suppress gcc warning */ bad_case(kaa); /* suppress gcc warning */
}
if (ugh != NULL)
{
oc->diag[kaa] = clone_str(ugh);
oc->refCount--;
}
} }
if (ugh)
/* 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))
{ {
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 /* Handle a kernel request. Supposedly, there's a message in
+4 -6
View File
@@ -24,7 +24,6 @@
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "id.h"
#include "connections.h" #include "connections.h"
#include "state.h" #include "state.h"
#include "packet.h" #include "packet.h"
@@ -835,19 +834,18 @@ static err_t find_preshared_key(struct state* st)
if (get_preshared_secret(c) == NULL) 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)) if (his_id_was_instantiated(c))
{ {
strcpy(his_id, "%any"); strcpy(his_id, "%any");
} }
else 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'" ugh = builddiag("Can't authenticate: no preshared key found "
, my_id, his_id); "for '%Y' and '%s'", c->spd.this.id, his_id);
} }
return ugh; return ugh;
} }
+1
View File
@@ -21,6 +21,7 @@
#include <crypto/diffie_hellman.h> #include <crypto/diffie_hellman.h>
#include "defs.h"
#include "connections.h" #include "connections.h"
/* Message ID mechanism. /* Message ID mechanism.
+50 -735
View File
@@ -26,8 +26,6 @@
#include <freeswan.h> #include <freeswan.h>
#include <asn1/asn1.h> #include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
#include <asn1/oid.h>
#include <crypto/hashers/hasher.h> #include <crypto/hashers/hasher.h>
#include <utils/enumerator.h> #include <utils/enumerator.h>
#include <utils/identification.h> #include <utils/identification.h>
@@ -35,7 +33,6 @@
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "log.h" #include "log.h"
#include "id.h"
#include "x509.h" #include "x509.h"
#include "crl.h" #include "crl.h"
#include "ca.h" #include "ca.h"
@@ -50,23 +47,6 @@
*/ */
static x509cert_t *x509certs = NULL; 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 = { const x509cert_t empty_x509cert = {
NULL , /* cert */ NULL , /* cert */
NULL , /* *next */ NULL , /* *next */
@@ -76,666 +56,6 @@ const x509cert_t empty_x509cert = {
/* coding of X.501 distinguished name */ /* 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 * 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 * 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; certificate_t *certificate = cert->cert;
x509_t *x509 = (x509_t*)certificate; 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_t *enumerator;
enumerator = x509->create_subjectAltName_enumerator(x509); enumerator = x509->create_subjectAltName_enumerator(x509);
while (enumerator->enumerate(enumerator, &subjectAltName)) while (enumerator->enumerate(enumerator, &subjectAltName))
{ {
struct id id = empty_id; if (id->equals(id, subjectAltName))
id_from_identification(&id, subjectAltName);
if (same_id(&id, end_id))
{ {
copy_subject_dn = FALSE; /* take subjectAltName instead */ copy_subject_dn = FALSE; /* take subjectAltName instead */
break; break;
@@ -805,23 +122,17 @@ void select_x509cert_id(x509cert_t *cert, struct id *end_id)
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
} }
if (copy_subject_dn) if (copy_subject_dn)
{ {
identification_t *subject = certificate->get_subject(certificate); id->destroy(id);
chunk_t subject_dn = subject->get_encoding(subject); 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) return subject->clone(subject);
{ }
char buf[BUF_LEN]; else
{
idtoa(end_id, buf, BUF_LEN); return id;
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);
} }
} }
@@ -899,42 +210,40 @@ void release_x509cert(x509cert_t *cert)
/** /**
* Stores a chained list of end certs and CA certs * 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 *x509cert, *cacerts = NULL;
x509cert_t **pp = firstcert; 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; x509_t *x509 = (x509_t*)cert;
certificate_t *certificate = cert->cert; x509_flag_t flags;
x509_t *x509 = (x509_t*)certificate;
x509_flag_t flags = x509->get_flags(x509);
flags = x509->get_flags(x509);
if (flags & X509_CA) if (flags & X509_CA)
{ {
*pp = cert->next;
/* we don't accept self-signed CA certs */ /* we don't accept self-signed CA certs */
if (flags & X509_SELF_SIGNED) if (flags & X509_SELF_SIGNED)
{ {
plog("self-signed cacert rejected"); plog("self-signed cacert rejected");
free_x509cert(cert);
} }
else else
{ {
/* insertion into temporary chain of candidate CA certs */ /* insertion into temporary chain of candidate CA certs */
cert->next = cacerts; x509cert = malloc_thing(x509cert_t);
cacerts = cert; *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 */ /* now verify the candidate CA certs */
@@ -957,27 +266,33 @@ void store_x509certs(x509cert_t **firstcert, bool strict)
/* now verify the end certificates */ /* now verify the end certificates */
pp = firstcert; enumerator = certs->create_enumerator(certs);
while (enumerator->enumerate(enumerator, &cert))
while (*pp)
{ {
time_t valid_until; 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, x509cert = malloc_thing(x509cert_t);
DBG_log("public key validated") *x509cert = empty_x509cert;
) x509cert->cert = cert->get_ref(cert);
add_x509_public_key(cert, valid_until, DAL_SIGNED);
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
View File
@@ -19,12 +19,12 @@
#define _X509_H #define _X509_H
#include <utils/identification.h> #include <utils/identification.h>
#include <utils/linked_list.h>
#include <credentials/keys/public_key.h> #include <credentials/keys/public_key.h>
#include <credentials/keys/private_key.h> #include <credentials/keys/private_key.h>
#include <credentials/certificates/x509.h> #include <credentials/certificates/x509.h>
#include "constants.h" #include "constants.h"
#include "id.h"
/* access structure for an X.509v3 certificate */ /* access structure for an X.509v3 certificate */
@@ -41,12 +41,7 @@ struct x509cert {
extern const x509cert_t empty_x509cert; extern const x509cert_t empty_x509cert;
extern bool same_keyid(chunk_t a, chunk_t b); extern bool same_keyid(chunk_t a, chunk_t b);
extern bool same_dn(chunk_t a, chunk_t b); extern identification_t* select_x509cert_id(x509cert_t *cert, identification_t *id);
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 void parse_authorityKeyIdentifier(chunk_t blob, int level0, extern void parse_authorityKeyIdentifier(chunk_t blob, int level0,
chunk_t *authKeyID, chunk_t *authKeyID,
chunk_t *authKeySerialNumber); 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 share_x509cert(x509cert_t *cert);
extern void release_x509cert(x509cert_t *cert); extern void release_x509cert(x509cert_t *cert);
extern void free_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, extern void list_x509cert_chain(const char *caption, x509cert_t* cert,
x509_flag_t flags, bool utc); x509_flag_t flags, bool utc);
extern void list_x509_end_certs(bool utc); extern void list_x509_end_certs(bool utc);
+1 -31
View File
@@ -24,8 +24,7 @@ LIBSTRONGSWANBUILDDIR=$(top_builddir)/src/libstrongswan
LIBFREESWANBUILDDIR=$(top_builddir)/src/libfreeswan LIBFREESWANBUILDDIR=$(top_builddir)/src/libfreeswan
scepclient_LDADD = \ scepclient_LDADD = \
ca.o crl.o certs.o constants.o defs.o fetch.o id.o keys.o lex.o \ constants.o defs.o lex.o pkcs7.o \
ocsp.o pgpcert.o pkcs7.o smartcard.o x509.o \
$(LIBSTRONGSWANBUILDDIR)/libstrongswan.la \ $(LIBSTRONGSWANBUILDDIR)/libstrongswan.la \
$(LIBFREESWANBUILDDIR)/libfreeswan.a $(LIBFREESWANBUILDDIR)/libfreeswan.a
@@ -37,44 +36,15 @@ endif
dist_man_MANS = scepclient.8 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 constants.o : $(PLUTODIR)/constants.c $(PLUTODIR)/constants.h
$(COMPILE) $(INCLUDES) -c -o $@ $< $(COMPILE) $(INCLUDES) -c -o $@ $<
crl.o : $(PLUTODIR)/crl.c $(PLUTODIR)/crl.h
$(COMPILE) $(INCLUDES) -c -o $@ $<
defs.o : $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h defs.o : $(PLUTODIR)/defs.c $(PLUTODIR)/defs.h
$(COMPILE) $(INCLUDES) -c -o $@ $< $(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 lex.o : $(PLUTODIR)/lex.c $(PLUTODIR)/lex.h
$(COMPILE) $(INCLUDES) -c -o $@ $< $(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 pkcs7.o : $(PLUTODIR)/pkcs7.c $(PLUTODIR)/pkcs7.h
$(COMPILE) $(INCLUDES) -c -o $@ $< $(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
View File
@@ -54,8 +54,8 @@
#include "../pluto/constants.h" #include "../pluto/constants.h"
#include "../pluto/defs.h" #include "../pluto/defs.h"
#include "../pluto/log.h" #include "../pluto/log.h"
#include "../pluto/pkcs7.h"
#include "../pluto/certs.h" #include "../pluto/certs.h"
#include "../pluto/pkcs7.h"
#include "scep.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 */ 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); 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 */ else /* generate an RSA key pair */
{ {
@@ -1020,10 +1020,12 @@ int main(int argc, char **argv)
*/ */
if (filetype_out & CERT) if (filetype_out & CERT)
{ {
certificate_t *cert;
enumerator_t *enumerator;
char *path = concatenate_paths(CA_CERT_PATH, file_in_cacert_sig); char *path = concatenate_paths(CA_CERT_PATH, file_in_cacert_sig);
time_t poll_start = 0; time_t poll_start = 0;
x509cert_t *certs = NULL; linked_list_t *certs = linked_list_create();
chunk_t envelopedData = chunk_empty; chunk_t envelopedData = chunk_empty;
chunk_t certData = chunk_empty; chunk_t certData = chunk_empty;
contentInfo_t data = empty_contentInfo; contentInfo_t data = empty_contentInfo;
@@ -1115,7 +1117,7 @@ int main(int argc, char **argv)
{ {
exit_scepclient("could not decrypt envelopedData"); 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"); exit_scepclient("error parsing the scep response");
} }
@@ -1123,11 +1125,12 @@ int main(int argc, char **argv)
/* store the end entity certificate */ /* store the end entity certificate */
path = concatenate_paths(HOST_CERT_PATH, file_out_cert); 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; bool stored = FALSE;
x509cert_t *cert = certs; x509_t *x509 = (x509_t*)cert;
x509_t *x509 = (x509_t*)cert->cert;
if (!(x509->get_flags(x509) & X509_CA)) 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"); 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)) if (!chunk_write(encoding, path, "requested cert", 0022, force))
{ {
exit_scepclient("could not write cert file '%s'", path); exit_scepclient("could not write cert file '%s'", path);
@@ -1143,9 +1146,8 @@ int main(int argc, char **argv)
chunk_free(&encoding); chunk_free(&encoding);
stored = TRUE; stored = TRUE;
} }
certs = certs->next;
free_x509cert(cert);
} }
certs->destroy_offset(certs, offsetof(certificate_t, destroy));
filetype_out &= ~CERT; /* delete CERT flag */ filetype_out &= ~CERT; /* delete CERT flag */
} }
+2
View File
@@ -17,6 +17,8 @@
#include <freeswan.h> #include <freeswan.h>
#include <defs.h>
/* copy of smartcard operations, defined in smartcard.h */ /* copy of smartcard operations, defined in smartcard.h */
#ifndef SC_OP_T #ifndef SC_OP_T
#define SC_OP_T #define SC_OP_T