Skip to content

Instantly share code, notes, and snippets.

@jehiah
Created January 22, 2016 02:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jehiah/a5b508b8f4efad08e67a to your computer and use it in GitHub Desktop.
Save jehiah/a5b508b8f4efad08e67a to your computer and use it in GitHub Desktop.
A Go TLS server that auto-generates Self-Signed certificates matching the presented clientHelloInfo.ServerName.
package main
// This TLS server generates self signed certificates on-the-fly with a DNSName matching
// the ServerName in the clientHello on connection
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"flag"
"log"
"math/big"
"net/http"
"time"
)
func generateDerCert(privKey *rsa.PrivateKey, expiration time.Time, domain string) ([]byte, error) {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, err
}
if expiration.IsZero() {
expiration = time.Now().Add(time.Minute)
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
CommonName: "Autogenerated Cert",
},
NotBefore: time.Now(),
NotAfter: expiration,
KeyUsage: x509.KeyUsageKeyEncipherment,
BasicConstraintsValid: true,
DNSNames: []string{domain},
}
return x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey)
}
func generatePemCert(privKey *rsa.PrivateKey, domain string) ([]byte, error) {
derBytes, err := generateDerCert(privKey, time.Time{}, domain)
if err != nil {
return nil, err
}
return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}), nil
}
func pemEncode(key *rsa.PrivateKey) []byte {
pemBlock := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}
return pem.EncodeToMemory(pemBlock)
}
func NewSelfSignedCert(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
rsaPrivKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, err
}
tempCertPEM, err := generatePemCert(rsaPrivKey, clientHello.ServerName)
if err != nil {
return nil, err
}
rsaPrivPEM := pemEncode(rsaPrivKey)
cert, err := tls.X509KeyPair(tempCertPEM, rsaPrivPEM)
return &cert, err
}
func main() {
addr := flag.String("addr", ":443", "interface to listen on")
flag.Parse()
cert, err := NewSelfSignedCert(&tls.ClientHelloInfo{ServerName: "localhost"})
if err != nil {
log.Panicf("err %s", err)
}
config := &tls.Config{
Certificates: []tls.Certificate{*cert},
GetCertificate: NewSelfSignedCert,
MinVersion: tls.VersionTLS10,
MaxVersion: tls.VersionTLS12,
}
server := &http.Server{
Addr: *addr,
TLSConfig: config,
}
log.Printf("listening to %v", *addr)
err = server.ListenAndServeTLS("", "")
if err != nil {
log.Printf("%s", err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment