14

I created a self-signed root Certificate Authority for a few internal services in our company, which I configured myself (mostly served over HTTPS). Then I created certificates for those services, signed with this CA.

Now I want to add an x509 extension (CRL distribution point) to the root CA without invalidating existing server certificates issued from this CA. Is this possible?

My gut feel is "yes" because as I understand, access to the corresponding private key is necessary and sufficient for "full authority" over certificate identity. That is, unless there is some sort of nonce incorporated along with the public key into the certificate when it is generated (likely).

I'm still fairly new to SSL certificate management, but I (think I) understand the basics of the standard trust chain. I'm also comfortable with basic use of other PKI crypto: I manage SSH keys and use GPG for signing and encryption. I studied Computer Science, though I'm only a self-taught dabbler in cryptography.

I never made a CSR for the original IIRC (I think it was the direct output of openssl req -new -x509). I still have the original CA's private key, of course, and using it I was able to "reverse" the original cert into a Certificate Signing Request: openssl x509 -x509toreq -in MyCA.pem -out MyCA.csr -signkey private/MyCA.key

I was hoping this would effectively "extract" the nonce mentioned above, and allow me to recreate the certificate but this time with a crlDistributionPoints field, and consequently all certificates that were signed with the original CA would still validate against this new CA, with the exception that clients would retrieve my (currently empty) CRL file from the HTTP URL designated in the field.

So I made an extension config file ext.conf:

[ cert_ext ] 
subjectKeyIdentifier=hash
crlDistributionPoints=URI:http://security.mycompany.co.za/root.crl

And I generated the new version of the root CA from the CSR:

openssl x509 -extfile ./ext.conf -extensions cert_ext -req -signkey private/MyCA.key -in MyCA.csr -out MyNewCA.pem

Now when I view the certificate with openssl x509 -text -in MyNewCA.pem | less

I can see the CRL extension part:

X509v3 extensions:
    X509v3 Subject Key Identifier: 
        82:D0:01:03:49:FF:30:16:FA:DC:0A:1E:C1:8C:3D:66:A1:78:FF:F8
    X509v3 CRL Distribution Points: 

        Full Name:
          URI:http://security.mycompany.co.za/root.crl`

But alas! My previously signed certificates no longer validate against this one:

openssl verify -verbose -CAfile MyCA.pem git.pem 
git.pem: OK

openssl verify -verbose -CAfile MyNewCA.pem git.pem 
git.pem: <redacted DN>
error 20 at 0 depth lookup:unable to get local issuer certificate

Mostly I'm looking for more insight into how certificates work and why. But I'd also welcome a solution to the problem that lead to this one, so here's some background info too.

How I got into this mess: HTTPS to internal services work great once my CA is installed via the Explorer RMB → Install Certificate GUI on Windows, or the /usr/local/share/ca-certificates followed by update-ca-certificates on Debian and Ubuntu. But I recently ran into an exception: Git on Windows, specifically if installed to use Windows Secure Channel as SSL back-end. Which apparently by default insists that there must be a CRL field in SSL certificates.

So I guess it's really a Windows Secure Channel issue because the error message I keep running into seems entirely Microsoft-specific: fatal: unable to access 'https://angery@git.mycompany.co.za/gitblit/r/secret_project.git/': schannel: next InitializeSecurityContext failed: Unknown error (0x80092012) - The revocation function was unable to check revocation for the certificate.

If I install Git with OpenSSL and manually concatenate my CA onto the file pointed to by git.http.sslcainfo then it works, but I fear my users will be inclined to nope out on SSL identity verification if they feel this process is more effort than clicking through the "easy" Windows certificate installer GUI.

