Ritho's blog

Download self signed certificates to your system

categories Programming Golang
tags programming golang
subject In this post we will see a small program to automatically download a self signed certificate to your system from a website.

Hi all,

In a previous post we saw how to generate a self signed SSL certificate for your local development and how to install it into your system. Following that post, I've created a small Go program that automatically downloads a certificate from a published website and install it into your system, avoiding the easy but manual steps to download the certificate chain and install it.

Here is the code for the program: package main

import (
    "crypto/tls"
    "crypto/x509"
    "encoding/pem"
    "flag"
    "fmt"
    "os"
    "os/exec"
    "strings"
)

func main() {
    var name, host string

    flag.StringVar(&name, "n", "website", "Website name")
    flag.StringVar(&host, "h", "localhost", "Host (domain) to fetch the certificates from")

    flag.Parse()
    certs, err := getCertificates(host)
    if err != nil {
        fmt.Printf("unable to get the certificates: %s", err)

        return
    }

    dir := "/usr/local/share/ca-certificates"
    os.Mkdir(dir, 0o700)
    for _, cert := range certs {
        if err := writeCertificate(cert, dir, name); err != nil {
            fmt.Printf("unable to write certificate: %s", err)

            return
        }
    }

    if err := updateSystemCertificates(); err != nil {
        fmt.Printf("unable to update the certificates: %s", err)

        return
    }
}

func getCertificates(host string) ([]*x509.Certificate, error) {
    conf := &tls.Config{
        InsecureSkipVerify: true,
    }

    conn, err := tls.Dial("tcp", host+":443", conf)
    if err != nil {
        return nil, fmt.Errorf("error in dial: %w", err)
    }

    defer conn.Close()

    return conn.ConnectionState().PeerCertificates, nil
}

func writeCertificate(cert *x509.Certificate, dir, site string) error {
    certName := strings.ReplaceAll(cert.Subject.CommonName, " ", "-")
    caPEM := &pem.Block{
        Type: "CERTIFICATE",
        Bytes: cert.Raw,
    }

    filename := fmt.Sprintf("%s/%s-%s.crt", dir, certName, site)
    publicKeyPem := pem.EncodeToMemory(caPEM)
    if err := os.WriteFile(filename, publicKeyPem, 0o600); err != nil {
        return fmt.Errorf("unable to write file %s: %w", filename, err)
    }

    return nil
}

func updateSystemCertificates() error {
    cmd := exec.Command("update-ca-certificates")

    return cmd.Run()
}

As you can see, the program is simple enough, it downloads all the certificates from a given host, writes them into the directory /usr/local/share/ca-certificates and executes the command update-ca-certificates, so it's recognized in your system. Remember that, for browsers like Firefox or Chrome, the certificate is loaded from a nss database, so you will need to copy the certificates in another directory and run other commands to make the certificates available in your browser, but, given the example (specially the part where the certificates are downloaded from the website) and the previous post (where we saw which commands to run to include the certificate in the browser database), it's quite easy to adapt the program to install the certificate for any browser of your choice.

Happy Hacking!