Created
January 28, 2020 13:03
-
-
Save annanay25/43e3846e21b30818d8dcd5f9987e852d to your computer and use it in GitHub Desktop.
Creating secure self signed certs in golang
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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