X509: Add "code sign" as purpose for verification of certificates
authorLutz Jaenicke <ljaenicke@phoenixcontact.com>
Thu, 14 Oct 2021 13:24:18 +0000 (15:24 +0200)
committerTomas Mraz <tomas@openssl.org>
Thu, 18 Aug 2022 08:24:53 +0000 (10:24 +0200)
Code signing certificates have other properties as for example described in
CA Browser Forum documents. This leads to "unsupported certificate purpose" errors when
verifying signed objects.
This patch adds the purpose "codesign" to the table in X.509 certificate verification and
the verification parameter "code_sign" to X509_VERIFY_PARAM.

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18567)

crypto/x509/v3_purp.c
crypto/x509/x509_vpm.c
doc/man1/openssl-verification-options.pod
doc/man3/X509_STORE_CTX_new.pod
doc/man3/X509_check_purpose.pod
include/openssl/x509v3.h.in

index fa3a8b1ebf495f492d9da15920d8db7373e82f4a..cac539b1e4bd4979a8a3ad8911856eb69e42f37d 100644 (file)
@@ -32,6 +32,8 @@ static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x,
                                   int require_ca);
 static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
                                         int require_ca);
+static int check_purpose_code_sign(const X509_PURPOSE *xp, const X509 *x,
+                                        int require_ca);
 static int no_check_purpose(const X509_PURPOSE *xp, const X509 *x,
                             int require_ca);
 static int check_purpose_ocsp_helper(const X509_PURPOSE *xp, const X509 *x,
@@ -61,6 +63,9 @@ static X509_PURPOSE xstandard[] = {
     {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0,
      check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign",
      NULL},
+    {X509_PURPOSE_CODE_SIGN, X509_TRUST_OBJECT_SIGN, 0,
+     check_purpose_code_sign, "Code signing", "codesign",
+     NULL},
 };
 
 #define X509_PURPOSE_COUNT OSSL_NELEM(xstandard)
@@ -865,6 +870,57 @@ static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
     return 1;
 }
 
