diff options
Diffstat (limited to 'src/libstrongswan/utils/identification.c')
-rw-r--r-- | src/libstrongswan/utils/identification.c | 382 |
1 files changed, 192 insertions, 190 deletions
diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index 10daf4679..b0da340bc 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -26,6 +26,7 @@ #include <asn1/oid.h> #include <asn1/asn1.h> +#include <crypto/hashers/hasher.h> ENUM_BEGIN(id_match_names, ID_MATCH_NONE, ID_MATCH_MAX_WILDCARDS, "MATCH_NONE", @@ -48,15 +49,14 @@ ENUM_BEGIN(id_type_names, ID_ANY, ID_KEY_ID, "ID_DER_ASN1_DN", "ID_DER_ASN1_GN", "ID_KEY_ID"); -ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_CERT_DER_SHA1, ID_KEY_ID, - "ID_DER_ASN1_GN_URI", - "ID_PUBKEY_INFO_SHA1", - "ID_PUBKEY_SHA1", - "ID_CERT_DER_SHA1"); -ENUM_END(id_type_names, ID_CERT_DER_SHA1); +ENUM_NEXT(id_type_names, ID_DER_ASN1_GN_URI, ID_MYID, ID_KEY_ID, + "ID_DER_ASN1_GN_URI" + "ID_IETF_ATTR_STRING" + "ID_MYID"); +ENUM_END(id_type_names, ID_MYID); /** - * coding of X.501 distinguished name + * coding of X.501 distinguished name */ typedef struct { const u_char *name; @@ -109,12 +109,12 @@ struct private_identification_t { * Public interface. */ identification_t public; - + /** * Encoded representation of this ID. */ chunk_t encoded; - + /** * Type of this ID. */ @@ -133,14 +133,11 @@ typedef struct { chunk_t seqs; } rdn_enumerator_t; -/** - * Implementation of rdn_enumerator_t.enumerate - */ -static bool rdn_enumerate(rdn_enumerator_t *this, chunk_t *oid, - u_char *type, chunk_t *data) +METHOD(enumerator_t, rdn_enumerate, bool, + rdn_enumerator_t *this, chunk_t *oid, u_char *type, chunk_t *data) { chunk_t rdn; - + /* a DN contains one or more SET, each containing one or more SEQUENCES, * each containing a OID/value RDN */ if (!this->seqs.len) @@ -155,7 +152,7 @@ static bool rdn_enumerate(rdn_enumerator_t *this, chunk_t *oid, asn1_unwrap(&rdn, oid) == ASN1_OID) { int t = asn1_unwrap(&rdn, data); - + if (t != ASN1_INVALID) { *type = t; @@ -170,11 +167,15 @@ static bool rdn_enumerate(rdn_enumerator_t *this, chunk_t *oid, */ static enumerator_t* create_rdn_enumerator(chunk_t dn) { - rdn_enumerator_t *e = malloc_thing(rdn_enumerator_t); - - e->public.enumerate = (void*)rdn_enumerate; - e->public.destroy = (void*)free; - + rdn_enumerator_t *e; + + INIT(e, + .public = { + .enumerate = (void*)_rdn_enumerate, + .destroy = (void*)free, + }, + ); + /* a DN is a SEQUENCE, get the first SET of it */ if (asn1_unwrap(&dn, &e->sets) == ASN1_SEQUENCE) { @@ -195,11 +196,8 @@ typedef struct { enumerator_t *inner; } rdn_part_enumerator_t; -/** - * Implementation of rdn_part_enumerator_t.enumerate(). - */ -static bool rdn_part_enumerate(rdn_part_enumerator_t *this, - id_part_t *type, chunk_t *data) +METHOD(enumerator_t, rdn_part_enumerate, bool, + rdn_part_enumerator_t *this, id_part_t *type, chunk_t *data) { int i, known_oid, strtype; chunk_t oid, inner_data; @@ -224,7 +222,7 @@ static bool rdn_part_enumerate(rdn_part_enumerator_t *this, {OID_EMAIL_ADDRESS, ID_PART_RDN_E}, {OID_EMPLOYEE_NUMBER, ID_PART_RDN_EN}, }; - + while (this->inner->enumerate(this->inner, &oid, &strtype, &inner_data)) { known_oid = asn1_known_oid(oid); @@ -241,30 +239,29 @@ static bool rdn_part_enumerate(rdn_part_enumerator_t *this, return FALSE; } -/** - * Implementation of rdn_part_enumerator_t.destroy(). - */ -static void rdn_part_enumerator_destroy(rdn_part_enumerator_t *this) +METHOD(enumerator_t, rdn_part_enumerator_destroy, void, + rdn_part_enumerator_t *this) { this->inner->destroy(this->inner); free(this); } -/** - * Implementation of identification_t.create_part_enumerator - */ -static enumerator_t* create_part_enumerator(private_identification_t *this) +METHOD(identification_t, create_part_enumerator, enumerator_t*, + private_identification_t *this) { switch (this->type) { case ID_DER_ASN1_DN: { - rdn_part_enumerator_t *e = malloc_thing(rdn_part_enumerator_t); - - e->inner = create_rdn_enumerator(this->encoded); - e->public.enumerate = (void*)rdn_part_enumerate; - e->public.destroy = (void*)rdn_part_enumerator_destroy; - + rdn_part_enumerator_t *e; + + INIT(e, + .inner = create_rdn_enumerator(this->encoded), + .public = { + .enumerate = (void*)_rdn_part_enumerate, + .destroy = _rdn_part_enumerator_destroy, + }, + ); return &e->public; } case ID_RFC822_ADDR: @@ -282,16 +279,16 @@ static enumerator_t* create_part_enumerator(private_identification_t *this) static void dntoa(chunk_t dn, char *buf, size_t len) { enumerator_t *e; - chunk_t oid_data, data; + chunk_t oid_data, data, printable; u_char type; int oid, written; bool finished = FALSE; - + e = create_rdn_enumerator(dn); while (e->enumerate(e, &oid_data, &type, &data)) { oid = asn1_known_oid(oid_data); - + if (oid == OID_UNKNOWN) { written = snprintf(buf, len, "%#B=", &oid_data); @@ -302,18 +299,13 @@ static void dntoa(chunk_t dn, char *buf, size_t len) } buf += written; len -= written; - - if (chunk_printable(data, NULL, '?')) - { - written = snprintf(buf, len, "%.*s", data.len, data.ptr); - } - else - { - written = snprintf(buf, len, "%#B", &data); - } + + chunk_printable(data, &printable, '?'); + written = snprintf(buf, len, "%.*s", printable.len, printable.ptr); + chunk_free(&printable); buf += written; len -= written; - + if (data.ptr + data.len != dn.ptr + dn.len) { written = snprintf(buf, len, ", "); @@ -347,7 +339,7 @@ static status_t atodn(char *src, chunk_t *dn) READ_NAME = 3, UNKNOWN_OID = 4 } state_t; - + chunk_t oid = chunk_empty; chunk_t name = chunk_empty; chunk_t rdns[RDN_MAX]; @@ -358,7 +350,7 @@ static status_t atodn(char *src, chunk_t *dn) asn1_t rdn_type; state_t state = SEARCH_OID; status_t status = SUCCESS; - + do { switch (state) @@ -379,7 +371,7 @@ static status_t atodn(char *src, chunk_t *dn) else { bool found = FALSE; - + for (i = 0; i < countof(x501rdns); i++) { if (strlen(x501rdns[i].name) == oid.len && @@ -424,15 +416,15 @@ static status_t atodn(char *src, chunk_t *dn) rdn_type = (x501rdns[i].type == ASN1_PRINTABLESTRING && !asn1_is_printablestring(name)) ? ASN1_T61STRING : x501rdns[i].type; - + if (rdn_count < RDN_MAX) { chunk_t rdn_oid; - + rdn_oid = asn1_build_known_oid(x501rdns[i].oid); if (rdn_oid.len) { - rdns[rdn_count] = + rdns[rdn_count] = asn1_wrap(ASN1_SET, "m", asn1_wrap(ASN1_SEQUENCE, "mm", rdn_oid, @@ -459,20 +451,20 @@ static status_t atodn(char *src, chunk_t *dn) break; } } while (*src++ != '\0'); - + /* build the distinguished name sequence */ { int i; u_char *pos = asn1_build_object(dn, ASN1_SEQUENCE, dn_len); - + for (i = 0; i < rdn_count; i++) { - memcpy(pos, rdns[i].ptr, rdns[i].len); + memcpy(pos, rdns[i].ptr, rdns[i].len); pos += rdns[i].len; free(rdns[i].ptr); } } - + if (status != SUCCESS) { free(dn->ptr); @@ -481,32 +473,26 @@ static status_t atodn(char *src, chunk_t *dn) return status; } -/** - * Implementation of identification_t.get_encoding. - */ -static chunk_t get_encoding(private_identification_t *this) +METHOD(identification_t, get_encoding, chunk_t, + private_identification_t *this) { return this->encoded; } -/** - * Implementation of identification_t.get_type. - */ -static id_type_t get_type(private_identification_t *this) +METHOD(identification_t, get_type, id_type_t, + private_identification_t *this) { return this->type; } -/** - * Implementation of identification_t.contains_wildcards for ID_DER_ASN1_DN. - */ -static bool contains_wildcards_dn(private_identification_t *this) +METHOD(identification_t, contains_wildcards_dn, bool, + private_identification_t *this) { enumerator_t *enumerator; bool contains = FALSE; id_part_t type; chunk_t data; - + enumerator = create_part_enumerator(this); while (enumerator->enumerate(enumerator, &type, &data)) { @@ -520,27 +506,22 @@ static bool contains_wildcards_dn(private_identification_t *this) return contains; } -/** - * Implementation of identification_t.contains_wildcards using memchr(*). - */ -static bool contains_wildcards_memchr(private_identification_t *this) +METHOD(identification_t, contains_wildcards_memchr, bool, + private_identification_t *this) { return memchr(this->encoded.ptr, '*', this->encoded.len) != NULL; } -/** - * Default implementation of identification_t.equals. - * compares encoded chunk for equality. - */ -static bool equals_binary(private_identification_t *this, private_identification_t *other) +METHOD(identification_t, equals_binary, bool, + private_identification_t *this, identification_t *other) { - if (this->type == other->type) + if (this->type == other->get_type(other)) { if (this->type == ID_ANY) { return TRUE; } - return chunk_equals(this->encoded, other->encoded); + return chunk_equals(this->encoded, other->get_encoding(other)); } return FALSE; } @@ -554,7 +535,7 @@ static bool compare_dn(chunk_t t_dn, chunk_t o_dn, int *wc) chunk_t t_oid, o_oid, t_data, o_data; u_char t_type, o_type; bool t_next, o_next, finished = FALSE; - + if (wc) { *wc = 0; @@ -571,14 +552,14 @@ static bool compare_dn(chunk_t t_dn, chunk_t o_dn, int *wc) { return TRUE; } - + t = create_rdn_enumerator(t_dn); o = create_rdn_enumerator(o_dn); while (TRUE) { t_next = t->enumerate(t, &t_oid, &t_type, &t_data); o_next = o->enumerate(o, &o_oid, &o_type, &o_data); - + if (!o_next && !t_next) { break; @@ -605,8 +586,7 @@ static bool compare_dn(chunk_t t_dn, chunk_t o_dn, int *wc) if (t_type == o_type && (t_type == ASN1_PRINTABLESTRING || (t_type == ASN1_IA5STRING && - (asn1_known_oid(t_oid) == OID_PKCS9_EMAIL || - asn1_known_oid(t_oid) == OID_EMAIL_ADDRESS)))) + asn1_known_oid(t_oid) == OID_EMAIL_ADDRESS))) { /* ignore case for printableStrings and email RDNs */ if (strncasecmp(t_data.ptr, o_data.ptr, t_data.len) != 0) { @@ -634,65 +614,55 @@ static bool compare_dn(chunk_t t_dn, chunk_t o_dn, int *wc) return finished; } -/** - * Special implementation of identification_t.equals for ID_DER_ASN1_DN. - */ -static bool equals_dn(private_identification_t *this, - private_identification_t *other) +METHOD(identification_t, equals_dn, bool, + private_identification_t *this, identification_t *other) { - return compare_dn(this->encoded, other->encoded, NULL); + return compare_dn(this->encoded, other->get_encoding(other), NULL); } -/** - * Special implementation of identification_t.equals for RFC822 and FQDN. - */ -static bool equals_strcasecmp(private_identification_t *this, - private_identification_t *other) +METHOD(identification_t, equals_strcasecmp, bool, + private_identification_t *this, identification_t *other) { - /* we do some extra sanity checks to check for invalid IDs with a + chunk_t encoded = other->get_encoding(other); + + /* we do some extra sanity checks to check for invalid IDs with a * terminating null in it. */ - if (this->encoded.len == other->encoded.len && + if (this->encoded.len == encoded.len && memchr(this->encoded.ptr, 0, this->encoded.len) == NULL && - memchr(other->encoded.ptr, 0, other->encoded.len) == NULL && - strncasecmp(this->encoded.ptr, other->encoded.ptr, this->encoded.len) == 0) + memchr(encoded.ptr, 0, encoded.len) == NULL && + strncasecmp(this->encoded.ptr, encoded.ptr, this->encoded.len) == 0) { return TRUE; } return FALSE; } -/** - * Default implementation of identification_t.matches. - */ -static id_match_t matches_binary(private_identification_t *this, - private_identification_t *other) +METHOD(identification_t, matches_binary, id_match_t, + private_identification_t *this, identification_t *other) { - if (other->type == ID_ANY) + if (other->get_type(other) == ID_ANY) { return ID_MATCH_ANY; } - if (this->type == other->type && - chunk_equals(this->encoded, other->encoded)) + if (this->type == other->get_type(other) && + chunk_equals(this->encoded, other->get_encoding(other))) { return ID_MATCH_PERFECT; } return ID_MATCH_NONE; } -/** - * Special implementation of identification_t.matches for ID_RFC822_ADDR/ID_FQDN. - * Checks for a wildcard in other-string, and compares it against this-string. - */ -static id_match_t matches_string(private_identification_t *this, - private_identification_t *other) +METHOD(identification_t, matches_string, id_match_t, + private_identification_t *this, identification_t *other) { - u_int len = other->encoded.len; - - if (other->type == ID_ANY) + chunk_t encoded = other->get_encoding(other); + u_int len = encoded.len; + + if (other->get_type(other) == ID_ANY) { return ID_MATCH_ANY; } - if (this->type != other->type) + if (this->type != other->get_type(other)) { return ID_MATCH_NONE; } @@ -707,15 +677,15 @@ static id_match_t matches_string(private_identification_t *this, } /* check for single wildcard at the head of the string */ - if (*other->encoded.ptr == '*') + if (*encoded.ptr == '*') { /* single asterisk matches any string */ if (len-- == 1) { /* not better than ID_ANY */ return ID_MATCH_ANY; } - if (strncasecmp(this->encoded.ptr + this->encoded.len - len, - other->encoded.ptr + 1, len) == 0) + if (strncasecmp(this->encoded.ptr + this->encoded.len - len, + encoded.ptr + 1, len) == 0) { return ID_MATCH_ONE_WILDCARD; } @@ -723,36 +693,29 @@ static id_match_t matches_string(private_identification_t *this, return ID_MATCH_NONE; } -/** - * Special implementation of identification_t.matches for ID_ANY. - * ANY matches only another ANY, but nothing other - */ -static id_match_t matches_any(private_identification_t *this, - private_identification_t *other) +METHOD(identification_t, matches_any, id_match_t, + private_identification_t *this, identification_t *other) { - if (other->type == ID_ANY) + if (other->get_type(other) == ID_ANY) { return ID_MATCH_ANY; } return ID_MATCH_NONE; } -/** - * Special implementation of identification_t.matches for ID_DER_ASN1_DN - */ -static id_match_t matches_dn(private_identification_t *this, - private_identification_t *other) +METHOD(identification_t, matches_dn, id_match_t, + private_identification_t *this, identification_t *other) { int wc; - - if (other->type == ID_ANY) + + if (other->get_type(other) == ID_ANY) { return ID_MATCH_ANY; } - - if (this->type == other->type) + + if (this->type == other->get_type(other)) { - if (compare_dn(this->encoded, other->encoded, &wc)) + if (compare_dn(this->encoded, other->get_encoding(other), &wc)) { wc = min(wc, ID_MATCH_ONE_WILDCARD - ID_MATCH_MAX_WILDCARDS); return ID_MATCH_PERFECT - wc; @@ -770,12 +733,12 @@ int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, private_identification_t *this = *((private_identification_t**)(args[0])); chunk_t proper; char buf[512]; - + if (this == NULL) { return print_in_hook(dst, len, "%*s", spec->width, "(null)"); } - + switch (this->type) { case ID_ANY: @@ -810,7 +773,8 @@ int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, snprintf(buf, sizeof(buf), "(ASN.1 general Name"); break; case ID_KEY_ID: - if (chunk_printable(this->encoded, NULL, '?')) + if (chunk_printable(this->encoded, NULL, '?') && + this->encoded.len != HASH_SIZE_SHA1) { /* fully printable, use ascii version */ snprintf(buf, sizeof(buf), "%.*s", this->encoded.len, this->encoded.ptr); @@ -820,10 +784,8 @@ int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, snprintf(buf, sizeof(buf), "%#B", &this->encoded); } break; - case ID_PUBKEY_INFO_SHA1: - case ID_PUBKEY_SHA1: - case ID_CERT_DER_SHA1: - snprintf(buf, sizeof(buf), "%#B", &this->encoded); + case ID_MYID: + snprintf(buf, sizeof(buf), "%%myid"); break; default: snprintf(buf, sizeof(buf), "(unknown ID type: %d)", this->type); @@ -835,13 +797,12 @@ int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, } return print_in_hook(dst, len, "%*s", spec->width, buf); } -/** - * Implementation of identification_t.clone. - */ -static identification_t *clone_(private_identification_t *this) + +METHOD(identification_t, clone, identification_t*, + private_identification_t *this) { private_identification_t *clone = malloc_thing(private_identification_t); - + memcpy(clone, this, sizeof(private_identification_t)); if (this->encoded.len) { @@ -850,10 +811,8 @@ static identification_t *clone_(private_identification_t *this) return &clone->public; } -/** - * Implementation of identification_t.destroy. - */ -static void destroy(private_identification_t *this) +METHOD(identification_t, destroy, void, + private_identification_t *this) { chunk_free(&this->encoded); free(this); @@ -864,42 +823,43 @@ static void destroy(private_identification_t *this) */ static private_identification_t *identification_create(id_type_t type) { - private_identification_t *this = malloc_thing(private_identification_t); - - this->public.get_encoding = (chunk_t (*) (identification_t*))get_encoding; - this->public.get_type = (id_type_t (*) (identification_t*))get_type; - this->public.create_part_enumerator = (enumerator_t*(*)(identification_t*))create_part_enumerator; - this->public.clone = (identification_t* (*) (identification_t*))clone_; - this->public.destroy = (void (*) (identification_t*))destroy; - + private_identification_t *this; + + INIT(this, + .public = { + .get_encoding = _get_encoding, + .get_type = _get_type, + .create_part_enumerator = _create_part_enumerator, + .clone = _clone, + .destroy = _destroy, + }, + .type = type, + ); + switch (type) { case ID_ANY: - this->public.matches = (id_match_t (*)(identification_t*,identification_t*))matches_any; - this->public.equals = (bool (*) (identification_t*,identification_t*))equals_binary; - this->public.contains_wildcards = (bool (*) (identification_t *this))return_true; + this->public.matches = _matches_any; + this->public.equals = _equals_binary; + this->public.contains_wildcards = return_true; break; case ID_FQDN: case ID_RFC822_ADDR: - this->public.matches = (id_match_t (*)(identification_t*,identification_t*))matches_string; - this->public.equals = (bool (*)(identification_t*,identification_t*))equals_strcasecmp; - this->public.contains_wildcards = (bool (*) (identification_t *this))contains_wildcards_memchr; + this->public.matches = _matches_string; + this->public.equals = _equals_strcasecmp; + this->public.contains_wildcards = _contains_wildcards_memchr; break; case ID_DER_ASN1_DN: - this->public.equals = (bool (*)(identification_t*,identification_t*))equals_dn; - this->public.matches = (id_match_t (*)(identification_t*,identification_t*))matches_dn; - this->public.contains_wildcards = (bool (*) (identification_t *this))contains_wildcards_dn; + this->public.equals = _equals_dn; + this->public.matches = _matches_dn; + this->public.contains_wildcards = _contains_wildcards_dn; break; default: - this->public.equals = (bool (*) (identification_t*,identification_t*))equals_binary; - this->public.matches = (id_match_t (*) (identification_t*,identification_t*))matches_binary; - this->public.contains_wildcards = (bool (*) (identification_t *this))return_false; + this->public.equals = _equals_binary; + this->public.matches = _matches_binary; + this->public.contains_wildcards = return_false; break; } - - this->type = type; - this->encoded = chunk_empty; - return this; } @@ -910,7 +870,7 @@ identification_t *identification_create_from_string(char *string) { private_identification_t *this; chunk_t encoded; - + if (string == NULL) { string = "%any"; @@ -951,7 +911,7 @@ identification_t *identification_create_from_string(char *string) { struct in_addr address; chunk_t chunk = {(void*)&address, sizeof(address)}; - + if (inet_pton(AF_INET, string, &address) > 0) { /* is IPv4 */ this = identification_create(ID_IPV4_ADDR); @@ -968,7 +928,7 @@ identification_t *identification_create_from_string(char *string) { struct in6_addr address; chunk_t chunk = {(void*)&address, sizeof(address)}; - + if (inet_pton(AF_INET6, string, &address) > 0) { /* is IPv6 */ this = identification_create(ID_IPV6_ADDR); @@ -1015,11 +975,23 @@ identification_t *identification_create_from_string(char *string) /* * Described in header. */ +identification_t * identification_create_from_data(chunk_t data) +{ + char buf[data.len + 1]; + + /* use string constructor */ + snprintf(buf, sizeof(buf), "%.*s", data.len, data.ptr); + return identification_create_from_string(buf); +} + +/* + * Described in header. + */ identification_t *identification_create_from_encoding(id_type_t type, chunk_t encoded) { private_identification_t *this = identification_create(type); - + /* apply encoded chunk */ if (type != ID_ANY) { @@ -1028,3 +1000,33 @@ identification_t *identification_create_from_encoding(id_type_t type, return &(this->public); } +/* + * Described in header. + */ +identification_t *identification_create_from_sockaddr(sockaddr_t *sockaddr) +{ + switch (sockaddr->sa_family) + { + case AF_INET: + { + struct in_addr *addr = &(((struct sockaddr_in*)sockaddr)->sin_addr); + + return identification_create_from_encoding(ID_IPV4_ADDR, + chunk_create((u_char*)addr, sizeof(struct in_addr))); + } + case AF_INET6: + { + struct in6_addr *addr = &(((struct sockaddr_in6*)sockaddr)->sin6_addr); + + return identification_create_from_encoding(ID_IPV6_ADDR, + chunk_create((u_char*)addr, sizeof(struct in6_addr))); + } + default: + { + private_identification_t *this = identification_create(ID_ANY); + + return &(this->public); + } + } +} + |