OpenSSL error "error 47 at 0 depth lookup: permitted subtree violation" explained, or: Why I have to generate a new CA root certificate
I wanted to get rid of the HTTPS-Warning when opening the web-frontend of my DSL-Router. As I still use the vendor-supplied selfsigned certificate there. Hence I used my ca-scripts (GitHub) to generate a certificate for the IP and standard hostname (fritz.box).
Only to get the error:
error 47 at 0 depth lookup: permitted subtree violation
error 192.168.1.1.crt: verification failed
Huh? This is how I used my script. hostcert.sh calls sign.sh to sign the CSR and verifies the signed certificate against the CA-Root certificate.
root@host:~/ca# ./hostcert.sh 192.168.1.1 fritz.box
CN: 192.168.1.1
DNS ANs: fritz.box
IP ANs: 192.168.1.1
Enter to confirm.
writing RSA key
Reading pass from $CAPASS
CA signing: 192.168.1.1.csr -> 192.168.1.1.crt:
Using configuration from ca.config
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'DE'
localityName :ASN.1 12:'Karlsruhe'
organizationName :ASN.1 12:'LAN CA host cert'
commonName :ASN.1 12:'192.168.1.1'
Certificate is to be certified until Mar 14 20:57:03 2027 GMT (365 days)
Write out database with 1 new entries
Database updated
CA verifying: 192.168.1.1.crt <-> CA cert
C=DE, L=Karlsruhe, O=LAN CA host cert, CN=192.168.1.1
error 47 at 0 depth lookup: permitted subtree violation
error 192.168.1.1.crt: verification failed
The offending command is:
root@host:~/ca# openssl verify -CAfile ca.crt fritz.box.crt
C=DE, L=Karlsruhe, O=LAN CA host cert, CN=fritz.box
error 47 at 0 depth lookup: permitted subtree violation
error fritz.box.crt: verification failed
The root cause is that I forgot that I added an X509v3 Name Constraints. This dictates that all Common Name or SubjectAltNames, have to end in .lan and clearly fritz.box is in violation of that.
root@host:~/ca# openssl x509 -in ca.crt -text | grep "X509v3 Name" -A2
X509v3 Name Constraints:
Permitted:
DNS:lan
The solution is to generate it solely for the IP, right?
root@host:~/ca# ./hostcert.sh 192.168.1.1
CA verifying: 192.168.1.1.crt <-> CA cert
C=DE, L=Karlsruhe, O=LAN CA host cert, CN=192.168.1.1
error 47 at 0 depth lookup: permitted subtree violation
error 192.168.1.1.crt: verification failed
Yeah no.. It's wrong too. In the first certificate the IP was also defined. I just thought fritz.box is the offending SAN as it is listed first (my script adds IP SANs after DNS SANs).
Through this I learned that as soon as one name constraint is specified, all SubjectAltNames have to follow the constraints. Constraints of type DNS and IPAddress are checked independently. And 192.168.1.1 doesn't match the Permitted DNS zone of .lan.
The corresponding RFC 5280 sections are:
- https://www.rfc-editor.org/rfc/rfc5280.html#section-4.2.1.10
- https://www.rfc-editor.org/rfc/rfc5280.html#section-6.1.4 scroll down to step (g).
Looks like I have to generate a new CA. Narf! This time however, I will make sure to extract all allowed and denied name constraints from the CA root certificate and check it against the supplied SubjectAltName BEFORE I create or sign the CSR.