Skip to content

Instantly share code, notes, and snippets.

@annanay25
Created January 28, 2020 13:03
Show Gist options
  • Save annanay25/43e3846e21b30818d8dcd5f9987e852d to your computer and use it in GitHub Desktop.
Save annanay25/43e3846e21b30818d8dcd5f9987e852d to your computer and use it in GitHub Desktop.
Creating secure self signed certs in golang
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"log"
"math/big"
"time"
)
// CertTemplate is a helper function to create a cert template with a serial number and other required fields
func CertTemplate() (*x509.Certificate, error) {
// generate a random serial number (a real cert authority would have some logic behind this)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, errors.New("failed to generate serial number: " + err.Error())
}
tmpl := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{Organization: []string{"JaegerTracing"}},
SignatureAlgorithm: x509.SHA256WithRSA,
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour * 24 * 30), // valid for a month
BasicConstraintsValid: true,
}
return &tmpl, nil
}
// CreateCert invokes x509.CreateCertificate and returns it in the x509.Certificate format
func CreateCert(template, parent *x509.Certificate, pub interface{}, parentPriv interface{}) (
cert *x509.Certificate, certPEM []byte, err error) {
certDER, err := x509.CreateCertificate(rand.Reader, template, parent, pub, parentPriv)
if err != nil {
return
}
// parse the resulting certificate so we can use it again
cert, err = x509.ParseCertificate(certDER)
if err != nil {
return
}
// PEM encode the certificate (this is a standard TLS encoding)
b := pem.Block{Type: "CERTIFICATE", Bytes: certDER}
certPEM = pem.EncodeToMemory(&b)
return
}
// NewTLSCredentials creates signed certificates for both the client and server
func NewTLSCredentials() (*x509.Certificate, tls.Certificate, []byte, tls.Certificate, []byte) {
// generate a new key-pair
rootKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatalf("generating random key: %v", err)
}
rootCertTmpl, err := CertTemplate()
if err != nil {
log.Fatalf("creating cert template: %v", err)
}
// this cert will be the CA that we will use to sign the server cert
rootCertTmpl.IsCA = true
// describe what the certificate will be used for
rootCertTmpl.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature
rootCertTmpl.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}
rootCert, _, err := CreateCert(rootCertTmpl, rootCertTmpl, &rootKey.PublicKey, rootKey)
if err != nil {
log.Fatalf("error creating cert: %v", err)
}
/*******************************************************************
Server Cert
*******************************************************************/
// create a key-pair for the server
servKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatalf("generating random key: %v", err)
}
// create a template for the server
servCertTmpl, err := CertTemplate()
if err != nil {
log.Fatalf("creating cert template: %v", err)
}
servCertTmpl.KeyUsage = x509.KeyUsageDigitalSignature
servCertTmpl.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
// create a certificate which wraps the server's public key, sign it with the root private key
_, servCertPEM, err := CreateCert(servCertTmpl, rootCert, &servKey.PublicKey, rootKey)
if err != nil {
log.Fatalf("error creating cert: %v", err)
}
// provide the private key and the cert
servKeyPEM := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(servKey),
})
servTLSCert, err := tls.X509KeyPair(servCertPEM, servKeyPEM)
if err != nil {
log.Fatalf("invalid key pair: %v", err)
}
/*******************************************************************
Client Cert
*******************************************************************/
// create a key-pair for the client
clientKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Fatalf("generating random key: %v", err)
}
// create a template for the client
clientCertTmpl, err := CertTemplate()
if err != nil {
log.Fatalf("creating cert template: %v", err)
}
clientCertTmpl.KeyUsage = x509.KeyUsageDigitalSignature
clientCertTmpl.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
// the root cert signs the cert by again providing its private key
_, clientCertPEM, err := CreateCert(clientCertTmpl, rootCert, &clientKey.PublicKey, rootKey)
if err != nil {
log.Fatalf("error creating cert: %v", err)
}
// encode and load the cert and private key for the client
clientKeyPEM := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(clientKey),
})
clientTLSCert, err := tls.X509KeyPair(clientCertPEM, clientKeyPEM)
if err != nil {
log.Fatalf("invalid key pair: %v", err)
}
// rootCert is the client CA as well as server CA, servTLSCert is for the server
return rootCert, clientTLSCert, clientKeyPEM, servTLSCert, servKeyPEM
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment