The goal of this demo is to show all the steps needed to have an untrusted server with an untrusted client and no certificate authority until the client and server
Here is a web server with no established trust. I will show the steps from your computer and your programs know nothing about the certificates until trust is established.
pkidemo.properties has the configuration for the certificate authority (CA), the server and the client.
Initially all lines are commented out.
- Firefox users: Firefox has a separate certificate store from the OS under Settings > Private & Security > Security > View Certificates. You have to install CA and client certificates here if you use Firefox
- Chrome users: The browser process has to be restarted to find new CA and client certificates in the operating system
- When I start
com.johannesbrodwall.pki.server.CaHttpServer, it complains that it needs to know where to store the information about the certificate authority. I specifyca.keyStoreandca.keyStorePasswordfor the storage of the file with the key and certificate and I also give the CA a name, which is called theca.create.issuerDN(Distinguished Name). Finally, I specify that it can be created if missingca.create.ifMissing - When I start the server, we can see that the file is created. In addition, the server exports a
.crtwith the same name. - I can now go to https://localhost:11443, but I get the message that the CA is untrusted. In the browser, we can examine the Certification Path and see that the CA that issued this certificate is not trusted
- I can install the
ca.crtfile in my operating system as a Trusted Root Authority. The browser will now trust the server, but watch out Chrome needs to be restarted to refresh the Root CAs (actually restarting the incognito browser is enough)
- Looking further down in
pkidemo.properties, we findca.https.address. You won't have so much use of a server running only on localhost, so change it toca.https.address=ca.boosterconf.local:11443 - If you go to https://localhost:11443 you will now get a warning from the browser that the hostname doesn't match the certificate
- If you go to https://ca.boosterconf.local:11443/ you probably will not get any luck. But update your hosts-file
(
C:\Windows\System32\drivers\etc\hostson Windows) and you will work better - If you examine the certificate, you will see that the name ca.boosterconf.local occurs both in the CN (common name) and as an extended certificate attribute
Quiz: In what extended certificate attribute does the hostname occur? What is the difference between this as the CN attribute?
- When I start
HttpsDemoServer, this server currently doesn't have a host certificate. It will start on http://localhost:8080, though - I can update
https.address=app.boosterconf.local:8443. Since it doesn't have a certificate, the server is still not starting https. But it will try to create .key with the private key and a .csr-file with the certification request. - Specify
https.key=certs/server/server.keyinpkdemo.propertiesso it can be generated - Upload the .csr file to https://ca.boosterconf.local:11443/ to generate a certificate, which should be placed
according to the configuration
https.certificate=inpkidemo.properties - The server will now start the https-port and you can access it at https://app.boosterconf.local:11443
- If you change
https.wantClientAuth=trueand restart the browser (sorry), the server will prompt you for a certificate. But it will not accept any certificate you already have because it requires the same CA as we just created. Press escape and you will still come to the server - Go to "Show client certificate" and the server will respond that it has no client certificate
- Let's ask the CA server to generate a key and certificate for us. Enter
CN=whateveras Common name and "Generate p12-file" - You will now get a file downloaded on your computer. Install it as a personal certificate
- When you restart the browser you can now see your client certificate
- You have to add
https.server
Note: In this scenario, the server has the chance to sniff the client certificate, which is not ideal. We will look at ways to avoid this.
The trust established in a Public Key Infrastructure is based on a few base assumptions:
- There exists keypairs with the mathematical property that what is encrypted by one of the members of the pair can be decrypted with the other and vice-versa, while knowing one doesn't make it possible to uncover the other. A metaphor of padlocks and keys can be imagined.
- Each party can freely share their public key but must guard their private key
- Since the relationship between the keys is symmetric, this can be used both for encryption and for authentication. If you have the public key of a party, you can determine if a message was actually sent from that party. This is called a message signature
- But a problem remains: With many parties, how do you get the public key of a party that you don't know already? The solution is a Certificate Authority. A client must somehow establish that it trusts the public key of a trusted third party
- The job of the certificate authority is to issue certificates to parties. When the certificate authority is satisfied about the identity of a party, that party can receive a certificate which is a message with it's name and public key, signed by the certificate authority. Others who trust the same CA can then verify that this is the correct public key
There are still a few hard problems in a PKI: How do you establish the trust on the CAs and how does CAs determine the identity of the parties before issuing a certificate. These are hard problems, but there exists a few simple cases:
- Operating systems ship with the certificates of a list of well known CAs
- CAs like letsencrypt issues challenges to parties to place files at a URL for a hostname they claim to control. This means that while creating certificates, letsencrypt would be vulnerable to DNS poisoning attacks
pkidemo.propertieshas client URL. Setclient.url=https://boosterconf.ssldemo.local:8443/demo/test, when you runcom.johannesbrodwall.pki.client.HttpsDemoClientyou get an exception- This is because even though your OS trusts the CA, Java maintains its own list of certificate authorities.
We can update the Java-installation, but that is normally not practical. Instead, we set the configuration
client.key.trustedCertificates=ca.crt - The client can now connect to the server, but the server hasn't established the authentication for the client.
We can take a p12-file generated from the CA web server and specify it as
client.key.keyStore=client/client.pfx. The server will now establish the identity of the client
When we generated the p12-file from the server, the server generated both the private key and the certificate and sent both to the client. In our case the server doesn't retain a copy of the private key (or the certificate for that matter), but the client has no guarantee of this. A better approach to maintain trust barriers is for the client to send a Certification Request to the server. The certification request contains the identification requested by the client as well as it's public key. The server can issue a certificate with the public key
In Windows, the program Manage User Certificates can be used to generate the certification request.
There's also a code example of how to generate a certification request in Java in
com.johannesbrodwall.pki.util.SunCertificateUtil.createHostnameCsr
We use certification issuance to keep track of all certificate clients of our server. Even though we terminate SSL on the HTTP proxy layer, we issue our own certificates in Java. This way we have the identity of all certificates in a database and can maintain privileges for computer users associated with each certificate