reworked parsing and matching of subjectAltNames
This commit is contained in:
parent
3c3595adfd
commit
353c7b57c8
|
@ -27,6 +27,8 @@
|
|||
|
||||
#include "x509.h"
|
||||
|
||||
#include <types.h>
|
||||
#include <definitions.h>
|
||||
#include <asn1/oid.h>
|
||||
#include <asn1/asn1.h>
|
||||
#include <asn1/pem.h>
|
||||
|
@ -34,24 +36,31 @@
|
|||
#include <utils/linked_list.h>
|
||||
#include <utils/identification.h>
|
||||
|
||||
#define BUF_LEN 512
|
||||
#define BITS_PER_BYTE 8
|
||||
#define RSA_MIN_OCTETS (1024 / BITS_PER_BYTE)
|
||||
#define RSA_MIN_OCTETS_UGH "RSA modulus too small for security: less than 1024 bits"
|
||||
#define RSA_MAX_OCTETS (8192 / BITS_PER_BYTE)
|
||||
#define RSA_MAX_OCTETS_UGH "RSA modulus too large: more than 8192 bits"
|
||||
|
||||
#define CERT_WARNING_INTERVAL 30 /* days */
|
||||
|
||||
logger_t *logger;
|
||||
|
||||
typedef struct generalName_t generalName_t;
|
||||
|
||||
/**
|
||||
* A generalName, chainable in a list
|
||||
* Different kinds of generalNames
|
||||
*/
|
||||
struct generalName_t {
|
||||
generalName_t *next;
|
||||
generalNames_t kind;
|
||||
chunk_t name;
|
||||
typedef enum generalNames_t generalNames_t;
|
||||
|
||||
enum generalNames_t {
|
||||
GN_OTHER_NAME = 0,
|
||||
GN_RFC822_NAME = 1,
|
||||
GN_DNS_NAME = 2,
|
||||
GN_X400_ADDRESS = 3,
|
||||
GN_DIRECTORY_NAME = 4,
|
||||
GN_EDI_PARTY_NAME = 5,
|
||||
GN_URI = 6,
|
||||
GN_IP_ADDRESS = 7,
|
||||
GN_REGISTERED_ID = 8,
|
||||
};
|
||||
|
||||
typedef struct private_x509_t private_x509_t;
|
||||
|
@ -110,11 +119,6 @@ struct private_x509_t {
|
|||
*/
|
||||
linked_list_t *subjectAltNames;
|
||||
|
||||
/**
|
||||
* List of identification_t's representing issuerAltNames
|
||||
*/
|
||||
linked_list_t *issuerAltNames;
|
||||
|
||||
/**
|
||||
* List of identification_t's representing crlDistributionPoints
|
||||
*/
|
||||
|
@ -153,6 +157,50 @@ struct private_x509_t {
|
|||
chunk_t signature;
|
||||
};
|
||||
|
||||
/**
|
||||
* ASN.1 definition of generalName
|
||||
*/
|
||||
static const asn1Object_t generalNameObjects[] = {
|
||||
{ 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */
|
||||
{ 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT|ASN1_BODY }, /* 2 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */
|
||||
{ 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 4 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
|
||||
{ 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 6 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
|
||||
{ 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT|ASN1_BODY }, /* 8 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
|
||||
{ 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT|ASN1_BODY }, /* 10 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */
|
||||
{ 0, "URI", ASN1_CONTEXT_S_6, ASN1_OPT|ASN1_BODY }, /* 12 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */
|
||||
{ 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT|ASN1_BODY }, /* 14 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */
|
||||
{ 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT|ASN1_BODY }, /* 16 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END } /* 17 */
|
||||
};
|
||||
#define GN_OBJ_OTHER_NAME 0
|
||||
#define GN_OBJ_RFC822_NAME 2
|
||||
#define GN_OBJ_DNS_NAME 4
|
||||
#define GN_OBJ_X400_ADDRESS 6
|
||||
#define GN_OBJ_DIRECTORY_NAME 8
|
||||
#define GN_OBJ_EDI_PARTY_NAME 10
|
||||
#define GN_OBJ_URI 12
|
||||
#define GN_OBJ_IP_ADDRESS 14
|
||||
#define GN_OBJ_REGISTERED_ID 16
|
||||
#define GN_OBJ_ROOF 18
|
||||
|
||||
/**
|
||||
* ASN.1 definition of otherName
|
||||
*/
|
||||
static const asn1Object_t otherNameObjects[] = {
|
||||
{0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */
|
||||
{0, "value", ASN1_CONTEXT_C_0, ASN1_BODY } /* 1 */
|
||||
};
|
||||
#define ON_OBJ_ID_TYPE 0
|
||||
#define ON_OBJ_VALUE 1
|
||||
#define ON_OBJ_ROOF 2
|
||||
/**
|
||||
* ASN.1 definition of a basicConstraints extension
|
||||
*/
|
||||
|
@ -330,56 +378,6 @@ static bool equals(private_x509_t *this, private_x509_t *other)
|
|||
return chunk_equals(this->signature, other->signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* encode a linked list of subjectAltNames
|
||||
*/
|
||||
chunk_t build_subjectAltNames(generalName_t *subjectAltNames)
|
||||
{
|
||||
u_char *pos;
|
||||
chunk_t names;
|
||||
size_t len = 0;
|
||||
generalName_t *gn = subjectAltNames;
|
||||
|
||||
/* compute the total size of the ASN.1 attributes object */
|
||||
while (gn != NULL)
|
||||
{
|
||||
len += gn->name.len;
|
||||
gn = gn->next;
|
||||
}
|
||||
|
||||
pos = build_asn1_object(&names, ASN1_SEQUENCE, len);
|
||||
|
||||
gn = subjectAltNames;
|
||||
while (gn != NULL)
|
||||
{
|
||||
memcpy(pos, gn->name.ptr, gn->name.len);
|
||||
pos += gn->name.len;
|
||||
gn = gn->next;
|
||||
}
|
||||
|
||||
return asn1_wrap(ASN1_SEQUENCE, "cm",
|
||||
ASN1_subjectAltName_oid,
|
||||
asn1_wrap(ASN1_OCTET_STRING, "m", names)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* free the dynamic memory used to store generalNames
|
||||
*/
|
||||
void free_generalNames(generalName_t* gn, bool free_name)
|
||||
{
|
||||
while (gn != NULL)
|
||||
{
|
||||
generalName_t *gn_top = gn;
|
||||
if (free_name)
|
||||
{
|
||||
free(gn->name.ptr);
|
||||
}
|
||||
gn = gn->next;
|
||||
free(gn_top);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* extracts the basicConstraints extension
|
||||
*/
|
||||
|
@ -402,13 +400,113 @@ static bool parse_basicConstraints(chunk_t blob, int level0)
|
|||
if (objectID == BASIC_CONSTRAINTS_CA)
|
||||
{
|
||||
isCA = object.len && *object.ptr;
|
||||
logger->log(logger, RAW|LEVEL1, " %s", isCA ? "TRUE" : "FALSE");
|
||||
logger->log(logger, CONTROL|LEVEL1, " %s", isCA ? "TRUE" : "FALSE");
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
return isCA;
|
||||
}
|
||||
|
||||
/*
|
||||
* extracts an otherName
|
||||
*/
|
||||
static bool
|
||||
parse_otherName(chunk_t blob, int level0)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
chunk_t object;
|
||||
int objectID = 0;
|
||||
u_int level;
|
||||
int oid = OID_UNKNOWN;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE);
|
||||
|
||||
while (objectID < ON_OBJ_ROOF)
|
||||
{
|
||||
if (!extract_object(otherNameObjects, &objectID, &object, &level, &ctx))
|
||||
return FALSE;
|
||||
|
||||
switch (objectID)
|
||||
{
|
||||
case ON_OBJ_ID_TYPE:
|
||||
oid = known_oid(object);
|
||||
break;
|
||||
case ON_OBJ_VALUE:
|
||||
if (oid == OID_XMPP_ADDR)
|
||||
{
|
||||
if (!parse_asn1_simple_object(&object, ASN1_UTF8STRING, level + 1, "xmppAddr"))
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* extracts a generalName
|
||||
*/
|
||||
static identification_t *parse_generalName(chunk_t blob, int level0)
|
||||
{
|
||||
u_char buf[BUF_LEN];
|
||||
asn1_ctx_t ctx;
|
||||
chunk_t object;
|
||||
int objectID = 0;
|
||||
u_int level;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE);
|
||||
|
||||
while (objectID < GN_OBJ_ROOF)
|
||||
{
|
||||
id_type_t id_type = ID_ANY;
|
||||
|
||||
if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx))
|
||||
return NULL;
|
||||
|
||||
switch (objectID)
|
||||
{
|
||||
case GN_OBJ_RFC822_NAME:
|
||||
id_type = ID_RFC822_ADDR;
|
||||
break;
|
||||
case GN_OBJ_DNS_NAME:
|
||||
id_type = ID_FQDN;
|
||||
break;
|
||||
case GN_OBJ_URI:
|
||||
id_type = ID_DER_ASN1_GN_URI;
|
||||
break;
|
||||
case GN_OBJ_DIRECTORY_NAME:
|
||||
id_type = ID_DER_ASN1_DN;
|
||||
break;
|
||||
case GN_OBJ_IP_ADDRESS:
|
||||
id_type = ID_IPV4_ADDR;
|
||||
break;
|
||||
case GN_OBJ_OTHER_NAME:
|
||||
if (!parse_otherName(object, level + 1))
|
||||
return NULL;
|
||||
break;
|
||||
case GN_OBJ_X400_ADDRESS:
|
||||
case GN_OBJ_EDI_PARTY_NAME:
|
||||
case GN_OBJ_REGISTERED_ID:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (id_type != ID_ANY)
|
||||
{
|
||||
identification_t *gn = identification_create_from_encoding(id_type, object);
|
||||
logger->log(logger, CONTROL|LEVEL1, " '%s'", gn->get_string(gn));
|
||||
return gn;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* extracts one or several GNs and puts them into a chained list
|
||||
*/
|
||||
|
@ -428,7 +526,10 @@ static void parse_generalNames(chunk_t blob, int level0, bool implicit, linked_l
|
|||
|
||||
if (objectID == GENERAL_NAMES_GN)
|
||||
{
|
||||
list->insert_last(list, identification_create_from_encoding(ID_DER_ASN1_GN, object));
|
||||
identification_t *gn = parse_generalName(object, level+1);
|
||||
|
||||
if (gn != NULL)
|
||||
list->insert_last(list, gn);
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
|
@ -547,10 +648,8 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0, chunk_t *accessL
|
|||
if (*object.ptr == ASN1_CONTEXT_S_6)
|
||||
{
|
||||
if (asn1_length(&object) == ASN1_INVALID_LENGTH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
logger->log(logger, RAW|LEVEL1, " '%.*s'",(int)object.len, object.ptr);
|
||||
logger->log(logger, CONTROL|LEVEL1, " '%.*s'",(int)object.len, object.ptr);
|
||||
/* only HTTP(S) URIs accepted */
|
||||
if (strncasecmp(object.ptr, "http", 4) == 0)
|
||||
{
|
||||
|
@ -659,7 +758,7 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert)
|
|||
break;
|
||||
case X509_OBJ_VERSION:
|
||||
cert->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
|
||||
logger->log(logger, RAW|LEVEL1, " v%d", cert->version);
|
||||
logger->log(logger, CONTROL|LEVEL1, " v%d", cert->version);
|
||||
break;
|
||||
case X509_OBJ_SERIAL_NUMBER:
|
||||
cert->serialNumber = object;
|
||||
|
@ -669,6 +768,7 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert)
|
|||
break;
|
||||
case X509_OBJ_ISSUER:
|
||||
cert->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
|
||||
logger->log(logger, CONTROL|LEVEL1, " '%s'", cert->issuer->get_string(cert->issuer));
|
||||
break;
|
||||
case X509_OBJ_NOT_BEFORE:
|
||||
cert->notBefore = parse_time(object, level);
|
||||
|
@ -678,6 +778,7 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert)
|
|||
break;
|
||||
case X509_OBJ_SUBJECT:
|
||||
cert->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object);
|
||||
logger->log(logger, CONTROL|LEVEL1, " '%s'", cert->subject->get_string(cert->subject));
|
||||
break;
|
||||
case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
|
||||
if (parse_algorithmIdentifier(object, level, NULL) != OID_RSA_ENCRYPTION)
|
||||
|
@ -737,9 +838,7 @@ bool parse_x509cert(chunk_t blob, u_int level0, private_x509_t *cert)
|
|||
case OID_NS_CA_POLICY_URL:
|
||||
case OID_NS_COMMENT:
|
||||
if (!parse_asn1_simple_object(&object, ASN1_IA5STRING , level, oid_names[extn_oid].name))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -789,12 +888,35 @@ err_t check_validity(const private_x509_t *cert, time_t *until)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements x509_t.equals_subjectAltName
|
||||
*/
|
||||
static bool equals_subjectAltName(private_x509_t *this, identification_t *id)
|
||||
{
|
||||
bool found = FALSE;
|
||||
iterator_t *iterator = this->subjectAltNames->create_iterator(this->subjectAltNames, TRUE);
|
||||
|
||||
while (iterator->has_next(iterator))
|
||||
{
|
||||
identification_t *subjectAltName;
|
||||
|
||||
iterator->current(iterator, (void**)&subjectAltName);
|
||||
if (id->equals(id, subjectAltName))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements x509_t.get_public_key
|
||||
*/
|
||||
static rsa_public_key_t *get_public_key(private_x509_t *this)
|
||||
{
|
||||
return this->public_key->clone(this->public_key);;
|
||||
return this->public_key->clone(this->public_key);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -824,32 +946,69 @@ static void destroy(private_x509_t *this)
|
|||
id->destroy(id);
|
||||
}
|
||||
this->subjectAltNames->destroy(this->subjectAltNames);
|
||||
while (this->issuerAltNames->remove_last(this->issuerAltNames, (void**)&id) == SUCCESS)
|
||||
{
|
||||
id->destroy(id);
|
||||
}
|
||||
this->issuerAltNames->destroy(this->issuerAltNames);
|
||||
|
||||
while (this->crlDistributionPoints->remove_last(this->crlDistributionPoints, (void**)&id) == SUCCESS)
|
||||
{
|
||||
id->destroy(id);
|
||||
}
|
||||
this->crlDistributionPoints->destroy(this->crlDistributionPoints);
|
||||
|
||||
if (this->issuer)
|
||||
{
|
||||
this->issuer->destroy(this->issuer);
|
||||
}
|
||||
|
||||
if (this->subject)
|
||||
{
|
||||
this->subject->destroy(this->subject);
|
||||
}
|
||||
|
||||
if (this->public_key)
|
||||
{
|
||||
this->public_key->destroy(this->public_key);
|
||||
}
|
||||
|
||||
free(this->certificate.ptr);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/** checks if the expiration date has been reached and
|
||||
* warns during the warning_interval of the imminent
|
||||
* expiry. strict=TRUE declares a fatal error,
|
||||
* strict=FALSE issues a warning upon expiry.
|
||||
*/
|
||||
char* check_expiry(time_t expiration_date, int warning_interval, bool strict)
|
||||
{
|
||||
time_t now;
|
||||
int time_left;
|
||||
|
||||
if (expiration_date == UNDEFINED_TIME)
|
||||
return "ok (expires never)";
|
||||
|
||||
time_left = (expiration_date - time(NULL));
|
||||
if (time_left < 0)
|
||||
return strict? "fatal (expired)" : "warning (expired)";
|
||||
|
||||
{
|
||||
static char buf[35]; /* temporary storage */
|
||||
const char* unit = "second";
|
||||
|
||||
if (time_left > 86400*warning_interval)
|
||||
return "ok";
|
||||
|
||||
if (time_left > 172800)
|
||||
{
|
||||
time_left /= 86400;
|
||||
unit = "day";
|
||||
}
|
||||
else if (time_left > 7200)
|
||||
{
|
||||
time_left /= 3600;
|
||||
unit = "hour";
|
||||
}
|
||||
else if (time_left > 120)
|
||||
{
|
||||
time_left /= 60;
|
||||
unit = "minute";
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "warning (expires in %d %s%s)", time_left, unit, (time_left == 1)?"":"s");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* log certificate
|
||||
*/
|
||||
|
@ -861,6 +1020,10 @@ static void log_certificate(private_x509_t *this, logger_t *logger, bool utc)
|
|||
rsa_public_key_t *rsa_key = this->public_key;
|
||||
|
||||
char buf[BUF_LEN];
|
||||
time_t now;
|
||||
|
||||
/* determine the current time */
|
||||
time(&now);
|
||||
|
||||
timetoa(buf, BUF_LEN, &this->installed, utc);
|
||||
logger->log(logger, CONTROL, "%s", buf);
|
||||
|
@ -869,9 +1032,11 @@ static void log_certificate(private_x509_t *this, logger_t *logger, bool utc)
|
|||
chunk_to_hex(buf, BUF_LEN, this->serialNumber);
|
||||
logger->log(logger, CONTROL, " serial: %s", buf);
|
||||
timetoa(buf, BUF_LEN, &this->notBefore, utc);
|
||||
logger->log(logger, CONTROL, " validity: not before %s", buf);
|
||||
logger->log(logger, CONTROL, " validity: not before %s %s", buf,
|
||||
(this->notBefore < now)? "ok":"fatal (not valid yet)");
|
||||
timetoa(buf, BUF_LEN, &this->notAfter, utc);
|
||||
logger->log(logger, CONTROL, " not after %s", buf);
|
||||
logger->log(logger, CONTROL, " not after %s %s", buf,
|
||||
check_expiry(this->notAfter, CERT_WARNING_INTERVAL, TRUE));
|
||||
logger->log(logger, CONTROL, " pubkey: RSA %d bits", BITS_PER_BYTE * rsa_key->get_keysize(rsa_key));
|
||||
if (this->subjectKeyID.ptr != NULL)
|
||||
{
|
||||
|
@ -899,6 +1064,7 @@ x509_t *x509_create_from_chunk(chunk_t chunk)
|
|||
|
||||
/* public functions */
|
||||
this->public.equals = (bool (*) (x509_t*,x509_t*))equals;
|
||||
this->public.equals_subjectAltName = (bool (*) (x509_t*,identification_t*))equals_subjectAltName;
|
||||
this->public.destroy = (void (*) (x509_t*))destroy;
|
||||
this->public.get_public_key = (rsa_public_key_t* (*) (x509_t*))get_public_key;
|
||||
this->public.get_subject = (identification_t* (*) (x509_t*))get_subject;
|
||||
|
@ -911,7 +1077,6 @@ x509_t *x509_create_from_chunk(chunk_t chunk)
|
|||
this->subject = NULL;
|
||||
this->issuer = NULL;
|
||||
this->subjectAltNames = linked_list_create();
|
||||
this->issuerAltNames = linked_list_create();
|
||||
this->crlDistributionPoints = linked_list_create();
|
||||
this->subjectKeyID = CHUNK_INITIALIZER;
|
||||
this->authKeyID = CHUNK_INITIALIZER;
|
||||
|
@ -920,8 +1085,7 @@ x509_t *x509_create_from_chunk(chunk_t chunk)
|
|||
/* we do not use a per-instance logger right now, since its not always accessible */
|
||||
logger = logger_manager->get_logger(logger_manager, ASN1);
|
||||
|
||||
if (!is_asn1(chunk) ||
|
||||
!parse_x509cert(chunk, 0, this))
|
||||
if (!is_asn1(chunk) || !parse_x509cert(chunk, 0, this))
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
|
@ -950,9 +1114,8 @@ x509_t *x509_create_from_file(const char *filename)
|
|||
return NULL;
|
||||
|
||||
cert = x509_create_from_chunk(chunk);
|
||||
|
||||
if (cert == NULL)
|
||||
{
|
||||
free(chunk.ptr);
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
|
|
|
@ -106,6 +106,15 @@ struct x509_t {
|
|||
*/
|
||||
bool (*equals) (x509_t *this, x509_t *that);
|
||||
|
||||
/**
|
||||
* @brief Checks if the certificate contains a subjectAltName equal to id.
|
||||
*
|
||||
* @param this certificate being examined
|
||||
* @param id id which is being compared to the subjectAltNames
|
||||
* @return TRUE if a match is found
|
||||
*/
|
||||
bool (*equals_subjectAltName) (x509_t *this, identification_t *id);
|
||||
|
||||
/**
|
||||
* @brief Destroys the certificate.
|
||||
*
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "definitions.h"
|
||||
#include "identification.h"
|
||||
|
||||
#include <asn1/asn1.h>
|
||||
|
@ -47,21 +48,17 @@ mapping_t id_type_m[] = {
|
|||
{MAPPING_END, NULL}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* X.501 acronyms for well known object identifiers (OIDs)
|
||||
*/
|
||||
static u_char oid_ND[] = {
|
||||
0x02, 0x82, 0x06, 0x01,
|
||||
0x0A, 0x07, 0x14
|
||||
0x02, 0x82, 0x06, 0x01, 0x0A, 0x07, 0x14
|
||||
};
|
||||
static u_char oid_UID[] = {
|
||||
0x09, 0x92, 0x26, 0x89, 0x93,
|
||||
0xF2, 0x2C, 0x64, 0x01, 0x01
|
||||
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
|
||||
0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19
|
||||
};
|
||||
static u_char oid_CN[] = {
|
||||
0x55, 0x04, 0x03
|
||||
|
@ -106,20 +103,16 @@ static u_char oid_ID[] = {
|
|||
0x55, 0x04, 0x2D
|
||||
};
|
||||
static u_char oid_EN[] = {
|
||||
0x60, 0x86, 0x48, 0x01, 0x86,
|
||||
0xF8, 0x42, 0x03, 0x01, 0x03
|
||||
0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x42, 0x03, 0x01, 0x03
|
||||
};
|
||||
static u_char oid_E[] = {
|
||||
0x2A, 0x86, 0x48, 0x86, 0xF7,
|
||||
0x0D, 0x01, 0x09, 0x01
|
||||
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01
|
||||
};
|
||||
static u_char oid_UN[] = {
|
||||
0x2A, 0x86, 0x48, 0x86, 0xF7,
|
||||
0x0D, 0x01, 0x09, 0x02
|
||||
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
|
||||
0x2B, 0x06, 0x01, 0x04, 0x01, 0x89, 0x31, 0x01, 0x01, 0x02, 0x02, 0x4B
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -162,49 +155,10 @@ static const x501rdn_t x501rdns[] = {
|
|||
#define X501_RDN_ROOF 26
|
||||
|
||||
/**
|
||||
* ASN.1 definition of generalName
|
||||
* maximum number of RDNs in atodn()
|
||||
*/
|
||||
static const asn1Object_t generalNameObjects[] = {
|
||||
{ 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */
|
||||
{ 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT|ASN1_BODY }, /* 2 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */
|
||||
{ 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 4 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
|
||||
{ 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 6 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
|
||||
{ 0, "directoryName", ASN1_CONTEXT_C_4, ASN1_OPT|ASN1_BODY }, /* 8 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
|
||||
{ 0, "ediPartyName", ASN1_CONTEXT_C_5, ASN1_OPT|ASN1_BODY }, /* 10 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 11 */
|
||||
{ 0, "URI", ASN1_CONTEXT_S_6, ASN1_OPT|ASN1_BODY }, /* 12 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 13 */
|
||||
{ 0, "ipAddress", ASN1_CONTEXT_S_7, ASN1_OPT|ASN1_BODY }, /* 14 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END }, /* 15 */
|
||||
{ 0, "registeredID", ASN1_CONTEXT_S_8, ASN1_OPT|ASN1_BODY }, /* 16 */
|
||||
{ 0, "end choice", ASN1_EOC, ASN1_END } /* 17 */
|
||||
};
|
||||
#define GN_OBJ_OTHER_NAME 0
|
||||
#define GN_OBJ_RFC822_NAME 2
|
||||
#define GN_OBJ_DNS_NAME 4
|
||||
#define GN_OBJ_X400_ADDRESS 6
|
||||
#define GN_OBJ_DIRECTORY_NAME 8
|
||||
#define GN_OBJ_EDI_PARTY_NAME 10
|
||||
#define GN_OBJ_URI 12
|
||||
#define GN_OBJ_IP_ADDRESS 14
|
||||
#define GN_OBJ_REGISTERED_ID 16
|
||||
#define GN_OBJ_ROOF 18
|
||||
#define RDN_MAX 20
|
||||
|
||||
/**
|
||||
* ASN.1 definition of otherName
|
||||
*/
|
||||
static const asn1Object_t otherNameObjects[] = {
|
||||
{0, "type-id", ASN1_OID, ASN1_BODY }, /* 0 */
|
||||
{0, "value", ASN1_CONTEXT_C_0, ASN1_BODY } /* 1 */
|
||||
};
|
||||
#define ON_OBJ_ID_TYPE 0
|
||||
#define ON_OBJ_VALUE 1
|
||||
#define ON_OBJ_ROOF 2
|
||||
|
||||
typedef struct private_identification_t private_identification_t;
|
||||
|
||||
|
@ -235,7 +189,6 @@ struct private_identification_t {
|
|||
|
||||
static private_identification_t *identification_create(void);
|
||||
|
||||
|
||||
/**
|
||||
* updates a chunk (!????)
|
||||
* TODO: We should reconsider this stuff, its not really clear
|
||||
|
@ -253,7 +206,7 @@ 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++)
|
||||
for (i = 0; i < bin.len; i++)
|
||||
{
|
||||
update_chunk(str, snprintf(str->ptr,str->len,"%02X",*bin.ptr++));
|
||||
}
|
||||
|
@ -396,18 +349,14 @@ static status_t dntoa(chunk_t dn, chunk_t *str)
|
|||
status_t status = init_rdn(dn, &rdn, &attribute, &next);
|
||||
|
||||
if (status != SUCCESS)
|
||||
{/* a parsing error has occured */
|
||||
return status;
|
||||
}
|
||||
|
||||
while (next)
|
||||
{
|
||||
status = get_next_rdn(&rdn, &attribute, &oid, &value, &type, &next);
|
||||
|
||||
if (status != SUCCESS)
|
||||
{/* a parsing error has occured */
|
||||
return status;
|
||||
}
|
||||
|
||||
if (first)
|
||||
{ /* first OID/value pair */
|
||||
|
@ -447,18 +396,15 @@ static bool same_dn(chunk_t a, chunk_t b)
|
|||
|
||||
/* same lengths for the DNs */
|
||||
if (a.len != b.len)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* try a binary comparison first */
|
||||
if (memcmp(a.ptr, b.ptr, b.len) == 0)
|
||||
{
|
||||
if (memeq(a.ptr, b.ptr, b.len))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* initialize DN parsing */
|
||||
if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS ||
|
||||
init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS)
|
||||
if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS
|
||||
|| init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -467,36 +413,31 @@ static bool same_dn(chunk_t a, chunk_t b)
|
|||
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) != SUCCESS ||
|
||||
get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != SUCCESS)
|
||||
if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != SUCCESS
|
||||
|| get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != SUCCESS)
|
||||
{
|
||||
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 && known_oid(oid_a) == OID_PKCS9_EMAIL)))
|
||||
if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING
|
||||
|| (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL)))
|
||||
{
|
||||
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 */
|
||||
|
@ -524,25 +465,25 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards)
|
|||
*wildcards = 0;
|
||||
|
||||
/* initialize DN parsing */
|
||||
if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS ||
|
||||
init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS)
|
||||
if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS
|
||||
|| init_rdn(b, &rdn_b, &attribute_b, &next_b) != SUCCESS)
|
||||
{
|
||||
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) != SUCCESS ||
|
||||
get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != SUCCESS)
|
||||
if (get_next_rdn(&rdn_a, &attribute_a, &oid_a, &value_a, &type_a, &next_a) != SUCCESS
|
||||
|| get_next_rdn(&rdn_b, &attribute_b, &oid_b, &value_b, &type_b, &next_b) != SUCCESS)
|
||||
{
|
||||
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 == '*')
|
||||
{
|
||||
|
@ -551,24 +492,19 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards)
|
|||
}
|
||||
/* 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 && known_oid(oid_a) == OID_PKCS9_EMAIL)))
|
||||
if (type_a == type_b && (type_a == ASN1_PRINTABLESTRING
|
||||
|| (type_a == ASN1_IA5STRING && known_oid(oid_a) == OID_PKCS9_EMAIL)))
|
||||
{
|
||||
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 */
|
||||
|
@ -580,59 +516,6 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* get string representation of a general name
|
||||
* TODO: Add support for gn types
|
||||
*/
|
||||
static char *gntoa(chunk_t blob)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
chunk_t object;
|
||||
int objectID = 0;
|
||||
u_int level;
|
||||
char buf[128];
|
||||
|
||||
asn1_init(&ctx, blob, 0, FALSE);
|
||||
|
||||
while (objectID < GN_OBJ_ROOF)
|
||||
{
|
||||
if (!extract_object(generalNameObjects, &objectID, &object, &level, &ctx))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
switch (objectID)
|
||||
{
|
||||
case GN_OBJ_RFC822_NAME:
|
||||
case GN_OBJ_DNS_NAME:
|
||||
case GN_OBJ_URI:
|
||||
snprintf(buf, sizeof(buf), "%.*s", object.len, object.ptr);
|
||||
return strdup(buf);
|
||||
case GN_OBJ_IP_ADDRESS:
|
||||
if (object.len == 4 &&
|
||||
inet_ntop(AF_INET, object.ptr, buf, sizeof(buf)))
|
||||
{
|
||||
return strdup(buf);
|
||||
}
|
||||
return NULL;
|
||||
break;
|
||||
case GN_OBJ_OTHER_NAME:
|
||||
return strdup("(other name)");
|
||||
case GN_OBJ_X400_ADDRESS:
|
||||
return strdup("(X400 Address)");
|
||||
case GN_OBJ_EDI_PARTY_NAME:
|
||||
return strdup("(EDI party name)");
|
||||
case GN_OBJ_REGISTERED_ID:
|
||||
return strdup("(registered ID)");
|
||||
case GN_OBJ_DIRECTORY_NAME:
|
||||
return strdup("(directory name)");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an LDAP-style human-readable ASCII-encoded
|
||||
* ASN.1 distinguished name into binary DER-encoded format
|
||||
|
@ -648,13 +531,13 @@ static status_t atodn(char *src, chunk_t *dn)
|
|||
UNKNOWN_OID = 4
|
||||
} state_t;
|
||||
|
||||
char *wrap_mode;
|
||||
chunk_t oid = CHUNK_INITIALIZER;
|
||||
chunk_t name = CHUNK_INITIALIZER;
|
||||
chunk_t names[25]; /* max to 25 rdns */
|
||||
int name_count = 0;
|
||||
chunk_t rdns[RDN_MAX];
|
||||
int rdn_count = 0;
|
||||
int dn_len = 0;
|
||||
int whitespace = 0;
|
||||
int pos = 0;
|
||||
int i;
|
||||
asn1_t rdn_type;
|
||||
state_t state = SEARCH_OID;
|
||||
status_t status = SUCCESS;
|
||||
|
@ -678,15 +561,15 @@ static status_t atodn(char *src, chunk_t *dn)
|
|||
}
|
||||
else
|
||||
{
|
||||
for (pos = 0; pos < X501_RDN_ROOF; pos++)
|
||||
for (i = 0; i < X501_RDN_ROOF; i++)
|
||||
{
|
||||
if (strlen(x501rdns[pos].name) == oid.len &&
|
||||
strncasecmp(x501rdns[pos].name, oid.ptr, oid.len) == 0)
|
||||
if (strlen(x501rdns[i].name) == oid.len
|
||||
&& strncasecmp(x501rdns[i].name, oid.ptr, oid.len) == 0)
|
||||
{
|
||||
break; /* found a valid OID */
|
||||
}
|
||||
}
|
||||
if (pos == X501_RDN_ROOF)
|
||||
if (i == X501_RDN_ROOF)
|
||||
{
|
||||
status = NOT_SUPPORTED;
|
||||
state = UNKNOWN_OID;
|
||||
|
@ -711,29 +594,26 @@ static status_t atodn(char *src, chunk_t *dn)
|
|||
{
|
||||
name.len++;
|
||||
if (*src == ' ')
|
||||
{
|
||||
whitespace++;
|
||||
}
|
||||
else
|
||||
{
|
||||
whitespace = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name.len -= whitespace;
|
||||
rdn_type = (x501rdns[pos].type == ASN1_PRINTABLESTRING
|
||||
&& !is_printablestring(name))? ASN1_T61STRING : x501rdns[pos].type;
|
||||
rdn_type = (x501rdns[i].type == ASN1_PRINTABLESTRING
|
||||
&& !is_printablestring(name))? ASN1_T61STRING : x501rdns[i].type;
|
||||
|
||||
if (name_count < 25)
|
||||
if (rdn_count < RDN_MAX)
|
||||
{
|
||||
names[name_count++] =
|
||||
rdns[rdn_count] =
|
||||
asn1_wrap(ASN1_SET, "m",
|
||||
asn1_wrap(ASN1_SEQUENCE, "mm",
|
||||
asn1_wrap(ASN1_OID, "c", x501rdns[pos].oid),
|
||||
asn1_wrap(rdn_type, "c", name)
|
||||
)
|
||||
);
|
||||
asn1_wrap(ASN1_SEQUENCE, "mm",
|
||||
asn1_wrap(ASN1_OID, "c", x501rdns[i].oid),
|
||||
asn1_wrap(rdn_type, "c", name)
|
||||
)
|
||||
);
|
||||
dn_len += rdns[rdn_count++].len;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -749,17 +629,19 @@ static status_t atodn(char *src, chunk_t *dn)
|
|||
}
|
||||
} while (*src++ != '\0');
|
||||
|
||||
|
||||
/* build the distinguished name sequence */
|
||||
wrap_mode = alloca(26);
|
||||
memset(wrap_mode, 0, 26);
|
||||
memset(wrap_mode, 'm', name_count);
|
||||
*dn = asn1_wrap(ASN1_SEQUENCE, wrap_mode,
|
||||
names[0], names[1], names[2], names[3], names[4],
|
||||
names[5], names[6], names[7], names[8], names[9],
|
||||
names[10], names[11], names[12], names[13], names[14],
|
||||
names[15], names[16], names[17], names[18], names[19],
|
||||
names[20], names[21], names[22], names[23], names[24]);
|
||||
{
|
||||
int i;
|
||||
u_char *pos = build_asn1_object(dn, ASN1_SEQUENCE, dn_len);
|
||||
|
||||
for (i = 0; i < rdn_count; i++)
|
||||
{
|
||||
memcpy(pos, rdns[i].ptr, rdns[i].len);
|
||||
pos += rdns[i].len;
|
||||
free(rdns[i].ptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
free(dn->ptr);
|
||||
|
@ -797,29 +679,16 @@ static char *get_string(private_identification_t *this)
|
|||
*/
|
||||
static bool contains_wildcards(private_identification_t *this)
|
||||
{
|
||||
if (this->type == ID_ANY ||
|
||||
memchr(this->encoded.ptr, '*', this->encoded.len) != NULL)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
return this->type == ID_ANY || memchr(this->encoded.ptr, '*', this->encoded.len) != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation of identification_t.equals and identification_t.belongs_to.
|
||||
* compares encoded chunk for equality.
|
||||
*/
|
||||
static bool equals_binary(private_identification_t *this,private_identification_t *other)
|
||||
static bool equals_binary(private_identification_t *this, private_identification_t *other)
|
||||
{
|
||||
if (this->type == other->type)
|
||||
{
|
||||
if (this->encoded.len == other->encoded.len &&
|
||||
memcmp(this->encoded.ptr, other->encoded.ptr, this->encoded.len) == 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
return this->type == other->type && chunk_equals(this->encoded, other->encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -882,11 +751,7 @@ static bool belongs_to_wc_string(private_identification_t *this, private_identif
|
|||
*/
|
||||
static bool belongs_to_any(private_identification_t *this, private_identification_t *other)
|
||||
{
|
||||
if (other->type == ID_ANY)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
return other->type == ID_ANY;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -968,9 +833,8 @@ identification_t *identification_create_from_string(char *string)
|
|||
{
|
||||
/* we interpret this as an ASCII X.501 ID_DER_ASN1_DN.
|
||||
* convert from LDAP style or openssl x509 -subject style to ASN.1 DN
|
||||
* discard optional @ character in front of DN
|
||||
*/
|
||||
if (atodn((*string == '@') ? string + 1 : string, &this->encoded) != SUCCESS)
|
||||
if (atodn(string, &this->encoded) != SUCCESS)
|
||||
{
|
||||
free(this);
|
||||
return NULL;
|
||||
|
@ -983,11 +847,11 @@ identification_t *identification_create_from_string(char *string)
|
|||
}
|
||||
else if (strchr(string, '@') == NULL)
|
||||
{
|
||||
if (strcmp(string, "%any") == 0 ||
|
||||
strcmp(string, "0.0.0.0") == 0 ||
|
||||
strcmp(string, "*") == 0 ||
|
||||
strcmp(string, "::") == 0||
|
||||
strcmp(string, "0::0") == 0)
|
||||
if (streq(string, "%any")
|
||||
|| streq(string, "0.0.0.0")
|
||||
|| streq(string, "*")
|
||||
|| streq(string, "::")
|
||||
|| streq(string, "0::0"))
|
||||
{
|
||||
/* any ID will be accepted */
|
||||
this->type = ID_ANY;
|
||||
|
@ -997,8 +861,6 @@ identification_t *identification_create_from_string(char *string)
|
|||
}
|
||||
else
|
||||
{
|
||||
/* TODO: Pluto resolve domainnames without '@' to IPv4/6 address. Is this really needed? */
|
||||
|
||||
if (strchr(string, ':') == NULL)
|
||||
{
|
||||
/* try IPv4 */
|
||||
|
@ -1039,14 +901,15 @@ identification_t *identification_create_from_string(char *string)
|
|||
{
|
||||
if (*(string + 1) == '#')
|
||||
{
|
||||
/* TODO: Pluto handles '#' as hex encoded ASN1/KEY ID. Do we need this, too? */
|
||||
/* TODO: Pluto handles '#' as hex encoded ASN1/KEY ID. Do we need this, too?
|
||||
Yes, key IDs are needed */
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->type = ID_FQDN;
|
||||
this->string = strdup(string + 1); /* discard @ */
|
||||
this->string = strdup(string);
|
||||
this->encoded.ptr = strdup(string + 1);
|
||||
this->encoded.len = strlen(string + 1);
|
||||
this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_wc_string;
|
||||
|
@ -1070,10 +933,10 @@ identification_t *identification_create_from_string(char *string)
|
|||
*/
|
||||
identification_t *identification_create_from_encoding(id_type_t type, chunk_t encoded)
|
||||
{
|
||||
private_identification_t *this = identification_create();
|
||||
char buf[256];
|
||||
chunk_t buf_chunk = chunk_from_buf(buf);
|
||||
char *pos;
|
||||
char buf[BUF_LEN];
|
||||
chunk_t buf_chunk = chunk_from_buf(buf);
|
||||
private_identification_t *this = identification_create();
|
||||
|
||||
this->type = type;
|
||||
switch (type)
|
||||
|
@ -1123,10 +986,14 @@ identification_t *identification_create_from_encoding(id_type_t type, chunk_t en
|
|||
this->public.belongs_to = (bool (*) (identification_t*,identification_t*))belongs_to_dn;
|
||||
break;
|
||||
case ID_DER_ASN1_GN:
|
||||
this->string = gntoa(encoded);
|
||||
this->string = strdup("ASN.1 coded generalName");
|
||||
break;
|
||||
case ID_KEY_ID:
|
||||
this->string = strdup("(unparsed KEY_ID)");
|
||||
this->string = strdup("(KEY_ID)");
|
||||
break;
|
||||
case ID_DER_ASN1_GN_URI:
|
||||
snprintf(buf, sizeof(buf), "%.*s", encoded.len, encoded.ptr);
|
||||
this->string = strdup(buf);
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, sizeof(buf), "(invalid ID type: %d)", type);
|
||||
|
|
|
@ -36,6 +36,11 @@ typedef enum id_type_t id_type_t;
|
|||
*/
|
||||
enum id_type_t {
|
||||
|
||||
/**
|
||||
* private type which matches any other id.
|
||||
*/
|
||||
ID_ANY = 0,
|
||||
|
||||
/**
|
||||
* ID data is a single four (4) octet IPv4 address.
|
||||
*/
|
||||
|
@ -78,11 +83,12 @@ enum id_type_t {
|
|||
* types of identification.
|
||||
*/
|
||||
ID_KEY_ID = 11,
|
||||
|
||||
|
||||
/**
|
||||
* Special type of PRIVATE USE which matches to any other id.
|
||||
* private type which represents a GeneralName of type URI
|
||||
*/
|
||||
ID_ANY = 201,
|
||||
ID_DER_ASN1_GN_URI = 201,
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -90,23 +96,6 @@ enum id_type_t {
|
|||
*/
|
||||
extern mapping_t id_type_m[];
|
||||
|
||||
/**
|
||||
* Different kinds of generalNames
|
||||
*/
|
||||
typedef enum generalNames_t generalNames_t;
|
||||
|
||||
enum generalNames_t {
|
||||
GN_OTHER_NAME = 0,
|
||||
GN_RFC822_NAME = 1,
|
||||
GN_DNS_NAME = 2,
|
||||
GN_X400_ADDRESS = 3,
|
||||
GN_DIRECTORY_NAME = 4,
|
||||
GN_EDI_PARTY_NAME = 5,
|
||||
GN_URI = 6,
|
||||
GN_IP_ADDRESS = 7,
|
||||
GN_REGISTERED_ID = 8,
|
||||
};
|
||||
|
||||
typedef struct identification_t identification_t;
|
||||
|
||||
/**
|
||||
|
@ -120,6 +109,7 @@ typedef struct identification_t identification_t;
|
|||
* - ID_DER_ASN1_DN
|
||||
* - ID_DER_ASN1_GN
|
||||
* - ID_KEY_ID
|
||||
* - ID_DER_ASN1_GN_URI
|
||||
*
|
||||
* @b Constructors:
|
||||
* - identification_create_from_string()
|
||||
|
|
Loading…
Reference in New Issue