pki: Allow inclusion of [unsupported] critical X.509 extension
authorAndreas Steffen <andreas.steffen@strongswan.org>
Mon, 6 May 2019 12:33:49 +0000 (14:33 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 8 May 2019 12:56:48 +0000 (14:56 +0200)
src/libstrongswan/credentials/builder.c
src/libstrongswan/credentials/builder.h
src/libstrongswan/plugins/x509/x509_cert.c
src/libstrongswan/plugins/x509/x509_crl.c
src/pki/commands/issue.c
src/pki/commands/self.c
src/pki/commands/signcrl.c
src/pki/man/pki---issue.1.in
src/pki/man/pki---self.1.in
src/pki/man/pki---signcrl.1.in

index 61dfbbc..a663636 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 Martin Willi
- * Copyright (C) 2016 Andreas Steffen
+ * Copyright (C) 2016-2019 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -75,5 +75,6 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
        "BUILD_THRESHOLD",
        "BUILD_EDDSA_PUB",
        "BUILD_EDDSA_PRIV_ASN1_DER",
+       "BUILD_CRITICAL_EXTENSION",
        "BUILD_END",
 );
index b283bd1..b623646 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 Martin Willi
- * Copyright (C) 2016 Andreas Steffen
+ * Copyright (C) 2016-2019 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -160,6 +160,8 @@ enum builder_part_t {
        BUILD_EDDSA_PUB,
        /** DER encoded ASN.1 EdDSA private key */
        BUILD_EDDSA_PRIV_ASN1_DER,
+       /** OID of an [unsupported] critical extension */
+       BUILD_CRITICAL_EXTENSION,
        /** end of variable argument builder list */
        BUILD_END,
 };
index f3d4377..7311708 100644 (file)
@@ -172,6 +172,11 @@ struct private_x509_cert_t {
        chunk_t authKeySerialNumber;
 
        /**
+        * Optional OID of an [unsupported] critical extension
+        */
+       chunk_t critical_extension_oid;
+
+       /**
         * Path Length Constraint
         */
        u_char pathLenConstraint;
@@ -1951,6 +1956,7 @@ METHOD(certificate_t, destroy, void,
                chunk_free(&this->authKeyIdentifier);
                chunk_free(&this->encoding);
                chunk_free(&this->encoding_hash);
+               chunk_free(&this->critical_extension_oid);
                if (!this->parsed)
                {       /* only parsed certificates point these fields to "encoded" */
                        chunk_free(&this->signature);
@@ -2203,6 +2209,7 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
        chunk_t policyConstraints = chunk_empty, inhibitAnyPolicy = chunk_empty;
        chunk_t ikeIntermediate = chunk_empty, msSmartcardLogon = chunk_empty;
        chunk_t ipAddrBlocks = chunk_empty, sig_scheme = chunk_empty;
+       chunk_t criticalExtension = chunk_empty;
        identification_t *issuer, *subject;
        chunk_t key_info;
        hasher_t *hasher;
@@ -2570,17 +2577,25 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
                                                chunk_from_thing(cert->inhibit_any))));
        }
 
+       if (cert->critical_extension_oid.len > 0)
+       {
+               criticalExtension = asn1_wrap(ASN1_SEQUENCE, "mmm",
+                                       asn1_simple_object(ASN1_OID, cert->critical_extension_oid),
+                                       asn1_simple_object(ASN1_BOOLEAN, chunk_from_chars(0xFF)),
+                                       asn1_simple_object(ASN1_OCTET_STRING, chunk_empty));
+       }
+
        if (basicConstraints.ptr || subjectAltNames.ptr || authKeyIdentifier.ptr ||
                crlDistributionPoints.ptr || nameConstraints.ptr || ipAddrBlocks.ptr)
        {
                extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m",
-                                               asn1_wrap(ASN1_SEQUENCE, "mmmmmmmmmmmmmm",
+                                               asn1_wrap(ASN1_SEQUENCE, "mmmmmmmmmmmmmmm",
                                                        basicConstraints, keyUsage, subjectKeyIdentifier,
                                                        authKeyIdentifier, subjectAltNames,
                                                        extendedKeyUsage, crlDistributionPoints,
                                                        authorityInfoAccess, nameConstraints, certPolicies,
                                                        policyMappings, policyConstraints, inhibitAnyPolicy,
-                                                       ipAddrBlocks));
+                                                       ipAddrBlocks, criticalExtension));
        }
 
        cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmccmcmm",
