EDIT: Reasons to roll my own
How can we trust a CA?
I’m designing my own server (
foo.ext), and I’ve been investigating about how I can authenticate myself to the rest of the world.
I understand that perfect security is not possible, but I would like to have enough security so that it would be difficult to break in even for the NSA.
After some investigation, I’ve arrived to the conclussion that the only way to maintain a chain of trust is to secure the first link. So I’m going to roll my own personal Certificate Authority and put it forever out of the internet.
I’ve designed 4 levels of CA in the following way:
Level 0 (Self-signed personal CA):
This is a self-signed CA. I will re-issue it every 10 years. It will live in my most secure computer which will never connect to the internet. It will sign one and only one certificate, the level 1 CA, every 5 years.
Level 1 (Limited personal CA):
This CA will live in the same computer as the level 0 CA (although in different containers). I will give in hand (USB) a copy of the certificate of this CA to my clients, who will have to install this CA in their browsers to be able to connect to my server securely.
This CA will be limited (by the level 0 CA) to issue certificates for
*.foo.com. The reason for this limitation is that my clients will be able to install this CA in their browsers, and have a guarantee that I will never be able to impersonate something like
google.com in their browsers.
Level 2 (Intermediate CA):
This CA will be signed by level 1 CA with the same limitations. This CA will sign certificates for two things: my server
foo.ext and my level 3 CA. It will live in a separate computer which will also be disconnected from the internet. It will exchange keys, certificates and certificate requests by USB.
The reason for this CA is to be a firewall before my level 1 & 0 CAs. For that purpose, every time I need to certificate this CA, I will first reset its computer, so that if there is a breach, it won’t propagate to level 1 & 0 CAs.
This CA will be certified every year.
Level 3 (Subordinate CA):
This CA will be further limited to only
*.foo.ext (and not
foo.ext). It will/may live in the same computer where my server will be.
It will certify the different services of my server every month or so.
Every CA and service will be isolated from the rest in a container.
I will have two different servers.
foo.ext will be the most secure of the two, and its purpose will only be to publish any breaches in the level 3 CA or any service certified by that CA. This server will be signed by level 2 CA, so it won’t be affected by such breaches. When a breach is published, I will publish any certificates to be revoked.
*.foo.ext will have a set of services, which will be the main objective of all this PKI. The rest is just security overhead.
For my services over SSH, I will be my only client (no-one will be allowed to SSH into my server).
For my services over HTTPS, anyone can connect, but those services will only serve static content, and will be download only (only GET & HEAD).
I also want to set up a mail server, but I still don’t know much about mail, so I will delay that until I know how to do it securely.
Every public key, certificate request and certificate exchanges between different units of my PKI will be done by hand (by myself) to avoid someone sneaking around. Private keys will never, under any circumstance, get out of the unit in which they were generated.
Private keys will not be password encrypted, because I would need to keep the password in plain text in the same computer, which makes it useless IMHO. Instead, I will just hide the level 0 & 1 computer from physical attacks as much as possible.
I have this picture of the whole PKI
Now to the code.
I’ve found in the internet some code to do that, but it was either outdated, or incomplete, or misdocumented or all of them. Given that I want it to be as secure as possible (within my possibilities), I’m not going to use that code until I know what every line is doing.
I will use RSA keys of (at least)
4096 bits. I won’t use more bits because it may not be supported by browsers. And not less because of security.
For Signing, I will use
I would like to do everything with
libressl, and avoid ssh-keygen or openssl as much as possible.
I have the following cheat sheet for now, which I hope is correct and up to date:
Generate a RSA private key:
libressl genpkey -algorithm RSA -out caX.foo.key.pem \ -pkeyopt rsa_keygen_bits:4096
Check private key:
libressl rsa -noout -text -in caX.foo.key.pem
Extract public key from PEM RSA private key:
libressl rsa -in caX.foo.key.pem -pubout -out caX.foo.key.pub
Generate level 0 certificate:
libressl req -new -x509 -key ca0.foo.key.pem -sha512 -days 3660 \ -out ca0.foo.cert.pem
What I don’t know how to do:
- Generate certificate requests and certificates
I have some (incomplete or incorrect) commands.
Generate CSR (certificate signing request):
libressl req -new -sha512 -key clientX.foo.key.pem -out clientX.foo.csr.pem
libressl x509 -req -in clientX.foo.csr.pem -out clientX.foo.cert.pem \ -CA caX.cert.pem -CAkey caX.key.pem -sha512 -CAcreateserial
-CAcreateserial as I understand it should only be used by a CA signing its first certificate.
Missing in those commands is for example the limitation for the CAs and for the end services to be able to certificate only the domains or subdomains I want them to certificate.
My question is: how to implement my PKI design? by which I mean, how to correctly generate CSRs and sign them with the specifications I want.
It may very well be splitted into various subbquestions, but I prefer to ask a single question because they are intrinsically related, and that way you can have an overview of the whole system, which is necessary to better answer the question.