-
Notifications
You must be signed in to change notification settings - Fork 3
/
listen.go
122 lines (108 loc) · 3.68 KB
/
listen.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package tlsdefaults
import (
"crypto/tls"
"fmt"
"net"
"os"
"time"
"github.com/getlantern/keyman"
)
var (
tenYearsFromToday = time.Now().AddDate(10, 0, 0)
)
// Listen opens a TLS listener at the given address using the private key and
// certificate PEM files at the given paths. If no files exists, it creates a
// new key and self-signed certificate at those locations.
func Listen(addr, pkfile, certfile string) (net.Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, fmt.Errorf("Unable to listen for connections at %s: %s\n", addr, err)
}
return NewListenerAddr(l, addr, pkfile, certfile)
}
// NewListener creates a TLS listener based on the given listener using the
// private key and certificate PEM files at the given paths. If no files exists,
// it creates a new key and self-signed certificate at those locations.
func NewListener(l net.Listener, pkfile, certfile string) (net.Listener, error) {
return NewListenerAddr(l, l.Addr().String(), pkfile, certfile)
}
// NewListenerAddr is like NewListener but uses the specified addr to generate
// the cert.
func NewListenerAddr(l net.Listener, addr string, pkfile, certfile string) (net.Listener, error) {
cfg, err := BuildListenerConfig(addr, pkfile, certfile)
if err != nil {
return nil, err
}
return tls.NewListener(l, cfg), nil
}
// BuildListenerConfig builds a tls.Config for a listener at the given addr
func BuildListenerConfig(addr string, pkfile string, certfile string) (*tls.Config, error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, fmt.Errorf("Unable to split host and port for %v: %v\n", addr, err)
}
mypkfile := pkfile
if mypkfile == "" {
mypkfile = "key.pem"
}
mycertfile := certfile
if mycertfile == "" {
mycertfile = "cert.pem"
}
ctx := CertContext{
PKFile: mypkfile,
ServerCertFile: mycertfile,
}
_, err1 := os.Stat(ctx.ServerCertFile)
_, err2 := os.Stat(ctx.PKFile)
if os.IsNotExist(err1) || os.IsNotExist(err2) {
fmt.Println("At least one of the Key/Cert files is not found -> Generating new key pair")
err = ctx.initServerCert(host)
if err != nil {
return nil, fmt.Errorf("Unable to init server cert: %s\n", err)
}
} /* else if *debug {
fmt.Println("Using provided Key/Cert files")
}*/
tlsConfig := Server()
cert, err := tls.LoadX509KeyPair(ctx.ServerCertFile, ctx.PKFile)
if err != nil {
return nil, fmt.Errorf("Unable to load certificate and key from %s and %s: %s\n", ctx.ServerCertFile, ctx.PKFile, err)
}
tlsConfig.Certificates = []tls.Certificate{cert}
return tlsConfig, nil
}
// CertContext encapsulates the certificates used by a Server
type CertContext struct {
PKFile string
ServerCertFile string
PK *keyman.PrivateKey
ServerCert *keyman.Certificate
}
// InitServerCert initializes a PK + cert for use by a server proxy, signed by
// the CA certificate. We always generate a new certificate just in case.
func (ctx *CertContext) initServerCert(host string) (err error) {
if ctx.PK, err = keyman.LoadPKFromFile(ctx.PKFile); err != nil {
if os.IsNotExist(err) {
fmt.Printf("Creating new PK at: %s\n", ctx.PKFile)
if ctx.PK, err = keyman.GeneratePK(2048); err != nil {
return
}
if err = ctx.PK.WriteToFile(ctx.PKFile); err != nil {
return fmt.Errorf("Unable to save private key: %s\n", err)
}
} else {
return fmt.Errorf("Unable to read private key, even though it exists: %s\n", err)
}
}
fmt.Printf("Creating new server cert at: %s\n", ctx.ServerCertFile)
ctx.ServerCert, err = ctx.PK.TLSCertificateFor(tenYearsFromToday, true, nil, "Lantern", host)
if err != nil {
return
}
err = ctx.ServerCert.WriteToFile(ctx.ServerCertFile)
if err != nil {
return
}
return nil
}