[openssl] master update

dev at ddvo.net dev at ddvo.net
Wed Jul 1 09:17:23 UTC 2020


The branch master has been updated
       via  b4cb9498c9c76877a354316ba4246afbea178c83 (commit)
       via  0d8dbb52e3900fdd096ca1765137958340fb8497 (commit)
       via  4cec750c2f08faa7f7cdfcfa02fc4264d3c2ac95 (commit)
       via  0e7b1383e138ce3fa66c5bd0ea4a9cb35487436c (commit)
       via  d18c7ad66aaaebe10c86127d966f5401bc414d2a (commit)
       via  da1f88bf53f1bb03cc9f198cfe71ef6157549eff (commit)
       via  4acd484d55ac3c86091e42f81479f514d0cf8b17 (commit)
       via  023697870bcd4372a142a606546253d719a81024 (commit)
       via  ade08735f9d0ac85d611c5abee8a1df651bbca13 (commit)
      from  5188d0d55c72138dd1b65521fb73ac31902f0a52 (commit)


- Log -----------------------------------------------------------------
commit b4cb9498c9c76877a354316ba4246afbea178c83
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Sat Jun 27 16:16:12 2020 +0200

    X509v3_cache_extensions(): Improve coding style and doc, fix case 'sha1 == NULL'
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10587)

commit 0d8dbb52e3900fdd096ca1765137958340fb8497
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Sat Dec 28 12:33:12 2019 +0100

    Add X509_self_signed(), extending and improving documenation and tests
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10587)

commit 4cec750c2f08faa7f7cdfcfa02fc4264d3c2ac95
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Sat Jun 27 17:37:34 2020 +0200

    Move doc of X509{,_REQ,_CRL}_verify{,_ex}() from X509_sign.pod to new X509_verify.pod
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10587)

commit 0e7b1383e138ce3fa66c5bd0ea4a9cb35487436c
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Tue Dec 24 11:25:15 2019 +0100

    Fix issue 1418 by moving check of KU_KEY_CERT_SIGN and weakening check_issued()
    
    Move check that cert signing is allowed from x509v3_cache_extensions() to
    where it belongs: internal_verify(), generalize it for proxy cert signing.
    Correct and simplify check_issued(), now checking self-issued (not: self-signed).
    Add test case to 25-test_verify.t that demonstrates successful fix
    
    Fixes #1418
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10587)

commit d18c7ad66aaaebe10c86127d966f5401bc414d2a
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Tue Dec 24 10:36:24 2019 +0100

    Optimization and safety precaution in find_issuer() of x509_vfy.c:
    candidate issuer cert cannot be the same as the subject cert 'x'
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10587)

commit da1f88bf53f1bb03cc9f198cfe71ef6157549eff
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Mon Dec 23 20:23:24 2019 +0100

    Add four more verify test cases on the self-signed Ed25519 and self-issed X25519 certs
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10587)

commit 4acd484d55ac3c86091e42f81479f514d0cf8b17
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Mon Dec 23 20:15:49 2019 +0100

    Make x509 -force_pubkey test case with self-issued cert more realistic
    by adding CA basic constraints, CA key usage, and key IDs to the cert
    and by add -partial_chain to the verify call that trusts this cert
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10587)

commit 023697870bcd4372a142a606546253d719a81024
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Mon Dec 23 17:37:17 2019 +0100

    Refactor (without semantic changes) crypto/x509/{v3_purp.c,x509_vfy.c}
    
    This prepares some corrections and improves readability (coding style).
    Among others, it adds the static function check_sig_alg_match() and
    the internal functions x509_likely_issued() and x509_signing_allowed().
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10587)

commit ade08735f9d0ac85d611c5abee8a1df651bbca13
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Mon Dec 23 15:40:47 2019 +0100

    Improve documentation, layout, and code comments regarding self-issued certs etc.
    
    Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10587)

-----------------------------------------------------------------------

Summary of changes:
 apps/verify.c                                    |   2 +-
 apps/x509.c                                      |  10 +-
 crypto/cmp/cmp_util.c                            |   8 +-
 crypto/x509/v3_purp.c                            | 166 ++++++++++++++---------
 crypto/x509/x509_local.h                         |   3 +
 crypto/x509/x509_txt.c                           |   7 +-
 crypto/x509/x509_vfy.c                           | 163 ++++++++++++----------
 doc/internal/man3/ossl_cmp_sk_X509_add1_cert.pod |   8 +-
 doc/man1/openssl-verify.pod.in                   |  10 +-
 doc/man1/openssl.pod                             |  95 +++++++------
 doc/man3/X509_STORE_CTX_get_error.pod            |  71 ++++++----
 doc/man3/X509_STORE_set_verify_cb_func.pod       |   4 +-
 doc/man3/X509_VERIFY_PARAM_set_flags.pod         |  33 ++---
 doc/man3/X509_check_issued.pod                   |  26 ++--
 doc/man3/X509_sign.pod                           |  57 ++------
 doc/man3/X509_verify.pod                         |  90 ++++++++++++
 doc/man3/X509v3_cache_extensions.pod             |   5 +-
 include/openssl/x509.h                           |   1 +
 include/openssl/x509_vfy.h                       |   1 +
 test/certs/ee-self-signed.pem                    |  18 +++
 test/certs/setup.sh                              |   3 +
 test/recipes/25-test_verify.t                    |  21 ++-
 test/recipes/25-test_x509.t                      |   8 +-
 test/recipes/70-test_verify_extra.t              |   1 +
 test/v3_ca_exts.cnf                              |   5 +
 test/verify_extra_test.c                         |  74 ++++++----
 util/libcrypto.num                               |   1 +
 27 files changed, 559 insertions(+), 332 deletions(-)
 create mode 100644 doc/man3/X509_verify.pod
 create mode 100644 test/certs/ee-self-signed.pem
 create mode 100644 test/v3_ca_exts.cnf

diff --git a/apps/verify.c b/apps/verify.c
index eee81799bf..c28f44571a 100644
--- a/apps/verify.c
+++ b/apps/verify.c
@@ -356,7 +356,7 @@ static int cb(int ok, X509_STORE_CTX *ctx)
             policies_print(ctx);
             /* fall thru */
         case X509_V_ERR_CERT_HAS_EXPIRED:
-            /* Continue even if the leaf is a self signed cert */
+            /* Continue even if the leaf is a self-signed cert */
         case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
             /* Continue after extension errors too */
         case X509_V_ERR_INVALID_CA:
diff --git a/apps/x509.c b/apps/x509.c
index ea083abc64..c64c7d2811 100644
--- a/apps/x509.c
+++ b/apps/x509.c
@@ -135,7 +135,7 @@ const OPTIONS x509_options[] = {
     {"setalias", OPT_SETALIAS, 's', "Set certificate alias"},
     {"days", OPT_DAYS, 'n',
      "How long till expiry of a signed certificate - def 30 days"},
-    {"signkey", OPT_SIGNKEY, 's', "Self sign cert with arg"},
+    {"signkey", OPT_SIGNKEY, 's', "Self-sign cert with arg"},
     {"set_serial", OPT_SET_SERIAL, 's', "Serial number to use"},
     {"extensions", OPT_EXTENSIONS, 's', "Section from config file to use"},
     {"certopt", OPT_CERTOPT, 's', "Various certificate text options"},
@@ -1030,7 +1030,7 @@ static int x509_certify(X509_STORE *ctx, const char *CAfile, const EVP_MD *diges
         goto end;
 
     /*
-     * NOTE: this certificate can/should be self signed, unless it was a
+     * NOTE: this certificate can/should be self-signed, unless it was a
      * certificate request in which case it is not.
      */
     X509_STORE_CTX_set_cert(xsc, x);
@@ -1084,8 +1084,8 @@ static int callb(int ok, X509_STORE_CTX *ctx)
     X509 *err_cert;
 
     /*
-     * it is ok to use a self signed certificate This case will catch both
-     * the initial ok == 0 and the final ok == 1 calls to this function
+     * It is ok to use a self-signed certificate. This case will catch both
+     * the initial ok == 0 and the final ok == 1 calls to this function.
      */
     err = X509_STORE_CTX_get_error(ctx);
     if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
@@ -1098,7 +1098,7 @@ static int callb(int ok, X509_STORE_CTX *ctx)
      */
     if (ok) {
         BIO_printf(bio_err,
-                   "error with certificate to be certified - should be self signed\n");
+                   "error with certificate to be certified - should be self-signed\n");
         return 0;
     } else {
         err_cert = X509_STORE_CTX_get_current_cert(ctx);
diff --git a/crypto/cmp/cmp_util.c b/crypto/cmp/cmp_util.c
index 570e14cd24..d1128d7e66 100644
--- a/crypto/cmp/cmp_util.c
+++ b/crypto/cmp/cmp_util.c
@@ -218,7 +218,7 @@ int ossl_cmp_sk_X509_add1_cert(STACK_OF(X509) *sk, X509 *cert,
 }
 
 int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
-                                int no_self_issued, int no_dups, int prepend)
+                                int no_self_signed, int no_dups, int prepend)
 /* compiler would allow 'const' for the list of certs, yet they are up-ref'ed */
 {
     int i;
@@ -230,7 +230,7 @@ int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
     for (i = 0; i < sk_X509_num(certs); i++) { /* certs may be NULL */
         X509 *cert = sk_X509_value(certs, i);
 
-        if (!no_self_issued || X509_check_issued(cert, cert) != X509_V_OK) {
+        if (!no_self_signed || X509_self_signed(cert, 0) != 1) {
             if (!ossl_cmp_sk_X509_add1_cert(sk, cert, no_dups, prepend))
                 return 0;
         }
@@ -239,7 +239,7 @@ int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
 }
 
 int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
-                                   int only_self_issued)
+                                   int only_self_signed)
 {
     int i;
 
@@ -252,7 +252,7 @@ int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
     for (i = 0; i < sk_X509_num(certs); i++) {
         X509 *cert = sk_X509_value(certs, i);
 
-        if (!only_self_issued || X509_check_issued(cert, cert) == X509_V_OK)
+        if (!only_self_signed || X509_self_signed(cert, 0) == 1)
             if (!X509_STORE_add_cert(store, cert)) /* ups cert ref counter */
                 return 0;
     }
diff --git a/crypto/x509/v3_purp.c b/crypto/x509/v3_purp.c
index b3401035f1..0fcf53a5ea 100644
--- a/crypto/x509/v3_purp.c
+++ b/crypto/x509/v3_purp.c
@@ -14,6 +14,7 @@
 #include <openssl/x509_vfy.h>
 #include "crypto/x509.h"
 #include "internal/tsan_assist.h"
+#include "x509_local.h"
 
 DEFINE_STACK_OF(GENERAL_NAME)
 DEFINE_STACK_OF(DIST_POINT)
@@ -346,6 +347,21 @@ static int setup_crldp(X509 *x)
     return 1;
 }
 
+/* Check that issuer public key algorithm matches subject signature algorithm */
+static int check_sig_alg_match(const EVP_PKEY *pkey, const X509 *subject)
+{
+    int pkey_nid;
+
+    if (pkey == NULL)
+        return X509_V_ERR_NO_ISSUER_PUBLIC_KEY;
+    if (OBJ_find_sigid_algs(OBJ_obj2nid(subject->cert_info.signature.algorithm),
+                            NULL, &pkey_nid) == 0)
+        return X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM;
+    if (EVP_PKEY_type(pkey_nid) != EVP_PKEY_base_id(pkey))
+        return X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH;
+    return X509_V_OK;
+}
+
 #define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
 #define ku_reject(x, usage) \
         (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
@@ -354,6 +370,11 @@ static int setup_crldp(X509 *x)
 #define ns_reject(x, usage) \
         (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
 
+/*
+ * Cache info on various X.509v3 extensions and further derived information,
+ * e.g., if cert 'x' is self-issued, in x->ex_flags and other internal fields.
+ * Set EXFLAG_INVALID and return 0 in case the certificate is invalid.
+ */
 int X509v3_cache_extensions(X509 *x, OPENSSL_CTX *libctx, const char *propq)
 {
     BASIC_CONSTRAINTS *bs;
@@ -372,24 +393,28 @@ int X509v3_cache_extensions(X509 *x, OPENSSL_CTX *libctx, const char *propq)
 #endif
 
     CRYPTO_THREAD_write_lock(x->lock);
-    if (x->ex_flags & EXFLAG_SET) {
+    if (x->ex_flags & EXFLAG_SET) { /* cert has already been processed */
         CRYPTO_THREAD_unlock(x->lock);
         return (x->ex_flags & EXFLAG_INVALID) == 0;
     }
 
+    /* Cache the SHA1 digest of the cert */
     sha1 = EVP_MD_fetch(libctx, "SHA1", propq);
-    if (sha1 == NULL || !X509_digest(x, sha1, x->sha1_hash, NULL))
+    if (sha1 != NULL) {
+        if (!X509_digest(x, sha1, x->sha1_hash, NULL))
             x->ex_flags |= EXFLAG_INVALID;
-    EVP_MD_free(sha1);
+        EVP_MD_free(sha1);
+    }
 
     /* V1 should mean no extensions ... */
-    if (!X509_get_version(x))
+    if (X509_get_version(x) == 0)
         x->ex_flags |= EXFLAG_V1;
+
     /* Handle basic constraints */
-    if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, &i, NULL))) {
+    if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, &i, NULL)) != NULL) {
         if (bs->ca)
             x->ex_flags |= EXFLAG_CA;
-        if (bs->pathlen) {
+        if (bs->pathlen != NULL) {
             if (bs->pathlen->type == V_ASN1_NEG_INTEGER) {
                 x->ex_flags |= EXFLAG_INVALID;
                 x->ex_pathlen = 0;
@@ -400,15 +425,17 @@ int X509v3_cache_extensions(X509 *x, OPENSSL_CTX *libctx, const char *propq)
                     x->ex_pathlen = 0;
                 }
             }
-        } else
+        } else {
             x->ex_pathlen = -1;
+        }
         BASIC_CONSTRAINTS_free(bs);
         x->ex_flags |= EXFLAG_BCONS;
     } else if (i != -1) {
         x->ex_flags |= EXFLAG_INVALID;
     }
+
     /* Handle proxy certificates */
-    if ((pci = X509_get_ext_d2i(x, NID_proxyCertInfo, &i, NULL))) {
+    if ((pci = X509_get_ext_d2i(x, NID_proxyCertInfo, &i, NULL)) != NULL) {
         if (x->ex_flags & EXFLAG_CA
             || X509_get_ext_by_NID(x, NID_subject_alt_name, -1) >= 0
             || X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) {
@@ -423,60 +450,55 @@ int X509v3_cache_extensions(X509 *x, OPENSSL_CTX *libctx, const char *propq)
     } else if (i != -1) {
         x->ex_flags |= EXFLAG_INVALID;
     }
-    /* Handle key usage */
-    if ((usage = X509_get_ext_d2i(x, NID_key_usage, &i, NULL))) {
+
+    /* Handle (basic and extended) key usage */
+    if ((usage = X509_get_ext_d2i(x, NID_key_usage, &i, NULL)) != NULL) {
+        x->ex_kusage = 0;
         if (usage->length > 0) {
             x->ex_kusage = usage->data[0];
             if (usage->length > 1)
                 x->ex_kusage |= usage->data[1] << 8;
-        } else
-            x->ex_kusage = 0;
+        }
         x->ex_flags |= EXFLAG_KUSAGE;
         ASN1_BIT_STRING_free(usage);
     } else if (i != -1) {
         x->ex_flags |= EXFLAG_INVALID;
     }
     x->ex_xkusage = 0;
-    if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, &i, NULL))) {
+    if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, &i, NULL)) != NULL) {
         x->ex_flags |= EXFLAG_XKUSAGE;
         for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
             switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) {
             case NID_server_auth:
                 x->ex_xkusage |= XKU_SSL_SERVER;
                 break;
-
             case NID_client_auth:
                 x->ex_xkusage |= XKU_SSL_CLIENT;
                 break;
-
             case NID_email_protect:
                 x->ex_xkusage |= XKU_SMIME;
                 break;
-
             case NID_code_sign:
                 x->ex_xkusage |= XKU_CODE_SIGN;
                 break;
-
             case NID_ms_sgc:
             case NID_ns_sgc:
                 x->ex_xkusage |= XKU_SGC;
                 break;
-
             case NID_OCSP_sign:
                 x->ex_xkusage |= XKU_OCSP_SIGN;
                 break;
-
             case NID_time_stamp:
                 x->ex_xkusage |= XKU_TIMESTAMP;
                 break;
-
             case NID_dvcs:
                 x->ex_xkusage |= XKU_DVCS;
                 break;
-
             case NID_anyExtendedKeyUsage:
                 x->ex_xkusage |= XKU_ANYEKU;
                 break;
+            default:
+                break;
             }
         }
         sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
@@ -484,7 +506,8 @@ int X509v3_cache_extensions(X509 *x, OPENSSL_CTX *libctx, const char *propq)
         x->ex_flags |= EXFLAG_INVALID;
     }
 
-    if ((ns = X509_get_ext_d2i(x, NID_netscape_cert_type, &i, NULL))) {
+    /* Handle legacy Netscape extension */
+    if ((ns = X509_get_ext_d2i(x, NID_netscape_cert_type, &i, NULL)) != NULL) {
         if (ns->length > 0)
             x->ex_nscert = ns->data[0];
         else
@@ -494,20 +517,25 @@ int X509v3_cache_extensions(X509 *x, OPENSSL_CTX *libctx, const char *propq)
     } else if (i != -1) {
         x->ex_flags |= EXFLAG_INVALID;
     }
+
+    /* Handle subject key identifier and issuer/authority key identifier */
     x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, &i, NULL);
     if (x->skid == NULL && i != -1)
         x->ex_flags |= EXFLAG_INVALID;
     x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, &i, NULL);
     if (x->akid == NULL && i != -1)
         x->ex_flags |= EXFLAG_INVALID;
-    /* Does subject name match issuer ? */
-    if (!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) {
-        x->ex_flags |= EXFLAG_SI;
-        /* If SKID matches AKID also indicate self signed */
-        if (X509_check_akid(x, x->akid) == X509_V_OK &&
-            !ku_reject(x, KU_KEY_CERT_SIGN))
-            x->ex_flags |= EXFLAG_SS;
+
+    /* Check if subject name matches issuer */
+    if (X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)) == 0) {
+        x->ex_flags |= EXFLAG_SI; /* cert is self-issued */
+        if (X509_check_akid(x, x->akid) == X509_V_OK /* SKID matches AKID */
+                /* .. and the signature alg matches the PUBKEY alg: */
+                && check_sig_alg_match(X509_get0_pubkey(x), x) == X509_V_OK)
+            x->ex_flags |= EXFLAG_SS; /* indicate self-signed */
     }
+
+    /* Handle subject alternative names and various other extensions */
     x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, &i, NULL);
     if (x->altname == NULL && i != -1)
         x->ex_flags |= EXFLAG_INVALID;
@@ -537,8 +565,10 @@ int X509v3_cache_extensions(X509 *x, OPENSSL_CTX *libctx, const char *propq)
             break;
         }
     }
+
     x509_init_sig_info(x);
-    x->ex_flags |= EXFLAG_SET;
+
+    x->ex_flags |= EXFLAG_SET; /* indicate that cert has been processed */
 #ifdef tsan_st_rel
     tsan_st_rel((TSAN_QUALIFIER int *)&x->ex_cached, 1);
     /*
@@ -559,7 +589,7 @@ int X509v3_cache_extensions(X509 *x, OPENSSL_CTX *libctx, const char *propq)
  * 1 is a CA
  * 2 Only possible in older versions of openSSL when basicConstraints are absent
  *   new versions will not return this value. May be a CA
- * 3 basicConstraints absent but self signed V1.
+ * 3 basicConstraints absent but self-signed V1.
  * 4 basicConstraints absent but keyUsage present and keyCertSign asserted.
  * 5 Netscape specific CA Flags present
  */
@@ -803,54 +833,59 @@ static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca)
 }
 
 /*-
- * Various checks to see if one certificate issued the second.
- * This can be used to prune a set of possible issuer certificates
- * which have been looked up using some simple method such as by
- * subject name.
+ * Various checks to see if one certificate potentially issued the second.
+ * This can be used to prune a set of possible issuer certificates which
+ * have been looked up using some simple method such as by subject name.
  * These are:
  * 1. Check issuer_name(subject) == subject_name(issuer)
  * 2. If akid(subject) exists, check that it matches issuer
  * 3. Check that issuer public key algorithm matches subject signature algorithm
- * 4. If key_usage(issuer) exists, check that it supports certificate signing
- * returns 0 for OK, positive for reason for mismatch, reasons match
- * codes for X509_verify_cert()
+ * 4. Check that any key_usage(issuer) allows certificate signing
+ * Note that this does not include actually checking the signature.
+ * Returns 0 for OK, or positive for reason for mismatch
+ * where reason codes match those for X509_verify_cert().
  */
+int x509_check_issued_int(X509 *issuer, X509 *subject,
+                          OPENSSL_CTX *libctx, const char *propq)
+{
+    int ret;
+
+    if ((ret = x509_likely_issued(issuer, subject, libctx, propq)) != X509_V_OK)
+        return ret;
+    return x509_signing_allowed(issuer, subject);
+}
 
-int x509_check_issued_int(X509 *issuer, X509 *subject, OPENSSL_CTX *libctx,
-                          const char *propq)
+/* do the checks 1., 2., and 3. as described above for X509_check_issued() */
+int x509_likely_issued(X509 *issuer, X509 *subject,
+                       OPENSSL_CTX *libctx, const char *propq)
 {
+    int ret;
+
     if (X509_NAME_cmp(X509_get_subject_name(issuer),
-                      X509_get_issuer_name(subject)))
+                      X509_get_issuer_name(subject)) != 0)
         return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
 
     if (!X509v3_cache_extensions(issuer, libctx, propq)
             || !X509v3_cache_extensions(subject, libctx, propq))
         return X509_V_ERR_UNSPECIFIED;
 
-    if (subject->akid) {
-        int ret = X509_check_akid(issuer, subject->akid);
-        if (ret != X509_V_OK)
-            return ret;
-    }
-
-    {
-        /*
-         * Check if the subject signature algorithm matches the issuer's PUBKEY
-         * algorithm
-         */
-        EVP_PKEY *i_pkey = X509_get0_pubkey(issuer);
-        X509_ALGOR *s_algor = &subject->cert_info.signature;
-        int s_pknid = NID_undef, s_mdnid = NID_undef;
-
-        if (i_pkey == NULL)
-            return X509_V_ERR_NO_ISSUER_PUBLIC_KEY;
+    ret = X509_check_akid(issuer, subject->akid);
+    if (ret != X509_V_OK)
+        return ret;
 
-        if (!OBJ_find_sigid_algs(OBJ_obj2nid(s_algor->algorithm),
-                                 &s_mdnid, &s_pknid)
-            || EVP_PKEY_type(s_pknid) != EVP_PKEY_base_id(i_pkey))
-            return X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH;
-    }
+    /* check if the subject signature alg matches the issuer's PUBKEY alg */
+    return check_sig_alg_match(X509_get0_pubkey(issuer), subject);
+}
 
