diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index 1c04c97ef..72b1c6a59 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -122,6 +122,151 @@ struct private_identification_t { id_type_t type; }; +/** + * Enumerator over RDNs + */ +typedef struct { + /* implements enumerator interface */ + enumerator_t public; + /* RDNs left to parse */ + chunk_t left; +} 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) +{ + chunk_t rdn; + + /* a RDN is a SET of attribute-values, each is a SEQUENCE ... */ + if (asn1_unwrap(&this->left, &rdn) == ASN1_SET && + asn1_unwrap(&rdn, &rdn) == ASN1_SEQUENCE) + { + /* ... of an OID */ + if (asn1_unwrap(&rdn, oid) == ASN1_OID) + { + /* and a specific string type */ + *type = asn1_unwrap(&rdn, data); + if (*type != ASN1_INVALID) + { + return TRUE; + } + } + } + return FALSE; +} + +/** + * Create an enumerator over all RDNs (oid, string type, data) of a DN + */ +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; + + /* a DN is a sequence of RDNs */ + if (asn1_unwrap(&dn, &e->left) == ASN1_SEQUENCE) + { + return &e->public; + } + return enumerator_create_empty(); +} + +/** + * Part enumerator over RDNs + */ +typedef struct { + /* implements enumerator interface */ + enumerator_t public; + /* inner RDN enumerator */ + 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) +{ + int i, known_oid, strtype; + chunk_t oid, inner_data; + static const struct { + int oid; + id_part_t type; + } oid2part[] = { + {OID_COMMON_NAME, ID_PART_RDN_CN}, + {OID_SURNAME, ID_PART_RDN_S}, + {OID_SERIAL_NUMBER, ID_PART_RDN_SN}, + {OID_COUNTRY, ID_PART_RDN_C}, + {OID_LOCALITY, ID_PART_RDN_L}, + {OID_STATE_OR_PROVINCE, ID_PART_RDN_ST}, + {OID_ORGANIZATION, ID_PART_RDN_O}, + {OID_ORGANIZATION_UNIT, ID_PART_RDN_OU}, + {OID_TITLE, ID_PART_RDN_T}, + {OID_DESCRIPTION, ID_PART_RDN_D}, + {OID_NAME, ID_PART_RDN_N}, + {OID_GIVEN_NAME, ID_PART_RDN_G}, + {OID_INITIALS, ID_PART_RDN_I}, + {OID_UNIQUE_IDENTIFIER, ID_PART_RDN_ID}, + {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); + for (i = 0; i < countof(oid2part); i++) + { + if (oid2part[i].oid == known_oid) + { + *type = oid2part[i].type; + *data = inner_data; + return TRUE; + } + } + } + return FALSE; +} + +/** + * Implementation of rdn_part_enumerator_t.destroy(). + */ +static void rdn_part_enumerator_destroy(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) +{ + 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; + + return &e->public; + } + case ID_RFC822_ADDR: + /* TODO */ + case ID_FQDN: + /* TODO */ + default: + return enumerator_create_empty(); + } +} + static private_identification_t *identification_create(void); /** @@ -917,125 +1062,6 @@ int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, } return print_in_hook(dst, len, "%*s", spec->width, buf); } - -/** - * Enumerator over RDNs - */ -typedef struct { - /* implements enumerator interface */ - enumerator_t public; - /* current RDN */ - chunk_t rdn; - /* current attribute */ - chunk_t attr; - /** have another RDN? */ - bool next; -} rdn_enumerator_t; - -/** - * Implementation of rdn_enumerator_t.enumerate - */ -static bool rdn_enumerate(rdn_enumerator_t *this, - id_part_t *type, chunk_t *data) -{ - chunk_t oid, value; - asn1_t asn1_type; - - while (this->next) - { - if (!get_next_rdn(&this->rdn, &this->attr, &oid, - &value, &asn1_type, &this->next)) - { - return FALSE; - } - switch (asn1_known_oid(oid)) - { - case OID_COMMON_NAME: - *type = ID_PART_RDN_CN; - break; - case OID_SURNAME: - *type = ID_PART_RDN_S; - break; - case OID_SERIAL_NUMBER: - *type = ID_PART_RDN_SN; - break; - case OID_COUNTRY: - *type = ID_PART_RDN_C; - break; - case OID_LOCALITY: - *type = ID_PART_RDN_L; - break; - case OID_STATE_OR_PROVINCE: - *type = ID_PART_RDN_ST; - break; - case OID_ORGANIZATION: - *type = ID_PART_RDN_O; - break; - case OID_ORGANIZATION_UNIT: - *type = ID_PART_RDN_OU; - break; - case OID_TITLE: - *type = ID_PART_RDN_T; - break; - case OID_DESCRIPTION: - *type = ID_PART_RDN_D; - break; - case OID_NAME: - *type = ID_PART_RDN_N; - break; - case OID_GIVEN_NAME: - *type = ID_PART_RDN_G; - break; - case OID_INITIALS: - *type = ID_PART_RDN_I; - break; - case OID_UNIQUE_IDENTIFIER: - *type = ID_PART_RDN_ID; - break; - case OID_EMAIL_ADDRESS: - *type = ID_PART_RDN_E; - break; - case OID_EMPLOYEE_NUMBER: - *type = ID_PART_RDN_EN; - break; - default: - continue; - } - *data = value; - return TRUE; - } - return FALSE; -} - -/** - * Implementation of identification_t.create_part_enumerator - */ -static enumerator_t* create_part_enumerator(private_identification_t *this) -{ - switch (this->type) - { - case ID_DER_ASN1_DN: - { - rdn_enumerator_t *e = malloc_thing(rdn_enumerator_t); - - e->public.enumerate = (void*)rdn_enumerate; - e->public.destroy = (void*)free; - if (init_rdn(this->encoded, &e->rdn, &e->attr, &e->next)) - { - return &e->public; - } - free(e); - /* FALL */ - } - case ID_RFC822_ADDR: - /* TODO */ - case ID_FQDN: - /* TODO */ - default: - return enumerator_create_empty(); - } -} - /** * Implementation of identification_t.clone. */