1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package httptest
17
18 import (
19 "bytes"
20 "context"
21 "crypto/ecdsa"
22 "crypto/elliptic"
23 "crypto/rand"
24 "crypto/tls"
25 "crypto/x509"
26 "encoding/pem"
27 "math/big"
28 "net"
29 "net/http"
30 "net/http/httptest"
31 "time"
32 )
33
34
35
36
37 func NewTLSServer(domain string, handler http.Handler) (*httptest.Server, error) {
38 s := httptest.NewUnstartedServer(handler)
39
40 template := x509.Certificate{
41 SerialNumber: big.NewInt(1),
42 NotBefore: time.Now().Add(-1 * time.Hour),
43 NotAfter: time.Now().Add(time.Hour),
44 IPAddresses: []net.IP{
45 net.IPv4(127, 0, 0, 1),
46 net.IPv6loopback,
47 },
48 DNSNames: []string{domain},
49
50 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
51 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
52 BasicConstraintsValid: true,
53 IsCA: true,
54 }
55
56 priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
57 if err != nil {
58 return nil, err
59 }
60
61 b, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
62 if err != nil {
63 return nil, err
64 }
65
66 pc := &bytes.Buffer{}
67 if err := pem.Encode(pc, &pem.Block{Type: "CERTIFICATE", Bytes: b}); err != nil {
68 return nil, err
69 }
70
71 ek, err := x509.MarshalECPrivateKey(priv)
72 if err != nil {
73 return nil, err
74 }
75
76 pk := &bytes.Buffer{}
77 if err := pem.Encode(pk, &pem.Block{Type: "EC PRIVATE KEY", Bytes: ek}); err != nil {
78 return nil, err
79 }
80
81 c, err := tls.X509KeyPair(pc.Bytes(), pk.Bytes())
82 if err != nil {
83 return nil, err
84 }
85 s.TLS = &tls.Config{
86 Certificates: []tls.Certificate{c},
87 }
88 s.StartTLS()
89
90 certpool := x509.NewCertPool()
91 certpool.AddCert(s.Certificate())
92
93 t := &http.Transport{
94 TLSClientConfig: &tls.Config{
95 RootCAs: certpool,
96 },
97 DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
98 return net.Dial(s.Listener.Addr().Network(), s.Listener.Addr().String())
99 },
100 }
101 s.Client().Transport = t
102
103 return s, nil
104 }
105
View as plain text