Using manage-certificates as a simple certification authority
If your server instances need to support an arbitrary or unknown set of clients, then it’s probably best to configure them with certificates from a trusted issuer, like a commercial authority or the free Let’s Encrypt service.
However, if you control all of the clients that will access the servers, then you might want to create your own internal certification authority. This allows you to have a common issuer for all servers so that clients just need to trust certificates signed by that issuer. There are commercial and open-source software packages that provide full-featured certification authority functionality, but you can also use the manage-certificates tool to create a certificate authority (CA) certificate and use it to sign certificate signing requests.
The first thing that you need to do is to create a certification authority certificate. This is a self-signed certificate that should have a key usage extension that includes at least the KeyCertSign usage, and a basic constraints extension that indicates that it’s a CA certificate. If you don’t plan to have an intermediate CA certificate, then the basic constraints extension should have a path length constraint of zero. If you do plan to have an intermediate CA certificate, then the path length constraint should be one to account for it. The CA certificate should also have a long life span because any certificates that it signs is only valid as long as all certificates in the chain are valid.
For example, you can use the following to create a new root CA certificate.
$ bin/manage-certificates generate-self-signed-certificate \
--keystore /ca/root-ca-keystore \
--keystore-password-file /ca/root-ca-keystore.pin \
--keystore-type JKS \
--alias root-ca-cert \
--subject-dn "CN=Example Root CA,O=Example Corp,C=US" \
--days-valid 7300 \
--key-algorithm RSA \
--key-size-bits 4096 \
--signature-algorithm SHA256withRSA \
--basic-constraints-is-ca true \
--basic-constraints-maximum-path-length 1 \
--key-usage key-cert-sign \
--key-usage crl-sign
Successfully created a new JKS keystore.
Successfully generated the following self-signed certificate:
Subject DN: CN=Example Root CA,O=Example Corp,C=US
Issuer DN: CN=Example Root CA,O=Example Corp,C=US
Validity Start Time: Monday, January 27, 2020 at 03:47:29 PM CST (0 seconds ago)
Validity End Time: Sunday, January 22, 2040 at 03:47:29 PM CST (7299 days, 23 hours, 59 minutes, 59 seconds from now)
Validity State: The certificate is currently within the validity window.
Signature Algorithm: SHA-256 with RSA
Public Key Algorithm: RSA (4096-bit)
SHA-1 Fingerprint: bc:8e:5b:30:52:ec:03:63:b4:9a:aa:1a:45:a0:fc:84:49:dd:e8:64
SHA-256 Fingerprint: d5:47:06:cd:a2:95:42:61:1f:c7:aa:04:16:1e:c1:70:41:c4:44:48:bf:74:20:5f:1c:61:e2:aa:40:08:3a:ff
You should then export the public portion of that root CA certificate so that you have it for reference, and so that it can be imported as a standalone certificate into trust stores and as part of a certificate chain when importing signed certificates.
If you want to create an intermediate CA certificate, then you should create a new certificate signing request for that certificate. It should essentially use the same settings as for the root CA, although if we assume that there is only a single intermediate CA, then its basic constraints extension should have a path length constraint of zero rather than one to indicate that it can only be used to sign end-entity certificates and cannot itself create subordinate CA certificates. That certificate signing request can be created with a command like the following.
$ bin/manage-certificates generate-certificate-signing-request \
--keystore /ca/intermediate-ca-keystore \
--keystore-password-file /ca/intermediate-ca-keystore.pin \
--keystore-type JKS \
--alias intermediate-ca-cert \
--subject-dn "CN=Example Intermediate CA,O=Example Corp,C=US" \
--key-algorithm RSA \
--key-size-bits 4096 \
--signature-algorithm SHA256withRSA \
--basic-constraints-is-ca true \
--basic-constraints-maximum-path-length 0 \
--key-usage key-cert-sign \
--key-usage crl-sign \
--output-file /ca/intermediate-ca-cert.csr \
--output-format PEM
Successfully created a new JKS keystore.
Successfully generated the key pair to use for the certificate signing
request.
Successfully wrote the certificate signing request to file
'/ca/intermediate-ca-cert.csr'.
Next, we need to use the root CA certificate to sign the certificate signing request for the intermediate CA certificate. That can be done with the sign-certificate-signing-request subcommand, which takes most of the same arguments as generating a self-signed certificate. The primary differences include:
-
The key store arguments provided should be for the key store containing the certificate to use to sign the request. The
--signing-certificate-alias
argument must be used to specify the name of the certificate to use to sign the request. -
You must provide a
--request-input-file argument
to specify the path to the file containing the certificate signing request file to generate. -
You can optionally provide a
--certificate-output-file
argument to specify the path to the file to which the signed certificate should be written. If this argument is omitted, then the PEM representation of the certificate is written to standard output. -
You can optionally provide an
--output-format
argument to specify the format (PEM or DER) in which the certificate should be written to the output file. -
You can optionally use the
--subject-dn
argument to specify the subject that should be used for the signed certificate, but you can omit it to indicate that the subject DN from the certificate signing request should be used. -
You cannot specify the key algorithm or key length, because the requester generated the key. You can, however, use the
--signature-algorithm
argument to specify the name of the signature algorithm. -
The
--include-requested-extensions
argument can be used to indicate that the signed certificate should include all of the extensions listed in the certificate signing request. If this argument is not provided, then you must explicitly specify the set of extensions that should be included.
For example, you can use a command like the following to sign the certificate signing request for an intermediate CA certificate.
$ bin/manage-certificates sign-certificate-signing-request \
--keystore /ca/root-ca-keystore \
--keystore-password-file /ca/root-ca-keystore.pin \
--signing-certificate-alias root-ca-cert \
--days-valid 7300 \
--include-requested-extensions \
--request-input-file /ca/intermediate-ca-cert.csr \
--certificate-output-file /ca/intermediate-ca-cert.pem \
--output-format PEM
Read the following certificate signing request:
PKCS #10 Certificate Signing Request Version: v1
Subject DN: CN=Example Intermediate CA,O=Example Corp,C=US
Signature Algorithm: SHA-256 with RSA
Public Key Algorithm: RSA (4096-bit)
Do you really want to sign this request? yes
Successfully wrote the signed certificate to file
'/ca/intermediate-ca-cert.pem'.
After you have the intermediate CA certificate, you should create secure, offline backups of the root CA certificate, and then remove it (or at least its private key) from all systems. All of the end-entity certificates should be signed with the intermediate CA certificate, and that process is identical to the example given above. The only reason that you should need to pull the root CA certificate out of cold storage is if you need to sign another intermediate CA certificate.