x509: Add support for signature schemes with parameters
authorTobias Brunner <tobias@strongswan.org>
Fri, 27 Oct 2017 09:18:35 +0000 (11:18 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 8 Nov 2017 15:48:10 +0000 (16:48 +0100)
Also adds support for specifying the hash algorithm for attribute
certificate signatures.

src/libstrongswan/plugins/x509/x509_ac.c
src/libstrongswan/plugins/x509/x509_cert.c
src/libstrongswan/plugins/x509/x509_crl.c
src/libstrongswan/plugins/x509/x509_ocsp_response.c
src/libstrongswan/plugins/x509/x509_pkcs10.c

index c0a64fc..8e2b4c1 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2017 Tobias Brunner
  * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
  * Copyright (C) 2003 Martin Berner, Lukas Suter
  * Copyright (C) 2002-2017 Andreas Steffen
@@ -116,9 +117,9 @@ struct private_x509_ac_t {
        bool noRevAvail;
 
        /**
-        * Signature algorithm
+        * Signature scheme
         */
-       int algorithm;
+       signature_params_t *scheme;
 
        /**
         * Signature
@@ -425,7 +426,7 @@ static bool parse_certificate(private_x509_ac_t *this)
        int objectID;
        int type     = OID_UNKNOWN;
        int extn_oid = OID_UNKNOWN;
-       int sig_alg  = OID_UNKNOWN;
+       signature_params_t sig_alg;
        bool success = FALSE;
        bool critical;
 
@@ -476,7 +477,11 @@ static bool parse_certificate(private_x509_ac_t *this)
                                }
                                break;
                        case AC_OBJ_SIG_ALG:
-                               sig_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
+                               if (!signature_params_parse(object, level, &sig_alg))
+                               {
+                                       DBG1(DBG_ASN, "  unable to parse signature algorithm");
+                                       goto end;
+                               }
                                break;
                        case AC_OBJ_SERIAL_NUMBER:
                                this->serialNumber = chunk_clone(object);
@@ -550,12 +555,15 @@ static bool parse_certificate(private_x509_ac_t *this)
                                break;
                        }
                        case AC_OBJ_ALGORITHM:
-                               this->algorithm = asn1_parse_algorithmIdentifier(object, level,
-                                                                                                                                NULL);
-                               if (this->algorithm != sig_alg)
+                               INIT(this->scheme);
+                               if (!signature_params_parse(object, level, this->scheme))
+                               {
+                                       DBG1(DBG_ASN, "  unable to parse signature algorithm");
+                                       goto end;
+                               }
+                               if (!signature_params_equal(this->scheme, &sig_alg))
                                {
                                        DBG1(DBG_ASN, "  signature algorithms do not agree");
-                                       success = FALSE;
                                        goto end;
                                }
                                break;
@@ -570,6 +578,7 @@ static bool parse_certificate(private_x509_ac_t *this)
 
 end:
        parser->destroy(parser);
+       signature_params_clear(&sig_alg);
        return success;
 }
 
@@ -742,13 +751,13 @@ static chunk_t build_extensions(private_x509_ac_t *this)
 /**
  * build attributeCertificateInfo
  */
-static chunk_t build_attr_cert_info(private_x509_ac_t *this)
+static chunk_t build_attr_cert_info(private_x509_ac_t *this, chunk_t sig_scheme)
 {
-       return asn1_wrap(ASN1_SEQUENCE, "cmmmmmmm",
+       return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm",
                                ASN1_INTEGER_1,
                                build_holder(this),
                                build_v2_form(this),
-                               asn1_algorithmIdentifier(OID_SHA1_WITH_RSA),
+                               sig_scheme,
                                asn1_simple_object(ASN1_INTEGER, this->serialNumber),
                                build_attr_cert_validity(this),
                                build_attributes(this),
@@ -758,20 +767,39 @@ static chunk_t build_attr_cert_info(private_x509_ac_t *this)
 /**
  * build an X.509 attribute certificate
  */
-static bool build_ac(private_x509_ac_t *this)
+static bool build_ac(private_x509_ac_t *this, hash_algorithm_t digest_alg)
 {
-       chunk_t signatureValue, attributeCertificateInfo;
+       chunk_t signatureValue, attributeCertificateInfo, sig_scheme;
+       private_key_t *key = this->signerKey;
+
+       if (!this->scheme)
+       {
+               INIT(this->scheme,
+                       .scheme = signature_scheme_from_oid(
+                                                               hasher_signature_algorithm_to_oid(digest_alg,
+                                                                                               key->get_type(key))),
+               );
+       }
+       if (this->scheme->scheme == SIGN_UNKNOWN)
+       {
+               return FALSE;
+       }
+       if (!signature_params_build(this->scheme, &sig_scheme))
+       {
+               return FALSE;
+       }
 
-       attributeCertificateInfo = build_attr_cert_info(this);
-       if (!this->signerKey->sign(this->signerKey, SIGN_RSA_EMSA_PKCS1_SHA1, NULL,
-                                                          attributeCertificateInfo, &signatureValue))
+       attributeCertificateInfo = build_attr_cert_info(this, sig_scheme);
+       if (!key->sign(key, this->scheme->scheme, this->scheme->params,
+                                  attributeCertificateInfo, &signatureValue))
        {
                free(attributeCertificateInfo.ptr);
+               free(sig_scheme.ptr);
                return FALSE;
        }
        this->encoding = asn1_wrap(ASN1_SEQUENCE, "mmm",
                                                attributeCertificateInfo,
-                                               asn1_algorithmIdentifier(OID_SHA1_WITH_RSA),
+                                               sig_scheme,
                                                asn1_bitstring("m", signatureValue));
        return TRUE;
 }
@@ -887,10 +915,9 @@ METHOD(certificate_t, has_issuer, id_match_t,
 
 METHOD(certificate_t, issued_by, bool,
        private_x509_ac_t *this, certificate_t *issuer,
-       signature_params_t **schemep)
+       signature_params_t **scheme)
 {
        public_key_t *key;
-       signature_scheme_t scheme;
        bool valid;
        x509_t *x509 = (x509_t*)issuer;
 
@@ -927,21 +954,16 @@ METHOD(certificate_t, issued_by, bool,
                }
        }
 
-       /* determine signature scheme */
-       scheme = signature_scheme_from_oid(this->algorithm);
-
-       if (scheme == SIGN_UNKNOWN || key == NULL)
+       if (!key)
        {
                return FALSE;
        }
-       valid = key->verify(key, scheme, NULL, this->certificateInfo,
-                                               this->signature);
+       valid = key->verify(key, this->scheme->scheme, this->scheme->params,
+                                               this->certificateInfo, this->signature);
        key->destroy(key);
-       if (valid && schemep)
+       if (valid && scheme)
        {
-               INIT(*schemep,
-                       .scheme = scheme,
-               );
+               *scheme = signature_params_clone(this->scheme);
        }
        return valid;
 }
@@ -1024,6 +1046,7 @@ METHOD(certificate_t, destroy, void,
                DESTROY_IF(this->signerCert);
                DESTROY_IF(this->signerKey);
                this->groups->destroy_function(this->groups, (void*)group_destroy);
+               signature_params_destroy(this->scheme);
                free(this->serialNumber.ptr);
                free(this->authKeyIdentifier.ptr);
                free(this->encoding.ptr);
@@ -1130,6 +1153,7 @@ static void add_groups_from_list(private_x509_ac_t *this, linked_list_t *list)
  */
 x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args)
 {
+       hash_algorithm_t digest_alg = HASH_SHA1;
        private_x509_ac_t *ac;
 
        ac = create_empty();
@@ -1161,6 +1185,13 @@ x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args)
                                ac->signerKey = va_arg(args, private_key_t*);
                                ac->signerKey->get_ref(ac->signerKey);
                                continue;
+                       case BUILD_SIGNATURE_SCHEME:
+                               ac->scheme = va_arg(args, signature_params_t*);
+                               ac->scheme = signature_params_clone(ac->scheme);
+                               continue;
+                       case BUILD_DIGEST_ALG:
+                               digest_alg = va_arg(args, int);
+                               continue;
                        case BUILD_END:
                                break;
                        default:
@@ -1174,7 +1205,7 @@ x509_ac_t *x509_ac_gen(certificate_type_t type, va_list args)
                ac->holderCert->get_type(ac->holderCert) == CERT_X509 &&
                ac->signerCert->get_type(ac->signerCert) == CERT_X509)
        {
-               if (build_ac(ac))
+               if (build_ac(ac, digest_alg))
                {
                        return &ac->public;
                }
index 9bb272a..d1f9d9a 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2002 Mario Strasser
  * Copyright (C) 2000-2017 Andreas Steffen
  * Copyright (C) 2006-2009 Martin Willi
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2017 Tobias Brunner
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -197,9 +197,9 @@ struct private_x509_cert_t {
        x509_flag_t flags;
 
        /**
-        * Signature algorithm
+        * Signature scheme
         */
-       int algorithm;
+       signature_params_t *scheme;
 
        /**
         * Signature
@@ -1375,7 +1375,7 @@ static bool parse_certificate(private_x509_cert_t *this)
        chunk_t object;
        int objectID;
        int extn_oid = OID_UNKNOWN;
-       int sig_alg  = OID_UNKNOWN;
+       signature_params_t sig_alg = {};
        bool success = FALSE;
        bool critical = FALSE;
 
@@ -1406,7 +1406,11 @@ static bool parse_certificate(private_x509_cert_t *this)
                                this->serialNumber = object;
                                break;
                        case X509_OBJ_SIG_ALG:
-                               sig_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
+                               if (!signature_params_parse(object, level, &sig_alg))
+                               {
+                                       DBG1(DBG_ASN, "  unable to parse signature algorithm");
+                                       goto end;
+                               }
                                break;
                        case X509_OBJ_ISSUER:
                                this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
@@ -1560,8 +1564,13 @@ static bool parse_certificate(private_x509_cert_t *this)
                                break;
                        }
                        case X509_OBJ_ALGORITHM:
-                               this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
-                               if (this->algorithm != sig_alg)
+                               INIT(this->scheme);
+                               if (!signature_params_parse(object, level, this->scheme))
+                               {
+                                       DBG1(DBG_ASN, "  unable to parse signature algorithm");
+                                       goto end;
+                               }
+                               if (!signature_params_equal(this->scheme, &sig_alg))
                                {
                                        DBG1(DBG_ASN, "  signature algorithms do not agree");
                                        goto end;
@@ -1578,6 +1587,7 @@ static bool parse_certificate(private_x509_cert_t *this)
 
 end:
        parser->destroy(parser);
+       signature_params_clear(&sig_alg);
        if (success)
        {
                hasher_t *hasher;
@@ -1677,26 +1687,21 @@ METHOD(certificate_t, has_issuer, id_match_t,
 
 METHOD(certificate_t, issued_by, bool,
        private_x509_cert_t *this, certificate_t *issuer,
-       signature_params_t **schemep)
+       signature_params_t **scheme)
 {
        public_key_t *key;
-       signature_scheme_t scheme;
        bool valid;
        x509_t *x509 = (x509_t*)issuer;
 
-       /* determine signature scheme */
-       scheme = signature_scheme_from_oid(this->algorithm);
-       if (scheme == SIGN_UNKNOWN)
-       {
-               return FALSE;
-       }
-
        if (&this->public.interface.interface == issuer)
        {
                if (this->flags & X509_SELF_SIGNED)
                {
-                       valid = TRUE;
-                       goto out;
+                       if (scheme)
+                       {
+                               *scheme = signature_params_clone(this->scheme);
+                       }
+                       return TRUE;
                }
        }
        else
@@ -1721,16 +1726,12 @@ METHOD(certificate_t, issued_by, bool,
        {
                return FALSE;
        }
-       valid = key->verify(key, scheme, NULL, this->tbsCertificate,
-                                               this->signature);
+       valid = key->verify(key, this->scheme->scheme, this->scheme->params,
+                                               this->tbsCertificate, this->signature);
        key->destroy(key);
-
-out:
-       if (valid && schemep)
+       if (valid && scheme)
        {
-               INIT(*schemep,
-                       .scheme = scheme,
-               );
+               *scheme = signature_params_clone(this->scheme);
        }
        return valid;
 }
@@ -1930,6 +1931,7 @@ METHOD(certificate_t, destroy, void,
                                                                                          (void*)cert_policy_destroy);
                this->policy_mappings->destroy_function(this->policy_mappings,
                                                                                          (void*)policy_mapping_destroy);
+               signature_params_destroy(this->scheme);
                DESTROY_IF(this->issuer);
                DESTROY_IF(this->subject);
                DESTROY_IF(this->public_key);
@@ -2185,10 +2187,9 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
        chunk_t crlDistributionPoints = chunk_empty, authorityInfoAccess = chunk_empty;
        chunk_t policyConstraints = chunk_empty, inhibitAnyPolicy = chunk_empty;
        chunk_t ikeIntermediate = chunk_empty, msSmartcardLogon = chunk_empty;
-       chunk_t ipAddrBlocks = chunk_empty;
+       chunk_t ipAddrBlocks = chunk_empty, sig_scheme = chunk_empty;
        identification_t *issuer, *subject;
        chunk_t key_info;
-       signature_scheme_t scheme;
        hasher_t *hasher;
        enumerator_t *enumerator;
        char *uri;
@@ -2221,18 +2222,28 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
                cert->notAfter = cert->notBefore + 60 * 60 * 24 * 365;
        }
 
-       /* select signature scheme */
-       cert->algorithm = hasher_signature_algorithm_to_oid(digest_alg,
-                                                               sign_key->get_type(sign_key));
-       if (cert->algorithm == OID_UNKNOWN)
+       /* select signature scheme, if not already specified */
+       if (!cert->scheme)
+       {
+               INIT(cert->scheme,
+                       .scheme = signature_scheme_from_oid(
+                                                               hasher_signature_algorithm_to_oid(digest_alg,
+                                                                                               sign_key->get_type(sign_key))),
+               );
+       }
+       if (cert->scheme->scheme == SIGN_UNKNOWN)
+       {
+               return FALSE;
+       }
+       if (!signature_params_build(cert->scheme, &sig_scheme))
        {
                return FALSE;
        }
-       scheme = signature_scheme_from_oid(cert->algorithm);
 
        if (!cert->public_key->get_encoding(cert->public_key,
                                                                                PUBKEY_SPKI_ASN1_DER, &key_info))
        {
+               chunk_free(&sig_scheme);
                return FALSE;
        }
 
@@ -2557,10 +2568,10 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
                                                        ipAddrBlocks));
        }
 
-       cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmmcmcmm",
+       cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmccmcmm",
                asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2),
                asn1_integer("c", cert->serialNumber),
-               asn1_algorithmIdentifier(cert->algorithm),
+               sig_scheme,
                issuer->get_encoding(issuer),
                asn1_wrap(ASN1_SEQUENCE, "mm",
                        asn1_from_time(&cert->notBefore, ASN1_UTCTIME),
@@ -2568,13 +2579,14 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
                subject->get_encoding(subject),
                key_info, extensions);
 
-       if (!sign_key->sign(sign_key, scheme, NULL, cert->tbsCertificate,
-                                               &cert->signature))
+       if (!sign_key->sign(sign_key, cert->scheme->scheme, cert->scheme->params,
+                                               cert->tbsCertificate, &cert->signature))
        {
+               chunk_free(&sig_scheme);
                return FALSE;
        }
        cert->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm", cert->tbsCertificate,
-                                                          asn1_algorithmIdentifier(cert->algorithm),
+                                                          sig_scheme,
                                                           asn1_bitstring("c", cert->signature));
 
        hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
@@ -2638,7 +2650,7 @@ x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args)
        private_x509_cert_t *cert;
        certificate_t *sign_cert = NULL;
        private_key_t *sign_key = NULL;
-       hash_algorithm_t digest_alg = HASH_SHA1;
+       hash_algorithm_t digest_alg = HASH_SHA256;
        u_int constraint;
 
        cert = create_empty();
