[openssl-users] Path Length Constraint ignored for Root and any self-issued certificate

Peter Magnusson blaufish.public.email at gmail.com
Mon Oct 8 12:47:53 UTC 2018


That is not correct behaviour as far as I can understand.

RFC5280 Certification Path Validation algorithm process from root to
leaf, i.e. (Root, EvilCA, EvilServer). 6.1.2 Initialization and 6.1.4
Preparation for Certificate i+1 is expected to occur upon Root
certificate, i.e. the following should be expected behaviour:
* max_path_length=n (initialisation)
* max_path_length=n-1 (first decrement)
* max_path_length=0 (copied from root certificate constraint)
* VERIFY(max_path_length>0) error upon preparing transition from i=1
(Root) to i=2 (EvilCA).

OpenSSL does everything in a slightly different reverse algorithm, but
should perform the same controls and behaivor as the RFC imho.

And aside from the RFC algorithm checking for this condition, it is
also analog with the description of the expected behaviour:

   The pathLenConstraint field is meaningful only if the cA boolean is
   asserted and the key usage extension, if present, asserts the
   keyCertSign bit (Section 4.2.1.3).  In this case, it gives the
   maximum number of non-self-issued intermediate certificates that may
   follow this certificate in a valid certification path.  (Note: The
   last certificate in the certification path is not an intermediate
   certificate, and is not included in this limit.  Usually, the last
   certificate is an end entity certificate, but it can be a CA
   certificate.)  A pathLenConstraint of zero indicates that no non-
   self-issued intermediate CA certificates may follow in a valid
   certification path.  Where it appears, the pathLenConstraint field
   MUST be greater than or equal to zero.  Where pathLenConstraint does
   not appear, no limit is imposed.