+static int check_purpose_code_sign(const X509_PURPOSE *xp, const X509 *x,
+                                   int require_ca)
+{
+    int i_ext;
+
+    /* If ca is true we must return if this is a valid CA certificate. */
+    if (require_ca)
+        return check_ca(x);
+
+    /*
+     * Check the key usage and extended key usage fields:
+     *
+     * Reference: CA Browser Forum,
+     * Baseline Requirements for the Issuance and Management of 
+     * Publicly‐Trusted Code Signing Certificates, Version 3.0.0,
+     * Section 7.1.2.3: Code signing and Timestamp Certificate
+     *
+     * Checking covers Key Usage and Extended Key Usage attributes.
+     * Other properties like CRL Distribution Points and Authoriy
+     * Information Access (AIA) are not checked.
+     */
+    /* Key Usage */
+    if ((x->ex_flags & EXFLAG_KUSAGE) == 0)
+        return 0;
+    if ((x->ex_kusage & KU_DIGITAL_SIGNATURE) == 0)
+        return 0;
+    if ((x->ex_kusage & (KU_KEY_CERT_SIGN | KU_CRL_SIGN)) != 0)
+        return 0;
+
+    /* Key Usage MUST be critical */
+    i_ext = X509_get_ext_by_NID(x, NID_key_usage, -1);
+    if (i_ext < 0)
+        return 0;
+    if (i_ext >= 0) {
+        X509_EXTENSION *ext = X509_get_ext((X509 *)x, i_ext);
+        if (!X509_EXTENSION_get_critical(ext))
+            return 0;
+    }
+
+    /* Extended Key Usage */
+    if ((x->ex_flags & EXFLAG_XKUSAGE) == 0)
+        return 0;
+    if ((x->ex_xkusage & XKU_CODE_SIGN) == 0)
+        return 0;
+    if ((x->ex_xkusage & (XKU_ANYEKU | XKU_SSL_SERVER)) != 0)
+        return 0;
+
+    return 1;
+
+}
+
 static int no_check_purpose(const X509_PURPOSE *xp, const X509 *x,
                             int require_ca)
 {
index b974f9ab89599fdaa96bce878d369d14f316f39d..598830bdcbfef522f978d6b6c2fe2d7848c72c3b 100644 (file)
@@ -502,6 +502,18 @@ const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param)
  */
 
 static const X509_VERIFY_PARAM default_table[] = {
+    {
+     "code_sign",               /* Code sign parameters */
+     0,                         /* check time to use */
+     0,                         /* inheritance flags */
+     0,                         /* flags */
+     X509_PURPOSE_CODE_SIGN,    /* purpose */
+     X509_TRUST_OBJECT_SIGN,    /* trust */
+     -1,                        /* depth */
+     -1,                        /* auth_level */
+     NULL,                      /* policies */
+     vpm_empty_id
+    },
     {
      "default",                 /* X509 default parameters */
      0,                         /* check time to use */
index 6888d5244fbe2ca18aa9d7bbbf5d0aa602db9c5b..57b29dc5837fe05bebf4d047c2165e80e826ed18 100644 (file)
@@ -458,7 +458,7 @@ Set policy variable inhibit-policy-mapping (see RFC5280).
 The intended use for the certificate.
 Currently defined purposes are C<sslclient>, C<sslserver>, C<nssslserver>,
 C<smimesign>, C<smimeencrypt>, C<crlsign>, C<ocsphelper>, C<timestampsign>,
-and C<any>.
+C<codesign> and C<any>.
 If peer certificate verification is enabled, by default the TLS implementation
 as well as the commands B<s_client> and B<s_server> check for consistency
 with TLS server or TLS client use, respectively.
index 2996a34eb6060f85a4b70148b1815660eebe4032..72f60093d7e832834b28ace2f0c59436760717c2 100644 (file)
@@ -187,7 +187,8 @@ verified in the I<ctx>. Built-in available values for the I<purpose> argument
 are B<X509_PURPOSE_SSL_CLIENT>, B<X509_PURPOSE_SSL_SERVER>,
 B<X509_PURPOSE_NS_SSL_SERVER>, B<X509_PURPOSE_SMIME_SIGN>,
 B<X509_PURPOSE_SMIME_ENCRYPT>, B<X509_PURPOSE_CRL_SIGN>, B<X509_PURPOSE_ANY>,
-B<X509_PURPOSE_OCSP_HELPER> and B<X509_PURPOSE_TIMESTAMP_SIGN>. It is also
+B<X509_PURPOSE_OCSP_HELPER>, B<X509_PURPOSE_TIMESTAMP_SIGN> and
+B<X509_PURPOSE_CODE_SIGN>.  It is also
 possible to create a custom purpose value. Setting a purpose will ensure that
 the key usage declared within certificates in the chain being verified is
 consistent with that purpose as well as, potentially, other checks. Every
index a3cfb78d6198c9affb0aa559554b56b71ab6a427..4331cfad92c907f4efe96492cc6371a62b4a905e 100644 (file)
@@ -29,6 +29,7 @@ Below are the potential ID's that can be checked:
  # define X509_PURPOSE_ANY               7
  # define X509_PURPOSE_OCSP_HELPER       8
  # define X509_PURPOSE_TIMESTAMP_SIGN    9
+ # define X509_PURPOSE_CODE_SIGN        10
 
 The checks performed take into account the X.509 extensions
 keyUsage, extendedKeyUsage, and basicConstraints.
index 7d7e4718b6db2bcbcfe523ed068b87b43755d304..80c69960b0c0e447495706eb99b4c8f30d658a23 100644 (file)
@@ -478,9 +478,10 @@ typedef struct x509_purpose_st {
 # define X509_PURPOSE_ANY                7
 # define X509_PURPOSE_OCSP_HELPER        8
 # define X509_PURPOSE_TIMESTAMP_SIGN     9
+# define X509_PURPOSE_CODE_SIGN         10
 
 # define X509_PURPOSE_MIN                1
-# define X509_PURPOSE_MAX                9
+# define X509_PURPOSE_MAX               10
 
 /* Flags for X509V3_EXT_print() */