6
  • 1
    Only the public key and the Subject makes a certificate unique. Therefore, if you don't change either, you should be able to re-sign your certificate while altering all other fields and extensions to your heart's content. Jul 13, 2017 at 13:07
  • @garethTheRed ah, that makes sense. I'm not sure how to do this; could you elaborate or post an answer with more details? I hoped that -x509toreq would recover all unique info from the existing root CA, but either it doesn't or there's something wrong with my process from there. Jul 14, 2017 at 13:14
  • 1
    req -new -x509 and x509 -req -signkey both default the serial of the self-signed cert to a random number (although this can be overridden) effectively a nonce. If your child cert (or any of them) contains AuthorityKeyIdentifier using the 'issuer+serial' option (instead of or in addition to the 'keyid' option), which will be the case if you used ca with the upstream default config file, you need to create the new root with the same serial as the old one; use -set_serial. ... Jul 15, 2017 at 11:40
  • ... But some sw may be unhappy if you try to import a new cert with the same name and serial as an existing one; you may need to clean out the old one first. Jul 15, 2017 at 11:44
  • 1
    Near-cross-dupe security.stackexchange.com/questions/17331/… PS: I think it's possible to get Windows to manually cache the CRL for a CA in which case the lack of CRLDP might not matter, but how inconvenient that would be I don't know. Jul 15, 2017 at 11:54

1 Answer 1

8

Two certificates are considered the same as long as the Subject Name and the Public Key of the certificates match.

Therefore, all you need to do is to re-use the keys and ensure that the Subject Name in the new certificate is the same as the old. After that, you can change any of the other fields and/or extensions and the resulting certificate will be considered the same.

For example, create your OpenSSL configuration file:

[ req ]

prompt             = no
string_mask        = default
distinguished_name = x509_distinguished_name
x509_extensions     = x509_ext

[ x509_distinguished_name ]

# Note that the following are in 'reverse order' to what you'd expect to see.
# Adjust for your setup:

countryName = za
organizationName = My Company
organizationalUnitName = Security
commonName = My Root CA

[ x509_ext ]

basicConstraints = critical,CA:true
keyUsage = critical, keyCertSign, cRLSign
subjectKeyIdentifier = hash
crlDistributionPoints = URI:http://security.mycompany.co.za/root.crl

and save it as e.g. rootca.cnf. Ensure that the elements of the [req_distinguished_name] are identical to the ones in your original Root CA certificate (this is the identical Subject Name part).

Next, run:

openssl req -new -x509 -key rootca.key -out MyNewCA.pem -config rootca.cnf

where rootca.key is the private key used in the original certificate (this is the identical Public/Private Key part).

This creates MyNewCA.pem, which you can check with:

$ openssl x509 -noout -text -in MyNewCA.pem

Certificate:
Data:
    Version: 3 (0x2)
    Serial Number: 17564687072266118846 (0xf3c24dd49d5166be)
Signature Algorithm: sha256WithRSAEncryption
    Issuer: C=za, O=My Company, OU=Security, CN=My Root CA
    Validity
        Not Before: Jul 15 05:05:54 2017 GMT
        Not After : Aug 14 05:05:54 2017 GMT
    Subject: C=za, O=My Company, OU=Security, CN=My Root CA
    Subject Public Key Info:
        Public Key Algorithm: rsaEncryption
            Public-Key: (2048 bit)
            Modulus:
                00:c8:3d:32:8a:56:31:f6:27:1a:ce:9e:b2:1d:fb:
                ce:9f:ce:5b:42:25:aa:fe:8b:f4:34:32:ac:b3:02:
                50:71:f8:c3:43:0c:c7:2c:9f:fe:48:1b:c6:c0:e7:
                d6:44:a9:e7:d7:a0:7e:58:f4:b6:38:61:7e:d0:af:
                0f:56:21:e7:49:7a:66:13:f5:7a:fe:3d:ab:65:f8:
                01:eb:52:a7:3b:ae:a0:cf:50:57:b9:e0:09:0b:1f:
                90:14:fb:18:56:1d:57:99:a9:76:a2:63:d1:c2:d3:
                a3:f4:3a:ff:91:0d:ee:8d:44:13:58:00:09:93:da:
                e8:6a:fd:64:5f:c3:42:8e:2a:49:6e:0d:73:b7:b9:
                d4:6c:c6:ce:30:c5:82:24:a5:00:37:17:a0:1d:f1:
                c9:e9:e3:18:48:22:4f:33:96:a7:3c:a9:31:f1:3f:
                14:40:6a:74:e8:78:82:45:04:d4:4b:56:0b:cd:be:
                48:8d:03:fb:39:70:0b:91:99:70:06:bd:5e:8b:f2:
                d1:f4:6f:fc:ce:e7:f8:3c:0a:20:ea:35:b8:5f:2f:
                ee:8d:ff:d3:93:85:6b:fb:71:db:1b:e6:e9:1d:a7:
                f8:e4:ae:f4:71:fe:35:a7:89:24:af:69:a4:34:3b:
                14:66:05:02:5e:2a:1d:ac:e0:d2:48:6c:13:4e:75:
                58:93
            Exponent: 65537 (0x10001)
    X509v3 extensions:
        X509v3 Basic Constraints: critical
            CA:TRUE
        X509v3 Key Usage: critical
            Certificate Sign, CRL Sign
        X509v3 Subject Key Identifier: 
            3B:45:93:3A:2A:BC:39:29:36:13:6C:BD:B6:B4:31:C7:E7:BB:32:73
        X509v3 CRL Distribution Points: 

            Full Name:
              URI:http://security.mycompany.co.za/root.crl

Signature Algorithm: sha256WithRSAEncryption
     4d:96:d4:03:4f:e3:7c:26:be:59:f8:23:87:60:f7:4c:d3:a1:
     1c:77:a1:14:e3:e7:da:c8:2a:a3:1b:06:2a:4d:55:1c:83:26:
     73:46:0d:8a:e4:b7:d1:1e:38:cc:78:90:00:01:b3:8e:f9:3c:
     62:be:04:09:90:4e:22:87:b1:aa:bd:f9:73:bd:a7:76:ad:d5:
     ae:2d:7a:1c:1e:1a:67:c8:57:4c:f9:6d:8b:62:d6:e5:ea:e0:
     40:5c:12:28:7e:ea:f0:0c:d6:cd:f4:1d:d5:56:09:ad:43:b4:
     eb:8c:68:ce:56:a2:a8:ae:a4:d5:35:bb:58:b8:ed:82:82:b5:
     ef:cb:e2:6d:76:61:ed:ee:a5:1f:68:95:07:ed:5b:f0:65:92:
     d2:dc:1d:c6:fa:7f:e0:c9:38:c2:c6:6f:03:38:e7:3a:b0:24:
     06:e0:bc:07:dd:e7:a0:dc:74:09:e5:37:7b:66:e1:6f:47:4c:
     71:ff:02:48:7f:d4:4f:ce:cb:91:e9:ee:cd:b6:f1:0a:03:19:
     3e:19:05:7d:8f:48:e7:f1:cc:07:37:3d:91:3c:6f:54:71:3c:
     a2:6c:55:c3:03:c1:7f:eb:9e:70:f1:8f:a1:fb:62:33:8b:86:
     2c:79:bc:76:e2:01:9a:68:df:af:40:a1:b2:9c:f6:a1:e1:6e:
     2a:dd:1a:d6

Use this new certificate in place of the original.

You can change other fields and extensions, such as the validity period of the certificate, but bear in mind that you shouldn't really have any constraints (other than basicConstraints = critical,CA:true) on the Root CA certificate.


After further consideration, your issue may simply be down to the fact that your replacement Root CA certificate doesn't have the basicConstraint and possibly the keyUsage extensions. It might be worth trying adding those two extensions to your ext.conf first and testing the resulting new Root CA certificate using the -x509toreq method you posted.

1
  • Thanks for the comprehensive answer, it has really helped me understand things better. With this and @dave_thompson_085's comments I've managed to regenerate my CA in a way that doesn't invalidate child certs. There were a few things wrong with my original attempt (I should probably post an answer with more detail?) Also thanks for that obvious-in-retrospect but important point that "Subject Name" is a field composed of those particular fields. I somehow doubt anyone else will post an answer, so I'm accepting this one. Jul 17, 2017 at 9:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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