3

I am trying to restrict the intermediate CA to sign only end user certificates. However, I am not able to do so.

Man page of x509v3_config says

basicConstraints=critical,CA:TRUE, pathlen:0

A CA certificate must include the basicConstraints value with the CA field set to TRUE . An end user certificate must either set CA to FALSE or exclude the extension entirely. Some software may require the inclusion of basicConstraints with CA set to FALSE for end entity certificates.

The pathlen parameter indicates the maximum number of CAs that can appear below this one in a chain. So if you have a CA with a pathlen of zero it can only be used to sign end user certificates and not further CAs

Step 1: Create a self signed root CA - rootCA.crt

openssl genrsa -out rootCA.key 4096

openssl req -x509 -new -nodes -key rootCA.key -sha256 -out rootCA.crt

Step 2: Create a Certificate signing request using below configuration file.

openssl req -new -config extension.conf -out intermediate.csr

[ req ]
 default_bits       = 4096
 default_md         = sha256
 prompt             = no
 encrypt_key        = no
 default_keyfile    = privkey.key
 distinguished_name = req_distinguished_name
 req_extensions     = v3_req
 
 [ req_distinguished_name ]
 countryName            = DE
 stateOrProvinceName    = Bayern
 localityName           = Munich
 0.organizationName     = Test AG
 organizationalUnitName = Services
 emailAddress           = services.dept@test.de
 
 [ v3_req ]
 basicConstraints       = critical,CA:true, pathlen:0
 keyUsage               = keyCertSign

The CSR is generated now

Step 3: Now sign the CSR with self-signed root CA with support from extension file

openssl x509 -req -in intermediate.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -extensions v3_req -extfile file.txt -out intermediate.crt -sha256

file.txt

[ v3_req ]
 subjectKeyIdentifier   = hash
 authorityKeyIdentifier = keyid:always

Now intermediate certificate is generated.

Step 4: Create one more intermediate certificate and lets call it TEST certificate - using sightly modified configuration file as below:

[ req ]
 default_bits       = 4096
 default_md         = sha256
 prompt             = no
 encrypt_key        = no
 default_keyfile    = privkey.key
 distinguished_name = req_distinguished_name
 req_extensions     = v3_req
 
 [ req_distinguished_name ]
 countryName            = DE
 stateOrProvinceName    = Berlin
 localityName           = Berlin
 0.organizationName     = Dummy AG
 organizationalUnitName = Product
 emailAddress           = product.dept@dummy.de
 
 [ v3_req ]
 basicConstraints       = critical,CA:true
 keyUsage               = keyCertSign

Generate the CSR

openssl req -new -config test.conf -out TEST.csr

Sign the CSR with intermediate.crt which should not be possible.

openssl x509 -req -in TEST.csr -CA intermediate.crt -CAkey privkey.key -CAcreateserial -out TEST.crt -sha256

As per the man page of x509v3_config, signing of the TEST.csr should fail as it is not the end user certificate.

The pathlen is 0 in my intermediate certificate. So I shouldn't be able to sign the TEST.csr. What am I doing wrong here? Can some one please kindly explain?

1
3

First, if you look at the cert you created in step 3 with openssl x509 -text <intermediate.crt you'll see it doesn't have any BC extension (nor KU either). This is because creating a cert with openssl x509 -req -CA/CAkey does not use any extensions (more exactly, requested extensions) from the CSR. See Missing X509 extensions with an openssl-generated certificate https://serverfault.com/questions/845806/how-to-issue-ssl-certificate-with-san-extension https://superuser.com/questions/862838/s-mime-for-mac-and-ios .

But even if you fix this, OpenSSL mostly doesn't check the certificate when it does a privatekey operation, except in the SSL/TLS protocol (which requires full checks). (And in one case, smime|cms -encrypt, it apparently doesn't check even on a publickey operation.) The man page might more accurately say a CA cert with pathlen=0 can only validly sign leaf certs, not other sub-CA certs: OpenSSL, with either openssl ca or openssl x509 -req -CA [-CAkey] will actually sign a cert that violates pathlen (or even CA=false!), but if you subsequently use that cert in most cases it will fail validation and be rejected.

2

The pathlen is 0 in my intermediate certificate. So I shouldn't be able to sign the TEST.csr. What am I doing wrong here?

openssl is the swiss-army knife of PKI. It will do whatever you ask it to. I often need "illegal" certs when testing applications. The fact that openssl is not a drama queen about this makes it my tool of choice for PKI testing.


So you have a cert chain

Root [pathLen: 1] --> Int1 [pathLen: 0] --> Int1 [pathLen: ?] --> EE

Yes, that cert is illegal because of the EE is pathLen: 1 from Int1. Where you will see errors is not on issuance, but when you try to use this cert. Try putting that cert on a website (for example openssl s_server in front of a python3 -m http.server 8000 --bind 127.0.0.1 ). Try connecting to it with browsers. The browsers should throw cert errors (if they don't, open bug reports with the browser, you may even get a bug bounty since that would be a real security issue).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.