Skip to content

Commit d1ea412

Browse files
committed
FAB-1260 Add support for mutual TLS to GRPCServer
Adds initial support for authentication using client certificates. * Regenerate test certificates as the CA did not include the clientauth extended usage attribute which is enforced by Go's x509 library * Added support for requiring and enforcing client certificates * Add a SecureServerConfig struct to collect TLS-related parameters in order to improve readiability / usability of the NewServer* functions * Refactor code and tests to use SecureServerConfig * Added utility methods to server_test.go to reduce duplicate code to make new tests more readable via table structure * Latest commit add additional tests and makes tests run in parallel * DOES NOT support dynamically adding client certificate authorities to a running server instance. Will be addressed in the next change set Change-Id: Ibeca9c2ac4412735ca7b482d4157dae3edc4ea6f Signed-off-by: Gari Singh <[email protected]>
1 parent dcaa22b commit d1ea412

File tree

63 files changed

+863
-422
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+863
-422
lines changed

core/comm/server.go

+56-54
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,25 @@ import (
2626
"google.golang.org/grpc/credentials"
2727
)
2828

29+
//A SecureServerConfig structure is used to configure security (e.g. TLS) for a
30+
//GRPCServer instance
31+
type SecureServerConfig struct {
32+
//Whether or not to use TLS for communication
33+
UseTLS bool
34+
//PEM-encoded X509 public key to be used by the server for TLS communication
35+
ServerCertificate []byte
36+
//PEM-encoded private key to be used by the server for TLS communication
37+
ServerKey []byte
38+
//Set of PEM-encoded X509 certificate authorities to optionally send
39+
//as part of the server handshake
40+
ServerRootCAs [][]byte
41+
//Whether or not TLS client must present certificates for authentication
42+
RequireClientCert bool
43+
//Set of PEM-encoded X509 certificate authorities to use when verifying
44+
//client certificates
45+
ClientRootCAs [][]byte
46+
}
47+
2948
//GRPCServer defines an interface representing a GRPC-based server
3049
type GRPCServer interface {
3150
//Address returns the listen address for the GRPCServer
@@ -40,7 +59,8 @@ type GRPCServer interface {
4059
Listener() net.Listener
4160
//ServerCertificate returns the tls.Certificate used by the grpc.Server
4261
ServerCertificate() tls.Certificate
43-
//TLSEnabled is a flag indicating whether or not TLS is enabled for this GRPCServer instance
62+
//TLSEnabled is a flag indicating whether or not TLS is enabled for this
63+
//GRPCServer instance
4464
TLSEnabled() bool
4565
}
4666

@@ -55,29 +75,19 @@ type grpcServerImpl struct {
5575
serverCertificate tls.Certificate
5676
//Key used by the server for TLS communication
5777
serverKeyPEM []byte
58-
//List of certificate authorities to optionally pass to the client during the TLS handshake
78+
//List of certificate authorities to optionally pass to the client during
79+
//the TLS handshake
5980
serverRootCAs []tls.Certificate
60-
//List of certificate authorities to be used to authenticate clients if client authentication is required
81+
//List of certificate authorities to be used to authenticate clients if
82+
//client authentication is required
6183
clientRootCAs *x509.CertPool
6284
//Is TLS enabled?
6385
tlsEnabled bool
6486
}
6587

66-
/*
67-
NewGRPCServer creates a new implementation of a GRPCServer given a listen address.
68-
In order to enable TLS, serverKey and ServerCertificate are required.
69-
70-
Parameters:
71-
address: Listen address to use formatted as hostname:port
72-
serverKey: PEM-encoded private key to be used by the server for TLS communication
73-
serverCertificate: PEM-encoded X509 public key to be used by the server for TLS communication
74-
serverRootCAs: (optional) Set of PEM-encoded X509 certificate authorities to optionally send as part of
75-
the server handshake
76-
clientRootCAs: (optional) Set of PEM-encoded X509 certificate authorities to use when verifying client
77-
certificates
78-
*/
79-
func NewGRPCServer(address string, serverKey []byte, serverCertificate []byte, serverRootCAs [][]byte,
80-
clientRootCAs [][]byte) (GRPCServer, error) {
88+
//NewGRPCServer creates a new implementation of a GRPCServer given a
89+
//listen address.
90+
func NewGRPCServer(address string, secureConfig SecureServerConfig) (GRPCServer, error) {
8191

8292
if address == "" {
8393
return nil, errors.New("Missing address parameter")
@@ -89,25 +99,13 @@ func NewGRPCServer(address string, serverKey []byte, serverCertificate []byte, s
8999
return nil, err
90100
}
91101

92-
return NewGRPCServerFromListener(lis, serverKey, serverCertificate, serverRootCAs, clientRootCAs)
102+
return NewGRPCServerFromListener(lis, secureConfig)
93103

94104
}
95105

96-
/*
97-
NewGRPCServerFromListener creates a new implementation of a GRPCServer given an existing Listener instance.
98-
In order to enable TLS, serverKey and ServerCertificate are required.
99-
100-
Parameters:
101-
listener: Listener to use
102-
serverKey: PEM-encoded private key to be used by the server for TLS communication
103-
serverCertificate: PEM-encoded X509 public key to be used by the server for TLS communication
104-
serverRootCAs: (optional) Set of PEM-encoded X509 certificate authorities to optionally send as part of
105-
the server handshake
106-
clientRootCAs: (optional) Set of PEM-encoded X509 certificate authorities to use when verifying client
107-
certificates
108-
*/
109-
func NewGRPCServerFromListener(listener net.Listener, serverKey []byte, serverCertificate []byte,
110-
serverRootCAs [][]byte, clientRootCAs [][]byte) (GRPCServer, error) {
106+
//NewGRPCServerFromListener creates a new implementation of a GRPCServer given
107+
//an existing net.Listener instance.
108+
func NewGRPCServerFromListener(listener net.Listener, secureConfig SecureServerConfig) (GRPCServer, error) {
111109

112110
grpcServer := &grpcServerImpl{
113111
address: listener.Addr().String(),
@@ -116,13 +114,13 @@ func NewGRPCServerFromListener(listener net.Listener, serverKey []byte, serverCe
116114

117115
//set up our server options
118116
var serverOpts []grpc.ServerOption
119-
//check for TLS parameters
120-
if serverKey != nil || serverCertificate != nil {
121-
//both are required
122-
if serverKey != nil && serverCertificate != nil {
117+
//check secureConfig
118+
if secureConfig.UseTLS {
119+
//both key and cert are required
120+
if secureConfig.ServerKey != nil && secureConfig.ServerCertificate != nil {
123121
grpcServer.tlsEnabled = true
124122
//load server public and private keys
125-
cert, err := tls.X509KeyPair(serverCertificate, serverKey)
123+
cert, err := tls.X509KeyPair(secureConfig.ServerCertificate, secureConfig.ServerKey)
126124
if err != nil {
127125
return nil, err
128126
}
@@ -132,21 +130,24 @@ func NewGRPCServerFromListener(listener net.Listener, serverKey []byte, serverCe
132130

133131
//base server certificate
134132
certificates := []tls.Certificate{grpcServer.serverCertificate}
135-
136-
/**
137-
//if we have server root CAs append them
138-
if len(serverRootCAs) > 0 {
139-
//certificates = append(certificates, serverRootCAs...)
140-
}
141-
142-
//if we have client root CAs, create a certPool
143-
if len(clientRootCAs) > 0 {
144-
grpcServer.clientRootCAs = x509.NewCertPool()
145-
}
146-
*/
147133
tlsConfig := &tls.Config{
148134
Certificates: certificates,
149135
}
136+
//checkif client authentication is required
137+
if secureConfig.RequireClientCert {
138+
//require TLS client auth
139+
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
140+
//if we have client root CAs, create a certPool
141+
if len(secureConfig.ClientRootCAs) > 0 {
142+
grpcServer.clientRootCAs = x509.NewCertPool()
143+
for _, clientRootCA := range secureConfig.ClientRootCAs {
144+
if !grpcServer.clientRootCAs.AppendCertsFromPEM(clientRootCA) {
145+
return nil, errors.New("Failed to load client root certificates")
146+
}
147+
}
148+
tlsConfig.ClientCAs = grpcServer.clientRootCAs
149+
}
150+
}
150151

151152
//create credentials
152153
creds := credentials.NewTLS(tlsConfig)
@@ -155,10 +156,10 @@ func NewGRPCServerFromListener(listener net.Listener, serverKey []byte, serverCe
155156
serverOpts = append(serverOpts, grpc.Creds(creds))
156157

157158
} else {
158-
return nil, errors.New("Both serverKey and serverCertificate are required in order to enable TLS")
159+
return nil, errors.New("secureConfig must contain both ServerKey and " +
160+
"ServerCertificate when UseTLS is true")
159161
}
160162
}
161-
162163
grpcServer.server = grpc.NewServer(serverOpts...)
163164

164165
return grpcServer, nil
@@ -184,7 +185,8 @@ func (gServer *grpcServerImpl) ServerCertificate() tls.Certificate {
184185
return gServer.serverCertificate
185186
}
186187

187-
//TLSEnabled is a flag indicating whether or not TLS is enabled for the GRPCServer instance
188+
//TLSEnabled is a flag indicating whether or not TLS is enabled for the
189+
//GRPCServer instance
188190
func (gServer *grpcServerImpl) TLSEnabled() bool {
189191
return gServer.tlsEnabled
190192
}

0 commit comments

Comments
 (0)