+/*-
+ * Check if certificate I<issuer> is allowed to issue certificate I<subject>
+ * according to the B<keyUsage> field of I<issuer> if present
+ * depending on any proxyCertInfo extension of I<subject>.
+ * Returns 0 for OK, or positive for reason for rejection
+ * where reason codes match those for X509_verify_cert().
+ */
+int x509_signing_allowed(const X509 *issuer, const X509 *subject)
+{
     if (subject->ex_flags & EXFLAG_PROXY) {
         if (ku_reject(issuer, KU_DIGITAL_SIGNATURE))
             return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
@@ -866,8 +901,7 @@ int X509_check_issued(X509 *issuer, X509 *subject)
 
 int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid)
 {
-
-    if (!akid)
+    if (akid == NULL)
         return X509_V_OK;
 
     /* Check key ids (if present) */
@@ -897,7 +931,7 @@ int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid)
                 break;
             }
         }
-        if (nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
+        if (nm != NULL && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)) != 0)
             return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
     }
     return X509_V_OK;
diff --git a/crypto/x509/x509_local.h b/crypto/x509/x509_local.h
index e174ae7611..a1fe4203b9 100644
--- a/crypto/x509/x509_local.h
+++ b/crypto/x509/x509_local.h
@@ -149,3 +149,6 @@ DEFINE_STACK_OF(STACK_OF_X509_NAME_ENTRY)
 
 void x509_set_signature_info(X509_SIG_INFO *siginf, const X509_ALGOR *alg,
                              const ASN1_STRING *sig);
+int x509_likely_issued(X509 *issuer, X509 *subject,
+                       OPENSSL_CTX *libctx, const char *propq);
+int x509_signing_allowed(const X509 *issuer, const X509 *subject);
diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c
index 4897c4d5dd..63d8d95f3f 100644
--- a/crypto/x509/x509_txt.c
+++ b/crypto/x509/x509_txt.c
@@ -58,9 +58,9 @@ const char *X509_verify_cert_error_string(long n)
     case X509_V_ERR_OUT_OF_MEM:
         return "out of memory";
     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
-        return "self signed certificate";
+        return "self-signed certificate";
     case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
-        return "self signed certificate in certificate chain";
+        return "self-signed certificate in certificate chain";
     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
         return "unable to get local issuer certificate";
     case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
@@ -178,6 +178,9 @@ const char *X509_verify_cert_error_string(long n)
         return "subject signature algorithm and issuer public key algorithm mismatch";
     case X509_V_ERR_NO_ISSUER_PUBLIC_KEY:
         return "issuer certificate doesn't have a public key";
+    case X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM:
+        return "Cannot find certificate signature algorithm";
+
     default:
         /* Printing an error number into a static buffer is not thread-safe */
         return "unknown certificate verification error";
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 1e881ccfcd..1f17c71bc1 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -111,20 +111,43 @@ static int null_callback(int ok, X509_STORE_CTX *e)
     return ok;
 }
 
-/* Return 1 is a certificate is self signed, 0 if not, or -1 on error */
-static int cert_self_signed(X509_STORE_CTX *ctx, X509 *x)
+/*-
+ * Return 1 if given cert is considered self-signed, 0 if not, or -1 on error.
+ * This actually verifies self-signedness only if requested.
+ * It calls X509v3_cache_extensions()
+ * to match issuer and subject names (i.e., the cert being self-issued) and any
+ * present authority key identifier to match the subject key identifier, etc.
+ */
+static int x509_self_signed_ex(X509 *cert, int verify_signature,
+                               OPENSSL_CTX *libctx, const char *propq)
 {
-    if (!X509v3_cache_extensions(x, ctx->libctx, ctx->propq))
-        return -1;
+    EVP_PKEY *pkey;
 
-    if (x->ex_flags & EXFLAG_SS)
-        return 1;
-    else
+    if ((pkey = X509_get0_pubkey(cert)) == NULL) { /* handles cert == NULL */
+        X509err(0, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY);
+        return -1;
+    }
+    if (!X509v3_cache_extensions(cert, libctx, propq))
+        return -1;
+    if ((cert->ex_flags & EXFLAG_SS) == 0)
         return 0;
+    if (!verify_signature)
+        return 1;
+    return X509_verify_ex(cert, pkey, libctx, propq);
 }
 
-/* Given a certificate try and find an exact match in the store */
+/* wrapper for internal use */
+static int cert_self_signed(X509_STORE_CTX *ctx, X509 *x, int verify_signature)
+{
+    return x509_self_signed_ex(x, verify_signature, ctx->libctx, ctx->propq);
+}
+
+int X509_self_signed(X509 *cert, int verify_signature)
+{
+    return x509_self_signed_ex(cert, verify_signature, NULL, NULL);
+}
 
+/* Given a certificate try and find an exact match in the store */
 static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x)
 {
     STACK_OF(X509) *certs;
@@ -324,7 +347,11 @@ static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x)
 
     for (i = 0; i < sk_X509_num(sk); i++) {
         issuer = sk_X509_value(sk, i);
-        if (ctx->check_issued(ctx, x, issuer)) {
+        /*
+         * Below check 'issuer != x' is an optimization and safety precaution:
+         * Candidate issuer cert cannot be the same as the subject cert 'x'.
+         */
+        if (issuer != x && ctx->check_issued(ctx, x, issuer)) {
             rv = issuer;
             if (x509_check_cert_time(ctx, rv, -1))
                 break;
@@ -333,46 +360,29 @@ static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x)
     return rv;
 }
 
-/* Given a possible certificate and issuer check them */
-
+/*
+ * Check that the given certificate 'x' is issued by the certificate 'issuer'
+ * and the issuer is not yet in ctx->chain, where the exceptional case
+ * that 'x' is self-issued and ctx->chain has just one element is allowed.
+ */
 static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer)
 {
-    int ret;
-    int ss;
-
-    if (x == issuer) {
-        ss = cert_self_signed(ctx, x);
-        if (ss < 0)
-            return 0;
-        return ss;
-    }
-
-    ret = x509_check_issued_int(issuer, x, ctx->libctx, ctx->propq);
-    if (ret == X509_V_OK) {
+    if (x509_likely_issued(issuer, x, ctx->libctx, ctx->propq) != X509_V_OK)
+        return 0;
+    if ((x->ex_flags & EXFLAG_SI) == 0 || sk_X509_num(ctx->chain) != 1) {
         int i;
         X509 *ch;
 
-        ss = cert_self_signed(ctx, x);
-        if (ss < 0)
-            return 0;
-
-        /* Special case: single self signed certificate */
-        if (ss > 0 && sk_X509_num(ctx->chain) == 1)
-            return 1;
         for (i = 0; i < sk_X509_num(ctx->chain); i++) {
             ch = sk_X509_value(ctx->chain, i);
-            if (ch == issuer || !X509_cmp(ch, issuer)) {
-                ret = X509_V_ERR_PATH_LOOP;
-                break;
-            }
+            if (ch == issuer || X509_cmp(ch, issuer) == 0)
+                return 0;
         }
     }
-
-    return (ret == X509_V_OK);
+    return 1;
 }
 
 /* Alternative lookup method: look from a STACK stored in other_ctx */
-
 static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
 {
     *issuer = find_issuer(ctx, ctx->other_ctx, x);
@@ -562,7 +572,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
             if (!verify_cb_cert(ctx, x, i, X509_V_ERR_PATH_LENGTH_EXCEEDED))
                 return 0;
         }
-        /* Increment path length if not a self issued intermediate CA */
+        /* Increment path length if not a self-issued intermediate CA */
         if (i > 0 && (x->ex_flags & EXFLAG_SI) == 0)
             plen++;
         /*
@@ -628,7 +638,7 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
         X509 *x = sk_X509_value(ctx->chain, i);
         int j;
 
-        /* Ignore self issued certs unless last in chain */
+        /* Ignore self-issued certs unless last in chain */
         if (i && (x->ex_flags & EXFLAG_SI))
             continue;
 
@@ -1527,7 +1537,7 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
     int cnum = ctx->error_depth;
     int chnum = sk_X509_num(ctx->chain) - 1;
 
-    /* if we have an alternative CRL issuer cert use that */
+    /* If we have an alternative CRL issuer cert use that */
     if (ctx->current_issuer)
         issuer = ctx->current_issuer;
     /*
@@ -1538,7 +1548,7 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
         issuer = sk_X509_value(ctx->chain, cnum + 1);
     else {
         issuer = sk_X509_value(ctx->chain, chnum);
-        /* If not self signed, can't check signature */
+        /* If not self-issued, can't check signature */
         if (!ctx->check_issued(ctx, issuer, issuer) &&
             !verify_cb_crl(ctx, X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER))
             return 0;
@@ -1753,7 +1763,7 @@ static int internal_verify(X509_STORE_CTX *ctx)
         goto check_cert;
     }
 