@@ -2830,6 +2842,10 @@ x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args)
                        case BUILD_SERIAL:
                                cert->serialNumber = chunk_clone(va_arg(args, chunk_t));
                                continue;
+                       case BUILD_SIGNATURE_SCHEME:
+                               cert->scheme = va_arg(args, signature_params_t*);
+                               cert->scheme = signature_params_clone(cert->scheme);
+                               continue;
                        case BUILD_DIGEST_ALG:
                                digest_alg = va_arg(args, int);
                                continue;
index 2712ad8..699ac5a 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2014-2017 Tobias Brunner
  * Copyright (C) 2008-2009 Martin Willi
  * Copyright (C) 2017 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
@@ -121,9 +122,9 @@ struct private_x509_crl_t {
        chunk_t baseCrlNumber;
 
        /**
-        * Signature algorithm
+        * Signature scheme
         */
-       int algorithm;
+       signature_params_t *scheme;
 
        /**
         * Signature
@@ -225,7 +226,7 @@ static bool parse(private_x509_crl_t *this)
        chunk_t extnID = chunk_empty;
        chunk_t userCertificate = chunk_empty;
        int objectID;
-       int sig_alg = OID_UNKNOWN;
+       signature_params_t sig_alg = {};
        bool success = FALSE;
        bool critical = FALSE;
        revoked_t *revoked = NULL;
@@ -246,7 +247,11 @@ static bool parse(private_x509_crl_t *this)
                                DBG2(DBG_ASN, "  v%d", this->version);
                                break;
                        case CRL_OBJ_SIG_ALG:
-                               sig_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
+                               if (!signature_params_parse(object, level, &sig_alg))
+                               {
+                                       DBG1(DBG_ASN, "  unable to parse signature algorithm");
+                                       goto end;
+                               }
                                break;
                        case CRL_OBJ_ISSUER:
                                this->issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object);
@@ -342,8 +347,13 @@ static bool parse(private_x509_crl_t *this)
                        }
                        case CRL_OBJ_ALGORITHM:
                        {
-                               this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
-                               if (this->algorithm != sig_alg)
+                               INIT(this->scheme);
+                               if (!signature_params_parse(object, level, this->scheme))
+                               {
+                                       DBG1(DBG_ASN, "  unable to parse signature algorithm");
+                                       goto end;
+                               }
+                               if (!signature_params_equal(this->scheme, &sig_alg))
                                {
                                        DBG1(DBG_ASN, "  signature algorithms do not agree");
                                        goto end;
@@ -361,6 +371,7 @@ static bool parse(private_x509_crl_t *this)
 
 end:
        parser->destroy(parser);
+       signature_params_clear(&sig_alg);
        return success;
 }
 
@@ -458,10 +469,9 @@ METHOD(certificate_t, has_issuer, id_match_t,
 
 METHOD(certificate_t, issued_by, bool,
        private_x509_crl_t *this, certificate_t *issuer,
-       signature_params_t **schemep)
+       signature_params_t **scheme)
 {
        public_key_t *key;
-       signature_scheme_t scheme;
        bool valid;
        x509_t *x509 = (x509_t*)issuer;
        chunk_t keyid = chunk_empty;
@@ -493,23 +503,17 @@ METHOD(certificate_t, issued_by, bool,
                }
        }
 
-       scheme = signature_scheme_from_oid(this->algorithm);
-       if (scheme == SIGN_UNKNOWN)
-       {
-               return FALSE;
-       }
        key = issuer->get_public_key(issuer);
        if (!key)
        {
                return FALSE;
        }
-       valid = key->verify(key, scheme, NULL, this->tbsCertList, this->signature);
+       valid = key->verify(key, this->scheme->scheme, this->scheme->params,
+                                               this->tbsCertList, this->signature);
        key->destroy(key);
-       if (valid && schemep)
+       if (valid && scheme)
        {
-               INIT(*schemep,
-                       .scheme = scheme,
-               );
+               *scheme = signature_params_clone(this->scheme);
        }
        return valid;
 }
@@ -596,6 +600,7 @@ METHOD(certificate_t, destroy, void,
                this->revoked->destroy_function(this->revoked, (void*)revoked_destroy);
                this->crl_uris->destroy_function(this->crl_uris,
                                                                                 (void*)x509_cdp_destroy);
+               signature_params_destroy(this->scheme);
                DESTROY_IF(this->issuer);
                free(this->authKeyIdentifier.ptr);
                free(this->encoding.ptr);
@@ -712,6 +717,7 @@ static bool generate(private_x509_crl_t *this, certificate_t *cert,
 {
        chunk_t extensions = chunk_empty, certList = chunk_empty, serial;
        chunk_t crlDistributionPoints = chunk_empty, baseCrlNumber = chunk_empty;
+       chunk_t sig_scheme = chunk_empty;
        enumerator_t *enumerator;
        crl_reason_t reason;
        time_t date;
@@ -724,10 +730,20 @@ static bool generate(private_x509_crl_t *this, certificate_t *cert,
 
        this->authKeyIdentifier = chunk_clone(x509->get_subjectKeyIdentifier(x509));
 
-       /* select signature scheme */
-       this->algorithm = hasher_signature_algorithm_to_oid(digest_alg,
-                                                                                                               key->get_type(key));
-       if (this->algorithm == OID_UNKNOWN)
+       /* select signature scheme, if not already specified */
+       if (!this->scheme)
+       {
+               INIT(this->scheme,
+                       .scheme = signature_scheme_from_oid(
+                                                               hasher_signature_algorithm_to_oid(digest_alg,
+                                                                                               key->get_type(key))),
+               );
+       }
+       if (this->scheme->scheme == SIGN_UNKNOWN)
+       {
+               return FALSE;
+       }
+       if (!signature_params_build(this->scheme, &sig_scheme))
        {
                return FALSE;
        }
@@ -781,23 +797,24 @@ static bool generate(private_x509_crl_t *this, certificate_t *cert,
                                                                asn1_integer("c", this->crlNumber))),
                                                crlDistributionPoints, baseCrlNumber));
 
-       this->tbsCertList = asn1_wrap(ASN1_SEQUENCE, "cmcmmmm",
+       this->tbsCertList = asn1_wrap(ASN1_SEQUENCE, "cccmmmm",
                                                        ASN1_INTEGER_1,
-                                                       asn1_algorithmIdentifier(this->algorithm),
+                                                       sig_scheme,
                                                        this->issuer->get_encoding(this->issuer),
                                                        asn1_from_time(&this->thisUpdate, ASN1_UTCTIME),
                                                        asn1_from_time(&this->nextUpdate, ASN1_UTCTIME),
                                                        asn1_wrap(ASN1_SEQUENCE, "m", certList),
                                                        extensions);
 
-       if (!key->sign(key, signature_scheme_from_oid(this->algorithm), NULL,
+       if (!key->sign(key, this->scheme->scheme, this->scheme->params,
                                   this->tbsCertList, &this->signature))
        {
+               chunk_free(&sig_scheme);
                return FALSE;
        }
        this->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm",
                                                        this->tbsCertList,
-                                                       asn1_algorithmIdentifier(this->algorithm),
+                                                       sig_scheme,
                                                        asn1_bitstring("c", this->signature));
        return TRUE;
 }
@@ -836,6 +853,10 @@ x509_crl_t *x509_crl_gen(certificate_type_t type, va_list args)
                                crl->crlNumber = va_arg(args, chunk_t);
                                crl->crlNumber = chunk_clone(crl->crlNumber);
                                continue;
+                       case BUILD_SIGNATURE_SCHEME:
+                               crl->scheme = va_arg(args, signature_params_t*);
+                               crl->scheme = signature_params_clone(crl->scheme);
+                               continue;
                        case BUILD_DIGEST_ALG:
                                digest_alg = va_arg(args, int);
                                continue;
index e803c18..aa4999c 100644 (file)
@@ -1,4 +1,5 @@
-/**
+/*
+ * Copyright (C) 2017 Tobias Brunner
  * Copyright (C) 2008-2009 Martin Willi
  * Copyright (C) 2007-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
@@ -63,9 +64,9 @@ struct private_x509_ocsp_response_t {
        chunk_t tbsResponseData;
 
        /**
-        * signature algorithm (OID)
+        * signature scheme
         */
-       int signatureAlgorithm;
+       signature_params_t *scheme;
 
        /**
         * signature
@@ -576,8 +577,13 @@ static bool parse_basicOCSPResponse(private_x509_ocsp_response_t *this,
                                }
                                break;
                        case BASIC_RESPONSE_ALGORITHM:
-                               this->signatureAlgorithm = asn1_parse_algorithmIdentifier(object,
-                                                                                               parser->get_level(parser)+1, NULL);
+                               INIT(this->scheme);
+                               if (!signature_params_parse(object, parser->get_level(parser)+1,
+                                                                                       this->scheme))
+                               {
+                                       DBG1(DBG_ASN, "  unable to parse signature algorithm");
+                                       goto end;
+                               }
                                break;
                        case BASIC_RESPONSE_SIGNATURE:
                                this->signature = chunk_skip(object, 1);
@@ -703,10 +709,9 @@ METHOD(certificate_t, has_issuer, id_match_t,
 
 METHOD(certificate_t, issued_by, bool,
        private_x509_ocsp_response_t *this, certificate_t *issuer,
-       signature_params_t **schemep)
+       signature_params_t **scheme)
 {
        public_key_t *key;
-       signature_scheme_t scheme;
        bool valid;
        x509_t *x509 = (x509_t*)issuer;
 
@@ -743,24 +748,17 @@ METHOD(certificate_t, issued_by, bool,
                return FALSE;
        }
 
-       /* get the public key of the issuer */
        key = issuer->get_public_key(issuer);
-
-       /* determine signature scheme */
-       scheme = signature_scheme_from_oid(this->signatureAlgorithm);
-
-       if (scheme == SIGN_UNKNOWN || key == NULL)
+       if (!key)
        {
                return FALSE;
        }
-       valid = key->verify(key, scheme, NULL, this->tbsResponseData,
-                                               this->signature);
+       valid = key->verify(key, this->scheme->scheme, this->scheme->params,
+                                               this->tbsResponseData, this->signature);
        key->destroy(key);
-       if (valid && schemep)
+       if (valid && scheme)
        {
-               INIT(*schemep,
-                       .scheme = scheme,
-               );
+               *scheme = signature_params_clone(this->scheme);
        }
        return valid;
 }
@@ -842,6 +840,7 @@ METHOD(certificate_t, destroy, void,
        {
                this->certs->destroy_offset(this->certs, offsetof(certificate_t, destroy));
                this->responses->destroy_function(this->responses, free);
+               signature_params_destroy(this->scheme);
                DESTROY_IF(this->responderId);
                free(this->encoding.ptr);
                free(this);
@@ -882,7 +881,6 @@ static x509_ocsp_response_t *load(chunk_t blob)
                .producedAt = UNDEFINED_TIME,
                .usableUntil = UNDEFINED_TIME,
                .responses = linked_list_create(),
-               .signatureAlgorithm = OID_UNKNOWN,
                .certs = linked_list_create(),
        );
 
index 019ccf7..587fbd5 100644 (file)
@@ -72,9 +72,9 @@ struct private_x509_pkcs10_t {
        chunk_t challengePassword;
 
        /**
-        * Signature algorithm
+        * Signature scheme
         */
-       int algorithm;
+       signature_params_t *scheme;
 
        /**
         * Signature
@@ -124,22 +124,15 @@ METHOD(certificate_t, has_subject, id_match_t,
 
 METHOD(certificate_t, issued_by, bool,
        private_x509_pkcs10_t *this, certificate_t *issuer,
-       signature_params_t **schemep)
+       signature_params_t **scheme)
 {
        public_key_t *key;
-       signature_scheme_t scheme;
        bool valid;
 
        if (&this->public.interface.interface != issuer)
        {
                return FALSE;
        }
-       /* determine signature scheme */
-       scheme = signature_scheme_from_oid(this->algorithm);
-       if (scheme == SIGN_UNKNOWN)
-       {
-               return FALSE;
-       }
        if (this->self_signed)
        {
                valid = TRUE;
@@ -152,14 +145,12 @@ METHOD(certificate_t, issued_by, bool,
                {
                        return FALSE;
                }
-               valid = key->verify(key, scheme, NULL, this->certificationRequestInfo,
-                                                       this->signature);
+               valid = key->verify(key, this->scheme->scheme, this->scheme->params,
+                                                       this->certificationRequestInfo, this->signature);
        }
-       if (valid && schemep)
+       if (valid && scheme)
        {
-               INIT(*schemep,
-                       .scheme = scheme,
-               );
+               *scheme = signature_params_clone(this->scheme);
        }
        return valid;
 }
@@ -413,7 +404,7 @@ static bool parse_certificate_request(private_x509_pkcs10_t *this)
                        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)
+                               if (!this->public_key)
                                {
                                        goto end;
                                }
@@ -441,7 +432,12 @@ static bool parse_certificate_request(private_x509_pkcs10_t *this)
                                }
                                break;
                        case PKCS10_ALGORITHM:
-                               this->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
+                               INIT(this->scheme);
+                               if (!signature_params_parse(object, level, this->scheme))
+                               {
+                                       DBG1(DBG_ASN, "  unable to parse signature algorithm");
+                                       goto end;
+                               }
                                break;
                        case PKCS10_SIGNATURE:
                                this->signature = chunk_skip(object, 1);
@@ -477,6 +473,7 @@ METHOD(certificate_t, destroy, void,
        {
                this->subjectAltNames->destroy_offset(this->subjectAltNames,
                                                                        offsetof(identification_t, destroy));
+               signature_params_destroy(this->scheme);
                DESTROY_IF(this->subject);
                DESTROY_IF(this->public_key);
                chunk_free(&this->encoding);
@@ -533,25 +530,34 @@ static bool generate(private_x509_pkcs10_t *cert, private_key_t *sign_key,
 {
        chunk_t key_info, subjectAltNames, attributes;
        chunk_t extensionRequest  = chunk_empty;
-       chunk_t challengePassword = chunk_empty;
-       signature_scheme_t scheme;
+       chunk_t challengePassword = chunk_empty, sig_scheme = chunk_empty;
        identification_t *subject;
 
        subject = cert->subject;
        cert->public_key = sign_key->get_public_key(sign_key);
 
-       /* select signature scheme */
-       cert->algorithm = hasher_signature_algorithm_to_oid(digest_alg,
-                                                                       sign_key->get_type(sign_key));
-       if (cert->algorithm == OID_UNKNOWN)
+       /* select signature scheme, if not already specified */
+       if (!cert->scheme)
+       {
+               INIT(cert->scheme,
+                       .scheme = signature_scheme_from_oid(
+                                                               hasher_signature_algorithm_to_oid(digest_alg,
+                                                                                               sign_key->get_type(sign_key))),
+               );
+       }
+       if (cert->scheme->scheme == SIGN_UNKNOWN)
+       {
+               return FALSE;
+       }
+       if (!signature_params_build(cert->scheme, &sig_scheme))
        {
                return FALSE;
        }
-       scheme = signature_scheme_from_oid(cert->algorithm);
 
        if (!cert->public_key->get_encoding(cert->public_key,
                                                                                PUBKEY_SPKI_ASN1_DER, &key_info))
        {
+               chunk_free(&sig_scheme);
                return FALSE;
        }
 
@@ -587,15 +593,16 @@ static bool generate(private_x509_pkcs10_t *cert, private_key_t *sign_key,
                                                        key_info,
                                                        attributes);
 
-       if (!sign_key->sign(sign_key, scheme, NULL, cert->certificationRequestInfo,
-                                               &cert->signature))
+       if (!sign_key->sign(sign_key, cert->scheme->scheme, cert->scheme->params,
+                                               cert->certificationRequestInfo, &cert->signature))
        {
+               chunk_free(&sig_scheme);
                return FALSE;
        }
 
        cert->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm",
                                                           cert->certificationRequestInfo,
-                                                          asn1_algorithmIdentifier(cert->algorithm),
+                                                          sig_scheme,
                                                           asn1_bitstring("c", cert->signature));
        return TRUE;
 }
@@ -677,6 +684,10 @@ x509_pkcs10_t *x509_pkcs10_gen(certificate_type_t type, va_list args)
                        case BUILD_CHALLENGE_PWD:
                                cert->challengePassword = chunk_clone(va_arg(args, chunk_t));
                                continue;
+                       case BUILD_SIGNATURE_SCHEME:
+                               cert->scheme = va_arg(args, signature_params_t*);
+                               cert->scheme = signature_params_clone(cert->scheme);
+                               continue;
                        case BUILD_DIGEST_ALG:
                                digest_alg = va_arg(args, int);
                                continue;