I use the term “Service Certificate” here since we are attaching a certificate to a service, be it a web server running Apache or an sftp server using openssh.
On our workstations, we installed the Certificate of Authority (CA) at a very low level, so all services could use that to validate remote services. On our servers, we will install Certificates, signed by that CA, to validate that a service is really the one you think it is.
Doing this requires building a certificate, signing it with our CA, then exporting it to the server whose service we want to validate. An example would be an Apache web service, where we might put the certificate into a directory, then modify the Apache configuration to use that certificate for SSL sessions (ie, using https).
Creating the certificate is similar to creating a CA: We create a key file, then turn it into a certificate. The difference is, as an intermediate step, we create a CSR (Certificate Request) which uses the key, then we use that to create and sign the certificate with the CA. The basic functionality is shown in the following four steps.
We'll take each one in turn, then I'll show you a simple script that can automate the process.
The EXT file defines how to create the cert and what services it is valid for. You can have one or more names which the certificate is valid for. For example, if a web server can be called as web.example.local, or simply web, you would want both. If you want the same certificate to also handle mail.example.local, you could add that. And, in some cases, it is advantageous to include the IP address(es) of the server it is on.
An EXT file is a lot like a openssl.cnf file, but with some additional stanzas. To simplify things, I tend to copy the openssl.cnf file to a new file name, then add the additional stanzas, then use the same file for both.
Here is an example of an ext file which has been merged with an openssl.cnf file to allow it to be used for both functions.
[ req ] default_bits = 2048 # default key size default_md = sha256 # default message digest algorithm distinguished_name = req_distinguished_name # definition used for DN req_extensions = v3_req # go look at v3_req section for the extensions def prompt = no # do not ask questions, take defaults [ req_distinguished_name ] # Required fields CN = www.example.com # not required C = US ST = Texas O = Example Corp L = Dallas OU = Headquarters emailAddress = info@example.com [ v3_req ] keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth, clientAuth subjectAltName = @alt_names # look for section [ alt_names ] for all the names basicConstraints = CA:FALSE [ alt_names ] DNS.1 = www.example.local DNS.2 = example.local DNS.3 = mail.example.local DNS.4 = 192.168.1.1
Here, we've added prompt = no to tell openssl to not prompt us for values, but instead use what is in the ext file if possible. We have also added req_extensions = v3_req to tell it to go look in the stanza labeled v3_req for some additional information.
In the [v3_req] stanza, we tell what this key will be used for (critical, digitalSignature, keyEncipherment), tell it the extendedKeyUsage (serverAuth, clientAuth), and add a basicConstraint of CA:FALSE, meaning this is not a Certificate of Authority.
Finally, we give it subjectAltName, which points to another stanza where we will list one or more names the certificate will be responsible for.
In the alt_names, we list multiple DN (alternate names). The format is DNS=URL But, since openssl configuration files can not list the same key more than once, we modify it slightly by adding arbitrary text after a period. openssl will ignore anything between the period and the equals sign, so we just list them as DNS.1=name DNS.2=alias DNS.3=another alias
This is used when we build a Certificate Request and then integrated as alternate names in the subject for the DN.
I save this file as name (the primary name of the service) with an extension of .ext
Private key generation is the same as it was for the CA, except we do not want a password in most cases. If we have a password, it would require you to enter the password every time a service was restarted.
Here, we're creating a private key named www.example.internal.key. This allows us to know which key this is for. Also note we did not include the -des3. Leaving off the encryption algorithm tells genpkey that we don't want to encrypt the key.
openssl \ genpkey \ -algorithm RSA \ --outform PEM \ --out www.example.local.key \ --pkeyopt rsa_keygen_bits:2048
Creating a Certificate Signing Request is simpler since we have the configuration file created earlier. Basically, we call openssl with the req flag and tell it what to do.
openssl \ req \ -new \ -key www.example.local.key \ -out www.example.local.csr \ -config www.example.local.ext
You can almost read this in english. Create a new (-new) signing request (req) using the key www.example.local.key, sending the output to www.example.local.csr, using the parameters found in the config file www.example.local.ext.
The certificate file is what all of this is about. We generate it using the Signing Request (csr), signing with the key.
openssl \ x509 \ -req \ -in www.example.local.csr \ -CA vanduzen_CA.pem \ -CAkey vanduzen_CA.key \ -CAcreateserial \ -out www.example.local.crt \ -days 365 \ -sha256 \ -extfile www.example.local.ext
[ ca ] default_ca = CA_default [ CA_default ] dir = ./myCA # Location of the CA certificate and private key database = $dir/myCAindex # Database index file new_certs_dir = $dir/newcerts # Directory where new certs are stored certificate = $dir/ca.crt # The CA certificate private_key = $dir/ca.key # The CA private key default_md = sha256 # Default digest method preserve = no # Keep existing certificates (yes/no) policy = policy_any # Default policy for issuing certificates [ policy_any ] countryName = optional stateOrProvinceName = optional organizationName = optional organizationalUnitName = optional commonName = required emailAddress = optional
# create private key openssl genpkey -algorithm RSA -out server.key -pkeyopt rsa_keygen_bits:2048 # create certificate for private key openssl req -new -key server.key -out server.csr # sign with CA (see configuration) openssl ca -in server.csr -out server.crt -config openssl.cnf # view cert openssl x509 -in server.crt -text -noout