-    if (ctx->check_issued(ctx, xi, xi))
+    if (ctx->check_issued(ctx, xi, xi)) /* the last cert appears self-signed */
         xs = xi;
     else {
         if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) {
@@ -1773,18 +1783,23 @@ static int internal_verify(X509_STORE_CTX *ctx)
      * is allowed to reset errors (at its own peril).
      */
     while (n >= 0) {
-        EVP_PKEY *pkey;
-
         /*
-         * Skip signature check for self signed certificates unless explicitly
-         * asked for.  It doesn't add any security and just wastes time.  If
-         * the issuer's public key is unusable, report the issuer certificate
+         * Skip signature check for self-signed certificates unless explicitly
+         * asked for because it does not add any security and just wastes time.
+         * If the issuer's public key is not available or its key usage does
+         * not support issuing the subject cert, report the issuer certificate
          * and its depth (rather than the depth of the subject).
          */
         if (xs != xi || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE)) {
+            EVP_PKEY *pkey;
+            int issuer_depth = n + (xi == xs ? 0 : 1);
+            int ret = x509_signing_allowed(xi, xs);
+
+            if (ret != X509_V_OK && !verify_cb_cert(ctx, xi, issuer_depth, ret))
+                return 0;
             if ((pkey = X509_get0_pubkey(xi)) == NULL) {
-                if (!verify_cb_cert(ctx, xi, xi != xs ? n+1 : n,
-                        X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY))
+                if (!verify_cb_cert(ctx, xi, issuer_depth,
+                                    X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY))
                     return 0;
             } else if (X509_verify_ex(xs, pkey, ctx->libctx, ctx->propq) <= 0) {
                 if (!verify_cb_cert(ctx, xs, n,
@@ -2803,7 +2818,7 @@ static int check_dane_issuer(X509_STORE_CTX *ctx, int depth)
         return  X509_TRUST_UNTRUSTED;
 
     /*
-     * Record any DANE trust-anchor matches, for the first depth to test, if
+     * Record any DANE trust anchor matches, for the first depth to test, if
      * there's one at that depth. (This'll be false for length 1 chains looking
      * for an exact match for the leaf certificate).
      */
@@ -2889,7 +2904,7 @@ static int dane_verify(X509_STORE_CTX *ctx)
      * When testing the leaf certificate, if we match a DANE-EE(3) record,
      * dane_match() returns 1 and we're done.  If however we match a PKIX-EE(1)
      * record, the match depth and matching TLSA record are recorded, but the
-     * return value is 0, because we still need to find a PKIX trust-anchor.
+     * return value is 0, because we still need to find a PKIX trust anchor.
      * Therefore, when DANE authentication is enabled (required), we're done
      * if:
      *   + matched < 0, internal error.
@@ -2956,7 +2971,7 @@ static int build_chain(X509_STORE_CTX *ctx)
     SSL_DANE *dane = ctx->dane;
     int num = sk_X509_num(ctx->chain);
     X509 *cert = sk_X509_value(ctx->chain, num - 1);
-    int ss;
+    int self_signed;
     STACK_OF(X509) *sktmp = NULL;
     unsigned int search;
     int may_trusted = 0;
@@ -2974,9 +2989,8 @@ static int build_chain(X509_STORE_CTX *ctx)
         return 0;
     }
 
-    ss = cert_self_signed(ctx, cert);
-    if (ss < 0) {
-        X509err(X509_F_BUILD_CHAIN, ERR_R_INTERNAL_ERROR);
+    self_signed = cert_self_signed(ctx, cert, 0);
+    if (self_signed < 0) {
         ctx->error = X509_V_ERR_UNSPECIFIED;
         return 0;
     }
@@ -3012,7 +3026,7 @@ static int build_chain(X509_STORE_CTX *ctx)
     }
 
     /*
-     * If we got any "DANE-TA(2) Cert(0) Full(0)" trust-anchors from DNS, add
+     * If we got any "DANE-TA(2) Cert(0) Full(0)" trust anchors from DNS, add
      * them to our working copy of the untrusted certificate stack.  Since the
      * caller of X509_STORE_CTX_init() may have provided only a leaf cert with
      * no corresponding stack of untrusted certificates, we may need to create
@@ -3045,7 +3059,7 @@ static int build_chain(X509_STORE_CTX *ctx)
         ctx->param->depth = INT_MAX/2;
 
     /*
-     * Try to Extend the chain until we reach an ultimately trusted issuer.
+     * Try to extend the chain until we reach an ultimately trusted issuer.
      * Build chains up to one longer the limit, later fail if we hit the limit,
      * with an X509_V_ERR_CERT_CHAIN_TOO_LONG error code.
      */
@@ -3059,7 +3073,7 @@ static int build_chain(X509_STORE_CTX *ctx)
          * Look in the trust store if enabled for first lookup, or we've run
          * out of untrusted issuers and search here is not disabled.  When we
          * reach the depth limit, we stop extending the chain, if by that point
-         * we've not found a trust-anchor, any trusted chain would be too long.
+         * we've not found a trust anchor, any trusted chain would be too long.
          *
          * The error reported to the application verify callback is at the
          * maximal valid depth with the current certificate equal to the last
@@ -3105,8 +3119,8 @@ static int build_chain(X509_STORE_CTX *ctx)
                  * Alternative trusted issuer for a mid-chain untrusted cert?
                  * Pop the untrusted cert's successors and retry.  We might now
                  * be able to complete a valid chain via the trust store.  Note
-                 * that despite the current trust-store match we might still
-                 * fail complete the chain to a suitable trust-anchor, in which
+                 * that despite the current trust store match we might still
+                 * fail complete the chain to a suitable trust anchor, in which
                  * case we may prune some more untrusted certificates and try
                  * again.  Thus the S_DOALTERNATE bit may yet be turned on
                  * again with an even shorter untrusted chain!
@@ -3116,7 +3130,7 @@ static int build_chain(X509_STORE_CTX *ctx)
                  * certificate among the ones from the trust store.
                  */
                 if ((search & S_DOALTERNATE) != 0) {
-                    if (!ossl_assert(num > i && i > 0 && ss == 0)) {
+                    if (!ossl_assert(num > i && i > 0 && !self_signed)) {
                         X509err(X509_F_BUILD_CHAIN, ERR_R_INTERNAL_ERROR);
                         X509_free(xtmp);
                         trust = X509_TRUST_REJECTED;
@@ -3144,7 +3158,7 @@ static int build_chain(X509_STORE_CTX *ctx)
                  * Self-signed untrusted certificates get replaced by their
                  * trusted matching issuer.  Otherwise, grow the chain.
                  */
-                if (ss == 0) {
+                if (!self_signed) {
                     if (!sk_X509_push(ctx->chain, x = xtmp)) {
                         X509_free(xtmp);
                         X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE);
@@ -3153,9 +3167,8 @@ static int build_chain(X509_STORE_CTX *ctx)
                         search = 0;
                         continue;
                     }
-                    ss = cert_self_signed(ctx, x);
-                    if (ss < 0) {
-                        X509err(X509_F_BUILD_CHAIN, ERR_R_INTERNAL_ERROR);
+                    self_signed = cert_self_signed(ctx, x, 0);
+                    if (self_signed < 0) {
                         ctx->error = X509_V_ERR_UNSPECIFIED;
                         return 0;
                     }
@@ -3163,7 +3176,7 @@ static int build_chain(X509_STORE_CTX *ctx)
                     /*
                      * We have a self-signed certificate that has the same
                      * subject name (and perhaps keyid and/or serial number) as
-                     * a trust-anchor.  We must have an exact match to avoid
+                     * a trust anchor.  We must have an exact match to avoid
                      * possible impersonation via key substitution etc.
                      */
                     if (X509_cmp(x, xtmp) != 0) {
@@ -3205,7 +3218,7 @@ static int build_chain(X509_STORE_CTX *ctx)
                         search = 0;
                         continue;
                     }
-                    if (ss == 0)
+                    if (!self_signed)
                         continue;
                 }
             }
@@ -3227,7 +3240,7 @@ static int build_chain(X509_STORE_CTX *ctx)
                 /* Search for a trusted issuer of a shorter chain */
                 search |= S_DOALTERNATE;
                 alt_untrusted = ctx->num_untrusted - 1;
-                ss = 0;
+                self_signed = 0;
             }
         }
 
@@ -3249,7 +3262,8 @@ static int build_chain(X509_STORE_CTX *ctx)
              * Once we run out of untrusted issuers, we stop looking for more
              * and start looking only in the trust store if enabled.
              */
-            xtmp = (ss || depth < num) ? NULL : find_issuer(ctx, sktmp, x);
+            xtmp = (self_signed || depth < num) ? NULL
+                                                : find_issuer(ctx, sktmp, x);
             if (xtmp == NULL) {
                 search &= ~S_DOUNTRUSTED;
                 if (may_trusted)
@@ -3279,11 +3293,10 @@ static int build_chain(X509_STORE_CTX *ctx)
 
             x = xtmp;
             ++ctx->num_untrusted;
-            ss = cert_self_signed(ctx, xtmp);
-            if (ss < 0) {
-                X509err(X509_F_BUILD_CHAIN, ERR_R_INTERNAL_ERROR);
-                ctx->error = X509_V_ERR_UNSPECIFIED;
+            self_signed = cert_self_signed(ctx, xtmp, 0);
+            if (self_signed < 0) {
                 sk_X509_free(sktmp);
+                ctx->error = X509_V_ERR_UNSPECIFIED;
                 return 0;
             }
 
@@ -3327,10 +3340,10 @@ static int build_chain(X509_STORE_CTX *ctx)
         if (DANETLS_ENABLED(dane) &&
             (!DANETLS_HAS_PKIX(dane) || dane->pdpth >= 0))
             return verify_cb_cert(ctx, NULL, num-1, X509_V_ERR_DANE_NO_MATCH);
-        if (ss && sk_X509_num(ctx->chain) == 1)
+        if (self_signed && sk_X509_num(ctx->chain) == 1)
             return verify_cb_cert(ctx, NULL, num-1,
                                   X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
-        if (ss)
+        if (self_signed)
             return verify_cb_cert(ctx, NULL, num-1,
                                   X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
         if (ctx->num_untrusted < num)
diff --git a/doc/internal/man3/ossl_cmp_sk_X509_add1_cert.pod b/doc/internal/man3/ossl_cmp_sk_X509_add1_cert.pod
index d8f617f55c..289428878e 100644
--- a/doc/internal/man3/ossl_cmp_sk_X509_add1_cert.pod
+++ b/doc/internal/man3/ossl_cmp_sk_X509_add1_cert.pod
@@ -15,9 +15,9 @@ ossl_cmp_X509_STORE_get1_certs
   int ossl_cmp_sk_X509_add1_cert(STACK_OF(X509) *sk, X509 *cert,
                                  int no_dup, int prepend);
   int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
-                                  int no_self_issued, int no_dups, int prepend);
+                                  int no_self_signed, int no_dups, int prepend);
   int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
-                                     int only_self_issued);
+                                     int only_self_signed);
   STACK_OF(X509) *ossl_cmp_X509_STORE_get1_certs(X509_STORE *store);
 
 =head1 DESCRIPTION
@@ -29,10 +29,10 @@ On success the reference count of the certificate is increased.
 
 ossl_cmp_sk_X509_add1_certs() appends or prepends (depending on the I<prepend>
 argument) a list of certificates to the given list,
-optionally only if not self-issued and optionally only if not already contained.
+optionally only if not self-signed and optionally only if not already contained.
 The reference counts of those certificates appended successfully are increased.
 
-ossl_cmp_X509_STORE_add1_certs() adds all or only self-issued certificates from
+ossl_cmp_X509_STORE_add1_certs() adds all or only self-signed certificates from
 the given stack to given store. The I<certs> parameter may be NULL.
 
 ossl_cmp_X509_STORE_get1_certs() retrieves a copy of all certificates in the
diff --git a/doc/man1/openssl-verify.pod.in b/doc/man1/openssl-verify.pod.in
index 7271efe833..bccaa2642f 100644
--- a/doc/man1/openssl-verify.pod.in
+++ b/doc/man1/openssl-verify.pod.in
@@ -97,9 +97,9 @@ with a B<->.
 
 =item I<certificate> ...
 
-One or more certificates to verify. If no certificates are given,
+One or more target certificates to verify. If no certificates are given,
 this command will attempt to read a certificate from standard input.
-If a certificate chain has multiple problems, this program tries to
+If a certificate chain has multiple problems, this program attempts to
 display all of them.
 
 =back
@@ -115,9 +115,9 @@ general form of the error message is:
 The first line contains the name of the certificate being verified followed by
 the subject name of the certificate. The second line contains the error number
 and the depth. The depth is number of the certificate being verified when a
-problem was detected starting with zero for the certificate being verified itself
-then 1 for the CA that signed the certificate and so on. Finally a text version
-of the error number is presented.
+problem was detected starting with zero for the target ("leaf") certificate
+itself then 1 for the CA that signed the target certificate and so on.
+Finally a textual version of the error number is presented.
 
 A list of the error codes and messages can be found in
 L<X509_STORE_CTX_get_error(3)>; the full list is defined in the header file
diff --git a/doc/man1/openssl.pod b/doc/man1/openssl.pod
index c9e75eb526..dee181d264 100644
--- a/doc/man1/openssl.pod
+++ b/doc/man1/openssl.pod
@@ -829,45 +829,54 @@ command handles errors are documented on the specific command page.
 Verification is a complicated process, consisting of a number of separate
 steps that are detailed in the following paragraphs.
 
-First, a certificate chain is built up starting from the supplied certificate
-and ending in a root CA.  It is an error if the whole chain cannot be
-built up.  The chain is built up by looking up the certificate that
-signed (or issued) the certificate. It then repeats the process, until
-it gets to a certificate that is self-issued.
+First, a certificate chain is built up starting from the target certificate
+and typically ending in a self-signed "root" CA certificate.
+It is an error if the whole chain cannot be built up
+unless the B<-partial_chain> option is given.
+The chain is built up iteratively, looking up in turn
+the certificate of the signer ("issuer") of the current certificate.
+If a certificate is found that appears to be its own issuer
+it is assumed to be the self-signed root, which must be trusted.
 
 The process of looking up the issuer's certificate itself involves a number
-of steps.  After all certificates whose subject name matches the issuer
-name of the current certificate are subject to further tests.  The relevant
-authority key identifier components of the current certificate (if present)
-must match the subject key identifier (if present) and issuer and serial
-number of the candidate issuer, in addition the keyUsage extension of the
-candidate issuer (if present) must permit certificate signing.
-
-The lookup first looks in the list of untrusted certificates and if no match
-is found the remaining lookups are from the trusted certificates. The root CA
-is always looked up in the trusted certificate list: if the certificate to
-verify is a root certificate then an exact match must be found in the trusted
-list.
-
-The second step is to check every untrusted certificate's extensions
-for consistency with the supplied purpose. If the B<-purpose> option is
-not included then no checks are done. The supplied or "leaf" certificate
-must have extensions compatible with the supplied purpose and all other
-certificates must also be valid CA certificates. The precise extensions
-required are described in more detail in
+of steps.
+All available certificates with a subject name that matches the issuer
+name of the current certificate are subject to further tests.
+The relevant authority key identifier components of the current certificate
+(if present) must match the subject key identifier (if present)
+and issuer and serial number of the candidate issuer certificate.
+
+The lookup first searches for issuer certificates in the trust store.
+If it does not find a match there it consults
+the list of untrusted "intermediate" CA certificates (if provided).
+The last certificate (which typically is of a root CA) is always looked up
+in the trusted certificate list; an exact match must be found there.
+
+The second step is to check the extensions of every untrusted certificate
+for consistency with the supplied purpose.
+If the B<-purpose> option is not included then no checks are done.
+The target or "leaf" certificate must have extensions compatible with the
+supplied purpose and all other certificates must also be valid CA certificates.
+The precise extensions required are described in more detail in
 L<openssl-x509(1)/CERTIFICATE EXTENSIONS>.
 
-The third step is to check the trust settings on the root CA. The root
-CA should be trusted for the supplied purpose.  For compatibility with
-previous versions of OpenSSL, a certificate with no trust settings is
-considered to be valid for all purposes.
-
-The fourth, and final, step is to check the validity of the certificate
-chain. The validity period is checked against the system time
-and the C<notBefore> and C<notAfter> dates in the certificate. The certificate
-signatures are also checked at this point. The B<-attime> flag may be
-used to specify a time other than "now."
-
+The third step is to check the trust settings on the last certficate,
+typically of a root CA.
+It should be trusted for the supplied purpose.
+For compatibility with previous versions of OpenSSL,
+a certificate with no trust settings is considered to be valid for all purposes.
+
+The fourth, and final, step is to check the validity of the certificate chain.
+The validity period is checked against the system time
+and the C<notBefore> and C<notAfter> dates in each certificate.
+The B<-attime> flag may be used to specify a time other than "now."
+The certificate signatures are also checked at this point
+(except for the signature of the self-signed "root CA" certificate,
+which is verified only if the B<-check_ss_sig> option is given).
+When verifying a certificate signature
+the keyUsage extension (if present) of the candidate issuer certificate
+is checked to permit digitalSignature for signing proxy certificates
+or to permit keyCertSign for signing other certificates, respectively.
 If all operations complete successfully then certificate is considered
 valid. If any operation fails then the certificate is not valid.
 
@@ -898,7 +907,7 @@ This disables non-compliant workarounds for broken certificates.
 
 =item B<-ignore_critical>
 
-Normally if an unhandled critical extension is present which is not
+Normally if an unhandled critical extension is present that is not
 supported by OpenSSL the certificate is rejected (as required by RFC5280).
 If this option is set critical extensions are ignored.
 
@@ -954,11 +963,14 @@ keys shorter than 1024 bits.
 Allow verification to succeed even if a I<complete> chain cannot be built to a
 self-signed trust-anchor, provided it is possible to construct a chain to a
 trusted certificate that might not be self-signed.
+This certificate may be self-issued or belong to an intermediate CA.
 
 =item B<-check_ss_sig>
 
-Verify the signature on the self-signed root CA. This is disabled by default
-because it doesn't add any security.
+Verify the signature on the last certificate in a chain
+even when it is a self-signed (root CA) certificate.
+By default in this case the check is disabled
+because it does not add any security.
 
 =item B<-allow_proxy_certs>
 
@@ -968,6 +980,10 @@ Allow the verification of proxy certificates.
 
 As of OpenSSL 1.1.0 this option is on by default and cannot be disabled.
 
+When constructing the certificate chain, the trusted certificates specified
+via B<-CAfile>, B<-CApath>, B<-CAstore> or B<-trusted> are always used
+before any certificates specified via B<-untrusted>.
+
 =item B<-no_alt_chains>
 
 As of OpenSSL 1.1.0, since B<-trusted_first> always on, this option has no
@@ -986,7 +1002,8 @@ This option may be used multiple times.
 =item B<-untrusted> I<file>
 
 Parse I<file> as a set of one or more certificates in PEM format.
-All certificates are untrusted certificates that may be used to
+All certificates are untrusted certificates (typically of intermedate CAs)
+that may be used to
 construct a certificate chain from the subject certificate to a trust anchor.
 This option may be used multiple times.
 
diff --git a/doc/man3/X509_STORE_CTX_get_error.pod b/doc/man3/X509_STORE_CTX_get_error.pod
index ce69e4da45..474dd4dc4f 100644
--- a/doc/man3/X509_STORE_CTX_get_error.pod
+++ b/doc/man3/X509_STORE_CTX_get_error.pod
@@ -107,24 +107,29 @@ Unspecified error; should not happen.
 
 The issuer certificate of a locally looked up certificate could not be found.
 This normally means the list of trusted certificates is not complete.
+To allow any certificate (not only a self-signed one) in the trust store
+to terminate the chain the B<X509_V_FLAG_PARTIAL_CHAIN> flag may be set.
 
 =item B<X509_V_ERR_UNABLE_TO_GET_CRL: unable to get certificate CRL>
 
 The CRL of a certificate could not be found.
 
-=item B<X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: unable to decrypt certificate's signature>
+=item B<X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+unable to decrypt certificate's signature>
 
 The certificate signature could not be decrypted. This means that the actual
 signature value could not be determined rather than it not matching the
 expected value, this is only meaningful for RSA keys.
 
-=item B<X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: unable to decrypt CRL's signature>
+=item B<X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+unable to decrypt CRL's signature>
 
 The CRL signature could not be decrypted: this means that the actual signature
 value could not be determined rather than it not matching the expected value.
 Unused.
 
-=item B<X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: unable to decode issuer public key>
+=item B<X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+unable to decode issuer public key>
 
 The public key in the certificate C<SubjectPublicKeyInfo> field could
 not be read.
@@ -155,19 +160,23 @@ The CRL is not yet valid.
 
 The CRL has expired.
 
-=item B<X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: format error in certificate's notBefore field>
+=item B<X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+format error in certificate's notBefore field>
 
 The certificate B<notBefore> field contains an invalid time.
 
-=item B<X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: format error in certificate's notAfter field>
+=item B<X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+format error in certificate's notAfter field>
 
 The certificate B<notAfter> field contains an invalid time.
 
-=item B<X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: format error in CRL's lastUpdate field>
+=item B<X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+format error in CRL's lastUpdate field>
 
 The CRL B<lastUpdate> field contains an invalid time.
 
-=item B<X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: format error in CRL's nextUpdate field>
+=item B<X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+format error in CRL's nextUpdate field>
 
 The CRL B<nextUpdate> field contains an invalid time.
 
@@ -175,25 +184,29 @@ The CRL B<nextUpdate> field contains an invalid time.
 
 An error occurred trying to allocate memory.
 
-=item B<X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: self signed certificate>
+=item B<X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: self-signed certificate>
 
 The passed certificate is self-signed and the same certificate cannot be found
 in the list of trusted certificates.
 
-=item B<X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: self signed certificate in certificate chain>
+=item B<X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+self-signed certificate in certificate chain>
 
-The certificate chain could be built up using the untrusted certificates but
-the root could not be found locally.
+The certificate chain could be built up using the untrusted certificates
+but no suitable trust anchor (which typically is a self-signed root certificate)
+could be found in the trust store.
 
-=item B<X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: unable to get local issuer certificate>
+=item B<X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+unable to get local issuer certificate>
 
 The issuer certificate could not be found: this occurs if the issuer certificate
 of an untrusted certificate cannot be found.
 
-=item B<X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: unable to verify the first certificate>
+=item B<X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+unable to verify the first certificate>
 
 No signatures could be verified because the chain contains only one certificate
-and it is not self signed.
+and it is not self-signed and the B<X509_V_FLAG_PARTIAL_CHAIN> flag is not set.
 
 =item B<X509_V_ERR_CERT_CHAIN_TOO_LONG: certificate chain too long>
 
@@ -214,7 +227,7 @@ The basicConstraints path-length parameter has been exceeded.
 
 =item B<X509_V_ERR_INVALID_PURPOSE: unsupported certificate purpose>
 
-The supplied certificate cannot be used for the specified purpose.
+The target certificate cannot be used for the specified purpose.
 
 =item B<X509_V_ERR_CERT_UNTRUSTED: certificate not trusted>
 
@@ -229,32 +242,37 @@ The root CA is marked to reject the specified purpose.
 The current candidate issuer certificate was rejected because its subject name
 did not match the issuer name of the current certificate.
 
-=item B<X509_V_ERR_AKID_SKID_MISMATCH: authority and subject key identifier mismatch>
+=item B<X509_V_ERR_AKID_SKID_MISMATCH:
+authority and subject key identifier mismatch>
 
 The current candidate issuer certificate was rejected because its subject key
 identifier was present and did not match the authority key identifier current
 certificate.
 Not used as of OpenSSL 1.1.0.
 
-=item B<X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: authority and issuer serial number mismatch>
+=item B<X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
+authority and issuer serial number mismatch>
 
 The current candidate issuer certificate was rejected because its issuer name
 and serial number was present and did not match the authority key identifier of
 the current certificate.
 Not used as of OpenSSL 1.1.0.
 
-=item B<X509_V_ERR_KEYUSAGE_NO_CERTSIGN:key usage does not include certificate signing>
+=item B<X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
+key usage does not include certificate signing>
 
 The current candidate issuer certificate was rejected because its B<keyUsage>
 extension does not permit certificate signing.
 Not used as of OpenSSL 1.1.0.
 
-=item B<X509_V_ERR_INVALID_EXTENSION: invalid or inconsistent certificate extension>
+=item B<X509_V_ERR_INVALID_EXTENSION:
+invalid or inconsistent certificate extension>
 
 A certificate extension had an invalid value (for example an incorrect
 encoding) or some value inconsistent with other extensions.
 
-=item B<X509_V_ERR_INVALID_POLICY_EXTENSION: invalid or inconsistent certificate policy extension>
+=item B<X509_V_ERR_INVALID_POLICY_EXTENSION:
+invalid or inconsistent certificate policy extension>
 
 A certificate policies extension had an invalid value (for example an incorrect
 encoding) or some value inconsistent with other extensions. This error only
@@ -265,7 +283,7 @@ occurs if policy processing is enabled.
 The verification flags were set to require and explicit policy but none was
 present.
 
-=item B<X509_V_ERR_DIFFERENT_CRL_SCOPE: Different CRL scope>
+=item B<X509_V_ERR_DIFFERENT_CRL_SCOPE: different CRL scope>
 
 The only CRLs that could be found did not match the scope of the certificate.
 
@@ -281,17 +299,20 @@ A name constraint violation occurred in the permitted subtrees.
 
 A name constraint violation occurred in the excluded subtrees.
 
-=item B<X509_V_ERR_SUBTREE_MINMAX: name constraints minimum and maximum not supported>
+=item B<X509_V_ERR_SUBTREE_MINMAX:
+name constraints minimum and maximum not supported>
 
 A certificate name constraints extension included a minimum or maximum field:
 this is not supported.
 
-=item B<X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: unsupported name constraint type>
+=item B<X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE:
+unsupported name constraint type>
 
 An unsupported name constraint type was encountered. OpenSSL currently only
 supports directory name, DNS name, email and URI types.
 
-=item B<X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: unsupported or invalid name constraint syntax>
+=item B<X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX:
+unsupported or invalid name constraint syntax>
 
 The format of the name constraint is not recognised: for example an email
 address format of a form not mentioned in RFC3280. This could be caused by
@@ -384,7 +405,7 @@ CA signature digest algorithm too weak.
 
 =item B<X509_V_ERR_INVALID_CALL: invalid certificate verification context>
 
-invalid certificate verification context.
+Invalid certificate verification context.
 
 =item B<X509_V_ERR_STORE_LOOKUP: issuer certificate lookup error>
 
diff --git a/doc/man3/X509_STORE_set_verify_cb_func.pod b/doc/man3/X509_STORE_set_verify_cb_func.pod
index e845906cc8..84b216ffbe 100644
--- a/doc/man3/X509_STORE_set_verify_cb_func.pod
+++ b/doc/man3/X509_STORE_set_verify_cb_func.pod
@@ -145,7 +145,9 @@ I<If no function to get the issuer is provided, the internal default
 function will be used instead.>
 
 X509_STORE_set_check_issued() sets the function to check that a given
-certificate B<x> is issued with the issuer certificate B<issuer>.
+certificate B<x> is issued by the issuer certificate B<issuer> and
+the issuer is not yet in the chain contained in <ctx>, where the exceptional
+case that B<x> is self-issued and ctx->chain has just one element is allowed.
 This function must return 0 on failure (among others if B<x> hasn't
 been issued with B<issuer>) and 1 on success.
 I<If no function to get the issuer is provided, the internal default
diff --git a/doc/man3/X509_VERIFY_PARAM_set_flags.pod b/doc/man3/X509_VERIFY_PARAM_set_flags.pod
index f34020cbaa..72da4cb143 100644
--- a/doc/man3/X509_VERIFY_PARAM_set_flags.pod
+++ b/doc/man3/X509_VERIFY_PARAM_set_flags.pod
@@ -112,8 +112,8 @@ A maximal depth chain contains 2 more certificates than the limit, since
 neither the end-entity certificate nor the trust-anchor count against this
 limit.
 Thus a B<depth> limit of 0 only allows the end-entity certificate to be signed
-directly by the trust-anchor, while with a B<depth> limit of 1 there can be one
-intermediate CA certificate between the trust-anchor and the end-entity
+directly by the trust anchor, while with a B<depth> limit of 1 there can be one
+intermediate CA certificate between the trust anchor and the end-entity
 certificate.
 
 X509_VERIFY_PARAM_set_auth_level() sets the authentication security level to
@@ -283,24 +283,25 @@ they are enabled.
 If B<X509_V_FLAG_USE_DELTAS> is set delta CRLs (if present) are used to
 determine certificate status. If not set deltas are ignored.
 
-B<X509_V_FLAG_CHECK_SS_SIGNATURE> enables checking of the root CA self signed
-certificate signature. By default this check is disabled because it doesn't
+B<X509_V_FLAG_CHECK_SS_SIGNATURE> requires verifying the signature of the last
+certificate in a chain even when it is a self-signed (root CA) certificate.
+In this case the check is disabled by default because it does not
 add any additional security but in some cases applications might want to
 check the signature anyway. A side effect of not checking the root CA
 signature is that disabled or unsupported message digests on the root CA
 are not treated as fatal errors.
 
-When B<X509_V_FLAG_TRUSTED_FIRST> is set, construction of the certificate chain
-in L<X509_verify_cert(3)> will search the trust store for issuer certificates
+When B<X509_V_FLAG_TRUSTED_FIRST> is set, which is always the case since
+OpenSSL 1.1.0, construction of the certificate chain
+in L<X509_verify_cert(3)> searches the trust store for issuer certificates
 before searching the provided untrusted certificates.
 Local issuer certificates are often more likely to satisfy local security
 requirements and lead to a locally trusted root.
 This is especially important when some certificates in the trust store have
 explicit trust settings (see "TRUST SETTINGS" in L<openssl-x509(1)>).
-As of OpenSSL 1.1.0 this option is on by default.
 
-The B<X509_V_FLAG_NO_ALT_CHAINS> flag suppresses checking for alternative
-chains.
+The B<X509_V_FLAG_NO_ALT_CHAINS> flag could have been used before OpenSSL 1.1.0
+to suppress checking for alternative chains.
 By default, unless B<X509_V_FLAG_TRUSTED_FIRST> is set, when building a
 certificate chain, if the first certificate chain found is not trusted, then
 OpenSSL will attempt to replace untrusted certificates supplied by the peer
@@ -309,15 +310,15 @@ found that is trusted.
 As of OpenSSL 1.1.0, with B<X509_V_FLAG_TRUSTED_FIRST> always set, this option
 has no effect.
 
-The B<X509_V_FLAG_PARTIAL_CHAIN> flag causes intermediate certificates in the
-trust store to be treated as trust-anchors, in the same way as the self-signed
+The B<X509_V_FLAG_PARTIAL_CHAIN> flag causes non-self-signed certificates in the
+trust store to be treated as trust anchors, in the same way as self-signed
 root CA certificates.
-This makes it possible to trust certificates issued by an intermediate CA
-without having to trust its ancestor root CA.
+This makes it possible to trust self-issued certificates as well as certificates
+issued by an intermediate CA without having to trust their ancestor root CA.
 With OpenSSL 1.1.0 and later and <X509_V_FLAG_PARTIAL_CHAIN> set, chain
-construction stops as soon as the first certificate from the trust store is
-added to the chain, whether that certificate is a self-signed "root"
-certificate or a not self-signed intermediate certificate.
+construction stops as soon as the first certificate contained in the trust store
+is added to the chain, whether that certificate is a self-signed "root"
+certificate or a not self-signed "intermediate" or self-issued certificate.
 Thus, when an intermediate certificate is found in the trust store, the
 verified chain passed to callbacks may be shorter than it otherwise would
 be without the B<X509_V_FLAG_PARTIAL_CHAIN> flag.
diff --git a/doc/man3/X509_check_issued.pod b/doc/man3/X509_check_issued.pod
index d41dfcd53e..0aedefa459 100644
--- a/doc/man3/X509_check_issued.pod
+++ b/doc/man3/X509_check_issued.pod
@@ -2,7 +2,7 @@
 
 =head1 NAME
 
-X509_check_issued - checks if certificate is issued by another
+X509_check_issued - checks if certificate is apparently issued by another
 certificate
 
 =head1 SYNOPSIS
@@ -14,24 +14,24 @@ certificate
 
 =head1 DESCRIPTION
 
-This function checks if certificate I<subject> was issued using CA
-certificate I<issuer>. This function takes into account not only
-matching of issuer field of I<subject> with subject field of I<issuer>,
-but also compares B<authorityKeyIdentifier> extension of I<subject> with
-B<subjectKeyIdentifier> of I<issuer> if B<authorityKeyIdentifier>
-present in the I<subject> certificate and checks B<keyUsage> field of
-I<issuer>.
+X509_check_issued() checks if certificate I<subject> was apparently issued
+using (CA) certificate I<issuer>. This function takes into account not only
+matching of the issuer field of I<subject> with the subject field of I<issuer>,
+but also compares all sub-fields of the B<authorityKeyIdentifier> extension of
+I<subject>, as far as present, with the respective B<subjectKeyIdentifier>,
+serial number, and issuer fields of I<issuer>, as far as present. It also checks
+if the B<keyUsage> field (if present) of I<issuer> allows certificate signing.
+It does not actually check the certificate signature.
 
 =head1 RETURN VALUES
 
-Function return B<X509_V_OK> if certificate I<subject> is issued by
-I<issuer> or some B<X509_V_ERR*> constant to indicate an error.
+X509_check_issued() returns B<X509_V_OK> if all checks are successful
+or some B<X509_V_ERR*> constant to indicate an error.
 
 =head1 SEE ALSO
 
-L<X509_verify_cert(3)>,
-L<X509_check_ca(3)>,
-L<openssl-verify(1)>
+L<X509_verify_cert(3)>, L<X509_verify(3)>, L<X509_check_ca(3)>,
+L<openssl-verify(1)>, L<X509_self_signed(3)>
 
 =head1 COPYRIGHT
 
diff --git a/doc/man3/X509_sign.pod b/doc/man3/X509_sign.pod
index ccce5f573b..5f621a11e4 100644
--- a/doc/man3/X509_sign.pod
+++ b/doc/man3/X509_sign.pod
@@ -2,10 +2,10 @@
 
 =head1 NAME
 
-X509_sign, X509_sign_ctx, X509_verify_ex, X509_verify, X509_REQ_sign,
-X509_REQ_sign_ctx, X509_REQ_verify_ex, X509_REQ_verify, X509_CRL_sign,
-X509_CRL_sign_ctx, X509_CRL_verify
-- sign or verify certificate, certificate request or CRL signature
+X509_sign, X509_sign_ctx,
+X509_REQ_sign, X509_REQ_sign_ctx,
+X509_CRL_sign, X509_CRL_sign_ctx -
+sign certificate, certificate request, or CRL signature
 
 =head1 SYNOPSIS
 
@@ -13,18 +13,12 @@ X509_CRL_sign_ctx, X509_CRL_verify
 
  int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md);
  int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx);
- int X509_verify_ex(X509 *x, EVP_PKEY *pkey, OPENSSL_CTX *libctx, const char *propq);
- int X509_verify(X509 *x, EVP_PKEY *pkey;
 
  int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md);
  int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx);
- int X509_REQ_verify_ex(X509_REQ *a, EVP_PKEY *pkey, OPENSSL_CTX *libctx,
-                        const char *propq);
- int X509_REQ_verify(X509_REQ *a, EVP_PKEY *pkey);
 
  int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md);
  int X509_CRL_sign_ctx(X509_CRL *x, EVP_MD_CTX *ctx);
- int X509_CRL_verify(X509_CRL *a, EVP_PKEY *pkey);
 
 =head1 DESCRIPTION
 
@@ -32,18 +26,9 @@ X509_sign() signs certificate I<x> using private key I<pkey> and message
 digest I<md> and sets the signature in I<x>. X509_sign_ctx() also signs
 certificate I<x> but uses the parameters contained in digest context I<ctx>.
 
-X509_verify_ex() verifies the signature of certificate I<x> using public key
-I<pkey>. Any cryptographic algorithms required for the verification are fetched
-using the library context I<libctx> and the property query string I<propq>. Only
-the signature is checked: no other checks (such as certificate chain validity)
-are performed.
-
-X509_verify() is the same as X509_verify_ex() except that the default library
-context and property query string are used.
-
-X509_REQ_sign(), X509_REQ_sign_ctx(), X509_REQ_verify_ex(), X509_REQ_verify(),
-X509_CRL_sign(), X509_CRL_sign_ctx() and X509_CRL_verify() sign and verify
-certificate requests and CRLs respectively.
+X509_REQ_sign(), X509_REQ_sign_ctx(),
+X509_CRL_sign(), and X509_CRL_sign_ctx()
+sign certificate requests and CRLs, respectively.
 
 =head1 NOTES
 
@@ -60,34 +45,18 @@ signature and signing will always update the encoding.
 
 =head1 RETURN VALUES
 
-X509_sign(), X509_sign_ctx(), X509_REQ_sign(), X509_REQ_sign_ctx(),
-X509_CRL_sign() and X509_CRL_sign_ctx() return the size of the signature
+All functions return the size of the signature
 in bytes for success and zero for failure.
 
-X509_verify_ex(), X509_verify(), X509_REQ_verify_ex(), X509_REQ_verify() and
-X509_CRL_verify() return 1 if the signature is valid and 0 if the signature
-check fails. If the signature could not be checked at all because it was invalid
-or some other error occurred then -1 is returned.
-
 =head1 SEE ALSO
 
-L<d2i_X509(3)>,
 L<ERR_get_error(3)>,
-L<X509_CRL_get0_by_serial(3)>,
-L<X509_get0_signature(3)>,
-L<X509_get_ext_d2i(3)>,
-L<X509_get_extension_flags(3)>,
-L<X509_get_pubkey(3)>,
-L<X509_get_subject_name(3)>,
-L<X509_get_version(3)>,
 L<X509_NAME_add_entry_by_txt(3)>,
-L<X509_NAME_ENTRY_get_object(3)>,
-L<X509_NAME_get_index_by_NID(3)>,
-L<X509_NAME_print_ex(3)>,
 L<X509_new(3)>,
-L<X509V3_get_d2i(3)>,
 L<X509_verify_cert(3)>,
-L<OPENSSL_CTX(3)>
+L<X509_verify_ex(3)>, L<X509_verify(3)>,
+L<X509_REQ_verify_ex(3)>, L<X509_REQ_verify(3)>,
+L<X509_CRL_verify(3)>
 
 =head1 HISTORY
 
@@ -95,9 +64,7 @@ The X509_sign(), X509_REQ_sign() and X509_CRL_sign() functions are
 available in all versions of OpenSSL.
 
 The X509_sign_ctx(), X509_REQ_sign_ctx()
-and X509_CRL_sign_ctx() functions were added OpenSSL 1.0.1.
-
-X509_verify_ex() and X509_REQ_verify_ex() were added in OpenSSL 3.0.
+and X509_CRL_sign_ctx() functions were added in OpenSSL 1.0.1.
 
 =head1 COPYRIGHT
 
diff --git a/doc/man3/X509_verify.pod b/doc/man3/X509_verify.pod
new file mode 100644
index 0000000000..e0028473a2
--- /dev/null
+++ b/doc/man3/X509_verify.pod
@@ -0,0 +1,90 @@
+=pod
+
+=head1 NAME
+
+X509_verify_ex, X509_verify, X509_self_signed,
+X509_REQ_verify_ex, X509_REQ_verify,
+X509_CRL_verify -
+verify certificate, certificate request, or CRL signature
+
+=head1 SYNOPSIS
+
+ #include <openssl/x509.h>
+
+ int X509_verify_ex(X509 *x, EVP_PKEY *pkey,
+                    OPENSSL_CTX *libctx, const char *propq);
+ int X509_verify(X509 *x, EVP_PKEY *pkey);
+ int X509_self_signed(X509 *cert, int verify_signature);
+
+ int X509_REQ_verify_ex(X509_REQ *a, EVP_PKEY *pkey,
+                        OPENSSL_CTX *libctx, const char *propq);
+ int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r);
+ int X509_CRL_verify(X509_CRL *a, EVP_PKEY *r);
+
+=head1 DESCRIPTION
+
+X509_verify_ex() verifies the signature of certificate I<x> using public key
+I<pkey>. Any cryptographic algorithms required for the verification are fetched
+using the library context I<libctx> and the property query string I<propq>.
+Only the signature is checked:
+no other checks (such as certificate chain validity) are performed.
+
+X509_verify() is the same as X509_verify_ex() except that the default library
+context and property query string are used.
+
+X509_self_signed() checks whether a certificate is self-signed.
+For success the issuer and subject names must match, the components of the
+authority key identifier (if present) must match the subject key identifier etc.
+The signature itself is actually verified only if B<verify_signature> is 1, as
+for explicitly trusted certificates this verification is not worth the effort.
+
+X509_REQ_verify_ex(), X509_REQ_verify() and X509_CRL_verify()
+verify the signatures of certificate requests and CRLs, respectively.
+
+=head1 RETURN VALUES
+
+X509_verify_ex(), X509_verify(),
+X509_REQ_verify_ex(), X509_REQ_verify() and X509_CRL_verify()
+return 1 if the signature is valid and 0 if the signature check fails.
+If the signature could not be checked at all because it was ill-formed
+or some other error occurred then -1 is returned.
+
+X509_self_signed() returns the same values but also returns 1
+if all respective fields match and B<verify_signature> is 0.
+
+=head1 SEE ALSO
+
+L<d2i_X509(3)>,
+L<ERR_get_error(3)>,
+L<X509_CRL_get0_by_serial(3)>,
+L<X509_get0_signature(3)>,
+L<X509_get_ext_d2i(3)>,
+L<X509_get_extension_flags(3)>,
+L<X509_get_pubkey(3)>,
+L<X509_get_subject_name(3)>,
+L<X509_get_version(3)>,
+L<X509_NAME_ENTRY_get_object(3)>,
+L<X509_NAME_get_index_by_NID(3)>,
+L<X509_NAME_print_ex(3)>,
+L<X509V3_get_d2i(3)>,
+L<X509_verify_cert(3)>,
+L<OPENSSL_CTX(3)>
+
+=head1 HISTORY
+
+The X509_verify(), X509_REQ_verify(), and X509_CRL_verify()
+functions are available in all versions of OpenSSL.
+
+X509_verify_ex(), X509_REQ_verify_ex(), and X509_self_signed()
+were added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2015-2020 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/X509v3_cache_extensions.pod b/doc/man3/X509v3_cache_extensions.pod
index 952a8c2ead..766ab50d28 100644
--- a/doc/man3/X509v3_cache_extensions.pod
+++ b/doc/man3/X509v3_cache_extensions.pod
@@ -3,7 +3,7 @@
 =head1 NAME
 
 X509v3_cache_extensions
