Add the X509v3_cache_extensions() function
authorMatt Caswell <matt@openssl.org>
Fri, 20 Mar 2020 11:52:07 +0000 (11:52 +0000)
committerMatt Caswell <matt@openssl.org>
Mon, 30 Mar 2020 13:54:37 +0000 (14:54 +0100)
Various functions cause the results of processing extensions to be
cached. The processing itself requires a libctx, and so this implicit
caching means that the default ctx is used which can lead to failures.
By explicitly caching the extensions we can specify the libctx to be used.

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/11409)

crypto/x509/v3_purp.c
doc/man3/X509_check_ca.pod
include/openssl/x509v3.h
util/libcrypto.num

index eae837ea88af97eaee528b2fb7a2c1a53715edd6..0d020903303b8a15417be37e02c6d33fa90f40f5 100644 (file)
@@ -15,8 +15,6 @@
 #include "crypto/x509.h"
 #include "internal/tsan_assist.h"
 
 #include "crypto/x509.h"
 #include "internal/tsan_assist.h"
 
-static void x509v3_cache_extensions(X509 *x);
-
 static int check_ssl_ca(const X509 *x);
 static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
                                     int ca);
 static int check_ssl_ca(const X509 *x);
 static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
                                     int ca);
@@ -80,8 +78,7 @@ int X509_check_purpose(X509 *x, int id, int ca)
     int idx;
     const X509_PURPOSE *pt;
 
     int idx;
     const X509_PURPOSE *pt;
 
-    x509v3_cache_extensions(x);
-    if (x->ex_flags & EXFLAG_INVALID)
+    if (!X509v3_cache_extensions(x, NULL, NULL))
         return -1;
 
     /* Return if side-effect only call */
         return -1;
 
     /* Return if side-effect only call */
@@ -352,7 +349,7 @@ static int setup_crldp(X509 *x)
 #define ns_reject(x, usage) \
         (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
 
 #define ns_reject(x, usage) \
         (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
 
-static void x509v3_cache_extensions(X509 *x)
+int X509v3_cache_extensions(X509 *x, OPENSSL_CTX *libctx, const char *propq)
 {
     BASIC_CONSTRAINTS *bs;
     PROXY_CERT_INFO_EXTENSION *pci;
 {
     BASIC_CONSTRAINTS *bs;
     PROXY_CERT_INFO_EXTENSION *pci;
@@ -361,21 +358,25 @@ static void x509v3_cache_extensions(X509 *x)
     EXTENDED_KEY_USAGE *extusage;
     X509_EXTENSION *ex;
     int i;
     EXTENDED_KEY_USAGE *extusage;
     X509_EXTENSION *ex;
     int i;
+    EVP_MD *sha1;
 
 #ifdef tsan_ld_acq
     /* fast lock-free check, see end of the function for details. */
     if (tsan_ld_acq((TSAN_QUALIFIER int *)&x->ex_cached))
 
 #ifdef tsan_ld_acq
     /* fast lock-free check, see end of the function for details. */
     if (tsan_ld_acq((TSAN_QUALIFIER int *)&x->ex_cached))
-        return;
+        return (x->ex_flags & EXFLAG_INVALID) == 0;
 #endif
 
     CRYPTO_THREAD_write_lock(x->lock);
     if (x->ex_flags & EXFLAG_SET) {
         CRYPTO_THREAD_unlock(x->lock);
 #endif
 
     CRYPTO_THREAD_write_lock(x->lock);
     if (x->ex_flags & EXFLAG_SET) {
         CRYPTO_THREAD_unlock(x->lock);
-        return;
+        return (x->ex_flags & EXFLAG_INVALID) == 0;
     }
 
     }
 
-    if (!X509_digest(x, EVP_sha1(), x->sha1_hash, NULL))
-        x->ex_flags |= EXFLAG_INVALID;
+    sha1 = EVP_MD_fetch(libctx, "SHA1", propq);
+    if (sha1 == NULL || !X509_digest(x, sha1, x->sha1_hash, NULL))
+            x->ex_flags |= EXFLAG_INVALID;
+    EVP_MD_free(sha1);
+
     /* V1 should mean no extensions ... */
     if (!X509_get_version(x))
         x->ex_flags |= EXFLAG_V1;
     /* V1 should mean no extensions ... */
     if (!X509_get_version(x))
         x->ex_flags |= EXFLAG_V1;
@@ -538,6 +539,8 @@ static void x509v3_cache_extensions(X509 *x)
      */
 #endif
     CRYPTO_THREAD_unlock(x->lock);
      */
 #endif
     CRYPTO_THREAD_unlock(x->lock);
+
+    return (x->ex_flags & EXFLAG_INVALID) == 0;
 }
 
 /*-
 }
 
 /*-
@@ -590,7 +593,9 @@ void X509_set_proxy_pathlen(X509 *x, long l)
 
 int X509_check_ca(X509 *x)
 {
 
 int X509_check_ca(X509 *x)
 {
-    x509v3_cache_extensions(x);
+    /* Note 0 normally means "not a CA" - but in this case means error. */
+    if (!X509v3_cache_extensions(x, NULL, NULL))
+        return 0;
 
     return check_ca(x);
 }
 
     return check_ca(x);
 }
@@ -806,11 +811,8 @@ int X509_check_issued(X509 *issuer, X509 *subject)
                       X509_get_issuer_name(subject)))
         return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
 
                       X509_get_issuer_name(subject)))
         return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
 
