Directly trusted self-issued end-entity certs - Re: How to rotate cert when only first matching cert been verified

David von Oheimb dev at ddvo.net
Fri Jan 1 21:16:57 UTC 2021


On 01.01.21 08:07, 定平袁 wrote:
> @David von Oheimb <mailto:dev at ddvo.net>
> Thank you so much for your deep investigation!
My pleasure!

> With subjectKeyIdentifier and authorityKeyIdentifier extensions, it
> works like a charm!
Good to hear.
I've meanwhile submitted a pull request that fixed the behavior also  in
case no SKID and AKID are included in the certs
and briefly mentioned your use case there:
https://github.com/openssl/openssl/pull/13748

> So, the former statements I found on this page
> <https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_load_verify_locations.html>
> only applies to CA cert, not EE cert.
> How to pick up cert from trust store(or cert container as you say)
> is decided by different implementation themselves, do I understand
> correctly?
It looks like my explanations were a bit mistakable.
Although self-signed (and more generally, self-issued) EE certs are out
of scope of RFC 5280, OpenSSL still tries to build a cert chain for them
and then to verify it.
Please also note that I did not write "cert container", but that these
certs are essentially just a convenient container /for a public key/.
In other words, they have the /format/ of an X.509 certificate, but the
only thing that really matters in such a cert is the public key.
Yet since they look like a certificate, they can be used where a
certificate is expected, e.g., in TLS handshake and in trust stores.

> Since GnuTls and golang could pick up the right cert in this kind of
> scenario,
> they must implement their own logic to pick up the right cert, do you
> think OpenSSL
> will implement this logic too? Or it's a more appropriate approach to
> just
> use the extensions you suggested?
With the fix mentioned above, chain building and verification will
always succeed,
regardless how the cert looks like because in this case it is sufficient
to find the target certificate in the trust store,
without having to check and further data that may be included in it.
Although not required by RFC 5280 for such a cert, OpenSSL does check
for its expiration
(and may check policy restrictions etc.) because this is helpful in most
application scenarios.

Regards,

    David


> David von Oheimb <dev at ddvo.net <mailto:dev at ddvo.net>> 于2020年12月26日周六
> 下午5:17写道:
>
>     On 25.12.20 00:35, 定平袁 wrote:
>>     @David von Oheimb <mailto:dev at ddvo.net> I will update to a new
>>     version and try again.
>
>     Good. Ideally try also a current 3.0.0 alpha release because there
>     have been some changes to cert chain building and verification
>     recently.
>
>>     To append cert is to make sure new cert and old cert both exist
>>     in trust store, thus when server switches cert, it can be trusted
>>     by client.
>     Understood, but my point was on a different aspect:
>     The chain building will take the first matching cert, so if you
>     want to prefer the new cert, it must be in the list *before* the
>     old one -
>     in other words, prepend the new cert to the list rather than
>     appending to it.
>
>>     @Jochen actually, the certs have different SN, which indeed is
>>     not consistent with the man doc
>
>     Different certs with the same issuer indeed *must* have different
>     SNs (except in the special case I mention below).
>     See also RFC 5280 section 4.1.2.2
>     https://tools.ietf.org/html/rfc5280#section-4.1.2.2:
>
>       It MUST be unique for each certificate issued by a given CA
>          (i.e., the issuer name and serial number identify a unique certificate). 
>
>
>     Yet there is a different inconsistency in what you write:
>
>>     The thing that confuses me is that CURL (compiled with gnutls)
>>     and Golang works.
>>     below is my ca.crt file, I am not sure where it went wrong, maybe
>>     just my wrong behavior?
>     You refer to them as CA certs, but they are not: they do no have a
>     basicConstraints field with the cA bit set.
>     And as far as I understand your scenario, they are not used to
>     issue other certs but by some (TLS) server,
>     so they really are end-entity (EE) certs, not CA certs, and it
>     looks like this is correct in your application scenario.
>
>     Directly trusted self-issued EE certs (which may be self-signed or
>     not) are a special situation.
>     This has been clarified in RFC 6818 (which updates RFC 5280)
>     https://tools.ietf.org/html/rfc6818#section-2:
>
>     | Consistent with Section 3.4.61 <https://tools.ietf.org/html/rfc6818#section-3.4.61> of X.509 (11/2008) [X.509 <https://tools.ietf.org/html/rfc6818#ref-X.509>], we note
>     | that use of self-issued certificates and self-signed certificates
>     | issued by entities other than CAs are outside the scope of this
>     | specification.  Thus, for example, a web server or client might
>     | generate a self-signed certificate to identify itself.  These
>     | certificates and how a relying party uses them to authenticate
>     | asserted identities are both outside the scope of RFC 5280 <https://tools.ietf.org/html/rfc5280>.
>
>     So the path building and verification, as well as other checks
>     defined RFC 5280, does not apply to them at all!
>     They are essentially just a convenient container for a public key,
>     where it is optional to check expiration etc.
>
>
>     Unfortunately, when using such certs for TLS connections etc.,
>     still verification is done on them, which may fail.
>     After renaming your ca.crt file to ee.crt for clarity and
>     extracting the first cert in ee1.crt and the second one in ee2.crt,
>     when verifying these directly trusted certs one gets the problem
>     you reported:
>
>     openssl verify -x509_strict -trusted ee.crt ee1.crt
>     ee1.crt: OK
>
>     openssl verify -x509_strict -trusted ee.crt ee2.crt
>     C = US, ST = CA, L = Palo Alto, O = VMware, CN =
>     nsxmanager.pks.vmware.local
>     error 18 at 0 depth lookup: self signed certificate
>     error ee2.crt: verification failed
>
>     So as I wrote before, unfortunately the path building picks up the
>     first matching cert from ee.crt,
>     which is the one in ee1.crt (i.e., your old one), and does not try
>     the second one (i.e., your new one).
>     This happens also with the latest OpenSSL pre-3.0.0 master.
>
>
>     A solution is to add both the subjectKeyIdentifier and
>     authorityKeyIdentifier extensions to your certs,
>     for instance like this:
>
>     echo >ee.cnf "
>     prompt = no
>     distinguished_name = my_server
>     x509_extensions = my_exts
>     [my_server]
>     commonName = test
>     [my_exts]
>     basicConstraints = CA:false
>     subjectKeyIdentifier=hash
>     authorityKeyIdentifier = keyid"
>
>     openssl req -config ee.cnf -new -x509 -out ee1.crt -nodes -keyout
>     ee1.pem
>     openssl req -config ee.cnf -new -x509 -out ee2.crt -nodes -keyout
>     ee2.pem
>     cat ee1.crt ee2.crt >ee.crt
>
>     The subjectKeyIdentifier and authorityKeyIdentifier extensions are
>     generally recommend
>     (and actually required to add for certs that are RFC 5280 compliant)
>     because they help for correct chain building, and indeed also in
>     this case they do:
>
>     openssl verify -x509_strict -trusted ee.crt ee1.crt
>     ee1.crt: OK
>     openssl verify -x509_strict -trusted ee.crt ee2.crt
>     ee2.crt: OK
>
>     Regards,
>
>         David
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mta.openssl.org/pipermail/openssl-users/attachments/20210101/09e2d3c4/attachment-0001.html>


More information about the openssl-users mailing list