-- process any extensions in an X509 object
+- cache info on various X.509v3 extensions and further derived certificate data
 
 =head1 SYNOPSIS
 
@@ -14,7 +14,8 @@ X509v3_cache_extensions
 =head1 DESCRIPTION
 
 This function processes any X509v3 extensions that might be present in an X509
-object and caches the result of that processing. Many OpenSSL functions that use
+object and caches the result of that processing as well as further derived info,
+for instance if the certificate is self-issued. Many OpenSSL functions that use
 an X509 object will cause extensions to be processed and cached implicitly. If
 this is done implicitly then the default library context and property query
 string will be used. In some cases it may be desirable to use some other library
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index b0e33d5286..2212ceeedc 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -345,6 +345,7 @@ const char *X509_verify_cert_error_string(long n);
 
 int X509_verify_ex(X509 *a, EVP_PKEY *r, OPENSSL_CTX *libctx, const char *propq);
 int X509_verify(X509 *a, EVP_PKEY *r);
+int X509_self_signed(X509 *cert, int verify_signature);
 
 int X509_REQ_verify_ex(X509_REQ *a, EVP_PKEY *r, OPENSSL_CTX *libctx,
                        const char *propq);
diff --git a/include/openssl/x509_vfy.h b/include/openssl/x509_vfy.h
index fda13502c3..5cd123f635 100644
--- a/include/openssl/x509_vfy.h
+++ b/include/openssl/x509_vfy.h
@@ -204,6 +204,7 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
 
 # define         X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH         76
 # define         X509_V_ERR_NO_ISSUER_PUBLIC_KEY                 77
