Created
December 12, 2015 17:16
-
-
Save shivakar/cd52b5594d4912fbeb46 to your computer and use it in GitHub Desktop.
TLS server with in-memory self-signed certificate
This file contains 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" | |
"errors" | |
"log" | |
"math/big" | |
"net" | |
"net/http" | |
"os" | |
"time" | |
) | |
// From https://golang.org/src/net/http/server.go | |
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted | |
// connections. It's used by ListenAndServe and ListenAndServeTLS so | |
// dead TCP connections (e.g. closing laptop mid-download) eventually | |
// go away. | |
type tcpKeepAliveListener struct { | |
*net.TCPListener | |
} | |
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) { | |
tc, err := ln.AcceptTCP() | |
if err != nil { | |
return | |
} | |
tc.SetKeepAlive(true) | |
tc.SetKeepAlivePeriod(3 * time.Minute) | |
return tc, nil | |
} | |
// GenX509KeyPair generates the TLS keypair for the server | |
func GenX509KeyPair() (tls.Certificate, error) { | |
now := time.Now() | |
template := &x509.Certificate{ | |
SerialNumber: big.NewInt(now.Unix()), | |
Subject: pkix.Name{ | |
CommonName: "quickserve.example.com", | |
Country: []string{"USA"}, | |
Organization: []string{"example.com"}, | |
OrganizationalUnit: []string{"quickserve"}, | |
}, | |
NotBefore: now, | |
NotAfter: now.AddDate(0, 0, 1), // Valid for one day | |
SubjectKeyId: []byte{113, 117, 105, 99, 107, 115, 101, 114, 118, 101}, | |
BasicConstraintsValid: true, | |
IsCA: true, | |
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, | |
KeyUsage: x509.KeyUsageKeyEncipherment | | |
x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, | |
} | |
priv, err := rsa.GenerateKey(rand.Reader, 2048) | |
if err != nil { | |
return tls.Certificate{}, err | |
} | |
cert, err := x509.CreateCertificate(rand.Reader, template, template, | |
priv.Public(), priv) | |
if err != nil { | |
return tls.Certificate{}, err | |
} | |
var outCert tls.Certificate | |
outCert.Certificate = append(outCert.Certificate, cert) | |
outCert.PrivateKey = priv | |
return outCert, nil | |
} | |
// Usage prints the usage string | |
func Usage() { | |
l := log.New(os.Stderr, "", 0) | |
l.Fatalf("Usage: %s <directory-to-serve>\n", os.Args[0]) | |
} | |
// ListenAndServeTLSKeyPair start a server using in-memory TLS KeyPair | |
func ListenAndServeTLSKeyPair(addr string, cert tls.Certificate, | |
handler http.Handler) error { | |
if addr == "" { | |
return errors.New("Invalid address string") | |
} | |
server := &http.Server{Addr: addr, Handler: handler} | |
config := &tls.Config{} | |
config.NextProtos = []string{"http/1.1"} | |
config.Certificates = make([]tls.Certificate, 1) | |
config.Certificates[0] = cert | |
ln, err := net.Listen("tcp", addr) | |
if err != nil { | |
return err | |
} | |
tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, | |
config) | |
return server.Serve(tlsListener) | |
} | |
func main() { | |
if len(os.Args) < 2 { | |
Usage() | |
} | |
cert, err := GenX509KeyPair() | |
if err != nil { | |
log.Fatalln(err) | |
} | |
mux := http.NewServeMux() | |
mux.Handle("/", http.FileServer(http.Dir(os.Args[1]))) | |
log.Println("Starting server at https://127.0.0.1:8080/") | |
err = ListenAndServeTLSKeyPair("127.0.0.1:8080", cert, mux) | |
if err != nil { | |
log.Fatalln(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For those still finding this on google, there is a simpler and slightly more up to date Q/A on StackOverflow: https://stackoverflow.com/questions/47857573/passing-certificate-and-key-as-string-to-listenandservetls/47857805