]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
pkcs10: Support of Microsoft CertTypeExtension
authorAndreas Steffen <andreas.steffen@strongswan.org>
Wed, 10 Aug 2022 22:21:28 +0000 (00:21 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Wed, 24 Aug 2022 18:46:44 +0000 (20:46 +0200)
The msCertificateTypeExtension OID (1.3.6.1.4.1.311.20.2) can
be used in a PKCS#10 certificate request to define a certificate
profile. It consists of an UTF8 string.

pki: profile option

src/libstrongswan/asn1/oid.txt
src/libstrongswan/credentials/builder.c
src/libstrongswan/credentials/builder.h
src/libstrongswan/credentials/certificates/pkcs10.h
src/libstrongswan/plugins/x509/x509_pkcs10.c
src/pki/commands/issue.c
src/pki/commands/req.c
src/pki/commands/scep.c
src/pki/man/pki---req.1.in
src/pki/man/pki---scep.1.in

index b09f9eafa69df523c723c38bef7febef9d1dc8f9..c91c1262aff5136034b50e58b0e62b82ebc0cfdb 100644 (file)
                   0x03       "msSGC"
                   0x04       "msEncryptingFileSystem"
               0x14           "msEnrollmentInfrastructure"
-                0x02         "msCertificateTypeExtension"
+                0x02         "msCertTypeExtension"             OID_MS_CERT_TYPE_EXT
                   0x02       "msSmartcardLogon"                        OID_MS_SMARTCARD_LOGON
                   0x03       "msUPN"                                   OID_USER_PRINCIPAL_NAME
               0x15           "msCertSrvInfrastructure"
index 196118f829c1807fd1bdc9e5788b1d4906c6e423..bb50e097f49299e6867e2b03d6b339d2df78f658 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 Martin Willi
- * Copyright (C) 2016-2019 Andreas Steffen
+ * Copyright (C) 2016-2022 Andreas Steffen
  *
  * Copyright (C) secunet Security Networks AG
  *
@@ -59,6 +59,7 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
        "BUILD_REVOKED_ENUMERATOR",
        "BUILD_BASE_CRL",
        "BUILD_CHALLENGE_PWD",
+       "BUILD_CERT_TYPE_EXT",
        "BUILD_PKCS7_ATTRIBUTE",
        "BUILD_PKCS11_MODULE",
        "BUILD_PKCS11_SLOT",
index f09c011460c850ad2580be045e29d368ba724f99..6d143dd4fc0cf076fb7bf3fa16bc64ad14dd2e03 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 Martin Willi
- * Copyright (C) 2016-2019 Andreas Steffen
+ * Copyright (C) 2016-2022 Andreas Steffen
  *
  * Copyright (C) secunet Security Networks AG
  *
@@ -127,6 +127,8 @@ enum builder_part_t {
        BUILD_BASE_CRL,
        /** PKCS#10 challenge password */
        BUILD_CHALLENGE_PWD,
+       /** PKCS#10 certificate type extension */
+       BUILD_CERT_TYPE_EXT,
        /** PKCS#7 attribute, int oid, chunk_t with ASN1 type encoded value */
        BUILD_PKCS7_ATTRIBUTE,
        /** friendly name of a PKCS#11 module, null terminated char* */
index a6727bc3a2ff7bcdb78f1cd366c087dea5984423..ab5e3cdaad85f228134d29110dceab4ea4fdc25e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Andreas Steffen
+ * Copyright (C) 2009-2022 Andreas Steffen
  *
  * Copyright (C) secunet Security Networks AG
  *
@@ -22,6 +22,8 @@
 #ifndef PKCS10_H_
 #define PKCS10_H_
 
+#include "x509.h"
+
 #include <collections/enumerator.h>
 #include <credentials/certificates/certificate.h>
 
@@ -47,8 +49,15 @@ struct pkcs10_t {
         */
        chunk_t (*get_challengePassword)(pkcs10_t *this);
 
+    /**
+     * Get Extended Key Usage (EKU) flags
+     *
+     * @return          EKU flags
+     */
+    x509_flag_t (*get_flags)(pkcs10_t *this);
+
        /**
-        * Get.
+        * Get subjectAltNames
         *
         * @return                      enumerator over subjectAltNames as identification_t*
         */
index f1d90abd0a8b9c40a5866ac027dd8b88dbb90bb9..cee518b51a30bf547957acc963dca9a0ea8b5069 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2005 Jan Hutter, Martin Willi
- * Copyright (C) 2009-2017 Andreas Steffen
+ * Copyright (C) 2009-2022 Andreas Steffen
  *
  * Copyright (C) secunet Security Networks AG
  *
@@ -72,6 +72,11 @@ struct private_x509_pkcs10_t {
         */
        chunk_t challengePassword;
 
+       /**
+        * certificate type extension
+        */
+       chunk_t certTypeExt;
+
        /**
         * Signature scheme
         */
@@ -230,6 +235,35 @@ METHOD(pkcs10_t, get_challengePassword, chunk_t,
        return this->challengePassword;
 }
 
+METHOD(pkcs10_t, get_flags, x509_flag_t,
+       private_x509_pkcs10_t *this)
+{
+       x509_flag_t flags = X509_NONE;
+       char *profile;
+
+       profile = strndup(this->certTypeExt.ptr, this->certTypeExt.len);
+
+       if (strcaseeq(profile, "server"))
+       {
+               flags |= X509_SERVER_AUTH;
+       }
+       else if (strcaseeq(profile, "client"))
+       {
+               flags |= X509_CLIENT_AUTH;
+       }
+       else if (strcaseeq(profile, "dual"))
+       {
+               flags |= (X509_SERVER_AUTH | X509_CLIENT_AUTH);
+       }
+       else if (strcaseeq(profile, "ocsp"))
+       {
+               flags |= X509_OCSP_SIGNER;
+       }
+       free(profile);
+
+       return flags;
+}
+
 METHOD(pkcs10_t, create_subjectAltName_enumerator, enumerator_t*,
        private_x509_pkcs10_t *this)
 {
@@ -240,12 +274,12 @@ METHOD(pkcs10_t, create_subjectAltName_enumerator, enumerator_t*,
  * ASN.1 definition of a PKCS#10 extension request
  */
 static const asn1Object_t extensionRequestObjects[] = {
-       { 0, "extensions",   ASN1_SEQUENCE,     ASN1_LOOP           }, /* 0 */
+       { 0, "extensions",    ASN1_SEQUENCE,     ASN1_LOOP          }, /* 0 */
        { 1,   "extension",   ASN1_SEQUENCE,     ASN1_NONE          }, /* 1 */
-       { 2,     "extnID",        ASN1_OID,          ASN1_BODY          }, /* 2 */
+       { 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, "end loop",      ASN1_EOC,          ASN1_END           }, /* 5 */
        { 0, "exit",          ASN1_EOC,          ASN1_EXIT          }
 };
 #define PKCS10_EXTN_ID                 2
@@ -291,6 +325,14 @@ static bool parse_extension_request(private_x509_pkcs10_t *this, chunk_t blob, i
                                                        goto end;
                                                }
                                                break;
+                                       case OID_MS_CERT_TYPE_EXT:
+                                               if (!asn1_parse_simple_object(&object, ASN1_UTF8STRING,
+                                                                                                         level, "certTypeExt"))
+                                               {
+                                                       goto end;
+                                               }
+                                               this->certTypeExt = object;
+                                               break;
                                        default:
                                                break;
                                }
@@ -482,6 +524,7 @@ METHOD(certificate_t, destroy, void,
                {       /* only parsed certificate requests point these fields to "encoded" */
                        chunk_free(&this->certificationRequestInfo);
                        chunk_free(&this->challengePassword);
+                       chunk_free(&this->certTypeExt);
                        chunk_free(&this->signature);
                }
                free(this);
@@ -513,6 +556,7 @@ static private_x509_pkcs10_t* create_empty(void)
                                        .destroy = _destroy,
                                },
                                .get_challengePassword = _get_challengePassword,
+                               .get_flags = _get_flags,
                                .create_subjectAltName_enumerator = _create_subjectAltName_enumerator,
                        },
                },
@@ -530,7 +574,7 @@ static bool generate(private_x509_pkcs10_t *cert, private_key_t *sign_key,
                                         int digest_alg)
 {
        chunk_t key_info, subjectAltNames, attributes;
-       chunk_t extensionRequest  = chunk_empty;
+       chunk_t extensionRequest  = chunk_empty, certTypeExt = chunk_empty;
        chunk_t challengePassword = chunk_empty, sig_scheme = chunk_empty;
        identification_t *subject;
 
@@ -565,35 +609,44 @@ static bool generate(private_x509_pkcs10_t *cert, private_key_t *sign_key,
        /* encode subjectAltNames */
        subjectAltNames = x509_build_subjectAltNames(cert->subjectAltNames);
 
-       if (subjectAltNames.ptr)
+       /* encode certTypeExt */
+       if (cert->certTypeExt.len > 0)
+       {
+               certTypeExt = asn1_wrap(ASN1_SEQUENCE, "mm",
+                               asn1_build_known_oid(OID_MS_CERT_TYPE_EXT),
+                               asn1_wrap(ASN1_OCTET_STRING, "m",
+                                       asn1_simple_object(ASN1_UTF8STRING, cert->certTypeExt)
+                               ));
+       }
+
+       /* encode extensionRequest attribute */
+       if (subjectAltNames.ptr || certTypeExt.ptr)
        {
                extensionRequest = asn1_wrap(ASN1_SEQUENCE, "mm",
-                                       asn1_build_known_oid(OID_EXTENSION_REQUEST),
-                                       asn1_wrap(ASN1_SET, "m",
-                                               asn1_wrap(ASN1_SEQUENCE, "m", subjectAltNames)
-                                       ));
+                               asn1_build_known_oid(OID_EXTENSION_REQUEST),
+                               asn1_wrap(ASN1_SET, "m",
+                                       asn1_wrap(ASN1_SEQUENCE, "mm", subjectAltNames, certTypeExt)
+                               ));
        }
+
+       /* encode challengePassword attribute */
        if (cert->challengePassword.len > 0)
        {
-               asn1_t type = asn1_is_printablestring(cert->challengePassword) ?
-                                                               ASN1_PRINTABLESTRING : ASN1_T61STRING;
-
                challengePassword = asn1_wrap(ASN1_SEQUENCE, "mm",
-                                       asn1_build_known_oid(OID_CHALLENGE_PASSWORD),
-                                       asn1_wrap(ASN1_SET, "m",
-                                               asn1_simple_object(type, cert->challengePassword)
-                                       )
-                       );
+                               asn1_build_known_oid(OID_CHALLENGE_PASSWORD),
+                               asn1_wrap(ASN1_SET, "m",
+                                       asn1_simple_object(ASN1_UTF8STRING, cert->challengePassword)
+                               ));
        }
+
        attributes = asn1_wrap(ASN1_CONTEXT_C_0, "mm", extensionRequest,
                                                                                                   challengePassword);
 
        cert->certificationRequestInfo = asn1_wrap(ASN1_SEQUENCE, "ccmm",
-                                                       ASN1_INTEGER_0,
-                                                       subject->get_encoding(subject),
-                                                       key_info,
-                                                       attributes);
-
+                                                                               ASN1_INTEGER_0,
+                                                                               subject->get_encoding(subject),
+                                                                               key_info,
+                                                                               attributes);
        if (!sign_key->sign(sign_key, cert->scheme->scheme, cert->scheme->params,
                                                cert->certificationRequestInfo, &cert->signature))
        {
@@ -685,6 +738,9 @@ 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_CERT_TYPE_EXT:
+                               cert->certTypeExt = 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);
index 1b66548d4022ca35253fe0f1a05f289ab1395d15..023f0536ab4ba3c03949b65b8b759068402d179f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2009 Martin Willi
- * Copyright (C) 2015-2019 Andreas Steffen
+ * Copyright (C) 2015-2022 Andreas Steffen
  *
  * Copyright (C) secunet Security Networks AG
  *
@@ -480,9 +480,12 @@ static int issue()
                        id = cert_req->get_subject(cert_req);
                        id = id->clone(id);
                }
+               req = (pkcs10_t*)cert_req;
+
+               /* Add Extended Key Usage (EKU) flags */
+               flags |= req->get_flags(req);
 
                /* Add subjectAltNames from PKCS#10 certificate request */
-               req = (pkcs10_t*)cert_req;
                enumerator = req->create_subjectAltName_enumerator(req);
                while (enumerator->enumerate(enumerator, &subjectAltName))
                {
index 44208771c0c8eb140446f855ba3b3d5fd5ca8ec4..b2f3545e64f29ab49f7c6c46e2bc41186969f287 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2009 Martin Willi
- * Copyright (C) 2009-2017 Andreas Steffen
+ * Copyright (C) 2009-2022 Andreas Steffen
  *
  * Copyright (C) secunet Security Networks AG
  *
@@ -39,6 +39,7 @@ static int req()
        linked_list_t *san;
        chunk_t encoding = chunk_empty;
        chunk_t challenge_password = chunk_empty;
+       chunk_t cert_type_ext = chunk_empty;
        char *arg;
        bool pss = lib->settings->get_bool(lib->settings, "%s.rsa_pss", FALSE,
                                                                           lib->ns);
@@ -101,6 +102,9 @@ static int req()
                        case 'a':
                                san->insert_last(san, identification_create_from_string(arg));
                                continue;
+                       case 'P':
+                               cert_type_ext = chunk_create(arg, strlen(arg));
+                               continue;
                        case 'p':
                                challenge_password = chunk_create(arg, strlen(arg));
                                continue;
@@ -180,6 +184,7 @@ static int req()
                                                          BUILD_SUBJECT, id,
                                                          BUILD_SUBJECT_ALTNAMES, san,
                                                          BUILD_CHALLENGE_PWD, challenge_password,
+                                                         BUILD_CERT_TYPE_EXT, cert_type_ext,
                                                          BUILD_SIGNATURE_SCHEME, scheme,
                                                          BUILD_END);
        if (!cert)
@@ -228,9 +233,9 @@ static void __attribute__ ((constructor))reg()
                req, 'r', "req",
                "create a PKCS#10 certificate request",
                {"[--in file|--keyid hex] [--type rsa|ecdsa|bliss|priv] --dn distinguished-name",
-                "[--san subjectAltName]+ [--password challengePassword]",
+                "[--san subjectAltName]+ [--profile server|client|dual|ocsp]",
+                "[--password challengePassword] [--rsa-padding pkcs1|pss]",
                 "[--digest md5|sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512]",
-                "[--rsa-padding pkcs1|pss]",
                 "[--outform der|pem]"},
                {
                        {"help",                'h', 0, "show usage information"},
@@ -239,6 +244,7 @@ static void __attribute__ ((constructor))reg()
                        {"type",                't', 1, "type of input key, default: priv"},
                        {"dn",                  'd', 1, "subject distinguished name"},
                        {"san",                 'a', 1, "subjectAltName to include in cert request"},
+                       {"profile",     'P', 1, "certificate profile name to include in cert request"},
                        {"password",    'p', 1, "challengePassword to include in cert request"},
                        {"digest",              'g', 1, "digest for signature creation, default: key-specific"},
                        {"rsa-padding", 'R', 1, "padding for RSA signatures, default: pkcs1"},
index 37f5a948286f056f54eda67bb5aabacfc2bb8212..03703e76a36b02956620a058f574d38de6cba89e 100644 (file)
@@ -46,6 +46,7 @@ static int scep()
        cred_encoding_type_t form = CERT_ASN1_DER;
        chunk_t scep_response = chunk_empty;
        chunk_t challenge_password = chunk_empty;
+       chunk_t cert_type = chunk_empty;
        chunk_t serialNumber = chunk_empty;
        chunk_t transID = chunk_empty;
        chunk_t pkcs10_encoding = chunk_empty;
@@ -114,6 +115,9 @@ static int scep()
                        case 'a':
                                san->insert_last(san, identification_create_from_string(arg));
                                continue;
+                       case 'P':
+                               cert_type = chunk_create(arg, strlen(arg));
+                               continue;
                        case 'p':
                                challenge_password = chunk_create(arg, strlen(arg));
                                continue;
@@ -351,6 +355,7 @@ static int scep()
                                                        BUILD_SUBJECT, subject,
                                                        BUILD_SUBJECT_ALTNAMES, san,
                                                        BUILD_CHALLENGE_PWD, challenge_password,
+                                                       BUILD_CERT_TYPE_EXT, cert_type,
                                                        BUILD_SIGNATURE_SCHEME, scheme,
                                                        BUILD_END);
        if (!pkcs10)
@@ -682,8 +687,9 @@ static void __attribute__ ((constructor))reg()
                scep, 'S', "scep",
                "Enroll an X.509 certificate with a SCEP server",
                {"--url url [--in file] --dn distinguished-name [--san subjectAltName]+",
-                "[--password password] --cacert-enc file --cacert-sig file [--cacert file]+",
-                "[--oldcert file --oldkey file] [--cipher aes|des3]",
+                "[--profile profile] [--password password]",
+                " --cacert-enc file --cacert-sig file [--cacert file]+",
+                " --oldcert file --oldkey file] [--cipher aes|des3]",
                 "[--digest sha256|sha384|sha512|sha224|sha1] [--rsa-padding pkcs1|pss]",
                 "[--interval time] [--maxpolltime time] [--outform der|pem]"},
                {
@@ -692,6 +698,7 @@ static void __attribute__ ((constructor))reg()
                        {"in",          'i', 1, "RSA private key input file, default: stdin"},
                        {"dn",          'd', 1, "subject distinguished name"},
                        {"san",         'a', 1, "subjectAltName to include in cert request"},
+                       {"profile",     'P', 1, "certificate profile name to include in cert request"},
                        {"password",    'p', 1, "challengePassword to include in cert request"},
                        {"cacert-enc",  'e', 1, "CA certificate for encryption"},
                        {"cacert-sig",  's', 1, "CA certificate for signature verification"},
index 8f7de248cefd4876ef7167ca4e596bcee5980a42..516088f3d21a02c6ef80a91ee564ea9b2703e3fc 100644 (file)
@@ -1,4 +1,4 @@
-.TH "PKI \-\-REQ" 1 "2013-07-31" "@PACKAGE_VERSION@" "strongSwan"
+.TH "PKI \-\-REQ" 1 "2022-08-11" "@PACKAGE_VERSION@" "strongSwan"
 .
 .SH "NAME"
 .
@@ -13,6 +13,7 @@ pki \-\-req \- Create a PKCS#10 certificate request
 .OP \-\-type type
 .BI \-\-dn\~ distinguished-name
 .OP \-\-san subjectAltName
+.OP \-\-profile profile
 .OP \-\-password password
 .OP \-\-digest digest
 .OP \-\-rsa\-padding padding
@@ -29,7 +30,7 @@ pki \-\-req \- Create a PKCS#10 certificate request
 |
 .B \-\-help
 .YS
-.
+.q
 .SH "DESCRIPTION"
 .
 This sub-command of
@@ -65,6 +66,15 @@ Subject distinguished name (DN). Required.
 .BI "\-a, \-\-san " subjectAltName
 subjectAltName extension to include in request. Can be used multiple times.
 .TP
+.BI "\-P, \-\-profile " profile
+Certificate profile name to be included in the certificate request. Can be any
+UTF8 string. Supported e.g. by
+.B openxpki
+with profiles (\fIpc-client\fR, \fItls-server\fR, etc.) or
+.B pki \-\-issue
+with (\fIserver\fR, \fIclient\fR, \fIdual\fR, or \fIocsp\fR) that are translated into
+corresponding Extended Key Usage (EKU) flags in the generated X.509 certificate.
+.TP
 .BI "\-p, \-\-password " password
 The challengePassword to include in the certificate request.
 .TP
@@ -83,11 +93,12 @@ Encoding of the created certificate file. Either \fIder\fR (ASN.1 DER) or
 .
 .SH "EXAMPLES"
 .
-Generate a certificate request for an RSA key, with a subjectAltName extension:
+Generate a certificate request for an RSA key, with a subjectAltName extension
+and a TLS-server profile:
 .PP
 .EX
   pki \-\-req \-\-in key.der \-\-dn "C=CH, O=strongSwan, CN=moon" \\
-       \-\-san moon@strongswan.org > req.der
+       \-\-san moon@strongswan.org \-\-profile server > req.der
 .EE
 .PP
 Generate a certificate request for an ECDSA key and a different digest:
index 2422b54ca7e7336118ff7b048d348056dba077d8..8817cffc11f16c016ce7002763c64012213d4297 100644 (file)
@@ -11,6 +11,7 @@ pki \-\-scep \- Enroll an X.509 certificate with a SCEP server
 .OP \-\-in file
 .BI \-\-dn\~ distinguished-name
 .OP \-\-san subjectAltName
+.OP \-\-profile profile
 .OP \-\-password password
 .BI \-\-ca-cert-enc\~ file
 .BI \-\-ca-cert-sig\~ file
@@ -74,6 +75,14 @@ Subject distinguished name (DN). Required.
 .BI "\-a, \-\-san " subjectAltName
 subjectAltName extension to include in request. Can be used multiple times.
 .TP
+.BI "\-P, \-\-profile " profile
+Certificate profile name to be included in the certificate request. Can be any
+UTF8 string. Supported e.g. by the
+.B openxpki
+SCEP server with profiles (\fIpc-client\fR, \fItls-server\fR, etc.) that are
+translated into corresponding Extended Key Usage (EKU) flags in the generated
+X.509 certificate.
+.TP
 .BI "\-p, \-\-password " password
 The challengePassword to include in the certificate request.
 .TP