+# define         X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM      78
 
 
 /* Certificate verify flags */
diff --git a/test/certs/ee-self-signed.pem b/test/certs/ee-self-signed.pem
new file mode 100644
index 0000000000..ad1e37ba0e
--- /dev/null
+++ b/test/certs/ee-self-signed.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzzCCAbegAwIBAgIUBP7iEKPlKuinZGQNFxSY3IBIb0swDQYJKoZIhvcNAQEL
+BQAwGTEXMBUGA1UEAwwOZWUtc2VsZi1zaWduZWQwHhcNMjAwNjI4MTA1MTQ1WhcN
+MjAwNzI4MTA1MTQ1WjAZMRcwFQYDVQQDDA5lZS1zZWxmLXNpZ25lZDCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKj/iVhhha7e2ywP1XP74reoG3p1YCvU
+fTxzdrWu3pMvfySQbckc9Io4zZ+igBZWy7Qsu5PlFx//DcZD/jE0+CjYdemju4iC
+76Ny4lNiBUVN4DGX76qdENJYDZ4GnjK7GwhWXWUPP2aOwjagEf/AWTX9SRzdHEIz
+BniuBDgj5ed1Z9OUrVqpQB+sWRD1DMFkrUrExjVTs5ZqghsVi9GZq+Seb5Sq0pbl
+V/uMkWSKPCQWxtIZvoJgEztisO0+HbPK+WvfMbl6nktHaKcpxz9K4iIntO+QY9fv
+0HJJPlutuRvUK2+GaN3VcxK4Q8ncQQ+io0ZPi2eIhA9h/nk0H0qJH7cCAwEAAaMP
+MA0wCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBCwUAA4IBAQBiLmIUCGb+hmRGbmpO
+lDqEwiRVdxHBs4OSb3IA9QgU1QKUDRqn7q27RRelmzTXllubZZcX3K6o+dunRW5G
+d3f3FVr+3Z7wnmkQtC2y3NWtGuWNczss+6rMLzKvla5CjRiNPlSvluMNpcs7BJxI
+ppk1LxlaiYlQkDW32OPyxzXWDNv1ZkphcOcoCkHAagnq9x1SszvLTjAlo5XpYrm5
+CPgBOEnVwFCgne5Ab4QPTgkxPh/Ta508I/FKaPLJqci1EfGKipZkS7mMGTUJEeVK
+wZrn4z7RiTfJ4PdqO5iv8eOpt03fqdPEXQWe8DrKyfGM6/e369FaXMFhcd2ZxZy2
+WHoc
+-----END CERTIFICATE-----
diff --git a/test/certs/setup.sh b/test/certs/setup.sh
index f4f3e046f0..d1c56bb56d 100755
--- a/test/certs/setup.sh
+++ b/test/certs/setup.sh
@@ -185,6 +185,9 @@ OPENSSL_SIGALG=md5 \
 OPENSSL_KEYBITS=768 \
 ./mkcert.sh genee server.example ee-key-768 ee-cert-768 ca-key ca-cert
 