-    x509v3_cache_extensions(issuer);
-    if (issuer->ex_flags & EXFLAG_INVALID)
-        return X509_V_ERR_UNSPECIFIED;
-    x509v3_cache_extensions(subject);
-    if (subject->ex_flags & EXFLAG_INVALID)
+    if (!X509v3_cache_extensions(issuer, NULL, NULL)
+            || !X509v3_cache_extensions(subject, NULL, NULL))
         return X509_V_ERR_UNSPECIFIED;
 
     if (subject->akid) {
         return X509_V_ERR_UNSPECIFIED;
 
     if (subject->akid) {
index 9fe01d1983961c97ca97456a775733ad1b9e825e..89adb2e3b6468502d1929ec03fb8f8dc568cb2d9 100644 (file)
@@ -24,6 +24,8 @@ B<keyUsage> extension with bit B<keyCertSign> set, but without
 B<basicConstraints>, and 5 if it has outdated Netscape Certificate Type
 extension telling that it is CA certificate.
 
 B<basicConstraints>, and 5 if it has outdated Netscape Certificate Type
 extension telling that it is CA certificate.
 
+This function will also return 0 on error.
+
 Actually, any nonzero value means that this certificate could have been
 used to sign other certificates.
 
 Actually, any nonzero value means that this certificate could have been
 used to sign other certificates.
 
index 63903efb200879b4ede17cb96ed3a5a80ff6ad08..e8efab2f086baa575d7a99234399356e2a5314d6 100644 (file)
@@ -572,6 +572,9 @@ GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out,
                                   const X509V3_EXT_METHOD *method,
                                   X509V3_CTX *ctx, CONF_VALUE *cnf,
                                   int is_nc);
                                   const X509V3_EXT_METHOD *method,
                                   X509V3_CTX *ctx, CONF_VALUE *cnf,
                                   int is_nc);
+
+int X509v3_cache_extensions(X509 *x, OPENSSL_CTX *libctx, const char *propq);
+
 void X509V3_conf_free(CONF_VALUE *val);
 
 X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid,
 void X509V3_conf_free(CONF_VALUE *val);
 
 X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid,
index fe6d69c2c53258918521e6a1dffcd2d93916e4ba..9fc7cfcf184cc68f23aea82fa4537a1fe8af1745 100644 (file)
@@ -5029,3 +5029,4 @@ SRP_Calc_B_ex                           ? 3_0_0   EXIST::FUNCTION:SRP
 SRP_Calc_u_ex                           ?      3_0_0   EXIST::FUNCTION:SRP
 SRP_Calc_x_ex                           ?      3_0_0   EXIST::FUNCTION:SRP
 SRP_Calc_client_key_ex                  ?      3_0_0   EXIST::FUNCTION:SRP
 SRP_Calc_u_ex                           ?      3_0_0   EXIST::FUNCTION:SRP
 SRP_Calc_x_ex                           ?      3_0_0   EXIST::FUNCTION:SRP
 SRP_Calc_client_key_ex                  ?      3_0_0   EXIST::FUNCTION:SRP
+X509v3_cache_extensions                 ?      3_0_0   EXIST::FUNCTION: