[openssl] master update

dev at ddvo.net dev at ddvo.net
Wed Jan 13 10:59:53 UTC 2021


The branch master has been updated
       via  2ed63033e46953d0d95ff100c1334da7cc32c49b (commit)
       via  04a1b3fa7b6090aaca88d2d884de847822e89bef (commit)
       via  0ae8d4ca9e2db5fd93683dbc42d28c2eba18045d (commit)
       via  73b1d24c1abfdf0c890b4461c3d07b8bff45844c (commit)
       via  b65c5ec8f5f8c9fa082c44bf805beed03d0fee0c (commit)
       via  41e597a01d95540f52e8bc4d69f88c3d93a093ce (commit)
       via  ea9fd333d19096d654cb252a2f6785ca03bfcbc1 (commit)
       via  7836f949c2550a00fe2720e96cfaffd824d357d1 (commit)
       via  855c68163b182960f2b27bb961a323944d96237e (commit)
       via  f0a057dd5343ca81849dd140ee9c302cda914f41 (commit)
       via  6ad957f1273e9918c22b27d0f1b1812360964a4e (commit)
       via  157959438308e586593592cc751195fbf3930a7d (commit)
       via  ec2bfb7d23b4790a5fbe3b5d73a3418966d7e8ad (commit)
      from  f2a0458731f15fd4d45f5574a221177f4591b1d8 (commit)


- Log -----------------------------------------------------------------
commit 2ed63033e46953d0d95ff100c1334da7cc32c49b
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Mon Jan 11 07:52:45 2021 +0100

    x509v3.h.in: Deprecate CTX_TEST and replace it by X509V3_CTX_TEST
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

commit 04a1b3fa7b6090aaca88d2d884de847822e89bef
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Wed Jan 6 12:16:44 2021 +0100

    apps/req.c: Make sure -verify option takes effect also with -x509
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

commit 0ae8d4ca9e2db5fd93683dbc42d28c2eba18045d
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Wed Jan 6 12:12:25 2021 +0100

    apps/req.c: Cosmetic improvements of code and documentation
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

commit 73b1d24c1abfdf0c890b4461c3d07b8bff45844c
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Fri Dec 25 12:10:44 2020 +0100

    crypto/x509: Rename v3_{skey,skid}.c, v3_{akey,akid}.c, v3_{alt,san}.c
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

commit b65c5ec8f5f8c9fa082c44bf805beed03d0fee0c
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Thu Dec 24 12:43:39 2020 +0100

    apps/req.c: Add -copy_extensions option for use with -x509; default: none
    
    Fixes #13708
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

commit 41e597a01d95540f52e8bc4d69f88c3d93a093ce
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Thu Dec 24 11:25:47 2020 +0100

    Add X509V3_set_issuer_pkey, needed for AKID of self-issued not self-signed cert
    
    Also clean up some related auxiliary functions and documentation
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

commit ea9fd333d19096d654cb252a2f6785ca03bfcbc1
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Thu Dec 24 07:42:08 2020 +0100

    apps/req.c: make -subj work with -x509; clean up related code
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

commit 7836f949c2550a00fe2720e96cfaffd824d357d1
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Mon Dec 21 15:52:01 2020 +0100

    X509_PUBKEY_set(): Fix error reporting
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

commit 855c68163b182960f2b27bb961a323944d96237e
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Mon Dec 21 13:50:09 2020 +0100

    apps/lib/opt.c: Fix error message on unknown option/digest
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

commit f0a057dd5343ca81849dd140ee9c302cda914f41
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Sat Dec 19 19:49:25 2020 +0100

    Add tests for (non-)default SKID and AKID inclusion by apps/{req,x509,ca}.c
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

commit 6ad957f1273e9918c22b27d0f1b1812360964a4e
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Sat Dec 19 19:46:14 2020 +0100

    apps/req.c: add -CA and -CAkey options; improve code and doc
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

commit 157959438308e586593592cc751195fbf3930a7d
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Thu Dec 10 21:02:47 2020 +0100

    APPS: Allow OPENSSL_CONF to be empty, not loading a config file
    
    Also document the function CONF_get1_default_config_file()
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

commit ec2bfb7d23b4790a5fbe3b5d73a3418966d7e8ad
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Thu Dec 10 15:23:41 2020 +0100

    apps/{req,x509,ca}.c Make sure certs have SKID and AKID X.509 extensions by default
    
    Fixes #13603
    
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/13658)

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

Summary of changes:
 CHANGES.md                                | 208 ++++++-------
 apps/ca.c                                 |   9 +-
 apps/include/apps.h                       |  10 +-
 apps/lib/apps.c                           |  85 ++++--
 apps/lib/opt.c                            |   3 +-
 apps/req.c                                | 473 ++++++++++++++++--------------
 apps/srp.c                                |   5 +-
 apps/x509.c                               |  16 +-
 crypto/conf/conf_api.c                    |   4 +-
 crypto/conf/conf_def.c                    |   5 +-
 crypto/conf/conf_mod.c                    |  11 +-
 crypto/x509/build.info                    |   2 +-
 crypto/x509/{v3_akey.c => v3_akid.c}      |  53 ++--
 crypto/x509/v3_conf.c                     |  34 ++-
 crypto/x509/{v3_alt.c => v3_san.c}        |   6 +-
 crypto/x509/{v3_skey.c => v3_skid.c}      |  62 ++--
 crypto/x509/v3_utf8.c                     |   1 -
 crypto/x509/x_pubkey.c                    |  16 +-
 doc/internal/man3/s2i_ASN1_UTF8STRING.pod |  46 ---
 doc/man1/openssl-ca.pod.in                |  49 ++--
 doc/man1/openssl-req.pod.in               | 103 +++++--
 doc/man1/openssl.pod                      |  11 +-
 doc/man3/ASN1_generate_nconf.pod          |   6 +-
 doc/man3/CONF_modules_load_file.pod       |  12 +-
 doc/man3/X509V3_set_ctx.pod               |  63 ++++
 doc/man3/s2i_ASN1_IA5STRING.pod           |  21 +-
 doc/man5/config.pod                       |   2 +-
 doc/man5/x509v3_config.pod                |  27 +-
 doc/man7/openssl-env.pod                  |   2 +-
 include/crypto/x509.h                     |   2 +
 include/crypto/x509v3.h                   |  23 --
 include/openssl/x509v3.h.in               |  22 +-
 test/certs/ext-check.csr                  |  18 ++
 test/recipes/25-test_req.t                | 104 ++++++-
 test/recipes/25-test_x509.t               |  19 +-
 test/recipes/tconversion.pl               |  47 +++
 util/libcrypto.num                        |   3 +
 util/missingcrypto.txt                    |   2 -
 util/missingcrypto111.txt                 |   1 -
 util/missingmacro.txt                     |   1 +
 40 files changed, 988 insertions(+), 599 deletions(-)
 rename crypto/x509/{v3_akey.c => v3_akid.c} (76%)
 rename crypto/x509/{v3_alt.c => v3_san.c} (99%)
 rename crypto/x509/{v3_skey.c => v3_skid.c} (68%)
 delete mode 100644 doc/internal/man3/s2i_ASN1_UTF8STRING.pod
 create mode 100644 doc/man3/X509V3_set_ctx.pod
 delete mode 100644 include/crypto/x509v3.h
 create mode 100644 test/certs/ext-check.csr

diff --git a/CHANGES.md b/CHANGES.md
index 65031b89a5..ac0b22c6fb 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -42,9 +42,9 @@ OpenSSL 3.0
 
    *Otto Hollmann*
 
- * The -cipher-commands and -digest-commands options of the command line
-   utility list has been deprecated.
-   Instead use the -cipher-algorithms and -digest-algorithms options.
+ * The `-cipher-commands` and `-digest-commands` options
+   of the command line utility `list` have been deprecated.
+   Instead use the `-cipher-algorithms` and `-digest-algorithms` options.
 
    *Dmitry Belyavskiy*
 
@@ -80,11 +80,11 @@ OpenSSL 3.0
 
    *Matt Caswell*
 
- * The -crypt option to the passwd command line tool has been removed.
+ * The `-crypt` option to the `passwd` command line tool has been removed.
 
    *Paul Dale*
 
- * The -C option to the x509, dhparam, dsaparam, and ecparam commands
+ * The -C option to the `x509`, `dhparam`, `dsaparam`, and `ecparam` commands
    were removed.
 
    *Rich Salz*
@@ -139,8 +139,8 @@ OpenSSL 3.0
 
    *Richard Levitte*
 
- * Deprecated EVP_PKEY_CTX_set_rsa_keygen_pubexp() & introduced
-   EVP_PKEY_CTX_set1_rsa_keygen_pubexp(), which is now preferred.
+ * Deprecated `EVP_PKEY_CTX_set_rsa_keygen_pubexp()` and introduced
+   `EVP_PKEY_CTX_set1_rsa_keygen_pubexp()`, which is now preferred.
 
    *Jeremy Walch*
 
@@ -156,7 +156,7 @@ OpenSSL 3.0
    implemented by EVP_RAND and EVP_RAND_CTX. The main reason is that the
    RAND_DRBG API is a mixture of 'front end' and 'back end' API calls
    and some of its API calls are rather low-level. This holds in particular
-   for the callback mechanism (RAND_DRBG_set_callbacks()).
+   for the callback mechanism (`RAND_DRBG_set_callbacks()`).
 
    Adding a compatibility layer to continue supporting the RAND_DRBG API as
    a legacy API for a regular deprecation period turned out to come at the
@@ -166,7 +166,7 @@ OpenSSL 3.0
 
    *Paul Dale and Matthias St. Pierre*
 
- * Allow SSL_set1_host() and SSL_add1_host() to take IP literal addresses
+ * Allow `SSL_set1_host()` and `SSL_add1_host()` to take IP literal addresses
    as well as actual hostnames.
 
    *David Woodhouse*
@@ -180,7 +180,7 @@ OpenSSL 3.0
    and DTLS.
 
    SSL_CTX instances that are created for a fixed protocol version (e.g.
-   TLSv1_server_method()) also silently ignore version bounds.  Previously
+   `TLSv1_server_method()`) also silently ignore version bounds.  Previously
    attempts to apply bounds to these protocol versions would result in an
    error.  Now only the "version-flexible" SSL_CTX instances are subject to
    limits in configuration files in command-line options.
@@ -244,14 +244,13 @@ OpenSSL 3.0
 
    *Tomas Mraz*
 
- * Dropped interactive mode from the 'openssl' program.  From now on,
-   the `openssl` command without arguments is equivalent to `openssl
-   help`.
+ * Dropped interactive mode from the `openssl` program.  From now on,
+   running it without arguments is equivalent to `openssl help`.
 
    *Richard Levitte*
 
- * Renamed EVP_PKEY_cmp() to EVP_PKEY_eq() and
-   EVP_PKEY_cmp_parameters() to EVP_PKEY_parameters_eq().
+ * Renamed `EVP_PKEY_cmp()` to `EVP_PKEY_eq()` and
+   `EVP_PKEY_cmp_parameters()` to `EVP_PKEY_parameters_eq()`.
    While the old function names have been retained for backward compatibility
    they should not be used in new developments
    because their return values are confusing: Unlike other `_cmp()` functions
@@ -259,8 +258,8 @@ OpenSSL 3.0
 
    *David von Oheimb*
 
- * Deprecated EC_METHOD_get_field_type(). Applications should switch to
-   EC_GROUP_get_field_type().
+ * Deprecated `EC_METHOD_get_field_type()`. Applications should switch to
+   `EC_GROUP_get_field_type()`.
 
    *Billy Bob Brumley*
 
@@ -339,7 +338,7 @@ OpenSSL 3.0
    reduced. This results in SSL 3, TLS 1.0, TLS 1.1 and DTLS 1.0 no longer
    working at the default security level of 1 and instead requires security
    level 0. The security level can be changed either using the cipher string
-   with @SECLEVEL, or calling SSL_CTX_set_security_level().
+   with `@SECLEVEL`, or calling `SSL_CTX_set_security_level()`.
 
    *Kurt Roeckx*
 
@@ -396,14 +395,14 @@ OpenSSL 3.0
    *Richard Levitte*
 
  * Added an implementation of CMP and CRMF (RFC 4210, RFC 4211 RFC 6712).
-   This adds crypto/cmp/, crpyto/crmf/, apps/cmp.c, and test/cmp_*.
+   This adds `crypto/cmp/`, `crpyto/crmf/`, `apps/cmp.c`, and `test/cmp_*`.
    See L<openssl-cmp(1)> and L<OSSL_CMP_exec_IR_ses(3)> as starting points.
 
    *David von Oheimb, Martin Peylo*
 
- * Generalized the HTTP client code from crypto/ocsp/ into crpyto/http/.
-   The legacy OCSP-focused and only partly documented API is retained.
-   See L<OSSL_CMP_MSG_http_perform(3)> etc. for details.
+ * Generalized the HTTP client code from `crypto/ocsp/` into `crpyto/http/`.
+   The legacy OCSP-focused and only partly documented API is retained for
+   backward compatibility. See L<OSSL_CMP_MSG_http_perform(3)> etc. for details.
 
    *David von Oheimb*
 
@@ -414,9 +413,9 @@ OpenSSL 3.0
 
    *David von Oheimb*
 
- * BIO_do_connect and BIO_do_handshake have been extended:
+ * `BIO_do_connect()` and `BIO_do_handshake()` have been extended:
    If domain name resolution yields multiple IP addresses all of them are tried
-   after connect() failures.
+   after `connect()` failures.
 
    *David von Oheimb*
 
@@ -461,13 +460,13 @@ OpenSSL 3.0
  * X509 certificates signed using SHA1 are no longer allowed at security
    level 1 and above.
    In TLS/SSL the default security level is 1. It can be set either
-   using the cipher string with @SECLEVEL, or calling
-   SSL_CTX_set_security_level(). If the leaf certificate is signed with SHA-1,
-   a call to SSL_CTX_use_certificate() will fail if the security level is not
+   using the cipher string with `@SECLEVEL`, or calling
+   `SSL_CTX_set_security_level()`. If the leaf certificate is signed with SHA-1,
+   a call to `SSL_CTX_use_certificate()` will fail if the security level is not
    lowered first.
    Outside TLS/SSL, the default security level is -1 (effectively 0). It can
-   be set using X509_VERIFY_PARAM_set_auth_level() or using the -auth_level
-   options of the apps.
+   be set using `X509_VERIFY_PARAM_set_auth_level()` or using the `-auth_level`
+   options of the commands.
 
    *Kurt Roeckx*
 
@@ -514,10 +513,11 @@ OpenSSL 3.0
    OSSL_DECODER and OSSL_ENCODER APIs to read and write DH files.
 
    Finaly functions that assign or obtain DH objects from an EVP_PKEY such as
-   EVP_PKEY_assign_DH(), EVP_PKEY_get0_DH, EVP_PKEY_get1_DH, EVP_PKEY_set1_DH
-   are also deprecated. Applications should instead either read or write an
-   EVP_PKEY directly using the OSSL_DECODER and OSSL_ENCODER APIs. Or load an
-   EVP_PKEY directly from DH data using EVP_PKEY_fromdata().
+   `EVP_PKEY_assign_DH()`, `EVP_PKEY_get0_DH()`, `EVP_PKEY_get1_DH()`, and
+   `EVP_PKEY_set1_DH()` are also deprecated.
+   Applications should instead either read or write an
+   EVP_PKEY directly using the OSSL_DECODER and OSSL_ENCODER APIs.
+   Or load an    EVP_PKEY directly from DH data using `EVP_PKEY_fromdata()`.
 
    *Paul Dale and Matt Caswell*
 
@@ -551,7 +551,7 @@ OpenSSL 3.0
    automatically become EVP_PKEY_SM2 rather than EVP_PKEY_EC.
    This means that applications don't have to look at the curve NID and
    `EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)` to get SM2 computations.
-   However, they still can, that EVP_PKEY_set_alias_type() call acts as
+   However, they still can, that `EVP_PKEY_set_alias_type()` call acts as
    a no-op when the EVP_PKEY is already of the given type.
 
    Parameter and key generation is also reworked to make it possible
@@ -882,8 +882,8 @@ OpenSSL 3.0
 
    *Jon Spillett*
 
- * Deprecated the public definition of ERR_STATE as well as the function
-   ERR_get_state().  This is done in preparation of making ERR_STATE an
+ * Deprecated the public definition of `ERR_STATE` as well as the function
+   `ERR_get_state()`.  This is done in preparation of making `ERR_STATE` an
    opaque type.
 
    *Richard Levitte*
@@ -914,7 +914,23 @@ OpenSSL 3.0
 
    *Richard Levitte*
 
- * Added several checks to X509_verify_cert() according to requirements in
+ * Added the `<-copy_extensions` option to the `req` command for use with `-x509`.
+   When given with the `copy` or `copyall` argument,
+   any extensions present in the certification request are copied to the certificate.
+
+   *David von Oheimb*
+
+ * The `x509`, `req`, and `ca` commands now make sure that certificates they
+   generate are RFC 5280 compliant by default: For X.509 version 3 certs they ensure that
+   a subjectKeyIdentifier extension is included containing a hash value of the public key
+   and an authorityKeyIdentifier extension is included for not self-signed certs
+   containing a keyIdentifier field with the hash value identifying the signing key.
+   This is done unless some configuration overrides the new default behavior,
+   e.g. `authorityKeyIdentifier = none`.
+
+   *David von Oheimb*
+
+ * Added several checks to `X509_verify_cert()` according to requirements in
    RFC 5280 in case `X509_V_FLAG_X509_STRICT` is set
    (which may be done by using the CLI option `-x509_strict`):
    * The basicConstraints of CA certificates must be marked critical.
@@ -933,7 +949,7 @@ OpenSSL 3.0
 
    *David von Oheimb*
 
- * Certificate verification using X509_verify_cert() meanwhile rejects EC keys
+ * Certificate verification using `X509_verify_cert()` meanwhile rejects EC keys
    with explicit curve parameters (specifiedCurve) as required by RFC 5480.
 
    *Tomas Mraz*
@@ -1004,20 +1020,20 @@ OpenSSL 3.0
  * Changed the library initialisation so that the config file is now loaded
    by default. This was already the case for libssl. It now occurs for both
    libcrypto and libssl. Use the OPENSSL_INIT_NO_LOAD_CONFIG option to
-   OPENSSL_init_crypto() to suppress automatic loading of a config file.
+   `OPENSSL_init_crypto()` to suppress automatic loading of a config file.
 
    *Matt Caswell*
 
- * Introduced new error raising macros, ERR_raise() and ERR_raise_data(),
-   where the former acts as a replacement for ERR_put_error(), and the
-   latter replaces the combination ERR_put_error()+ERR_add_error_data().
-   ERR_raise_data() adds more flexibility by taking a format string and
+ * Introduced new error raising macros, `ERR_raise()` and `ERR_raise_data()`,
+   where the former acts as a replacement for `ERR_put_error()`, and the
+   latter replaces the combination `ERR_put_error()` + `ERR_add_error_data()`.
+   `ERR_raise_data()` adds more flexibility by taking a format string and
    an arbitrary number of arguments following it, to be processed with
