Below is an example of how to generate a private key, private key, and the root CA certificate.
Let us become a CA (Certificate Authority) by creating our CA private key, called rootCA.key
openssl genrsa -des3 -out rootCA.key 2048
Now using that private key we can create our Root CA Certificate called rootCA.pem
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1825 -out rootCA.pem
Let us now create the keys for our client (we will be using the rootCA above to generate these)
Let us create our clients private key
openssl genrsa -out client.key 2048
Create a Certificate Signing Request for our client
openssl req -new -key client.key -out client.csr
Sign our Certificate Signing Request with our rootCA to give us our Certificate
openssl x509 -req -in client.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out client.crt -days 825 -sha256
The Go Code
package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"os"
)
var (
rootCA = mustOpenAndReadFile("./secrets/rootCA.pem")
cert = mustOpenAndReadFile("./secrets/app.crt")
privateKey = mustOpenAndReadFile("./secrets/app.key")
)
func main() {
// generate the client certificate, that our app will use with our own certificate and our private key
clientCert, err := tls.X509KeyPair(cert, privateKey)
if err != nil {
panic(err)
}
rootCAPool := x509.NewCertPool()
// here we will provide our rootCA, the certificate which was used to create our app cert (see above)
ok := rootCAPool.AppendCertsFromPEM(rootCA)
if !ok {
panic("unable to append supplied cert into tls.Config, are you sure it is a valid certificate")
}
config := tls.Config{
Certificates: []tls.Certificate{clientCert},
RootCAs: rootCAPool,
}
// to prevent an unused variable
var _ = config
}
// mustOpenAndReadFile opens and reads the supplied file into memory
// since this is a "must" function, if any part of this op fails,
// FailNow is called as we are unable to proceed with the test
func mustOpenAndReadFile(path string) []byte {
f, err := os.Open(path)
if err != nil {
panic(fmt.Sprintf("unable to open test file %s: %s", path, err))
}
b, err := ioutil.ReadAll(f)
if err != nil {
panic(fmt.Sprintf("unable to ReadAll of test file %s: %s", path, err))
}
return b
}