diff options
Diffstat (limited to 'src/libstrongswan/plugins/openssl')
-rw-r--r-- | src/libstrongswan/plugins/openssl/Makefile.am | 4 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/Makefile.in | 10 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_crl.c | 530 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_crl.h | 48 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c | 6 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_ec_private_key.c | 27 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_ec_public_key.c | 31 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_plugin.c | 36 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c | 28 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c | 44 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_sha1_prf.h | 2 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_util.c | 83 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_util.h | 56 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_x509.c | 871 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_x509.h | 50 |
15 files changed, 1763 insertions, 63 deletions
diff --git a/src/libstrongswan/plugins/openssl/Makefile.am b/src/libstrongswan/plugins/openssl/Makefile.am index a50799798..5c845a19c 100644 --- a/src/libstrongswan/plugins/openssl/Makefile.am +++ b/src/libstrongswan/plugins/openssl/Makefile.am @@ -20,7 +20,9 @@ libstrongswan_openssl_la_SOURCES = \ openssl_rsa_public_key.c openssl_rsa_public_key.h \ openssl_ec_diffie_hellman.c openssl_ec_diffie_hellman.h \ openssl_ec_private_key.c openssl_ec_private_key.h \ - openssl_ec_public_key.c openssl_ec_public_key.h + openssl_ec_public_key.c openssl_ec_public_key.h \ + openssl_x509.c openssl_x509.h \ + openssl_crl.c openssl_crl.h libstrongswan_openssl_la_LDFLAGS = -module -avoid-version libstrongswan_openssl_la_LIBADD = -lcrypto diff --git a/src/libstrongswan/plugins/openssl/Makefile.in b/src/libstrongswan/plugins/openssl/Makefile.in index a2a931d42..de9df7271 100644 --- a/src/libstrongswan/plugins/openssl/Makefile.in +++ b/src/libstrongswan/plugins/openssl/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11 from Makefile.am. +# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -79,7 +79,7 @@ am_libstrongswan_openssl_la_OBJECTS = openssl_plugin.lo \ openssl_sha1_prf.lo openssl_diffie_hellman.lo \ openssl_rsa_private_key.lo openssl_rsa_public_key.lo \ openssl_ec_diffie_hellman.lo openssl_ec_private_key.lo \ - openssl_ec_public_key.lo + openssl_ec_public_key.lo openssl_x509.lo openssl_crl.lo libstrongswan_openssl_la_OBJECTS = \ $(am_libstrongswan_openssl_la_OBJECTS) libstrongswan_openssl_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -276,7 +276,9 @@ libstrongswan_openssl_la_SOURCES = \ openssl_rsa_public_key.c openssl_rsa_public_key.h \ openssl_ec_diffie_hellman.c openssl_ec_diffie_hellman.h \ openssl_ec_private_key.c openssl_ec_private_key.h \ - openssl_ec_public_key.c openssl_ec_public_key.h + openssl_ec_public_key.c openssl_ec_public_key.h \ + openssl_x509.c openssl_x509.h \ + openssl_crl.c openssl_crl.h libstrongswan_openssl_la_LDFLAGS = -module -avoid-version libstrongswan_openssl_la_LIBADD = -lcrypto @@ -363,6 +365,7 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_crl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_crypter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_diffie_hellman.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_ec_diffie_hellman.Plo@am__quote@ @@ -374,6 +377,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_rsa_public_key.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_sha1_prf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_x509.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/src/libstrongswan/plugins/openssl/openssl_crl.c b/src/libstrongswan/plugins/openssl/openssl_crl.c new file mode 100644 index 000000000..5645d72d7 --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_crl.c @@ -0,0 +1,530 @@ +/* + * 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. + */ + +/* + * Copyright (C) 2010 secunet Security Networks AG + * Copyright (C) 2010 Thomas Egerer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "openssl_crl.h" +#include "openssl_util.h" + +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#include <debug.h> +#include <utils/enumerator.h> +#include <credentials/certificates/x509.h> + +typedef struct private_openssl_crl_t private_openssl_crl_t; + +/** + * Private data of an openssl_crl_t object. + */ +struct private_openssl_crl_t { + + /** + * Public openssl_crl_t interface. + */ + openssl_crl_t public; + + /** + * OpenSSL representation of a CRL + */ + X509_CRL *crl; + + /** + * DER encoding of the CRL + */ + chunk_t encoding; + + /** + * Serial Number (crlNumber) of the CRL) + */ + chunk_t serial; + + /** + * AuthorityKeyIdentifier of the issuing CA + */ + chunk_t authKeyIdentifier; + + /** + * Date of this CRL + */ + time_t thisUpdate; + + /** + * Date of next CRL expected + */ + time_t nextUpdate; + + /** + * Issuer of this CRL + */ + identification_t *issuer; + + /** + * Signature scheme used in this CRL + */ + signature_scheme_t scheme; + + /** + * References to this CRL + */ + refcount_t ref; +}; + +/** + * Enumerator over revoked certificates + */ +typedef struct { + /** + * Implements enumerator_t + */ + enumerator_t public; + + /** + * stack of revoked certificates + */ + STACK_OF(X509_REVOKED) *stack; + + /** + * Total number of revoked certificates + */ + int num; + + /** + * Current position of enumerator + */ + int i; +} crl_enumerator_t; + + +METHOD(enumerator_t, crl_enumerate, bool, + crl_enumerator_t *this, chunk_t *serial, time_t *date, crl_reason_t *reason) +{ + if (this->i < this->num) + { + X509_REVOKED *revoked; + ASN1_ENUMERATED *crlrsn; + + revoked = sk_X509_REVOKED_value(this->stack, this->i); + if (serial) + { + *serial = openssl_asn1_str2chunk(revoked->serialNumber); + } + if (date) + { + *date = openssl_asn1_to_time(revoked->revocationDate); + } + if (reason) + { + *reason = CRL_REASON_UNSPECIFIED; + crlrsn = X509_REVOKED_get_ext_d2i(revoked, NID_crl_reason, + NULL, NULL); + if (crlrsn) + { + if (ASN1_STRING_type(crlrsn) == V_ASN1_ENUMERATED && + ASN1_STRING_length(crlrsn) == 1) + { + *reason = *ASN1_STRING_data(crlrsn); + } + ASN1_STRING_free(crlrsn); + } + } + this->i++; + return TRUE; + } + return FALSE; +} + +METHOD(crl_t, create_enumerator, enumerator_t*, + private_openssl_crl_t *this) +{ + crl_enumerator_t *enumerator; + + INIT(enumerator, + .public = { + .enumerate = (void*)_crl_enumerate, + .destroy = (void*)free, + }, + .stack = X509_CRL_get_REVOKED(this->crl), + ); + if (!enumerator->stack) + { + free(enumerator); + return enumerator_create_empty(); + } + enumerator->num = sk_X509_EXTENSION_num(enumerator->stack); + return &enumerator->public; +} + +METHOD(crl_t, get_serial, chunk_t, + private_openssl_crl_t *this) +{ + return this->serial; +} + +METHOD(crl_t, get_authKeyIdentifier, chunk_t, + private_openssl_crl_t *this) +{ + return this->authKeyIdentifier; +} + +METHOD(certificate_t, get_type, certificate_type_t, + private_openssl_crl_t *this) +{ + return CERT_X509_CRL; +} + +METHOD(certificate_t, get_subject_or_issuer, identification_t*, + private_openssl_crl_t *this) +{ + return this->issuer; +} + +METHOD(certificate_t, has_subject_or_issuer, id_match_t, + private_openssl_crl_t *this, identification_t *id) +{ + if (id->get_type(id) == ID_KEY_ID && + chunk_equals(this->authKeyIdentifier, id->get_encoding(id))) + { + return ID_MATCH_PERFECT; + } + return this->issuer->matches(this->issuer, id); +} + +METHOD(certificate_t, issued_by, bool, + private_openssl_crl_t *this, certificate_t *issuer) +{ + chunk_t fingerprint, tbs; + public_key_t *key; + x509_t *x509; + bool valid; + + if (issuer->get_type(issuer) != CERT_X509) + { + return FALSE; + } + x509 = (x509_t*)issuer; + if (!(x509->get_flags(x509) & X509_CA)) + { + return FALSE; + } + key = issuer->get_public_key(issuer); + if (!key) + { + return FALSE; + } + if (this->authKeyIdentifier.ptr && key) + { + if (!key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fingerprint) || + !chunk_equals(fingerprint, this->authKeyIdentifier)) + { + return FALSE; + } + } + else + { + if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer))) + { + return FALSE; + } + } + if (this->scheme == SIGN_UNKNOWN) + { + return FALSE; + } + tbs = openssl_i2chunk(X509_CRL_INFO, this->crl->crl); + valid = key->verify(key, this->scheme, tbs, + openssl_asn1_str2chunk(this->crl->signature)); + free(tbs.ptr); + key->destroy(key); + return valid; +} + +METHOD(certificate_t, get_public_key, public_key_t*, + private_openssl_crl_t *this) +{ + return NULL; +} + +METHOD(certificate_t, get_validity, bool, + private_openssl_crl_t *this, + time_t *when, time_t *not_before, time_t *not_after) +{ + time_t t = when ? *when : time(NULL); + + if (not_before) + { + *not_before = this->thisUpdate; + } + if (not_after) + { + *not_after = this->nextUpdate; + } + return t <= this->nextUpdate; +} + +METHOD(certificate_t, get_encoding, bool, + private_openssl_crl_t *this, cred_encoding_type_t type, chunk_t *encoding) +{ + if (type == CERT_ASN1_DER) + { + *encoding = chunk_clone(this->encoding); + return TRUE; + } + return lib->encoding->encode(lib->encoding, type, NULL, encoding, + CRED_PART_X509_CRL_ASN1_DER, this->encoding, CRED_PART_END); +} + +METHOD(certificate_t, equals, bool, + private_openssl_crl_t *this, certificate_t *other) +{ + chunk_t encoding; + bool equal; + + if (&this->public.crl.certificate == other) + { + return TRUE; + } + if (other->equals == (void*)equals) + { /* skip allocation if we have the same implementation */ + return chunk_equals(this->encoding, + ((private_openssl_crl_t*)other)->encoding); + } + if (!other->get_encoding(other, CERT_ASN1_DER, &encoding)) + { + return FALSE; + } + equal = chunk_equals(this->encoding, encoding); + free(encoding.ptr); + return equal; +} + +METHOD(certificate_t, get_ref, certificate_t*, + private_openssl_crl_t *this) +{ + ref_get(&this->ref); + return &this->public.crl.certificate; +} + +METHOD(certificate_t, destroy, void, + private_openssl_crl_t *this) +{ + if (ref_put(&this->ref)) + { + if (this->crl) + { + X509_CRL_free(this->crl); + } + DESTROY_IF(this->issuer); + free(this->authKeyIdentifier.ptr); + free(this->serial.ptr); + free(this->encoding.ptr); + free(this); + } +} + +/** + * Create an empty CRL. + */ +static private_openssl_crl_t *create_empty() +{ + private_openssl_crl_t *this; + + INIT(this, + .public = { + .crl = { + .certificate = { + .get_type = _get_type, + .get_subject = _get_subject_or_issuer, + .get_issuer = _get_subject_or_issuer, + .has_subject = _has_subject_or_issuer, + .has_issuer = _has_subject_or_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_serial = _get_serial, + .get_authKeyIdentifier = _get_authKeyIdentifier, + .create_enumerator = _create_enumerator, + }, + }, + .ref = 1, + ); + return this; +} + +/** + * Parse the authKeyIdentifier extension + */ +static bool parse_authKeyIdentifier_ext(private_openssl_crl_t *this, + X509_EXTENSION *ext) +{ + AUTHORITY_KEYID *keyid; + + keyid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ext); + if (keyid) + { + free(this->authKeyIdentifier.ptr); + this->authKeyIdentifier = chunk_clone( + openssl_asn1_str2chunk(keyid->keyid)); + AUTHORITY_KEYID_free(keyid); + return TRUE; + } + return FALSE; +} + +/** + * Parse the crlNumber extension + */ +static bool parse_crlNumber_ext(private_openssl_crl_t *this, + X509_EXTENSION *ext) +{ + free(this->serial.ptr); + this->serial = chunk_clone( + openssl_asn1_str2chunk(X509_EXTENSION_get_data(ext))); + return this->serial.len != 0; +} + +/** + * Parse X509 CRL extensions + */ +static bool parse_extensions(private_openssl_crl_t *this) +{ + bool ok; + int i, num; + X509_EXTENSION *ext; + STACK_OF(X509_EXTENSION) *extensions; + + extensions = this->crl->crl->extensions; + if (extensions) + { + num = sk_X509_EXTENSION_num(extensions); + for (i = 0; i < num; ++i) + { + ext = sk_X509_EXTENSION_value(extensions, i); + + switch (OBJ_obj2nid(X509_EXTENSION_get_object(ext))) + { + case NID_authority_key_identifier: + ok = parse_authKeyIdentifier_ext(this, ext); + break; + case NID_crl_number: + ok = parse_crlNumber_ext(this, ext); + break; + default: + ok = TRUE; + break; + } + if (!ok) + { + return FALSE; + } + } + } + return TRUE; +} + +/** + * Parse a X509 CRL + */ +static bool parse_crl(private_openssl_crl_t *this) +{ + const unsigned char *ptr = this->encoding.ptr; + + this->crl = d2i_X509_CRL(NULL, &ptr, this->encoding.len); + if (!this->crl) + { + return FALSE; + } + + if (!chunk_equals( + openssl_asn1_obj2chunk(this->crl->crl->sig_alg->algorithm), + openssl_asn1_obj2chunk(this->crl->sig_alg->algorithm))) + { + return FALSE; + } + this->scheme = signature_scheme_from_oid(openssl_asn1_known_oid( + this->crl->sig_alg->algorithm)); + + this->issuer = openssl_x509_name2id(X509_CRL_get_issuer(this->crl)); + if (!this->issuer) + { + return FALSE; + } + this->thisUpdate = openssl_asn1_to_time(X509_CRL_get_lastUpdate(this->crl)); + this->nextUpdate = openssl_asn1_to_time(X509_CRL_get_nextUpdate(this->crl)); + + return parse_extensions(this); +} + +/** + * Load the CRL. + */ +openssl_crl_t *openssl_crl_load(certificate_type_t type, va_list args) +{ + chunk_t blob = chunk_empty; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_BLOB_ASN1_DER: + blob = va_arg(args, chunk_t); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + if (blob.ptr) + { + private_openssl_crl_t *this = create_empty(); + + this->encoding = chunk_clone(blob); + if (parse_crl(this)) + { + return &this->public; + } + destroy(this); + } + return NULL; +} diff --git a/src/libstrongswan/plugins/openssl/openssl_crl.h b/src/libstrongswan/plugins/openssl/openssl_crl.h new file mode 100644 index 000000000..a0837cf50 --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_crl.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +/** + * @defgroup openssl_crl openssl_crl + * @{ @ingroup openssl_p + */ + +#ifndef OPENSSL_CRL_H_ +#define OPENSSL_CRL_H_ + +typedef struct openssl_crl_t openssl_crl_t; + +#include <credentials/certificates/crl.h> + +/** + * X.509 Certificate Revocation list implemented with OpenSSL. + */ +struct openssl_crl_t { + + /** + * Implements the crl_t interface. + */ + crl_t crl; +}; + +/** + * Load a X.509 CRL using OpenSSL. + * + * @param type certificate type, CERT_X509_CRL only + * @param args builder_part_t argument list + * @return X.509 CRL, NULL on failure + */ +openssl_crl_t *openssl_crl_load(certificate_type_t type, va_list args); + +#endif /** OPENSSL_CRL_H_ @}*/ diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c index faec411cd..a53e8aea0 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_diffie_hellman.c @@ -13,6 +13,10 @@ * for more details. */ +#include <openssl/opensslconf.h> + +#ifndef OPENSSL_NO_EC + #include <openssl/ec.h> #include <openssl/objects.h> @@ -331,3 +335,5 @@ openssl_ec_diffie_hellman_t *openssl_ec_diffie_hellman_create(diffie_hellman_gro return &this->public; } +#endif /* OPENSSL_NO_EC */ + diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c index bdcfda974..281155913 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c @@ -14,6 +14,10 @@ * for more details. */ +#include <openssl/opensslconf.h> + +#ifndef OPENSSL_NO_EC + #include "openssl_ec_private_key.h" #include "openssl_ec_public_key.h" #include "openssl_util.h" @@ -47,7 +51,7 @@ struct private_openssl_ec_private_key_t { }; /* from ec public key */ -bool openssl_ec_fingerprint(EC_KEY *ec, key_encoding_type_t type, chunk_t *fp); +bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp); /** * Build a signature as in RFC 4754 @@ -217,7 +221,7 @@ static public_key_t* get_public_key(private_openssl_ec_private_key_t *this) * Implementation of private_key_t.get_fingerprint. */ static bool get_fingerprint(private_openssl_ec_private_key_t *this, - key_encoding_type_t type, chunk_t *fingerprint) + cred_encoding_type_t type, chunk_t *fingerprint) { return openssl_ec_fingerprint(this->ec, type, fingerprint); } @@ -226,14 +230,14 @@ static bool get_fingerprint(private_openssl_ec_private_key_t *this, * Implementation of private_key_t.get_encoding. */ static bool get_encoding(private_openssl_ec_private_key_t *this, - key_encoding_type_t type, chunk_t *encoding) + cred_encoding_type_t type, chunk_t *encoding) { u_char *p; switch (type) { - case KEY_PRIV_ASN1_DER: - case KEY_PRIV_PEM: + case PRIVKEY_ASN1_DER: + case PRIVKEY_PEM: { bool success = TRUE; @@ -241,13 +245,13 @@ static bool get_encoding(private_openssl_ec_private_key_t *this, p = encoding->ptr; i2d_ECPrivateKey(this->ec, &p); - if (type == KEY_PRIV_PEM) + if (type == PRIVKEY_PEM) { chunk_t asn1_encoding = *encoding; - success = lib->encoding->encode(lib->encoding, KEY_PRIV_PEM, - NULL, encoding, KEY_PART_ECDSA_PRIV_ASN1_DER, - asn1_encoding, KEY_PART_END); + success = lib->encoding->encode(lib->encoding, PRIVKEY_PEM, + NULL, encoding, CRED_PART_ECDSA_PRIV_ASN1_DER, + asn1_encoding, CRED_PART_END); chunk_clear(&asn1_encoding); } return success; @@ -296,9 +300,9 @@ static private_openssl_ec_private_key_t *create_empty(void) this->public.interface.get_public_key = (public_key_t* (*)(private_key_t *this))get_public_key; this->public.interface.equals = private_key_equals; this->public.interface.belongs_to = private_key_belongs_to; - this->public.interface.get_fingerprint = (bool(*)(private_key_t*, key_encoding_type_t type, chunk_t *fp))get_fingerprint; + this->public.interface.get_fingerprint = (bool(*)(private_key_t*, cred_encoding_type_t type, chunk_t *fp))get_fingerprint; this->public.interface.has_fingerprint = (bool(*)(private_key_t*, chunk_t fp))private_key_has_fingerprint; - this->public.interface.get_encoding = (bool(*)(private_key_t*, key_encoding_type_t type, chunk_t *encoding))get_encoding; + this->public.interface.get_encoding = (bool(*)(private_key_t*, cred_encoding_type_t type, chunk_t *encoding))get_encoding; this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref; this->public.interface.destroy = (void (*)(private_key_t *this))destroy; @@ -402,4 +406,5 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type, } return &this->public; } +#endif /* OPENSSL_NO_EC */ diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c index 790a8487d..def36c92f 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c @@ -14,6 +14,10 @@ * for more details. */ +#include <openssl/opensslconf.h> + +#ifndef OPENSSL_NO_EC + #include "openssl_ec_public_key.h" #include "openssl_util.h" @@ -189,7 +193,7 @@ static size_t get_keysize(private_openssl_ec_public_key_t *this) /** * Calculate fingerprint from a EC_KEY, also used in ec private key. */ -bool openssl_ec_fingerprint(EC_KEY *ec, key_encoding_type_t type, chunk_t *fp) +bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp) { hasher_t *hasher; chunk_t key; @@ -201,12 +205,12 @@ bool openssl_ec_fingerprint(EC_KEY *ec, key_encoding_type_t type, chunk_t *fp) } switch (type) { - case KEY_ID_PUBKEY_SHA1: + case KEYID_PUBKEY_SHA1: key = chunk_alloc(i2o_ECPublicKey(ec, NULL)); p = key.ptr; i2o_ECPublicKey(ec, &p); break; - case KEY_ID_PUBKEY_INFO_SHA1: + case KEYID_PUBKEY_INFO_SHA1: key = chunk_alloc(i2d_EC_PUBKEY(ec, NULL)); p = key.ptr; i2d_EC_PUBKEY(ec, &p); @@ -232,7 +236,7 @@ bool openssl_ec_fingerprint(EC_KEY *ec, key_encoding_type_t type, chunk_t *fp) * Implementation of private_key_t.get_fingerprint. */ static bool get_fingerprint(private_openssl_ec_public_key_t *this, - key_encoding_type_t type, chunk_t *fingerprint) + cred_encoding_type_t type, chunk_t *fingerprint) { return openssl_ec_fingerprint(this->ec, type, fingerprint); } @@ -241,14 +245,14 @@ static bool get_fingerprint(private_openssl_ec_public_key_t *this, * Implementation of private_key_t.get_encoding. */ static bool get_encoding(private_openssl_ec_public_key_t *this, - key_encoding_type_t type, chunk_t *encoding) + cred_encoding_type_t type, chunk_t *encoding) { u_char *p; switch (type) { - case KEY_PUB_SPKI_ASN1_DER: - case KEY_PUB_PEM: + case PUBKEY_SPKI_ASN1_DER: + case PUBKEY_PEM: { bool success = TRUE; @@ -256,13 +260,13 @@ static bool get_encoding(private_openssl_ec_public_key_t *this, p = encoding->ptr; i2d_EC_PUBKEY(this->ec, &p); - if (type == KEY_PUB_PEM) + if (type == PUBKEY_PEM) { chunk_t asn1_encoding = *encoding; - success = lib->encoding->encode(lib->encoding, KEY_PUB_PEM, - NULL, encoding, KEY_PART_ECDSA_PUB_ASN1_DER, - asn1_encoding, KEY_PART_END); + success = lib->encoding->encode(lib->encoding, PUBKEY_PEM, + NULL, encoding, CRED_PART_ECDSA_PUB_ASN1_DER, + asn1_encoding, CRED_PART_END); chunk_clear(&asn1_encoding); } return success; @@ -309,9 +313,9 @@ static private_openssl_ec_public_key_t *create_empty() this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt_; this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize; this->public.interface.equals = public_key_equals; - this->public.interface.get_fingerprint = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *fp))get_fingerprint; + this->public.interface.get_fingerprint = (bool(*)(public_key_t*, cred_encoding_type_t type, chunk_t *fp))get_fingerprint; this->public.interface.has_fingerprint = (bool(*)(public_key_t*, chunk_t fp))public_key_has_fingerprint; - this->public.interface.get_encoding = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *encoding))get_encoding; + this->public.interface.get_encoding = (bool(*)(public_key_t*, cred_encoding_type_t type, chunk_t *encoding))get_encoding; this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref; this->public.interface.destroy = (void (*)(public_key_t *this))destroy; @@ -358,4 +362,5 @@ openssl_ec_public_key_t *openssl_ec_public_key_load(key_type_t type, } return &this->public; } +#endif /* OPENSSL_NO_EC */ diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c index c1545ffb8..31697dcb8 100644 --- a/src/libstrongswan/plugins/openssl/openssl_plugin.c +++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c @@ -14,10 +14,12 @@ * for more details. */ -#include <openssl/conf.h> #include <openssl/evp.h> -#include <openssl/engine.h> +#include <openssl/conf.h> #include <openssl/crypto.h> +#ifndef OPENSSL_NO_ENGINE +#include <openssl/engine.h> +#endif #include "openssl_plugin.h" @@ -34,6 +36,8 @@ #include "openssl_rsa_public_key.h" #include "openssl_ec_private_key.h" #include "openssl_ec_public_key.h" +#include "openssl_x509.h" +#include "openssl_crl.h" typedef struct private_openssl_plugin_t private_openssl_plugin_t; @@ -175,8 +179,6 @@ static void destroy(private_openssl_plugin_t *this) (prf_constructor_t)openssl_sha1_prf_create); lib->crypto->remove_dh(lib->crypto, (dh_constructor_t)openssl_diffie_hellman_create); - lib->crypto->remove_dh(lib->crypto, - (dh_constructor_t)openssl_ec_diffie_hellman_create); lib->creds->remove_builder(lib->creds, (builder_function_t)openssl_rsa_private_key_load); lib->creds->remove_builder(lib->creds, @@ -185,14 +187,24 @@ static void destroy(private_openssl_plugin_t *this) (builder_function_t)openssl_rsa_private_key_connect); lib->creds->remove_builder(lib->creds, (builder_function_t)openssl_rsa_public_key_load); +#ifndef OPENSSL_NO_EC + lib->crypto->remove_dh(lib->crypto, + (dh_constructor_t)openssl_ec_diffie_hellman_create); lib->creds->remove_builder(lib->creds, (builder_function_t)openssl_ec_private_key_load); lib->creds->remove_builder(lib->creds, (builder_function_t)openssl_ec_private_key_gen); lib->creds->remove_builder(lib->creds, (builder_function_t)openssl_ec_public_key_load); +#endif /* OPENSSL_NO_EC */ + lib->creds->remove_builder(lib->creds, + (builder_function_t)openssl_x509_load); + lib->creds->remove_builder(lib->creds, + (builder_function_t)openssl_crl_load); +#ifndef OPENSSL_NO_ENGINE ENGINE_cleanup(); +#endif /* OPENSSL_NO_ENGINE */ EVP_cleanup(); CONF_modules_free(); @@ -215,9 +227,11 @@ plugin_t *openssl_plugin_create() OPENSSL_config(NULL); OpenSSL_add_all_algorithms(); +#ifndef OPENSSL_NO_ENGINE /* activate support for hardware accelerators */ ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); +#endif /* OPENSSL_NO_ENGINE */ /* crypter */ lib->crypto->add_crypter(lib->crypto, ENCR_AES_CBC, @@ -272,6 +286,7 @@ plugin_t *openssl_plugin_create() (dh_constructor_t)openssl_diffie_hellman_create); lib->crypto->add_dh(lib->crypto, MODP_1536_BIT, (dh_constructor_t)openssl_diffie_hellman_create); +#ifndef OPENSSL_NO_EC lib->crypto->add_dh(lib->crypto, ECP_256_BIT, (dh_constructor_t)openssl_ec_diffie_hellman_create); lib->crypto->add_dh(lib->crypto, ECP_384_BIT, @@ -282,6 +297,7 @@ plugin_t *openssl_plugin_create() (dh_constructor_t)openssl_ec_diffie_hellman_create); lib->crypto->add_dh(lib->crypto, ECP_192_BIT, (dh_constructor_t)openssl_ec_diffie_hellman_create); +#endif /* OPENSSL_NO_EC */ lib->crypto->add_dh(lib->crypto, MODP_3072_BIT, (dh_constructor_t)openssl_diffie_hellman_create); lib->crypto->add_dh(lib->crypto, MODP_4096_BIT, @@ -306,14 +322,24 @@ plugin_t *openssl_plugin_create() (builder_function_t)openssl_rsa_private_key_connect); lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, (builder_function_t)openssl_rsa_public_key_load); + lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, + (builder_function_t)openssl_rsa_public_key_load); - /* ec */ +#ifndef OPENSSL_NO_EC + /* ecdsa */ lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_ECDSA, (builder_function_t)openssl_ec_private_key_load); lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_ECDSA, (builder_function_t)openssl_ec_private_key_gen); lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA, (builder_function_t)openssl_ec_public_key_load); +#endif /* OPENSSL_NO_EC */ + + /* X509 certificates */ + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509, + (builder_function_t)openssl_x509_load); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL, + (builder_function_t)openssl_crl_load); return &this->public.plugin; } diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c index de751fe89..5817ade9e 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c @@ -21,7 +21,9 @@ #include <openssl/evp.h> #include <openssl/rsa.h> +#ifndef OPENSSL_NO_ENGINE #include <openssl/engine.h> +#endif /* OPENSSL_NO_ENGINE */ /** * Public exponent to use for key generation. @@ -56,7 +58,7 @@ struct private_openssl_rsa_private_key_t { }; /* implemented in rsa public key */ -bool openssl_rsa_fingerprint(RSA *rsa, key_encoding_type_t type, chunk_t *fp); +bool openssl_rsa_fingerprint(RSA *rsa, cred_encoding_type_t type, chunk_t *fp); /** * Build an EMPSA PKCS1 signature described in PKCS#1 @@ -206,7 +208,7 @@ static public_key_t* get_public_key(private_openssl_rsa_private_key_t *this) * Implementation of public_key_t.get_fingerprint. */ static bool get_fingerprint(private_openssl_rsa_private_key_t *this, - key_encoding_type_t type, chunk_t *fingerprint) + cred_encoding_type_t type, chunk_t *fingerprint) { return openssl_rsa_fingerprint(this->rsa, type, fingerprint); } @@ -215,7 +217,7 @@ static bool get_fingerprint(private_openssl_rsa_private_key_t *this, * Implementation of public_key_t.get_encoding. */ static bool get_encoding(private_openssl_rsa_private_key_t *this, - key_encoding_type_t type, chunk_t *encoding) + cred_encoding_type_t type, chunk_t *encoding) { u_char *p; @@ -225,8 +227,8 @@ static bool get_encoding(private_openssl_rsa_private_key_t *this, } switch (type) { - case KEY_PRIV_ASN1_DER: - case KEY_PRIV_PEM: + case PRIVKEY_ASN1_DER: + case PRIVKEY_PEM: { bool success = TRUE; @@ -234,13 +236,13 @@ static bool get_encoding(private_openssl_rsa_private_key_t *this, p = encoding->ptr; i2d_RSAPrivateKey(this->rsa, &p); - if (type == KEY_PRIV_PEM) + if (type == PRIVKEY_PEM) { chunk_t asn1_encoding = *encoding; - success = lib->encoding->encode(lib->encoding, KEY_PRIV_PEM, - NULL, encoding, KEY_PART_RSA_PRIV_ASN1_DER, - asn1_encoding, KEY_PART_END); + success = lib->encoding->encode(lib->encoding, PRIVKEY_PEM, + NULL, encoding, CRED_PART_RSA_PRIV_ASN1_DER, + asn1_encoding, CRED_PART_END); chunk_clear(&asn1_encoding); } return success; @@ -289,9 +291,9 @@ static private_openssl_rsa_private_key_t *create_empty(void) this->public.interface.get_public_key = (public_key_t* (*) (private_key_t*))get_public_key; this->public.interface.equals = private_key_equals; this->public.interface.belongs_to = private_key_belongs_to; - this->public.interface.get_fingerprint = (bool(*)(private_key_t*, key_encoding_type_t type, chunk_t *fp))get_fingerprint; + this->public.interface.get_fingerprint = (bool(*)(private_key_t*, cred_encoding_type_t type, chunk_t *fp))get_fingerprint; this->public.interface.has_fingerprint = (bool(*)(private_key_t*, chunk_t fp))private_key_has_fingerprint; - this->public.interface.get_encoding = (bool(*)(private_key_t*, key_encoding_type_t type, chunk_t *encoding))get_encoding; + this->public.interface.get_encoding = (bool(*)(private_key_t*, cred_encoding_type_t type, chunk_t *encoding))get_encoding; this->public.interface.get_ref = (private_key_t* (*) (private_key_t*))get_ref; this->public.interface.destroy = (void (*) (private_key_t*))destroy; @@ -447,6 +449,7 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_load(key_type_t type, openssl_rsa_private_key_t *openssl_rsa_private_key_connect(key_type_t type, va_list args) { +#ifndef OPENSSL_NO_ENGINE private_openssl_rsa_private_key_t *this; char *keyid = NULL, *pin = NULL; EVP_PKEY *key; @@ -511,5 +514,8 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_connect(key_type_t type, this->engine = TRUE; return &this->public; +#else /* OPENSSL_NO_ENGINE */ + return NULL; +#endif /* OPENSSL_NO_ENGINE */ } diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index ffa575a97..6ac61a65c 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -172,7 +172,7 @@ static size_t get_keysize(private_openssl_rsa_public_key_t *this) /** * Calculate fingerprint from a RSA key, also used in rsa private key. */ -bool openssl_rsa_fingerprint(RSA *rsa, key_encoding_type_t type, chunk_t *fp) +bool openssl_rsa_fingerprint(RSA *rsa, cred_encoding_type_t type, chunk_t *fp) { hasher_t *hasher; chunk_t key; @@ -184,12 +184,12 @@ bool openssl_rsa_fingerprint(RSA *rsa, key_encoding_type_t type, chunk_t *fp) } switch (type) { - case KEY_ID_PUBKEY_SHA1: + case KEYID_PUBKEY_SHA1: key = chunk_alloc(i2d_RSAPublicKey(rsa, NULL)); p = key.ptr; i2d_RSAPublicKey(rsa, &p); break; - case KEY_ID_PUBKEY_INFO_SHA1: + case KEYID_PUBKEY_INFO_SHA1: key = chunk_alloc(i2d_RSA_PUBKEY(rsa, NULL)); p = key.ptr; i2d_RSA_PUBKEY(rsa, &p); @@ -215,7 +215,7 @@ bool openssl_rsa_fingerprint(RSA *rsa, key_encoding_type_t type, chunk_t *fp) * Implementation of public_key_t.get_fingerprint. */ static bool get_fingerprint(private_openssl_rsa_public_key_t *this, - key_encoding_type_t type, chunk_t *fingerprint) + cred_encoding_type_t type, chunk_t *fingerprint) { return openssl_rsa_fingerprint(this->rsa, type, fingerprint); } @@ -224,14 +224,14 @@ static bool get_fingerprint(private_openssl_rsa_public_key_t *this, * Implementation of public_key_t.get_encoding. */ static bool get_encoding(private_openssl_rsa_public_key_t *this, - key_encoding_type_t type, chunk_t *encoding) + cred_encoding_type_t type, chunk_t *encoding) { u_char *p; switch (type) { - case KEY_PUB_SPKI_ASN1_DER: - case KEY_PUB_PEM: + case PUBKEY_SPKI_ASN1_DER: + case PUBKEY_PEM: { bool success = TRUE; @@ -239,18 +239,18 @@ static bool get_encoding(private_openssl_rsa_public_key_t *this, p = encoding->ptr; i2d_RSA_PUBKEY(this->rsa, &p); - if (type == KEY_PUB_PEM) + if (type == PUBKEY_PEM) { chunk_t asn1_encoding = *encoding; - success = lib->encoding->encode(lib->encoding, KEY_PUB_PEM, - NULL, encoding, KEY_PART_RSA_PUB_ASN1_DER, - asn1_encoding, KEY_PART_END); + success = lib->encoding->encode(lib->encoding, PUBKEY_PEM, + NULL, encoding, CRED_PART_RSA_PUB_ASN1_DER, + asn1_encoding, CRED_PART_END); chunk_clear(&asn1_encoding); } return success; } - case KEY_PUB_ASN1_DER: + case PUBKEY_ASN1_DER: { *encoding = chunk_alloc(i2d_RSAPublicKey(this->rsa, NULL)); p = encoding->ptr; @@ -299,9 +299,9 @@ static private_openssl_rsa_public_key_t *create_empty() this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt_; this->public.interface.equals = public_key_equals; this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize; - this->public.interface.get_fingerprint = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *fp))get_fingerprint; + this->public.interface.get_fingerprint = (bool(*)(public_key_t*, cred_encoding_type_t type, chunk_t *fp))get_fingerprint; this->public.interface.has_fingerprint = (bool(*)(public_key_t*, chunk_t fp))public_key_has_fingerprint; - this->public.interface.get_encoding = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *encoding))get_encoding; + this->public.interface.get_encoding = (bool(*)(public_key_t*, cred_encoding_type_t type, chunk_t *encoding))get_encoding; this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref; this->public.interface.destroy = (void (*)(public_key_t *this))destroy; @@ -345,13 +345,25 @@ openssl_rsa_public_key_t *openssl_rsa_public_key_load(key_type_t type, this = create_empty(); if (blob.ptr) { - this->rsa = d2i_RSAPublicKey(NULL, (const u_char**)&blob.ptr, blob.len); + switch (type) + { + case KEY_ANY: + this->rsa = d2i_RSA_PUBKEY(NULL, (const u_char**)&blob.ptr, + blob.len); + break; + case KEY_RSA: + this->rsa = d2i_RSAPublicKey(NULL, (const u_char**)&blob.ptr, + blob.len); + break; + default: + break; + } if (this->rsa) { return &this->public; } } - else if (n.ptr && e.ptr) + else if (n.ptr && e.ptr && type == KEY_RSA) { this->rsa = RSA_new(); this->rsa->n = BN_bin2bn((const u_char*)n.ptr, n.len, NULL); diff --git a/src/libstrongswan/plugins/openssl/openssl_sha1_prf.h b/src/libstrongswan/plugins/openssl/openssl_sha1_prf.h index 9a24e7ee1..384e328e2 100644 --- a/src/libstrongswan/plugins/openssl/openssl_sha1_prf.h +++ b/src/libstrongswan/plugins/openssl/openssl_sha1_prf.h @@ -15,7 +15,7 @@ /** * @defgroup openssl_sha1_prf openssl_sha1_prf - * @{ @ingroup sha1_p + * @{ @ingroup openssl_p */ #ifndef OPENSSL_SHA1_PRF_H_ diff --git a/src/libstrongswan/plugins/openssl/openssl_util.c b/src/libstrongswan/plugins/openssl/openssl_util.c index 55b18a524..99dca3631 100644 --- a/src/libstrongswan/plugins/openssl/openssl_util.c +++ b/src/libstrongswan/plugins/openssl/openssl_util.c @@ -100,7 +100,6 @@ error: return FALSE; } - /** * Described in header. */ @@ -124,3 +123,85 @@ bool openssl_bn_split(chunk_t chunk, BIGNUM *a, BIGNUM *b) return TRUE; } +/** + * Described in header. + */ +chunk_t openssl_asn1_obj2chunk(ASN1_OBJECT *asn1) +{ + if (asn1) + { + return chunk_create(asn1->data, asn1->length); + } + return chunk_empty; +} + +/** + * Described in header. + */ +chunk_t openssl_asn1_str2chunk(ASN1_STRING *asn1) +{ + if (asn1) + { + return chunk_create(ASN1_STRING_data(asn1), ASN1_STRING_length(asn1)); + } + return chunk_empty; +} + +/** + * Convert a X509 name to a ID_DER_ASN1_DN identification_t + */ +identification_t *openssl_x509_name2id(X509_NAME *name) +{ + if (name) + { + identification_t *id; + chunk_t chunk; + + chunk = openssl_i2chunk(X509_NAME, name); + if (chunk.len) + { + id = identification_create_from_encoding(ID_DER_ASN1_DN, chunk); + free(chunk.ptr); + return id; + } + } + return NULL; +} + +/** + * We can't include <asn1/asn1.h>, as the ASN1_ definitions would clash + * with OpenSSL. Redeclare what we need. + */ +int asn1_known_oid(chunk_t); +time_t asn1_to_time(chunk_t *,int); + +/** + * Described in header. + */ +int openssl_asn1_known_oid(ASN1_OBJECT *obj) +{ + return asn1_known_oid(openssl_asn1_obj2chunk(obj)); +} + +/** + * Described in header. + */ +time_t openssl_asn1_to_time(ASN1_TIME *time) +{ + chunk_t chunk; + + if (time) + { + chunk = openssl_asn1_str2chunk(time); + switch (time->type) + { + case V_ASN1_UTCTIME: + case V_ASN1_GENERALIZEDTIME: + return asn1_to_time(&chunk, time->type); + default: + break; + } + } + DBG1(DBG_LIB, "invalid ASN1 time"); + return 0; +} diff --git a/src/libstrongswan/plugins/openssl/openssl_util.h b/src/libstrongswan/plugins/openssl/openssl_util.h index 538008f2c..25c692a1a 100644 --- a/src/libstrongswan/plugins/openssl/openssl_util.h +++ b/src/libstrongswan/plugins/openssl/openssl_util.h @@ -23,6 +23,7 @@ #include <library.h> #include <openssl/bn.h> +#include <openssl/asn1.h> /** * Returns the length in bytes of a field element @@ -37,7 +38,7 @@ * @param hash_type NID of the hash * @param data the chunk of data to hash * @param hash chunk that contains the hash - * @return TRUE on success, FALSE otherwise + * @return TRUE on success, FALSE otherwise */ bool openssl_hash_chunk(int hash_type, chunk_t data, chunk_t *hash); @@ -65,4 +66,57 @@ bool openssl_bn_cat(int len, BIGNUM *a, BIGNUM *b, chunk_t *chunk); */ bool openssl_bn_split(chunk_t chunk, BIGNUM *a, BIGNUM *b); + +/** + * Allocate a chunk using the i2d function of a given object + * + * @param type type of the object + * @param obj object to convert to DER + * @returns allocated chunk of the object, or chunk_empty + */ +#define openssl_i2chunk(type, obj) ({ \ + unsigned char *ptr = NULL; \ + int len = i2d_##type(obj, &ptr); \ + len < 0 ? chunk_empty : chunk_create(ptr, len);}) + +/** + * Convert an OpenSSL ASN1_OBJECT to a chunk. + * + * @param asn1 asn1 object to convert + * @return chunk, pointing into asn1 object + */ +chunk_t openssl_asn1_obj2chunk(ASN1_OBJECT *asn1); + +/** + * Convert an OpenSSL ASN1_STRING to a chunk. + * + * @param asn1 asn1 string to convert + * @return chunk, pointing into asn1 string + */ +chunk_t openssl_asn1_str2chunk(ASN1_STRING *asn1); + +/** + * Convert an openssl X509_NAME to a identification_t of type ID_DER_ASN1_DN. + * + * @param name name to convert + * @return identification_t, NULL on error + */ +identification_t *openssl_x509_name2id(X509_NAME *name); + +/** + * Check if an ASN1 oid is a an OID known by libstrongswan. + * + * @param obj openssl ASN1 object + * @returns OID, as defined in <asn1/oid.h> + */ +int openssl_asn1_known_oid(ASN1_OBJECT *obj); + +/** + * Convert an OpenSSL ASN1_TIME to a time_t. + * + * @param time openssl ASN1_TIME + * @returns time_t, 0 on error + */ +time_t openssl_asn1_to_time(ASN1_TIME *time); + #endif /** OPENSSL_UTIL_H_ @}*/ diff --git a/src/libstrongswan/plugins/openssl/openssl_x509.c b/src/libstrongswan/plugins/openssl/openssl_x509.c new file mode 100644 index 000000000..1c9bb699e --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_x509.c @@ -0,0 +1,871 @@ +/* + * 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. + */ + +/* + * Copyright (C) 2010 secunet Security Networks AG + * Copyright (C) 2010 Thomas Egerer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#include "openssl_x509.h" +#include "openssl_util.h" + +#include <debug.h> +#include <asn1/oid.h> +#include <utils/linked_list.h> + + +typedef struct private_openssl_x509_t private_openssl_x509_t; + +/** + * Private data of an openssl_x509_t object. + */ +struct private_openssl_x509_t { + + /** + * Public openssl_x509_t interface. + */ + openssl_x509_t public; + + /** + * OpenSSL certificate representation + */ + X509 *x509; + + /** + * DER encoded certificate + */ + chunk_t encoding; + + /** + * SHA1 hash of the certificate + */ + chunk_t hash; + + /** + * X509 flags + */ + x509_flag_t flags; + + /** + * Pathlen constraint + */ + int pathlen; + + /** + * certificate subject + */ + identification_t *subject; + + /** + * certificate issuer + */ + identification_t *issuer; + + /** + * Certificates public key + */ + public_key_t *pubkey; + + /** + * subjectKeyIdentifier as read from cert + */ + chunk_t subjectKeyIdentifier; + + /** + * authorityKeyIdentifier as read from cert + */ + chunk_t authKeyIdentifier; + + /** + * Start time of certificate validity + */ + time_t notBefore; + + /** + * End time of certificate validity + */ + time_t notAfter; + + /** + * Signature scheme of the certificate + */ + signature_scheme_t scheme; + + /** + * subjectAltNames + */ + linked_list_t *subjectAltNames; + + /** + * issuerAltNames + */ + linked_list_t *issuerAltNames; + + /** + * List of CRL URIs + */ + linked_list_t *crl_uris; + + /** + * List of OCSP URIs + */ + linked_list_t *ocsp_uris; + + /** + * References to this cert + */ + refcount_t ref; +}; + +/** + * Convert a GeneralName to an identification_t. + */ +static identification_t *general_name2id(GENERAL_NAME *name) +{ + if (!name) + { + return NULL; + } + switch (name->type) + { + case GEN_EMAIL: + return identification_create_from_encoding(ID_RFC822_ADDR, + openssl_asn1_str2chunk(name->d.rfc822Name)); + case GEN_DNS: + return identification_create_from_encoding(ID_FQDN, + openssl_asn1_str2chunk(name->d.dNSName)); + case GEN_URI: + return identification_create_from_encoding(ID_DER_ASN1_GN_URI, + openssl_asn1_str2chunk(name->d.uniformResourceIdentifier)); + case GEN_IPADD: + { + chunk_t chunk = openssl_asn1_str2chunk(name->d.iPAddress); + if (chunk.len == 4) + { + return identification_create_from_encoding(ID_IPV4_ADDR, chunk); + } + if (chunk.len == 16) + { + return identification_create_from_encoding(ID_IPV6_ADDR, chunk); + } + return NULL; + } + case GEN_DIRNAME : + return openssl_x509_name2id(name->d.directoryName); + default: + return NULL; + } +} + +METHOD(x509_t, get_flags, x509_flag_t, + private_openssl_x509_t *this) +{ + return this->flags; +} + +METHOD(x509_t, get_serial, chunk_t, + private_openssl_x509_t *this) +{ + return openssl_asn1_str2chunk(X509_get_serialNumber(this->x509)); +} + +METHOD(x509_t, get_subjectKeyIdentifier, chunk_t, + private_openssl_x509_t *this) +{ + chunk_t fingerprint; + + if (this->subjectKeyIdentifier.len) + { + return this->subjectKeyIdentifier; + } + if (this->pubkey->get_fingerprint(this->pubkey, KEYID_PUBKEY_SHA1, + &fingerprint)) + { + return fingerprint; + } + return chunk_empty; +} + +METHOD(x509_t, get_authKeyIdentifier, chunk_t, + private_openssl_x509_t *this) +{ + if (this->authKeyIdentifier.len) + { + return this->authKeyIdentifier; + } + return chunk_empty; +} + +METHOD(x509_t, get_pathLenConstraint, int, + private_openssl_x509_t *this) +{ + return this->pathlen; +} + +METHOD(x509_t, create_subjectAltName_enumerator, enumerator_t*, + private_openssl_x509_t *this) +{ + return this->subjectAltNames->create_enumerator(this->subjectAltNames); +} + +METHOD(x509_t, create_crl_uri_enumerator, enumerator_t*, + private_openssl_x509_t *this) +{ + return this->crl_uris->create_enumerator(this->crl_uris); +} + +METHOD(x509_t, create_ocsp_uri_enumerator, enumerator_t*, + private_openssl_x509_t *this) +{ + return this->ocsp_uris->create_enumerator(this->ocsp_uris); +} + +METHOD(x509_t, create_ipAddrBlock_enumerator, enumerator_t*, + private_openssl_x509_t *this) +{ + /* TODO */ + return enumerator_create_empty(); +} + +METHOD(certificate_t, get_type, certificate_type_t, + private_openssl_x509_t *this) +{ + return CERT_X509; +} + +METHOD(certificate_t, get_subject, identification_t*, + private_openssl_x509_t *this) +{ + return this->subject; +} + +METHOD(certificate_t, get_issuer, identification_t*, + private_openssl_x509_t *this) +{ + return this->issuer; +} + +METHOD(certificate_t, has_subject, id_match_t, + private_openssl_x509_t *this, identification_t *subject) +{ + identification_t *current; + enumerator_t *enumerator; + id_match_t match, best; + + if (subject->get_type(subject) == ID_KEY_ID) + { + if (chunk_equals(this->hash, subject->get_encoding(subject))) + { + return ID_MATCH_PERFECT; + } + } + best = this->subject->matches(this->subject, subject); + enumerator = create_subjectAltName_enumerator(this); + while (enumerator->enumerate(enumerator, ¤t)) + { + match = current->matches(current, subject); + if (match > best) + { + best = match; + } + } + enumerator->destroy(enumerator); + return best; +} + +METHOD(certificate_t, has_issuer, id_match_t, + private_openssl_x509_t *this, identification_t *issuer) +{ + /* issuerAltNames currently not supported */ + return this->issuer->matches(this->issuer, issuer); +} + +METHOD(certificate_t, issued_by, bool, + private_openssl_x509_t *this, certificate_t *issuer) +{ + public_key_t *key; + bool valid; + x509_t *x509 = (x509_t*)issuer; + chunk_t tbs; + + if (&this->public.x509.interface == issuer) + { + if (this->flags & X509_SELF_SIGNED) + { + return TRUE; + } + } + else + { + if (issuer->get_type(issuer) != CERT_X509) + { + return FALSE; + } + if (!(x509->get_flags(x509) & X509_CA)) + { + return FALSE; + } + if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer))) + { + return FALSE; + } + } + if (this->scheme == SIGN_UNKNOWN) + { + return FALSE; + } + key = issuer->get_public_key(issuer); + if (!key) + { + return FALSE; + } + tbs = openssl_i2chunk(X509_CINF, this->x509->cert_info); + valid = key->verify(key, this->scheme, tbs, + openssl_asn1_str2chunk(this->x509->signature)); + free(tbs.ptr); + key->destroy(key); + return valid; +} + +METHOD(certificate_t, get_public_key, public_key_t*, + private_openssl_x509_t *this) +{ + return this->pubkey->get_ref(this->pubkey); +} + +METHOD(certificate_t, get_validity, bool, + private_openssl_x509_t *this, + time_t *when, time_t *not_before, time_t *not_after) +{ + time_t t; + + if (when) + { + t = *when; + } + else + { + t = time(NULL); + } + if (not_before) + { + *not_before = this->notBefore; + } + if (not_after) + { + *not_after = this->notAfter; + } + return (t >= this->notBefore && t <= this->notAfter); +} + +METHOD(certificate_t, get_encoding, bool, + private_openssl_x509_t *this, cred_encoding_type_t type, chunk_t *encoding) +{ + if (type == CERT_ASN1_DER) + { + *encoding = chunk_clone(this->encoding); + return TRUE; + } + return lib->encoding->encode(lib->encoding, type, NULL, encoding, + CRED_PART_X509_ASN1_DER, this->encoding, CRED_PART_END); +} + + +METHOD(certificate_t, equals, bool, + private_openssl_x509_t *this, certificate_t *other) +{ + chunk_t encoding; + bool equal; + + if (this == (private_openssl_x509_t*)other) + { + return TRUE; + } + if (other->get_type(other) != CERT_X509) + { + return FALSE; + } + if (other->equals == (void*)equals) + { /* skip allocation if we have the same implementation */ + encoding = ((private_openssl_x509_t*)other)->encoding; + return chunk_equals(this->encoding, encoding); + } + if (!other->get_encoding(other, CERT_ASN1_DER, &encoding)) + { + return FALSE; + } + equal = chunk_equals(this->encoding, encoding); + free(encoding.ptr); + return equal; +} + +METHOD(certificate_t, get_ref, certificate_t*, + private_openssl_x509_t *this) +{ + ref_get(&this->ref); + return &this->public.x509.interface; +} + +METHOD(certificate_t, destroy, void, + private_openssl_x509_t *this) +{ + if (ref_put(&this->ref)) + { + if (this->x509) + { + X509_free(this->x509); + } + DESTROY_IF(this->subject); + DESTROY_IF(this->issuer); + DESTROY_IF(this->pubkey); + free(this->subjectKeyIdentifier.ptr); + free(this->authKeyIdentifier.ptr); + free(this->encoding.ptr); + free(this->hash.ptr); + this->subjectAltNames->destroy_offset(this->subjectAltNames, + offsetof(identification_t, destroy)); + this->issuerAltNames->destroy_offset(this->issuerAltNames, + offsetof(identification_t, destroy)); + this->crl_uris->destroy_function(this->crl_uris, free); + this->ocsp_uris->destroy_function(this->ocsp_uris, free); + free(this); + } +} + +/** + * Create an empty certificate + */ +static private_openssl_x509_t *create_empty() +{ + private_openssl_x509_t *this; + + INIT(this, + .public = { + .x509 = { + .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_pathLenConstraint = _get_pathLenConstraint, + .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, + }, + }, + .subjectAltNames = linked_list_create(), + .issuerAltNames = linked_list_create(), + .crl_uris = linked_list_create(), + .ocsp_uris = linked_list_create(), + .pathlen = X509_NO_PATH_LEN_CONSTRAINT, + .ref = 1, + ); + + return this; +} + +/** + * parse an extionsion containing GENERAL_NAMES into a list + */ +static bool parse_generalNames_ext(linked_list_t *list, + X509_EXTENSION *ext) +{ + GENERAL_NAMES *names; + GENERAL_NAME *name; + identification_t *id; + int i, num; + + names = X509V3_EXT_d2i(ext); + if (!names) + { + return FALSE; + } + + num = sk_GENERAL_NAME_num(names); + for (i = 0; i < num; i++) + { + name = sk_GENERAL_NAME_value(names, i); + id = general_name2id(name); + if (id) + { + list->insert_last(list, id); + } + GENERAL_NAME_free(name); + } + sk_GENERAL_NAME_free(names); + return TRUE; +} + +/** + * parse basic constraints + */ +static bool parse_basicConstraints_ext(private_openssl_x509_t *this, + X509_EXTENSION *ext) +{ + BASIC_CONSTRAINTS *constraints; + + constraints = (BASIC_CONSTRAINTS*)X509V3_EXT_d2i(ext); + if (constraints) + { + if (constraints->ca) + { + this->flags |= X509_CA; + } + if (constraints->pathlen) + { + this->pathlen = ASN1_INTEGER_get(constraints->pathlen); + } + BASIC_CONSTRAINTS_free(constraints); + return TRUE; + } + return FALSE; +} + +/** + * Parse CRL distribution points + */ +static bool parse_crlDistributionPoints_ext(private_openssl_x509_t *this, + X509_EXTENSION *ext) +{ + CRL_DIST_POINTS *cdps; + DIST_POINT *cdp; + identification_t *id; + char *uri; + int i, j, point_num, name_num; + + cdps = X509V3_EXT_d2i(ext); + if (!cdps) + { + return FALSE; + } + point_num = sk_DIST_POINT_num(cdps); + for (i = 0; i < point_num; i++) + { + cdp = sk_DIST_POINT_value(cdps, i); + if (cdp) + { + if (cdp->distpoint && cdp->distpoint->type == 0 && + cdp->distpoint->name.fullname) + { + name_num = sk_GENERAL_NAME_num(cdp->distpoint->name.fullname); + for (j = 0; j < name_num; j++) + { + id = general_name2id(sk_GENERAL_NAME_value( + cdp->distpoint->name.fullname, j)); + if (id) + { + if (asprintf(&uri, "%Y", id) > 0) + { + this->crl_uris->insert_first(this->crl_uris, uri); + } + id->destroy(id); + } + } + } + DIST_POINT_free(cdp); + } + } + sk_DIST_POINT_free(cdps); + return TRUE; +} + +/** + * Parse authorityInfoAccess with OCSP URIs + */ +static bool parse_authorityInfoAccess_ext(private_openssl_x509_t *this, + X509_EXTENSION *ext) +{ + AUTHORITY_INFO_ACCESS *infos; + ACCESS_DESCRIPTION *desc; + identification_t *id; + int i, num; + char *uri; + + infos = X509V3_EXT_d2i(ext); + if (!infos) + { + return FALSE; + } + num = sk_ACCESS_DESCRIPTION_num(infos); + for (i = 0; i < num; i++) + { + desc = sk_ACCESS_DESCRIPTION_value(infos, i); + if (desc) + { + if (openssl_asn1_known_oid(desc->method) == OID_OCSP) + { + id = general_name2id(desc->location); + if (id) + { + if (asprintf(&uri, "%Y", id) > 0) + { + this->ocsp_uris->insert_first(this->ocsp_uris, uri); + } + id->destroy(id); + } + } + ACCESS_DESCRIPTION_free(desc); + } + } + sk_ACCESS_DESCRIPTION_free(infos); + return TRUE; +} + +/** + * Parse authorityKeyIdentifier extension + */ +static bool parse_authKeyIdentifier_ext(private_openssl_x509_t *this, + X509_EXTENSION *ext) +{ + AUTHORITY_KEYID *keyid; + + keyid = (AUTHORITY_KEYID*)X509V3_EXT_d2i(ext); + if (keyid) + { + free(this->authKeyIdentifier.ptr); + this->authKeyIdentifier = chunk_clone( + openssl_asn1_str2chunk(keyid->keyid)); + AUTHORITY_KEYID_free(keyid); + return TRUE; + } + return FALSE; +} + +/** + * Parse subjectKeyIdentifier extension + */ +static bool parse_subjectKeyIdentifier_ext(private_openssl_x509_t *this, + X509_EXTENSION *ext) +{ + chunk_t ostr; + + ostr = openssl_asn1_str2chunk(X509_EXTENSION_get_data(ext)); + /* quick and dirty unwrap of octet string */ + if (ostr.len > 2 && + ostr.ptr[0] == V_ASN1_OCTET_STRING && ostr.ptr[1] == ostr.len - 2) + { + free(this->subjectKeyIdentifier.ptr); + this->subjectKeyIdentifier = chunk_clone(chunk_skip(ostr, 2)); + return TRUE; + } + return FALSE; +} + +/** + * Parse X509 extensions we are interested in + */ +static bool parse_extensions(private_openssl_x509_t *this) +{ + STACK_OF(X509_EXTENSION) *extensions; + int i, num; + + extensions = this->x509->cert_info->extensions; + if (extensions) + { + num = sk_X509_EXTENSION_num(extensions); + + for (i = 0; i < num; i++) + { + X509_EXTENSION *ext; + bool ok; + + ext = sk_X509_EXTENSION_value(extensions, i); + switch (OBJ_obj2nid(X509_EXTENSION_get_object(ext))) + { + case NID_info_access: + ok = parse_authorityInfoAccess_ext(this, ext); + break; + case NID_authority_key_identifier: + ok = parse_authKeyIdentifier_ext(this, ext); + break; + case NID_subject_key_identifier: + ok = parse_subjectKeyIdentifier_ext(this, ext); + break; + case NID_subject_alt_name: + ok = parse_generalNames_ext(this->subjectAltNames, ext); + break; + case NID_issuer_alt_name: + ok = parse_generalNames_ext(this->issuerAltNames, ext); + break; + case NID_basic_constraints: + ok = parse_basicConstraints_ext(this, ext); + break; + case NID_crl_distribution_points: + ok = parse_crlDistributionPoints_ext(this, ext); + break; + default: + ok = TRUE; + break; + } + if (!ok) + { + return FALSE; + } + } + } + return TRUE; +} + +/** + * Parse a DER encoded x509 certificate + */ +static bool parse_certificate(private_openssl_x509_t *this) +{ + const unsigned char *ptr = this->encoding.ptr; + hasher_t *hasher; + chunk_t chunk; + + this->x509 = d2i_X509(NULL, &ptr, this->encoding.len); + if (!this->x509) + { + return FALSE; + } + this->subject = openssl_x509_name2id(X509_get_subject_name(this->x509)); + this->issuer = openssl_x509_name2id(X509_get_issuer_name(this->x509)); + + switch (openssl_asn1_known_oid(this->x509->cert_info->key->algor->algorithm)) + { + case OID_RSA_ENCRYPTION: + this->pubkey = lib->creds->create(lib->creds, + CRED_PUBLIC_KEY, KEY_RSA, BUILD_BLOB_ASN1_DER, + openssl_asn1_str2chunk(X509_get0_pubkey_bitstr(this->x509)), + BUILD_END); + break; + case OID_EC_PUBLICKEY: + /* for ECDSA, we need the full subjectPublicKeyInfo, as it contains + * the curve parameters. */ + chunk = openssl_i2chunk(X509_PUBKEY, X509_get_X509_PUBKEY(this->x509)); + this->pubkey = lib->creds->create(lib->creds, + CRED_PUBLIC_KEY, KEY_ECDSA, BUILD_BLOB_ASN1_DER, + chunk, BUILD_END); + free(chunk.ptr); + break; + default: + DBG1(DBG_LIB, "unsupported public key algorithm"); + break; + } + if (!this->subject || !this->issuer || !this->pubkey) + { + return FALSE; + } + + this->notBefore = openssl_asn1_to_time(X509_get_notBefore(this->x509)); + this->notAfter = openssl_asn1_to_time(X509_get_notAfter(this->x509)); + + if (!chunk_equals( + openssl_asn1_obj2chunk(this->x509->cert_info->signature->algorithm), + openssl_asn1_obj2chunk(this->x509->sig_alg->algorithm))) + { + return FALSE; + } + this->scheme = signature_scheme_from_oid(openssl_asn1_known_oid( + this->x509->sig_alg->algorithm)); + + if (!parse_extensions(this)) + { + return TRUE; + } + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher) + { + return FALSE; + } + hasher->allocate_hash(hasher, this->encoding, &this->hash); + hasher->destroy(hasher); + + if (issued_by(this, &this->public.x509.interface)) + { + this->flags |= X509_SELF_SIGNED; + } + return TRUE; +} + +openssl_x509_t *openssl_x509_load(certificate_type_t type, va_list args) +{ + chunk_t blob = chunk_empty; + x509_flag_t flags = 0; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_BLOB_ASN1_DER: + blob = va_arg(args, chunk_t); + continue; + case BUILD_X509_FLAG: + flags |= va_arg(args, x509_flag_t); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + + if (blob.ptr) + { + private_openssl_x509_t *this; + + this = create_empty(); + this->encoding = chunk_clone(blob); + this->flags |= flags; + if (parse_certificate(this)) + { + return &this->public; + } + DBG1(DBG_LIB, "OpenSSL X.509 parsing failed"); + destroy(this); + } + return NULL; +} diff --git a/src/libstrongswan/plugins/openssl/openssl_x509.h b/src/libstrongswan/plugins/openssl/openssl_x509.h new file mode 100644 index 000000000..52555925a --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_x509.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +/** + * @defgroup openssl_x509 openssl_x509 + * @{ @ingroup openssl_p + */ + +#ifndef OPENSSL_X509_H_ +#define OPENSSL_X509_H_ + +#include <credentials/certificates/x509.h> + +typedef struct openssl_x509_t openssl_x509_t; + +/** + * X.509 certificate implementation using OpenSSL. + */ +struct openssl_x509_t { + + /** + * Implements x509_t interface. + */ + x509_t x509; +}; + +/** + * Load a X.509 certificate. + * + * This function takes a BUILD_BLOB_ASN1_DER. + * + * @param type certificate type, CERT_X509 only + * @param args builder_part_t argument list + * @return X.509 certificate, NULL on failure + */ +openssl_x509_t *openssl_x509_load(certificate_type_t type, va_list args); + +#endif /** OPENSSL_X509_H_ @}*/ |