-   BIO_snprintf().
+   `BIO_snprintf()`.
 
    *Richard Levitte*
 
- * Introduced a new function, OSSL_PROVIDER_available(), which can be used
+ * Introduced a new function, `OSSL_PROVIDER_available()`, which can be used
    to check if a named provider is loaded and available.  When called, it
    will also activate all fallback providers if such are still present.
 
@@ -1081,7 +1097,7 @@ OpenSSL 3.0
 
    *Paul Yang*
 
- * Use SHA256 as the default digest for TS query in the ts app.
+ * Use SHA256 as the default digest for TS query in the `ts` app.
 
    *Tomas Mraz*
 
@@ -1110,13 +1126,6 @@ OpenSSL 3.0
 
    *Richard Levitte*
 
- * Change the default RSA, DSA and DH size to 2048 bit instead of 1024.
-   This changes the size when using the genpkey app when no size is given. It
-   fixes an omission in earlier changes that changed all RSA, DSA and DH
-   generation apps to use 2048 bits by default.
-
-   *Kurt Roeckx*
-
  * Added command 'openssl kdf' that uses the EVP_KDF API.
 
    *Shane Lontis*
@@ -1178,7 +1187,7 @@ OpenSSL 3.0
    by registering BIOs as trace channels for a number of tracing and debugging
    categories.
 
-   The 'openssl' application has been expanded to enable any of the types
+   The `openssl` program has been expanded to enable any of the types
    available via environment variables defined by the user, and serves as
    one possible example on how to use this functionality.
 
@@ -1629,9 +1638,9 @@ OpenSSL 1.1.1
    *Patrick Steuer*
 
  * Change the default RSA, DSA and DH size to 2048 bit instead of 1024.
-   This changes the size when using the genpkey app when no size is given. It
-   fixes an omission in earlier changes that changed all RSA, DSA and DH
-   generation apps to use 2048 bits by default.
+   This changes the size when using the `genpkey` command when no size is given.
+   It fixes an omission in earlier changes that changed all RSA, DSA and DH
+   generation commands to use 2048 bits by default.
 
    *Kurt Roeckx*
 
@@ -1645,7 +1654,7 @@ OpenSSL 1.1.1
 
    *Matt Caswell*
 
- * Have apps like 's_client' and 's_server' output the signature scheme
+ * Have commands like `s_client` and `s_server` output the signature scheme
    along with other cipher suite parameters when debugging.
 
    *Lorinczy Zsigmond*
@@ -1870,7 +1879,7 @@ OpenSSL 1.1.1
 
    *Matt Caswell*
 
- * Enforce checking in the pkeyutl command line app to ensure that the input
+ * Enforce checking in the `pkeyutl` command to ensure that the input
    length does not exceed the maximum supported digest length when performing
    a sign, verify or verifyrecover operation.
 
@@ -2343,9 +2352,9 @@ OpenSSL 1.1.0
 ### Changes between 1.1.0j and 1.1.0k [28 May 2019]
 
  * Change the default RSA, DSA and DH size to 2048 bit instead of 1024.
-   This changes the size when using the genpkey app when no size is given. It
-   fixes an omission in earlier changes that changed all RSA, DSA and DH
-   generation apps to use 2048 bits by default.
+   This changes the size when using the `genpkey` command when no size is given.
+   It fixes an omission in earlier changes that changed all RSA, DSA and DH
+   generation commands to use 2048 bits by default.
 
    *Kurt Roeckx*
 
@@ -3136,7 +3145,7 @@ OpenSSL 1.1.0
 
  * Configuration change; it's now possible to build dynamic engines
    without having to build shared libraries and vice versa.  This
-   only applies to the engines in engines/, those in crypto/engine/
+   only applies to the engines in `engines/`, those in `crypto/engine/`
    will always be built into libcrypto (i.e. "static").
 
    Building dynamic engines is enabled by default; to disable, use
@@ -4140,9 +4149,9 @@ OpenSSL 1.0.2
 ### Changes between 1.0.2r and 1.0.2s [28 May 2019]
 
  * Change the default RSA, DSA and DH size to 2048 bit instead of 1024.
-   This changes the size when using the genpkey app when no size is given. It
-   fixes an omission in earlier changes that changed all RSA, DSA and DH
-   generation apps to use 2048 bits by default.
+   This changes the size when using the `genpkey` command when no size is given.
+   It fixes an omission in earlier changes that changed all RSA, DSA and DH
+   generation commands to use 2048 bits by default.
 
    *Kurt Roeckx*
 
@@ -4877,10 +4886,10 @@ OpenSSL 1.0.2
 
    *Andy Polyakov*
 
- * Change the req app to generate a 2048-bit RSA/DSA key by default,
+ * Change the `req` command to generate a 2048-bit RSA/DSA key by default,
    if no keysize is specified with default_bits. This fixes an
    omission in an earlier change that changed all RSA/DSA key generation
-   apps to use 2048 bits by default.
+   commands to use 2048 bits by default.
 
    *Emilia Käsper*
 
@@ -6079,10 +6088,10 @@ OpenSSL 1.0.1
 
    *Andy Polyakov*
 
- * Change the req app to generate a 2048-bit RSA/DSA key by default,
+ * Change the req command to generate a 2048-bit RSA/DSA key by default,
    if no keysize is specified with default_bits. This fixes an
    omission in an earlier change that changed all RSA/DSA key generation
-   apps to use 2048 bits by default.
+   commands to use 2048 bits by default.
 
    *Emilia Käsper*
 
@@ -7975,7 +7984,7 @@ OpenSSL 1.0.1.]
 
    *Steve Henson*
 
- * Add load_crls() function to apps tidying load_certs() too. Add option
+ * Add load_crls() function to commands tidying load_certs() too. Add option
    to verify utility to allow additional CRLs to be included.
 
    *Steve Henson*
@@ -7990,7 +7999,7 @@ OpenSSL 1.0.1.]
 
    *Julia Lawall <julia at diku.dk>*
 
- * Update verify callback code in apps/s_cb.c and apps/verify.c, it
+ * Update verify callback code in `apps/s_cb.c` and `apps/verify.c`, it
    needlessly dereferenced structures, used obsolete functions and
    didn't handle all updated verify codes correctly.
 
@@ -8420,7 +8429,7 @@ OpenSSL 1.0.1.]
    arranges the ciphersuites in reasonable order before starting
    to process the rule string.  Thus, the definition for "DEFAULT"
    (SSL_DEFAULT_CIPHER_LIST) now is just "ALL:!aNULL:!eNULL", but
-   remains equivalent to "AES:ALL:!aNULL:!eNULL:+aECDH:+kRSA:+RC4:@STRENGTH".
+   remains equivalent to `"AES:ALL:!aNULL:!eNULL:+aECDH:+kRSA:+RC4:@STRENGTH"`.
    This makes it much easier to arrive at a reasonable default order
    in applications for which anonymous ciphers are OK (meaning
    that you can't actually use DEFAULT).
@@ -9442,7 +9451,7 @@ OpenSSL 0.9.x
    - fixed x86nasm.pl to create correct asm files for NASM COFF output
    - added AES, WHIRLPOOL and CPUID assembler code to build files
    - added missing AES assembler make rules to mk1mf.pl
-   - fixed order of includes in apps/ocsp.c so that e_os.h settings apply
+   - fixed order of includes in `apps/ocsp.c` so that `e_os.h` settings apply
 
    *Guenter Knauf <eflash at gmx.net>*
 
@@ -9951,7 +9960,7 @@ OpenSSL 0.9.8.]
    *Nils Larsch*
 
  * Use SHA-1 instead of MD5 as the default digest algorithm for
-   the apps/openssl applications.
+   the `apps/openssl` commands.
 
    *Nils Larsch*
 
@@ -11734,7 +11743,7 @@ OpenSSL 0.9.7.]
 
  * Add the configuration target debug-linux-ppro.
    Make 'openssl rsa' use the general key loading routines
-   implemented in apps.c, and make those routines able to
+   implemented in `apps.c`, and make those routines able to
    handle the key format FORMAT_NETSCAPE and the variant
    FORMAT_IISSGC.
 
@@ -12229,12 +12238,13 @@ s-cbc           3624.96k     5258.21k     5530.91k     5624.30k     5628.26k
 
    *"Brian Havard" <brianh at kheldar.apana.org.au> and Richard Levitte*
 
- * Rewrite apps to use NCONF routines instead of the old CONF. New functions
-   to support NCONF routines in extension code. New function CONF_set_nconf()
-   to allow functions which take an NCONF to also handle the old LHASH
-   structure: this means that the old CONF compatible routines can be
-   retained (in particular wrt extensions) without having to duplicate the
-   code. New function X509V3_add_ext_nconf_sk to add extensions to a stack.
+ * Rewrite commands to use `NCONF` routines instead of the old `CONF`.
+   New functions to support `NCONF `routines in extension code.
+   New function `CONF_set_nconf()`
+   to allow functions which take an `NCONF` to also handle the old `LHASH`
+   structure: this means that the old `CONF` compatible routines can be
+   retained (in particular w.rt. extensions) without having to duplicate the
+   code. New function `X509V3_add_ext_nconf_sk()` to add extensions to a stack.
 
    *Steve Henson*
 
@@ -12739,7 +12749,7 @@ s-cbc           3624.96k     5258.21k     5530.91k     5624.30k     5628.26k
 
    *Steve Henson*
 
- * Disable stdin buffering in load_cert (apps/apps.c) so that no certs are
+ * Disable stdin buffering in `load_cert()` (`apps/apps.c`) so that no certs are
    skipped when using openssl x509 multiple times on a single input file,
    e.g. `(openssl x509 -out cert1; openssl x509 -out cert2) <certs`.
 
@@ -13099,7 +13109,7 @@ s-cbc           3624.96k     5258.21k     5530.91k     5624.30k     5628.26k
 
    *Steve Henson*
 
- * Add functionality to apps/openssl.c for detecting locking
+ * Add functionality to `apps/openssl.c` for detecting locking
    problems: As the program is single-threaded, all we have
    to do is register a locking callback using an array for
    storing which locks are currently held by the program.
@@ -13707,7 +13717,7 @@ s-cbc           3624.96k     5258.21k     5530.91k     5624.30k     5628.26k
 
    *Nils Larsch <nla at trustcenter.de>; problem pointed out by Bodo Moeller*
 
- * Check various `X509_...()` return values in apps/req.c.
+ * Check various `X509_...()` return values in `apps/req.c`.
 
    *Nils Larsch <nla at trustcenter.de>*
 
@@ -15268,7 +15278,7 @@ s-cbc           3624.96k     5258.21k     5530.91k     5624.30k     5628.26k
 
    *Steve Henson*
 
- * Bugfixes in apps/x509.c: Avoid a memory leak; and don't use
+ * Bugfixes in `apps/x509.c`: Avoid a memory leak; and don't use
    perror when PEM_read_bio_X509_REQ fails, the error message must
    be obtained from the error queue.
 
@@ -15833,7 +15843,7 @@ s-cbc           3624.96k     5258.21k     5530.91k     5624.30k     5628.26k
 
    The syntax for the cipher sorting has been extended to support sorting by
    cipher-strength (using the strength_bits hard coded in the tables).
-   The new command is "@STRENGTH" (see also doc/apps/ciphers.pod).
+   The new command is `@STRENGTH` (see also `doc/apps/ciphers.pod`).
 
    Fix a bug in the cipher-command parser: when supplying a cipher command
    string with an "undefined" symbol (neither command nor alphanumeric
@@ -16286,7 +16296,7 @@ s-cbc           3624.96k     5258.21k     5530.91k     5624.30k     5628.26k
    because it isn't possible to mix certificates and CRLs in DER format
    without choking one or the other routine. Changed this to just read
    a certificate: this is the best we can do. Also modified the code
-   in apps/verify.c to take notice of return codes: it was previously
+   in `apps/verify.c` to take notice of return codes: it was previously
    attempting to read in certificates from NULL pointers and ignoring
    any errors: this is one reason why the cert and CRL reader seemed
    to work. It doesn't check return codes from the default certificate
@@ -16459,7 +16469,7 @@ s-cbc           3624.96k     5258.21k     5530.91k     5624.30k     5628.26k
 
    *Bodo Moeller*
 
- * New file apps/app_rand.c with commonly needed functionality
+ * New file `apps/app_rand.c` with commonly needed functionality
    for handling the random seed file.
 
    Use the random seed file in some applications that previously did not:
@@ -17190,7 +17200,7 @@ ndif
 
    *Steve Henson*
 
- * Set #! path to perl in apps/der_chop to where we found it
+ * Set #! path to perl in `apps/der_chop` to where we found it
    instead of using a fixed path.
 
    *Bodo Moeller*
@@ -18065,14 +18075,14 @@ ndif
 
    *Eric A. Young, (from changes to C2Net SSLeay, integrated by Mark Cox)*
 
- * Run extensive memory leak checks on SSL apps. Fixed *lots* of memory
-   leaks in ssl/ relating to new X509_get_pubkey() behaviour. Also fixes
-   in apps/ and an unrelated leak in crypto/dsa/dsa_vrf.c
+ * Run extensive memory leak checks on SSL commands. Fixed *lots* of memory
+   leaks in `ssl/` relating to new `X509_get_pubkey()` behaviour. Also fixes
+   in `apps/` and an unrelated leak in `crypto/dsa/dsa_vrf.c`.
 
    *Steve Henson*
 
  * Support for RAW extensions where an arbitrary extension can be
-   created by including its DER encoding. See apps/openssl.cnf for
+   created by including its DER encoding. See `apps/openssl.cnf` for
    an example.
 
    *Steve Henson*
@@ -18331,7 +18341,7 @@ ndif
 
    *Ben Laurie*
 
- * Get the gendsa program working (hopefully) and add it to app list. Remove
+ * Get the `gendsa` command working and add it to the `list` command. Remove
    encryption from sample DSA keys (in case anyone is interested the password
    was "1234").
 
@@ -18350,7 +18360,7 @@ ndif
 
    *Bodo Moeller <3moeller at informatik.uni-hamburg.de>*
 
- * Don't blow it for numeric -newkey arguments to apps/req.
+ * Don't blow it for numeric `-newkey` arguments to `apps/req`.
 
    *Bodo Moeller <3moeller at informatik.uni-hamburg.de>*
 
@@ -18390,7 +18400,7 @@ ndif
 
    *Ralf S. Engelschall*
 
- * Fix the various library and apps files to free up pkeys obtained from
+ * Fix the various library and `apps/` files to free up pkeys obtained from
    X509_PUBKEY_get() et al. Also allow x509.c to handle netscape extensions.
 
    *Steve Henson*
@@ -18400,7 +18410,7 @@ ndif
 
    *Steve Henson and Ben Laurie*
 
- * First cut of a cleanup for apps/. First the `ssleay` program is now named
+ * First cut of a cleanup for `apps/`. First the `ssleay` program is now named
    `openssl` and second, the shortcut symlinks for the `openssl <command>`
    are no longer created. This way we have a single and consistent command
    line interface `openssl <command>`, similar to `cvs <command>`.
@@ -18550,11 +18560,13 @@ ndif
    *Ralf S. Engelschall*
 
  * Removed dummy files from the 0.9.1b source tree:
+   ```
    crypto/asn1/x crypto/bio/cd crypto/bio/fg crypto/bio/grep crypto/bio/vi
    crypto/bn/asm/......add.c crypto/bn/asm/a.out crypto/dsa/f crypto/md5/f
    crypto/pem/gmon.out crypto/perlasm/f crypto/pkcs7/build crypto/rsa/f
    crypto/sha/asm/f crypto/threads/f ms/zzz ssl/f ssl/f.mak test/f
    util/f.mak util/pl/f util/pl/f.mak crypto/bf/bf_locl.old apps/f
+   ```
 
    *Ralf S. Engelschall*
 
diff --git a/apps/ca.c b/apps/ca.c
index 2772072b79..d97be7568e 100755
--- a/apps/ca.c
+++ b/apps/ca.c
@@ -494,9 +494,7 @@ end_of_options:
     argc = opt_num_rest();
     argv = opt_rest();
 
-    BIO_printf(bio_err, "Using configuration from %s\n", configfile);
-
-    if ((conf = app_load_config(configfile)) == NULL)
+    if ((conf = app_load_config_verbose(configfile, 1)) == NULL)
         goto end;
     if (configfile != default_config_file && !app_load_modules(conf))
         goto end;
@@ -1482,6 +1480,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509,
     OPENSSL_STRING *irow = NULL;
     OPENSSL_STRING *rrow = NULL;
     char buf[25];
+    X509V3_CTX ext_ctx;
 
     for (i = 0; i < DB_NUMBER; i++)
         row[i] = NULL;
@@ -1699,8 +1698,6 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509,
 
     /* Lets add the extensions, if there are any */
     if (ext_sect) {
-        X509V3_CTX ext_ctx;
-
         /* Initialize the context structure */
         X509V3_set_ctx(&ext_ctx, selfsign ? ret : x509,
                        ret, req, NULL, X509V3_CTX_REPLACE);
@@ -1903,7 +1900,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509,
         !EVP_PKEY_missing_parameters(pkey))
         EVP_PKEY_copy_parameters(pktmp, pkey);
 
-    if (!do_X509_sign(ret, pkey, dgst, sigopts))
+    if (!do_X509_sign(ret, pkey, dgst, sigopts, &ext_ctx))
         goto end;
 
     /* We now just add it to the database as DB_TYPE_VAL('V') */
diff --git a/apps/include/apps.h b/apps/include/apps.h
index 0a8d6f4060..4bed7d7540 100644
--- a/apps/include/apps.h
+++ b/apps/include/apps.h
@@ -48,7 +48,7 @@
 void app_RAND_load_conf(CONF *c, const char *section);
 void app_RAND_write(void);
 
-extern char *default_config_file;
+extern char *default_config_file; /* may be "" */
 extern BIO *bio_in;
 extern BIO *bio_out;
 extern BIO *bio_err;
@@ -63,8 +63,10 @@ BIO *bio_open_owner(const char *filename, int format, int private);
 BIO *bio_open_default(const char *filename, char mode, int format);
 BIO *bio_open_default_quiet(const char *filename, char mode, int format);
 CONF *app_load_config_bio(BIO *in, const char *filename);
-CONF *app_load_config(const char *filename);
-CONF *app_load_config_quiet(const char *filename);
+#define app_load_config(filename) app_load_config_internal(filename, 0)
+#define app_load_config_quiet(filename) app_load_config_internal(filename, 1)
+CONF *app_load_config_internal(const char *filename, int quiet);
+CONF *app_load_config_verbose(const char *filename, int verbose);
 int app_load_modules(const CONF *config);
 CONF *app_load_config_modules(const char *configfile);
 void unbuffer(FILE *fp);
@@ -231,7 +233,7 @@ int init_gen_str(EVP_PKEY_CTX **pctx,
                  const char *algname, ENGINE *e, int do_param,
                  OSSL_LIB_CTX *libctx, const char *propq);
 int do_X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md,
-                 STACK_OF(OPENSSL_STRING) *sigopts);
+                 STACK_OF(OPENSSL_STRING) *sigopts, X509V3_CTX *ext_ctx);
 int do_X509_verify(X509 *x, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *vfyopts);
 int do_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md,
                      STACK_OF(OPENSSL_STRING) *sigopts);
