Prefix
All previous squid caching server series talk about SSL bumping, and include steps on creating a self-signed certificate. I.e., it has been overly-discussed --
- You can find many other blog/articles talking about this all over the Internet. Besides,
- There is a question on stackoverflow with over a thousand up votes.
So why another one?
- First, many such blog/articles just talk about it, giving some commands but without explaining the parameters in details (just like the first two articles we covered in this series). E.g., the comment
-nodes
doesn't mean "nodes" have received over four hundred up-votes before the explanation is added to the above accepted answer. - You will find that each of them, of all those blog/articles on the Internet, are doing it a little bit differently. So why the differences? And again, is any of them outdated?
- And most importantly, the accepted answer is not the only answer there, and if you scroll down, you'd realized that there are much more things to be cautious on than the accepted answer. For example,
- "Modern browsers now throw a security error for otherwise well-formed self-signed certificates ..., so many developers' tutorials and bookmarks are suddenly outdated." A comment can be easily missed because it is buried within all the other answers and resides at the very low part of them, you have to scroll a long way to get to it.
This is part of my fact-collecting blog of the squid caching server series, extending on the creating self-signed certificate part, which combines the image & writing from Linode's Create a Self-Signed TLS Certificate and the answers from above stackoverflow question.
What is a Self-Signed TLS Certificate?
Self-signed TLS certificates are suitable for personal use or for applications that are used internally within an organization. If you intend to use your SSL certificate on a website, see our (linode.com) guide on enabling TLS for NGINX once you’ve completed the process outlined in this guide.
Create the Certificate - Getting Started
Again, reposting from linode's article,
-
Change to the
root
user and change to the directory in which you want to create the certificate and key pair. That location will vary depending on your needs. Here we'll use/root/certs
:su - root mkdir /root/certs && cd /root/certs
-
Create the certificate:
openssl req -new -newkey rsa:4096 -x509 -sha256 -days 365 -nodes -out MyCertificate.crt -keyout MyKey.key
You will be prompted to add identifying information about your website or organization to the certificate. Since a self-signed certificate won't be used publicly, this information isn't necessary. If this certificate will be passed on to a certificate authority for signing, the information needs to be as accurate as possible.
The following is a breakdown of the OpenSSL options used in this command. There are many other options available, but these will create a basic certificate which will be good for a year. For more information, see man openssl
in your terminal.
-
-newkey rsa:4096
: Create a 4096 bit RSA key for use with the certificate.RSA 2048
is the default on more recent versions of OpenSSL but to be sure of the key size, you should specify it during creation. -
-x509
: Create a self-signed certificate. -
-sha256
: Generate the certificate request using 265-bit SHA (Secure Hash Algorithm). -
-days
: Determines the length of time in days that the certificate is being issued for. For a self-signed certificate, this value can be increased as necessary. -
-nodes
: Create a certificate that does not require a passphrase. If this option is excluded, you will be required to enter the passphrase in the console each time the application using it is restarted.
-
Restrict the key's permissions so that only
root
can access it:chmod 400 /root/certs/MyKey.key
Back up your certificate and key to external storage. This is an important step. Do not skip it!
Create the Certificate - The whole nine-yard
That's quite clear. Unfortunately it is now fallen into those "suddenly outdated" developers' tutorials and bookmarks, because "Modern browsers now throw a security error". So the following are the summary of the above stackoverflow question, to the best of my knowledge.
To create a self-signed certificate, which does not chain back to a trusted anchor, involves:
- Create your own authority (i.e., become a CA)
- Create a certificate signing request (CSR) for the server
- Sign the server's CSR with your CA key
But the devil is in the details:
- The above may take several steps, for each of them, but it may also be done in one command.
- Some command in the out-dated articles uses
SHA-1
hash algorithm which in many browsers throws warnings in console, because now "SHA-1 certificates" are considered not secure. So remember to use-sha256
to generate SHA-256-based certificates. - However, there is a saying that, using
SHA-2
does not add any security to a self-signed certificate (updated May 2018). If it concerns you, check the details here. -
"You will be prompted to add identifying information", so use
-subj '/CN=localhost'
(replacelocalhost
with your desired domain) to suppress the whole list of questions about the contents of the certificate. However, be aware that usingCN
is now deprecated, because of the following point. - Modern browsers now throw a security error for otherwise well-formed self-signed certificates if they are missing a
SAN
(Subject Alternate Name), so many developers' tutorials and bookmarks are suddenly outdated. There has been a while that OpenSSL had not been able to provide a command-line way to specifySAN
, and you had to create a short, stand-alone conf file first. Many examples are doing that way, however, - As of 2019, all can be done in one single command, including
SAN
. - Note that to complicate things up, browsers follow the CA/Browser Forum policies; and not the IETF policies. That's one of the reasons a certificate created with OpenSSL (which generally follows the IETF) sometimes does not validate under a browser (browsers follow the CA/B). They are different standards, they have different issuing policies and different validation requirements.
- Thus, it's important to put DNS name in the
SAN
and not theCN
, because both the IETF and the CA/Browser Forums specify the practice. They also specify that DNS names in theCN
are deprecated (but not prohibited). If you put a DNS name in theCN
, then it must be included in theSAN
under theCA/B
policies. So you can't avoid using the Subject Alternate NameSAN
. - The self-signed certificate provides the same level of encryption as a certificate signed by a trusted authority (costing around $1000 ~ $2000 per year), however it is not validated with any third party unless you import it to the browsers, once.
Create the Certificate - The actual command
As of 2019, the following command serves all your needs, including SAN:
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout example.key -out example.crt -extensions san -config <(echo "[req]"; echo distinguished_name=req; echo "[san]"; echo subjectAltName=DNS:example.com,DNS:example.net,IP:10.0.0.1) -subj /CN=example.com
Further, with OpenSSL ≥ 1.1.1, this can be shortened to:
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout example.key -out example.crt -subj /CN=example.com -addext subjectAltName=DNS:example.com,DNS:example.net,IP:10.0.0.1
It creates a certificate that is
- valid for the domains
example.com
andexample.net
(SAN), - also valid for the IP address
10.0.0.1
(SAN), - relatively strong (as of 2019) and
- valid for
3650
days (~10 years).
It creates the following files:
- Private key:
example.key
- Certificate:
example.crt
All information is provided at the command line. There is no annoying interactive input. There is no messing around with config files. All necessary steps are executed by this single OpenSSL invocation: from private key generation up to the self-signed certificate.
Remark #1: Crypto parameters
Since the certificate is self-signed and needs to be accepted by users manually, it doesn't make sense to use a short expiration or weak cryptography.
In the future, you might want to use more than 4096
bits for the RSA key and a hash algorithm stronger than sha256
, but as of 2019 these are sane values. They are sufficiently strong while being supported by all modern browsers.
Remark #2: Parameter "-nodes
"
Theoretically you could leave out the -nodes
parameter (which means "no DES encryption"), in which case example.key
would be encrypted with a password. However, this is almost never useful for a server installation, because you would either have to store the password on the server as well, or you'd have to enter it manually on each reboot.
Remark #3: MinGW
On Windows in the MinGW bash, you should prefix the command with MSYS_NO_PATHCONV=1
:
MSYS_NO_PATHCONV=1 openssl ...
Alternatively, run the command in the plain cmd.exe
Windows command prompt.
Remark #4: See also
- Provide subjectAltName to openssl directly on command line
- How to add multiple email adresses to an SSL certificate via the command line?
- More information about MSYS_NO_PATHCONV
To combine the two (Private key .key
& Certificate .crt
) into a .pem
file:
cat server.crt server.key > cert.pem
Moreover, in order to use the self-signed certificate, you have to
- Install the server certificate on the server
- Install the CA certificate on the client
which we've already covered in the previous articles.
Create the Certificate - Parameter explained
Here are the options described in more detail, from the documentation:
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days XXX
req
PKCS#10 certificate request and certificate generating utility.
-x509
this option outputs a self signed certificate instead of a certificate request.
This is typically used to generate a test certificate or a self signed root CA.-newkey arg
this option creates a new certificate request and a new private key. The argument
takes one of several forms. rsa:nbits, where nbits is the number of bits,
generates an RSA key nbits in size.-keyout filename
this gives the filename to write the newly created private key to.
-out filename
This specifies the output filename to write to or standard output by default.
-days n
when the -x509 option is being used this specifies the number of days to certify
the certificate for. The default is 30 days.-nodes
if this option is specified then if a private key is created it will not be encrypted.
The documentation is actually more detailed than the above summary.
Create the Certificate - For the public
Should you want to get a real certificate that will be recognizable by anyone on the public Internet then the procedure is below.
- Generate a private key
- Use that private key to create a CSR file
- Submit CSR to CA (Verisign or others, etc.)
- Install received cert from CA on web server
- Add other certs to authentication chain depending on the type cert
check the details here.
Top comments (5)
Or you can just use mkcert github.com/FiloSottile/mkcert
I use it like this on windows
mkcert.exe "*.dev.local" localhost 127.0.0.1
Cool! Thanks a lot for that!!!
Good one! I am now wondering, can makecert.exe do all of this?
"makecert.exe"? Oh, I didn't know it. I assume it is windows based, right?
yes. A part of windows SDK.