# HOWTO: Create Your Own Self-Signed Certificate with Subject Alternative Names Using OpenSSL in Ubuntu Bash for Window ## Overview My main development workstation is a Windows 10 machine, so we'll approach this from that viewpoint. Recently, *Google Chrome* started giving me a warning when I open a site that uses https and self-signed certificate on my local development machine due to some SSL certificate issues like the one below: ![Self-Signed SSL Issue in Chrome](https://content.screencast.com/users/jchandra74/folders/Jing/media/da07e9d1-b3f1-4304-bc85-a0d204471321/2017-05-01_1405.png) or one that is described in [this forum post](https://productforums.google.com/forum/#!topic/chrome/zVo3M8CgKzQ;context-place=topicsearchin/chrome/category$3ACanary%7Csort:relevance%7Cspell:false) which I originally got. I made my self-signed certificate using [MAKECERT](https://msdn.microsoft.com/en-us/library/bfsktky3(vs.100).aspx) utility previously. Apparently, this tool does not support creating self-signed SSL certificate with Subject Alternative Name (SAN). If anyone knows different, please let me know. So, after doing some searches, it seems that [OpenSSL](https://www.openssl.org/) is the best solution for this. If you are trying to use OpenSSL on Windows like me, you will probably be scratching your head on where to start. Build from the [repository](https://github.com/openssl/openssl)? Ouch. That's what they called [yak shaving](https://en.wiktionary.org/wiki/yak_shaving). I just want to quickly create my own damn self-signed certificate, not build a factory that can do that. Sure, there is binary installation available [here](https://slproweb.com/products/Win32OpenSSL.html), but after getting it installed and trying to figure out how to make it run nicely with **PowerShell**, I gave up. Luckily, Windows 10 now has the ability to run Ubuntu Bash and after playing around with it, this seems to be the best way forward when using `openssl`. ## Setup Ubuntu on Windows 10 To set it up, follow the instruction [here](https://msdn.microsoft.com/en-au/commandline/wsl/install_guide). ## Install OpenSSL To install `openssl` run the following command from the **bash** shell: ```bash sudo apt-get install openssl ``` Once installed, you are ready to create your own self-signed certificate. ## Creating Self-Signed Certificate I am using [this OpenSSL Ubuntu article](https://msdn.microsoft.com/en-au/commandline/wsl/install_guide) as the base, but there are some modifications along the way, so I'll just explain the way I did it here. If you need further information, please visit that article. The original article is using SHA1 but we really need to move to something else that is stronger like SHA256. If you are using SHA1 as suggested, you will be getting the **Your connection is not private** page in Chrome. ### Creating Your Working Environment We will use your user profile root directory (`~/` which points to `/home/jchandra` in my case) to do this work. If you use anything else, you might need to customize the `caconfig.cnf` and `localhost.cnf` content below. To create your environment, run the following in **bash**: ```bash cd ~/ && mkdir myCA && mkdir -p myCA/signedcerts && mkdir myCA/private && cd myCA ``` This will create the following directories under your user profile root folder: | Directory | Contents | |-----------|----------| | `~/myCA` | contains CA certificate, certificates database, generated certificates, keys, and requests | | `~/myCA/signedcerts` | contains copies of each signed certificate | | `~/myCA/private` | contains the private key | ### Create the Certificate Database To create the database, enter the following in **bash**: ```bash echo '01' > serial && touch index.txt ``` ### Create Certificate Authority Configuration File Create `caconfig.cnf` using `vim` or `nano` or whatever Linux text-editor of your choice. To create it using `vim`, do the following: ```bash vim ~/myCA/caconfig.cnf ``` To create it using `nano` do the following: ```bash nano ~/myCA/caconfig.cnf ``` The content should be like so: ```text # My sample caconfig.cnf file. # # Default configuration to use when one is not provided on the command line. # [ ca ] default_ca = local_ca # # # Default location of directories and files needed to generate certificates. # [ local_ca ] dir = /home/jchandra/myCA certificate = $dir/cacert.pem database = $dir/index.txt new_certs_dir = $dir/signedcerts private_key = $dir/private/cakey.pem serial = $dir/serial # # # Default expiration and encryption policies for certificates # default_crl_days = 365 default_days = 1825 # sha1 is no longer recommended, we will be using sha256 default_md = sha256 # policy = local_ca_policy x509_extensions = local_ca_extensions # # # Copy extensions specified in the certificate request # copy_extensions = copy # # # Default policy to use when generating server certificates. # The following fields must be defined in the server certificate. # # DO NOT CHANGE "supplied" BELOW TO ANYTHING ELSE. # It is the correct content. # [ local_ca_policy ] commonName = supplied stateOrProvinceName = supplied countryName = supplied emailAddress = supplied organizationName = supplied organizationalUnitName = supplied # # # x509 extensions to use when generating server certificates # [ local_ca_extensions ] basicConstraints = CA:false # # # The default root certificate generation policy # [ req ] default_bits = 2048 default_keyfile = /home/jchandra/myCA/private/cakey.pem # # sha1 is no longer recommended, we will be using sha256 default_md = sha256 # prompt = no distinguished_name = root_ca_distinguished_name x509_extensions = root_ca_extensions # # # Root Certificate Authority distinguished name # # DO CHANGE THE CONTENT OF THESE FIELDS TO MATCH # YOUR OWN SETTINGS! # [ root_ca_distinguished_name ] commonName = InvoiceSmashDev Root Certificate Authority stateOrProvinceName = NSW countryName = AU emailAddress = support.team@blahblahblah.com organizationName = Coupa InvoiceSmash organizationalUnitName = Development # [ root_ca_extensions ] basicConstraints = CA:true ``` #### Caveats for `caconfig.cnf`: 1. In `[ local_ca ]` section, make sure you replace `` with your Ubuntu username that you created when you setup Ubuntu on Windows 10. Mine for example is `dir = /home/jchandra/myCA`. **NOTE: DO NOT USE `~/myCA`. It does not work.**.
Similarly, change the `default_keyfile` setting in `[ req ]` section to be the same. 2. Leave the `[ local_ca_policy ]` section alone. `commonName = supplied`, etc. are correct and not to be overwritten. 3. In `[ root_ca_distinguished_name ]` section, replace all values to your own settings. ### Creating Your Test Certificate Authority 1. Run the following command so `openssl` will pick the settings automatically: ```bash export OPENSSL_CONF=~/myCA/caconfig.cnf ``` 2. Generate the Certificate Authority (CA) certificate: ```bash openssl req -x509 -newkey rsa:2048 -out cacert.pem -outform PEM -days 1825 ``` 3. Enter and retype the password you wish to use to import/export the certificate.
**NOTE:** Remember this password, you will need it throughout this walk-through. Once you are done you should have the following files: | File | Content | |------|----------| | `~/myCA/cacert.pem` | CA public certificate | | `~/myCA/private/cakey.pem` | CA private key | In Windows, we will be using `.crt` file instead, so create one using the following command: ```bash openssl x509 -in cacert.pem -out cacert.crt ``` ### Creating Your Self-Signed Certificate with Subject Alternative Name (SAN) Now that you have your CA, you can create the actual self-signed SSL certificate. But first, we need to create the configuration file for it. So again, use `vim` or `nano`, etc. to create the file. In this example, I will call mine `localhost.cnf` since that's the server that I am going to be using to test my development code. You can call it whatever you want. Just make sure you use the right filename in the `export` command later on. Below is the content of `~/myCA/localhost.cnf`: ```text # # localhost.cnf # [ req ] prompt = no distinguished_name = server_distinguished_name req_extensions = v3_req [ server_distinguished_name ] commonName = localhost stateOrProvinceName = NSW countryName = AU emailAddress = invoicesmashteam@coupa.com organizationName = Coupa InvoiceSmash organizationalUnitName = Development [ v3_req ] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [ alt_names ] DNS.0 = localhost DNS.1 = invoicesmash.local ``` #### Caveats for `localhost.conf` 1. Change the values in `[ server_distinguished_name ]` section to match your own settings. 2. In `[ alt_names ]` section, change the value for `DNS.0` and `DNS.1` to whatever you need. In my case, I test my web application using `https://localhost:44300`, therefore the correct value for me is `DNS.0 = localhost`. I am not sure what to do with `DNS.1` so, I just changed it to `DNS.1 = invoicesmash.local`. If so happen that I have a host entry in my `hosts` file that matches this (mapped to IP Address `127.0.0.1`), it should still work. Once you created the configuration file, you need to export it: ```bash export OPENSSL_CONF=~/myCA/localhost.cnf ``` Now generate the certificate and key: ```bash openssl req -newkey rsa:2048 -keyout tempkey.pem -keyform PEM -out tempreq.pem -outform PEM ``` Again, provide the password that you previously entered and wait for the command complete. Next, run the following to create the unencrypted key file: ```bash openssl rsa < tempkey.pem > server_key.pem ``` Again, provide the password that you previously entered and wait for the command to be completed. Now switch back the export to `caconfig.cnf` so we can sign the new certificate request with the CA: ```bash export OPENSSL_CONF=~/myCA/caconfig.cnf ``` And sign it: ```bash openssl ca -in tempreq.pem -out server_crt.pem ``` Again, provide the password that you previously entered and wait for the command to be completed and just type in **Y** whenever it asks you for `[y/n]`. Now you should have your self-signed certificate and the key. | File | Content | |------|---------| | `~/myCA/server_crt.pem` | Self signed SSL certificate | | `~/myCA/server_key.pem` | Self signed SSL certificate private key | ### Converting the .pem files to .pfx for usage by Windows In Windows, we mostly use `.pfx` and `.crt` files. Therefore, we need to convert the `.pem` file to `.pfx`. We'll use `cat` to combine `server_key.pem` and `server_crt.pem` into a file called `hold.pem`. Then we will do the conversion using `openssl pkcs12` command as shown below. You can use whatever text you want to describe your new `.pfx` file in the `-name` parameter. ```bash cat server_key.pem server_crt.pem > hold.pem openssl pkcs12 -export -out localhost.pfx -in hold.pem -name "InvoiceSmash Dev Self-Signed SSL Certificate" ``` Again, provide the password that you previously entered and wait for the command to be completed. Now you should have the following files that we will use in the next section. | File | Content | |------|---------| | `~/myCA/localhost.pfx` | Self signed SSL certificate in PKCS#12 format | | `~/myCA/cacert.crt` | CA certificate used to signed the self-signed certificate | ## Copy the PFX and CA Certificate to a Windows location and Install the CA & PFX into Windows ### Copying PFX and CA from Ubuntu bash to Windows Side It seems it is forbidden to touch the Linux Subsystem from Windows side, but you can touch Windows side from Linux side, so that's what we are going to do. To copy the files from inside Ubuntu, you need to know where you want to copy the files to on Windows side. For example, if I want to copy the files to `C:\certificates` folder, I'd do something like `cp {localhost.pfx,cacert.crt} /mnt/c/certificates`. See this [faq](https://msdn.microsoft.com/en-au/commandline/wsl/faq) if you want to know more about this. ### Install the new CA and self-signed certificates To install the CA and self-signed certificates, all you need to do is double-click the file from where you copied them into. Once clicked, just follow the **Install Certificate** steps and you should be good. For the CA Certificate (`cacert.crt), make sure you install it to **Local Machine**, **Trusted Root Certification Authorities**. For the self-signed certificate (`localhost.pfx`), install it to **Local Machine**, enter the password as previously, and store it in **Personal**. That's it. Now you can configure your application to use the new certificate. In my situation, I just need to configure the Azure Cloud Service project to use that certificate as pointed by [this document](https://docs.microsoft.com/en-us/azure/cloud-services/cloud-services-configure-ssl-certificate). I do not know your workflow, so it might be different. ## References - [Bash on Ubuntu on Windows Installation Guide](https://msdn.microsoft.com/en-au/commandline/wsl/install_guide) - [Ubuntu OpenSSL](https://help.ubuntu.com/community/OpenSSL)