diff --git a/apps/lib/apps.c b/apps/lib/apps.c
index 457dac87bc..d5654d9dc9 100644
--- a/apps/lib/apps.c
+++ b/apps/lib/apps.c
@@ -54,6 +54,9 @@ static int WIN32_rename(const char *from, const char *to);
 # define _kbhit kbhit
 #endif
 
+static BIO *bio_open_default_(const char *filename, char mode, int format,
+                              int quiet);
+
 #define PASS_SOURCE_SIZE_MAX 4
 
 DEFINE_STACK_OF(CONF)
@@ -379,29 +382,25 @@ CONF *app_load_config_bio(BIO *in, const char *filename)
     return NULL;
 }
 
-CONF *app_load_config(const char *filename)
+CONF *app_load_config_verbose(const char *filename, int verbose)
 {
-    BIO *in;
-    CONF *conf;
-
-    in = bio_open_default(filename, 'r', FORMAT_TEXT);
-    if (in == NULL)
-        return NULL;
-
-    conf = app_load_config_bio(in, filename);
-    BIO_free(in);
-    return conf;
+    if (verbose) {
+        if (*filename == '\0')
+            BIO_printf(bio_err, "No configuration used\n");
+        else
+            BIO_printf(bio_err, "Using configuration from %s\n", filename);
+    }
+    return app_load_config_internal(filename, 0);
 }
 