@@ -2864,6 +2879,9 @@ x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args)
                        case BUILD_DIGEST_ALG:
                                digest_alg = va_arg(args, int);
                                continue;
+                       case BUILD_CRITICAL_EXTENSION:
+                               cert->critical_extension_oid = chunk_clone(va_arg(args, chunk_t));
+                               continue;
                        case BUILD_END:
                                break;
                        default:
index 95cb11c..a315c62 100644 (file)
@@ -117,6 +117,11 @@ struct private_x509_crl_t {
        chunk_t authKeySerialNumber;
 
        /**
+        * Optional OID of an [unsupported] critical extension
+        */
+       chunk_t critical_extension_oid;
+
+       /**
         * Number of BaseCRL, if a delta CRL
         */
        chunk_t baseCrlNumber;
@@ -605,6 +610,7 @@ METHOD(certificate_t, destroy, void,
                DESTROY_IF(this->issuer);
                free(this->authKeyIdentifier.ptr);
                free(this->encoding.ptr);
+               free(this->critical_extension_oid.ptr);
                if (this->generated)
                {
                        free(this->crlNumber.ptr);
@@ -718,7 +724,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;
+       chunk_t sig_scheme = chunk_empty, criticalExtension = chunk_empty;
        enumerator_t *enumerator;
        crl_reason_t reason;
        time_t date;
@@ -784,8 +790,16 @@ static bool generate(private_x509_crl_t *this, certificate_t *cert,
                                                                asn1_integer("c", this->baseCrlNumber)));
        }
 
+       if (this->critical_extension_oid.len > 0)
+       {
+               criticalExtension = asn1_wrap(ASN1_SEQUENCE, "mmm",
+                                       asn1_simple_object(ASN1_OID, this->critical_extension_oid),
+                                       asn1_simple_object(ASN1_BOOLEAN, chunk_from_chars(0xFF)),
+                                       asn1_simple_object(ASN1_OCTET_STRING, chunk_empty));
+       }
+
        extensions = asn1_wrap(ASN1_CONTEXT_C_0, "m",
-                                       asn1_wrap(ASN1_SEQUENCE, "mmmm",
+                                       asn1_wrap(ASN1_SEQUENCE, "mmmmm",
                                                asn1_wrap(ASN1_SEQUENCE, "mm",
                                                        asn1_build_known_oid(OID_AUTHORITY_KEY_ID),
                                                        asn1_wrap(ASN1_OCTET_STRING, "m",
@@ -796,7 +810,8 @@ static bool generate(private_x509_crl_t *this, certificate_t *cert,
                                                        asn1_build_known_oid(OID_CRL_NUMBER),
                                                        asn1_wrap(ASN1_OCTET_STRING, "m",
                                                                asn1_integer("c", this->crlNumber))),
-                                               crlDistributionPoints, baseCrlNumber));
+                                               crlDistributionPoints, baseCrlNumber,
+                                               criticalExtension));
 
        this->tbsCertList = asn1_wrap(ASN1_SEQUENCE, "cccmmmm",
                                                        ASN1_INTEGER_1,
@@ -887,6 +902,9 @@ x509_crl_t *x509_crl_gen(certificate_type_t type, va_list args)
                                enumerator->destroy(enumerator);
                                continue;
                        }
+                       case BUILD_CRITICAL_EXTENSION:
+                               crl->critical_extension_oid = chunk_clone(va_arg(args, chunk_t));
+                               continue;
                        case BUILD_END:
                                break;
                        default:
index b117fa1..4f11e7a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2009 Martin Willi
- * Copyright (C) 2015-2017 Andreas Steffen
+ * Copyright (C) 2015-2019 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -77,6 +77,7 @@ static int issue()
        int inhibit_mapping = X509_NO_CONSTRAINT, require_explicit = X509_NO_CONSTRAINT;
        chunk_t serial = chunk_empty;
        chunk_t encoding = chunk_empty;
+       chunk_t critical_extension_oid = chunk_empty;
        time_t not_before, not_after, lifetime = 1095 * 24 * 60 * 60;
        char *datenb = NULL, *datena = NULL, *dateform = NULL;
        x509_flag_t flags = 0;
@@ -333,6 +334,10 @@ static int issue()
                        case 'o':
                                ocsp->insert_last(ocsp, arg);
                                continue;
+                       case 'X':
+                               chunk_free(&critical_extension_oid);
+                               critical_extension_oid = asn1_oid_from_string(arg);
+                               continue;
                        case EOF:
                                break;
                        default:
@@ -558,6 +563,7 @@ static int issue()
                                        BUILD_POLICY_REQUIRE_EXPLICIT, require_explicit,
                                        BUILD_POLICY_INHIBIT_MAPPING, inhibit_mapping,
                                        BUILD_POLICY_INHIBIT_ANY, inhibit_any,
+                                       BUILD_CRITICAL_EXTENSION, critical_extension_oid,
                                        BUILD_SIGNATURE_SCHEME, scheme,
                                        BUILD_END);
        if (!cert)
@@ -593,6 +599,7 @@ end:
        cdps->destroy_function(cdps, (void*)destroy_cdp);
        ocsp->destroy(ocsp);
        signature_params_destroy(scheme);
+       free(critical_extension_oid.ptr);
        free(encoding.ptr);
        free(serial.ptr);
 
@@ -612,6 +619,7 @@ usage:
        mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
        cdps->destroy_function(cdps, (void*)destroy_cdp);
        ocsp->destroy(ocsp);
+       free(critical_extension_oid.ptr);
        return command_usage(error);
 }
 
