@@ -19,8 +19,11 @@ package comm
19
19
import (
20
20
"crypto/tls"
21
21
"crypto/x509"
22
+ "encoding/pem"
22
23
"errors"
24
+ "fmt"
23
25
"net"
26
+ "sync"
24
27
25
28
"google.golang.org/grpc"
26
29
"google.golang.org/grpc/credentials"
@@ -62,6 +65,12 @@ type GRPCServer interface {
62
65
//TLSEnabled is a flag indicating whether or not TLS is enabled for this
63
66
//GRPCServer instance
64
67
TLSEnabled () bool
68
+ //AppendClientRootCAs appends PEM-encoded X509 certificate authorities to
69
+ //the list of authorities used to verify client certificates
70
+ AppendClientRootCAs (clientRoots [][]byte ) error
71
+ //RemoveClientRootCAs removes PEM-encoded X509 certificate authorities from
72
+ //the list of authorities used to verify client certificates
73
+ RemoveClientRootCAs (clientRoots [][]byte ) error
65
74
}
66
75
67
76
type grpcServerImpl struct {
@@ -78,9 +87,13 @@ type grpcServerImpl struct {
78
87
//List of certificate authorities to optionally pass to the client during
79
88
//the TLS handshake
80
89
serverRootCAs []tls.Certificate
81
- //List of certificate authorities to be used to authenticate clients if
82
- //client authentication is required
83
- clientRootCAs * x509.CertPool
90
+ //lock to protect concurrent access to append / remove
91
+ lock * sync.Mutex
92
+ //Set of PEM-encoded X509 certificate authorities used to populate
93
+ //the tlsConfig.ClientCAs indexed by subject
94
+ clientRootCAs map [string ]* x509.Certificate
95
+ //TLS configuration used by the grpc server
96
+ tlsConfig * tls.Config
84
97
//Is TLS enabled?
85
98
tlsEnabled bool
86
99
}
@@ -110,6 +123,7 @@ func NewGRPCServerFromListener(listener net.Listener, secureConfig SecureServerC
110
123
grpcServer := & grpcServerImpl {
111
124
address : listener .Addr ().String (),
112
125
listener : listener ,
126
+ lock : & sync.Mutex {},
113
127
}
114
128
115
129
//set up our server options
@@ -130,27 +144,29 @@ func NewGRPCServerFromListener(listener net.Listener, secureConfig SecureServerC
130
144
131
145
//base server certificate
132
146
certificates := []tls.Certificate {grpcServer .serverCertificate }
133
- tlsConfig := & tls.Config {
134
- Certificates : certificates ,
147
+ grpcServer .tlsConfig = & tls.Config {
148
+ Certificates : certificates ,
149
+ SessionTicketsDisabled : true ,
135
150
}
136
151
//checkif client authentication is required
137
152
if secureConfig .RequireClientCert {
138
153
//require TLS client auth
139
- tlsConfig .ClientAuth = tls .RequireAndVerifyClientCert
154
+ grpcServer . tlsConfig .ClientAuth = tls .RequireAndVerifyClientCert
140
155
//if we have client root CAs, create a certPool
141
156
if len (secureConfig .ClientRootCAs ) > 0 {
142
- grpcServer .clientRootCAs = x509 .NewCertPool ()
157
+ grpcServer .clientRootCAs = make (map [string ]* x509.Certificate )
158
+ grpcServer .tlsConfig .ClientCAs = x509 .NewCertPool ()
143
159
for _ , clientRootCA := range secureConfig .ClientRootCAs {
144
- if ! grpcServer .clientRootCAs .AppendCertsFromPEM (clientRootCA ) {
145
- return nil , errors .New ("Failed to load client root certificates" )
160
+ err = grpcServer .appendClientRootCA (clientRootCA )
161
+ if err != nil {
162
+ return nil , err
146
163
}
147
164
}
148
- tlsConfig .ClientCAs = grpcServer .clientRootCAs
149
165
}
150
166
}
151
167
152
168
//create credentials
153
- creds := credentials .NewTLS (tlsConfig )
169
+ creds := credentials .NewTLS (grpcServer . tlsConfig )
154
170
155
171
//add to server options
156
172
serverOpts = append (serverOpts , grpc .Creds (creds ))
@@ -200,3 +216,116 @@ func (gServer *grpcServerImpl) Start() error {
200
216
func (gServer * grpcServerImpl ) Stop () {
201
217
gServer .server .Stop ()
202
218
}
219
+
220
+ //AppendClientRootCAs appends PEM-encoded X509 certificate authorities to
221
+ //the list of authorities used to verify client certificates
222
+ func (gServer * grpcServerImpl ) AppendClientRootCAs (clientRoots [][]byte ) error {
223
+ gServer .lock .Lock ()
224
+ defer gServer .lock .Unlock ()
225
+ for _ , clientRoot := range clientRoots {
226
+ err := gServer .appendClientRootCA (clientRoot )
227
+ if err != nil {
228
+ return err
229
+ }
230
+ }
231
+ return nil
232
+ }
233
+
234
+ //internal function to add a PEM-encoded clientRootCA
235
+ func (gServer * grpcServerImpl ) appendClientRootCA (clientRoot []byte ) error {
236
+
237
+ errMsg := "Failed to append client root certificate(s): %s"
238
+ //convert to x509
239
+ certs , subjects , err := pemToX509Certs (clientRoot )
240
+ if err != nil {
241
+ return fmt .Errorf (errMsg , err .Error ())
242
+ }
243
+
244
+ if len (certs ) < 1 {
245
+ return fmt .Errorf (errMsg , "No client root certificates found" )
246
+ }
247
+
248
+ for i , cert := range certs {
249
+ //first add to the ClientCAs
250
+ gServer .tlsConfig .ClientCAs .AddCert (cert )
251
+ //add it to our clientRootCAs map using subject as key
252
+ gServer.clientRootCAs [subjects [i ]] = cert
253
+ }
254
+ return nil
255
+ }
256
+
257
+ //RemoveClientRootCAs removes PEM-encoded X509 certificate authorities from
258
+ //the list of authorities used to verify client certificates
259
+ func (gServer * grpcServerImpl ) RemoveClientRootCAs (clientRoots [][]byte ) error {
260
+ gServer .lock .Lock ()
261
+ defer gServer .lock .Unlock ()
262
+ //remove from internal map
263
+ for _ , clientRoot := range clientRoots {
264
+ err := gServer .removeClientRootCA (clientRoot )
265
+ if err != nil {
266
+ return err
267
+ }
268
+ }
269
+
270
+ //create a new CertPool and populate with current clientRootCAs
271
+ certPool := x509 .NewCertPool ()
272
+ for _ , clientRoot := range gServer .clientRootCAs {
273
+ certPool .AddCert (clientRoot )
274
+ }
275
+
276
+ //replace the current ClientCAs pool
277
+ gServer .tlsConfig .ClientCAs = certPool
278
+ return nil
279
+ }
280
+
281
+ //internal function to remove a PEM-encoded clientRootCA
282
+ func (gServer * grpcServerImpl ) removeClientRootCA (clientRoot []byte ) error {
283
+
284
+ errMsg := "Failed to remove client root certificate(s): %s"
285
+ //convert to x509
286
+ certs , subjects , err := pemToX509Certs (clientRoot )
287
+ if err != nil {
288
+ return fmt .Errorf (errMsg , err .Error ())
289
+ }
290
+
291
+ if len (certs ) < 1 {
292
+ return fmt .Errorf (errMsg , "No client root certificates found" )
293
+ }
294
+
295
+ for i , subject := range subjects {
296
+ //remove it from our clientRootCAs map using subject as key
297
+ //check to see if we have match
298
+ if certs [i ].Equal (gServer .clientRootCAs [subject ]) {
299
+ delete (gServer .clientRootCAs , subject )
300
+ }
301
+ }
302
+ return nil
303
+ }
304
+
305
+ //utility function to parse PEM-encoded certs
306
+ func pemToX509Certs (pemCerts []byte ) ([]* x509.Certificate , []string , error ) {
307
+
308
+ //it's possible that multiple certs are encoded
309
+ certs := []* x509.Certificate {}
310
+ subjects := []string {}
311
+ for len (pemCerts ) > 0 {
312
+ var block * pem.Block
313
+ block , pemCerts = pem .Decode (pemCerts )
314
+ if block == nil {
315
+ break
316
+ }
317
+ if block .Type != "CERTIFICATE" || len (block .Headers ) != 0 {
318
+ continue
319
+ }
320
+
321
+ cert , err := x509 .ParseCertificate (block .Bytes )
322
+ if err != nil {
323
+ return nil , subjects , err
324
+ } else {
325
+ certs = append (certs , cert )
326
+ //extract and append the subject
327
+ subjects = append (subjects , string (cert .RawSubject ))
328
+ }
329
+ }
330
+ return certs , subjects , nil
331
+ }
0 commit comments