-CONF *app_load_config_quiet(const char *filename)
+CONF *app_load_config_internal(const char *filename, int quiet)
 {
-    BIO *in;
+    BIO *in = NULL; /* leads to empty config in case filename == "" */
     CONF *conf;
 
-    in = bio_open_default_quiet(filename, 'r', FORMAT_TEXT);
-    if (in == NULL)
+    if (*filename != '\0'
+        && (in = bio_open_default_(filename, 'r', FORMAT_TEXT, quiet)) == NULL)
         return NULL;
-
     conf = app_load_config_bio(in, filename);
     BIO_free(in);
     return conf;
@@ -457,9 +456,7 @@ CONF *app_load_config_modules(const char *configfile)
     CONF *conf = NULL;
 
     if (configfile != NULL) {
-        BIO_printf(bio_err, "Using configuration from %s\n", configfile);
-
-        if ((conf = app_load_config(configfile)) == NULL)
+        if ((conf = app_load_config_verbose(configfile, 1)) == NULL)
             return NULL;
         if (configfile != default_config_file && !app_load_modules(conf)) {
             NCONF_free(conf);
@@ -1982,12 +1979,41 @@ static int do_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey,
         && do_pkey_ctx_init(pkctx, sigopts);
 }
 
-/* Ensure RFC 5280 compliance and then sign the certificate info */
+static int adapt_keyid_ext(X509 *cert, X509V3_CTX *ext_ctx,
+                           const char *name, const char *value, int add_default)
+{
+    const STACK_OF(X509_EXTENSION) *exts = X509_get0_extensions(cert);
+    X509_EXTENSION *new_ext = X509V3_EXT_nconf(NULL, ext_ctx, name, value);
+    int idx, rv = 0;
+
+    if (new_ext == NULL)
+        return rv;
+
+    idx = X509v3_get_ext_by_OBJ(exts, X509_EXTENSION_get_object(new_ext), -1);
+    if (idx >= 0) {
+        X509_EXTENSION *found_ext = X509v3_get_ext(exts, idx);
+        ASN1_OCTET_STRING *data = X509_EXTENSION_get_data(found_ext);
+        int disabled = ASN1_STRING_length(data) <= 2; /* config said "none" */
+
+        if (disabled) {
+            X509_delete_ext(cert, idx);
+            X509_EXTENSION_free(found_ext);
+        } /* else keep existing key identifier, which might be outdated */
+        rv = 1;
+    } else  {
+        rv = !add_default || X509_add_ext(cert, new_ext, -1);
+    }
+    X509_EXTENSION_free(new_ext);
+    return rv;
+}
+
+/* Ensure RFC 5280 compliance, adapt keyIDs as needed, and sign the cert info */
 int do_X509_sign(X509 *cert, EVP_PKEY *pkey, const EVP_MD *md,
-                 STACK_OF(OPENSSL_STRING) *sigopts)
+                 STACK_OF(OPENSSL_STRING) *sigopts, X509V3_CTX *ext_ctx)
 {
     const STACK_OF(X509_EXTENSION) *exts = X509_get0_extensions(cert);
     EVP_MD_CTX *mctx = EVP_MD_CTX_new();
+    int self_sign;
     int rv = 0;
 
     if (sk_X509_EXTENSION_num(exts /* may be NULL */) > 0) {
@@ -1995,6 +2021,21 @@ int do_X509_sign(X509 *cert, EVP_PKEY *pkey, const EVP_MD *md,
         if (!X509_set_version(cert, 2)) /* Make sure cert is X509 v3 */
             goto end;
 
+        /*
+         * Add default SKID before such that default AKID can make use of it
+         * in case the certificate is self-signed
+         */
+        /* Prevent X509_V_ERR_MISSING_SUBJECT_KEY_IDENTIFIER */
+        if (!adapt_keyid_ext(cert, ext_ctx, "subjectKeyIdentifier", "hash", 1))
+            goto end;
+        /* Prevent X509_V_ERR_MISSING_AUTHORITY_KEY_IDENTIFIER */
+        ERR_set_mark();
+        self_sign = X509_check_private_key(cert, pkey);
+        ERR_pop_to_mark();
+        if (!adapt_keyid_ext(cert, ext_ctx, "authorityKeyIdentifier",
+                             "keyid, issuer", !self_sign))
+            goto end;
+
         /* TODO any further measures for ensuring default RFC 5280 compliance */
     }
 
@@ -2745,7 +2786,7 @@ static BIO *bio_open_default_(const char *filename, char mode, int format,
         if (ret != NULL)
             return ret;
         BIO_printf(bio_err,
-                   "Can't open %s for %s, %s\n",
+                   "Can't open \"%s\" for %s, %s\n",
                    filename, modeverb(mode), strerror(errno));
     }
     ERR_print_errors(bio_err);
diff --git a/apps/lib/opt.c b/apps/lib/opt.c
index 22d4138301..9675bc474d 100644
--- a/apps/lib/opt.c
+++ b/apps/lib/opt.c
@@ -370,7 +370,8 @@ int opt_md(const char *name, const EVP_MD **mdp)
     *mdp = EVP_get_digestbyname(name);
     if (*mdp != NULL)
         return 1;
-    opt_printf_stderr("%s: Unknown message digest: %s\n", prog, name);
+    opt_printf_stderr("%s: Unknown option or message digest: %s\n", prog,
+                      name != NULL ? name : "\"\"");
     return 0;
 }
 
diff --git a/apps/req.c b/apps/req.c
index acd0cd09cb..8c66f2a5fb 100644
--- a/apps/req.c
+++ b/apps/req.c
@@ -30,23 +30,24 @@
 # include <openssl/dsa.h>
 #endif
 
-#define BITS            "default_bits"
-#define KEYFILE         "default_keyfile"
-#define PROMPT          "prompt"
-#define DISTINGUISHED_NAME      "distinguished_name"
-#define ATTRIBUTES      "attributes"
-#define V3_EXTENSIONS   "x509_extensions"
-#define REQ_EXTENSIONS  "req_extensions"
-#define STRING_MASK     "string_mask"
-#define UTF8_IN         "utf8"
-
-#define DEFAULT_KEY_LENGTH      2048
-#define MIN_KEY_LENGTH          512
-
-static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *dn, int mutlirdn,
-                    int attribs, unsigned long chtype);
-static int build_subject(X509_REQ *req, const char *subj, unsigned long chtype,
-                         int multirdn);
+#define BITS               "default_bits"
+#define KEYFILE            "default_keyfile"
+#define PROMPT             "prompt"
+#define DISTINGUISHED_NAME "distinguished_name"
+#define ATTRIBUTES         "attributes"
+#define V3_EXTENSIONS      "x509_extensions"
+#define REQ_EXTENSIONS     "req_extensions"
+#define STRING_MASK        "string_mask"
+#define UTF8_IN            "utf8"
+
+#define DEFAULT_KEY_LENGTH 2048
+#define MIN_KEY_LENGTH     512
+#define DEFAULT_DAYS       30 /* default cert validity period in days */
+#define UNSET_DAYS         -2 /* -1 may be used for testing expiration checks */
+#define EXT_COPY_UNSET     -1
+
+static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, X509_NAME *fsubj,
+                    int mutlirdn, int attribs, unsigned long chtype);
 static int prompt_info(X509_REQ *req,
                        STACK_OF(CONF_VALUE) *dn_sk, const char *dn_sect,
                        STACK_OF(CONF_VALUE) *attr_sk, const char *attr_sect,
@@ -61,11 +62,9 @@ static int add_DN_object(X509_NAME *n, char *text, const char *def,
                          char *value, int nid, int n_min, int n_max,
                          unsigned long chtype, int mval);
 static int genpkey_cb(EVP_PKEY_CTX *ctx);
-static int build_data(char *text, const char *def,
-                      char *value, int n_min, int n_max,
-                      char *buf, const int buf_size,
-                      const char *desc1, const char *desc2
-                      );
+static int build_data(char *text, const char *def, char *value,
+                      int n_min, int n_max, char *buf, const int buf_size,
+                      const char *desc1, const char *desc2);
 static int req_check_len(int len, int n_min, int n_max);
 static int check_end(const char *str, const char *end);
 static int join(char buf[], size_t buf_size, const char *name,
@@ -87,7 +86,9 @@ typedef enum OPTION_choice {
     OPT_PKEYOPT, OPT_SIGOPT, OPT_VFYOPT, OPT_BATCH, OPT_NEWHDR, OPT_MODULUS,
     OPT_VERIFY, OPT_NOENC, OPT_NODES, OPT_NOOUT, OPT_VERBOSE, OPT_UTF8,
     OPT_NAMEOPT, OPT_REQOPT, OPT_SUBJ, OPT_SUBJECT, OPT_TEXT, OPT_X509,
-    OPT_MULTIVALUE_RDN, OPT_DAYS, OPT_SET_SERIAL, OPT_ADDEXT, OPT_EXTENSIONS,
+    OPT_CA, OPT_CAKEY,
+    OPT_MULTIVALUE_RDN, OPT_DAYS, OPT_SET_SERIAL,
+    OPT_COPY_EXTENSIONS, OPT_ADDEXT, OPT_EXTENSIONS,
     OPT_REQEXTS, OPT_PRECERT, OPT_MD,
     OPT_SECTION,
     OPT_R_ENUM, OPT_PROV_ENUM
@@ -101,9 +102,9 @@ const OPTIONS req_options[] = {
     {"keygen_engine", OPT_KEYGEN_ENGINE, 's',
      "Specify engine to be used for key generation operations"},
 #endif
-    {"in", OPT_IN, '<', "Input file"},
+    {"in", OPT_IN, '<', "X.509 request input file"},
     {"inform", OPT_INFORM, 'F', "Input format - DER or PEM"},
-    {"verify", OPT_VERIFY, '-', "Verify signature on REQ"},
+    {"verify", OPT_VERIFY, '-', "Verify self-signature on the request"},
 
     OPT_SECTION("Certificate"),
     {"new", OPT_NEW, '-', "New request"},
@@ -115,13 +116,19 @@ const OPTIONS req_options[] = {
     {"text", OPT_TEXT, '-', "Text form of request"},
     {"x509", OPT_X509, '-',
      "Output an x509 structure instead of a cert request"},
+    {"CA", OPT_CA, '<', "Issuer certificate to use with -x509"},
+    {"CAkey", OPT_CAKEY, 's',
+     "Issuer private key to use with -x509; default is -CA arg"},
     {OPT_MORE_STR, 1, 1, "(Required by some CA's)"},
-    {"subj", OPT_SUBJ, 's', "Set or modify request subject"},
-    {"subject", OPT_SUBJECT, '-', "Output the request's subject"},
+    {"subj", OPT_SUBJ, 's', "Set or modify subject of request or cert"},
+    {"subject", OPT_SUBJECT, '-',
+     "Print the subject of the output request or cert"},
     {"multivalue-rdn", OPT_MULTIVALUE_RDN, '-',
      "Deprecated; multi-valued RDNs support is always on."},
     {"days", OPT_DAYS, 'p', "Number of days cert is valid for"},
     {"set_serial", OPT_SET_SERIAL, 's', "Serial number to use"},
+    {"copy_extensions", OPT_COPY_EXTENSIONS, 's',
+     "copy extensions from request when using -x509"},
     {"addext", OPT_ADDEXT, 's',
      "Additional cert extension key=value pair (may be given more than once)"},
     {"extensions", OPT_EXTENSIONS, 's',
@@ -134,8 +141,8 @@ const OPTIONS req_options[] = {
     {"key", OPT_KEY, 's', "Private key to use"},
     {"keyform", OPT_KEYFORM, 'f', "Key file format (ENGINE, other values ignored)"},
     {"pubkey", OPT_PUBKEY, '-', "Output public key"},
-    {"keyout", OPT_KEYOUT, '>', "File to send the key to"},
-    {"passin", OPT_PASSIN, 's', "Private key password source"},
+    {"keyout", OPT_KEYOUT, '>', "File to save newly created private key"},
+    {"passin", OPT_PASSIN, 's', "Private key and certificate password source"},
     {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"},
     {"newkey", OPT_NEWKEY, 's', "Specify as type:bits"},
     {"pkeyopt", OPT_PKEYOPT, 's', "Public key options as opt:value"},
@@ -160,7 +167,6 @@ const OPTIONS req_options[] = {
     {NULL}
 };
 
-
 /*
  * An LHASH of strings, where each string is an extension name.
  */
@@ -180,9 +186,8 @@ static void exts_cleanup(OPENSSL_STRING *x)
 }
 
 /*
- * Is the |kv| key already duplicated?  This is remarkably tricky to get
- * right.  Return 0 if unique, -1 on runtime error; 1 if found or a syntax
- * error.
+ * Is the |kv| key already duplicated? This is remarkably tricky to get right.
+ * Return 0 if unique, -1 on runtime error; 1 if found or a syntax error.
  */
 static int duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv)
 {
@@ -211,7 +216,7 @@ static int duplicated(LHASH_OF(OPENSSL_STRING) *addexts, char *kv)
     *p = '\0';
 
     /* Finally have a clean "key"; see if it's there [by attempt to add it]. */
-    p = (char *)lh_OPENSSL_STRING_insert(addexts, (OPENSSL_STRING*)kv);
+    p = (char *)lh_OPENSSL_STRING_insert(addexts, (OPENSSL_STRING *)kv);
     if (p != NULL) {
         OPENSSL_free(p);
         return 1;
@@ -228,30 +233,34 @@ int req_main(int argc, char **argv)
     ASN1_INTEGER *serial = NULL;
     BIO *out = NULL;
     ENGINE *e = NULL, *gen_eng = NULL;
-    EVP_PKEY *pkey = NULL;
+    EVP_PKEY *pkey = NULL, *CAkey = NULL;
     EVP_PKEY_CTX *genctx = NULL;
     STACK_OF(OPENSSL_STRING) *pkeyopts = NULL, *sigopts = NULL, *vfyopts = NULL;
     LHASH_OF(OPENSSL_STRING) *addexts = NULL;
-    X509 *x509ss = NULL;
+    X509 *new_x509 = NULL, *CAcert = NULL;
     X509_REQ *req = NULL;
     const EVP_CIPHER *cipher = NULL;
     const EVP_MD *md_alg = NULL, *digest = NULL;
+    int ext_copy = EXT_COPY_UNSET;
     BIO *addext_bio = NULL;
-    char *extensions = NULL, *infile = NULL;
+    char *extensions = NULL;
+    const char *infile = NULL, *CAfile = NULL, *CAkeyfile = NULL;
     char *outfile = NULL, *keyfile = NULL;
     char *keyalgstr = NULL, *p, *prog, *passargin = NULL, *passargout = NULL;
     char *passin = NULL, *passout = NULL;
     char *nofree_passin = NULL, *nofree_passout = NULL;
     char *req_exts = NULL, *subj = NULL;
+    X509_NAME *fsubj = NULL;
     char *template = default_config_file, *keyout = NULL;
     const char *keyalg = NULL;
     OPTION_CHOICE o;
-    int ret = 1, x509 = 0, days = 0, i = 0, newreq = 0, verbose = 0;
-    int pkey_type = -1, private = 0;
+    int days = UNSET_DAYS;
+    int ret = 1, gen_x509 = 0, i = 0, newreq = 0, verbose = 0;
+    int pkey_type = -1;
     int informat = FORMAT_PEM, outformat = FORMAT_PEM, keyform = FORMAT_PEM;
     int modulus = 0, multirdn = 1, verify = 0, noout = 0, text = 0;
     int noenc = 0, newhdr = 0, subject = 0, pubkey = 0, precert = 0;
-    long newkey = -1;
+    long newkey_len = -1;
     unsigned long chtype = MBSTRING_ASC, reqflag = 0;
 
 #ifndef OPENSSL_NO_DES
@@ -392,10 +401,21 @@ int req_main(int argc, char **argv)
             text = 1;
             break;
         case OPT_X509:
-            x509 = 1;
+            gen_x509 = 1;
+            break;
+        case OPT_CA:
+            CAfile = opt_arg();
+            break;
+        case OPT_CAKEY:
+            CAkeyfile = opt_arg();
             break;
         case OPT_DAYS:
             days = atoi(opt_arg());
+            if (days < -1) {
+                BIO_printf(bio_err, "%s: -days parameter arg must be >= -1\n",
+                           prog);
+                goto end;
+            }
             break;
         case OPT_SET_SERIAL:
             if (serial != NULL) {
@@ -415,6 +435,13 @@ int req_main(int argc, char **argv)
         case OPT_MULTIVALUE_RDN:
             /* obsolete */
             break;
+        case OPT_COPY_EXTENSIONS:
+            if (!set_ext_copy(&ext_copy, opt_arg())) {
+                BIO_printf(bio_err, "Invalid extension copy option: \"%s\"\n",
+                           opt_arg());
+                goto end;
+            }
+            break;
         case OPT_ADDEXT:
             p = opt_arg();
             if (addexts == NULL) {
@@ -453,22 +480,21 @@ int req_main(int argc, char **argv)
     if (argc != 0)
         goto opthelp;
 
-    if (days && !x509)
-        BIO_printf(bio_err, "Ignoring -days; not generating a certificate\n");
-    if (x509 && infile == NULL)
+    if (!gen_x509) {
+        if (days != UNSET_DAYS)
+            BIO_printf(bio_err, "Ignoring -days without -x509; not generating a certificate\n");
+        if (ext_copy == EXT_COPY_NONE)
+            BIO_printf(bio_err, "Ignoring -copy_extensions 'none' when -x509 is not given\n");
+    }
+    if (gen_x509 && infile == NULL)
         newreq = 1;
 
-    /* TODO: simplify this as pkey is still always NULL here */
-    private = newreq && (pkey == NULL) ? 1 : 0;
-
     if (!app_passwd(passargin, passargout, &passin, &passout)) {
         BIO_printf(bio_err, "Error getting passwords\n");
         goto end;
     }
 
-    if (verbose)
-        BIO_printf(bio_err, "Using configuration from %s\n", template);
-    if ((req_conf = app_load_config(template)) == NULL)
+    if ((req_conf = app_load_config_verbose(template, verbose)) == NULL)
         goto end;
     if (addext_bio != NULL) {
         if (verbose)
@@ -489,10 +515,11 @@ int req_main(int argc, char **argv)
 
             oid_bio = BIO_new_file(p, "r");
             if (oid_bio == NULL) {
-                /*-
-                BIO_printf(bio_err,"problems opening %s for extra oid's\n",p);
-                ERR_print_errors(bio_err);
-                */
+                if (verbose) {
+                    BIO_printf(bio_err,
+                               "Problems opening '%s' for extra OIDs\n", p);
+                    ERR_print_errors(bio_err);
+                }
             } else {
                 OBJ_create_objects(oid_bio);
                 BIO_free(oid_bio);
@@ -521,17 +548,20 @@ int req_main(int argc, char **argv)
     if (extensions != NULL) {
         /* Check syntax of file */
         X509V3_CTX ctx;
+
         X509V3_set_ctx_test(&ctx);
         X509V3_set_nconf(&ctx, req_conf);
         if (!X509V3_EXT_add_nconf(req_conf, &ctx, extensions, NULL)) {
             BIO_printf(bio_err,
-                       "Error checking x509 extension section %s\n", extensions);
+                       "Error checking x509 extension section %s\n",
+                       extensions);
             goto end;
         }
     }
     if (addext_conf != NULL) {
         /* Check syntax of command line extensions */
         X509V3_CTX ctx;
+
         X509V3_set_ctx_test(&ctx);
         X509V3_set_nconf(&ctx, addext_conf);
         if (!X509V3_EXT_add_nconf(addext_conf, &ctx, "default", NULL)) {
@@ -579,6 +609,7 @@ int req_main(int argc, char **argv)
     if (req_exts != NULL) {
         /* Check syntax of file */
         X509V3_CTX ctx;
+
         X509V3_set_ctx_test(&ctx);
         X509V3_set_nconf(&ctx, req_conf);
         if (!X509V3_EXT_add_nconf(req_conf, &ctx, req_exts, NULL)) {
@@ -596,46 +627,48 @@ int req_main(int argc, char **argv)
         app_RAND_load_conf(req_conf, section);
     }
 
-    if (newreq && (pkey == NULL)) {
+    if (newreq && pkey == NULL) {
         app_RAND_load_conf(req_conf, section);
 
-        if (!NCONF_get_number(req_conf, section, BITS, &newkey)) {
-            newkey = DEFAULT_KEY_LENGTH;
+        if (!NCONF_get_number(req_conf, section, BITS, &newkey_len)) {
+            newkey_len = DEFAULT_KEY_LENGTH;
         }
 
         if (keyalg != NULL) {
-            genctx = set_keygen_ctx(keyalg, &pkey_type, &newkey,
+            genctx = set_keygen_ctx(keyalg, &pkey_type, &newkey_len,
                                     &keyalgstr, gen_eng);
             if (genctx == NULL)
                 goto end;
         }
 
-        if (newkey < MIN_KEY_LENGTH
+        if (newkey_len < MIN_KEY_LENGTH
             && (pkey_type == EVP_PKEY_RSA || pkey_type == EVP_PKEY_DSA)) {
-            BIO_printf(bio_err, "private key length is too short,\n");
-            BIO_printf(bio_err, "it needs to be at least %d bits, not %ld\n",
-                       MIN_KEY_LENGTH, newkey);
+            BIO_printf(bio_err, "Private key length is too short,\n");
+            BIO_printf(bio_err, "it needs to be at least %d bits, not %ld.\n",
+                       MIN_KEY_LENGTH, newkey_len);
             goto end;
         }
 
-        if (pkey_type == EVP_PKEY_RSA && newkey > OPENSSL_RSA_MAX_MODULUS_BITS)
+        if (pkey_type == EVP_PKEY_RSA
+                && newkey_len > OPENSSL_RSA_MAX_MODULUS_BITS)
             BIO_printf(bio_err,
                        "Warning: It is not recommended to use more than %d bit for RSA keys.\n"
                        "         Your key size is %ld! Larger key size may behave not as expected.\n",
-                       OPENSSL_RSA_MAX_MODULUS_BITS, newkey);
+                       OPENSSL_RSA_MAX_MODULUS_BITS, newkey_len);
 
 #ifndef OPENSSL_NO_DSA
-        if (pkey_type == EVP_PKEY_DSA && newkey > OPENSSL_DSA_MAX_MODULUS_BITS)
+        if (pkey_type == EVP_PKEY_DSA
+                && newkey_len > OPENSSL_DSA_MAX_MODULUS_BITS)
             BIO_printf(bio_err,
                        "Warning: It is not recommended to use more than %d bit for DSA keys.\n"
                        "         Your key size is %ld! Larger key size may behave not as expected.\n",
-                       OPENSSL_DSA_MAX_MODULUS_BITS, newkey);
+                       OPENSSL_DSA_MAX_MODULUS_BITS, newkey_len);
 #endif
 
         if (genctx == NULL) {
-            genctx = set_keygen_ctx(NULL, &pkey_type, &newkey,
+            genctx = set_keygen_ctx(NULL, &pkey_type, &newkey_len,
                                     &keyalgstr, gen_eng);
-            if (!genctx)
+            if (genctx == NULL)
                 goto end;
         }
 
@@ -644,8 +677,7 @@ int req_main(int argc, char **argv)
             for (i = 0; i < sk_OPENSSL_STRING_num(pkeyopts); i++) {
                 genopt = sk_OPENSSL_STRING_value(pkeyopts, i);
                 if (pkey_ctrl_string(genctx, genopt) <= 0) {
-                    BIO_printf(bio_err, "parameter error \"%s\"\n", genopt);
-                    ERR_print_errors(bio_err);
+                    BIO_printf(bio_err, "Key parameter error \"%s\"\n", genopt);
                     goto end;
                 }
             }
@@ -675,10 +707,10 @@ int req_main(int argc, char **argv)
         }
 
         if (keyout == NULL)
-            BIO_printf(bio_err, "writing new private key to stdout\n");
+            BIO_printf(bio_err, "Writing new private key to stdout\n");
         else
-            BIO_printf(bio_err, "writing new private key to '%s'\n", keyout);
-        out = bio_open_owner(keyout, outformat, private);
+            BIO_printf(bio_err, "Writing new private key to '%s'\n", keyout);
+        out = bio_open_owner(keyout, outformat, newreq);
         if (out == NULL)
             goto end;
 
@@ -696,7 +728,7 @@ int req_main(int argc, char **argv)
 
         i = 0;
  loop:
-        assert(private);
+        assert(newreq);
         if (!PEM_write_bio_PrivateKey(out, pkey, cipher,
                                       NULL, 0, NULL, passout)) {
             if ((ERR_GET_REASON(ERR_peek_error()) ==
@@ -712,15 +744,55 @@ int req_main(int argc, char **argv)
         BIO_printf(bio_err, "-----\n");
     }
 
+    /*
+     * subj is expected to be in the format /type0=value0/type1=value1/type2=...
+     * where characters may be escaped by \
+     */
+    if (subj != NULL
+            && (fsubj = parse_name(subj, chtype, multirdn, "subject")) == NULL)
+        goto end;
+
     if (!newreq) {
         req = load_csr(infile, informat, "X509 request");
         if (req == NULL)
             goto end;
     }
 
-    if (newreq || x509) {
-        if (pkey == NULL) {
-            BIO_printf(bio_err, "you need to specify a private key\n");
+    if (CAkeyfile == NULL)
+        CAkeyfile = CAfile;
+    if (CAkeyfile != NULL) {
+        if (CAfile == NULL) {
+            BIO_printf(bio_err,
+                       "Ignoring -CAkey option since no -CA option is given\n");
+        } else {
+            if ((CAkey = load_key(CAkeyfile, FORMAT_PEM,
+                                  0, passin, e, "issuer private key")) == NULL)
+                goto end;
+        }
+    }
+    if (CAfile != NULL) {
+        if (!gen_x509) {
+            BIO_printf(bio_err,
+                       "Warning: Ignoring -CA option without -x509\n");
+        } else {
+            if (CAkeyfile == NULL) {
+                BIO_printf(bio_err,
+                           "Need to give the -CAkey option if using -CA\n");
+                goto end;
+            }
+            if ((CAcert = load_cert_pass(CAfile, 1, passin,
+                                         "issuer certificate")) == NULL)
+                goto end;
+            if (!X509_check_private_key(CAcert, CAkey)) {
+                BIO_printf(bio_err,
+                           "Issuer certificate and key do not match\n");
+                goto end;
+            }
+        }
+    }
+    if (newreq || gen_x509) {
+        if (pkey == NULL /* can happen only if !newreq */) {
+            BIO_printf(bio_err, "Must provide a signature key using -key\n");
             goto end;
         }
 
@@ -730,82 +802,95 @@ int req_main(int argc, char **argv)
                 goto end;
             }
 
-            i = make_REQ(req, pkey, subj, multirdn, !x509, chtype);
-            subj = NULL;        /* done processing '-subj' option */
-            if (!i) {
-                BIO_printf(bio_err, "problems making Certificate Request\n");
+            if (!make_REQ(req, pkey, fsubj, multirdn, !gen_x509, chtype)){
+                BIO_printf(bio_err, "Error making certificate request\n");
                 goto end;
             }
         }
-        if (x509) {
-            EVP_PKEY *tmppkey;
+        if (gen_x509) {
+            EVP_PKEY *pub_key = X509_REQ_get0_pubkey(req);
             X509V3_CTX ext_ctx;
-            if ((x509ss = X509_new_ex(app_get0_libctx(), app_get0_propq())) == NULL)
+            X509_NAME *issuer = CAcert != NULL ? X509_get_subject_name(CAcert) :
+                X509_REQ_get_subject_name(req);
+            X509_NAME *n_subj = fsubj != NULL ? fsubj :
+                X509_REQ_get_subject_name(req);
+
+            if ((new_x509 = X509_new_ex(app_get0_libctx(),
+                                        app_get0_propq())) == NULL)
                 goto end;
 
-            /* Set version to V3 */
             if (serial != NULL) {
-                if (!X509_set_serialNumber(x509ss, serial))
+                if (!X509_set_serialNumber(new_x509, serial))
                     goto end;
             } else {
-                if (!rand_serial(NULL, X509_get_serialNumber(x509ss)))
+                if (!rand_serial(NULL, X509_get_serialNumber(new_x509)))
                     goto end;
             }
 
-            if (!X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req)))
+            if (!X509_set_issuer_name(new_x509, issuer))
                 goto end;
-            if (days == 0) {
-                /* set default days if it's not specified */
-                days = 30;
+            if (days == UNSET_DAYS) {
+                days = DEFAULT_DAYS;
             }
-            if (!set_cert_times(x509ss, NULL, NULL, days))
+            if (!set_cert_times(new_x509, NULL, NULL, days))
+                goto end;
+            if (!X509_set_subject_name(new_x509, n_subj))
                 goto end;
-            if (!X509_set_subject_name
-                (x509ss, X509_REQ_get_subject_name(req)))
+            if (!pub_key || !X509_set_pubkey(new_x509, pub_key))
                 goto end;
-            tmppkey = X509_REQ_get0_pubkey(req);
-            if (!tmppkey || !X509_set_pubkey(x509ss, tmppkey))
+            if (ext_copy == EXT_COPY_UNSET) {
+                BIO_printf(bio_err, "Warning: No -copy_extensions given; ignoring any extensions in the request\n");
+            } else if (!copy_extensions(new_x509, req, ext_copy)) {
+                BIO_printf(bio_err, "Error copying extensions from request\n");
                 goto end;
+            }
 
             /* Set up V3 context struct */
-
-            X509V3_set_ctx(&ext_ctx, x509ss, x509ss, NULL, NULL, X509V3_CTX_REPLACE);
+            X509V3_set_ctx(&ext_ctx, CAcert != NULL ? CAcert : new_x509,
+                           new_x509, NULL, NULL, X509V3_CTX_REPLACE);
+            if (CAcert == NULL) { /* self-issued, possibly self-signed */
+                if (!X509V3_set_issuer_pkey(&ext_ctx, pkey)) /* prepare right AKID */
+                    goto end;
+                ERR_set_mark();
+                if (!X509_check_private_key(new_x509, pkey))
+                    BIO_printf(bio_err,
+                               "Warning: Signature key and public key of cert do not match\n");
+                ERR_pop_to_mark();
+            }
             X509V3_set_nconf(&ext_ctx, req_conf);
 
             /* Add extensions */
-            if (extensions != NULL && !X509V3_EXT_add_nconf(req_conf,
-                                                            &ext_ctx, extensions,
-                                                            x509ss)) {
+            if (extensions != NULL
+                    && !X509V3_EXT_add_nconf(req_conf, &ext_ctx, extensions,
+                                             new_x509)) {
                 BIO_printf(bio_err, "Error adding x509 extensions from section %s\n",
                            extensions);
                 goto end;
             }
             if (addext_conf != NULL
                 && !X509V3_EXT_add_nconf(addext_conf, &ext_ctx, "default",
-                                         x509ss)) {
+                                         new_x509)) {
                 BIO_printf(bio_err, "Error adding extensions defined via -addext\n");
                 goto end;
             }
 
             /* If a pre-cert was requested, we need to add a poison extension */
             if (precert) {
-                if (X509_add1_ext_i2d(x509ss, NID_ct_precert_poison, NULL, 1, 0)
-                    != 1) {
+                if (X509_add1_ext_i2d(new_x509, NID_ct_precert_poison,
+                                      NULL, 1, 0) != 1) {
                     BIO_printf(bio_err, "Error adding poison extension\n");
                     goto end;
                 }
             }
 
-            i = do_X509_sign(x509ss, pkey, digest, sigopts);
-            if (!i) {
-                ERR_print_errors(bio_err);
+            i = do_X509_sign(new_x509, CAcert != NULL ? CAkey : pkey,
+                             digest, sigopts, &ext_ctx);
+            if (!i)
                 goto end;
-            }
         } else {
             X509V3_CTX ext_ctx;
 
             /* Set up V3 context struct */
-
             X509V3_set_ctx(&ext_ctx, NULL, NULL, req, NULL, 0);
             X509V3_set_nconf(&ext_ctx, req_conf);
 
@@ -824,38 +909,30 @@ int req_main(int argc, char **argv)
                 goto end;
             }
             i = do_X509_REQ_sign(req, pkey, digest, sigopts);
-            if (!i) {
-                ERR_print_errors(bio_err);
+            if (!i)
                 goto end;
-            }
         }
     }
 
-    if (subj && x509) {
-        BIO_printf(bio_err, "Cannot modify certificate subject\n");
-        goto end;
-    }
-
-    if (subj && !x509) {
+    if (subj != NULL && !newreq && !gen_x509) {
         if (verbose) {
-            BIO_printf(bio_err, "Modifying Request's Subject\n");
-            print_name(bio_err, "old subject=",
+            BIO_printf(bio_err, "Modifying subject of certificate request\n");
+            print_name(bio_err, "Old subject=",
                        X509_REQ_get_subject_name(req), get_nameopt());
         }
 
-        if (build_subject(req, subj, chtype, multirdn) == 0) {
-            BIO_printf(bio_err, "ERROR: cannot modify subject\n");
-            ret = 1;
+        if (!X509_REQ_set_subject_name(req, fsubj)) {
+            BIO_printf(bio_err, "Error modifying subject of certificate request\n");
             goto end;
         }
 
         if (verbose) {
-            print_name(bio_err, "new subject=",
+            print_name(bio_err, "New subject=",
                        X509_REQ_get_subject_name(req), get_nameopt());
         }
     }
 
-    if (verify && !x509) {
+    if (verify) {
         EVP_PKEY *tpubkey = pkey;
 
         if (tpubkey == NULL) {
@@ -869,10 +946,10 @@ int req_main(int argc, char **argv)
         if (i < 0) {
             goto end;
         } else if (i == 0) {
-            BIO_printf(bio_err, "verify failure\n");
+            BIO_printf(bio_err, "Certificate request self-signature verify failure\n");
             ERR_print_errors(bio_err);
-        } else {                 /* if (i > 0) */
-            BIO_printf(bio_err, "verify OK\n");
+        } else { /* i > 0 */
+            BIO_printf(bio_err, "Certificate request self-signature verify OK\n");
         }
     }
 
@@ -893,32 +970,29 @@ int req_main(int argc, char **argv)
 
         if (tpubkey == NULL) {
             BIO_printf(bio_err, "Error getting public key\n");
-            ERR_print_errors(bio_err);
             goto end;
         }
         PEM_write_bio_PUBKEY(out, tpubkey);
     }
 
     if (text) {
-        if (x509)
-            ret = X509_print_ex(out, x509ss, get_nameopt(), reqflag);
+        if (gen_x509)
+            ret = X509_print_ex(out, new_x509, get_nameopt(), reqflag);
         else
             ret = X509_REQ_print_ex(out, req, get_nameopt(), reqflag);
 
         if (ret == 0) {
-            if (x509)
-              BIO_printf(bio_err, "Error printing certificate\n");
+            if (gen_x509)
+                BIO_printf(bio_err, "Error printing certificate\n");
             else
-              BIO_printf(bio_err, "Error printing certificate request\n");
-
-            ERR_print_errors(bio_err);
+                BIO_printf(bio_err, "Error printing certificate request\n");
             goto end;
         }
     }
 
     if (subject) {
-        if (x509)
-            print_name(out, "subject=", X509_get_subject_name(x509ss),
+        if (gen_x509)
+            print_name(out, "subject=", X509_get_subject_name(new_x509),
                        get_nameopt());
         else
             print_name(out, "subject=", X509_REQ_get_subject_name(req),
@@ -928,12 +1002,12 @@ int req_main(int argc, char **argv)
     if (modulus) {
         EVP_PKEY *tpubkey;
 
-        if (x509)
-            tpubkey = X509_get0_pubkey(x509ss);
+        if (gen_x509)
+            tpubkey = X509_get0_pubkey(new_x509);
         else
             tpubkey = X509_REQ_get0_pubkey(req);
         if (tpubkey == NULL) {
-            fprintf(stdout, "Modulus=unavailable\n");
+            fprintf(stdout, "Modulus is unavailable\n");
             goto end;
         }
         fprintf(stdout, "Modulus=");
@@ -950,7 +1024,7 @@ int req_main(int argc, char **argv)
         fprintf(stdout, "\n");
     }
 
-    if (!noout && !x509) {
+    if (!noout && !gen_x509) {
         if (outformat == FORMAT_ASN1)
             i = i2d_X509_REQ_bio(out, req);
         else if (newhdr)
@@ -958,17 +1032,17 @@ int req_main(int argc, char **argv)
         else
             i = PEM_write_bio_X509_REQ(out, req);
         if (!i) {
-            BIO_printf(bio_err, "unable to write X509 request\n");
+            BIO_printf(bio_err, "Unable to write certificate request\n");
             goto end;
         }
     }
-    if (!noout && x509 && (x509ss != NULL)) {
+    if (!noout && gen_x509 && new_x509 != NULL) {
         if (outformat == FORMAT_ASN1)
-            i = i2d_X509_bio(out, x509ss);
+            i = i2d_X509_bio(out, new_x509);
         else
-            i = PEM_write_bio_X509(out, x509ss);
+            i = PEM_write_bio_X509(out, new_x509);
         if (!i) {
-            BIO_printf(bio_err, "unable to write X509 certificate\n");
+            BIO_printf(bio_err, "Unable to write X509 certificate\n");
             goto end;
         }
     }
@@ -993,7 +1067,10 @@ int req_main(int argc, char **argv)
 #endif
     OPENSSL_free(keyalgstr);
     X509_REQ_free(req);
-    X509_free(x509ss);
+    X509_NAME_free(fsubj);
+    X509_free(new_x509);
+    X509_free(CAcert);
+    EVP_PKEY_free(CAkey);
     ASN1_INTEGER_free(serial);
     release_engine(e);
     if (passin != nofree_passin)
@@ -1003,12 +1080,12 @@ int req_main(int argc, char **argv)
     return ret;
 }
 
-static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int multirdn,
-                    int attribs, unsigned long chtype)
+static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, X509_NAME *fsubj,
+                    int multirdn, int attribs, unsigned long chtype)
 {
     int ret = 0, i;
     char no_prompt = 0;
-    STACK_OF(CONF_VALUE) *dn_sk, *attr_sk = NULL;
+    STACK_OF(CONF_VALUE) *dn_sk = NULL, *attr_sk = NULL;
     char *tmp, *dn_sect, *attr_sect;
 
     tmp = NCONF_get_string(req_conf, section, PROMPT);
@@ -1019,34 +1096,31 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int multirdn,
 
     dn_sect = NCONF_get_string(req_conf, section, DISTINGUISHED_NAME);
     if (dn_sect == NULL) {
-        BIO_printf(bio_err, "unable to find '%s' in config\n",
-                   DISTINGUISHED_NAME);
-        goto err;
-    }
-    dn_sk = NCONF_get_section(req_conf, dn_sect);
-    if (dn_sk == NULL) {
-        BIO_printf(bio_err, "unable to get '%s' section\n", dn_sect);
-        goto err;
+        ERR_clear_error();
+    } else {
+        dn_sk = NCONF_get_section(req_conf, dn_sect);
+        if (dn_sk == NULL) {
+            BIO_printf(bio_err, "Unable to get '%s' section\n", dn_sect);
+            goto err;
+        }
     }
 
     attr_sect = NCONF_get_string(req_conf, section, ATTRIBUTES);
     if (attr_sect == NULL) {
         ERR_clear_error();
-        attr_sk = NULL;
     } else {
         attr_sk = NCONF_get_section(req_conf, attr_sect);
         if (attr_sk == NULL) {
-            BIO_printf(bio_err, "unable to get '%s' section\n", attr_sect);
+            BIO_printf(bio_err, "Unable to get '%s' section\n", attr_sect);
             goto err;
         }
     }
 
-    /* setup version number */
-    if (!X509_REQ_set_version(req, 0L))
-        goto err;               /* version 1 */
+    if (!X509_REQ_set_version(req, 0L)) /* so far there is only version 1 */
+        goto err;
 
-    if (subj)
-        i = build_subject(req, subj, chtype, multirdn);
+    if (fsubj != NULL)
+        i = X509_REQ_set_subject_name(req, fsubj);
     else if (no_prompt)
         i = auto_info(req, dn_sk, attr_sk, attribs, chtype);
     else
@@ -1063,26 +1137,6 @@ static int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int multirdn,
     return ret;
 }
 
-/*
- * subject is expected to be in the format /type0=value0/type1=value1/type2=...
- * where characters may be escaped by \
- */
-static int build_subject(X509_REQ *req, const char *subject, unsigned long chtype,
-                         int multirdn)
-{
-    X509_NAME *n;
-
-    if ((n = parse_name(subject, chtype, multirdn, "subject")) == NULL)
-        return 0;
-
-    if (!X509_REQ_set_subject_name(req, n)) {
-        X509_NAME_free(n);
-        return 0;
-    }
-    X509_NAME_free(n);
-    return 1;
-}
-
 static int prompt_info(X509_REQ *req,
                        STACK_OF(CONF_VALUE) *dn_sk, const char *dn_sect,
                        STACK_OF(CONF_VALUE) *attr_sk, const char *attr_sect,
@@ -1116,7 +1170,7 @@ static int prompt_info(X509_REQ *req,
     if (sk_CONF_VALUE_num(dn_sk)) {
         i = -1;
  start:
-        for ( ; ; ) {
+        for (;;) {
             i++;
             if (sk_CONF_VALUE_num(dn_sk) <= i)
                 break;
@@ -1168,7 +1222,6 @@ static int prompt_info(X509_REQ *req,
                 n_min = -1;
             }
 
-
             if (!join(buf, sizeof(buf), v->name, "_max", "Name"))
                 return 0;
             if (!NCONF_get_number(req_conf, dn_sect, buf, &n_max)) {
@@ -1181,7 +1234,7 @@ static int prompt_info(X509_REQ *req,
                 return 0;
         }
         if (X509_NAME_entry_count(subj) == 0) {
-            BIO_printf(bio_err, "error, no objects specified in config file\n");
+            BIO_printf(bio_err, "Error: No objects specified in config file\n");
             return 0;
         }
 
@@ -1196,7 +1249,7 @@ static int prompt_info(X509_REQ *req,
 
             i = -1;
  start2:
-            for ( ; ; ) {
+            for (;;) {
                 i++;
                 if ((attr_sk == NULL) || (sk_CONF_VALUE_num(attr_sk) <= i))
                     break;
@@ -1222,7 +1275,7 @@ static int prompt_info(X509_REQ *req,
                     value = NULL;
                 }
 
-                if (!join(buf, sizeof(buf), type,"_min", "Name"))
+                if (!join(buf, sizeof(buf), type, "_min", "Name"))
                     return 0;
                 if (!NCONF_get_number(req_conf, attr_sect, buf, &n_min)) {
                     ERR_clear_error();
@@ -1273,10 +1326,10 @@ static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk,
          */
         for (p = v->name; *p; p++) {
 #ifndef CHARSET_EBCDIC
-            spec_char = ((*p == ':') || (*p == ',') || (*p == '.'));
+            spec_char = (*p == ':' || *p == ',' || *p == '.');
 #else
-            spec_char = ((*p == os_toascii[':']) || (*p == os_toascii[','])
-                    || (*p == os_toascii['.']));
+            spec_char = (*p == os_toascii[':'] || *p == os_toascii[',']
+                         || *p == os_toascii['.']);
 #endif
             if (spec_char) {
                 p++;
@@ -1304,7 +1357,7 @@ static int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk,
     }
 
     if (!X509_NAME_entry_count(subj)) {
-        BIO_printf(bio_err, "error, no objects specified in config file\n");
+        BIO_printf(bio_err, "Error: No objects specified in config file\n");
         return 0;
     }
     if (attribs) {
@@ -1361,12 +1414,9 @@ static int add_attribute_object(X509_REQ *req, char *text, const char *def,
     return ret;
 }
 
-
-static int build_data(char *text, const char *def,
-                         char *value, int n_min, int n_max,
-                         char *buf, const int buf_size,
-                         const char *desc1, const char *desc2
-                         )
+static int build_data(char *text, const char *def, char *value,
+                      int n_min, int n_max, char *buf, const int buf_size,
+                      const char *desc1, const char *desc2)
 {
     int i;
  start:
@@ -1401,7 +1451,7 @@ static int build_data(char *text, const char *def,
 
     i = strlen(buf);
     if (buf[i - 1] != '\n') {
-        BIO_printf(bio_err, "weird input :-(\n");
+        BIO_printf(bio_err, "Missing newline at end of input\n");
         return 0;
     }
     buf[--i] = '\0';
@@ -1418,16 +1468,14 @@ static int build_data(char *text, const char *def,
 
 static int req_check_len(int len, int n_min, int n_max)
 {
-    if ((n_min > 0) && (len < n_min)) {
+    if (n_min > 0 && len < n_min) {
         BIO_printf(bio_err,
-                   "string is too short, it needs to be at least %d bytes long\n",
-                   n_min);
+                   "String too short, must be at least %d bytes long\n", n_min);
         return 0;
     }
-    if ((n_max >= 0) && (len > n_max)) {
+    if (n_max >= 0 && len > n_max) {
         BIO_printf(bio_err,
-                   "string is too long, it needs to be no more than %d bytes long\n",
-                   n_max);
+                   "String too long, must be at most %d bytes long\n", n_max);
         return 0;
     }
     return 1;
@@ -1525,7 +1573,7 @@ static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr,
     if (paramfile != NULL) {
         pbio = BIO_new_file(paramfile, "r");
         if (pbio == NULL) {
-            BIO_printf(bio_err, "Can't open parameter file %s\n", paramfile);
+            BIO_printf(bio_err, "Cannot open parameter file %s\n", paramfile);
             return NULL;
         }
         param = PEM_read_bio_Parameters(pbio, NULL);
@@ -1550,7 +1598,7 @@ static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr,
         if (*pkey_type == -1) {
             *pkey_type = EVP_PKEY_id(param);
         } else if (*pkey_type != EVP_PKEY_base_id(param)) {
-            BIO_printf(bio_err, "Key Type does not match parameters\n");
+            BIO_printf(bio_err, "Key type does not match parameters\n");
             EVP_PKEY_free(param);
             return NULL;
         }
@@ -1583,20 +1631,17 @@ static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr,
 
     if (gctx == NULL) {
         BIO_puts(bio_err, "Error allocating keygen context\n");
-        ERR_print_errors(bio_err);
         return NULL;
     }
 
     if (EVP_PKEY_keygen_init(gctx) <= 0) {
         BIO_puts(bio_err, "Error initializing keygen context\n");
-        ERR_print_errors(bio_err);
         EVP_PKEY_CTX_free(gctx);
         return NULL;
     }
     if ((*pkey_type == EVP_PKEY_RSA) && (keylen != -1)) {
         if (EVP_PKEY_CTX_set_rsa_keygen_bits(gctx, keylen) <= 0) {
             BIO_puts(bio_err, "Error setting RSA keysize\n");
-            ERR_print_errors(bio_err);
             EVP_PKEY_CTX_free(gctx);
             return NULL;
         }
diff --git a/apps/srp.c b/apps/srp.c
index 3d8ce3e7c6..f7edfa9930 100644
--- a/apps/srp.c
+++ b/apps/srp.c
@@ -338,10 +338,7 @@ int srp_main(int argc, char **argv)
         if (configfile == NULL)
             configfile = default_config_file;
 
-        if (verbose)
-            BIO_printf(bio_err, "Using configuration from %s\n",
-                       configfile);
-        conf = app_load_config(configfile);
+        conf = app_load_config_verbose(configfile, verbose);
         if (conf == NULL)
             goto end;
         if (configfile != default_config_file && !app_load_modules(conf))
diff --git a/apps/x509.c b/apps/x509.c
index c8fcb7a7ae..5769f5f982 100644
--- a/apps/x509.c
+++ b/apps/x509.c
@@ -1067,6 +1067,8 @@ static int sign(X509 *x, EVP_PKEY *pkey, X509 *issuer,
                 const EVP_MD *digest, CONF *conf, const char *section,
                 int preserve_dates)
 {
+    X509V3_CTX ext_ctx;
+
     if (!X509_set_issuer_name(x, X509_get_subject_name(issuer)))
         return 0;
 
@@ -1077,10 +1079,14 @@ static int sign(X509 *x, EVP_PKEY *pkey, X509 *issuer,
         while (X509_get_ext_count(x) > 0)
             X509_delete_ext(x, 0);
     }
-    if (conf != NULL) {
-        X509V3_CTX ext_ctx;
 
-        X509V3_set_ctx(&ext_ctx, issuer, x, NULL, NULL, X509V3_CTX_REPLACE);
+    X509V3_set_ctx(&ext_ctx, issuer, x, NULL, NULL, X509V3_CTX_REPLACE);
+    if (issuer == x
+        /* prepare the correct AKID of self-issued, possibly self-signed cert */
+            && !X509V3_set_issuer_pkey(&ext_ctx, pkey))
+        return 0;
+
+    if (conf != NULL) {
         X509V3_set_nconf(&ext_ctx, conf);
         if (!X509V3_EXT_add_nconf(conf, &ext_ctx, section, x)) {
             BIO_printf(bio_err,
@@ -1088,7 +1094,7 @@ static int sign(X509 *x, EVP_PKEY *pkey, X509 *issuer,
             return 0;
         }
     }
-    return do_X509_sign(x, pkey, digest, sigopts);
+    return do_X509_sign(x, pkey, digest, sigopts, &ext_ctx);
 }
 
 static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt)
@@ -1149,7 +1155,7 @@ static int print_x509v3_exts(BIO *bio, X509 *x, const char *ext_names)
 
     exts = X509_get0_extensions(x);
     if ((num = sk_X509_EXTENSION_num(exts)) <= 0) {
-        BIO_printf(bio, "No extensions in certificate\n");
+        BIO_printf(bio_err, "No extensions in certificate\n");
         ret = 1;
         goto end;
     }
diff --git a/crypto/conf/conf_api.c b/crypto/conf/conf_api.c
index d64cc5031a..5133114fc8 100644
--- a/crypto/conf/conf_api.c
+++ b/crypto/conf/conf_api.c
@@ -27,7 +27,7 @@ CONF_VALUE *_CONF_get_section(const CONF *conf, const char *section)
         return NULL;
     vv.name = NULL;
     vv.section = (char *)section;
-    return lh_CONF_VALUE_retrieve(conf->data, &vv);
+    return conf->data != NULL ? lh_CONF_VALUE_retrieve(conf->data, &vv) : NULL;
 }
 
 STACK_OF(CONF_VALUE) *_CONF_get_section_values(const CONF *conf,
@@ -72,6 +72,8 @@ char *_CONF_get_string(const CONF *conf, const char *section,
         return NULL;
     if (conf == NULL)
         return ossl_safe_getenv(name);
+    if (conf->data == NULL)
+        return NULL;
     if (section != NULL) {
         vv.name = (char *)name;
         vv.section = (char *)section;
diff --git a/crypto/conf/conf_def.c b/crypto/conf/conf_def.c
index 3f63a5f88d..a7f5677a26 100644
--- a/crypto/conf/conf_def.c
+++ b/crypto/conf/conf_def.c
@@ -239,11 +239,12 @@ static int def_load_bio(CONF *conf, BIO *in, long *line)
         p = &(buff->data[bufnum]);
         *p = '\0';
  read_retry:
-        BIO_gets(in, p, CONFBUFSIZE - 1);
+        if (in != NULL && BIO_gets(in, p, CONFBUFSIZE - 1) < 0)
+            goto err;
         p[CONFBUFSIZE - 1] = '\0';
         ii = i = strlen(p);
         if (i == 0 && !again) {
-            /* the currently processed BIO is at EOF */
+            /* the currently processed BIO is NULL or at EOF */
             BIO *parent;
 
 #ifndef OPENSSL_NO_POSIX_IO
diff --git a/crypto/conf/conf_mod.c b/crypto/conf/conf_mod.c
index cb1bf7cd3c..8de3222c34 100644
--- a/crypto/conf/conf_mod.c
+++ b/crypto/conf/conf_mod.c
@@ -156,11 +156,6 @@ int CONF_modules_load_file_ex(OSSL_LIB_CTX *libctx, const char *filename,
     CONF *conf = NULL;
     int ret = 0, diagnostics = 0;
 
-    ERR_set_mark();
-    conf = NCONF_new_ex(libctx, NULL);
-    if (conf == NULL)
-        goto err;
-
     if (filename == NULL) {
         file = CONF_get1_default_config_file();
         if (file == NULL)
@@ -169,6 +164,11 @@ int CONF_modules_load_file_ex(OSSL_LIB_CTX *libctx, const char *filename,
         file = (char *)filename;
     }
 
+    ERR_set_mark();
+    conf = NCONF_new_ex(libctx, NULL);
+    if (conf == NULL)
+        goto err;
+
     if (NCONF_load(conf, file, NULL) <= 0) {
         if ((flags & CONF_MFLAGS_IGNORE_MISSING_FILE) &&
             (ERR_GET_REASON(ERR_peek_last_error()) == CONF_R_NO_SUCH_FILE)) {
@@ -539,7 +539,6 @@ void CONF_module_set_usr_data(CONF_MODULE *pmod, void *usr_data)
 }
 
 /* Return default config file name */
-
 char *CONF_get1_default_config_file(void)
 {
     const char *t;
diff --git a/crypto/x509/build.info b/crypto/x509/build.info
index 04b63d0bc3..93019cc5e6 100644
--- a/crypto/x509/build.info
+++ b/crypto/x509/build.info
@@ -9,7 +9,7 @@ SOURCE[../../libcrypto]=\
         x_crl.c t_crl.c x_req.c t_req.c x_x509.c t_x509.c \
         x_pubkey.c x_x509a.c x_attrib.c x_exten.c x_name.c \
         v3_bcons.c v3_bitst.c v3_conf.c v3_extku.c v3_ia5.c v3_utf8.c v3_lib.c \
-        v3_prn.c v3_utl.c v3err.c v3_genn.c v3_alt.c v3_skey.c v3_akey.c \
+        v3_prn.c v3_utl.c v3err.c v3_genn.c v3_san.c v3_skid.c v3_akid.c \
         v3_pku.c v3_int.c v3_enum.c v3_sxnet.c v3_cpols.c v3_crld.c v3_purp.c \
         v3_info.c v3_akeya.c v3_pmaps.c v3_pcons.c v3_ncons.c \
         v3_pcia.c v3_pci.c v3_ist.c \
diff --git a/crypto/x509/v3_akey.c b/crypto/x509/v3_akid.c
similarity index 76%
rename from crypto/x509/v3_akey.c
rename to crypto/x509/v3_akid.c
index 96e415aeb1..0b1283f0af 100644
--- a/crypto/x509/v3_akey.c
+++ b/crypto/x509/v3_akid.c
@@ -13,6 +13,7 @@
 #include <openssl/asn1.h>
 #include <openssl/asn1t.h>
 #include <openssl/x509v3.h>
+#include "crypto/x509.h"
 #include "ext_dat.h"
 
 static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
@@ -78,7 +79,7 @@ static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
                                             STACK_OF(CONF_VALUE) *values)
 {
     char keyid = 0, issuer = 0;
-    int i;
+    int i, n = sk_CONF_VALUE_num(values);
     CONF_VALUE *cnf;
     ASN1_OCTET_STRING *ikeyid = NULL;
     X509_NAME *isname = NULL;
@@ -86,13 +87,17 @@ static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
     GENERAL_NAME *gen = NULL;
     ASN1_INTEGER *serial = NULL;
     X509_EXTENSION *ext;
-    X509 *cert;
+    X509 *issuer_cert;
     AUTHORITY_KEYID *akeyid = AUTHORITY_KEYID_new();
 
     if (akeyid == NULL)
         goto err;
 
-    for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
+    if (n == 1 && strcmp(sk_CONF_VALUE_value(values, 0)->name, "none") == 0) {
+        return akeyid;
+    }
+
+    for (i = 0; i < n; i++) {
         cnf = sk_CONF_VALUE_value(values, i);
         if (strcmp(cnf->name, "keyid") == 0) {
             keyid = 1;
@@ -109,35 +114,49 @@ static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
         }
     }
 
-    if (!ctx || !ctx->issuer_cert) {
-        if (ctx && (ctx->flags == CTX_TEST))
-            return akeyid;
+    if (ctx != NULL && (ctx->flags & X509V3_CTX_TEST) != 0)
+        return akeyid;
+
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
+        goto err;
+    }
+    if ((issuer_cert = ctx->issuer_cert) == NULL) {
         ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_ISSUER_CERTIFICATE);
         goto err;
     }
 
-    cert = ctx->issuer_cert;
-
-    if (keyid) {
-        i = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1);
-        if ((i >= 0) && (ext = X509_get_ext(cert, i)))
+    if (keyid != 0) {
+        /* prefer any pre-existing subject key identifier of the issuer cert */
+        i = X509_get_ext_by_NID(issuer_cert, NID_subject_key_identifier, -1);
+        if (i >= 0 && (ext = X509_get_ext(issuer_cert, i)) != NULL)
             ikeyid = X509V3_EXT_d2i(ext);
-        if ((keyid == 2 || issuer == 0) && ikeyid == NULL) {
+        if (ikeyid == NULL && ctx->issuer_pkey != NULL) { /* fallback */
+            /* generate AKID from scratch, emulating s2i_skey_id(..., "hash") */
+            X509_PUBKEY *pubkey = NULL;
+
+            if (X509_PUBKEY_set(&pubkey, ctx->issuer_pkey))
+                ikeyid = x509_pubkey_hash(pubkey);
+            X509_PUBKEY_free(pubkey);
+        }
+        if ((keyid == 2 || issuer == 0)
+            && (ikeyid == NULL
+                || ASN1_STRING_length(ikeyid) <= 2) /* indicating "none" */) {
             ERR_raise(ERR_LIB_X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID);
             goto err;
         }
     }
 
-    if ((issuer && !ikeyid) || (issuer == 2)) {
-        isname = X509_NAME_dup(X509_get_issuer_name(cert));
-        serial = ASN1_INTEGER_dup(X509_get0_serialNumber(cert));
-        if (!isname || !serial) {
+    if (issuer == 2 || (issuer == 1 && ikeyid == NULL)) {
+        isname = X509_NAME_dup(X509_get_issuer_name(issuer_cert));
+        serial = ASN1_INTEGER_dup(X509_get0_serialNumber(issuer_cert));
+        if (isname == NULL || serial == NULL) {
             ERR_raise(ERR_LIB_X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS);
             goto err;
         }
     }
 
-    if (isname) {
+    if (isname != NULL) {
         if ((gens = sk_GENERAL_NAME_new_null()) == NULL
             || (gen = GENERAL_NAME_new()) == NULL
             || !sk_GENERAL_NAME_push(gens, gen)) {
diff --git a/crypto/x509/v3_conf.c b/crypto/x509/v3_conf.c
index 1f424325a0..f8a2e3fe27 100644
--- a/crypto/x509/v3_conf.c
+++ b/crypto/x509/v3_conf.c
@@ -437,6 +437,10 @@ static X509V3_CONF_METHOD nconf_method = {
 
 void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf)
 {
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
+        return;
+    }
     ctx->db_meth = &nconf_method;
     ctx->db = conf;
 }
@@ -444,11 +448,33 @@ void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf)
 void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subj, X509_REQ *req,
                     X509_CRL *crl, int flags)
 {
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
+        return;
+    }
+    ctx->flags = flags;
     ctx->issuer_cert = issuer;
     ctx->subject_cert = subj;
-    ctx->crl = crl;
     ctx->subject_req = req;
-    ctx->flags = flags;
+    ctx->crl = crl;
+    ctx->db_meth = NULL;
+    ctx->db = NULL;
+    ctx->issuer_pkey = NULL;
+}
+
+/* For API backward compatibility, this is separate from X509V3_set_ctx() */
+int X509V3_set_issuer_pkey(X509V3_CTX *ctx, EVP_PKEY *pkey)
+{
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    if (ctx->subject_cert == NULL && pkey != NULL) {
+        ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_INVALID_ARGUMENT);
+        return 0;
+    }
+    ctx->issuer_pkey = pkey;
+    return 1;
 }
 
 /* Old conf compatibility functions */
@@ -489,6 +515,10 @@ static X509V3_CONF_METHOD conf_lhash_method = {
 
 void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH_OF(CONF_VALUE) *lhash)
 {
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_X509V3, ERR_R_PASSED_NULL_PARAMETER);
+        return;
+    }
     ctx->db_meth = &conf_lhash_method;
     ctx->db = lhash;
 }
diff --git a/crypto/x509/v3_alt.c b/crypto/x509/v3_san.c
similarity index 99%
rename from crypto/x509/v3_alt.c
rename to crypto/x509/v3_san.c
index 2344c554fa..cf7fdc6e38 100644
--- a/crypto/x509/v3_alt.c
+++ b/crypto/x509/v3_san.c
@@ -325,7 +325,7 @@ static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens)
     X509_EXTENSION *ext;
     int i, num;
 
-    if (ctx && (ctx->flags == CTX_TEST))
+    if (ctx != NULL && (ctx->flags & X509V3_CTX_TEST) != 0)
         return 1;
     if (!ctx || !ctx->issuer_cert) {
         ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_ISSUER_DETAILS);
@@ -410,12 +410,12 @@ static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p)
     GENERAL_NAME *gen = NULL;
     int i = -1;
 
-    if (ctx != NULL && ctx->flags == CTX_TEST)
+    if (ctx != NULL && (ctx->flags & X509V3_CTX_TEST) != 0)
         return 1;
     if (ctx == NULL
         || (ctx->subject_cert == NULL && ctx->subject_req == NULL)) {
         ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_SUBJECT_DETAILS);
-        goto err;
+        return 0;
     }
     /* Find the subject name */
     if (ctx->subject_cert)
diff --git a/crypto/x509/v3_skey.c b/crypto/x509/v3_skid.c
similarity index 68%
rename from crypto/x509/v3_skey.c
rename to crypto/x509/v3_skid.c
index b4b1616688..f1581e7452 100644
--- a/crypto/x509/v3_skey.c
+++ b/crypto/x509/v3_skid.c
@@ -52,55 +52,49 @@ ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method,
 
 }
 
-static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method,
-                                      X509V3_CTX *ctx, char *str)
+ASN1_OCTET_STRING *x509_pubkey_hash(X509_PUBKEY *pubkey)
 {
     ASN1_OCTET_STRING *oct;
-    X509_PUBKEY *pubkey;
     const unsigned char *pk;
     int pklen;
     unsigned char pkey_dig[EVP_MAX_MD_SIZE];
     unsigned int diglen;
 
-    if (strcmp(str, "hash"))
-        return s2i_ASN1_OCTET_STRING(method, ctx, str);
-
-    if ((oct = ASN1_OCTET_STRING_new()) == NULL) {
-        ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
+    if (pubkey == NULL) {
+        ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_PUBLIC_KEY);
         return NULL;
     }
+    if ((oct = ASN1_OCTET_STRING_new()) == NULL)
+        return NULL;
 
-    if (ctx && (ctx->flags == CTX_TEST))
+    X509_PUBKEY_get0_param(NULL, &pk, &pklen, NULL, pubkey);
+    /* TODO(3.0) - explicitly fetch the digest */
+    if (EVP_Digest(pk, pklen, pkey_dig, &diglen, EVP_sha1(), NULL)
+            && ASN1_OCTET_STRING_set(oct, pkey_dig, diglen))
         return oct;
 
-    if (!ctx || (!ctx->subject_req && !ctx->subject_cert)) {
-        ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_PUBLIC_KEY);
-        goto err;
-    }
-
-    if (ctx->subject_req)
-        pubkey = ctx->subject_req->req_info.pubkey;
-    else
-        pubkey = ctx->subject_cert->cert_info.key;
-
-    if (pubkey == NULL) {
-        ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_PUBLIC_KEY);
-        goto err;
-    }
+    ASN1_OCTET_STRING_free(oct);
+    return NULL;
+}
 
-    X509_PUBKEY_get0_param(NULL, &pk, &pklen, NULL, pubkey);
+static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method,
+                                      X509V3_CTX *ctx, char *str)
+{
+    if (strcmp(str, "none") == 0)
+        return ASN1_OCTET_STRING_new(); /* dummy */
 
-    if (!EVP_Digest(pk, pklen, pkey_dig, &diglen, EVP_sha1(), NULL))
-        goto err;
+    if (strcmp(str, "hash") != 0)
+        return s2i_ASN1_OCTET_STRING(method, ctx /* not used */, str);
 
-    if (!ASN1_OCTET_STRING_set(oct, pkey_dig, diglen)) {
-        ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
-        goto err;
+    if (ctx != NULL && (ctx->flags & X509V3_CTX_TEST) != 0)
+        return ASN1_OCTET_STRING_new();
+    if (ctx == NULL
+        || (ctx->subject_cert == NULL && ctx->subject_req == NULL)) {
+        ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_SUBJECT_DETAILS);
+        return NULL;
     }
 
-    return oct;
-
- err:
-    ASN1_OCTET_STRING_free(oct);
-    return NULL;
+    return x509_pubkey_hash(ctx->subject_req != NULL ?
+                            ctx->subject_req->req_info.pubkey :
+                            ctx->subject_cert->cert_info.key);
 }
diff --git a/crypto/x509/v3_utf8.c b/crypto/x509/v3_utf8.c
index d37ac73246..465e0a39a3 100644
--- a/crypto/x509/v3_utf8.c
+++ b/crypto/x509/v3_utf8.c
@@ -12,7 +12,6 @@
 #include <openssl/asn1.h>
 #include <openssl/conf.h>
 #include <openssl/x509v3.h>
-#include <crypto/x509v3.h>
 #include "ext_dat.h"
 
 /*
diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c
index a9beef682b..7423b122d3 100644
--- a/crypto/x509/x_pubkey.c
+++ b/crypto/x509/x_pubkey.c
@@ -99,11 +99,10 @@ int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey)
 {
     X509_PUBKEY *pk = NULL;
 
-    if (x == NULL)
+    if (x == NULL || pkey == NULL) {
+        ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
         return 0;
-
-    if (pkey == NULL)
-        goto unsupported;
+    }
 
     if (pkey->ameth != NULL) {
         if ((pk = X509_PUBKEY_new()) == NULL) {
@@ -137,8 +136,10 @@ int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey)
         OPENSSL_free(der);
     }
 
-    if (pk == NULL)
-        goto unsupported;
+    if (pk == NULL) {
+        ERR_raise(ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM);
+        goto error;
+    }
 
     X509_PUBKEY_free(*x);
     if (!EVP_PKEY_up_ref(pkey)) {
@@ -165,9 +166,6 @@ int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey)
     pk->pkey = pkey;
     return 1;
 
- unsupported:
-    ERR_raise(ERR_LIB_X509, X509_R_UNSUPPORTED_ALGORITHM);
-
  error:
     X509_PUBKEY_free(pk);
     return 0;
diff --git a/doc/internal/man3/s2i_ASN1_UTF8STRING.pod b/doc/internal/man3/s2i_ASN1_UTF8STRING.pod
deleted file mode 100644
index b6d1375189..0000000000
--- a/doc/internal/man3/s2i_ASN1_UTF8STRING.pod
+++ /dev/null
@@ -1,46 +0,0 @@
-=pod
-
-=head1 NAME
-
-i2s_ASN1_UTF8STRING,
-s2i_ASN1_UTF8STRING
-- convert objects from/to ASN.1/string representation
-
-=head1 SYNOPSIS
-
- #include "crypto/x509v3.h"
-
- char *i2s_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
-                           ASN1_UTF8STRING *utf8);
- ASN1_UTF8STRING *s2i_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
-                                      X509V3_CTX *ctx, const char *str);
-
-=head1 DESCRIPTION
-
-These functions convert OpenSSL objects to and from their ASN.1/string
-representation. This function is used for B<X509v3> extensions.
-
-=head1 NOTES
-
-The letters B<i> and B<s> in i2s_ASN1_UTF8STRING() stand for
-"internal" (that is, an internal C structure) and string respectively.
-So B<i2s_ASN1_UTF8STRING>() converts from internal to string.
-
-=head1 RETURN VALUES
-
-B<s2i_ASN1_UTF8STRING>() return a valid
-B<ASN1_UTF8STRING> structure or NULL if an error occurs.
-
-B<i2s_ASN1_UTF8STRING>() returns the pointer to a UTF-8 string
-or NULL if an error occurs.
-
-=head1 COPYRIGHT
-
-Copyright 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/man1/openssl-ca.pod.in b/doc/man1/openssl-ca.pod.in
index d2d3bfb13d..e222f6f2a8 100644
--- a/doc/man1/openssl-ca.pod.in
+++ b/doc/man1/openssl-ca.pod.in
@@ -69,15 +69,20 @@ B<openssl> B<ca>
 
 =head1 DESCRIPTION
 
-This command is a minimal CA application. It can be used
-to sign certificate requests in a variety of forms and generate
-CRLs. It also maintains a text database of issued certificates
-and their status.
-When signing certificates, a single certificate request can be specified
+This command emulates a CA application.
+See the B<WARNINGS> especially when considering to use it productively.
+It can be used to sign certificate requests (CSRs) in a variety of forms
+and generate certificate revocation lists (CRLs).
+It also maintains a text database of issued certificates and their status.
+When signing certificates, a single request can be specified
 with the B<-in> option, or multiple requests can be processed by
 specifying a set of B<certreq> files after all options.
 
-The options descriptions will be divided into each purpose.
+Note that there are also very lean ways of generating certificates:
+the B<req> and B<x509> commands can be used for directly creating certificates.
+See L<openssl-req(1)> and L<openssl-x509(1)> for details.
+
+The descriptions of the B<ca> command options are divided into each purpose.
 
 =head1 OPTIONS
 
@@ -104,12 +109,12 @@ B<default_ca> in the B<ca> section).
 
 =item B<-in> I<filename>
 
-An input filename containing a single certificate request to be
+An input filename containing a single certificate request (CSR) to be
 signed by the CA.
 
 =item B<-inform> B<DER>|B<PEM>
 
-The format of the data in CSR input files.
+The format of the data in certificate request input files.
 The default is PEM.
 
 =item B<-ss_cert> I<filename>
@@ -150,7 +155,8 @@ This option has no effect and is retained for backward compatibility only.
 
 =item B<-keyfile> I<filename>|I<uri>
 
-The CA private key to sign requests with. This must match with B<-cert>.
+The CA private key to sign certificate requests with.
+This must match with B<-cert>.
 
 =item B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>
 
@@ -168,8 +174,8 @@ Names and values of these options are algorithm-specific.
 Pass options to the signature algorithm during verify operations.
 Names and values of these options are algorithm-specific.
 
-This often needs to be given while signing too, because the input
-certificate signature request is verified against its own public key,
+This often needs to be given while signing too, because the self-signature of
+a certificate signing request (CSR) is verified against the included public key,
 and that verification may need its own set of options.
 
 =item B<-key> I<password>
@@ -192,9 +198,8 @@ see L<openssl-passphrase-options(1)>.
 
 Indicates the issued certificates are to be signed with the key
 the certificate requests were signed with (given with B<-keyfile>).
-Certificate requests signed with a different key are ignored.  If
-B<-spkac>, B<-ss_cert> or B<-gencrl> are given, B<-selfsign> is
-ignored.
+Certificate requests signed with a different key are ignored.
+If B<-spkac>, B<-ss_cert> or B<-gencrl> are given, B<-selfsign> is ignored.
 
 A consequence of using B<-selfsign> is that the self-signed
 certificate appears among the entries in the certificate database
@@ -739,6 +744,8 @@ possible to include one SPKAC or self-signed certificate.
 
 =head1 BUGS
 
+This command is quirky and at times downright unfriendly.
+
 The use of an in-memory text database can cause problems when large
 numbers of certificates are present because, as the name implies
 the database has to be kept in memory.
@@ -760,11 +767,14 @@ create an empty file.
 
 =head1 WARNINGS
 
-This command is quirky and at times downright unfriendly.
-
-This command was originally meant as an example of how to do
-things in a CA. It was not supposed to be used as a full blown CA itself:
-nevertheless some people are using it for this purpose.
+This command was originally meant as an example of how to do things in a CA.
+Its code does not have production quality.
+It was not supposed to be used as a full blown CA itself,
+nevertheless some people are using it for this purpose at least internally.
+When doing so, specific care should be taken to
+properly secure the private key(s) used for signing certificates.
+It is advisable to keep them in a secure HW storage such as a smart card or HSM
+and access them via a suitable engine or crypto provider.
 
 This command command is effectively a single user command: no locking
 is done on the various files and attempts to run more than one B<openssl ca>
@@ -776,7 +786,6 @@ request contains a basicConstraints extension with CA:TRUE and the
 B<copy_extensions> value is set to B<copyall> and the user does not spot
 this when the certificate is displayed then this will hand the requester
 a valid CA certificate.
-
 This situation can be avoided by setting B<copy_extensions> to B<copy>
 and including basicConstraints with CA:FALSE in the configuration file.
 Then if the request contains a basicConstraints extension it will be
diff --git a/doc/man1/openssl-req.pod.in b/doc/man1/openssl-req.pod.in
index f778ec5cea..72f9997aea 100644
--- a/doc/man1/openssl-req.pod.in
+++ b/doc/man1/openssl-req.pod.in
@@ -33,9 +33,12 @@ B<openssl> B<req>
 [B<-config> I<filename>]
 [B<-section> I<name>]
 [B<-x509>]
+[B<-CA> I<filename>|I<uri>]
+[B<-CAkey> I<filename>|I<uri>]
 [B<-days> I<n>]
 [B<-set_serial> I<n>]
 [B<-newhdr>]
+[B<-copy_extensions> I<arg>]
 [B<-addext> I<ext>]
 [B<-extensions> I<section>]
 [B<-reqexts> I<section>]
@@ -57,8 +60,8 @@ B<openssl> B<req>
 
 =head1 DESCRIPTION
 
-This command primarily creates and processes certificate requests
-in PKCS#10 format. It can additionally create self signed certificates
+This command primarily creates and processes certificate requests (CSRs)
+in PKCS#10 format. It can additionally create self-signed certificates
 for use as root CAs for example.
 
 =head1 OPTIONS
@@ -71,7 +74,7 @@ Print out a usage message.
 
 =item B<-inform> B<DER>|B<PEM>, B<-outform> B<DER>|B<PEM>
 
-The input and formats; the default is B<PEM>.
+The input and output formats; the default is B<PEM>.
 See L<openssl-format-options(1)> for details.
 
 The data is a PKCS#10 object.
@@ -80,7 +83,7 @@ The data is a PKCS#10 object.
 
 This specifies the input filename to read a request from or standard input
 if this option is not specified. A request is only read if the creation
-options (B<-new> and B<-newkey>) are not specified.
+options (B<-new> or B<-newkey>) are not specified.
 
 =item B<-sigopt> I<nm>:I<v>
 
@@ -100,16 +103,21 @@ which supports both options for good reasons.
 
 =end comment
 
-=item B<-passin> I<arg>, B<-passout> I<arg>
+=item B<-passin> I<arg>
 
-The password source for the input and output file.
+The password source for the request input file and the certificate input.
+For more information about the format of B<arg>
+see L<openssl-passphrase-options(1)>.
+
+=item B<-passout> I<arg>
+
+The password source for the output file.
 For more information about the format of B<arg>
 see L<openssl-passphrase-options(1)>.
 
 =item B<-out> I<filename>
 
-This specifies the output filename to write to or standard output by
-default.
+This specifies the output filename to write to or standard output by default.
 
 =item B<-text>
 
@@ -117,25 +125,24 @@ Prints out the certificate request in text form.
 
 =item B<-subject>
 
-Prints out the request subject (or certificate subject if B<-x509> is
-specified)
+Prints out the certificate request subject
+(or certificate subject if B<-x509> is specified).
 
 =item B<-pubkey>
 
-Outputs the public key.
+Prints out the public key.
 
 =item B<-noout>
 
-This option prevents output of the encoded version of the request.
+This option prevents output of the encoded version of the certificate request.
 
 =item B<-modulus>
 
-This option prints out the value of the modulus of the public key
-contained in the request.
+Prints out the value of the modulus of the public key contained in the request.
 
 =item B<-verify>
 
-Verifies the signature on the request.
+Verifies the self-signature on the request.
 
 =item B<-new>
 
@@ -144,8 +151,9 @@ the user for the relevant field values. The actual fields
 prompted for and their maximum and minimum sizes are specified
 in the configuration file and any requested extensions.
 
-If the B<-key> option is not used it will generate a new RSA private
-key using information specified in the configuration file.
+If the B<-key> option is not given it will generate a new RSA private key
+using information specified in the configuration file or given with
+the B<-newkey> and B<-pkeyopt> options, else by default with 2048 bits length.
 
 =item B<-newkey> I<arg>
 
@@ -183,8 +191,9 @@ See L<openssl-genpkey(1)/KEY GENERATION OPTIONS> for more details.
 
 =item B<-key> I<filename>|I<uri>
 
-This specifies the private key to use. It also
-accepts PKCS#8 format private keys for PEM format files.
+This specifies the private key to use for request self-signature
+and signing certificates produced using the B<-x509> option.
+It also accepts PKCS#8 format private keys for PEM format files.
 
 =item B<-keyform> B<DER>|B<PEM>|B<P12>|B<ENGINE>
 
@@ -231,7 +240,7 @@ Specifies the name of the section to use; the default is B<req>.
 =item B<-subj> I<arg>
 
 Sets subject name for new request or supersedes the subject name
-when processing a request.
+when processing a certificate request.
 
 The arg must be formatted as C</type0=value0/type1=value1/type2=...>.
 Special characters may be escaped by C<\> (backslash), whitespace is retained.
@@ -250,15 +259,33 @@ This option has been deprecated and has no effect.
 
 =item B<-x509>
 
-This option outputs a self signed certificate instead of a certificate
-request. This is typically used to generate a test certificate or
-a self signed root CA. The extensions added to the certificate
-(if any) are specified in the configuration file. Unless specified
-using the B<-set_serial> option, a large random number will be used for
-the serial number.
+This option outputs a certificate instead of a certificate request.
+This is typically used to generate test certificates.
+
+If an existing request is specified with the B<-in> option, it is converted
+to the a certificate; otherwise a request is created from scratch.
+
+Unless specified using the B<-set_serial> option,
+a large random number will be used for the serial number.
+
+Unless the B<-copy_extensions> option is used,
+X.509 extensions are not copied from any provided request input file.
 
-If existing request is specified with the B<-in> option, it is converted
-to the self signed certificate otherwise new request is created.
+X.509 extensions to be added can be specified in the configuration file
+or using the B<-addext> option.
+
+=item B<-CA> I<filename>|I<uri>
+
+Specifies the "CA" certificate to be used for signing with the B<-x509> option.
+When present, this behaves like a "micro CA" as follows:
+The subject name of the "CA" certificate is placed as issuer name in the new
+certificate, which is then signed using the "CA" key given as specified below.
+
+=item B<-CAkey> I<filename>|I<uri>
+
+Sets the "CA" private key to sign a certificate with.
+The private key must match the public key of the certificate given with B<-CA>.
+If this option is not provided then the key must be present in the B<-CA> input.
 
 =item B<-days> I<n>
 
@@ -268,8 +295,20 @@ be a positive integer. The default is 30 days.
 
 =item B<-set_serial> I<n>
 
-Serial number to use when outputting a self signed certificate. This
-may be specified as a decimal value or a hex value if preceded by C<0x>.
+Serial number to use when outputting a self-signed certificate.
+This may be specified as a decimal value or a hex value if preceded by C<0x>.
+If not given, a large random number will be used.
+
+=item B<-copy_extensions> I<arg>
+
+Determines how X.509 extensions in certificate requests should be handled
+when B<-x509> is given.
+If I<arg> is B<none> or this option is not present then extensions are ignored.
+If I<arg> is B<copy> or B<copyall> then
+all extensions in the request are copied to the certificate.
+
+The main use of this option is to allow a certificate request to supply
+values for certain extensions such as subjectAltName.
 
 =item B<-addext> I<ext>
 
@@ -308,7 +347,7 @@ configuration file, must be valid UTF8 strings.
 
 =item B<-reqopt> I<option>
 
-Customise the output format used with B<-text>. The I<option> argument can be
+Customise the printing format used with B<-text>. The I<option> argument can be
 a single option or multiple options separated by commas.
 
 See discussion of the  B<-certopt> parameter in the L<openssl-x509(1)>
@@ -533,7 +572,7 @@ The same but just using req:
 
  openssl req -newkey rsa:2048 -keyout key.pem -out req.pem
 
-Generate a self signed root certificate:
+Generate a self-signed root certificate:
 
  openssl req -x509 -newkey rsa:2048 -keyout key.pem -out req.pem
 
diff --git a/doc/man1/openssl.pod b/doc/man1/openssl.pod
index abb5d5e3e4..3396f684f9 100644
--- a/doc/man1/openssl.pod
+++ b/doc/man1/openssl.pod
@@ -83,10 +83,13 @@ Many commands use an external configuration file for some or all of their
 arguments and have a B<-config> option to specify that file.
 The default name of the file is F<openssl.cnf> in the default certificate
 storage area, which can be determined from the L<openssl-version(1)>
-command. This can be used to load modules.
-The environment variable B<OPENSSL_CONF> can be used to specify
-a different location of the file.
-See L<openssl-env(7)>.
+command using the B<-d> or B<-a> option.
+The environment variable B<OPENSSL_CONF> can be used to specify a different
+file location or to disable loading a configuration (using the empty string).
+
+Among others, the configuration file can be used to load modules
+and to specify parameters for generating certificates and random numbers.
+See L<config(5)> for details.
 
 =head2 Standard Commands
 
diff --git a/doc/man3/ASN1_generate_nconf.pod b/doc/man3/ASN1_generate_nconf.pod
index a507e444c6..8b195d523f 100644
--- a/doc/man3/ASN1_generate_nconf.pod
+++ b/doc/man3/ASN1_generate_nconf.pod
@@ -2,7 +2,7 @@
 
 =head1 NAME
 
-ASN1_generate_nconf, ASN1_generate_v3 - ASN1 generation functions
+ASN1_generate_nconf, ASN1_generate_v3 - ASN1 string generation functions
 
 =head1 SYNOPSIS
 
@@ -16,10 +16,10 @@ ASN1_generate_nconf, ASN1_generate_v3 - ASN1 generation functions
 These functions generate the ASN1 encoding of a string
 in an B<ASN1_TYPE> structure.
 
-I<str> contains the string to encode I<nconf> or I<cnf> contains
+I<str> contains the string to encode. I<nconf> or I<cnf> contains
 the optional configuration information where additional strings
 will be read from. I<nconf> will typically come from a config
-file whereas I<cnf> is obtained from an B<X509V3_CTX> structure
+file whereas I<cnf> is obtained from an B<X509V3_CTX> structure,
 which will typically be used by X509 v3 certificate extension
 functions. I<cnf> or I<nconf> can be set to NULL if no additional
 configuration will be used.
diff --git a/doc/man3/CONF_modules_load_file.pod b/doc/man3/CONF_modules_load_file.pod
index fff60c192e..59e8f6f34c 100644
--- a/doc/man3/CONF_modules_load_file.pod
+++ b/doc/man3/CONF_modules_load_file.pod
@@ -2,6 +2,7 @@
 
 =head1 NAME
 
+CONF_get1_default_config_file,
 CONF_modules_load_file_ex, CONF_modules_load_file, CONF_modules_load
 - OpenSSL configuration functions
 
@@ -9,6 +10,7 @@ CONF_modules_load_file_ex, CONF_modules_load_file, CONF_modules_load
 
  #include <openssl/conf.h>
 
+ char *CONF_get1_default_config_file(void);
  int CONF_modules_load_file_ex(OSSL_LIB_CTX *libctx, const char *filename,
                                const char *appname, unsigned long flags);
  int CONF_modules_load_file(const char *filename, const char *appname,
@@ -18,9 +20,17 @@ CONF_modules_load_file_ex, CONF_modules_load_file, CONF_modules_load
 
 =head1 DESCRIPTION
 
+The function CONF_get1_default_config_file() determines the default
+configuration file pathname as follows.
+If the B<OPENSSL_CONF> environment variable is set its value is returned.
+Else the function returns the path obtained using
+L<X509_get_default_cert_area(3)> with the filename C<"openssl.cnf"> appended.
+The caller is responsible for freeing any string returned.
+
 The function CONF_modules_load_file_ex() configures OpenSSL using
 library context B<libctx> file B<filename> and application name B<appname>.
-If B<filename> is NULL the standard OpenSSL configuration file is used.
+If B<filename> is NULL the standard OpenSSL configuration file is used
+as determined by calling CONF_get1_default_config_file().
 If B<appname> is NULL the standard OpenSSL application name B<openssl_conf> is
 used.
 The behaviour can be customized using B<flags>. Note that, the error suppressing
diff --git a/doc/man3/X509V3_set_ctx.pod b/doc/man3/X509V3_set_ctx.pod
new file mode 100644
index 0000000000..6357199483
--- /dev/null
+++ b/doc/man3/X509V3_set_ctx.pod
@@ -0,0 +1,63 @@
+=pod
+
+=head1 NAME
+
+X509V3_set_ctx,
+X509V3_set_issuer_pkey - X.509 v3 extension generation utilities
+
+=head1 SYNOPSIS
+
+ #include <openssl/x509v3.h>
+
+ void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject,
+                     X509_REQ *req, X509_CRL *crl, int flags);
+ int X509V3_set_issuer_pkey(X509V3_CTX *ctx, EVP_PKEY *pkey);
+
+=head1 DESCRIPTION
+
+X509V3_set_ctx() fills in the basic fields of I<ctx> of type B<X509V3_CTX>,
+providing details potentially needed by functions producing X509 v3 extensions,
+e.g., to look up values for filling in authority key identifiers.
+Any of I<subj>, I<req>, or I<crl> may be provided, pointing to a certificate,
+certification request, or certificate revocation list, respectively.
+If I<subj> or I<crl> is provided, I<issuer> should point to its issuer,
+for instance to help generating an authority key identifier extension.
+Note that if I<subj> is provided, I<issuer> may be the same as I<subj>,
+which means that I<subj> is self-issued (or even self-signed).
+I<flags> may be 0
+or contain B<X509V3_CTX_TEST>, which means that just the syntax of
+extension definitions is to be checked without actually producing an extension,
+or B<X509V3_CTX_REPLACE>, which means that each X.509v3 extension added as
+defined in some configuration section shall replace any already existing
+extension with the same OID.
+
+X509V3_set_issuer_pkey() explicitly sets the issuer private key of
+the certificate that has been provided in I<ctx>.
+This should be done for self-issued certificates (which may be self-signed
+or not) to provide fallback data for the authority key identifier extension.
+
+=head1 RETURN VALUES
+
+X509V3_set_ctx() and X509V3_set_issuer_pkey()
+return 1 on success and 0 on error.
+
+=head1 SEE ALSO
+
+L<X509_add_ext(3)>
+
+=head1 HISTORY
+
+X509V3_set_issuer_pkey() was added in OpenSSL 3.0.
+
+CTX_TEST was deprecated in OpenSSL 3.0; use X509V3_CTX_TEST instead.
+
+=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/s2i_ASN1_IA5STRING.pod b/doc/man3/s2i_ASN1_IA5STRING.pod
index e59a85606b..5215b6a179 100644
--- a/doc/man3/s2i_ASN1_IA5STRING.pod
+++ b/doc/man3/s2i_ASN1_IA5STRING.pod
@@ -10,11 +10,13 @@ i2s_ASN1_OCTET_STRING,
 s2i_ASN1_OCTET_STRING,
 i2s_ASN1_ENUMERATED,
 i2s_ASN1_ENUMERATED_TABLE,
+i2s_ASN1_UTF8STRING,
+s2i_ASN1_UTF8STRING
 - convert objects from/to ASN.1/string representation
 
 =head1 SYNOPSIS
 
-=for openssl generic
+ #include <openssl/x509v3.h>
 
  char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ASN1_IA5STRING *ia5);
  ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method,
@@ -29,6 +31,11 @@ i2s_ASN1_ENUMERATED_TABLE,
  char *i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *method,
                                 const ASN1_ENUMERATED *e);
 
+ char *i2s_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
+                           ASN1_UTF8STRING *utf8);
+ ASN1_UTF8STRING *s2i_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
+                                      X509V3_CTX *ctx, const char *str);
+
 =head1 DESCRIPTION
 
 These functions convert OpenSSL objects to and from their ASN.1/string
@@ -36,7 +43,7 @@ representation. This function is used for B<X509v3> extensions.
 
 =head1 NOTES
 
-The letters B<i> and B<s> in B<i2s_ASN1_IA5STRING>() stand for
+The letters B<i> and B<s> in B<i2s> and B<s2i> stand for
 "internal" (that is, an internal C structure) and string respectively.
 So B<i2s_ASN1_IA5STRING>() converts from internal to string.
 
@@ -70,6 +77,16 @@ string or NULL if an error occurs.
 B<s2i_ASN1_ENUMERATED>() returns the pointer to a B<ASN1_ENUMERATED>
 structure or NULL if an error occurs.
 
+B<s2i_ASN1_UTF8STRING>() return a valid
+B<ASN1_UTF8STRING> structure or NULL if an error occurs.
+
+B<i2s_ASN1_UTF8STRING>() returns the pointer to a UTF-8 string
+or NULL if an error occurs.
+
+=head1 HISTORY
+
+i2s_ASN1_UTF8STRING() and s2i_ASN1_UTF8STRING() were made public in OpenSSL 3.0.
+
 =head1 COPYRIGHT
 
 Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man5/config.pod b/doc/man5/config.pod
index 45165f20ec..de4b5aec59 100644
--- a/doc/man5/config.pod
+++ b/doc/man5/config.pod
@@ -502,7 +502,7 @@ F<sample>.
 
 =item B<OPENSSL_CONF>
 
-The path to the config file.
+The path to the config file, or the empty string for none.
 Ignored in set-user-ID and set-group-ID programs.
 
 =item B<OPENSSL_ENGINES>
diff --git a/doc/man5/x509v3_config.pod b/doc/man5/x509v3_config.pod
index cf08f78695..c15a1d0ce0 100644
--- a/doc/man5/x509v3_config.pod
+++ b/doc/man5/x509v3_config.pod
@@ -168,9 +168,10 @@ Examples:
 
 =head2 Subject Key Identifier
 
-This SKID extension is a string with one of two legal values.
-If it is the word B<hash>, then OpenSSL will follow
-the process specified in RFC 5280 section 4.2.1.2. (1):
+The SKID extension specification has a value with three choices.
+If the value is the word B<none> then no SKID extension will be included.
+If the value is the word B<hash>, or by default for the B<x509>, B<req>, and
+B<ca> apps, the process specified in RFC 5280 section 4.2.1.2. (1) is followed:
 The keyIdentifier is composed of the 160-bit SHA-1 hash of the value of the BIT
 STRING subjectPublicKey (excluding the tag, length, and number of unused bits).
 
@@ -183,19 +184,23 @@ Example:
 
 =head2 Authority Key Identifier
 
-The AKID extension specification may have the value B<keyid> or B<issuer>
+The AKID extension specification may have the value B<none>
+indicating that no AKID shall be included.
+Otherwise it may have the value B<keyid> or B<issuer>
 or both of them, separated by C<,>.
 Either or both can have the option B<always>,
-indicated by putting a colon C<:> between the value and this opton.
+indicated by putting a colon C<:> between the value and this option.
+By default the B<x509>, B<req>, and B<ca> apps behave as if
+"none" was given for self-signed certificates and "keyid, issuer" otherwise.
 
-If B<keyid> is present, an attempt is made to copy the subject key identifier
-(SKID) from the issuer certificate, which is the default behavior.
+If B<keyid> is present, an attempt is made to compute the hash of the public key
+corresponding to the signing key in case the certificate is self-signed,
+or else to copy the subject key identifier (SKID) from the issuer certificate.
 If this fails and the option B<always> is present, an error is returned.
-For self-issued certs the specification for the SKID must be given before.
 
-If B<issuer> is present and no B<keyid> has been added
-or it has the option B<always> specified, then
-the issuer DN and serial number are copied from the issuer certificate.
+If B<issuer> is present, and in addition it has the option B<always> specified
+or B<keyid> is not present,
+then the issuer DN and serial number are copied from the issuer certificate.
 
 Examples:
 
diff --git a/doc/man7/openssl-env.pod b/doc/man7/openssl-env.pod
index 8e131affb7..4702615e8a 100644
--- a/doc/man7/openssl-env.pod
+++ b/doc/man7/openssl-env.pod
@@ -28,7 +28,7 @@ and by the B<CA.pl> script (see L<CA.pl(1)/NOTES>
 
 Specifies the path to a configuration file and the directory for
 included files.
-See L<openssl(1)> and L<config(5)>.
+See L<config(5)>.
 
 =item B<OPENSSL_CONFIG>
 
diff --git a/include/crypto/x509.h b/include/crypto/x509.h
index d88cd31902..1003f6f652 100644
--- a/include/crypto/x509.h
+++ b/include/crypto/x509.h
@@ -318,3 +318,5 @@ int X509_add_cert_new(STACK_OF(X509) **sk, X509 *cert, int flags);
 
 int X509_PUBKEY_get0_libctx(OSSL_LIB_CTX **plibctx, const char **ppropq,
                             const X509_PUBKEY *key);
+/* Calculate default key identifier according to RFC 5280 section 4.2.1.2 (1) */
+ASN1_OCTET_STRING *x509_pubkey_hash(X509_PUBKEY *pubkey);
diff --git a/include/crypto/x509v3.h b/include/crypto/x509v3.h
deleted file mode 100644
index 4ca85e9a2e..0000000000
--- a/include/crypto/x509v3.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 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
- * https://www.openssl.org/source/license.html
- */
-#ifndef OSSL_CRYPTO_X509V3_H
-# define OSSL_CRYPTO_X509V3_H
-
-#define EXT_UTF8STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_UTF8STRING), \
-                        0,0,0,0, \
-                        (X509V3_EXT_I2S)i2s_ASN1_UTF8STRING, \
-                        (X509V3_EXT_S2I)s2i_ASN1_UTF8STRING, \
-                        0,0,0,0, \
-                        NULL}
-
-char *i2s_ASN1_UTF8STRING(X509V3_EXT_METHOD *method, ASN1_UTF8STRING *utf8);
-ASN1_UTF8STRING *s2i_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
-                                   X509V3_CTX *ctx, const char *str);
-
-#endif
diff --git a/include/openssl/x509v3.h.in b/include/openssl/x509v3.h.in
index dad8694ffa..1df530985a 100644
--- a/include/openssl/x509v3.h.in
+++ b/include/openssl/x509v3.h.in
@@ -87,9 +87,12 @@ typedef struct X509V3_CONF_METHOD_st {
     void (*free_section) (void *db, STACK_OF(CONF_VALUE) *section);
 } X509V3_CONF_METHOD;
 
-/* Context specific info */
+/* Context specific info for producing X509 v3 extensions*/
 struct v3_ext_ctx {
-# define CTX_TEST 0x1
+# define X509V3_CTX_TEST 0x1
+# ifndef OPENSSL_NO_DEPRECATED_3_0
+#  define CTX_TEST X509V3_CTX_TEST
+# endif
 # define X509V3_CTX_REPLACE 0x2
     int flags;
     X509 *issuer_cert;
@@ -98,6 +101,7 @@ struct v3_ext_ctx {
     X509_CRL *crl;
     X509V3_CONF_METHOD *db_meth;
     void *db;
+    EVP_PKEY *issuer_pkey;
 /* Maybe more here */
 };
 
@@ -362,7 +366,7 @@ struct ISSUING_DIST_POINT_st {
                         ",name:", (val)->name, ",value:", (val)->value)
 
 # define X509V3_set_ctx_test(ctx) \
-                        X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, CTX_TEST)
+    X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, X509V3_CTX_TEST)
 # define X509V3_set_ctx_nodb(ctx) (ctx)->db = NULL;
 
 # define EXT_BITSTRING(nid, table) { nid, 0, ASN1_ITEM_ref(ASN1_BIT_STRING), \
@@ -380,6 +384,13 @@ struct ISSUING_DIST_POINT_st {
                         0,0,0,0, \
                         NULL}
 
+#define EXT_UTF8STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_UTF8STRING), \
+                        0,0,0,0, \
+                        (X509V3_EXT_I2S)i2s_ASN1_UTF8STRING, \
+                        (X509V3_EXT_S2I)s2i_ASN1_UTF8STRING, \
+                        0,0,0,0, \
+                        NULL}
+
 # define EXT_END { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
 
 /* X509_PURPOSE stuff */
@@ -525,6 +536,9 @@ STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
 char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ASN1_IA5STRING *ia5);
 ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method,
                                    X509V3_CTX *ctx, const char *str);
+char *i2s_ASN1_UTF8STRING(X509V3_EXT_METHOD *method, ASN1_UTF8STRING *utf8);
+ASN1_UTF8STRING *s2i_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
+                                   X509V3_CTX *ctx, const char *str);
 
 STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
                                        GENERAL_NAME *gen,
@@ -645,6 +659,8 @@ void X509V3_string_free(X509V3_CTX *ctx, char *str);
 void X509V3_section_free(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section);
 void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject,
                     X509_REQ *req, X509_CRL *crl, int flags);
+/* For API backward compatibility, this is separate from X509V3_set_ctx(): */
+int X509V3_set_issuer_pkey(X509V3_CTX *ctx, EVP_PKEY *pkey);
 
 int X509V3_add_value(const char *name, const char *value,
                      STACK_OF(CONF_VALUE) **extlist);
diff --git a/test/certs/ext-check.csr b/test/certs/ext-check.csr
new file mode 100644
index 0000000000..ee974e05ce
--- /dev/null
+++ b/test/certs/ext-check.csr
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICzTCCAbcCAQAwVDELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
+ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDENMAsGA1UEAwwEdGVz
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJadpD0ASxxfxsvdj9Ix
+sogVzMSGLFziaYuE9KejU9+R479RifvwfBANO62sNWJ19X//9G5UjwWmkiOzn1k5
+0DkYsBBA3mJzik6wjt/c58lBIlSEgAgpvDU8ht8w3t20JP9+YqXAeugqFj/Wl9rF
+QtsvaWSRywjXVlp5fxuEQelNnXcJEKhsKTNExsBUZebo4/J1BWpklWzA9P0lYW5I
+NvDAAwcF1nzlEf0Y6Eot03IMNyg2MTE4hehxjdgCSci8GYnFirE/ojXqqpAcZGh7
+r2dqWgZUD1Dh+bT2vjrUzj8eTH3GdzI+oljt29102JIUaqj3yzRYkah8FLF9CLNN
+sUcCAwEAAaA2MBYGCSqGSIb3DQEJAjEJDAdDb21wYW55MBwGCSqGSIb3DQEJDjEP
+MA0wCwYDVR0PBAQDAgeAMAsGCSqGSIb3DQEBCwOCAQEAYd4B+FkWRuVVDPYfrN8P
+UdZbLTggUGrpdhRibnoAsLNQ3cCS90OsCq5FLD6TVUCNb1gnp15Jp1WChQSyD3zC
+jb8VgivDeDOuk08Zy2Fl2+QvuwyQ9hKTAOTdAmP/bapAi7zniElSTP6BZ8vyEtuP
+FCEWJ5UjhvUYbZOG5WIHxhT+24CtYH3iHNir4OlDbsYrUBKEmQZIDj6WC01UT+4U
+/up2xKq1Y+rOUv2Xy3K9O/U1W/3AF7IvcDyd7+qQTGD8U2X3efzZYOffhTN+9Rvn
+5t82CnHLjFn4Co43RBiOcbjSDbvtaghtDiYB2tSUuqafHiuAJKx6zAm0Y2FR8X+z
+gg==
+-----END CERTIFICATE REQUEST-----
diff --git a/test/recipes/25-test_req.t b/test/recipes/25-test_req.t
index b5d63fe1da..861212f110 100644
--- a/test/recipes/25-test_req.t
+++ b/test/recipes/25-test_req.t
@@ -15,9 +15,11 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/;
 
 setup("test_req");
 
-plan tests => 16;
+plan tests => 42;
 
-require_ok(srctop_file('test','recipes','tconversion.pl'));
+require_ok(srctop_file('test', 'recipes', 'tconversion.pl'));
+
+my @certs = qw(test certs);
 
 # What type of key to generate?
 my @req_new;
@@ -190,7 +192,7 @@ subtest "generating SM2 certificate requests" => sub {
         if disabled("sm2");
         ok(run(app(["openssl", "req",
                     "-config", srctop_file("test", "test.cnf"),
-                    "-new", "-key", srctop_file("test", "certs", "sm2.key"),
+                    "-new", "-key", srctop_file(@certs, "sm2.key"),
                     "-sigopt", "distid:1234567812345678",
                     "-out", "testreq-sm2.pem", "-sm3"])),
            "Generating SM2 certificate request");
@@ -203,7 +205,7 @@ subtest "generating SM2 certificate requests" => sub {
 
         ok(run(app(["openssl", "req",
                     "-config", srctop_file("test", "test.cnf"),
-                    "-new", "-key", srctop_file("test", "certs", "sm2.key"),
+                    "-new", "-key", srctop_file(@certs, "sm2.key"),
                     "-sigopt", "hexdistid:DEADBEEF",
                     "-out", "testreq-sm2.pem", "-sm3"])),
            "Generating SM2 certificate request with hex id");
@@ -246,3 +248,97 @@ sub run_conversion {
         done_testing();
     };
 }
+
+# Test both generation and verification of certs w.r.t. RFC 5280 requirements
+
+my $ca_cert; # will be set below
+sub generate_cert {
+    my $cert = shift @_;
+    my $ss = $cert =~ m/self-signed/;
+    my $is_ca = $cert =~ m/CA/;
+    my $cn = $is_ca ? "CA" : "EE";
+    my $ca_key = srctop_file(@certs, "ca-key.pem");
+    my $key = $is_ca ? $ca_key : srctop_file(@certs, "ee-key.pem");
+    my @cmd = ("openssl", "req", "-config", "\"\"", "-x509",
+               "-key", $key, "-subj", "/CN=$cn", @_, "-out", $cert);
+    push(@cmd, ("-CA", $ca_cert, "-CAkey", $ca_key)) unless $ss;
+    ok(run(app([@cmd])), "generate $cert");
+}
+sub has_SKID {
+    my $cert = shift @_;
+    my $expect = shift @_;
+    cert_contains($cert, "Subject Key Identifier", $expect);
+}
+sub has_AKID {
+    my $cert = shift @_;
+    my $expect = shift @_;
+    cert_contains($cert, "Authority Key Identifier", $expect);
+}
+sub has_keyUsage {
+    my $cert = shift @_;
+    my $expect = shift @_;
+    cert_contains($cert, "Key Usage", $expect);
+}
+sub strict_verify {
+    my $cert = shift @_;
+    my $expect = shift @_;
+    my $trusted = shift @_;
+    $trusted = $cert unless $trusted;
+    ok(run(app(["openssl", "verify", "-x509_strict", "-trusted", $trusted,
+                "-partial_chain", $cert])) == $expect,
+       "strict verify allow $cert");
+}
+
+my @v3_ca = ("-addext", "basicConstraints = critical,CA:true",
+             "-addext", "keyUsage = keyCertSign");
+my $SKID_AKID = "subjectKeyIdentifier,authorityKeyIdentifier";
+my $cert = "self-signed_v1_CA_no_KIDs.pem";
+generate_cert($cert);
+cert_ext_has_n_different_lines($cert, 0, $SKID_AKID); # no SKID and no AKID
+#TODO strict_verify($cert, 1); # self-signed v1 root cert should be accepted as CA
+
+$ca_cert = "self-signed_v3_CA_default_SKID.pem";
+generate_cert($ca_cert, @v3_ca);
+has_SKID($ca_cert, 1);
+has_AKID($ca_cert, 0);
+strict_verify($ca_cert, 1);
+
+$cert = "self-signed_v3_CA_no_SKID.pem";
+generate_cert($cert, @v3_ca, "-addext", "subjectKeyIdentifier = none");
+cert_ext_has_n_different_lines($cert, 0, $SKID_AKID); # no SKID and no AKID
+#TODO strict_verify($cert, 0);
+
+$cert = "self-signed_v3_CA_both_KIDs.pem";
+generate_cert($cert, @v3_ca, "-addext", "subjectKeyIdentifier = hash",
+            "-addext", "authorityKeyIdentifier = keyid");
+cert_ext_has_n_different_lines($cert, 3, $SKID_AKID); # SKID == AKID
+strict_verify($cert, 1);
+
+$cert = "self-signed_v3_EE_wrong_keyUsage.pem";
+generate_cert($cert, "-addext", "keyUsage = keyCertSign");
+#TODO strict_verify($cert, 1); # should be accepted because RFC 5280 does not apply
+
+$cert = "v3_EE_default_KIDs.pem";
+generate_cert($cert, "-addext", "keyUsage = dataEncipherment");
+cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID
+strict_verify($cert, 1, $ca_cert);
+
+$cert = "v3_EE_no_AKID.pem";
+generate_cert($cert, "-addext", "authorityKeyIdentifier = none");
+has_SKID($cert, 1);
+has_AKID($cert, 0);
+strict_verify($cert, 0, $ca_cert);
+
+$cert = "self-issued_v3_EE_default_KIDs.pem";
+generate_cert($cert, "-addext", "keyUsage = dataEncipherment",
+    "-in", srctop_file(@certs, "x509-check.csr"));
+cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID
+strict_verify($cert, 1);
+
+my $cert = "self-signed_CA_no_keyUsage.pem";
+generate_cert($cert, "-in", srctop_file(@certs, "ext-check.csr"));
+has_keyUsage($cert, 0);
+my $cert = "self-signed_CA_with_keyUsages.pem";
+generate_cert($cert, "-in", srctop_file(@certs, "ext-check.csr"),
+    "-copy_extensions", "copy");
+has_keyUsage($cert, 1);
diff --git a/test/recipes/25-test_x509.t b/test/recipes/25-test_x509.t
index 19ff335f82..e9550f1fe4 100644
--- a/test/recipes/25-test_x509.t
+++ b/test/recipes/25-test_x509.t
@@ -20,6 +20,7 @@ plan tests => 15;
 
 require_ok(srctop_file('test','recipes','tconversion.pl'));
 
+my @certs = qw(test certs);
 my $pem = srctop_file("test/certs", "cyrillic.pem");
 my $out_msb = "out-cyrillic.msb";
 my $out_utf8 = "out-cyrillic.utf8";
@@ -88,21 +89,9 @@ subtest 'x509 -- pathlen' => sub {
     ok(run(test(["v3ext", srctop_file("test/certs", "pathlen.pem")])));
 };
 
-subtest 'x500 -- subjectAltName' => sub {
-     my $fp = srctop_file("test/certs", "fake-gp.pem");
-     my $out = "ext.out";
-     ok(run(app(["openssl", "x509", "-text", "-in", $fp, "-out", $out])));
-     ok(has_doctor_id($out));
-     unlink $out;
-};
-
-sub has_doctor_id { 
-    $_ = shift @_;
-    open(DATA,$_) or return 0;
-    $_= join('',<DATA>); 
-    close(DATA);
-    return m/2.16.528.1.1003.1.3.5.5.2-1-0000006666-Z-12345678-01.015-12345678/;
-}
+cert_contains(srctop_file(@certs, "fake-gp.pem"),
+              "2.16.528.1.1003.1.3.5.5.2-1-0000006666-Z-12345678-01.015-12345678",
+              1, 'x500 -- subjectAltName');
 
 sub test_errors { # actually tests diagnostics of OSSL_STORE
     my ($expected, $cert, @opts) = @_;
diff --git a/test/recipes/tconversion.pl b/test/recipes/tconversion.pl
index d3b64590da..6ae5cf17ea 100644
--- a/test/recipes/tconversion.pl
+++ b/test/recipes/tconversion.pl
@@ -108,4 +108,51 @@ sub cmp_text {
     });
 }
 
+sub file_contains {
+    $_ = shift @_;
+    my $pattern = shift @_;
+    open(DATA, $_) or return 0;
+    $_= join('', <DATA>);
+    close(DATA);
+    return m/$pattern/ ? 1 : 0;
+}
+
+sub cert_contains {
+    my $cert = shift @_;
+    my $pattern = shift @_;
+    my $expected = shift @_;
+    my $name = shift @_;
+    my $out = "cert_contains.out";
+    run(app(["openssl", "x509", "-noout", "-text", "-in", $cert, "-out", $out]));
+    is(file_contains($out, $pattern), $expected, ($name ? "$name: " : "").
+       "$cert should ".($expected ? "" : "not ")."contain $pattern");
+    # not unlinking $out
+}
+
+sub uniq (@) {
+    my %seen = ();
+    grep { not $seen{$_}++ } @_;
+}
+
+sub file_n_different_lines {
+    my $filename = shift @_;
+    open(DATA, $filename) or return 0;
+    chomp(my @lines = <DATA>);
+    close(DATA);
+    return scalar(uniq @lines);
+}
+
+sub cert_ext_has_n_different_lines {
+    my $cert = shift @_;
+    my $expected = shift @_;
+    my $exts = shift @_;
+    my $name = shift @_;
+    my $out = "cert_n_different_exts.out";
+    run(app(["openssl", "x509", "-noout", "-ext", $exts,
+             "-in", $cert, "-out", $out]));
+    is(file_n_different_lines($out), $expected, ($name ? "$name: " : "").
+       "$cert '$exts' output should contain $expected different lines");
+    # not unlinking $out
+}
+
 1;
diff --git a/util/libcrypto.num b/util/libcrypto.num
index aa35b4185c..2f3255303d 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -5100,6 +5100,9 @@ X509_STORE_load_file_ex                 ?	3_0_0	EXIST::FUNCTION:
 X509_STORE_load_store_ex                ?	3_0_0	EXIST::FUNCTION:
 X509_STORE_load_locations_ex            ?	3_0_0	EXIST::FUNCTION:
 X509_STORE_set_default_paths_ex         ?	3_0_0	EXIST::FUNCTION:
+X509V3_set_issuer_pkey                  ?	3_0_0	EXIST::FUNCTION:
+i2s_ASN1_UTF8STRING                     ?	3_0_0	EXIST::FUNCTION:
+s2i_ASN1_UTF8STRING                     ?	3_0_0	EXIST::FUNCTION:
 OSSL_STORE_open_ex                      ?	3_0_0	EXIST::FUNCTION:
 OSSL_DECODER_fetch                      ?	3_0_0	EXIST::FUNCTION:
 OSSL_DECODER_up_ref                     ?	3_0_0	EXIST::FUNCTION:
diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt
index b547e52858..8b3ebab119 100644
--- a/util/missingcrypto.txt
+++ b/util/missingcrypto.txt
@@ -379,7 +379,6 @@ COMP_zlib(3)
 CONF_dump_bio(3)
 CONF_dump_fp(3)
 CONF_free(3)
-CONF_get1_default_config_file(3)
 CONF_get_number(3)
 CONF_get_section(3)
 CONF_get_string(3)
@@ -1295,7 +1294,6 @@ X509V3_get_value_int(3)
 X509V3_parse_list(3)
 X509V3_section_free(3)
 X509V3_set_conf_lhash(3)
-X509V3_set_ctx(3)
 X509V3_set_nconf(3)
 X509V3_string_free(3)
 X509_ALGORS_it(3)
diff --git a/util/missingcrypto111.txt b/util/missingcrypto111.txt
index 9e945703dc..4be52cf25c 100644
--- a/util/missingcrypto111.txt
+++ b/util/missingcrypto111.txt
@@ -403,7 +403,6 @@ COMP_zlib(3)
 CONF_dump_bio(3)
 CONF_dump_fp(3)
 CONF_free(3)
-CONF_get1_default_config_file(3)
 CONF_get_number(3)
 CONF_get_section(3)
 CONF_get_string(3)
diff --git a/util/missingmacro.txt b/util/missingmacro.txt
index a24cb8a685..4cad414f3a 100644
--- a/util/missingmacro.txt
+++ b/util/missingmacro.txt
@@ -174,3 +174,4 @@ X509V3_set_ctx_test(3)
 X509V3_set_ctx_nodb(3)
 EXT_BITSTRING(3)
 EXT_IA5STRING(3)
+EXT_UTF8STRING(3)


More information about the openssl-commits mailing list