development, documentation, openssl, tls,

How to modify openssl CSR before signing

agowa338 agowa338 Mar 07, 2024 · 4 mins read
Share this

Some commands to change a Certificate Signing Request (CSR, or sometimes req) before signing it. Sometimes appliances generate a CSR but we do not want to sign it with the options it requested. This may be for different reasons, like it including undesired SAN names or not including some desired ones. Or it including just unwanted requestor strings.
Note: Sadly it is not possible to "patch" or regenerate the csr file without having the private key of the requestor. And if we have the private key we may as well just generate the desired CSR ourselfe.

Other common requirements

  • add/change/remove CPS, CRL, and OCSP URIs
  • remove sensitive information that the appliance doesn't allow to remove
  • Add a loadbalancer endpoint fqdn
  • Adding ipaddress entries
  • Adding somewhat invalid data to work around bugs in appliances. Like adding a SAN entry for the IP using "DNS:" instead of "ipaddress:"

Using -extfile

  1. Create tmp.cnf with your replacement content like e.g.:
    nsCertType = server
    nsComment = "OpenSSL Generated Server Certificate"
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid,issuer:always
    keyUsage = critical, digitalSignature, keyEncipherment
    extendedKeyUsage = serverAuth
    subjectAltName = @alt_names
    [alt_names]
    IP.1 = 127.0.0.1
    DNS.1 = localhost
  2. use this command to sign the reqest including our overwrite config:
    openssl x509 -req -in originalRequest.csr -out finalCert.crt -preserve_dates -copy_extensions copyall -CA pki/ca.crt -CAkey pki/private/ca.key -extfile tmp.cnf
  3. Check the final certificate:
    openssl x509 -in finalCert.crt -text -noout
  4. Using Easy-RSA

    Some basic customization is also available within Easy-RSA.
    # Move the originalRequest file into the req directory and thereby also change the file extension to req as Easy-RSA expects.
    mv originalRequest.csr ./pki/req/originalRequest.req
    
    # Example commands to sign:
    ./easyrsa --copy-ext sign-req server originalRequest preserve
    # Note: The help page says that when --san is used the names are "added to" but instead all san names need to be cli provided or they'll be overwritten by the ones you provided and any additional ones will be lost.
    # Note: Also note that even though this will show both san entries on the summary page it will NOT include both within the certificate. For me only the last one shown was ever included.
    #       And using a single parameter and separating the entries using semicolons or comma also didn't work. I think this may be a bug and will probably be fixed in a later version.
    ./easyrsa --san="DNS:localhost.localdomain,IP:127.0.0.1" sign-req server originalRequest preserve

    Alternatives

    • Try to extract the private key from the appliance to generate a CSR using it yourself, or generate keys externally and upload them. This doesn't work with most appliances, however if you're able to get your hands on the private key file easily it's the best solution.
    • Create a CSR for a dummy keypair and use the -force_pubkey option of openssl x509 -req to overwrite the publik key the final certificate is issued to with the real one. This approach requires a kind of backwards thinking and may be a bit confusing at first, however once you've been used to it its also rellatively straight forward.

    openssl x509 -req -force_pubkey

    1. Separate the public key from the original CSR file: openssl req -in original.csr -pubkey -out original.pub
    2. Create an entirely new "dummy" CSR that has all the correct information EXCEPT for the requestors public key: openssl req -newkey rsa:4096 -nodes -keyout dummy.key -out dummy.csr and append all other options you'd like to have, within your csr. Like e.g. -sub "/C=DE/ST=Hesse/L=Frankfurt/CN=Requestor Name or FQDN" or -config custom_openssl.conf.
    3. Now when we have one CSR with the desired options but the wrong Key and one with the correct key but the wrong options. We cannot get both within one CSR without also having the private key. BUT we can hand both files to openssl.
    4. Sign the certificate using our CA: openssl x509 -req -in dummy.csr -force_pubkey original.pub -CA pki/ca.crt -CAkey pki/privte/ca.key -out final.crt except for the -force_pubkey parameter this is the regular command to sign a CSR using your own CA keys. This parameter is what tells openssl to ignore the public key within the CSR and use the explicitely provided one. And similarly to the normal case it is also possible to add additional parameters like -extfile, -sha256, -sha512, -outform pem, ... here.

    Other useful openssl commands

    • Generate a new keypair: openssl genrsa -out yourServer_private.key 4096
    • Generate a "plain" CSR: openssl req -new -key yourServer_private.key -out yourServer.csr
    • Generate an advanced CSR: openssl req -new -key yourServer_private.key -out yourServer.csr -config tmp.cnf
    • Print CRT content: openssl x509 -in finalCert.crt -text -noout
    • Print CSR content: openssl req -in originalRequest.csr -text -noout

    Further links and references

agowa338
Written by agowa338