Skip to content

Instantly share code, notes, and snippets.

@mdelillo
Created July 22, 2018 21:44
Show Gist options
  • Save mdelillo/09a5332faf4371f38f920cc758eef72c to your computer and use it in GitHub Desktop.
Save mdelillo/09a5332faf4371f38f920cc758eef72c to your computer and use it in GitHub Desktop.
Create a self-signed CA and use it to create a signed certificate
package main
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"io/ioutil"
"log"
"math/big"
"time"
)
func main() {
caCertBytes, caKeyBytes, err := generateSelfSignedCA()
if err != nil {
log.Fatalf("Failed to generate CA: %s", err.Error())
}
if err := ioutil.WriteFile("caCert.pem", caCertBytes, 0644); err != nil {
log.Fatalf("Failed to write caCert.pem: %s", err.Error())
}
if err := ioutil.WriteFile("caKey.pem", caKeyBytes, 0600); err != nil {
log.Fatalf("Failed to write caKey.pem: %s", err.Error())
}
certBytes, keyBytes, err := generateSignedCert(caCertBytes, caKeyBytes)
if err != nil {
log.Fatalf("Failed to generate signed certificate: %s", err.Error())
}
if err := ioutil.WriteFile("cert.pem", certBytes, 0644); err != nil {
log.Fatalf("Failed to write cert.pem: %s", err.Error())
}
if err := ioutil.WriteFile("key.pem", keyBytes, 0600); err != nil {
log.Fatalf("Failed to write key.pem: %s", err.Error())
}
block, _ := pem.Decode(certBytes)
if block == nil {
log.Fatal("Failed to decode certificate")
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
log.Fatalf("Failed to parse certificate: %s", err.Error())
}
roots := x509.NewCertPool()
roots.AppendCertsFromPEM(caCertBytes)
if _, err := cert.Verify(x509.VerifyOptions{Roots: roots}); err != nil {
log.Fatalf("Verification failed: %s", err.Error())
}
fmt.Println("Verification succeeded")
}
func generateSelfSignedCA() ([]byte, []byte, error) {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 256)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate serial number: %s", err)
}
template := &x509.Certificate{
SerialNumber: serialNumber,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour * 24 * 30),
Subject: pkix.Name{CommonName: "my-ca"},
IsCA: true,
MaxPathLenZero: true,
BasicConstraintsValid: true,
}
key, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate key: %s", err)
}
derBytes, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
if err != nil {
return nil, nil, fmt.Errorf("failed to create certificate: %s", err)
}
var certPem, keyPem bytes.Buffer
if err := pem.Encode(&certPem, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
return nil, nil, fmt.Errorf("failed to encode certificate: %s", err)
}
if err := pem.Encode(&keyPem, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}); err != nil {
return nil, nil, fmt.Errorf("failed to encode key: %s", err)
}
return certPem.Bytes(), keyPem.Bytes(), nil
}
func generateSignedCert(caCertBytes, caKeyBytes []byte) ([]byte, []byte, error) {
key, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate key: %s", err)
}
csrDerBytes, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{}, key)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate csr: %s", err.Error())
}
csr, err := x509.ParseCertificateRequest(csrDerBytes)
if err != nil {
return nil, nil, fmt.Errorf("failed to parse csr: %s", err.Error())
}
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 256)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate serial number: %s", err)
}
template := &x509.Certificate{
SerialNumber: serialNumber,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour * 24 * 30),
Subject: pkix.Name{CommonName: "my-cert"},
}
caTLS, err := tls.X509KeyPair(caCertBytes, caKeyBytes)
if err != nil {
return nil, nil, fmt.Errorf("failed to load CA key pair: %s", err)
}
ca, err := x509.ParseCertificate(caTLS.Certificate[0])
if err != nil {
return nil, nil, fmt.Errorf("failed to parse CA certificate: %s", err)
}
derBytes, err := x509.CreateCertificate(rand.Reader, template, ca, csr.PublicKey, caTLS.PrivateKey)
if err != nil {
return nil, nil, fmt.Errorf("failed to create certificate: %s", err)
}
var certPem, keyPem bytes.Buffer
if err := pem.Encode(&certPem, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
return nil, nil, fmt.Errorf("failed to encode certificate: %s", err)
}
if err := pem.Encode(&keyPem, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}); err != nil {
return nil, nil, fmt.Errorf("failed to encode key: %s", err)
}
return certPem.Bytes(), keyPem.Bytes(), nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment