Unable to upload intermediate CA certificate

My setup:

  • External-to-vault root CA
  • Vault-generated Intermediate key and CSR
  • Sign CSR with root CA
  • Import to Vault
    • This is where it fails

The problem:
When I try to upload the signed certificate, vault rejects it because “Refusing to import non-CA certificate”.

What I’ve tried:

vault write pki/keys/generate/internal \
      key_name=example-imca \
      key_type=rsa \
      key_bits=4096

vault write -format=json pki/intermediate/generate/existing \
  key_ref=example-imca \
  common_name="example.com Intermediate Certificate" | jq -r .data.csr > /tmp/example-imca.csr.pem

openssl x509 \
  -req \
  -days 3650 \
  -CA example-root.crt.pem \
  -CAkey example-root.key.pem \
  -in /tmp/example-imca.csr.pem \
  -out /tmp/example-imca.crt.pem

vault write pki/intermediate/set-signed \
  certificate=@/tmp/example-imca.crt.pem

Everything works fine up until the final command. That’s when it throws the “Refusing to import non-CA certificate” error.

Everything seems to be pretty straight forward, but it’s failing. I don’t know what I’m missing.

Hi @pjbehr87,

When you check your example-imca.crt.pem with openssl, does it have the flag CA:TRUE? You could check with openssl -in /tmp/example-imca.crt.pem -noout -text

I assume you meant the command openssl x509. Sorry for the late response, there was a networking rework and I lost access to the machine in question for a few days.

Here is the complete output (with the issuer identifying information removed) of that command:

Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            16:e6:f1:d4:a9:7d:e1:25:24:68:4a:3f:6d:76:66:6a:33:a8:b4:de
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, ST = , L = , O = , OU = , CN = 
        Validity
            Not Before: Jul  2 00:43:13 2024 GMT
            Not After : Jun 30 00:43:13 2034 GMT
        Subject: CN = example.com Intermediate Certificate
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (4096 bit)
                Modulus:
                    00:c2:57:2f:5f:de:96:91:b0:9b:2c:e2:a4:6f:47:
                    e9:a7:fa:45:92:d7:ae:a7:41:e9:5f:4a:e2:73:ad:
                    c8:80:ed:68:08:62:57:63:43:08:f7:4e:be:b1:df:
                    67:b4:aa:76:15:07:02:4d:d7:d5:23:31:a8:b3:c3:
                    03:a2:1d:9e:67:0a:64:db:dd:ab:b0:37:93:ba:cc:
                    7a:19:aa:d3:da:be:c8:af:28:86:aa:f6:50:47:fc:
                    29:34:d2:de:e2:69:96:bd:20:5f:75:a2:27:d7:7e:
                    5f:c6:c0:ec:35:51:9a:55:61:7a:46:97:e2:0c:08:
                    e1:a3:1c:ea:83:f4:17:b6:1b:9f:17:74:4a:30:96:
                    33:d4:76:a5:c5:5f:f8:f7:94:53:1a:74:1e:d2:16:
                    d6:13:9f:0f:5e:97:4a:ce:59:6e:d2:00:ad:68:8c:
                    75:7c:21:35:5c:52:cb:f8:5e:1c:8e:83:ee:a9:ff:
                    9b:c4:4d:9d:6a:61:2d:03:03:aa:07:19:93:75:c6:
                    e9:41:7e:5d:14:1b:9c:75:07:ba:d2:a2:77:89:d8:
                    f6:47:eb:6b:06:c3:69:42:16:6c:bd:0c:7f:be:45:
                    83:0e:a4:95:72:2c:61:46:d8:59:a1:f6:67:c4:2d:
                    93:68:2d:eb:dd:35:cd:63:77:a2:ee:2c:01:99:c4:
                    30:94:a9:d9:03:e6:70:ee:6f:27:14:4d:b7:fa:52:
                    7c:6f:1d:c4:99:4f:03:d9:5b:ae:c0:1b:63:43:d1:
                    5f:d9:f0:33:c8:27:c9:c6:6a:a3:49:0c:af:b1:5a:
                    69:9f:e9:4c:e4:08:49:87:03:86:40:36:1f:bc:41:
                    07:20:69:30:17:c4:51:35:42:c9:ea:63:9d:3a:b0:
                    bb:42:c4:ad:16:c2:b5:0c:74:e2:a3:7a:a2:94:3d:
                    72:3d:8b:bf:04:95:c4:74:e0:50:49:51:ae:12:c7:
                    a7:97:d4:18:8a:4c:3b:b5:99:34:b7:85:90:4c:27:
                    6f:20:db:e8:fc:93:ae:5c:1b:b9:74:32:c3:5b:e1:
                    3b:cd:4d:10:33:8b:52:4c:f4:ae:39:59:a9:a0:33:
                    61:43:d0:a7:74:8b:49:23:99:23:a1:87:1f:de:71:
                    44:11:b9:38:a5:69:1d:7b:c3:b7:56:24:9d:35:7c:
                    b9:06:39:27:f5:43:2d:62:6e:43:4a:dd:d4:5f:f9:
                    c2:b3:40:58:5a:f7:2b:1e:c3:b7:22:32:52:d3:d4:
                    bd:df:c4:7b:8f:8a:da:88:52:1b:52:6e:e7:30:1e:
                    a5:f9:db:d8:40:a6:4a:31:7c:6f:48:41:0c:5e:53:
                    95:59:e7:f8:81:4c:eb:40:0e:42:ab:1d:02:76:56:
                    c8:28:19
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         35:e9:08:65:ed:6b:8b:fe:47:8b:91:89:3b:00:83:f4:9e:b6:
         df:9a:44:9c:83:15:77:b9:86:8e:59:14:00:fd:ce:eb:2c:63:
         a6:c9:29:0a:d6:63:3c:9e:ab:3f:7a:f9:82:01:2e:b0:23:24:
         bd:f2:04:f1:ab:03:a6:bb:3e:20:d5:e4:cf:88:24:a0:a9:72:
         5c:5e:af:6f:a5:ab:9b:f5:c8:ff:23:d1:eb:e3:d8:1c:c7:36:
         94:b1:1e:39:bc:67:f1:0d:83:37:4b:e0:e0:98:0c:d4:64:6a:
         96:e0:14:83:1d:b8:6b:e6:0b:bc:a4:2d:b8:ee:8a:b2:21:77:
         39:d5:dd:fe:65:cd:1e:73:b4:dd:a5:8b:5c:fe:af:9f:4e:d4:
         f7:2e:73:b4:67:56:26:83:ef:00:90:bd:42:1d:cf:e1:da:57:
         f3:bf:3a:aa:27:6b:32:8b:2c:db:df:61:1f:a1:9f:df:c3:29:
         6b:a6:1c:44:e4:19:ae:fe:69:b3:0d:15:8f:e2:99:f3:31:18:
         fd:27:b0:75:ef:16:a9:39:3b:ec:93:66:75:5c:7a:42:5b:1d:
         93:00:be:8c:c3:fe:7e:19:42:f8:40:0d:1d:71:07:fd:39:f2:
         7c:e2:cb:2c:f7:de:52:25:9f:15:98:c4:98:15:c7:0a:7a:a0:
         35:5f:16:98:c1:38:c1:6c:64:55:ad:0c:3b:b1:30:1e:13:e4:
         31:e9:c9:20:70:2d:7c:13:7b:b1:2a:56:83:1b:f6:57:26:c7:
         45:de:56:13:95:3e:fb:7f:52:e6:b6:6c:e5:4e:8d:1d:72:36:
         b3:99:e3:05:87:16:eb:a8:50:74:24:f4:95:4b:aa:83:71:bf:
         b3:6a:99:18:c0:ce:f0:b1:15:51:99:83:7d:8a:b7:81:96:1a:
         a6:c0:16:b3:f9:ef:31:d3:c2:5a:9d:b9:4b:17:f1:97:d9:19:
         8a:54:96:e7:24:26:07:ae:f9:30:7c:c6:54:b7:40:e0:58:f4:
         8f:df:cc:6d:81:e6:96:4c:66:87:2c:0f:08:e6:6b:4f:98:16:
         8a:a7:7a:c5:14:66:77:cb:f0:bb:df:2e:c7:89:fd:be:f4:45:
         6e:7d:59:3f:81:e5:ed:61:04:22:a0:22:fe:1b:a3:f1:93:03:
         97:6e:bd:2b:1d:ca:11:30:63:1e:97:6c:11:f7:a8:a2:f0:7e:
         34:5f:26:2d:5c:5e:e7:75:26:2d:fd:a5:3c:29:a4:7b:a5:57:
         4b:db:16:be:62:08:07:86:e6:b6:e4:c4:ff:e4:83:33:24:04:
         b9:7e:b6:b6:0d:6d:f1:10:68:72:3a:7d:41:fd:74:6b:91:49:
         24:42:0e:ac:13:67:48:af

I assume you meant the command openssl x509

Exactly! Sorry I missed that part in my copy paste.

The output you provided shows me that this is not a CA certificate (the X509v3 extensions block is missing, where the CA:TRUE basic constraint should be set for CAs, /docs/manmaster/man5/x509v3_config.html).

To sign the CSR with the CA flag set to true, you can try the following:

# create openssl configuration to sign a subordinate CA
CA_CONFIG="
[ req ]
distinguished_name = dn
[ dn ]
[ ext ]
basicConstraints   = critical, CA:true, pathlen:1
keyUsage           = critical, digitalSignature, cRLSign, keyCertSign
"

# use req command to sign, include the X509v3 extensions
openssl req \
  -x509 \
  -days 3650 \
  -CA example-root.crt.pem \
  -CAkey example-root.key.pem \
  -in /tmp/example-imca.csr.pem \
  -out /tmp/example-imca.crt.pem \
  -config <(echo "$CA_CONFIG") -extensions ext