So my understanding is that the OpenSSL algorithm is confused and
fails to perform a check that is applicable to self-issued
certificates. The decrement of max_path_length (aka plen++ in OpenSSL
implementation) should not occur for self issued certificates, but the
validation of max_path_length>0 (aka plen>(constraint+1)) should
occur.
On Mon, Oct 8, 2018 at 1:27 PM J Decker <d3ck0r at gmail.com> wrote:
>
> It was my interpretation that 0 pathlen on the root self signed meant infinite.
> The pathlen only applies on the certs between root and the leaf (which obviously can be 0, and CA true or not, but bad form to say true I'd imagine.)
>
> On Mon, Oct 8, 2018 at 1:57 AM Peter Magnusson <blaufish.public.email at gmail.com> wrote:
>>
>> One more logic confusion in the OpenSSL Path Length Constraint check.
>> Any Path Length Constraint set by Root (or any other Self-Issued
>> Certificate) is ignored.
>> Root cause appears to be !(x->ex_flags & EXFLAG_SI)=0 incorrectly
>> applied to the checker (i.e. the checker and the calculation logic
>> have been mixed up).
>>
>> https://github.com/blaufish/openssl-pathlen/tree/master/testcase_2
>>
>> openssl x509 -text -in root.pem | grep -a1 "X509v3 Basic"
>>                 Certificate Sign, CRL Sign
>>             X509v3 Basic Constraints: critical
>>                 CA:TRUE, pathlen:0
>> openssl x509 -text -in evilca.pem | grep -a1 "X509v3 Basic"
>>                 Certificate Sign, CRL Sign
>>             X509v3 Basic Constraints: critical
>>                 CA:TRUE, pathlen:0
>> openssl x509 -text -in evilserver.pem | grep -a1 "X509v3 Basic"
>>         X509v3 extensions:
>>             X509v3 Basic Constraints: critical
>>                 CA:FALSE
>> ----
>> openssl x509 -text -in root.pem | egrep -a1 "X509v3 .* Key Identifier"
>>         X509v3 extensions:
>>             X509v3 Subject Key Identifier:
>>                 49:39:72:82:78:39:E8:60:AD:17:79:83:DB:65:B8:5C:E6:A7:84:B5
>> --
>> --
>>                 49:39:72:82:78:39:E8:60:AD:17:79:83:DB:65:B8:5C:E6:A7:84:B5
>>             X509v3 Authority Key Identifier:
>>
>> keyid:49:39:72:82:78:39:E8:60:AD:17:79:83:DB:65:B8:5C:E6:A7:84:B5
>> openssl x509 -text -in evilca.pem | grep -a1 "X509v3 .* Key Identifier"
>>         X509v3 extensions:
>>             X509v3 Subject Key Identifier:
>>                 B6:B4:75:66:18:B5:D2:4F:57:10:53:93:4F:CD:51:71:A4:27:84:7C
>> --
>> --
>>                 B6:B4:75:66:18:B5:D2:4F:57:10:53:93:4F:CD:51:71:A4:27:84:7C
>>             X509v3 Authority Key Identifier:
>>
>> keyid:49:39:72:82:78:39:E8:60:AD:17:79:83:DB:65:B8:5C:E6:A7:84:B5
>> openssl x509 -text -in evilserver.pem | egrep -a1 "X509v3 .* Key Identifier"
>>                 TLS Web Server Authentication
>>             X509v3 Subject Key Identifier:
>>                 03:C6:48:91:09:73:F5:DF:EF:B5:9D:A4:66:00:16:C3:E9:DB:99:EE
>> --
>> --
>>                 03:C6:48:91:09:73:F5:DF:EF:B5:9D:A4:66:00:16:C3:E9:DB:99:EE
>>             X509v3 Authority Key Identifier:
>>
>> keyid:B6:B4:75:66:18:B5:D2:4F:57:10:53:93:4F:CD:51:71:A4:27:84:7C
>> ----
>> ../openssl-1.1.1/apps/openssl verify -show_chain -verbose -CAfile
>> root.pem -untrusted evilca.pem evilserver.pem
>> ******* important variables *******
>> *** check_chain_extensions:524 i=0
>> *** check_chain_extensions:525 plen=0
>> *** check_chain_extensions:526 x->ex_pathlen=-1
>> ******* if statement components *******
>> *** check_chain_extensions:528 i > 1=0
>> *** check_chain_extensions:529 !(x->ex_flags & EXFLAG_SI)=1
>> *** check_chain_extensions:530 (x->ex_pathlen != -1)=0
>> *** check_chain_extensions:531 (plen > (x->ex_pathlen +
>> proxy_path_length + 1))=0
>> ******* important variables *******
>> *** check_chain_extensions:524 i=1
>> *** check_chain_extensions:525 plen=1
>> *** check_chain_extensions:526 x->ex_pathlen=0
>> ******* if statement components *******
>> *** check_chain_extensions:528 i > 1=0
>> *** check_chain_extensions:529 !(x->ex_flags & EXFLAG_SI)=1
>> *** check_chain_extensions:530 (x->ex_pathlen != -1)=1
>> *** check_chain_extensions:531 (plen > (x->ex_pathlen +
>> proxy_path_length + 1))=0
>> ******* important variables *******
>> *** check_chain_extensions:524 i=2
>> *** check_chain_extensions:525 plen=2
>> *** check_chain_extensions:526 x->ex_pathlen=0
>> ******* if statement components *******
>> *** check_chain_extensions:528 i > 1=1
>> *** check_chain_extensions:529 !(x->ex_flags & EXFLAG_SI)=0
>> *** check_chain_extensions:530 (x->ex_pathlen != -1)=1
>> *** check_chain_extensions:531 (plen > (x->ex_pathlen +
>> proxy_path_length + 1))=1
>> evilserver.pem: OK
>> Chain:
>> depth=0: C = SE, ST = EvilServer, L = EvilServer, O = EvilServer, OU =
>> EvilServer, CN = EvilServer (untrusted)
>> depth=1: C = SE, ST = EvilCA, L = EvilCA, O = EvilCA, OU = EvilCA, CN
>> = EvilCA (untrusted)
>> depth=2: C = SE, ST = Root, L = Root, O = Root, OU = Root, CN = Root
>> --
>> openssl-users mailing list
>> To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users
>
> --
> openssl-users mailing list
> To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-users


More information about the openssl-users mailing list