+# self-signed end-entity cert with explicit keyUsage not including KeyCertSign
+openssl req -new -x509 -key ee-key.pem -subj /CN=ee-self-signed -out ee-self-signed.pem -addext keyUsage=digitalSignature
+
 # Proxy certificates, off of ee-client
 # Start with some good ones
 ./mkcert.sh req pc1-key "0.CN = server.example" "1.CN = proxy 1" | \
diff --git a/test/recipes/25-test_verify.t b/test/recipes/25-test_verify.t
index 9039a5db81..42d44dcdce 100644
--- a/test/recipes/25-test_verify.t
+++ b/test/recipes/25-test_verify.t
@@ -27,7 +27,7 @@ sub verify {
     run(app([@args]));
 }
 
-plan tests => 139;
+plan tests => 144;
 
 # Canonical success
 ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]),
@@ -368,13 +368,28 @@ ok(verify("some-names2", "sslserver", ["many-constraints"], ["many-constraints"]
 ok(verify("root-cert-rsa2", "sslserver", ["root-cert-rsa2"], [], "-check_ss_sig"),
     "Public Key Algorithm rsa instead of rsaEncryption");
 
+    ok(verify("ee-self-signed", "sslserver", ["ee-self-signed"], []),
+       "accept trusted self-signed EE cert excluding key usage keyCertSign");
+
 SKIP: {
-    skip "Ed25519 is not supported by this OpenSSL build", 1
+    skip "Ed25519 is not supported by this OpenSSL build", 5
 	      if disabled("ec");
 
     # ED25519 certificate from draft-ietf-curdle-pkix-04
     ok(verify("ee-ed25519", "sslserver", ["root-ed25519"], []),
-       "ED25519 signature");
+       "accept X25519 EE cert issued by trusted Ed25519 self-signed CA cert");
+
+    ok(!verify("root-ed25519", "sslserver", ["ee-ed25519"], []),
+       "fail Ed25519 CA and EE certs swapped");
+
+    ok(verify("root-ed25519", "sslserver", ["root-ed25519"], []),
+       "accept trusted Ed25519 self-signed CA cert");
+
+    ok(!verify("ee-ed25519", "sslserver", ["ee-ed25519"], []),
+       "fail trusted Ed25519-signed self-issued X25519 cert");
+
+    ok(verify("ee-ed25519", "sslserver", ["ee-ed25519"], [], "-partial_chain"),
+       "accept last-resort direct leaf match Ed25519-signed self-issued cert");
 
 }
 
diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t
index 427c6b7fea..250738487a 100644
--- a/test/recipes/25-test_x509.t
+++ b/test/recipes/25-test_x509.t
@@ -41,6 +41,7 @@ SKIP: {
     # producing and checking self-issued (but not self-signed) cert
     my @path = qw(test certs);
     my $subj = "/CN=CA"; # using same DN as in issuer of ee-cert.pem
+    my $extfile = srctop_file("test", "v3_ca_exts.cnf");
     my $pkey = srctop_file(@path, "ca-key.pem"); #  issuer private key
     my $pubkey = "ca-pubkey.pem"; # the corresponding issuer public key
     # use any (different) key for signing our self-issued cert:
@@ -50,10 +51,13 @@ SKIP: {
     ok(run(app(["openssl", "pkey", "-in", $pkey, "-pubout", "-out", $pubkey]))
        &&
        run(app(["openssl", "x509", "-new", "-force_pubkey", $pubkey,
-                "-subj", $subj, "-signkey", $signkey, "-out", $selfout]))
+                "-subj", $subj, "-extfile", $extfile,
+                "-signkey", $signkey, "-out", $selfout]))
        &&
        run(app(["openssl", "verify", "-no_check_time",
-                "-trusted", $selfout, $testcert])));
+                "-trusted", $selfout, "-partial_chain", $testcert])));
+    unlink $pubkey;
+    unlink $selfout;
 }
 
 subtest 'x509 -- x.509 v1 certificate' => sub {
diff --git a/test/recipes/70-test_verify_extra.t b/test/recipes/70-test_verify_extra.t
index b8f4ab4312..6876870bbf 100644
--- a/test/recipes/70-test_verify_extra.t
+++ b/test/recipes/70-test_verify_extra.t
@@ -14,6 +14,7 @@ setup("test_verify_extra");
 plan tests => 1;
 
 ok(run(test(["verify_extra_test",
+             srctop_file("test", "certs", "rootCA.pem"),
              srctop_file("test", "certs", "roots.pem"),
              srctop_file("test", "certs", "untrusted.pem"),
              srctop_file("test", "certs", "bad.pem"),
diff --git a/test/v3_ca_exts.cnf b/test/v3_ca_exts.cnf
new file mode 100644
index 0000000000..a6d3245fb4
--- /dev/null
+++ b/test/v3_ca_exts.cnf
@@ -0,0 +1,5 @@
+basicConstraints = CA:true
+keyUsage = cRLSign, keyCertSign
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always
+
diff --git a/test/verify_extra_test.c b/test/verify_extra_test.c
index 6cce626026..99a6361142 100644
--- a/test/verify_extra_test.c
+++ b/test/verify_extra_test.c
@@ -18,11 +18,24 @@
 
 DEFINE_STACK_OF(X509)
 
+static const char *root_f;
 static const char *roots_f;
 static const char *untrusted_f;
 static const char *bad_f;
 static const char *req_f;
 
+static X509 *load_cert_from_file(const char *filename)
+{
+    X509 *cert = NULL;
+    BIO *bio;
+
+    bio = BIO_new_file(filename, "r");
+    if (bio != NULL)
+        cert = PEM_read_bio_X509(bio, NULL, 0, NULL);
+    BIO_free(bio);
+    return cert;
+}
+
 static STACK_OF(X509) *load_certs_from_file(const char *filename)
 {
     STACK_OF(X509) *certs;
@@ -97,7 +110,6 @@ static int test_alt_chains_cert_forgery(void)
     int i;
     X509 *x = NULL;
     STACK_OF(X509) *untrusted = NULL;
-    BIO *bio = NULL;
     X509_STORE_CTX *sctx = NULL;
     X509_STORE *store = NULL;
     X509_LOOKUP *lookup = NULL;
@@ -114,10 +126,7 @@ static int test_alt_chains_cert_forgery(void)
 
     untrusted = load_certs_from_file(untrusted_f);
 
-    if ((bio = BIO_new_file(bad_f, "r")) == NULL)
-        goto err;
-
-    if ((x = PEM_read_bio_X509(bio, NULL, 0, NULL)) == NULL)
+    if ((x = load_cert_from_file(bad_f)) == NULL)
         goto err;
 
     sctx = X509_STORE_CTX_new();
@@ -136,7 +145,6 @@ static int test_alt_chains_cert_forgery(void)
  err:
     X509_STORE_CTX_free(sctx);
     X509_free(x);
-    BIO_free(bio);
     sk_X509_pop_free(untrusted, X509_free);
     X509_STORE_free(store);
     return ret;
@@ -146,14 +154,9 @@ static int test_store_ctx(void)
 {
     X509_STORE_CTX *sctx = NULL;
     X509 *x = NULL;
-    BIO *bio = NULL;
     int testresult = 0, ret;
 
-    bio = BIO_new_file(bad_f, "r");
-    if (bio == NULL)
-        goto err;
-
-    x = PEM_read_bio_X509(bio, NULL, 0, NULL);
+    x = load_cert_from_file(bad_f);
     if (x == NULL)
         goto err;
 
@@ -175,7 +178,6 @@ static int test_store_ctx(void)
  err:
     X509_STORE_CTX_free(sctx);
     X509_free(x);
-    BIO_free(bio);
     return testresult;
 }
 
@@ -184,16 +186,11 @@ OPT_TEST_DECLARE_USAGE("roots.pem untrusted.pem bad.pem\n")
 static int test_distinguishing_id(void)
 {
     X509 *x = NULL;
-    BIO *bio = NULL;
     int ret = 0;
     ASN1_OCTET_STRING *v = NULL, *v2 = NULL;
     char *distid = "this is an ID";
 
-    bio = BIO_new_file(bad_f, "r");
-    if (bio == NULL)
-        goto err;
-
-    x = PEM_read_bio_X509(bio, NULL, 0, NULL);
+    x = load_cert_from_file(bad_f);
     if (x == NULL)
         goto err;
 
@@ -217,7 +214,6 @@ static int test_distinguishing_id(void)
     ret = 1;
  err:
     X509_free(x);
-    BIO_free(bio);
     return ret;
 }
 
@@ -261,6 +257,32 @@ static int test_req_distinguishing_id(void)
     return ret;
 }
 
+static int test_self_signed(const char *filename, int expected)
+{
+    X509 *cert;
+    int ret;
+
+    cert = load_cert_from_file(filename); /* may result in NULL */
+    ret = TEST_int_eq(X509_self_signed(cert, 1), expected);
+    X509_free(cert);
+    return ret;
+}
+
+static int test_self_signed_good(void)
+{
+    return test_self_signed(root_f, 1);
+}
+
+static int test_self_signed_bad(void)
+{
+    return test_self_signed(bad_f, 0);
+}
+
+static int test_self_signed_error(void)
+{
+    return test_self_signed("nonexistent file name", -1);
+}
+
 int setup_tests(void)
 {
     if (!test_skip_common_options()) {
@@ -268,15 +290,19 @@ int setup_tests(void)
         return 0;
     }
 
-    if (!TEST_ptr(roots_f = test_get_argument(0))
-            || !TEST_ptr(untrusted_f = test_get_argument(1))
-            || !TEST_ptr(bad_f = test_get_argument(2))
-            || !TEST_ptr(req_f = test_get_argument(3)))
+    if (!TEST_ptr(root_f = test_get_argument(0))
+            || !TEST_ptr(roots_f = test_get_argument(1))
+            || !TEST_ptr(untrusted_f = test_get_argument(2))
+            || !TEST_ptr(bad_f = test_get_argument(3))
+            || !TEST_ptr(req_f = test_get_argument(4)))
         return 0;
 
     ADD_TEST(test_alt_chains_cert_forgery);
     ADD_TEST(test_store_ctx);
     ADD_TEST(test_distinguishing_id);
     ADD_TEST(test_req_distinguishing_id);
+    ADD_TEST(test_self_signed_good);
+    ADD_TEST(test_self_signed_bad);
+    ADD_TEST(test_self_signed_error);
     return 1;
 }
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 22c7cdc709..db033eee9d 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4681,6 +4681,7 @@ ERR_set_error                           ?	3_0_0	EXIST::FUNCTION:
 ERR_vset_error                          ?	3_0_0	EXIST::FUNCTION:
 X509_get0_authority_issuer              ?	3_0_0	EXIST::FUNCTION:
 X509_get0_authority_serial              ?	3_0_0	EXIST::FUNCTION:
+X509_self_signed                        ?	3_0_0	EXIST::FUNCTION:
 EC_GROUP_new_by_curve_name_ex           ?	3_0_0	NOEXIST::FUNCTION:EC
 EC_KEY_new_ex                           ?	3_0_0	NOEXIST::FUNCTION:EC
 EC_KEY_new_by_curve_name_ex             ?	3_0_0	NOEXIST::FUNCTION:EC


More information about the openssl-commits mailing list