Note that the openssl command used here is openssl req command, not the x509 command, because the later can only be used to sign “leaf” certificates (server/client certs). From the openssl-req manpage (/docs/manmaster/man1/openssl-req.html):

It can additionally create self-signed certificates for use as root CAs for example.

After signing with openssl req you should be able to verify the extension block in the certificate (openssl x509 -in /tmp/example-imca.crt.pem -noout -text).

I also quickly tested with your commands (vault server -dev) and the resulting CA certificate loads fine back into Vault (pki/intermediate/set-signed).

Hope it helps. I think the basic issue here is the missing extensions in the certificate that makes it a valid CA.

2 Likes

Thank you so much for your help. I’m now getting a different error, which is progress I’m happy to see.

Some slight modifications to your code to get it to work (in case anyone else finds this in the future):

openssl req \
  -x509 \
  -days 3650 \
  -key ~/darc-net-root.pem \
  -in /tmp/example-imca.csr.pem \
  -out /tmp/example-imca.crt.pem \
  -config <(echo "$CA_CONFIG") \
  -extensions ext

The new error is:

URL: PUT http://172.16.7.245:8200/v1/pki/intermediate/set-signed
Code: 500. Errors:

* 1 error occurred:
        * Rebuilding the CRL failed. While this is indicative of a problem with the imported issuers (perhaps because of their revocation_signature_algorithm), they did import successfully and are now usable. It is strongly suggested to fix the CRL building errors before continuing. The original error is reproduced below:

        error building CRLs: error building CRLs: unable to build CRL for issuer (72365bbc-a92e-7b1c-2d0a-a8f5d0b8d922): error creating new CRL: x509: issuer certificate doesn't contain a subject key identifier

So I added the subjectKeyIdentifier to the CA_CONFIG variable:

CA_CONFIG="
[ req ]
distinguished_name = dn
[ dn ]
[ ext ]
basicConstraints     = critical, CA:true, pathlen:1
keyUsage             = critical, digitalSignature, cRLSign, keyCertSign
subjectKeyIdentifier = hash
"

Which adds the SKI info to the signed certificate:

X509v3 extensions:
  X509v3 Basic Constraints: critical
    CA:TRUE, pathlen:1
  X509v3 Key Usage: critical
    Digital Signature, Certificate Sign, CRL Sign
  X509v3 Subject Key Identifier: 
    81:5A:83:E8:04:DE:FE:F8:BC:16:60:43:79:57:70:4C:7A:92:8C:B8

But the error persists even with the newly signed cert with the SKI added.
Thank you so much for your help!

Hi @pjbehr87,

Glad you slowly get it working. I know PKI is a jungle though…

I can reproduce your new error. Please note that the import of the CA was successful. From the error message:

“they did import successfully and are now usable”

Vault supports cross-signed CAs. This means, theoretically, you can have multiple issuers for one PKI endpoint (PKI secrets engine - considerations | OpenBao).

You can check all the issuers on the current PKI engine mount point with:

bao list pki/issuers
Keys
----
914ea320-3b76-a826-4d9c-79cb069223b6
bdfc2237-8f0c-a9d6-8890-445138d96924

I assume that you have at least two issuers in your PKI mount (one of them with the missing SKI).

The general recommendation is to have “One CA certificate, one secrets engine”, meaning, one issuer per PKI mount (PKI secrets engine - considerations | OpenBao). This just to keep things simple. Most use cases don’t require cross-signed certificates (it has a use case for rotation, though I don’t want to go into details, PKI secrets engine - rotation primitives | OpenBao).

tl;dr;

What helped in my case was disable the engine and start from scratch:

bao secrets disable pki

Then generate the internal key and the csr, sign the csr (once, including the SKI) and you should be good.

The problem is, because you had one issuer in that list which does not have SKI. This tripped the CRL generation process, because the CRL is still maintained once per PKI mount (see point 1 in PKI secrets engine (API) | OpenBao). Note the warning in the previous link, to always set a default issuer explicitly.

Another solution I found was setting the “default issuer” (PKI secrets engine (API) | OpenBao) to an issuer that has the SKI:

bao write pki/config/issuers default=335f66a1-030e-e086-14cb-5a3b51edd807

You can also check, which issuer has the SKI:

bao read -field=certificate pki/issuer/253f5c78-9369-29e4-8863-0036e39b34a8 | openssl x509 -noout -text

But as mentioned, I would only configure one issuer per PKI mount unless required otherwise.

I did not check the default_follows_latest_issuer flag (of the pki/config/issuers endpoint), though I think setting this to true would also fix the CRL generation process when a new signed CA with SKI is uploaded.

That did it!

Thank you for the explanation. Every guide I’ve found on the subject assumes that you’re already versed in the arcane art of PKI. This was extremely helpful.