-
-
Save iDanielLaw/8554e10436fa6291d68465e098b0b4c4 to your computer and use it in GitHub Desktop.
TLS server with in-memory self-signed certificate
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" | |
"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