From: Clemens Lang Date: Sun, 3 Aug 2025 18:47:36 +0000 (+0200) Subject: x509: Accept 'contentCommitment' as alias X-Git-Tag: openssl-3.6.0-alpha1~195 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6b93db7bfd572e81fac581c5be7b0d7509febb80;p=thirdparty%2Fopenssl.git x509: Accept 'contentCommitment' as alias ITU-T X.509 (10/2019) section 9.2.2.3 [1] defines 'contentCommitment' as the current name for what had previously been called 'nonRepudiation', and deprecates the old name: > It is not incorrect to refer to this keyUsage bit using the identifier > nonRepudiation. However, the use of this identifier has been > deprecated. Allow 'contentCommitment' as an alias wherever 'nonRepudiation' has been accepted before, so that passing -addext keyUsage=critical,contentCommitment works as expected. Add a test that checks that contentCommitment sets the same keyUsage bit as nonRepudiation. Adjust the docs to mention the available alias name. [1]: https://www.itu.int/rec/T-REC-X.509-201910-I/en Signed-off-by: Clemens Lang Reviewed-by: David von Oheimb Reviewed-by: Dmitry Belyavskiy (Merged from https://github.com/openssl/openssl/pull/28161) --- diff --git a/crypto/asn1/t_bitst.c b/crypto/asn1/t_bitst.c index e7b817f78e1..4c49283bed3 100644 --- a/crypto/asn1/t_bitst.c +++ b/crypto/asn1/t_bitst.c @@ -17,8 +17,19 @@ int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs, { BIT_STRING_BITNAME *bnam; char first = 1; + int last_seen_bit = -1; + BIO_printf(out, "%*s", indent, ""); for (bnam = tbl; bnam->lname; bnam++) { + /* + * Skip duplicate entries for the same bit in the BIT_STRING_BITNAME + * table. Those are aliases, but we only want to print the first entry + * when converting to a string. + */ + if (last_seen_bit == bnam->bitnum) + continue; + last_seen_bit = bnam->bitnum; + if (ASN1_BIT_STRING_get_bit(bs, bnam->bitnum)) { if (!first) BIO_puts(out, ", "); diff --git a/crypto/x509/v3_bitst.c b/crypto/x509/v3_bitst.c index d41c95b5138..e487dc98e13 100644 --- a/crypto/x509/v3_bitst.c +++ b/crypto/x509/v3_bitst.c @@ -28,6 +28,7 @@ static BIT_STRING_BITNAME ns_cert_type_table[] = { static BIT_STRING_BITNAME key_usage_type_table[] = { {0, "Digital Signature", "digitalSignature"}, {1, "Non Repudiation", "nonRepudiation"}, + {1, "Content Commitment", "contentCommitment"}, {2, "Key Encipherment", "keyEncipherment"}, {3, "Data Encipherment", "dataEncipherment"}, {4, "Key Agreement", "keyAgreement"}, @@ -48,7 +49,17 @@ STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, STACK_OF(CONF_VALUE) *ret) { BIT_STRING_BITNAME *bnam; + int last_seen_bit = -1; + for (bnam = method->usr_data; bnam->lname; bnam++) { + /* + * If the bitnumber did not change from the last iteration, this entry + * is an an alias for the previous bit; treat the first result as + * canonical and ignore the rest. + */ + if (last_seen_bit == bnam->bitnum) + continue; + last_seen_bit = bnam->bitnum; if (ASN1_BIT_STRING_get_bit(bits, bnam->bitnum)) X509V3_add_value(bnam->lname, NULL, &ret); } diff --git a/doc/man1/openssl-verification-options.pod b/doc/man1/openssl-verification-options.pod index 81a11c37f4c..6f78fcdcc5b 100644 --- a/doc/man1/openssl-verification-options.pod +++ b/doc/man1/openssl-verification-options.pod @@ -661,7 +661,8 @@ This is used as a workaround if the basicConstraints extension is absent. =item B (C) In addition to the common S/MIME checks, for target certificates -the key usage must allow for C and/or B. +the key usage must allow for C and/or B (or +its alias name B). =item B (C) @@ -685,7 +686,8 @@ For all other certificates the normal CA checks apply. =item B (C) For target certificates, if the key usage extension is present, it must include -C and/or C and must not include other bits. +C and/or C (or its alias name +C) and must not include other bits. The EKU extension must be present and contain C only. Moreover, it must be marked as critical. diff --git a/doc/man5/x509v3_config.pod b/doc/man5/x509v3_config.pod index ab33b7e7afe..7aaa8d24045 100644 --- a/doc/man5/x509v3_config.pod +++ b/doc/man5/x509v3_config.pod @@ -130,13 +130,16 @@ any sub-CA's, and can only sign end-entity certificates. Key usage is a multi-valued extension consisting of a list of names of the permitted key usages. The defined values are: C, -C, C, C, C, -C, C, C, and C. +C (with an alternative name C), +C, C, C, C, +C, C, and C. Examples: keyUsage = digitalSignature, nonRepudiation + keyUsage = digitalSignature, contentCommitment + keyUsage = critical, keyCertSign =head2 Extended Key Usage diff --git a/test/recipes/25-test_req.t b/test/recipes/25-test_req.t index 0b1c16aee05..7dfbe02778e 100644 --- a/test/recipes/25-test_req.t +++ b/test/recipes/25-test_req.t @@ -15,7 +15,7 @@ use OpenSSL::Test qw/:DEFAULT srctop_file/; setup("test_req"); -plan tests => 113; +plan tests => 116; require_ok(srctop_file('test', 'recipes', 'tconversion.pl')); @@ -748,6 +748,13 @@ generate_cert($cert, "-in", srctop_file(@certs, "ext-check.csr"), "-copy_extensions", "copy"); has_keyUsage($cert, 1); +# keyUsage=contentCommitment is an alias for nonRepudiation +$cert = "self-issued-v3_CA_keyUsage_contentCommitment.pem"; +generate_cert($cert, "-addext", "keyUsage = contentCommitment", + "-in", srctop_file(@certs, "x509-check.csr")); +cert_contains($cert, "Non Repudiation", 1); +cert_contains($cert, "Content Commitment", 0); + # Generate cert using req with '-modulus' ok(run(app(["openssl", "req", "-x509", "-new", "-days", "365", "-key", srctop_file("test", "testrsa.pem"),