Self signed certificate
Tags: ssl, development, coding
Published: 2024-04-03 12:30:28

## What is a certificate? 

Certificate represents an identity of any entity.  An entity could be a person, host, application. In real world, I relate passport to a certificate. A passport is valid only when a *passport issuing authority* approves a passport request. This is a valid passport because *passport issuing authority* is trusted. With a trusted authority issuing a passport, this passport becomes an identity of the requesting entity, a certificate. Of course, authority requires a fees to be paid to validate the passport request before issuing one. 

## What is a self signed certificate? 

> In cryptography and computer security, self-signed certificates are public key certificates that their users issue on their own behalf, as opposed to a certificate authority (CA) issuing them.  

*[ do not try this at home :-) ]* Issuing your passport by your own self is a typical example I relate self signed certificate with. No authority is going to accept a self issued passport. Consider yourself spared if you even tried and not face legal issues. Issuing your own passport has no valid use case in real world. But a self signed certificate has a few use cases like it can be used in application development phase, no signing authority (CA) is involved - so no wait time on the authority to certificate approved and no cost involved.  

> Never use a self signed certificate in a production system.

## How to create self signed certificate?

There are tools available to create self signed certificate - `keytool` and `openssl` are popular ones. In this blog, I will use `keytool` which is provided with jdk. `openssl` can also be used but the steps would be different. I will assume that I have a web application hosted in my local machine. This application should be serving HTTP requests over ssl - *HTTPS*.  Let's create a self signed certificate by running the following command.

```bash
keytool -storetype pkcs12 -keystore sks.p12 -storepass manage \
-alias server_key_rsa -keyalg rsa \
-genkeypair \
-dname "CN=is, OU=rnd, O=sag, L=ba, ST=ka, C=in" \
-ext ku=digitalsignature,keyencipherment,dataencipherment,keycertsign \
-ext bc=ca:true \
-ext san=dns:localhost
```
Explanation of the options used.

Option  | Description
--------  |:----------
**-storetype** *pkcs12* | Defines type of the keystore. Either pkcs12 or jks. 
**- keystore** *sks.p12* | Defines name of keystore file. Ex: *sks.p12*.  Keystore file could be any name. A new file is created if one mentioned is not present.
**-storepass** *manage* | Defines the password for the store. 
**-keyalg** rsa | Defines the algorithm to create the keypair. 
**-alias** *server_key_rsa* | Defines an alias for the keypair in a keystore. A keystore can have many key pairs, each of them uniquely identified by an alias. Ex: *server_key_rsa*.
**-genkeypair**| Command to create keypair.
**-dname** *"CN=is, OU=rnd, O=gas, L=ba, ST=ka, C=in"* | Defines distinguished name for the entity.
**-ext ku=digitalsignature,dataencipherment,keycertsign** | For a self signed certificate, key usage (***ku***) should have **keycertsign** and **digitalsignature** as the primary generated by the entity will be used to sign its own public certificate. 
**-ext bc=ca:true**| Defines certificate entity as ca.
**-ext san=dns:localhost** | Defines server name as *localhost*. It is also possible to *localhost* in CN and clients could accept but it is more clear to define the dns as localhost to be explicit while the name of application can be used in *CN*.

Now, we have a keystore (*sks.p12*) with a keypair identified by alias *'server_key_rsa'*.  This keystore should be configured in java server application to server HTTP over ssl. I wont be getting into how to configure keystore in java application to server HTTPS. 

## Extracting self signed cert

Let's assume application is serving HTTPS on port 5443. I use `curl` and `httpie`.  On firing `curl https://localhost:5443`, there is an ssl error. 

![bash.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1652131255613/V6M9AUFtb.png align="left")

`Curl` connected to https port. Server sent the certificate, a self signed one which curl does not trust simply because there is no issuing authority involved.  

## Fixing the client to accommodate self signed certificate 

I know that the server is using a self signed certificate and this is not a production system. So, I want the client to work with it. That leaves two options. 

- Ignore ssl verification

curl | httpie 
----|:------
```curl https://localhost:5443 --insecure ``` | ```http https://localhost:5443 --verify no ```

- Get the server certificate which was prepared with `-ext bc=ca:true` to be used as a mocked ca cert.

Refresh the keystore command we used to create the keypair. The alias we use is *server_key* and we need a server certificate. Use the below command to extract the server certificate. 

```bash
keytool -export -rfc -keystore sks.p12 -alias server_key_rsa --storepass manage -file server_key_rsa_ca.pem
```
Most of the command options, by now, are already defined are familiar. Option `-rfc` defines the format of the certificate to be rfc format. Now, server certificate is exported to a file *server_key_rsa_ca.pem*. Feel free to try out `keytool -printcert -file server_key_rsa_ca.pem` to view the content of certificate. 

curl | httpie 
----|:------
```curl https://localhost:5443 --cacert  server_key_rsa_ca.pem ``` | ```http https://localhost:5443 --verify  server_key_rsa_ca.pem ```

Now, the self signed certificate sent by the server is validated against the server certificate and request passes through. 

This is how I got self signed certificate created, configured and used it in the client to test. 

I put this blog up as I went through a lot of articles to get the self signed working with server and client by accepting the certificate. While this is a reference to the future me, I hope this article helped you as well. 

Now, leave your experience with self signed certificate for me to learn !!