Securing Server Client Connections with Self Signed TLS Certs

I am not an expert, and this has not been review by one.

Why Self Signed?

If you are running a public website, then go get a certificate signed by a trusted authority.

If you are running a server that is not a public website, with few technical limitations, self signed can be a good choice.

If you are out sourcing your security then use a trusted authority.

Difference breakdown:

Self SignedTrusted Authority
Authentication TLS client libraries can be configered with Self Signed Certs, but not possible from browser JavaScript. Build in.
Public website usage Self signed certificate warning. I know self signed should be better than no TLS at all, but browsers are just not designed for it. Seamless.
Private usage Any address, including LAN ips that public authorities are not allowed to sign. Your private server need a public domain name.
Trusts Protect one file containing the private key. Many authority providers from all over the world, and that they are listed up-to-date on the client side. This increased attack surface allows you to switch between providers.
Trusts (user side hacking) If cert is checked by code, this makes it vary hard for the user to change and slows down anyone looking at the inner working of the appication by network packets. User can add any user trusted authority and proxy the connection, network packets become plain text to the user.
Revocation Update client code. Having a revocation infrastructure is not worth it compared to investing more into protecting keys or updating faster. Ya, someone else's problem.

It is also possible to mix the above features outside the web browser. For example, pinning the root cert of an authority signed cert so that what other authorities the user trusts does not matter. And, establish a LAN connection with private ip address, but check the cert for the public domain name to use a signed cert privately.

It can be tempting to install the self signed cert as a root certificate, but I think that is only appriate for development (testing API access points from a browser) and not appropriate for an user base, even a small one (then each has high value to you). The system wide root certifcatie store is too powerful, adding to it has only one purpose: employee monitoring. Exposing users this way is inappropriate when alternatives are possible.

My Use Case

Choose Self Signed

When I started to work on the server connections I know I wanted to designed it ground up as TLS only. I started using a self signed cert to start and see how fare I could get. Self signing turned out to be a very good exercise in learing TLS and certificate chains, and let me use some powerful features.

I use XCA to crate my certs.

At this stage, I want to create a certificate that emulates the standard root authoritaties. You can find them on your system in your browser -> settings -> advanced -> certificates. You can also find a full step by step guides else where on the internet, so I will just fill in some details that confused me:

Choosing The Validity Time

A few month or less: You are plaining on replacing the certificate regularly, the process will be highly automated. This does not make sense for root certificates. For end entities, if the cert signer is fully automated and always on line, then the validity can be days or less.

Decades or more: Not plaining on replacing the certificate. This is for a root cert that might out live the project that's using it.

A year or few years: common for websites. Mostly selected as a good time period for contracts and renews.

After the "Not After" date, the cert become invalid and must be replaced. It is intuitive to think of it as a balance between timely revocation and replacement cost. But this is an impossible choice. If a certificate becomes insecure during it valid time, assuming any time is equally likely, chances are half of the cert's life time it is insecure (actually more than half, since once a cert is insecure, it can't be insecure again). This is unacceptable with any medium or long valid time. Unless you lower the replacement cost to a online cert signer, which just moves the responsibility to an other equally hard to secure online device, you must have active revocation.

To revoke individual certs of a root, the authority need to keep a revocation list. This is where "Not After" is really usefull. Those past "Not After" can be removed from the list.

For a self signed root cert, beening not trusted by default, revocation is simply not been included. This makes "Not After" useless, so it can be set long in the future.

To revoke certs signed by a self signed root cert without changing root cert, in a small deployment such as what I am doing, instead of keeping a revocation list, it can be easier to just revoke all certs created before a certain date (using "Not Before") in client side code and update all server certs. This also makes "Not After" useless for revocaion.

A problem with long valid time is felling out of practice with replacing certs. Having to do replacement is probably the worst time to learn it. When I first signed the server cert, I started with valid time of a week, then a month, then longer. This allowed me to convince my self that I have a working server cert update process that worked well over time. Without "Not After" forcing me to practice and streamline the process, I would been unlikely to do so.

In short, "Not After" is only usefull for intentionally short authorizations, renewal fees, or making sure certificate replacement is regularly practiced. Not a revocation strategy, set it as long as you like.

Server Certificates


Choice of Cipher Suites (for TLS Handshake)

Update: deployments of HTTP/2 that use TLS 1.2 MUST support TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 [TLS-ECDHE] with the P-256 elliptic curve [FIPS186].

Choose the fewest and select state of the art cipher suites that is supported by the server and clients. Learning about what each option mean is a good education on crypto algorithms, but will not solve the over abundance of choice.

My process have been to use TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b) as the first choose, it is the prefered cipher in firefox and widely supported. If some client does not support it, then just add one more cipher to support it.

SSL LABS have a good list of what cipher suites are supported by browsers.

Client Certificates