Skip to content

Instantly share code, notes, and snippets.

@dmage
Created September 7, 2017 15:20
Show Gist options
  • Save dmage/2f02039cb5f7b3c22cf960c90dfc9132 to your computer and use it in GitHub Desktop.
Save dmage/2f02039cb5f7b3c22cf960c90dfc9132 to your computer and use it in GitHub Desktop.
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"fmt"
"log"
"math/big"
"net"
"net/http"
"time"
)
type KeyPair struct {
Certificate []byte
PrivateKey interface{}
}
type CertificateOptions struct {
Subject pkix.Name
ValidFor time.Duration
IsCA bool
DNSNames []string
IPAddresses []net.IP
}
func GenerateRSAKeyPair(rsaBits int, parent *KeyPair, opts CertificateOptions) (*KeyPair, error) {
fail := func(format string, args ...interface{}) (*KeyPair, error) {
return nil, fmt.Errorf(format, args)
}
priv, err := rsa.GenerateKey(rand.Reader, rsaBits)
if err != nil {
return fail("failed to generate private key: %s", err)
}
notBefore := time.Now()
notAfter := notBefore.Add(opts.ValidFor)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return fail("failed to generate serial number: %s", err)
}
keyUsage := x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature
if opts.IsCA {
keyUsage |= x509.KeyUsageCertSign
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: opts.Subject,
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: keyUsage,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
IsCA: opts.IsCA,
DNSNames: opts.DNSNames,
IPAddresses: opts.IPAddresses,
}
var parentCert *x509.Certificate
var parentPriv interface{}
if parent != nil {
parentCert, err = x509.ParseCertificate(parent.Certificate)
if err != nil {
return fail("failed to parse parent certificate: %s", err)
}
parentPriv = parent.PrivateKey
} else {
parentCert = &template
parentPriv = priv
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, parentCert, &priv.PublicKey, parentPriv)
if err != nil {
return fail("failed to create certificate: %s", err)
}
return &KeyPair{
Certificate: derBytes,
PrivateKey: priv,
}, nil
}
func main() {
rootKeyPair, err := GenerateRSAKeyPair(1024, nil, CertificateOptions{
Subject: pkix.Name{
Organization: []string{"OpenShift Test Suite"},
},
ValidFor: 24 * time.Hour,
IsCA: true,
})
if err != nil {
log.Fatal(err)
}
keyPair, err := GenerateRSAKeyPair(1024, rootKeyPair, CertificateOptions{
Subject: pkix.Name{
Organization: []string{"Server Certificate"},
CommonName: "localhost",
},
ValidFor: 12 * time.Hour,
})
if err != nil {
log.Fatal(err)
}
config := &tls.Config{
Certificates: []tls.Certificate{{
Certificate: [][]byte{keyPair.Certificate},
PrivateKey: keyPair.PrivateKey,
}},
}
server := &http.Server{
Addr: ":8443",
TLSConfig: config,
}
log.Fatal(server.ListenAndServeTLS("", ""))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment