From f03e0e91479424c120c92cb44484651bb59f3f3e Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Sun, 13 Sep 2009 21:00:15 +0200 Subject: [PATCH] support of PKCS#10 certificate request parsing --- src/libstrongswan/Makefile.am | 1 + .../credentials/certificates/certificate.c | 1 + .../credentials/certificates/certificate.h | 4 +- .../credentials/certificates/pkcs10.h | 57 ++ .../credentials/certificates/req.h | 105 +++ src/libstrongswan/plugins/pem/pem_plugin.c | 2 + src/libstrongswan/plugins/x509/Makefile.am | 1 + src/libstrongswan/plugins/x509/x509_pkcs10.c | 640 ++++++++++++++++++ src/libstrongswan/plugins/x509/x509_pkcs10.h | 65 ++ src/libstrongswan/plugins/x509/x509_plugin.c | 9 + src/pki/commands/issue.c | 104 ++- 11 files changed, 965 insertions(+), 24 deletions(-) create mode 100644 src/libstrongswan/credentials/certificates/pkcs10.h create mode 100644 src/libstrongswan/credentials/certificates/req.h create mode 100644 src/libstrongswan/plugins/x509/x509_pkcs10.c create mode 100644 src/libstrongswan/plugins/x509/x509_pkcs10.h diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 7cba9fe9e9..46a2f09db4 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -32,6 +32,7 @@ credentials/certificates/certificate.c credentials/certificates/certificate.h \ credentials/certificates/x509.h credentials/certificates/x509.c \ credentials/certificates/ac.h \ credentials/certificates/crl.h credentials/certificates/crl.c \ +credentials/certificates/pkcs10.h \ credentials/certificates/ocsp_request.h \ credentials/certificates/ocsp_response.h credentials/certificates/ocsp_response.c \ database/database.h database/database_factory.h database/database_factory.c \ diff --git a/src/libstrongswan/credentials/certificates/certificate.c b/src/libstrongswan/credentials/certificates/certificate.c index 93ce7e970d..b99e63eab2 100644 --- a/src/libstrongswan/credentials/certificates/certificate.c +++ b/src/libstrongswan/credentials/certificates/certificate.c @@ -24,6 +24,7 @@ ENUM(certificate_type_names, CERT_ANY, CERT_PLUTO_CRL, "X509_OCSP_REQUEST", "X509_OCSP_RESPONSE", "X509_AC", + "PKCS10_REQUEST", "TRUSTED_PUBKEY", "PGP", "PLUTO_CERT", diff --git a/src/libstrongswan/credentials/certificates/certificate.h b/src/libstrongswan/credentials/certificates/certificate.h index 81a231dc96..1b05492839 100644 --- a/src/libstrongswan/credentials/certificates/certificate.h +++ b/src/libstrongswan/credentials/certificates/certificate.h @@ -45,6 +45,8 @@ enum certificate_type_t { CERT_X509_OCSP_RESPONSE, /** X.509 attribute certificate */ CERT_X509_AC, + /** PKCS#10 certificate request */ + CERT_PKCS10_REQUEST, /** trusted, preinstalled public key */ CERT_TRUSTED_PUBKEY, /** PGP certificate */ @@ -96,7 +98,7 @@ struct certificate_t { /** * Get the type of the certificate. * - * @return certifcate type + * @return certificate type */ certificate_type_t (*get_type)(certificate_t *this); diff --git a/src/libstrongswan/credentials/certificates/pkcs10.h b/src/libstrongswan/credentials/certificates/pkcs10.h new file mode 100644 index 0000000000..9a49797578 --- /dev/null +++ b/src/libstrongswan/credentials/certificates/pkcs10.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 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 . + * + * 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 req req + * @{ @ingroup certificates + */ + +#ifndef PKCS10_H_ +#define PKCS10_H_ + +#include +#include + +typedef struct pkcs10_t pkcs10_t; + +/** + * PKCS#10 certificate request interface. + * + * This interface adds additional methods to the certificate_t type to + * allow further operations on a certificate request. + */ +struct pkcs10_t { + + /** + * Implements certificate_t. + */ + certificate_t interface; + + /** + * Get the challenge password + * + * @return challenge password as a chunk_t + */ + chunk_t (*get_challengePassword)(pkcs10_t *this); + + /** + * Get. + * + * @return enumerator over subjectAltNames as identification_t* + */ + enumerator_t* (*create_subjectAltName_enumerator)(pkcs10_t *this); +}; + +#endif /** PKCS10_H_ @}*/ diff --git a/src/libstrongswan/credentials/certificates/req.h b/src/libstrongswan/credentials/certificates/req.h new file mode 100644 index 0000000000..540eb988be --- /dev/null +++ b/src/libstrongswan/credentials/certificates/req.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * 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 . + * + * 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 x509 x509 + * @{ @ingroup certificates + */ + +#ifndef X509_H_ +#define X509_H_ + +#include +#include + +typedef struct x509_t x509_t; +typedef enum x509_flag_t x509_flag_t; + +/** + * X.509 certificate flags. + */ +enum x509_flag_t { + /** cert has CA constraint */ + X509_CA = (1<<0), + /** cert has AA constraint */ + X509_AA = (1<<1), + /** cert has OCSP signer constraint */ + X509_OCSP_SIGNER = (1<<2), + /** cert is self-signed */ + X509_SELF_SIGNED = (1<<3), +}; + +/** + * enum names for x509 flags + */ +extern enum_name_t *x509_flag_names; + +/** + * X.509 certificate interface. + * + * This interface adds additional methods to the certificate_t type to + * allow further operations on these certificates. + */ +struct x509_t { + + /** + * Implements certificate_t. + */ + certificate_t interface; + + /** + * Get the flags set for this certificate. + * + * @return set of flags + */ + x509_flag_t (*get_flags)(x509_t *this); + + /** + * Get the certificate serial number. + * + * @return chunk pointing to internal serial number + */ + chunk_t (*get_serial)(x509_t *this); + + /** + * Get the the authorityKeyIdentifier. + * + * @return authKeyIdentifier as chunk_t, internal data + */ + chunk_t (*get_authKeyIdentifier)(x509_t *this); + + /** + * Create an enumerator over all subjectAltNames. + * + * @return enumerator over subjectAltNames as identification_t* + */ + enumerator_t* (*create_subjectAltName_enumerator)(x509_t *this); + + /** + * Create an enumerator over all CRL URIs. + * + * @return enumerator over URIs as char* + */ + enumerator_t* (*create_crl_uri_enumerator)(x509_t *this); + + /** + * Create an enumerator over all OCSP URIs. + * + * @return enumerator over URIs as char* + */ + enumerator_t* (*create_ocsp_uri_enumerator)(x509_t *this); +}; + +#endif /** X509_H_ @}*/ diff --git a/src/libstrongswan/plugins/pem/pem_plugin.c b/src/libstrongswan/plugins/pem/pem_plugin.c index 2a24e681c4..1afab2cf62 100644 --- a/src/libstrongswan/plugins/pem/pem_plugin.c +++ b/src/libstrongswan/plugins/pem/pem_plugin.c @@ -87,6 +87,8 @@ plugin_t *plugin_create() (builder_function_t)pem_certificate_load); lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, (builder_function_t)pem_certificate_load); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST, + (builder_function_t)pem_certificate_load); lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY, (builder_function_t)pem_certificate_load); lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_GPG, diff --git a/src/libstrongswan/plugins/x509/Makefile.am b/src/libstrongswan/plugins/x509/Makefile.am index e9668b4e4c..560e186e22 100644 --- a/src/libstrongswan/plugins/x509/Makefile.am +++ b/src/libstrongswan/plugins/x509/Makefile.am @@ -9,6 +9,7 @@ libstrongswan_x509_la_SOURCES = x509_plugin.h x509_plugin.c \ x509_cert.h x509_cert.c \ x509_crl.h x509_crl.c \ x509_ac.h x509_ac.c \ + x509_pkcs10.h x509_pkcs10.c \ x509_ocsp_request.h x509_ocsp_request.c \ x509_ocsp_response.h x509_ocsp_response.c \ ietf_attr_list.h ietf_attr_list.c diff --git a/src/libstrongswan/plugins/x509/x509_pkcs10.c b/src/libstrongswan/plugins/x509/x509_pkcs10.c new file mode 100644 index 0000000000..31e4683819 --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_pkcs10.c @@ -0,0 +1,640 @@ +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Copyright (C) 2009 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 . + * + * 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_pkcs10.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct private_x509_pkcs10_t private_x509_pkcs10_t; + +/** + * Private data of a x509_pkcs10_t object. + */ +struct private_x509_pkcs10_t { + /** + * Public interface for this certificate. + */ + x509_pkcs10_t public; + + /** + * PKCS#10 certificate request encoding in ASN.1 DER format + */ + chunk_t encoding; + + /** + * PKCS#10 request body over which signature is computed + */ + chunk_t certificationRequestInfo; + + /** + * Version of the PKCS#10 certificate request + */ + u_int version; + + /** + * ID representing the certificate subject + */ + identification_t *subject; + + /** + * List of subjectAltNames as identification_t + */ + linked_list_t *subjectAltNames; + + /** + * certificate's embedded public key + */ + public_key_t *public_key; + + /** + * challenge password + */ + chunk_t challengePassword; + + /** + * Signature algorithm + */ + int algorithm; + + /** + * Signature + */ + chunk_t signature; + + /** + * Is the certificate request self-signed? + */ + bool self_signed; + + /** + * Certificate request parsed from blob/file? + */ + bool parsed; + + /** + * reference count + */ + refcount_t ref; +}; + +/** + * Implementation of certificate_t.get_type. + */ +static certificate_type_t get_type(private_x509_pkcs10_t *this) +{ + return CERT_PKCS10_REQUEST; +} + +/** + * Implementation of certificate_t.get_subject and get_issuer. + */ +static identification_t* get_subject(private_x509_pkcs10_t *this) +{ + return this->subject; +} + +/** + * Implementation of certificate_t.has_subject and has_issuer. + */ +static id_match_t has_subject(private_x509_pkcs10_t *this, identification_t *subject) +{ + return this->subject->matches(this->subject, subject); +} + +/** + * Implementation of certificate_t.issued_by. + */ +static bool issued_by(private_x509_pkcs10_t *this, certificate_t *issuer) +{ + public_key_t *key; + signature_scheme_t scheme; + + if (&this->public.interface.interface != issuer) + { + return FALSE; + } + if (this->self_signed) + { + return TRUE; + } + + /* determine signature scheme */ + scheme = signature_scheme_from_oid(this->algorithm); + if (scheme == SIGN_UNKNOWN) + { + return FALSE; + } + + /* get the public key contained in the certificate request */ + key = this->public_key; + if (!key) + { + return FALSE; + } + return key->verify(key, scheme, this->certificationRequestInfo, + this->signature); +} + +/** + * Implementation of certificate_t.get_public_key. + */ +static public_key_t* get_public_key(private_x509_pkcs10_t *this) +{ + this->public_key->get_ref(this->public_key); + return this->public_key; +} + +/** + * Implementation of certificate_t.get_validity. + */ +static bool get_validity(private_x509_pkcs10_t *this, time_t *when, + time_t *not_before, time_t *not_after) +{ + if (not_before) + { + *not_before = 0; + } + if (not_after) + { + *not_after = ~0; + } + return TRUE; +} + +/** + * Implementation of certificate_t.is_newer. + */ +static bool is_newer(certificate_t *this, certificate_t *that) +{ + return FALSE; +} + +/** + * Implementation of certificate_t.get_encoding. + */ +static chunk_t get_encoding(private_x509_pkcs10_t *this) +{ + return chunk_clone(this->encoding); +} + +/** + * Implementation of certificate_t.equals. + */ +static bool equals(private_x509_pkcs10_t *this, certificate_t *other) +{ + chunk_t encoding; + bool equal; + + if (this == (private_x509_pkcs10_t*)other) + { + return TRUE; + } + if (other->get_type(other) != CERT_PKCS10_REQUEST) + { + return FALSE; + } + if (other->equals == (void*)equals) + { /* skip allocation if we have the same implementation */ + return chunk_equals(this->encoding, ((private_x509_pkcs10_t*)other)->encoding); + } + encoding = other->get_encoding(other); + equal = chunk_equals(this->encoding, encoding); + free(encoding.ptr); + return equal; +} + +/** + * Implementation of certificate_t.get_ref + */ +static private_x509_pkcs10_t* get_ref(private_x509_pkcs10_t *this) +{ + ref_get(&this->ref); + return this; +} + +/** + * Implementation of certificate_t.get_challengePassword. + */ +static chunk_t get_challengePassword(private_x509_pkcs10_t *this) +{ + return this->challengePassword; +} + +/** + * Implementation of pkcs10_t.create_subjectAltName_enumerator. + */ +static enumerator_t* create_subjectAltName_enumerator(private_x509_pkcs10_t *this) +{ + return this->subjectAltNames->create_enumerator(this->subjectAltNames); +} + +/** + * Imported from x509_cert.c + */ +extern void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list); + +/** + * ASN.1 definition of a PKCS#10 extension request + */ +static const asn1Object_t extensionRequestObjects[] = { + { 0, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 1, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ + { 2, "extnID", ASN1_OID, ASN1_BODY }, /* 2 */ + { 2, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 3 */ + { 2, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */ + { 1, "end loop", ASN1_EOC, ASN1_END }, /* 5 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKCS10_EXTN_ID 2 +#define PKCS10_EXTN_CRITICAL 3 +#define PKCS10_EXTN_VALUE 4 + +/** + * Parses a PKCS#10 extension request + */ +static bool parse_extension_request(private_x509_pkcs10_t *this, chunk_t blob, int level0) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + int extn_oid = OID_UNKNOWN; + bool success = FALSE; + bool critical; + + parser = asn1_parser_create(extensionRequestObjects, blob); + parser->set_top_level(parser, level0); + + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser)+1; + + switch (objectID) + { + case PKCS10_EXTN_ID: + extn_oid = asn1_known_oid(object); + break; + case PKCS10_EXTN_CRITICAL: + critical = object.len && *object.ptr; + DBG2(" %s", critical ? "TRUE" : "FALSE"); + break; + case PKCS10_EXTN_VALUE: + { + switch (extn_oid) + { + case OID_SUBJECT_ALT_NAME: + x509_parse_generalNames(object, level, FALSE, + this->subjectAltNames); + break; + default: + break; + } + break; + } + default: + break; + } + } + success = parser->success(parser); + parser->destroy(parser); + return success; +} + +/** + * Parses a PKCS#10 challenge password + */ +static bool parse_challengePassword(private_x509_pkcs10_t *this, chunk_t blob, int level) +{ + char tag; + + if (blob.len < 2) + { + DBG1("L%d - challengePassword: ASN.1 object smaller than 2 octets", + level); + return FALSE; + } + tag = *blob.ptr; + if (tag < ASN1_UTF8STRING || tag > ASN1_IA5STRING) + { + DBG1("L%d - challengePassword: ASN.1 object is not a character string", + level); + return FALSE; + } + if (asn1_length(&blob) == ASN1_INVALID_LENGTH) + { + DBG1("L%d - challengePassword: ASN.1 object has an invalid length", + level); + return FALSE; + } + DBG2("L%d - challengePassword:", level); + DBG4(" '%.*s'", blob.len, blob.ptr); + return TRUE; +} + +/** + * ASN.1 definition of a PKCS#10 certificate request + */ +static const asn1Object_t certificationRequestObjects[] = { + { 0, "certificationRequest", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "certificationRequestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ + { 2, "version", ASN1_INTEGER, ASN1_RAW }, /* 2 */ + { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 3 */ + { 2, "subjectPublicKeyInfo", ASN1_SEQUENCE, ASN1_RAW }, /* 4 */ + { 2, "attributes", ASN1_CONTEXT_C_0, ASN1_LOOP }, /* 5 */ + { 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 6 */ + { 4, "type", ASN1_OID, ASN1_BODY }, /* 7 */ + { 4, "values", ASN1_SET, ASN1_LOOP }, /* 8 */ + { 5, "value", ASN1_EOC, ASN1_RAW }, /* 9 */ + { 4, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ + { 2, "end loop", ASN1_EOC, ASN1_END }, /* 11 */ + { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 12 */ + { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 13 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKCS10_CERT_REQUEST_INFO 1 +#define PKCS10_VERSION 2 +#define PKCS10_SUBJECT 3 +#define PKCS10_SUBJECT_PUBLIC_KEY_INFO 4 +#define PKCS10_ATTR_TYPE 7 +#define PKCS10_ATTR_VALUE 9 +#define PKCS10_ALGORITHM 12 +#define PKCS10_SIGNATURE 13 + +/** + * Parses a PKCS#10 certificate request + */ +static bool parse_certificate_request(private_x509_pkcs10_t *this) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + int attr_oid = OID_UNKNOWN; + bool success = FALSE; + + parser = asn1_parser_create(certificationRequestObjects, this->encoding); + + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser)+1; + + switch (objectID) + { + case PKCS10_CERT_REQUEST_INFO: + this->certificationRequestInfo = object; + break; + case PKCS10_VERSION: + this->version = (object.len) ? (1+(u_int)*object.ptr) : 1; + DBG2(" v%d", this->version); + break; + break; + case PKCS10_SUBJECT: + this->subject = identification_create_from_encoding(ID_DER_ASN1_DN, object); + DBG2(" '%Y'", this->subject); + break; + case PKCS10_SUBJECT_PUBLIC_KEY_INFO: + this->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, + KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END); + if (this->public_key == NULL) + { + goto end; + } + break; + case PKCS10_ATTR_TYPE: + attr_oid = asn1_known_oid(object); + break; + case PKCS10_ATTR_VALUE: + switch (attr_oid) + { + case OID_EXTENSION_REQUEST: + if (!parse_extension_request(this, object, level)) + { + goto end; + } + break; + case OID_CHALLENGE_PASSWORD: + if (!parse_challengePassword(this, object, level)) + { + goto end; + } + break; + default: + break; + } + break; + case PKCS10_ALGORITHM: + this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case PKCS10_SIGNATURE: + this->signature = object; + break; + default: + break; + } + } + success = parser->success(parser); + +end: + parser->destroy(parser); + if (success) + { + /* check if the certificate request is self-signed */ + if (issued_by(this, &this->public.interface.interface)) + { + this->self_signed = TRUE; + } + else + { + DBG1("certificate request is not self-signed"); + success = FALSE; + } + } + return success; +} + +/** + * Implementation of certificate_t.destroy + */ +static void destroy(private_x509_pkcs10_t *this) +{ + if (ref_put(&this->ref)) + { + this->subjectAltNames->destroy_offset(this->subjectAltNames, + offsetof(identification_t, destroy)); + DESTROY_IF(this->subject); + DESTROY_IF(this->public_key); + chunk_free(&this->encoding); + if (!this->parsed) + { /* only parsed certificate requests point these fields to "encoded" */ + chunk_free(&this->certificationRequestInfo); + chunk_free(&this->challengePassword); + chunk_free(&this->signature); + } + free(this); + } +} + +/** + * create an empty but initialized PKCS#10 certificate request + */ +static private_x509_pkcs10_t* create_empty(void) +{ + private_x509_pkcs10_t *this = malloc_thing(private_x509_pkcs10_t); + + this->public.interface.interface.get_type = (certificate_type_t (*) (certificate_t*))get_type; + this->public.interface.interface.get_subject = (identification_t* (*) (certificate_t*))get_subject; + this->public.interface.interface.get_issuer = (identification_t* (*) (certificate_t*))get_subject; + this->public.interface.interface.has_subject = (id_match_t (*) (certificate_t*, identification_t*))has_subject; + this->public.interface.interface.has_issuer = (id_match_t (*) (certificate_t*, identification_t*))has_subject; + this->public.interface.interface.issued_by = (bool (*) (certificate_t*, certificate_t*))issued_by; + this->public.interface.interface.get_public_key = (public_key_t* (*) (certificate_t*))get_public_key; + this->public.interface.interface.get_validity = (bool (*) (certificate_t*, time_t*, time_t*, time_t*))get_validity; + this->public.interface.interface.is_newer = (bool (*) (certificate_t*,certificate_t*))is_newer; + this->public.interface.interface.get_encoding = (chunk_t (*) (certificate_t*))get_encoding; + this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t*))equals; + this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t*))get_ref; + this->public.interface.interface.destroy = (void (*)(certificate_t*))destroy; + this->public.interface.get_challengePassword = (chunk_t (*)(pkcs10_t*))get_challengePassword; + this->public.interface.create_subjectAltName_enumerator = (enumerator_t* (*)(pkcs10_t*))create_subjectAltName_enumerator; + + this->encoding = chunk_empty; + this->certificationRequestInfo = chunk_empty; + this->subject = NULL; + this->public_key = NULL; + this->subjectAltNames = linked_list_create(); + this->challengePassword = chunk_empty; + this->signature = chunk_empty; + this->ref = 1; + this->self_signed = FALSE; + this->parsed = FALSE; + + return this; +} + +/** + * Generate and sign a new certificate + */ +static bool generate(private_x509_pkcs10_t *cert, private_key_t *sign_key, + int digest_alg) +{ + /* TODO */ + return TRUE; +} + +/** + * See header. + */ +x509_pkcs10_t *x509_pkcs10_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_x509_pkcs10_t *cert = create_empty(); + + cert->encoding = chunk_clone(blob); + cert->parsed = TRUE; + if (parse_certificate_request(cert)) + { + return &cert->public; + } + destroy(cert); + } + return NULL; +} + +/** + * See header. + */ +x509_pkcs10_t *x509_pkcs10_gen(certificate_type_t type, va_list args) +{ + private_x509_pkcs10_t *cert; + private_key_t *sign_key = NULL; + hash_algorithm_t digest_alg = HASH_SHA1; + + cert = create_empty(); + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_SIGNING_KEY: + sign_key = va_arg(args, private_key_t*); + continue; + case BUILD_PUBLIC_KEY: + cert->public_key = va_arg(args, public_key_t*); + cert->public_key->get_ref(cert->public_key); + continue; + case BUILD_SUBJECT: + cert->subject = va_arg(args, identification_t*); + cert->subject = cert->subject->clone(cert->subject); + continue; + case BUILD_SUBJECT_ALTNAMES: + { + enumerator_t *enumerator; + identification_t *id; + linked_list_t *list; + + list = va_arg(args, linked_list_t*); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &id)) + { + cert->subjectAltNames->insert_last( + cert->subjectAltNames, id->clone(id)); + } + enumerator->destroy(enumerator); + continue; + } + case BUILD_DIGEST_ALG: + digest_alg = va_arg(args, int); + continue; + case BUILD_END: + break; + default: + destroy(cert); + return NULL; + } + break; + } + + if (sign_key && generate(cert, sign_key, digest_alg)) + { + return &cert->public; + } + destroy(cert); + return NULL; +} + diff --git a/src/libstrongswan/plugins/x509/x509_pkcs10.h b/src/libstrongswan/plugins/x509/x509_pkcs10.h new file mode 100644 index 0000000000..8bdc43363f --- /dev/null +++ b/src/libstrongswan/plugins/x509/x509_pkcs10.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008-2009 Martin Willi + * Copyright (C) 2009 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 . + * + * 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 x509_pkcs10 x509_pkcs10 + * @{ @ingroup x509_p + */ + +#ifndef X509_PKCS10_H_ +#define X509_PKCS10_H_ + +typedef struct x509_pkcs10_t x509_pkcs10_t; + +#include +#include + +/** + * Implementation of pkcs10_t/certificate_t using own ASN.1 parser. + */ +struct x509_pkcs10_t { + + /** + * Implements the pkcs10_t interface + */ + pkcs10_t interface; +}; + +/** + * Load a PKCS#10 certificate. + * + * This function takes a BUILD_BLOB_ASN1_DER. + * + * @param type certificate type, CERT_PKCS10_REQUEST only + * @param args builder_part_t argument list + * @return PKCS#10 certificate request, NULL on failure + */ +x509_pkcs10_t *x509_pkcs10_load(certificate_type_t type, va_list args); + +/** + * Generate a PKCS#10 certificate request. + * + * To issue a self-signed certificate, the function takes: + * BUILD_SUBJECT, BUILD_SUBJECT_ALTNAMES, BUILD_SIGNING_KEY, BUILD_DIGEST_ALG. + * + * @param type certificate type, CERT_PKCS10_REQUEST only + * @param args builder_part_t argument list + * @return PKCS#10 certificate request, NULL on failure + */ +x509_pkcs10_t *x509_pkcs10_gen(certificate_type_t type, va_list args); + +#endif /** X509_PKCS10_H_ @}*/ diff --git a/src/libstrongswan/plugins/x509/x509_plugin.c b/src/libstrongswan/plugins/x509/x509_plugin.c index 1c5a33b419..94c49b1e12 100644 --- a/src/libstrongswan/plugins/x509/x509_plugin.c +++ b/src/libstrongswan/plugins/x509/x509_plugin.c @@ -21,6 +21,7 @@ #include "x509_crl.h" #include "x509_ocsp_request.h" #include "x509_ocsp_response.h" +#include "x509_pkcs10.h" typedef struct private_x509_plugin_t private_x509_plugin_t; @@ -54,6 +55,10 @@ static void destroy(private_x509_plugin_t *this) (builder_function_t)x509_ocsp_request_gen); lib->creds->remove_builder(lib->creds, (builder_function_t)x509_ocsp_response_load); + lib->creds->remove_builder(lib->creds, + (builder_function_t)x509_pkcs10_gen); + lib->creds->remove_builder(lib->creds, + (builder_function_t)x509_pkcs10_load); free(this); } @@ -80,6 +85,10 @@ plugin_t *plugin_create() (builder_function_t)x509_ocsp_request_gen); lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE, (builder_function_t)x509_ocsp_response_load); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST, + (builder_function_t)x509_pkcs10_gen); + lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST, + (builder_function_t)x509_pkcs10_load); return &this->public.plugin; } diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c index 3f9a6c2bd8..9953e32c63 100644 --- a/src/pki/commands/issue.c +++ b/src/pki/commands/issue.c @@ -21,6 +21,7 @@ #include #include #include +#include /** * Issue a certificate using a CA certificate and key @@ -28,9 +29,10 @@ static int issue(int argc, char *argv[]) { hash_algorithm_t digest = HASH_SHA1; - certificate_t *cert = NULL, *ca =NULL; + certificate_t *cert_req = NULL, *cert = NULL, *ca =NULL; private_key_t *private = NULL; public_key_t *public = NULL; + bool pkcs10 = FALSE; char *file = NULL, *dn = NULL, *hex = NULL, *cacert = NULL, *cakey = NULL; char *error = NULL; identification_t *id = NULL; @@ -62,7 +64,11 @@ static int issue(int argc, char *argv[]) } continue; case 't': - if (!streq(optarg, "pub")) + if (streq(optarg, "pkcs10")) + { + pkcs10 = TRUE; + } + else if (!streq(optarg, "pub")) { error = "invalid input type"; goto usage; @@ -120,7 +126,7 @@ static int issue(int argc, char *argv[]) break; } - if (!dn) + if (!pkcs10 && !dn) { error = "--dn is required"; goto usage; @@ -135,11 +141,14 @@ static int issue(int argc, char *argv[]) error = "--cakey is required"; goto usage; } - id = identification_create_from_string(dn); - if (id->get_type(id) != ID_DER_ASN1_DN) + if (dn) { - error = "supplied --dn is not a distinguished name"; - goto end; + id = identification_create_from_string(dn); + if (id->get_type(id) != ID_DER_ASN1_DN) + { + error = "supplied --dn is not a distinguished name"; + goto end; + } } ca = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, cacert, BUILD_END); @@ -176,22 +185,6 @@ static int issue(int argc, char *argv[]) } public->destroy(public); - if (file) - { - public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, - BUILD_FROM_FILE, file, BUILD_END); - } - else - { - public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, - BUILD_FROM_FD, 0, BUILD_END); - } - if (!public) - { - error = "parsing public key failed"; - goto end; - } - if (hex) { serial = chunk_from_hex(chunk_create(hex, strlen(hex)), NULL); @@ -208,8 +201,72 @@ static int issue(int argc, char *argv[]) rng->allocate_bytes(rng, 8, &serial); rng->destroy(rng); } + + if (pkcs10) + { + enumerator_t *enumerator; + identification_t *subjectAltName; + pkcs10_t *req; + + if (file) + { + cert_req = lib->creds->create(lib->creds, CRED_CERTIFICATE, + CERT_PKCS10_REQUEST, + BUILD_FROM_FILE, file, BUILD_END); + } + else + { + cert_req = lib->creds->create(lib->creds, CRED_CERTIFICATE, + CERT_PKCS10_REQUEST, + BUILD_FROM_FD, 0, BUILD_END); + } + if (!cert_req) + { + error = "parsing certificate request failed"; + goto end; + } + + /* If not set yet use subject from PKCS#10 certificate request as DN */ + if (!id) + { + id = cert_req->get_subject(cert_req); + id = id->clone(id); + } + + /* Add subjectAltNames from PKCS#10 certificate request */ + req = (pkcs10_t*)cert_req; + enumerator = req->create_subjectAltName_enumerator(req); + while (enumerator->enumerate(enumerator, &subjectAltName)) + { + san->insert_last(san, subjectAltName->clone(subjectAltName)); + } + enumerator->destroy(enumerator); + + /* Use public key from PKCS#10 certificate request */ + public = cert_req->get_public_key(cert_req); + } + else + { + if (file) + { + public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, + BUILD_FROM_FILE, file, BUILD_END); + } + else + { + public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY, + BUILD_FROM_FD, 0, BUILD_END); + } + } + if (!public) + { + error = "parsing public key failed"; + goto end; + } + not_before = time(NULL); not_after = not_before + lifetime * 24 * 60 * 60; + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_SIGNING_KEY, private, BUILD_SIGNING_CERT, ca, BUILD_PUBLIC_KEY, public, BUILD_SUBJECT, id, @@ -237,6 +294,7 @@ static int issue(int argc, char *argv[]) end: DESTROY_IF(id); + DESTROY_IF(cert_req); DESTROY_IF(cert); DESTROY_IF(ca); DESTROY_IF(public); -- 2.47.2