options just like any other extension. See their documentation and also
`x509v3_config(5)` for additional details.
+ Updated the syntax of the `subjectKeyIdentifier` (SKID) and
+ `authorityKeyIdentifier` (AKID) extensions, introducing the `nonss` qualifier
+ for the `keyid` and `issuer` keywords.
+
The x509 "mini-CA" now attempts to find extension settings in the default
configuration file even if neither the `-extfile` nor the `-extensions`
option is explicitly specified. Failure to open the default configuration
# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
+# The issuer of a proxy certificate should have SKID.
authorityKeyIdentifier=keyid:always
# This stuff is for subjectAltName and issuerAltname.
# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
+# The issuer of a proxy certificate should have SKID.
authorityKeyIdentifier=keyid:always
# This stuff is for subjectAltName and issuerAltname.
if (att == NULL)
goto end;
- X509at_delete_attr(req->req_info.attributes, loc);
X509_ATTRIBUTE_free(att);
}
- ret = X509_REQ_add1_attr_by_NID(req, *pnid, V_ASN1_SEQUENCE, ext, extlen);
-
+ if (sk_X509_EXTENSION_num(exts) > 0)
+ ret = X509_REQ_add1_attr_by_NID(req, *pnid, V_ASN1_SEQUENCE, ext, extlen);
+ else
+ ret = 1;
end:
OPENSSL_free(ext);
return ret;
#include <openssl/x509v3.h>
#include "ext_dat.h"
+#include "x509_local.h"
static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL;
return 1;
}
+int ossl_ignored_x509_extension(const X509_EXTENSION *ex, int flags)
+{
+ /*
+ * Empty OCTET STRINGs and empty SEQUENCEs encode to just two bytes of tag
+ * (0x04 or 0x30) and length (0x00). We use this fact to suppress empty
+ * AKID and SKID extensions that may be briefly generated when processing
+ * the "= none" value or only ":nonss"-qualified AKIDs when the subject is
+ * self-signed.
+ *
+ * The resulting extension is empty, and must not be retained, but does
+ * serve to drop any previous value of the same extension, when called
+ * via
+ * - X509v3_add_extensions(), or
+ * - either of X509V3_add1_i2d() or X509V3_EXT_add_nconf_sk(),
+ * with a flags (or ctx->flags) value that allows replacement.
+ */
+ if (ex->value.length == 2
+ && (ex->value.data[0] == 0x30 || ex->value.data[0] == 0x04)) {
+ ASN1_OBJECT *obj = ex->object;
+ ASN1_OBJECT *skid = OBJ_nid2obj(NID_subject_key_identifier);
+ ASN1_OBJECT *akid = OBJ_nid2obj(NID_authority_key_identifier);
+
+ if (OBJ_cmp(obj, skid) == 0 || OBJ_cmp(obj, akid) == 0) {
+ if ((flags & X509V3_ADD_SILENT) == 0)
+ ERR_raise_data(ERR_LIB_X509, X509_R_INVALID_EXTENSION,
+ "Invalid empty X.509 %s extension", obj->sn);
+ return 1;
+ }
+ }
+ return 0;
+}
+
/* Return an extension internal structure */
void *X509V3_EXT_d2i(const X509_EXTENSION *ext)
/* If extension exists replace it.. */
if (extidx >= 0) {
extmp = sk_X509_EXTENSION_value(*x, extidx);
- X509_EXTENSION_free(extmp);
- if (!sk_X509_EXTENSION_set(*x, extidx, ext))
+ if (ossl_ignored_x509_extension(ext, X509V3_ADD_SILENT)) {
+ if (!sk_X509_EXTENSION_delete(*x, extidx))
+ return -1;
+ } else if (!sk_X509_EXTENSION_set(*x, extidx, ext)) {
return -1;
+ }
+ X509_EXTENSION_free(extmp);
return 1;
}
if (X509v3_add_ext(&exts, ex, loc) == NULL)
return 0;
+ /*
+ * A duplicate empty SKID/AKID extension can displace a prior non-empty
+ * one, but is then not itself added, so, somewhat counter-intutively, the
+ * the extension list can become empty after an "add", in which case we must
+ * drop the extension stack entirely, setting it to NULL. The extensions
+ * list is either non-empty or absent.
+ */
if (sk_X509_EXTENSION_num(exts) != 0) {
x->cert_info.extensions = exts;
} else {
- sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+ sk_X509_EXTENSION_free(exts);
sk_X509_EXTENSION_pop_free(x->cert_info.extensions, X509_EXTENSION_free);
x->cert_info.extensions = NULL;
}
typedef STACK_OF(X509_NAME_ENTRY) STACK_OF_X509_NAME_ENTRY;
DEFINE_STACK_OF(STACK_OF_X509_NAME_ENTRY)
+int ossl_ignored_x509_extension(const X509_EXTENSION *ex, int flags);
int ossl_x509_likely_issued(const X509 *issuer, const X509 *subject);
int ossl_x509_signing_allowed(const X509 *issuer, const X509 *subject);
int ossl_x509_store_ctx_get_by_subject(const X509_STORE_CTX *ctx, X509_LOOKUP_TYPE type,
} else
sk = *x;
- /*
- * Empty OCTET STRINGs and empty SEQUENCEs encode to just two bytes of tag
- * (0x04 or 0x30) and length (0x00). We use this fact to suppress empty
- * AKID and SKID extensions that may be briefly generated when processing
- * the "= none" value or only ":nonss"-qualified AKIDs when the subject is
- * self-signed. The resulting extension is empty, and must not be retained,
- * but does serve to drop any previous value of the same extension.
- */
- if (ex->value.length == 2
- && (ex->value.data[0] == 0x30 || ex->value.data[0] == 0x04)) {
- ASN1_OBJECT *obj = ex->object;
- ASN1_OBJECT *skid = OBJ_nid2obj(NID_subject_key_identifier);
- ASN1_OBJECT *akid = OBJ_nid2obj(NID_authority_key_identifier);
-
- if (OBJ_cmp(obj, skid) == 0 || OBJ_cmp(obj, akid) == 0)
- goto done;
- }
+ if (ossl_ignored_x509_extension(ex, X509V3_ADD_SILENT))
+ goto done;
n = sk_X509_EXTENSION_num(sk);
if (loc > n)
#include "crypto/x509.h"
#include "crypto/x509_acert.h"
#include "crypto/rsa.h"
+#include "x509_local.h"
int X509_verify(const X509 *a, EVP_PKEY *r)
{
for (i = 0; i < n; ++i) {
X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
- const ASN1_STRING *der = X509_EXTENSION_get_data(ext);
-
- /*
- * Empty OCTET STRINGs and empty SEQUENCEs encode to just two bytes of
- * tag (0x04 or 0x30) and length (0x00).
- */
- if (der->length == 2 && (der->data[0] == 0x04 || der->data[0] == 0x30)) {
- const ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext);
- const ASN1_OBJECT *skid = OBJ_nid2obj(NID_subject_key_identifier);
- const ASN1_OBJECT *akid = OBJ_nid2obj(NID_authority_key_identifier);
-
- if (OBJ_cmp(obj, skid) != 0 && OBJ_cmp(obj, akid) != 0)
- continue;
- ERR_raise_data(ERR_LIB_X509, X509_R_INVALID_EXTENSION,
- "Invalid empty X.509 %s extension", obj->sn);
+
+ if (ossl_ignored_x509_extension(ext, X509V3_ADD_DEFAULT))
return 1;
- }
}
return 0;
}
This allows several different sections to be used in the same configuration
file to specify requests for a variety of purposes.
+When signing a new CSR or X.509 certificate, if neither the the B<-extensions>
+option nor its alias B<-reqexts> are specified, the name of the extension
+section is taken from from C<req> section of the configuration file.
+Specifically, from the value of that section's C<req_extensions> variable (for
+a CSR) or its C<x509_extensions> variable (for a certificate).
+If there is no setting for the variable (name/value assignment, see
+L<config(5)>) in question, the configuration file does not add any extensions.
+The B<-section> option can be used to override C<req> with a custom section in
+which to look for the above C<req_extensions> and C<x509_extensions> variables.
+
OpenSSL 4.0 removed built-in generation of the B<subjectKeyIdentifier> and
B<authorityKeyIdentifier> extensions when generating certificates.
Any desired extensions need to be listed either in the configuration file or
If only the B<-extfile> I<filename> option is given, the section name to use is
taken from the value of the variable named C<extensions> in the file's unnamed
-(C<default>) section.
-If no B<extensions> setting is found, the file's C<default> section itself is
-instead used as the list of extensions to add.
+section (also called its B<default> section, see L<config(5)>).
+If no B<extensions> setting is found, the file's B<default> (unnamed) section
+itself is instead used as the list of extensions to add.
As before, the file must be readable and all the extensions must be valid.
Prior to OpenSSL 4.0, the B<-extensions> option required that the B<-extfile>
If neither of the options are given, an attempt is made to open the default
configuration file (as detailed above).
If the file does not exist or cannot be opened, no extensions are added.
-If the unnamed (C<default>) section of the file does not list an B<extensions>
-variable, no extensions are added.
+If the unnamed section (B<default>, see L<config(5)>) of the file does not list
+an B<extensions> variable, no extensions are added.
Otherwise, the section named by the B<extensions> variable is taken to be the
list of extensions to add.
The extensions listed there must all be valid.
L<openssl-genrsa(1)>,
L<openssl-gendsa(1)>,
L<openssl-verify(1)>,
+L<config(5)>,
L<x509v3_config(5)>
=head1 HISTORY
begins with the section name in square brackets, and ends when a new
section starts, or at the end of the file. The section name can consist
of alphanumeric characters and underscores.
-Whitespace between the name and the brackets is removed.
+Whitespace between the name and the brackets is ignored.
-The first section of a configuration file is special and is referred to
-as the B<default> section. This section is usually unnamed and spans from
-the start of file until the first named section. When a name is being
-looked up, it is first looked up in the current or named section,
-and then the default section if necessary.
+The content at the start of the configuration file that precedes its first
+named section is special and is referred to as the B<default> or B<unnamed>
+section.
The environment is mapped onto a section called B<ENV>.
The B<issuer> keyword asks that the AKID include the serial number and issuer
distinguished name (grandparent name of subject certificate) of the issuer
certificate.
-By default these are added only as a fallback when no SKID is available in the
+Unless qualified with C<always> (as described below), these are added only as a
+fallback if the B<keyid> is not requested, or no SKID was available in the
issuer certificate.
Either or both keywords can be suffixed with an optional qualifier, which can
you want to have a mandatory (C<always> qualified) B<keyid> in the AKID
extension.
-If an empty AKID would otherwise be generated, the extension is instead skipped
-entirely, just as with C<none>.
-
See L<openssl-x509(1)>, L<openssl-req(1)>, and L<openssl-ca(1)> for further
details relevant to that specific command-line utility.
# # SKID
-my $cert = "self-signed_default_SKID_no_explicit_exts.pem";
+my $cert = "self-signed_default_SKID_minimal_exts.pem";
generate_cert($cert);
has_version($cert, 3);
has_SKID($cert, 1);
$cert = "self-signed_v3_CA_explicit_AKID.pem";
generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = keyid:nonss");
-has_AKID($cert, 0); # for self-signed cert, AKID suppressed and not forced
+has_AKID($cert, 0); # for self-signed cert, AKID suppressed since self-signed
$cert = "self-signed_v3_CA_forced_AKID.pem";
generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = keyid:always");
$cert = "self-signed_v3_CA_issuer_AKID.pem";
generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = issuer:nonss");
-has_AKID($cert, 0); # suppressed AKID since not forced
+has_AKID($cert, 0); # suppressed AKID since self-signed
$cert = "self-signed_v3_CA_forced_issuer_AKID.pem";
generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = issuer:always");
my $v3_cert = "v3-test.crt";
ok(run(app(["openssl", "ca", "-batch", "-config", $cnf, "-extensions", "minimal",
"-in", src_file("x509-check.csr"), "-out", $v3_cert])));
-# although no explicit extensions given:
+# The "minimal" extensions include SKID and AKID.
has_version($v3_cert, 3);
has_SKID($v3_cert, 1);
has_AKID($v3_cert, 1);
static int test_drop_empty_csr_keyids(void)
{
static const unsigned char commonName[] = "test";
+ BIO *bio = NULL;
+ CONF *conf = NULL;
X509_REQ *x = NULL;
X509_NAME *subject = NULL;
X509_NAME_ENTRY *name_entry = NULL;
|| !TEST_int_eq(X509_REQ_set_pubkey(x, pubkey), 1))
goto err;
- X509V3_set_ctx(&ctx, NULL, NULL, x, NULL, 0);
- if (!TEST_ptr(ext = X509V3_EXT_conf(NULL, &ctx, "subjectKeyIdentifier",
- "none"))
- || !TEST_ptr(X509v3_add_ext(&exts, ext, -1))
- || !TEST_int_eq(sk_X509_EXTENSION_num(exts), 0))
- goto err;
- X509_EXTENSION_free(ext);
-
- if (!TEST_ptr(ext = X509V3_EXT_conf(NULL, &ctx, "authorityKeyIdentifier",
- "none"))
- || !TEST_ptr(X509v3_add_ext(&exts, ext, -1)))
- goto err;
-
- if (!TEST_int_eq(X509_REQ_add_extensions(x, exts), 1)
- || !TEST_int_eq(sk_X509_EXTENSION_num(exts), 0))
+ /* Add non-empty SKID, CSRs have no issuer, so no AKID */
+ if (!TEST_ptr(bio = BIO_new(BIO_s_mem()))
+ || !TEST_int_ge(BIO_printf(bio, "subjectKeyIdentifier = hash\n"), 0)
+ || !TEST_ptr(conf = NCONF_new(NULL))
+ || !TEST_int_gt(NCONF_load_bio(conf, bio, NULL), 0))
goto err;
- sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
-
- if (!TEST_ptr(exts = X509_REQ_get_extensions(x))
- || !TEST_int_eq(sk_X509_EXTENSION_num(exts), 0))
+ (void)BIO_reset(bio);
+
+ X509V3_set_ctx(&ctx, NULL, NULL, x, NULL, X509V3_CTX_REPLACE);
+ X509V3_set_nconf(&ctx, conf);
+ if (!TEST_true(X509V3_EXT_REQ_add_nconf(conf, &ctx, "default", x))
+ || !TEST_int_eq(X509_REQ_get_attr_count(x), 1)
+ || !TEST_ptr(exts = X509_REQ_get_extensions(x))
+ || !TEST_int_eq(sk_X509_EXTENSION_num(exts), 1))
goto err;
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
exts = NULL;
- if (!TEST_int_gt(X509_REQ_sign(x, privkey, signmd), 0))
+ /* Request an "empty" SKID in order to drop the previous SKID */
+ NCONF_free(conf);
+ if (!TEST_ptr(conf = NCONF_new(NULL))
+ || !TEST_int_ge(BIO_printf(bio, "subjectKeyIdentifier = none\n"), 0)
+ || !TEST_int_gt(NCONF_load_bio(conf, bio, NULL), 0))
goto err;
- if (!TEST_ptr(exts = X509_REQ_get_extensions(x))
- || !TEST_int_eq(sk_X509_EXTENSION_num(exts), 0))
+ X509V3_set_nconf(&ctx, conf);
+ if (!TEST_true(X509V3_EXT_REQ_add_nconf(conf, &ctx, "default", x))
+ || !TEST_int_gt(X509_REQ_sign(x, privkey, signmd), 0)
+ || !TEST_int_eq(X509_REQ_get_attr_count(x), 0))
goto err;
ret = 1;
+
err:
+ BIO_free(bio);
+ NCONF_free(conf);
X509_NAME_ENTRY_free(name_entry);
X509_NAME_free(subject);
X509_EXTENSION_free(ext);