diff options
Diffstat (limited to 'src/libstrongswan/credentials')
10 files changed, 1107 insertions, 39 deletions
diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index 9988d8021..956ce08c9 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2015 Tobias Brunner + * Copyright (C) 2008-2016 Tobias Brunner * Copyright (C) 2007-2009 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -46,11 +46,13 @@ ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_AC_CERT, "RULE_SUBJECT_CERT", "RULE_CRL_VALIDATION", "RULE_OCSP_VALIDATION", + "RULE_CERT_VALIDATION_SUSPENDED", "RULE_GROUP", "RULE_RSA_STRENGTH", "RULE_ECDSA_STRENGTH", "RULE_BLISS_STRENGTH", "RULE_SIGNATURE_SCHEME", + "RULE_IKE_SIGNATURE_SCHEME", "RULE_CERT_POLICY", "HELPER_IM_CERT", "HELPER_SUBJECT_CERT", @@ -79,6 +81,7 @@ static inline bool is_multi_value_rule(auth_rule_t type) case AUTH_RULE_AAA_IDENTITY: case AUTH_RULE_XAUTH_IDENTITY: case AUTH_RULE_XAUTH_BACKEND: + case AUTH_RULE_CERT_VALIDATION_SUSPENDED: case AUTH_HELPER_SUBJECT_CERT: case AUTH_HELPER_SUBJECT_HASH_URL: case AUTH_RULE_MAX: @@ -91,6 +94,7 @@ static inline bool is_multi_value_rule(auth_rule_t type) case AUTH_RULE_IM_CERT: case AUTH_RULE_CERT_POLICY: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: case AUTH_HELPER_IM_CERT: case AUTH_HELPER_IM_HASH_URL: case AUTH_HELPER_REVOCATION_CERT: @@ -211,6 +215,8 @@ static void init_entry(entry_t *this, auth_rule_t type, va_list args) case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_BLISS_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: + case AUTH_RULE_CERT_VALIDATION_SUSPENDED: /* integer type */ this->value = (void*)(uintptr_t)va_arg(args, u_int); break; @@ -260,6 +266,8 @@ static bool entry_equals(entry_t *e1, entry_t *e2) case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_BLISS_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: + case AUTH_RULE_CERT_VALIDATION_SUSPENDED: { return e1->value == e2->value; } @@ -351,6 +359,8 @@ static void destroy_entry_value(entry_t *entry) case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_BLISS_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: + case AUTH_RULE_CERT_VALIDATION_SUSPENDED: case AUTH_RULE_MAX: break; } @@ -383,6 +393,8 @@ static void replace(private_auth_cfg_t *this, entry_enumerator_t *enumerator, case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_BLISS_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: + case AUTH_RULE_CERT_VALIDATION_SUSPENDED: /* integer type */ entry->value = (void*)(uintptr_t)va_arg(args, u_int); break; @@ -459,11 +471,13 @@ METHOD(auth_cfg_t, get, void*, case AUTH_RULE_BLISS_STRENGTH: return (void*)0; case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: return (void*)HASH_UNKNOWN; case AUTH_RULE_CRL_VALIDATION: case AUTH_RULE_OCSP_VALIDATION: return (void*)VALIDATION_FAILED; case AUTH_RULE_IDENTITY_LOOSE: + case AUTH_RULE_CERT_VALIDATION_SUSPENDED: return (void*)FALSE; case AUTH_RULE_IDENTITY: case AUTH_RULE_EAP_IDENTITY: @@ -510,6 +524,183 @@ static void add(private_auth_cfg_t *this, auth_rule_t type, ...) } } +METHOD(auth_cfg_t, add_pubkey_constraints, void, + private_auth_cfg_t *this, char* constraints, bool ike) +{ + enumerator_t *enumerator; + bool is_ike = FALSE, ike_added = FALSE; + key_type_t expected_type = -1; + auth_rule_t expected_strength = AUTH_RULE_MAX; + int strength; + char *token; + auth_rule_t type; + void *value; + + enumerator = enumerator_create_token(constraints, "-", ""); + while (enumerator->enumerate(enumerator, &token)) + { + bool found = FALSE; + int i; + struct { + char *name; + signature_scheme_t scheme; + key_type_t key; + } schemes[] = { + { "md5", SIGN_RSA_EMSA_PKCS1_MD5, KEY_RSA, }, + { "sha1", SIGN_RSA_EMSA_PKCS1_SHA1, KEY_RSA, }, + { "sha224", SIGN_RSA_EMSA_PKCS1_SHA224, KEY_RSA, }, + { "sha256", SIGN_RSA_EMSA_PKCS1_SHA256, KEY_RSA, }, + { "sha384", SIGN_RSA_EMSA_PKCS1_SHA384, KEY_RSA, }, + { "sha512", SIGN_RSA_EMSA_PKCS1_SHA512, KEY_RSA, }, + { "sha1", SIGN_ECDSA_WITH_SHA1_DER, KEY_ECDSA, }, + { "sha256", SIGN_ECDSA_WITH_SHA256_DER, KEY_ECDSA, }, + { "sha384", SIGN_ECDSA_WITH_SHA384_DER, KEY_ECDSA, }, + { "sha512", SIGN_ECDSA_WITH_SHA512_DER, KEY_ECDSA, }, + { "sha256", SIGN_ECDSA_256, KEY_ECDSA, }, + { "sha384", SIGN_ECDSA_384, KEY_ECDSA, }, + { "sha512", SIGN_ECDSA_521, KEY_ECDSA, }, + { "sha256", SIGN_BLISS_WITH_SHA2_256, KEY_BLISS, }, + { "sha384", SIGN_BLISS_WITH_SHA2_384, KEY_BLISS, }, + { "sha512", SIGN_BLISS_WITH_SHA2_512, KEY_BLISS, }, + }; + + if (expected_strength != AUTH_RULE_MAX) + { /* expecting a key strength token */ + strength = atoi(token); + if (strength) + { + add(this, expected_strength, (uintptr_t)strength); + } + expected_strength = AUTH_RULE_MAX; + if (strength) + { + continue; + } + } + if (streq(token, "rsa") || streq(token, "ike:rsa")) + { + expected_type = KEY_RSA; + expected_strength = AUTH_RULE_RSA_STRENGTH; + is_ike = strpfx(token, "ike:"); + continue; + } + if (streq(token, "ecdsa") || streq(token, "ike:ecdsa")) + { + expected_type = KEY_ECDSA; + expected_strength = AUTH_RULE_ECDSA_STRENGTH; + is_ike = strpfx(token, "ike:"); + continue; + } + if (streq(token, "bliss") || streq(token, "ike:bliss")) + { + expected_type = KEY_BLISS; + expected_strength = AUTH_RULE_BLISS_STRENGTH; + is_ike = strpfx(token, "ike:"); + continue; + } + if (streq(token, "pubkey") || streq(token, "ike:pubkey")) + { + expected_type = KEY_ANY; + is_ike = strpfx(token, "ike:"); + continue; + } + if (is_ike && !ike) + { + continue; + } + + for (i = 0; i < countof(schemes); i++) + { + if (streq(schemes[i].name, token)) + { + if (expected_type == KEY_ANY || expected_type == schemes[i].key) + { + if (is_ike) + { + add(this, AUTH_RULE_IKE_SIGNATURE_SCHEME, + (uintptr_t)schemes[i].scheme); + ike_added = TRUE; + } + else + { + add(this, AUTH_RULE_SIGNATURE_SCHEME, + (uintptr_t)schemes[i].scheme); + } + } + found = TRUE; + } + } + if (!found) + { + DBG1(DBG_CFG, "ignoring invalid auth token: '%s'", token); + } + } + enumerator->destroy(enumerator); + + /* if no explicit IKE signature contraints were added we add them for all + * configured signature contraints */ + if (ike && !ike_added && + lib->settings->get_bool(lib->settings, + "%s.signature_authentication_constraints", TRUE, + lib->ns)) + { + enumerator = create_enumerator(this); + while (enumerator->enumerate(enumerator, &type, &value)) + { + if (type == AUTH_RULE_SIGNATURE_SCHEME) + { + add(this, AUTH_RULE_IKE_SIGNATURE_SCHEME, + (uintptr_t)value); + } + } + enumerator->destroy(enumerator); + } +} + +/** + * Check if signature schemes of a specific type are compliant + */ +static bool complies_scheme(private_auth_cfg_t *this, auth_cfg_t *constraints, + auth_rule_t type, bool log_error) +{ + enumerator_t *e1, *e2; + auth_rule_t t1, t2; + signature_scheme_t scheme; + void *value; + bool success = TRUE; + + e2 = create_enumerator(this); + while (e2->enumerate(e2, &t2, &scheme)) + { + if (t2 == type) + { + success = FALSE; + e1 = constraints->create_enumerator(constraints); + while (e1->enumerate(e1, &t1, &value)) + { + if (t1 == type && (uintptr_t)value == scheme) + { + success = TRUE; + break; + } + } + e1->destroy(e1); + if (!success) + { + if (log_error) + { + DBG1(DBG_CFG, "%s signature scheme %N not acceptable", + AUTH_RULE_SIGNATURE_SCHEME == type ? "X.509" : "IKE", + signature_scheme_names, (int)scheme); + } + break; + } + } + } + e2->destroy(e2); + return success; +} + METHOD(auth_cfg_t, complies, bool, private_auth_cfg_t *this, auth_cfg_t *constraints, bool log_error) { @@ -518,7 +709,7 @@ METHOD(auth_cfg_t, complies, bool, bool ca_match = FALSE, cert_match = FALSE; identification_t *require_group = NULL; certificate_t *require_ca = NULL, *require_cert = NULL; - signature_scheme_t scheme = SIGN_UNKNOWN; + signature_scheme_t ike_scheme = SIGN_UNKNOWN, scheme = SIGN_UNKNOWN; u_int strength = 0; auth_rule_t t1, t2; char *key_type; @@ -573,6 +764,11 @@ METHOD(auth_cfg_t, complies, bool, { uintptr_t validated; + if (get(this, AUTH_RULE_CERT_VALIDATION_SUSPENDED)) + { /* skip validation, may happen later */ + break; + } + e2 = create_enumerator(this); while (e2->enumerate(e2, &t2, &validated)) { @@ -714,6 +910,11 @@ METHOD(auth_cfg_t, complies, bool, strength = (uintptr_t)value; break; } + case AUTH_RULE_IKE_SIGNATURE_SCHEME: + { + ike_scheme = (uintptr_t)value; + break; + } case AUTH_RULE_SIGNATURE_SCHEME: { scheme = (uintptr_t)value; @@ -745,6 +946,8 @@ METHOD(auth_cfg_t, complies, bool, /* just an indication when verifying AUTH_RULE_IDENTITY */ case AUTH_RULE_XAUTH_BACKEND: /* not enforced, just a hint for local authentication */ + case AUTH_RULE_CERT_VALIDATION_SUSPENDED: + /* not a constraint */ case AUTH_HELPER_IM_CERT: case AUTH_HELPER_SUBJECT_CERT: case AUTH_HELPER_IM_HASH_URL: @@ -766,35 +969,13 @@ METHOD(auth_cfg_t, complies, bool, * signature schemes. */ if (success && scheme != SIGN_UNKNOWN) { - e2 = create_enumerator(this); - while (e2->enumerate(e2, &t2, &scheme)) - { - if (t2 == AUTH_RULE_SIGNATURE_SCHEME) - { - success = FALSE; - e1 = constraints->create_enumerator(constraints); - while (e1->enumerate(e1, &t1, &value)) - { - if (t1 == AUTH_RULE_SIGNATURE_SCHEME && - (uintptr_t)value == scheme) - { - success = TRUE; - break; - } - } - e1->destroy(e1); - if (!success) - { - if (log_error) - { - DBG1(DBG_CFG, "signature scheme %N not acceptable", - signature_scheme_names, (int)scheme); - } - break; - } - } - } - e2->destroy(e2); + success = complies_scheme(this, constraints, + AUTH_RULE_SIGNATURE_SCHEME, log_error); + } + if (success && ike_scheme != SIGN_UNKNOWN) + { + success = complies_scheme(this, constraints, + AUTH_RULE_IKE_SIGNATURE_SCHEME, log_error); } /* Check if we have a matching constraint (or none at all) for used @@ -918,6 +1099,8 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_BLISS_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: + case AUTH_RULE_CERT_VALIDATION_SUSPENDED: { add(this, type, (uintptr_t)value); break; @@ -1088,6 +1271,8 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_BLISS_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: + case AUTH_RULE_IKE_SIGNATURE_SCHEME: + case AUTH_RULE_CERT_VALIDATION_SUSPENDED: clone->add(clone, type, (uintptr_t)value); break; case AUTH_RULE_MAX: @@ -1116,6 +1301,7 @@ auth_cfg_t *auth_cfg_create() INIT(this, .public = { .add = (void(*)(auth_cfg_t*, auth_rule_t type, ...))add, + .add_pubkey_constraints = _add_pubkey_constraints, .get = _get, .create_enumerator = _create_enumerator, .replace = (void(*)(auth_cfg_t*,enumerator_t*,auth_rule_t,...))replace, diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h index 53f1b3805..6940069de 100644 --- a/src/libstrongswan/credentials/auth_cfg.h +++ b/src/libstrongswan/credentials/auth_cfg.h @@ -94,6 +94,8 @@ enum auth_rule_t { AUTH_RULE_CRL_VALIDATION, /** result of a OCSP validation, cert_validation_t */ AUTH_RULE_OCSP_VALIDATION, + /** CRL/OCSP validation is disabled, bool */ + AUTH_RULE_CERT_VALIDATION_SUSPENDED, /** subject is member of a group, identification_t* * The group membership constraint is fulfilled if the subject is member of * one group defined in the constraints. */ @@ -106,6 +108,8 @@ enum auth_rule_t { AUTH_RULE_BLISS_STRENGTH, /** required signature scheme, signature_scheme_t */ AUTH_RULE_SIGNATURE_SCHEME, + /** required signature scheme for IKE authentication, signature_scheme_t */ + AUTH_RULE_IKE_SIGNATURE_SCHEME, /** certificatePolicy constraint, numerical OID as char* */ AUTH_RULE_CERT_POLICY, @@ -182,6 +186,15 @@ struct auth_cfg_t { void (*add)(auth_cfg_t *this, auth_rule_t rule, ...); /** + * Add public key and signature scheme constraints to the set. + * + * @param constraints constraints string (e.g. "rsa-sha384") + * @param ike whether to add/parse constraints for IKE signatures + */ + void (*add_pubkey_constraints)(auth_cfg_t *this, char *constraints, + bool ike); + + /** * Get a rule value. * * For rules we expect only once the latest value is returned. diff --git a/src/libstrongswan/credentials/certificates/certificate.c b/src/libstrongswan/credentials/certificates/certificate.c index b281c1669..761082986 100644 --- a/src/libstrongswan/credentials/certificates/certificate.c +++ b/src/libstrongswan/credentials/certificates/certificate.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil + * Copyright (C) 2015 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -22,10 +23,10 @@ ENUM(certificate_type_names, CERT_ANY, CERT_GPG, "ANY", "X509", "X509_CRL", - "X509_OCSP_REQUEST", - "X509_OCSP_RESPONSE", + "OCSP_REQUEST", + "OCSP_RESPONSE", "X509_AC", - "TRUSTED_PUBKEY", + "PUBKEY", "PKCS10_REQUEST", "PGP", ); diff --git a/src/libstrongswan/credentials/certificates/certificate_printer.c b/src/libstrongswan/credentials/certificates/certificate_printer.c new file mode 100644 index 000000000..c618e80bf --- /dev/null +++ b/src/libstrongswan/credentials/certificates/certificate_printer.c @@ -0,0 +1,753 @@ +/* + * Copyright (C) 2015 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "certificate_printer.h" +#include "credentials/certificates/x509.h" +#include "credentials/certificates/crl.h" +#include "credentials/certificates/ac.h" +#include "credentials/certificates/ocsp_response.h" +#include "credentials/certificates/pgp_certificate.h" + +#include <asn1/asn1.h> +#include <asn1/oid.h> +#include <selectors/traffic_selector.h> + +#include <time.h> + +typedef struct private_certificate_printer_t private_certificate_printer_t; + +/** + * Private data of an certificate_printer_t object. + */ +struct private_certificate_printer_t { + + /** + * Public certificate_printer_t interface. + */ + certificate_printer_t public; + + /** + * File to print to + */ + FILE *f; + + /** + * Print detailed certificate information + */ + bool detailed; + + /** + * Print time information in UTC + */ + bool utc; + + /** + * Previous certificate type + */ + certificate_type_t type; + + /** + * Previous X.509 certificate flag + */ + x509_flag_t flag; + +}; + +/** + * Print X509 specific certificate information + */ +static void print_x509(private_certificate_printer_t *this, x509_t *x509) +{ + enumerator_t *enumerator; + identification_t *id; + traffic_selector_t *block; + chunk_t chunk; + bool first; + char *uri; + int len, explicit, inhibit; + x509_flag_t flags; + x509_cdp_t *cdp; + x509_cert_policy_t *policy; + x509_policy_mapping_t *mapping; + FILE *f = this->f; + + chunk = chunk_skip_zero(x509->get_serial(x509)); + fprintf(f, " serial: %#B\n", &chunk); + + first = TRUE; + enumerator = x509->create_subjectAltName_enumerator(x509); + while (enumerator->enumerate(enumerator, &id)) + { + if (first) + { + fprintf(f, " altNames: "); + first = FALSE; + } + else + { + fprintf(f, ", "); + } + fprintf(f, "%Y", id); + } + if (!first) + { + fprintf(f, "\n"); + } + enumerator->destroy(enumerator); + + if (this->detailed) + { + flags = x509->get_flags(x509); + if (flags != X509_NONE) + { + fprintf(f, " flags: "); + if (flags & X509_CA) + { + fprintf(f, "CA "); + } + if (flags & X509_CRL_SIGN) + { + fprintf(f, "CRLSign "); + } + if (flags & X509_OCSP_SIGNER) + { + fprintf(f, "ocspSigning "); + } + if (flags & X509_SERVER_AUTH) + { + fprintf(f, "serverAuth "); + } + if (flags & X509_CLIENT_AUTH) + { + fprintf(f, "clientAuth "); + } + if (flags & X509_IKE_INTERMEDIATE) + { + fprintf(f, "ikeIntermediate "); + } + if (flags & X509_MS_SMARTCARD_LOGON) + { + fprintf(f, "msSmartcardLogon"); + } + if (flags & X509_SELF_SIGNED) + { + fprintf(f, "self-signed "); + } + fprintf(f, "\n"); + } + + first = TRUE; + enumerator = x509->create_crl_uri_enumerator(x509); + while (enumerator->enumerate(enumerator, &cdp)) + { + if (first) + { + fprintf(f, " CRL URIs: %s", cdp->uri); + first = FALSE; + } + else + { + fprintf(f, " %s", cdp->uri); + } + if (cdp->issuer) + { + fprintf(f, " (CRL issuer: %Y)", cdp->issuer); + } + fprintf(f, "\n"); + } + enumerator->destroy(enumerator); + + first = TRUE; + enumerator = x509->create_ocsp_uri_enumerator(x509); + while (enumerator->enumerate(enumerator, &uri)) + { + if (first) + { + fprintf(f, " OCSP URIs: %s\n", uri); + first = FALSE; + } + else + { + fprintf(f, " %s\n", uri); + } + } + enumerator->destroy(enumerator); + + len = x509->get_constraint(x509, X509_PATH_LEN); + if (len != X509_NO_CONSTRAINT) + { + fprintf(f, " pathlen: %d\n", len); + } + + first = TRUE; + enumerator = x509->create_name_constraint_enumerator(x509, TRUE); + while (enumerator->enumerate(enumerator, &id)) + { + if (first) + { + fprintf(f, " permitted nameConstraints:\n"); + first = FALSE; + } + fprintf(f, " %Y\n", id); + } + enumerator->destroy(enumerator); + + first = TRUE; + enumerator = x509->create_name_constraint_enumerator(x509, FALSE); + while (enumerator->enumerate(enumerator, &id)) + { + if (first) + { + fprintf(f, " excluded nameConstraints:\n"); + first = FALSE; + } + fprintf(f, " %Y\n", id); + } + enumerator->destroy(enumerator); + + first = TRUE; + enumerator = x509->create_cert_policy_enumerator(x509); + while (enumerator->enumerate(enumerator, &policy)) + { + char *oid; + + if (first) + { + fprintf(f, " certificatePolicies:\n"); + first = FALSE; + } + oid = asn1_oid_to_string(policy->oid); + if (oid) + { + fprintf(f, " %s\n", oid); + free(oid); + } + else + { + fprintf(f, " %#B\n", &policy->oid); + } + if (policy->cps_uri) + { + fprintf(f, " CPS: %s\n", policy->cps_uri); + } + if (policy->unotice_text) + { + fprintf(f, " Notice: %s\n", policy->unotice_text); + } + } + enumerator->destroy(enumerator); + + first = TRUE; + enumerator = x509->create_policy_mapping_enumerator(x509); + while (enumerator->enumerate(enumerator, &mapping)) + { + char *issuer_oid, *subject_oid; + + if (first) + { + fprintf(f, " policyMappings:\n"); + first = FALSE; + } + issuer_oid = asn1_oid_to_string(mapping->issuer); + subject_oid = asn1_oid_to_string(mapping->subject); + fprintf(f, " %s => %s\n", issuer_oid, subject_oid); + free(issuer_oid); + free(subject_oid); + } + enumerator->destroy(enumerator); + + explicit = x509->get_constraint(x509, X509_REQUIRE_EXPLICIT_POLICY); + inhibit = x509->get_constraint(x509, X509_INHIBIT_POLICY_MAPPING); + len = x509->get_constraint(x509, X509_INHIBIT_ANY_POLICY); + + if (explicit != X509_NO_CONSTRAINT || inhibit != X509_NO_CONSTRAINT || + len != X509_NO_CONSTRAINT) + { + fprintf(f, " policyConstraints:\n"); + if (explicit != X509_NO_CONSTRAINT) + { + fprintf(f, " requireExplicitPolicy: %d\n", explicit); + } + if (inhibit != X509_NO_CONSTRAINT) + { + fprintf(f, " inhibitPolicyMapping: %d\n", inhibit); + } + if (len != X509_NO_CONSTRAINT) + { + fprintf(f, " inhibitAnyPolicy: %d\n", len); + } + } + + if (x509->get_flags(x509) & X509_IP_ADDR_BLOCKS) + { + first = TRUE; + fprintf(f, " addresses: "); + enumerator = x509->create_ipAddrBlock_enumerator(x509); + while (enumerator->enumerate(enumerator, &block)) + { + if (first) + { + first = FALSE; + } + else + { + fprintf(f, ", "); + } + fprintf(f, "%R", block); + } + enumerator->destroy(enumerator); + fprintf(f, "\n"); + } + } + + chunk = x509->get_authKeyIdentifier(x509); + if (chunk.ptr) + { + fprintf(f, " authkeyId: %#B\n", &chunk); + } + + chunk = x509->get_subjectKeyIdentifier(x509); + if (chunk.ptr) + { + fprintf(f, " subjkeyId: %#B\n", &chunk); + } +} + +/** + * Print CRL specific information + */ +static void print_crl(private_certificate_printer_t *this, crl_t *crl) +{ + enumerator_t *enumerator; + time_t ts; + crl_reason_t reason; + chunk_t chunk; + int count = 0; + bool first; + x509_cdp_t *cdp; + FILE *f = this->f; + + chunk = chunk_skip_zero(crl->get_serial(crl)); + fprintf(f, " serial: %#B\n", &chunk); + + if (crl->is_delta_crl(crl, &chunk)) + { + chunk = chunk_skip_zero(chunk); + fprintf(f, " delta CRL: for serial %#B\n", &chunk); + } + chunk = crl->get_authKeyIdentifier(crl); + fprintf(f, " authKeyId: %#B\n", &chunk); + + first = TRUE; + enumerator = crl->create_delta_crl_uri_enumerator(crl); + while (enumerator->enumerate(enumerator, &cdp)) + { + if (first) + { + fprintf(f, " freshest: %s", cdp->uri); + first = FALSE; + } + else + { + fprintf(f, " %s", cdp->uri); + } + if (cdp->issuer) + { + fprintf(f, " (CRL issuer: %Y)", cdp->issuer); + } + fprintf(f, "\n"); + } + enumerator->destroy(enumerator); + + enumerator = crl->create_enumerator(crl); + while (enumerator->enumerate(enumerator, &chunk, &ts, &reason)) + { + count++; + } + enumerator->destroy(enumerator); + + fprintf(f, " %d revoked certificate%s%s\n", count, (count == 1) ? "" : "s", + (count && this->detailed) ? ":" : ""); + + if (this->detailed) + { + enumerator = crl->create_enumerator(crl); + while (enumerator->enumerate(enumerator, &chunk, &ts, &reason)) + { + chunk = chunk_skip_zero(chunk); + fprintf(f, " %#B: %T, %N\n", &chunk, &ts, this->utc, + crl_reason_names, reason); + } + enumerator->destroy(enumerator); + } +} + +/** + * Print AC specific information + */ +static void print_ac(private_certificate_printer_t *this, ac_t *ac) +{ + ac_group_type_t type; + identification_t *id; + enumerator_t *groups; + chunk_t chunk; + bool first = TRUE; + FILE *f = this->f; + + chunk = chunk_skip_zero(ac->get_serial(ac)); + fprintf(f, " serial: %#B\n", &chunk); + + id = ac->get_holderIssuer(ac); + if (id) + { + fprintf(f, " hissuer: \"%Y\"\n", id); + } + chunk = chunk_skip_zero(ac->get_holderSerial(ac)); + if (chunk.ptr) + { + fprintf(f, " hserial: %#B\n", &chunk); + } + groups = ac->create_group_enumerator(ac); + while (groups->enumerate(groups, &type, &chunk)) + { + int oid; + char *str; + + if (first) + { + fprintf(f, " groups: "); + first = FALSE; + } + else + { + fprintf(f, " "); + } + switch (type) + { + case AC_GROUP_TYPE_STRING: + fprintf(f, "%.*s", (int)chunk.len, chunk.ptr); + break; + case AC_GROUP_TYPE_OID: + oid = asn1_known_oid(chunk); + if (oid == OID_UNKNOWN) + { + str = asn1_oid_to_string(chunk); + if (str) + { + fprintf(f, "%s", str); + free(str); + } + else + { + fprintf(f, "OID:%#B", &chunk); + } + } + else + { + fprintf(f, "%s", oid_names[oid].name); + } + break; + case AC_GROUP_TYPE_OCTETS: + fprintf(f, "%#B", &chunk); + break; + } + fprintf(f, "\n"); + } + groups->destroy(groups); + + chunk = ac->get_authKeyIdentifier(ac); + if (chunk.ptr) + { + fprintf(f, " authkey: %#B\n", &chunk); + } +} + +/** + * Print OCSP response specific information + */ +static void print_ocsp_response(private_certificate_printer_t *this, + ocsp_response_t *ocsp_response) +{ + enumerator_t *enumerator; + chunk_t serialNumber; + cert_validation_t status; + char *status_text; + time_t revocationTime; + crl_reason_t *revocationReason; + bool first = TRUE; + FILE *f = this->f; + + if (this->detailed) + { + fprintf(f, " responses: "); + + enumerator = ocsp_response->create_response_enumerator(ocsp_response); + while (enumerator->enumerate(enumerator, &serialNumber, &status, + &revocationTime, &revocationReason)) + { + if (first) + { + first = FALSE; + } + else + { + fprintf(f, " "); + } + serialNumber = chunk_skip_zero(serialNumber); + + switch (status) + { + case VALIDATION_GOOD: + status_text = "good"; + break; + case VALIDATION_REVOKED: + status_text = "revoked"; + break; + default: + status_text = "unknown"; + } + fprintf(f, "%#B: %s", &serialNumber, status_text); + + if (status == VALIDATION_REVOKED) + { + fprintf(f, " on %T, %N", &revocationTime, this->utc, + crl_reason_names, revocationReason); + } + fprintf(f, "\n"); + } + enumerator->destroy(enumerator); + } +} + +/** + * Print public key information + */ +static void print_pubkey(private_certificate_printer_t *this, public_key_t *key, + bool has_privkey) +{ + chunk_t chunk; + FILE *f = this->f; + + fprintf(f, " pubkey: %N %d bits", key_type_names, key->get_type(key), + key->get_keysize(key)); + if (has_privkey) + { + fprintf(f, ", has private key"); + } + fprintf(f, "\n"); + if (key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &chunk)) + { + fprintf(f, " keyid: %#B\n", &chunk); + } + if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &chunk)) + { + fprintf(f, " subjkey: %#B\n", &chunk); + } +} + +METHOD(certificate_printer_t, print, void, + private_certificate_printer_t *this, certificate_t *cert, bool has_privkey) +{ + time_t now, notAfter, notBefore; + certificate_type_t type; + identification_t *subject; + char *t0, *t1, *t2; + public_key_t *key; + FILE *f = this->f; + + now = time(NULL); + type = cert->get_type(cert); + subject = cert->get_subject(cert); + + if ((type != CERT_X509_CRL && type != CERT_X509_OCSP_RESPONSE && + type != CERT_TRUSTED_PUBKEY) || + (type == CERT_TRUSTED_PUBKEY && subject->get_type(subject) != ID_KEY_ID)) + { + fprintf(f, " subject: \"%Y\"\n", subject); + } + if (type != CERT_TRUSTED_PUBKEY && type != CERT_GPG) + { + fprintf(f, " issuer: \"%Y\"\n", cert->get_issuer(cert)); + } + + /* list validity if set */ + cert->get_validity(cert, &now, ¬Before, ¬After); + if (notBefore != UNDEFINED_TIME && notAfter != UNDEFINED_TIME) + { + if (type == CERT_GPG) + { + fprintf(f, " created: %T\n", ¬Before, this->utc); + fprintf(f, " until: %T%s\n", ¬After, this->utc, + (notAfter == TIME_32_BIT_SIGNED_MAX) ?" expires never" : ""); + } + else + { + if (type == CERT_X509_CRL || type == CERT_X509_OCSP_RESPONSE) + { + t0 = "update: "; + t1 = "this on"; + t2 = "next on"; + } + else + { + t0 = "validity:"; + t1 = "not before"; + t2 = "not after "; + } + fprintf(f, " %s %s %T, ", t0, t1, ¬Before, this->utc); + if (now < notBefore) + { + fprintf(f, "not valid yet (valid in %V)\n", &now, ¬Before); + } + else + { + fprintf(f, "ok\n"); + } + fprintf(f, " %s %T, ", t2, ¬After, this->utc); + if (now > notAfter) + { + fprintf(f, "expired (%V ago)\n", &now, ¬After); + } + else + { + fprintf(f, "ok (expires in %V)\n", &now, ¬After); + } + } + } + + switch (cert->get_type(cert)) + { + case CERT_X509: + print_x509(this, (x509_t*)cert); + break; + case CERT_X509_CRL: + print_crl(this, (crl_t*)cert); + break; + case CERT_X509_AC: + print_ac(this, (ac_t*)cert); + break; + case CERT_X509_OCSP_RESPONSE: + print_ocsp_response(this, (ocsp_response_t*)cert); + break; + case CERT_TRUSTED_PUBKEY: + default: + break; + } + if (type == CERT_GPG) + { + pgp_certificate_t *pgp_cert = (pgp_certificate_t*)cert; + chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert); + + fprintf(f, " pgpDigest: %#B\n", &fingerprint); + } + key = cert->get_public_key(cert); + if (key) + { + print_pubkey(this, key, has_privkey); + key->destroy(key); + } +} + +METHOD(certificate_printer_t, print_caption, void, + private_certificate_printer_t *this, certificate_type_t type, + x509_flag_t flag) +{ + char *caption; + + if (type != this->type || (type == CERT_X509 && flag != this->flag)) + { + switch (type) + { + case CERT_X509: + switch (flag) + { + case X509_NONE: + caption = "X.509 End Entity Certificate"; + break; + case X509_CA: + caption = "X.509 CA Certificate"; + break; + case X509_AA: + caption = "X.509 AA Certificate"; + break; + case X509_OCSP_SIGNER: + caption = "X.509 OCSP Signer Certificate"; + break; + default: + return; + } + break; + case CERT_X509_AC: + caption = "X.509 Attribute Certificate"; + break; + case CERT_X509_CRL: + caption = "X.509 CRL"; + break; + case CERT_X509_OCSP_RESPONSE: + caption = "OCSP Response"; + break; + case CERT_TRUSTED_PUBKEY: + caption = "Raw Public Key"; + break; + case CERT_GPG: + caption = "PGP End Entity Certificate"; + break; + default: + return; + } + fprintf(this->f, "\nList of %ss\n", caption); + + /* Update to current type and flag value */ + this->type = type; + if (type == CERT_X509) + { + this->flag = flag; + } + } + fprintf(this->f, "\n"); +} + +METHOD(certificate_printer_t, destroy, void, + private_certificate_printer_t *this) +{ + free(this); +} + +/** + * See header + */ +certificate_printer_t *certificate_printer_create(FILE *f, bool detailed, + bool utc) +{ + private_certificate_printer_t *this; + + INIT(this, + .public = { + .print = _print, + .print_caption = _print_caption, + .destroy = _destroy, + }, + .f = f, + .detailed = detailed, + .utc = utc, + .type = CERT_ANY, + .flag = X509_ANY, + ); + + return &this->public; +} diff --git a/src/libstrongswan/credentials/certificates/certificate_printer.h b/src/libstrongswan/credentials/certificates/certificate_printer.h new file mode 100644 index 000000000..7953eb060 --- /dev/null +++ b/src/libstrongswan/credentials/certificates/certificate_printer.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2015 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup certificate_printer certificate_printer + * @{ @ingroup certificates + */ + +#ifndef CERTIFICATE_PRINTER_H_ +#define CERTIFICATE_PRINTER_H_ + +typedef struct certificate_printer_t certificate_printer_t; + +#include "credentials/certificates/certificate.h" +#include "credentials/certificates/x509.h" + +#include <stdio.h> + +/** + * An object for printing certificate information. + */ +struct certificate_printer_t { + + /** + * Print a certificate. + * + * @param cert certificate to be printed + * @param has_privkey indicates that certificate has a matching private key + */ + void (*print)(certificate_printer_t *this, certificate_t *cert, + bool has_privkey); + + /** + * Print a caption if the certificate type changed. + * + * @param type certificate type + * @param flag X.509 certificate flag + */ + void (*print_caption)(certificate_printer_t *this, certificate_type_t type, + x509_flag_t flag); + + /** + * Destroy the certificate_printer object. + */ + void (*destroy)(certificate_printer_t *this); +}; + +/** + * Create a certificate_printer object + * + * @param f file where print output is directed to (usually stdout) + * @param detailed print more detailed certificate information + * @param utc print time inforamtion in UTC + */ +certificate_printer_t* certificate_printer_create(FILE *f, bool detailed, + bool utc); + +#endif /** CERTIFICATE_PRINTER_H_ @}*/ diff --git a/src/libstrongswan/credentials/certificates/ocsp_response.h b/src/libstrongswan/credentials/certificates/ocsp_response.h index 9c5637b9f..c6a4c1277 100644 --- a/src/libstrongswan/credentials/certificates/ocsp_response.h +++ b/src/libstrongswan/credentials/certificates/ocsp_response.h @@ -77,6 +77,13 @@ struct ocsp_response_t { * @return enumerator over certificate_t* */ enumerator_t* (*create_cert_enumerator)(ocsp_response_t *this); + + /** + * Create an enumerator over the contained responses. + * + * @return enumerator over major response fields + */ + enumerator_t* (*create_response_enumerator)(ocsp_response_t *this); }; #endif /** OCSP_RESPONSE_H_ @}*/ diff --git a/src/libstrongswan/credentials/certificates/x509.c b/src/libstrongswan/credentials/certificates/x509.c new file mode 100644 index 000000000..5eefa0bb4 --- /dev/null +++ b/src/libstrongswan/credentials/certificates/x509.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "x509.h" + +ENUM_BEGIN(x509_flag_names, X509_NONE, X509_AA, + "NONE", + "CA", + "AA"); +ENUM_NEXT(x509_flag_names, X509_OCSP_SIGNER, X509_OCSP_SIGNER, X509_AA, + "OCSP"); +ENUM_NEXT(x509_flag_names, X509_ANY, X509_ANY, X509_OCSP_SIGNER, + "ANY"); +ENUM_END(x509_flag_names, X509_ANY); + diff --git a/src/libstrongswan/credentials/certificates/x509.h b/src/libstrongswan/credentials/certificates/x509.h index 6cbfcdeed..601c034ef 100644 --- a/src/libstrongswan/credentials/certificates/x509.h +++ b/src/libstrongswan/credentials/certificates/x509.h @@ -46,6 +46,8 @@ enum x509_flag_t { X509_AA = (1<<1), /** cert has OCSP signer constraint */ X509_OCSP_SIGNER = (1<<2), + /** cert has either CA, AA or OCSP constraint */ + X509_ANY = X509_CA | X509_AA | X509_OCSP_SIGNER, /** cert has serverAuth key usage */ X509_SERVER_AUTH = (1<<3), /** cert has clientAuth key usage */ @@ -62,6 +64,8 @@ enum x509_flag_t { X509_MS_SMARTCARD_LOGON = (1<<9), }; +extern enum_name_t *x509_flag_names; + /** * Different numerical X.509 constraints. */ diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c index 371e6404d..95c5cd777 100644 --- a/src/libstrongswan/credentials/credential_manager.c +++ b/src/libstrongswan/credentials/credential_manager.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2015 Tobias Brunner * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -917,6 +918,8 @@ METHOD(enumerator_t, trusted_destroy, void, DESTROY_IF(this->auth); DESTROY_IF(this->candidates); this->failed->destroy_offset(this->failed, offsetof(certificate_t, destroy)); + /* check for delayed certificate cache queue */ + cache_queue(this->this); free(this); } @@ -985,7 +988,6 @@ METHOD(enumerator_t, public_destroy, void, this->wrapper->destroy(this->wrapper); } this->this->lock->unlock(this->this->lock); - /* check for delayed certificate cache queue */ cache_queue(this->this); free(this); @@ -993,7 +995,7 @@ METHOD(enumerator_t, public_destroy, void, METHOD(credential_manager_t, create_public_enumerator, enumerator_t*, private_credential_manager_t *this, key_type_t type, identification_t *id, - auth_cfg_t *auth) + auth_cfg_t *auth, bool online) { public_enumerator_t *enumerator; @@ -1002,7 +1004,7 @@ METHOD(credential_manager_t, create_public_enumerator, enumerator_t*, .enumerate = (void*)_public_enumerate, .destroy = _public_destroy, }, - .inner = create_trusted_enumerator(this, type, id, TRUE), + .inner = create_trusted_enumerator(this, type, id, online), .this = this, ); if (auth) diff --git a/src/libstrongswan/credentials/credential_manager.h b/src/libstrongswan/credentials/credential_manager.h index 445ea3f9c..022ca566c 100644 --- a/src/libstrongswan/credentials/credential_manager.h +++ b/src/libstrongswan/credentials/credential_manager.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2015 Tobias Brunner * Copyright (C) 2007-2009 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -202,14 +203,18 @@ struct credential_manager_t { * where the auth config helper contains rules for constraint checks. * This function is very similar to create_trusted_enumerator(), but * gets public keys directly. + * If online is set, revocations are checked online for the whole + * trustchain. * * @param type type of the key to get * @param id owner of the key, signer of the signature * @param auth authentication infos + * @param online whether revocations should be checked online * @return enumerator */ enumerator_t* (*create_public_enumerator)(credential_manager_t *this, - key_type_t type, identification_t *id, auth_cfg_t *auth); + key_type_t type, identification_t *id, auth_cfg_t *auth, + bool online); /** * Cache a certificate by invoking cache_cert() on all registered sets. |