@@ -632,7 +640,7 @@ static void __attribute__ ((constructor))reg()
                 "[--policy-explicit len] [--policy-inhibit len] [--policy-any len]",
                 "[--cert-policy oid [--cps-uri uri] [--user-notice text]]+",
                 "[--digest md5|sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512]",
-                "[--rsa-padding pkcs1|pss]",
+                "[--rsa-padding pkcs1|pss] [--critical oid]",
                 "[--outform der|pem]"},
                {
                        {"help",                        'h', 0, "show usage information"},
@@ -666,6 +674,7 @@ static void __attribute__ ((constructor))reg()
                        {"ocsp",                        'o', 1, "OCSP AuthorityInfoAccess URI to include"},
                        {"digest",                      'g', 1, "digest for signature creation, default: key-specific"},
                        {"rsa-padding",         'R', 1, "padding for RSA signatures, default: pkcs1"},
+                       {"critical",            'X', 1, "critical extension OID to include"},
                        {"outform",                     'f', 1, "encoding of generated cert, default: der"},
                }
        });
index a08ee99..31018e8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2009 Martin Willi
- * Copyright (C) 2015-2017 Andreas Steffen
+ * Copyright (C) 2015-2019 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -65,6 +65,7 @@ static int self()
        int require_explicit = X509_NO_CONSTRAINT;
        chunk_t serial = chunk_empty;
        chunk_t encoding = chunk_empty;
+       chunk_t critical_extension_oid = chunk_empty;
        time_t not_before, not_after, lifetime = 1095 * 24 * 60 * 60;
        char *datenb = NULL, *datena = NULL, *dateform = NULL;
        x509_flag_t flags = 0;
@@ -289,6 +290,10 @@ static int self()
                        case 'o':
                                ocsp->insert_last(ocsp, arg);
                                continue;
+                       case 'X':
+                               chunk_free(&critical_extension_oid);
+                               critical_extension_oid = asn1_oid_from_string(arg);
+                               continue;
                        case EOF:
                                break;
                        default:
@@ -399,6 +404,7 @@ static int self()
                                                BUILD_POLICY_REQUIRE_EXPLICIT, require_explicit,
                                                BUILD_POLICY_INHIBIT_MAPPING, inhibit_mapping,
                                                BUILD_POLICY_INHIBIT_ANY, inhibit_any,
+                                               BUILD_CRITICAL_EXTENSION, critical_extension_oid,
                                                BUILD_END);
        if (!cert)
        {
@@ -430,6 +436,7 @@ end:
        mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
        ocsp->destroy(ocsp);
        signature_params_destroy(scheme);
+       free(critical_extension_oid.ptr);
        free(encoding.ptr);
        free(serial.ptr);
 
@@ -448,6 +455,7 @@ usage:
        policies->destroy_function(policies, (void*)destroy_cert_policy);
        mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
        ocsp->destroy(ocsp);
+       free(critical_extension_oid.ptr);
        return command_usage(error);
 }
 
