-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.go
153 lines (131 loc) · 4.28 KB
/
server.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package main
import (
"crypto/tls"
"crypto/x509"
"flag"
"io/ioutil"
"log"
"path/filepath"
"github.com/grantae/certinfo"
)
func main() {
// flag for whether to print full cert details or just minimal details
verbose := flag.Bool("verbose", false, "Verbose==true prints out entire client certificates in human-readable format.")
// set port
port := flag.String("port", "443", "Set port to listen on.")
flag.Parse()
// get the origin server cert pair for TLS
certificate, err := getOriginCertPair("certs/origin.pem", "certs/origin.key")
handleError(err)
// get the CA cert for server side of mTLS
clientCertPool, err := getClientCACert("certs/root.crt")
handleError(err)
config := tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert, // set to tls.RequireAndVerifyClientCert if you want the chain to be verified (if not valid, you won't get to see the client cert data sent to server- handshake will fail first)
ClientCAs: clientCertPool,
Certificates: []tls.Certificate{*certificate},
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: true, // true == accept any cert from origin server (used if you self-signed your origin certs) (this is unrelated to mutual authentication)
}
// start a tcp server
listener, err := tls.Listen("tcp", "0.0.0.0:"+*port, &config)
if err != nil {
log.Printf("server: could not start listening, error: %s\n", err)
log.Printf("try running the server with the -port=# flag to listen on another port\n")
return
}
log.Printf("server: ready\n")
for {
// wait for a new incoming connection
conn, err := listener.Accept()
if err != nil {
log.Printf("server: could not accept incoming connection, error: %s\n", err)
continue
}
// we got a connection
log.Printf("server: accepted connection from: %s\n", conn.RemoteAddr())
// get the underlying tls connection
tlsConn, ok := conn.(*tls.Conn)
if !ok {
log.Printf("server: erm, this is not a tls conn\n")
}
// perform handshake
if err := tlsConn.Handshake(); err != nil {
log.Printf("client: error during handshake, error: %s\n", err)
}
tlsConn.ConnectionState()
// get connection state and print certs sent by client
state := tlsConn.ConnectionState()
log.Printf("Certs from state.VerifiedChains\n")
for _, list := range state.VerifiedChains {
log.Printf("VERIFIED\n")
for _, v := range list {
log.Printf(" * Verified cert: Subject %s, Issuer: %s\n", v.Subject, v.Issuer)
}
}
log.Printf("Certs from state.PeerCertificates\n")
for _, v := range state.PeerCertificates {
log.Printf(" * Client cert: Subject: %s, Issuer: %s\n", v.Subject, v.Issuer)
if *verbose {
text, err := certinfo.CertificateText(v) // this library can only give the entire human-readable cert, cannot specific select parts
if err != nil {
log.Printf("server: error converting cert to human-readable format, error: %s\n", err)
}
log.Printf("Cert data:\n%s\n", text)
}
}
log.Println("Did resume? ", tlsConn.ConnectionState().DidResume)
// close connection
conn.Close()
log.Println()
}
}
// getOriginCertPair gets the origin cert pair for regular TLS
func getOriginCertPair(certPath string, keyPath string) (*tls.Certificate, error) {
// get cert and key
originCert, err := readFile(certPath)
if err != nil {
return nil, err
}
originKey, err := readFile(keyPath)
if err != nil {
return nil, err
}
// make tls.Certificate
certificate, err := tls.X509KeyPair(originCert, originKey)
if err != nil {
return nil, err
}
return &certificate, nil
}
// getClientCACert gets the root certificate for the origin server side of mTLS
func getClientCACert(path string) (*x509.CertPool, error) {
// get cert
clientCACert, err := readFile(path)
if err != nil {
return nil, err
}
// create cert pool
clientCertPool := x509.NewCertPool()
clientCertPool.AppendCertsFromPEM(clientCACert)
return clientCertPool, err
}
// readFile reads a file and returns the bytes
func readFile(path string) ([]byte, error) {
// get cert filepath
absPathServerCrt, err := filepath.Abs(path)
if err != nil {
return nil, err
}
// read the cert file
certBytes, err := ioutil.ReadFile(absPathServerCrt)
if err != nil {
return nil, err
}
return certBytes, nil
}
func handleError(err error) {
if err != nil {
log.Println("Error, ", err)
}
}