#!/usr/bin/env bash # Create self-signed certificates and keys for a CA and a server # Primarily for using with SSL/TLS to secure communications # between local servers and clients NOT ON THE INTERNET! # # Inspired by: https://github.com/Daplie/nodejs-self-signed-certificate-example/blob/master/make-root-ca-and-certificates.sh # # Use as: bash make-certs.sh 'localhost.daplie.com' # # Author: Julian Knight, Totally Information, 2016-11-05 # Updates: # v1.1 2017-12-08: JK change to add SAN as now required by Chrome # License: MIT, may be freely reused. function create_ca { # ------------------- CA -------------------- # # You can reuse CA certs, no need to recreate # # unless they are compromised # # ------------------------------------------- # # Create/update the ca/ca.cnf file create_ca_cnf # We need the ca.cnf file in order to create the CA cert if [ ! -f ca/ca.cnf ]; then echo " " echo "ERROR in create_ca() - STOPPING" echo " The ca/ca.cnf file does not exist." echo " Please ensure the cnf setup function has been run." echo " " exit 1 fi echo " " echo "Creating Root Certificate Authority private key" openssl genrsa \ -out ca/my-private-root-ca.privkey.pem \ 2048 echo " " echo "Creating the Self-signed Root Certificate Authority certificate" # Since this is private, the details can be as bogus as you like openssl req \ -x509 \ -new \ -nodes \ -days 9999 \ -outform PEM \ -key ca/my-private-root-ca.privkey.pem \ -out ca/my-private-root-ca.cert.pem \ -config ca/ca.cnf # Create CRT format copy for Windows use if needed openssl x509 -in ca/my-private-root-ca.cert.pem -out ca/my-private-root-ca.cert.crt echo " " echo "Import ca/my-private-root-ca.cert.crt to Windows Trusted Root store if required" echo " or use load-trusted-root.ps1" } function create_srv { # ------------- Server ------------- # # Need one of these for each server # # where you want different certs # # ---------------------------------- # # Create/update the ./ssl.cnf file create_ssl_cnf # We need the ./ssl.cnf file in order to create the CA cert if [ ! -f ./ssl.cnf ]; then echo " " echo "ERROR in create_srv() - STOPPING" echo " The ./ssl.cnf file does not exist." echo " Please ensure the create_cnf function has been run." echo " " exit 1 fi # We need the ca/ca.cnf file in order to sign the server cert request if [ ! -f ca/ca.cnf ]; then echo " " echo "ERROR in create_srv() - STOPPING" echo " The ca/ca.cnf file does not exist." echo " Please ensure the create_cnf function has been run." echo " " exit 1 fi # We need the CA private key and certificate files in order to create a server certificate if [ ! \( -f ca/my-private-root-ca.cert.pem -a -f ca/my-private-root-ca.privkey.pem \) ]; then echo " " echo "ERROR in create_srv() - STOPPING" echo " The CA private key and/or certificate files are missing." echo " Please ensure the create_ca function has been run." echo " " exit 1 fi echo " " echo "Creating a Server Private Key - KEEP THIS SECURE ON THE SERVER!" echo " It is required for the server to use SSL or TLS." openssl genrsa \ -out server/privkey.pem \ 2048 echo " " echo "Creating a temp request (CSR) from your Server, which your Root CA will sign" # 1 for each domain such as 192.168.1.167, example.com, *.example.com, awesome.example.com # NOTE: You MUST match CN to the domain name or ip address you want to use # Multi-domain certs require the use of a configuration file and SubjectAltName openssl req -new -sha256 \ -key server/privkey.pem \ -out tmp/csr.pem \ -config ./ssl.cnf echo " " echo "Signing the server request with your Root CA, creates the actual server cert" openssl x509 \ -CAcreateserial -req \ -extfile v3ext.cnf \ -in tmp/csr.pem \ -CA ca/my-private-root-ca.cert.pem \ -CAkey ca/my-private-root-ca.privkey.pem \ -out server/cert.pem \ -outform PEM \ -days 9999 #openssl ca -config ./ssl.cnf \ # -extensions server_cert -days 9999 -notext -md sha256 \ # -in tmp/csr.pem \ # -out server/cert.pem # NOTE use of -extfile here, it appears to be the only successful # way to pass in the x509 extension parameters without using # the ca function instead of the x509 one. echo " " echo "Creating a combined pfx file for convenience" openssl pkcs12 -export \ -certfile ca/my-private-root-ca.cert.pem \ -inkey server/privkey.pem \ -in server/cert.pem \ -out server/cert.pfx \ -name "Self-Signed Server Certificate" #echo " " #echo "Copying root ca cert to server as chain.pem" #echo " This is only required if NOT using the fullchain certificate." #rsync -a ca/my-private-root-ca.cert.pem server/chain.pem echo " " echo "Creating a server full chain cert for SSL/TLS use" echo " Using fullchain removes the need to include the ca parameter in server settings." cat server/cert.pem ca/my-private-root-ca.cert.pem > server/fullchain.pem echo " " echo "Use in Node.JS as: sslOpts = { key: 'server/privkey.pem', cert: 'server/fullchain.pem' }" echo " as this is self-signed, use of ca opt isn't required as it is included in the chain" } function create_client { # -------------- Client -------------- # # Need one of these for each client # # you want to authenticate to a server # # ------------------------------------ # # We need the ./ssl.cnf file in order to create the CA cert if [ ! -f ./ssl.cnf ]; then echo " " echo "ERROR - STOPPING" echo " The ./ssl.cnf file does not exist." echo " Please ensure the create_cnf function has been run." echo " " exit 1 fi # We need the CA certificate if [ ! -f ca/my-private-root-ca.cert.pem ]; then echo " " echo "ERROR - STOPPING" echo " The CA certificate file is missing." echo " Please ensure the create_ca function has been run." echo " " exit 1 fi # We need the SERVER private key if [ ! -f server/privkey.pem ]; then echo " " echo "ERROR - STOPPING" echo " A SERVER private key is needed." echo " Please ensure the create_srv function has been run." echo " " exit 1 fi #echo " " #echo "Copying root ca cert to client folder as chain.pem" #echo " This is only required if NOT using the fullchain certificate." #rsync -a ca/my-private-root-ca.cert.pem client/chain.pem echo " " echo "Create a public key to match an existing server." echo " In case you want a client to be able to encrypt messages to this server." echo " Not required for simply accessing SSL/TLS web pages" openssl rsa -pubout \ -in server/privkey.pem \ -out client/server-pubkey.pem echo " " echo "Create DER format crt file for iOS Mobile Safari, etc" openssl x509 \ -outform der \ -in ca/my-private-root-ca.cert.pem \ -out client/my-private-root-ca.crt } function create_ca_cnf { # This is the configuration file for creatin a CA root certificate echo " " echo "Creating CA OpenSSL configuration file for certificate creation" # Required as this is the only way to add SubjectAltName fields which are now required # by Chrome. cat >ca/ca.cnf <./ssl.cnf <./v3ext.cnf <