@@ -468,7 +476,7 @@ static void __attribute__ ((constructor))reg()
                 "[--policy-explicit len] [--policy-inhibit len] [--policy-any len]",
                 "[--cert-policy oid [--cps-uri uri] [--user-notice text]]+",
                 "[--digest md5|sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512]",
-                "[--rsa-padding pkcs1|pss]",
+                "[--rsa-padding pkcs1|pss] [--critical oid]",
                 "[--outform der|pem]"},
                {
                        {"help",                        'h', 0, "show usage information"},
@@ -498,6 +506,7 @@ static void __attribute__ ((constructor))reg()
                        {"ocsp",                        'o', 1, "OCSP AuthorityInfoAccess URI to include"},
                        {"digest",                      'g', 1, "digest for signature creation, default: key-specific"},
                        {"rsa-padding",         'R', 1, "padding for RSA signatures, default: pkcs1"},
+                       {"critical",            'X', 1, "critical extension OID to include for test purposes"},
                        {"outform",                     'f', 1, "encoding of generated cert, default: der"},
                }
        });
index 8c234fe..dfe1ce0 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 2010 Martin Willi
  * Copyright (C) 2010 revosec AG
  *
- * Copyright (C) 2017 Andreas Steffen
+ * Copyright (C) 2017-2019 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
 #include <credentials/certificates/certificate.h>
 #include <credentials/certificates/x509.h>
 #include <credentials/certificates/crl.h>
+#include <asn1/asn1.h>
 
 
 /**
@@ -133,6 +134,7 @@ static int sign_crl()
        enumerator_t *enumerator, *lastenum = NULL;
        x509_cdp_t *cdp;
        chunk_t crl_serial = chunk_empty, baseCrlNumber = chunk_empty;
+       chunk_t critical_extension_oid = chunk_empty;
        chunk_t encoding = chunk_empty;
        bool pss = lib->settings->get_bool(lib->settings, "%s.rsa_pss", FALSE,
                                                                           lib->ns);
@@ -279,6 +281,10 @@ static int sign_crl()
                                        goto usage;
                                }
                                continue;
+                       case 'X':
+                               chunk_free(&critical_extension_oid);
+                               critical_extension_oid = asn1_oid_from_string(arg);
+                               continue;
                        case EOF:
                                break;
                        default:
@@ -414,6 +420,7 @@ static int sign_crl()
                        BUILD_REVOKED_ENUMERATOR, enumerator,
                        BUILD_REVOKED_ENUMERATOR, lastenum, BUILD_SIGNATURE_SCHEME, scheme,
                        BUILD_CRL_DISTRIBUTION_POINTS, cdps, BUILD_BASE_CRL, baseCrlNumber,
+                       BUILD_CRITICAL_EXTENSION, critical_extension_oid,
                        BUILD_END);
        enumerator->destroy(enumerator);
 
@@ -442,6 +449,7 @@ error:
        DESTROY_IF(lastenum);
        DESTROY_IF((certificate_t*)lastcrl);
        signature_params_destroy(scheme);
+       free(critical_extension_oid.ptr);
        free(encoding.ptr);
        free(baseCrlNumber.ptr);
        free(crl_serial.ptr);
@@ -457,6 +465,7 @@ error:
 usage:
        list->destroy_function(list, (void*)revoked_destroy);
        cdps->destroy_function(cdps, (void*)x509_cdp_destroy);
+       free(critical_extension_oid.ptr);
        return command_usage(error);
 }
 
@@ -474,7 +483,7 @@ static void __attribute__ ((constructor))reg()
                 "           superseded|cessation-of-operation|certificate-hold]",
                 " [--date timestamp] --cert file|--serial hex]*",
                 "[--digest md5|sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512]",
-                "[--rsa-padding pkcs1|pss]",
+                "[--rsa-padding pkcs1|pss] [--critical oid]",
                 "[--outform der|pem]"},
                {
                        {"help",                'h', 0, "show usage information"},
@@ -494,6 +503,7 @@ static void __attribute__ ((constructor))reg()
                        {"date",                'd', 1, "revocation date as unix timestamp, default: now"},
                        {"digest",              'g', 1, "digest for signature creation, default: key-specific"},
                        {"rsa-padding", 'R', 1, "padding for RSA signatures, default: pkcs1"},
+                       {"critical",    'X', 1, "critical extension OID to include for test purposes"},
                        {"outform",             'f', 1, "encoding of generated crl, default: der"},
                }
        });
index 8aec653..99dcaca 100644 (file)
@@ -1,4 +1,4 @@
-.TH "PKI \-\-ISSUE" 1 "2016-12-13" "@PACKAGE_VERSION@" "strongSwan"
+.TH "PKI \-\-ISSUE" 1 "2019-05-06" "@PACKAGE_VERSION@" "strongSwan"
 .
 .SH "NAME"
 .
@@ -24,9 +24,10 @@ pki \-\-issue \- Issue a certificate using a CA certificate and key
 .OP \-\-crl uri\ \fR[\fB\-\-crlissuer\ \fIissuer\fR]
 .OP \-\-ocsp uri
 .OP \-\-pathlen len
-.OP \-\-nc-permitted name
 .OP \-\-addrblock block
+.OP \-\-nc-permitted name
 .OP \-\-nc-excluded name
+.OP \-\-critical oid
 .OP \-\-policy\-mapping mapping
 .OP \-\-policy\-explicit len
 .OP \-\-policy\-inhibit len
@@ -181,6 +182,9 @@ or
 .B email:
 prefix to force a constraint type.
 .TP
+.BI "\-X, \-\-critical " oid
+Add a critical extension with the given OID.
+.TP
 .BI "\-M, \-\-policy-mapping " issuer-oid:subject-oid
 Add policyMapping from issuer to subject OID.
 .TP
index 5f7e421..6e04609 100644 (file)
@@ -1,4 +1,4 @@
-.TH "PKI \-\-SELF" 1 "2016-12-13" "@PACKAGE_VERSION@" "strongSwan"
+.TH "PKI \-\-SELF" 1 "2019-05-06" "@PACKAGE_VERSION@" "strongSwan"
 .
 .SH "NAME"
 .
@@ -26,6 +26,7 @@ pki \-\-self \- Create a self-signed certificate
 .OP \-\-addrblock block
 .OP \-\-nc-permitted name
 .OP \-\-nc-excluded name
+.OP \-\-critical oid
 .OP \-\-policy\-mapping mapping
 .OP \-\-policy\-explicit len
 .OP \-\-policy\-inhibit len
@@ -160,6 +161,9 @@ or
 .B email:
 prefix to force a constraint type.
 .TP
+.BI "\-X, \-\-critical " oid
+Add a critical extension with the given OID.
+.TP
 .BI "\-M, \-\-policy-mapping " issuer-oid:subject-oid
 Add policyMapping from issuer to subject OID.
 .TP
index 0abd166..781de8b 100644 (file)
@@ -1,4 +1,4 @@
-.TH "PKI \-\-SIGNCRL" 1 "2013-08-12" "@PACKAGE_VERSION@" "strongSwan"
+.TH "PKI \-\-SIGNCRL" 1 "2019-05-06" "@PACKAGE_VERSION@" "strongSwan"
 .
 .SH "NAME"
 .
@@ -18,6 +18,7 @@ pki \-\-signcrl \- Issue a Certificate Revocation List (CRL) using a CA certific
 .OP \-\-digest digest
 .OP \-\-rsa\-padding padding
 .OP \fR[\fB\-\-reason\ \fIreason\fR]\ \fR[\fB\-\-date\ \fIts\fR]\ \fB\-\-cert\ \fIfile\fB|\-\-serial\ \fIhex\fR
+.OP \-\-critical oid
 .OP \-\-outform encoding
 .OP \-\-debug level
 .YS
@@ -107,6 +108,9 @@ determined based on the type and size of the signature key.
 Padding to use for RSA signatures. Either \fIpkcs1\fR or \fIpss\fR, defaults
 to \fIpkcs1\fR.
 .TP
+.BI "\-X, \-\-critical " oid
+Add a critical extension with the given OID.
+.TP
 .BI "\-f, \-\-outform " encoding
 Encoding of the created certificate file. Either \fIder\fR (ASN.1 DER) or
 \fIpem\fR (Base64 PEM), defaults to \fIder\fR.