summaryrefslogtreecommitdiff
path: root/src/libstrongswan/plugins/x509
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/plugins/x509')
-rw-r--r--src/libstrongswan/plugins/x509/Makefile.in4
-rw-r--r--src/libstrongswan/plugins/x509/x509_cert.c1192
-rw-r--r--src/libstrongswan/plugins/x509/x509_crl.c173
-rw-r--r--src/libstrongswan/plugins/x509/x509_plugin.c16
4 files changed, 1096 insertions, 289 deletions
diff --git a/src/libstrongswan/plugins/x509/Makefile.in b/src/libstrongswan/plugins/x509/Makefile.in
index b1cc2f168..57deab98e 100644
--- a/src/libstrongswan/plugins/x509/Makefile.in
+++ b/src/libstrongswan/plugins/x509/Makefile.in
@@ -221,9 +221,7 @@ includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
ipsecdir = @ipsecdir@
-ipsecgid = @ipsecgid@
ipsecgroup = @ipsecgroup@
-ipsecuid = @ipsecuid@
ipsecuser = @ipsecuser@
libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
@@ -262,6 +260,8 @@ sbindir = @sbindir@
scepclient_plugins = @scepclient_plugins@
scripts_plugins = @scripts_plugins@
sharedstatedir = @sharedstatedir@
+soup_CFLAGS = @soup_CFLAGS@
+soup_LIBS = @soup_LIBS@
srcdir = @srcdir@
strongswan_conf = @strongswan_conf@
sysconfdir = @sysconfdir@
diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c
index 559090aa0..526dbe8c6 100644
--- a/src/libstrongswan/plugins/x509/x509_cert.c
+++ b/src/libstrongswan/plugins/x509/x509_cert.c
@@ -117,7 +117,7 @@ struct private_x509_cert_t {
linked_list_t *subjectAltNames;
/**
- * List of crlDistributionPoints as allocated char*
+ * List of crlDistributionPoints as x509_cdp_t*
*/
linked_list_t *crl_uris;
@@ -132,6 +132,26 @@ struct private_x509_cert_t {
linked_list_t *ipAddrBlocks;
/**
+ * List of permitted name constraints
+ */
+ linked_list_t *permitted_names;
+
+ /**
+ * List of exluced name constraints
+ */
+ linked_list_t *excluded_names;
+
+ /**
+ * List of certificatePolicies, as x509_cert_policy_t
+ */
+ linked_list_t *cert_policies;
+
+ /**
+ * List of policyMappings, as x509_policy_mapping_t
+ */
+ linked_list_t *policy_mappings;
+
+ /**
* certificate's embedded public key
*/
public_key_t *public_key;
@@ -154,7 +174,22 @@ struct private_x509_cert_t {
/**
* Path Length Constraint
*/
- int pathLenConstraint;
+ u_char pathLenConstraint;
+
+ /**
+ * requireExplicitPolicy Constraint
+ */
+ u_char require_explicit;
+
+ /**
+ * inhibitPolicyMapping Constraint
+ */
+ u_char inhibit_mapping;
+
+ /**
+ * inhibitAnyPolicy Constraint
+ */
+ u_char inhibit_any;
/**
* x509 constraints and other flags
@@ -187,6 +222,53 @@ static const chunk_t ASN1_subjectAltName_oid = chunk_from_chars(
);
/**
+ * Destroy a CertificateDistributionPoint
+ */
+static void crl_uri_destroy(x509_cdp_t *this)
+{
+ free(this->uri);
+ DESTROY_IF(this->issuer);
+ free(this);
+}
+
+/**
+ * Destroy a CertificatePolicy
+ */
+static void cert_policy_destroy(x509_cert_policy_t *this)
+{
+ free(this->oid.ptr);
+ free(this->cps_uri);
+ free(this->unotice_text);
+ free(this);
+}
+
+/**
+ * Free policy mapping
+ */
+static void policy_mapping_destroy(x509_policy_mapping_t *mapping)
+{
+ free(mapping->issuer.ptr);
+ free(mapping->subject.ptr);
+ free(mapping);
+}
+
+/**
+ * Parse a length constraint from an unwrapped integer
+ */
+static u_int parse_constraint(chunk_t object)
+{
+ switch (object.len)
+ {
+ case 0:
+ return 0;
+ case 1:
+ return (object.ptr[0] & 0x80) ? X509_NO_CONSTRAINT : object.ptr[0];
+ default:
+ return X509_NO_CONSTRAINT;
+ }
+}
+
+/**
* ASN.1 definition of a basicConstraints extension
*/
static const asn1Object_t basicConstraintsObjects[] = {
@@ -228,15 +310,7 @@ static void parse_basicConstraints(chunk_t blob, int level0,
case BASIC_CONSTRAINTS_PATH_LEN:
if (isCA)
{
- if (object.len == 0)
- {
- this->pathLenConstraint = 0;
- }
- else if (object.len == 1)
- {
- this->pathLenConstraint = *object.ptr;
- }
- /* we ignore path length constraints > 127 */
+ this->pathLenConstraint = parse_constraint(object);
}
break;
default:
@@ -574,7 +648,7 @@ static void parse_authorityInfoAccess(chunk_t blob, int level0,
}
break;
default:
- /* unkown accessMethod, ignoring */
+ /* unknown accessMethod, ignoring */
break;
}
break;
@@ -589,6 +663,60 @@ end:
}
/**
+ * Extract KeyUsage flags
+ */
+static void parse_keyUsage(chunk_t blob, private_x509_cert_t *this)
+{
+ enum {
+ KU_DIGITAL_SIGNATURE = 0,
+ KU_NON_REPUDIATION = 1,
+ KU_KEY_ENCIPHERMENT = 2,
+ KU_DATA_ENCIPHERMENT = 3,
+ KU_KEY_AGREEMENT = 4,
+ KU_KEY_CERT_SIGN = 5,
+ KU_CRL_SIGN = 6,
+ KU_ENCIPHER_ONLY = 7,
+ KU_DECIPHER_ONLY = 8,
+ };
+
+ if (asn1_unwrap(&blob, &blob) == ASN1_BIT_STRING && blob.len)
+ {
+ int bit, byte, unused = blob.ptr[0];
+
+ blob = chunk_skip(blob, 1);
+ for (byte = 0; byte < blob.len; byte++)
+ {
+ for (bit = 0; bit < 8; bit++)
+ {
+ if (byte == blob.len - 1 && bit > (7 - unused))
+ {
+ break;
+ }
+ if (blob.ptr[byte] & 1 << (7 - bit))
+ {
+ switch (byte * 8 + bit)
+ {
+ case KU_CRL_SIGN:
+ this->flags |= X509_CRL_SIGN;
+ break;
+ case KU_KEY_CERT_SIGN:
+ /* we use the caBasicConstraint, MUST be set */
+ case KU_DIGITAL_SIGNATURE:
+ case KU_NON_REPUDIATION:
+ case KU_KEY_ENCIPHERMENT:
+ case KU_DATA_ENCIPHERMENT:
+ case KU_KEY_AGREEMENT:
+ case KU_ENCIPHER_ONLY:
+ case KU_DECIPHER_ONLY:
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
* ASN.1 definition of a extendedKeyUsage extension
*/
static const asn1Object_t extendedKeyUsageObjects[] = {
@@ -600,7 +728,7 @@ static const asn1Object_t extendedKeyUsageObjects[] = {
#define EXT_KEY_USAGE_PURPOSE_ID 1
/**
- * Extracts extendedKeyUsage OIDs - currently only OCSP_SIGING is returned
+ * Extracts extendedKeyUsage OIDs
*/
static void parse_extendedKeyUsage(chunk_t blob, int level0,
private_x509_cert_t *this)
@@ -649,51 +777,328 @@ static const asn1Object_t crlDistributionPointsObjects[] = {
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
{ 2, "reasons", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_BODY }, /* 8 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
- { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_BODY }, /* 10 */
+ { 2, "crlIssuer", ASN1_CONTEXT_C_2, ASN1_OPT|ASN1_OBJ }, /* 10 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 12 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
+#define CRL_DIST_POINTS 1
#define CRL_DIST_POINTS_FULLNAME 3
+#define CRL_DIST_POINTS_ISSUER 10
+
+/**
+ * Add entry to the list of each pairing of URI and Issuer
+ */
+static void add_cdps(linked_list_t *list, linked_list_t *uris,
+ linked_list_t *issuers)
+{
+ identification_t *issuer, *id;
+ enumerator_t *enumerator;
+ x509_cdp_t *cdp;
+ char *uri;
+
+ while (uris->remove_last(uris, (void**)&id) == SUCCESS)
+ {
+ if (asprintf(&uri, "%Y", id) > 0)
+ {
+ if (issuers->get_count(issuers))
+ {
+ enumerator = issuers->create_enumerator(issuers);
+ while (enumerator->enumerate(enumerator, &issuer))
+ {
+ INIT(cdp,
+ .uri = strdup(uri),
+ .issuer = issuer->clone(issuer),
+ );
+ list->insert_last(list, cdp);
+ }
+ enumerator->destroy(enumerator);
+ free(uri);
+ }
+ else
+ {
+ INIT(cdp,
+ .uri = uri,
+ );
+ list->insert_last(list, cdp);
+ }
+ }
+ id->destroy(id);
+ }
+ while (issuers->remove_last(issuers, (void**)&id) == SUCCESS)
+ {
+ id->destroy(id);
+ }
+}
/**
* Extracts one or several crlDistributionPoints into a list
*/
-static void parse_crlDistributionPoints(chunk_t blob, int level0,
- private_x509_cert_t *this)
+void x509_parse_crlDistributionPoints(chunk_t blob, int level0,
+ linked_list_t *list)
{
+ linked_list_t *uris, *issuers;
asn1_parser_t *parser;
chunk_t object;
int objectID;
- linked_list_t *list = linked_list_create();
+ uris = linked_list_create();
+ issuers = linked_list_create();
parser = asn1_parser_create(crlDistributionPointsObjects, blob);
parser->set_top_level(parser, level0);
while (parser->iterate(parser, &objectID, &object))
{
- if (objectID == CRL_DIST_POINTS_FULLNAME)
+ switch (objectID)
{
- identification_t *id;
+ case CRL_DIST_POINTS:
+ add_cdps(list, uris, issuers);
+ break;
+ case CRL_DIST_POINTS_FULLNAME:
+ x509_parse_generalNames(object, parser->get_level(parser) + 1,
+ TRUE, uris);
+ break;
+ case CRL_DIST_POINTS_ISSUER:
+ x509_parse_generalNames(object, parser->get_level(parser) + 1,
+ TRUE, issuers);
+ break;
+ default:
+ break;
+ }
+ }
+ parser->destroy(parser);
- /* append extracted generalNames to existing chained list */
- x509_parse_generalNames(object, parser->get_level(parser)+1,
- TRUE, list);
+ add_cdps(list, uris, issuers);
- while (list->remove_last(list, (void**)&id) == SUCCESS)
- {
- char *uri;
+ uris->destroy(uris);
+ issuers->destroy(issuers);
+}
+
+/**
+ * ASN.1 definition of nameConstraints
+ */
+static const asn1Object_t nameConstraintsObjects[] = {
+ { 0, "nameConstraints", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
+ { 1, "permittedSubtrees", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 1 */
+ { 2, "generalSubtree", ASN1_SEQUENCE, ASN1_BODY }, /* 2 */
+ { 1, "end loop", ASN1_EOC, ASN1_END }, /* 3 */
+ { 1, "excludedSubtrees", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_LOOP }, /* 4 */
+ { 2, "generalSubtree", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */
+ { 1, "end loop", ASN1_EOC, ASN1_END }, /* 6 */
+ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 7 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+#define NAME_CONSTRAINT_PERMITTED 2
+#define NAME_CONSTRAINT_EXCLUDED 5
+
+/**
+ * Parse permitted/excluded nameConstraints
+ */
+static void parse_nameConstraints(chunk_t blob, int level0,
+ private_x509_cert_t *this)
+{
+ asn1_parser_t *parser;
+ identification_t *id;
+ chunk_t object;
+ int objectID;
+
+ parser = asn1_parser_create(nameConstraintsObjects, blob);
+ parser->set_top_level(parser, level0);
- if (asprintf(&uri, "%Y", id) > 0)
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID)
+ {
+ case NAME_CONSTRAINT_PERMITTED:
+ id = parse_generalName(object, parser->get_level(parser) + 1);
+ if (id)
{
- this->crl_uris->insert_last(this->crl_uris, uri);
+ this->permitted_names->insert_last(this->permitted_names, id);
}
- id->destroy(id);
- }
+ break;
+ case NAME_CONSTRAINT_EXCLUDED:
+ id = parse_generalName(object, parser->get_level(parser) + 1);
+ if (id)
+ {
+ this->excluded_names->insert_last(this->excluded_names, id);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ parser->destroy(parser);
+}
+
+/**
+ * ASN.1 definition of a certificatePolicies extension
+ */
+static const asn1Object_t certificatePoliciesObject[] = {
+ { 0, "certificatePolicies", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
+ { 1, "policyInformation", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
+ { 2, "policyId", ASN1_OID, ASN1_BODY }, /* 2 */
+ { 2, "qualifier", ASN1_SEQUENCE, ASN1_OPT|ASN1_BODY }, /* 3 */
+ { 3, "qualifierInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 4 */
+ { 4, "qualifierId", ASN1_OID, ASN1_BODY }, /* 5 */
+ { 4, "cPSuri", ASN1_IA5STRING, ASN1_OPT|ASN1_BODY }, /* 6 */
+ { 4, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
+ { 4, "userNotice", ASN1_SEQUENCE, ASN1_OPT|ASN1_NONE }, /* 8 */
+ { 5, "explicitText", ASN1_EOC, ASN1_RAW }, /* 9 */
+ { 4, "end choice", ASN1_EOC, ASN1_END }, /* 10 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */
+ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 13 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+#define CERT_POLICY_ID 2
+#define CERT_POLICY_QUALIFIER_ID 5
+#define CERT_POLICY_CPS_URI 6
+#define CERT_POLICY_EXPLICIT_TEXT 9
+
+/**
+ * Parse certificatePolicies
+ */
+static void parse_certificatePolicies(chunk_t blob, int level0,
+ private_x509_cert_t *this)
+{
+ x509_cert_policy_t *policy = NULL;
+ asn1_parser_t *parser;
+ chunk_t object;
+ int objectID, qualifier = OID_UNKNOWN;
+
+ parser = asn1_parser_create(certificatePoliciesObject, blob);
+ parser->set_top_level(parser, level0);
+
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID)
+ {
+ case CERT_POLICY_ID:
+ INIT(policy,
+ .oid = chunk_clone(object),
+ );
+ this->cert_policies->insert_last(this->cert_policies, policy);
+ break;
+ case CERT_POLICY_QUALIFIER_ID:
+ qualifier = asn1_known_oid(object);
+ break;
+ case CERT_POLICY_CPS_URI:
+ if (policy && !policy->cps_uri && object.len &&
+ qualifier == OID_POLICY_QUALIFIER_CPS &&
+ chunk_printable(object, NULL, 0))
+ {
+ policy->cps_uri = strndup(object.ptr, object.len);
+ }
+ break;
+ case CERT_POLICY_EXPLICIT_TEXT:
+ /* TODO */
+ break;
+ default:
+ break;
+ }
+ }
+ parser->destroy(parser);
+}
+
+/**
+ * ASN.1 definition of a policyMappings extension
+ */
+static const asn1Object_t policyMappingsObjects[] = {
+ { 0, "policyMappings", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
+ { 1, "policyMapping", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
+ { 2, "issuerPolicy", ASN1_OID, ASN1_BODY }, /* 2 */
+ { 2, "subjectPolicy", ASN1_OID, ASN1_BODY }, /* 3 */
+ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 4 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+#define POLICY_MAPPING 1
+#define POLICY_MAPPING_ISSUER 2
+#define POLICY_MAPPING_SUBJECT 3
+
+/**
+ * Parse policyMappings
+ */
+static void parse_policyMappings(chunk_t blob, int level0,
+ private_x509_cert_t *this)
+{
+ x509_policy_mapping_t *map = NULL;
+ asn1_parser_t *parser;
+ chunk_t object;
+ int objectID;
+
+ parser = asn1_parser_create(policyMappingsObjects, blob);
+ parser->set_top_level(parser, level0);
+
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID)
+ {
+ case POLICY_MAPPING:
+ INIT(map);
+ this->policy_mappings->insert_last(this->policy_mappings, map);
+ break;
+ case POLICY_MAPPING_ISSUER:
+ if (map && !map->issuer.len)
+ {
+ map->issuer = chunk_clone(object);
+ }
+ break;
+ case POLICY_MAPPING_SUBJECT:
+ if (map && !map->subject.len)
+ {
+ map->subject = chunk_clone(object);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ parser->destroy(parser);
+}
+
+/**
+ * ASN.1 definition of a policyConstraints extension
+ */
+static const asn1Object_t policyConstraintsObjects[] = {
+ { 0, "policyConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "requireExplicitPolicy", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_NONE }, /* 1 */
+ { 2, "SkipCerts", ASN1_INTEGER, ASN1_BODY }, /* 2 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
+ { 1, "inhibitPolicyMapping", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_NONE }, /* 4 */
+ { 2, "SkipCerts", ASN1_INTEGER, ASN1_BODY }, /* 5 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
+};
+#define POLICY_CONSTRAINT_EXPLICIT 2
+#define POLICY_CONSTRAINT_INHIBIT 5
+
+/**
+ * Parse policyConstraints
+ */
+static void parse_policyConstraints(chunk_t blob, int level0,
+ private_x509_cert_t *this)
+{
+ asn1_parser_t *parser;
+ chunk_t object;
+ int objectID;
+
+ parser = asn1_parser_create(policyConstraintsObjects, blob);
+ parser->set_top_level(parser, level0);
+
+ while (parser->iterate(parser, &objectID, &object))
+ {
+ switch (objectID)
+ {
+ case POLICY_CONSTRAINT_EXPLICIT:
+ this->require_explicit = parse_constraint(object);
+ break;
+ case POLICY_CONSTRAINT_INHIBIT:
+ this->inhibit_mapping = parse_constraint(object);
+ break;
+ default:
+ break;
}
}
parser->destroy(parser);
- list->destroy(list);
}
/**
@@ -888,11 +1293,6 @@ static const asn1Object_t certObjects[] = {
#define X509_OBJ_SIGNATURE 25
/**
- * forward declaration
- */
-static bool issued_by(private_x509_cert_t *this, certificate_t *issuer);
-
-/**
* Parses an X.509v3 certificate
*/
static bool parse_certificate(private_x509_cert_t *this)
@@ -992,7 +1392,8 @@ static bool parse_certificate(private_x509_cert_t *this)
parse_basicConstraints(object, level, this);
break;
case OID_CRL_DISTRIBUTION_POINTS:
- parse_crlDistributionPoints(object, level, this);
+ x509_parse_crlDistributionPoints(object, level,
+ this->crl_uris);
break;
case OID_AUTHORITY_KEY_ID:
this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object,
@@ -1002,7 +1403,7 @@ static bool parse_certificate(private_x509_cert_t *this)
parse_authorityInfoAccess(object, level, this);
break;
case OID_KEY_USAGE:
- /* TODO parse the flags */
+ parse_keyUsage(object, this);
break;
case OID_EXTENDED_KEY_USAGE:
parse_extendedKeyUsage(object, level, this);
@@ -1010,6 +1411,26 @@ static bool parse_certificate(private_x509_cert_t *this)
case OID_IP_ADDR_BLOCKS:
parse_ipAddrBlocks(object, level, this);
break;
+ case OID_NAME_CONSTRAINTS:
+ parse_nameConstraints(object, level, this);
+ break;
+ case OID_CERTIFICATE_POLICIES:
+ parse_certificatePolicies(object, level, this);
+ break;
+ case OID_POLICY_MAPPINGS:
+ parse_policyMappings(object, level, this);
+ break;
+ case OID_POLICY_CONSTRAINTS:
+ parse_policyConstraints(object, level, this);
+ break;
+ case OID_INHIBIT_ANY_POLICY:
+ if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
+ level, "inhibitAnyPolicy"))
+ {
+ goto end;
+ }
+ this->inhibit_any = parse_constraint(object);
+ break;
case OID_NS_REVOCATION_URL:
case OID_NS_CA_REVOCATION_URL:
case OID_NS_CA_POLICY_URL:
@@ -1022,9 +1443,9 @@ static bool parse_certificate(private_x509_cert_t *this)
break;
default:
if (critical && lib->settings->get_bool(lib->settings,
- "libstrongswan.plugins.x509.enforce_critical", FALSE))
+ "libstrongswan.x509.enforce_critical", TRUE))
{
- DBG1(DBG_LIB, "critical %s extension not supported",
+ DBG1(DBG_LIB, "critical '%s' extension not supported",
(extn_oid == OID_UNKNOWN) ? "unknown" :
(char*)oid_names[extn_oid].name);
goto end;
@@ -1057,7 +1478,9 @@ end:
hasher_t *hasher;
/* check if the certificate is self-signed */
- if (issued_by(this, &this->public.interface.interface))
+ if (this->public.interface.interface.issued_by(
+ &this->public.interface.interface,
+ &this->public.interface.interface))
{
this->flags |= X509_SELF_SIGNED;
}
@@ -1074,34 +1497,26 @@ end:
return success;
}
-/**
- * Implementation of certificate_t.get_type
- */
-static certificate_type_t get_type(private_x509_cert_t *this)
+METHOD(certificate_t, get_type, certificate_type_t,
+ private_x509_cert_t *this)
{
return CERT_X509;
}
-/**
- * Implementation of certificate_t.get_subject
- */
-static identification_t* get_subject(private_x509_cert_t *this)
+METHOD(certificate_t, get_subject, identification_t*,
+ private_x509_cert_t *this)
{
return this->subject;
}
-/**
- * Implementation of certificate_t.get_issuer
- */
-static identification_t* get_issuer(private_x509_cert_t *this)
+METHOD(certificate_t, get_issuer, identification_t*,
+ private_x509_cert_t *this)
{
return this->issuer;
}
-/**
- * Implementation of certificate_t.has_subject.
- */
-static id_match_t has_subject(private_x509_cert_t *this, identification_t *subject)
+METHOD(certificate_t, has_subject, id_match_t,
+ private_x509_cert_t *this, identification_t *subject)
{
identification_t *current;
enumerator_t *enumerator;
@@ -1142,19 +1557,15 @@ static id_match_t has_subject(private_x509_cert_t *this, identification_t *subje
return best;
}
-/**
- * Implementation of certificate_t.has_issuer.
- */
-static id_match_t has_issuer(private_x509_cert_t *this, identification_t *issuer)
+METHOD(certificate_t, has_issuer, id_match_t,
+ private_x509_cert_t *this, identification_t *issuer)
{
/* issuerAltNames currently not supported */
return this->issuer->matches(this->issuer, issuer);
}
-/**
- * Implementation of certificate_t.issued_by.
- */
-static bool issued_by(private_x509_cert_t *this, certificate_t *issuer)
+METHOD(certificate_t, issued_by, bool,
+ private_x509_cert_t *this, certificate_t *issuer)
{
public_key_t *key;
signature_scheme_t scheme;
@@ -1201,37 +1612,23 @@ static bool issued_by(private_x509_cert_t *this, certificate_t *issuer)
return valid;
}
-/**
- * Implementation of certificate_t.get_public_key
- */
-static public_key_t* get_public_key(private_x509_cert_t *this)
+METHOD(certificate_t, get_public_key, public_key_t*,
+ private_x509_cert_t *this)
{
this->public_key->get_ref(this->public_key);
return this->public_key;
}
-/**
- * Implementation of certificate_t.get_ref
- */
-static private_x509_cert_t* get_ref(private_x509_cert_t *this)
+METHOD(certificate_t, get_ref, certificate_t*,
+ private_x509_cert_t *this)
{
ref_get(&this->ref);
- return this;
+ return &this->public.interface.interface;
}
-/**
- * Implementation of x509_cert_t.get_flags.
- */
-static x509_flag_t get_flags(private_x509_cert_t *this)
-{
- return this->flags;
-}
-
-/**
- * Implementation of x509_cert_t.get_validity.
- */
-static bool get_validity(private_x509_cert_t *this, time_t *when,
- time_t *not_before, time_t *not_after)
+METHOD(certificate_t, get_validity, bool,
+ private_x509_cert_t *this, time_t *when, time_t *not_before,
+ time_t *not_after)
{
time_t t = when ? *when : time(NULL);
@@ -1246,11 +1643,8 @@ static bool get_validity(private_x509_cert_t *this, time_t *when,
return (t >= this->notBefore && t <= this->notAfter);
}
-/**
- * Implementation of certificate_t.get_encoding.
- */
-static bool get_encoding(private_x509_cert_t *this, cred_encoding_type_t type,
- chunk_t *encoding)
+METHOD(certificate_t, get_encoding, bool,
+ private_x509_cert_t *this, cred_encoding_type_t type, chunk_t *encoding)
{
if (type == CERT_ASN1_DER)
{
@@ -1261,10 +1655,8 @@ static bool get_encoding(private_x509_cert_t *this, cred_encoding_type_t type,
CRED_PART_X509_ASN1_DER, this->encoding, CRED_PART_END);
}
-/**
- * Implementation of certificate_t.equals.
- */
-static bool equals(private_x509_cert_t *this, certificate_t *other)
+METHOD(certificate_t, equals, bool,
+ private_x509_cert_t *this, certificate_t *other)
{
chunk_t encoding;
bool equal;
@@ -1290,18 +1682,20 @@ static bool equals(private_x509_cert_t *this, certificate_t *other)
return equal;
}
-/**
- * Implementation of x509_t.get_serial.
- */
-static chunk_t get_serial(private_x509_cert_t *this)
+METHOD(x509_t, get_flags, x509_flag_t,
+ private_x509_cert_t *this)
+{
+ return this->flags;
+}
+
+METHOD(x509_t, get_serial, chunk_t,
+ private_x509_cert_t *this)
{
return this->serialNumber;
}
-/**
- * Implementation of x509_t.get_subjectKeyIdentifier.
- */
-static chunk_t get_subjectKeyIdentifier(private_x509_cert_t *this)
+METHOD(x509_t, get_subjectKeyIdentifier, chunk_t,
+ private_x509_cert_t *this)
{
if (this->subjectKeyIdentifier.ptr)
{
@@ -1323,66 +1717,95 @@ static chunk_t get_subjectKeyIdentifier(private_x509_cert_t *this)
}
}
-/**
- * Implementation of x509_t.get_authKeyIdentifier.
- */
-static chunk_t get_authKeyIdentifier(private_x509_cert_t *this)
+METHOD(x509_t, get_authKeyIdentifier, chunk_t,
+ private_x509_cert_t *this)
{
return this->authKeyIdentifier;
}
-/**
- * Implementation of x509_t.get_pathLenConstraint.
- */
-static int get_pathLenConstraint(private_x509_cert_t *this)
+METHOD(x509_t, get_constraint, u_int,
+ private_x509_cert_t *this, x509_constraint_t type)
{
- return this->pathLenConstraint;
+ switch (type)
+ {
+ case X509_PATH_LEN:
+ return this->pathLenConstraint;
+ case X509_REQUIRE_EXPLICIT_POLICY:
+ return this->require_explicit;
+ case X509_INHIBIT_POLICY_MAPPING:
+ return this->inhibit_mapping;
+ case X509_INHIBIT_ANY_POLICY:
+ return this->inhibit_any;
+ default:
+ return X509_NO_CONSTRAINT;
+ }
}
-/**
- * Implementation of x509_cert_t.create_subjectAltName_enumerator.
- */
-static enumerator_t* create_subjectAltName_enumerator(private_x509_cert_t *this)
+METHOD(x509_t, create_subjectAltName_enumerator, enumerator_t*,
+ private_x509_cert_t *this)
{
return this->subjectAltNames->create_enumerator(this->subjectAltNames);
}
-/**
- * Implementation of x509_cert_t.create_ocsp_uri_enumerator.
- */
-static enumerator_t* create_ocsp_uri_enumerator(private_x509_cert_t *this)
+METHOD(x509_t, create_ocsp_uri_enumerator, enumerator_t*,
+ private_x509_cert_t *this)
{
return this->ocsp_uris->create_enumerator(this->ocsp_uris);
}
-/**
- * Implementation of x509_cert_t.create_crl_uri_enumerator.
- */
-static enumerator_t* create_crl_uri_enumerator(private_x509_cert_t *this)
+METHOD(x509_t, create_crl_uri_enumerator, enumerator_t*,
+ private_x509_cert_t *this)
{
return this->crl_uris->create_enumerator(this->crl_uris);
}
-/**
- * Implementation of x509_cert_t.create_ipAddrBlock_enumerator.
- */
-static enumerator_t* create_ipAddrBlock_enumerator(private_x509_cert_t *this)
+METHOD(x509_t, create_ipAddrBlock_enumerator, enumerator_t*,
+ private_x509_cert_t *this)
{
return this->ipAddrBlocks->create_enumerator(this->ipAddrBlocks);
}
-/**
- * Implementation of certificate_t.destroy.
- */
-static void destroy(private_x509_cert_t *this)
+METHOD(x509_t, create_name_constraint_enumerator, enumerator_t*,
+ private_x509_cert_t *this, bool perm)
+{
+ if (perm)
+ {
+ return this->permitted_names->create_enumerator(this->permitted_names);
+ }
+ return this->excluded_names->create_enumerator(this->excluded_names);
+}
+
+METHOD(x509_t, create_cert_policy_enumerator, enumerator_t*,
+ private_x509_cert_t *this)
+{
+ return this->cert_policies->create_enumerator(this->cert_policies);
+}
+
+METHOD(x509_t, create_policy_mapping_enumerator, enumerator_t*,
+ private_x509_cert_t *this)
+{
+ return this->policy_mappings->create_enumerator(this->policy_mappings);
+}
+
+METHOD(certificate_t, destroy, void,
+ private_x509_cert_t *this)
{
if (ref_put(&this->ref))
{
this->subjectAltNames->destroy_offset(this->subjectAltNames,
offsetof(identification_t, destroy));
- this->crl_uris->destroy_function(this->crl_uris, free);
+ this->crl_uris->destroy_function(this->crl_uris, (void*)crl_uri_destroy);
this->ocsp_uris->destroy_function(this->ocsp_uris, free);
- this->ipAddrBlocks->destroy_offset(this->ipAddrBlocks, offsetof(traffic_selector_t, destroy));
+ this->ipAddrBlocks->destroy_offset(this->ipAddrBlocks,
+ offsetof(traffic_selector_t, destroy));
+ this->permitted_names->destroy_offset(this->permitted_names,
+ offsetof(identification_t, destroy));
+ this->excluded_names->destroy_offset(this->excluded_names,
+ offsetof(identification_t, destroy));
+ this->cert_policies->destroy_function(this->cert_policies,
+ (void*)cert_policy_destroy);
+ this->policy_mappings->destroy_function(this->policy_mappings,
+ (void*)policy_mapping_destroy);
DESTROY_IF(this->issuer);
DESTROY_IF(this->subject);
DESTROY_IF(this->public_key);
@@ -1404,63 +1827,93 @@ static void destroy(private_x509_cert_t *this)
*/
static private_x509_cert_t* create_empty(void)
{
- private_x509_cert_t *this = malloc_thing(private_x509_cert_t);
-
- this->public.interface.interface.get_type = (certificate_type_t (*) (certificate_t*))get_type;
- this->public.interface.interface.get_subject = (identification_t* (*) (certificate_t*))get_subject;
- this->public.interface.interface.get_issuer = (identification_t* (*) (certificate_t*))get_issuer;
- this->public.interface.interface.has_subject = (id_match_t (*) (certificate_t*, identification_t*))has_subject;
- this->public.interface.interface.has_issuer = (id_match_t (*) (certificate_t*, identification_t*))has_issuer;
- this->public.interface.interface.issued_by = (bool (*) (certificate_t*, certificate_t*))issued_by;
- this->public.interface.interface.get_public_key = (public_key_t* (*) (certificate_t*))get_public_key;
- this->public.interface.interface.get_validity = (bool (*) (certificate_t*, time_t*, time_t*, time_t*))get_validity;
- this->public.interface.interface.get_encoding = (bool (*) (certificate_t*,cred_encoding_type_t,chunk_t*))get_encoding;
- this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t*))equals;
- this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t*))get_ref;
- this->public.interface.interface.destroy = (void (*)(certificate_t*))destroy;
- this->public.interface.get_flags = (x509_flag_t (*)(x509_t*))get_flags;
- this->public.interface.get_serial = (chunk_t (*)(x509_t*))get_serial;
- this->public.interface.get_subjectKeyIdentifier = (chunk_t (*)(x509_t*))get_subjectKeyIdentifier;
- this->public.interface.get_authKeyIdentifier = (chunk_t (*)(x509_t*))get_authKeyIdentifier;
- this->public.interface.get_pathLenConstraint = (int (*)(x509_t*))get_pathLenConstraint;
- this->public.interface.create_subjectAltName_enumerator = (enumerator_t* (*)(x509_t*))create_subjectAltName_enumerator;
- this->public.interface.create_crl_uri_enumerator = (enumerator_t* (*)(x509_t*))create_crl_uri_enumerator;
- this->public.interface.create_ocsp_uri_enumerator = (enumerator_t* (*)(x509_t*))create_ocsp_uri_enumerator;
- this->public.interface.create_ipAddrBlock_enumerator = (enumerator_t* (*)(x509_t*))create_ipAddrBlock_enumerator;
-
- this->encoding = chunk_empty;
- this->encoding_hash = chunk_empty;
- this->tbsCertificate = chunk_empty;
- this->version = 1;
- this->serialNumber = chunk_empty;
- this->notBefore = 0;
- this->notAfter = 0;
- this->public_key = NULL;
- this->subject = NULL;
- this->issuer = NULL;
- this->subjectAltNames = linked_list_create();
- this->crl_uris = linked_list_create();
- this->ocsp_uris = linked_list_create();
- this->ipAddrBlocks = linked_list_create();
- this->subjectKeyIdentifier = chunk_empty;
- this->authKeyIdentifier = chunk_empty;
- this->authKeySerialNumber = chunk_empty;
- this->pathLenConstraint = X509_NO_PATH_LEN_CONSTRAINT;
- this->algorithm = 0;
- this->signature = chunk_empty;
- this->flags = 0;
- this->ref = 1;
- this->parsed = FALSE;
-
+ private_x509_cert_t *this;
+
+ INIT(this,
+ .public = {
+ .interface = {
+ .interface = {
+ .get_type = _get_type,
+ .get_subject = _get_subject,
+ .get_issuer = _get_issuer,
+ .has_subject = _has_subject,
+ .has_issuer = _has_issuer,
+ .issued_by = _issued_by,
+ .get_public_key = _get_public_key,
+ .get_validity = _get_validity,
+ .get_encoding = _get_encoding,
+ .equals = _equals,
+ .get_ref = _get_ref,
+ .destroy = _destroy,
+ },
+ .get_flags = _get_flags,
+ .get_serial = _get_serial,
+ .get_subjectKeyIdentifier = _get_subjectKeyIdentifier,
+ .get_authKeyIdentifier = _get_authKeyIdentifier,
+ .get_constraint = _get_constraint,
+ .create_subjectAltName_enumerator = _create_subjectAltName_enumerator,
+ .create_crl_uri_enumerator = _create_crl_uri_enumerator,
+ .create_ocsp_uri_enumerator = _create_ocsp_uri_enumerator,
+ .create_ipAddrBlock_enumerator = _create_ipAddrBlock_enumerator,
+ .create_name_constraint_enumerator = _create_name_constraint_enumerator,
+ .create_cert_policy_enumerator = _create_cert_policy_enumerator,
+ .create_policy_mapping_enumerator = _create_policy_mapping_enumerator,
+ },
+ },
+ .version = 1,
+ .subjectAltNames = linked_list_create(),
+ .crl_uris = linked_list_create(),
+ .ocsp_uris = linked_list_create(),
+ .ipAddrBlocks = linked_list_create(),
+ .permitted_names = linked_list_create(),
+ .excluded_names = linked_list_create(),
+ .cert_policies = linked_list_create(),
+ .policy_mappings = linked_list_create(),
+ .pathLenConstraint = X509_NO_CONSTRAINT,
+ .require_explicit = X509_NO_CONSTRAINT,
+ .inhibit_mapping = X509_NO_CONSTRAINT,
+ .inhibit_any = X509_NO_CONSTRAINT,
+ .ref = 1,
+ );
return this;
}
/**
+ * Build a generalName from an id
+ */
+chunk_t build_generalName(identification_t *id)
+{
+ int context;
+
+ switch (id->get_type(id))
+ {
+ case ID_RFC822_ADDR:
+ context = ASN1_CONTEXT_S_1;
+ break;
+ case ID_FQDN:
+ context = ASN1_CONTEXT_S_2;
+ break;
+ case ID_DER_ASN1_DN:
+ context = ASN1_CONTEXT_C_4;
+ break;
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ context = ASN1_CONTEXT_S_7;
+ break;
+ default:
+ DBG1(DBG_LIB, "encoding %N as generalName not supported",
+ id_type_names, id->get_type(id));
+ return chunk_empty;
+ }
+ return asn1_wrap(context, "c", id->get_encoding(id));
+}
+
+/**
* Encode a linked list of subjectAltNames
*/
chunk_t x509_build_subjectAltNames(linked_list_t *list)
{
- chunk_t subjectAltNames = chunk_empty;
+ chunk_t subjectAltNames = chunk_empty, name;
enumerator_t *enumerator;
identification_t *id;
@@ -1472,29 +1925,7 @@ chunk_t x509_build_subjectAltNames(linked_list_t *list)
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &id))
{
- int context;
- chunk_t name;
-
- switch (id->get_type(id))
- {
- case ID_RFC822_ADDR:
- context = ASN1_CONTEXT_S_1;
- break;
- case ID_FQDN:
- context = ASN1_CONTEXT_S_2;
- break;
- case ID_IPV4_ADDR:
- case ID_IPV6_ADDR:
- context = ASN1_CONTEXT_S_7;
- break;
- default:
- DBG1(DBG_LIB, "encoding %N as subjectAltName not supported",
- id_type_names, id->get_type(id));
- enumerator->destroy(enumerator);
- free(subjectAltNames.ptr);
- return chunk_empty;
- }
- name = asn1_wrap(context, "c", id->get_encoding(id));
+ name = build_generalName(id);
subjectAltNames = chunk_cat("mm", subjectAltNames, name);
}
enumerator->destroy(enumerator);
@@ -1508,6 +1939,47 @@ chunk_t x509_build_subjectAltNames(linked_list_t *list)
}
/**
+ * Encode CRL distribution points extension from a x509_cdp_t list
+ */
+chunk_t x509_build_crlDistributionPoints(linked_list_t *list, int extn)
+{
+ chunk_t crlDistributionPoints = chunk_empty;
+ enumerator_t *enumerator;
+ x509_cdp_t *cdp;
+
+ if (list->get_count(list) == 0)
+ {
+ return chunk_empty;
+ }
+
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &cdp))
+ {
+ chunk_t distributionPoint, crlIssuer = chunk_empty;
+
+ if (cdp->issuer)
+ {
+ crlIssuer = asn1_wrap(ASN1_CONTEXT_C_2, "m",
+ build_generalName(cdp->issuer));
+ }
+ distributionPoint = asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_wrap(ASN1_CONTEXT_C_0, "m",
+ asn1_wrap(ASN1_CONTEXT_C_0, "m",
+ asn1_wrap(ASN1_CONTEXT_S_6, "c",
+ chunk_create(cdp->uri, strlen(cdp->uri))))),
+ crlIssuer);
+ crlDistributionPoints = chunk_cat("mm", crlDistributionPoints,
+ distributionPoint);
+ }
+ enumerator->destroy(enumerator);
+
+ return asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_build_known_oid(extn),
+ asn1_wrap(ASN1_OCTET_STRING, "m",
+ asn1_wrap(ASN1_SEQUENCE, "m", crlDistributionPoints)));
+}
+
+/**
* Generate and sign a new certificate
*/
static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
@@ -1515,12 +1987,13 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
{
chunk_t extensions = chunk_empty, extendedKeyUsage = chunk_empty;
chunk_t serverAuth = chunk_empty, clientAuth = chunk_empty;
- chunk_t ocspSigning = chunk_empty;
- chunk_t basicConstraints = chunk_empty;
- chunk_t keyUsage = chunk_empty;
- chunk_t subjectAltNames = chunk_empty;
+ chunk_t ocspSigning = chunk_empty, certPolicies = chunk_empty;
+ chunk_t basicConstraints = chunk_empty, nameConstraints = chunk_empty;
+ chunk_t keyUsage = chunk_empty, keyUsageBits = chunk_empty;
+ chunk_t subjectAltNames = chunk_empty, policyMappings = chunk_empty;
chunk_t subjectKeyIdentifier = chunk_empty, authKeyIdentifier = chunk_empty;
chunk_t crlDistributionPoints = chunk_empty, authorityInfoAccess = chunk_empty;
+ chunk_t policyConstraints = chunk_empty, inhibitAnyPolicy = chunk_empty;
identification_t *issuer, *subject;
chunk_t key_info;
signature_scheme_t scheme;
@@ -1574,29 +2047,8 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
/* encode subjectAltNames */
subjectAltNames = x509_build_subjectAltNames(cert->subjectAltNames);
- /* encode CRL distribution points extension */
- enumerator = cert->crl_uris->create_enumerator(cert->crl_uris);
- while (enumerator->enumerate(enumerator, &uri))
- {
- chunk_t distributionPoint;
-
- distributionPoint = asn1_wrap(ASN1_SEQUENCE, "m",
- asn1_wrap(ASN1_CONTEXT_C_0, "m",
- asn1_wrap(ASN1_CONTEXT_C_0, "m",
- asn1_wrap(ASN1_CONTEXT_S_6, "c",
- chunk_create(uri, strlen(uri))))));
-
- crlDistributionPoints = chunk_cat("mm", crlDistributionPoints,
- distributionPoint);
- }
- enumerator->destroy(enumerator);
- if (crlDistributionPoints.ptr)
- {
- crlDistributionPoints = asn1_wrap(ASN1_SEQUENCE, "mm",
- asn1_build_known_oid(OID_CRL_DISTRIBUTION_POINTS),
- asn1_wrap(ASN1_OCTET_STRING, "m",
- asn1_wrap(ASN1_SEQUENCE, "m", crlDistributionPoints)));
- }
+ crlDistributionPoints = x509_build_crlDistributionPoints(cert->crl_uris,
+ OID_CRL_DISTRIBUTION_POINTS);
/* encode OCSP URIs in authorityInfoAccess extension */
enumerator = cert->ocsp_uris->create_enumerator(cert->ocsp_uris);
@@ -1625,11 +2077,10 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
{
chunk_t pathLenConstraint = chunk_empty;
- if (cert->pathLenConstraint != X509_NO_PATH_LEN_CONSTRAINT)
+ if (cert->pathLenConstraint != X509_NO_CONSTRAINT)
{
- char pathlen = (char)cert->pathLenConstraint;
-
- pathLenConstraint = asn1_integer("c", chunk_from_thing(pathlen));
+ pathLenConstraint = asn1_integer("c",
+ chunk_from_thing(cert->pathLenConstraint));
}
basicConstraints = asn1_wrap(ASN1_SEQUENCE, "mmm",
asn1_build_known_oid(OID_BASIC_CONSTRAINTS),
@@ -1640,13 +2091,20 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
asn1_wrap(ASN1_BOOLEAN, "c",
chunk_from_chars(0xFF)),
pathLenConstraint)));
+ /* set CertificateSign and implicitly CRLsign */
+ keyUsageBits = chunk_from_chars(0x01, 0x06);
+ }
+ else if (cert->flags & X509_CRL_SIGN)
+ {
+ keyUsageBits = chunk_from_chars(0x01, 0x02);
+ }
+ if (keyUsageBits.len)
+ {
keyUsage = asn1_wrap(ASN1_SEQUENCE, "mmm",
- asn1_build_known_oid(OID_KEY_USAGE),
- asn1_wrap(ASN1_BOOLEAN, "c",
- chunk_from_chars(0xFF)),
- asn1_wrap(ASN1_OCTET_STRING, "m",
- asn1_wrap(ASN1_BIT_STRING, "c",
- chunk_from_chars(0x01, 0x06))));
+ asn1_build_known_oid(OID_KEY_USAGE),
+ asn1_wrap(ASN1_BOOLEAN, "c", chunk_from_chars(0xFF)),
+ asn1_wrap(ASN1_OCTET_STRING, "m",
+ asn1_wrap(ASN1_BIT_STRING, "c", keyUsageBits)));
}
/* add serverAuth extendedKeyUsage flag */
@@ -1675,7 +2133,7 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
}
/* add subjectKeyIdentifier to CA and OCSP signer certificates */
- if (cert->flags & (X509_CA | X509_OCSP_SIGNER))
+ if (cert->flags & (X509_CA | X509_OCSP_SIGNER | X509_CRL_SIGN))
{
chunk_t keyid;
@@ -1703,15 +2161,153 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
asn1_wrap(ASN1_CONTEXT_S_0, "c", keyid))));
}
}
+
+ if (cert->permitted_names->get_count(cert->permitted_names) ||
+ cert->excluded_names->get_count(cert->excluded_names))
+ {
+ chunk_t permitted = chunk_empty, excluded = chunk_empty, subtree;
+ identification_t *id;
+
+ enumerator = create_name_constraint_enumerator(cert, TRUE);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ subtree = asn1_wrap(ASN1_SEQUENCE, "m", build_generalName(id));
+ permitted = chunk_cat("mm", permitted, subtree);
+ }
+ enumerator->destroy(enumerator);
+ if (permitted.ptr)
+ {
+ permitted = asn1_wrap(ASN1_CONTEXT_C_0, "m", permitted);
+ }
+
+ enumerator = create_name_constraint_enumerator(cert, FALSE);
+ while (enumerator->enumerate(enumerator, &id))
+ {
+ subtree = asn1_wrap(ASN1_SEQUENCE, "m", build_generalName(id));
+ excluded = chunk_cat("mm", excluded, subtree);
+ }
+ enumerator->destroy(enumerator);
+ if (excluded.ptr)
+ {
+ excluded = asn1_wrap(ASN1_CONTEXT_C_1, "m", excluded);
+ }
+
+ nameConstraints = asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_build_known_oid(OID_NAME_CONSTRAINTS),
+ asn1_wrap(ASN1_OCTET_STRING, "m",
+ asn1_wrap(ASN1_SEQUENCE, "mm",
+ permitted, excluded)));
+ }
+
+ if (cert->cert_policies->get_count(cert->cert_policies))
+ {
+ x509_cert_policy_t *policy;
+
+ enumerator = create_cert_policy_enumerator(cert);
+ while (enumerator->enumerate(enumerator, &policy))
+ {
+ chunk_t chunk = chunk_empty, cps = chunk_empty, notice = chunk_empty;
+
+ if (policy->cps_uri)
+ {
+ cps = asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_build_known_oid(OID_POLICY_QUALIFIER_CPS),
+ asn1_wrap(ASN1_IA5STRING, "c",
+ chunk_create(policy->cps_uri,
+ strlen(policy->cps_uri))));
+ }
+ if (policy->unotice_text)
+ {
+ notice = asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_build_known_oid(OID_POLICY_QUALIFIER_UNOTICE),
+ asn1_wrap(ASN1_SEQUENCE, "m",
+ asn1_wrap(ASN1_VISIBLESTRING, "c",
+ chunk_create(policy->unotice_text,
+ strlen(policy->unotice_text)))));
+ }
+ if (cps.len || notice.len)
+ {
+ chunk = asn1_wrap(ASN1_SEQUENCE, "mm", cps, notice);
+ }
+ chunk = asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_wrap(ASN1_OID, "c", policy->oid), chunk);
+ certPolicies = chunk_cat("mm", certPolicies, chunk);
+ }
+ enumerator->destroy(enumerator);
+
+ certPolicies = asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_build_known_oid(OID_CERTIFICATE_POLICIES),
+ asn1_wrap(ASN1_OCTET_STRING, "m",
+ asn1_wrap(ASN1_SEQUENCE, "m", certPolicies)));
+ }
+
+ if (cert->policy_mappings->get_count(cert->policy_mappings))
+ {
+ x509_policy_mapping_t *mapping;
+
+ enumerator = create_policy_mapping_enumerator(cert);
+ while (enumerator->enumerate(enumerator, &mapping))
+ {
+ chunk_t chunk;
+
+ chunk = asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_wrap(ASN1_OID, "c", mapping->issuer),
+ asn1_wrap(ASN1_OID, "c", mapping->subject));
+ policyMappings = chunk_cat("mm", policyMappings, chunk);
+ }
+ enumerator->destroy(enumerator);
+
+ policyMappings = asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_build_known_oid(OID_POLICY_MAPPINGS),
+ asn1_wrap(ASN1_OCTET_STRING, "m",
+ asn1_wrap(ASN1_SEQUENCE, "m", policyMappings)));
+ }
+
+ if (cert->inhibit_mapping != X509_NO_CONSTRAINT ||
+ cert->require_explicit != X509_NO_CONSTRAINT)
+ {
+ chunk_t inhibit = chunk_empty, explicit = chunk_empty;
+
+ if (cert->require_explicit != X509_NO_CONSTRAINT)
+ {
+ explicit = asn1_wrap(ASN1_CONTEXT_C_0, "m",
+ asn1_integer("c",
+ chunk_from_thing(cert->require_explicit)));
+ }
+ if (cert->inhibit_mapping != X509_NO_CONSTRAINT)
+ {
+ inhibit = asn1_wrap(ASN1_CONTEXT_C_1, "m",
+ asn1_integer("c",
+ chunk_from_thing(cert->inhibit_mapping)));
+ }
+ policyConstraints = asn1_wrap(ASN1_SEQUENCE, "mmm",
+ asn1_build_known_oid(OID_POLICY_CONSTRAINTS),
+ asn1_wrap(ASN1_BOOLEAN, "c", chunk_from_chars(0xFF)),
+ asn1_wrap(ASN1_OCTET_STRING, "m",
+ asn1_wrap(ASN1_SEQUENCE, "mm",
+ explicit, inhibit)));
+ }
+
+ if (cert->inhibit_any != X509_NO_CONSTRAINT)
+ {
+ inhibitAnyPolicy = asn1_wrap(ASN1_SEQUENCE, "mmm",
+ asn1_build_known_oid(OID_INHIBIT_ANY_POLICY),
+ asn1_wrap(ASN1_BOOLEAN, "c", chunk_from_chars(0xFF)),
+ asn1_wrap(ASN1_OCTET_STRING, "m",
+ asn1_integer("c",
+ chunk_from_thing(cert->inhibit_any))));
+ }
+
if (basicConstraints.ptr || subjectAltNames.ptr || authKeyIdentifier.ptr ||
- crlDistributionPoints.ptr)
+ crlDistributionPoints.ptr || nameConstraints.ptr)
{
extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m",
- asn1_wrap(ASN1_SEQUENCE, "mmmmmmmm",
+ asn1_wrap(ASN1_SEQUENCE, "mmmmmmmmmmmmm",
basicConstraints, keyUsage, subjectKeyIdentifier,
authKeyIdentifier, subjectAltNames,
extendedKeyUsage, crlDistributionPoints,
- authorityInfoAccess));
+ authorityInfoAccess, nameConstraints, certPolicies,
+ policyMappings, policyConstraints, inhibitAnyPolicy));
}
cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmmcmcmm",
@@ -1794,6 +2390,7 @@ x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args)
certificate_t *sign_cert = NULL;
private_key_t *sign_key = NULL;
hash_algorithm_t digest_alg = HASH_SHA1;
+ u_int constraint;
cert = create_empty();
while (TRUE)
@@ -1837,13 +2434,17 @@ x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args)
{
enumerator_t *enumerator;
linked_list_t *list;
- char *uri;
+ x509_cdp_t *in, *cdp;
list = va_arg(args, linked_list_t*);
enumerator = list->create_enumerator(list);
- while (enumerator->enumerate(enumerator, &uri))
+ while (enumerator->enumerate(enumerator, &in))
{
- cert->crl_uris->insert_last(cert->crl_uris, strdup(uri));
+ INIT(cdp,
+ .uri = strdup(in->uri),
+ .issuer = in->issuer ? in->issuer->clone(in->issuer) : NULL,
+ );
+ cert->crl_uris->insert_last(cert->crl_uris, cdp);
}
enumerator->destroy(enumerator);
continue;
@@ -1864,11 +2465,96 @@ x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args)
continue;
}
case BUILD_PATHLEN:
- cert->pathLenConstraint = va_arg(args, int);
- if (cert->pathLenConstraint < 0 || cert->pathLenConstraint > 127)
+ constraint = va_arg(args, u_int);
+ cert->pathLenConstraint = (constraint < 128) ?
+ constraint : X509_NO_CONSTRAINT;
+ continue;
+ case BUILD_PERMITTED_NAME_CONSTRAINTS:
+ {
+ enumerator_t *enumerator;
+ linked_list_t *list;
+ identification_t *constraint;
+
+ list = va_arg(args, linked_list_t*);
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &constraint))
+ {
+ cert->permitted_names->insert_last(cert->permitted_names,
+ constraint->clone(constraint));
+ }
+ enumerator->destroy(enumerator);
+ continue;
+ }
+ case BUILD_EXCLUDED_NAME_CONSTRAINTS:
+ {
+ enumerator_t *enumerator;
+ linked_list_t *list;
+ identification_t *constraint;
+
+ list = va_arg(args, linked_list_t*);
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &constraint))
+ {
+ cert->excluded_names->insert_last(cert->excluded_names,
+ constraint->clone(constraint));
+ }
+ enumerator->destroy(enumerator);
+ continue;
+ }
+ case BUILD_CERTIFICATE_POLICIES:
+ {
+ enumerator_t *enumerator;
+ linked_list_t *list;
+ x509_cert_policy_t *policy, *in;
+
+ list = va_arg(args, linked_list_t*);
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &in))
+ {
+ INIT(policy,
+ .oid = chunk_clone(in->oid),
+ .cps_uri = strdupnull(in->cps_uri),
+ .unotice_text = strdupnull(in->unotice_text),
+ );
+ cert->cert_policies->insert_last(cert->cert_policies, policy);
+ }
+ enumerator->destroy(enumerator);
+ continue;
+ }
+ case BUILD_POLICY_MAPPINGS:
+ {
+ enumerator_t *enumerator;
+ linked_list_t *list;
+ x509_policy_mapping_t* mapping, *in;
+
+ list = va_arg(args, linked_list_t*);
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &in))
{
- cert->pathLenConstraint = X509_NO_PATH_LEN_CONSTRAINT;
+ INIT(mapping,
+ .issuer = chunk_clone(in->issuer),
+ .subject = chunk_clone(in->subject),
+ );
+ cert->policy_mappings->insert_last(cert->policy_mappings,
+ mapping);
}
+ enumerator->destroy(enumerator);
+ continue;
+ }
+ case BUILD_POLICY_REQUIRE_EXPLICIT:
+ constraint = va_arg(args, u_int);
+ cert->require_explicit = (constraint < 128) ?
+ constraint : X509_NO_CONSTRAINT;
+ continue;
+ case BUILD_POLICY_INHIBIT_MAPPING:
+ constraint = va_arg(args, u_int);
+ cert->inhibit_mapping = (constraint < 128) ?
+ constraint : X509_NO_CONSTRAINT;
+ continue;
+ case BUILD_POLICY_INHIBIT_ANY:
+ constraint = va_arg(args, u_int);
+ cert->inhibit_any = (constraint < 128) ?
+ constraint : X509_NO_CONSTRAINT;
continue;
case BUILD_NOT_BEFORE_TIME:
cert->notBefore = va_arg(args, time_t);
diff --git a/src/libstrongswan/plugins/x509/x509_crl.c b/src/libstrongswan/plugins/x509/x509_crl.c
index 4bd0470d3..758505ab5 100644
--- a/src/libstrongswan/plugins/x509/x509_crl.c
+++ b/src/libstrongswan/plugins/x509/x509_crl.c
@@ -100,6 +100,11 @@ struct private_x509_crl_t {
linked_list_t *revoked;
/**
+ * List of Freshest CRL distribution points
+ */
+ linked_list_t *crl_uris;
+
+ /**
* Authority Key Identifier
*/
chunk_t authKeyIdentifier;
@@ -110,6 +115,11 @@ struct private_x509_crl_t {
chunk_t authKeySerialNumber;
/**
+ * Number of BaseCRL, if a delta CRL
+ */
+ chunk_t baseCrlNumber;
+
+ /**
* Signature algorithm
*/
int algorithm;
@@ -133,9 +143,19 @@ struct private_x509_crl_t {
/**
* from x509_cert
*/
-extern chunk_t x509_parse_authorityKeyIdentifier(
- chunk_t blob, int level0,
- chunk_t *authKeySerialNumber);
+extern chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, int level0,
+ chunk_t *authKeySerialNumber);
+
+/**
+ * from x509_cert
+ */
+extern void x509_parse_crlDistributionPoints(chunk_t blob, int level0,
+ linked_list_t *list);
+
+/**
+ * from x509_cert
+ */
+extern chunk_t x509_build_crlDistributionPoints(linked_list_t *list, int extn);
/**
* ASN.1 definition of an X.509 certificate revocation list
@@ -206,7 +226,7 @@ static bool parse(private_x509_crl_t *this)
int objectID;
int sig_alg = OID_UNKNOWN;
bool success = FALSE;
- bool critical;
+ bool critical = FALSE;
revoked_t *revoked = NULL;
parser = asn1_parser_create(crlObjects, this->encoding);
@@ -258,35 +278,61 @@ static bool parse(private_x509_crl_t *this)
break;
case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
case CRL_OBJ_EXTN_VALUE:
- {
- int extn_oid = asn1_known_oid(extnID);
+ {
+ int extn_oid = asn1_known_oid(extnID);
- if (revoked && extn_oid == OID_CRL_REASON_CODE)
- {
- if (*object.ptr == ASN1_ENUMERATED &&
- asn1_length(&object) == 1)
+ switch (extn_oid)
+ {
+ case OID_CRL_REASON_CODE:
+ if (revoked)
{
- revoked->reason = *object.ptr;
+ if (object.len && *object.ptr == ASN1_ENUMERATED &&
+ asn1_length(&object) == 1)
+ {
+ revoked->reason = *object.ptr;
+ }
+ DBG2(DBG_LIB, " '%N'", crl_reason_names,
+ revoked->reason);
}
- DBG2(DBG_LIB, " '%N'", crl_reason_names,
- revoked->reason);
- }
- else if (extn_oid == OID_AUTHORITY_KEY_ID)
- {
- this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object,
- level, &this->authKeySerialNumber);
- }
- else if (extn_oid == OID_CRL_NUMBER)
- {
+ break;
+ case OID_AUTHORITY_KEY_ID:
+ this->authKeyIdentifier =
+ x509_parse_authorityKeyIdentifier(
+ object, level, &this->authKeySerialNumber);
+ break;
+ case OID_CRL_NUMBER:
if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
level, "crlNumber"))
{
goto end;
}
this->crlNumber = object;
- }
+ break;
+ case OID_FRESHEST_CRL:
+ x509_parse_crlDistributionPoints(object, level,
+ this->crl_uris);
+ break;
+ case OID_DELTA_CRL_INDICATOR:
+ if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
+ level, "deltaCrlIndicator"))
+ {
+ goto end;
+ }
+ this->baseCrlNumber = object;
+ break;
+ default:
+ if (critical && lib->settings->get_bool(lib->settings,
+ "libstrongswan.x509.enforce_critical", TRUE))
+ {
+ DBG1(DBG_LIB, "critical '%s' extension not supported",
+ (extn_oid == OID_UNKNOWN) ? "unknown" :
+ (char*)oid_names[extn_oid].name);
+ goto end;
+ }
+ break;
}
break;
+ }
case CRL_OBJ_ALGORITHM:
{
this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
@@ -344,6 +390,26 @@ METHOD(crl_t, get_authKeyIdentifier, chunk_t,
return this->authKeyIdentifier;
}
+METHOD(crl_t, is_delta_crl, bool,
+ private_x509_crl_t *this, chunk_t *base_crl)
+{
+ if (this->baseCrlNumber.len)
+ {
+ if (base_crl)
+ {
+ *base_crl = this->baseCrlNumber;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+METHOD(crl_t, create_delta_crl_uri_enumerator, enumerator_t*,
+ private_x509_crl_t *this)
+{
+ return this->crl_uris->create_enumerator(this->crl_uris);
+}
+
METHOD(crl_t, create_enumerator, enumerator_t*,
private_x509_crl_t *this)
{
@@ -388,7 +454,7 @@ METHOD(certificate_t, issued_by, bool,
{
return FALSE;
}
- if (!(x509->get_flags(x509) & X509_CA))
+ if (!(x509->get_flags(x509) & (X509_CA | X509_CRL_SIGN)))
{
return FALSE;
}
@@ -501,18 +567,30 @@ static void revoked_destroy(revoked_t *revoked)
free(revoked);
}
+/**
+ * Destroy a CDP entry
+ */
+static void cdp_destroy(x509_cdp_t *this)
+{
+ free(this->uri);
+ DESTROY_IF(this->issuer);
+ free(this);
+}
+
METHOD(certificate_t, destroy, void,
private_x509_crl_t *this)
{
if (ref_put(&this->ref))
{
this->revoked->destroy_function(this->revoked, (void*)revoked_destroy);
+ this->crl_uris->destroy_function(this->crl_uris, (void*)cdp_destroy);
DESTROY_IF(this->issuer);
free(this->authKeyIdentifier.ptr);
free(this->encoding.ptr);
if (this->generated)
{
free(this->crlNumber.ptr);
+ free(this->baseCrlNumber.ptr);
free(this->signature.ptr);
free(this->tbsCertList.ptr);
}
@@ -546,10 +624,13 @@ static private_x509_crl_t* create_empty(void)
},
.get_serial = _get_serial,
.get_authKeyIdentifier = _get_authKeyIdentifier,
+ .is_delta_crl = _is_delta_crl,
+ .create_delta_crl_uri_enumerator = _create_delta_crl_uri_enumerator,
.create_enumerator = _create_enumerator,
},
},
.revoked = linked_list_create(),
+ .crl_uris = linked_list_create(),
.ref = 1,
);
return this;
@@ -618,6 +699,7 @@ static bool generate(private_x509_crl_t *this, certificate_t *cert,
private_key_t *key, hash_algorithm_t digest_alg)
{
chunk_t extensions = chunk_empty, certList = chunk_empty, serial;
+ chunk_t crlDistributionPoints = chunk_empty, baseCrlNumber = chunk_empty;
enumerator_t *enumerator;
crl_reason_t reason;
time_t date;
@@ -625,7 +707,7 @@ static bool generate(private_x509_crl_t *this, certificate_t *cert,
x509 = (x509_t*)cert;
- this->issuer = cert->get_issuer(cert);
+ this->issuer = cert->get_subject(cert);
this->issuer = this->issuer->clone(this->issuer);
this->authKeyIdentifier = chunk_clone(x509->get_subjectKeyIdentifier(x509));
@@ -660,8 +742,21 @@ static bool generate(private_x509_crl_t *this, certificate_t *cert,
}
enumerator->destroy(enumerator);
+ crlDistributionPoints = x509_build_crlDistributionPoints(this->crl_uris,
+ OID_FRESHEST_CRL);
+
+ if (this->baseCrlNumber.len)
+ {
+ baseCrlNumber = asn1_wrap(ASN1_SEQUENCE, "mmm",
+ asn1_build_known_oid(OID_DELTA_CRL_INDICATOR),
+ asn1_wrap(ASN1_BOOLEAN, "c",
+ chunk_from_chars(0xFF)),
+ asn1_wrap(ASN1_OCTET_STRING, "m",
+ asn1_integer("c", this->baseCrlNumber)));
+ }
+
extensions = asn1_wrap(ASN1_CONTEXT_C_0, "m",
- asn1_wrap(ASN1_SEQUENCE, "mm",
+ asn1_wrap(ASN1_SEQUENCE, "mmmm",
asn1_wrap(ASN1_SEQUENCE, "mm",
asn1_build_known_oid(OID_AUTHORITY_KEY_ID),
asn1_wrap(ASN1_OCTET_STRING, "m",
@@ -671,9 +766,8 @@ static bool generate(private_x509_crl_t *this, certificate_t *cert,
asn1_wrap(ASN1_SEQUENCE, "mm",
asn1_build_known_oid(OID_CRL_NUMBER),
asn1_wrap(ASN1_OCTET_STRING, "m",
- asn1_integer("c", this->crlNumber))
- )
- ));
+ asn1_integer("c", this->crlNumber))),
+ crlDistributionPoints, baseCrlNumber));
this->tbsCertList = asn1_wrap(ASN1_SEQUENCE, "cmcmmmm",
ASN1_INTEGER_1,
@@ -736,6 +830,29 @@ x509_crl_t *x509_crl_gen(certificate_type_t type, va_list args)
case BUILD_REVOKED_ENUMERATOR:
read_revoked(crl, va_arg(args, enumerator_t*));
continue;
+ case BUILD_BASE_CRL:
+ crl->baseCrlNumber = va_arg(args, chunk_t);
+ crl->baseCrlNumber = chunk_clone(crl->baseCrlNumber);
+ break;
+ case BUILD_CRL_DISTRIBUTION_POINTS:
+ {
+ enumerator_t *enumerator;
+ linked_list_t *list;
+ x509_cdp_t *in, *cdp;
+
+ list = va_arg(args, linked_list_t*);
+ enumerator = list->create_enumerator(list);
+ while (enumerator->enumerate(enumerator, &in))
+ {
+ INIT(cdp,
+ .uri = strdup(in->uri),
+ .issuer = in->issuer ? in->issuer->clone(in->issuer) : NULL,
+ );
+ crl->crl_uris->insert_last(crl->crl_uris, cdp);
+ }
+ enumerator->destroy(enumerator);
+ continue;
+ }
case BUILD_END:
break;
default:
diff --git a/src/libstrongswan/plugins/x509/x509_plugin.c b/src/libstrongswan/plugins/x509/x509_plugin.c
index 11a7f023c..d40cc3567 100644
--- a/src/libstrongswan/plugins/x509/x509_plugin.c
+++ b/src/libstrongswan/plugins/x509/x509_plugin.c
@@ -36,10 +36,8 @@ struct private_x509_plugin_t {
x509_plugin_t public;
};
-/**
- * Implementation of x509_plugin_t.x509troy
- */
-static void destroy(private_x509_plugin_t *this)
+METHOD(plugin_t, destroy, void,
+ private_x509_plugin_t *this)
{
lib->creds->remove_builder(lib->creds,
(builder_function_t)x509_cert_gen);
@@ -69,9 +67,15 @@ static void destroy(private_x509_plugin_t *this)
*/
plugin_t *x509_plugin_create()
{
- private_x509_plugin_t *this = malloc_thing(private_x509_plugin_t);
+ private_x509_plugin_t *this;
- this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
+ INIT(this,
+ .public = {
+ .plugin = {
+ .destroy = _destroy,
+ },
+ },
+ );
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509, FALSE,
(builder_function_t)x509_cert_gen);