github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/core/comm/server.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package comm 8 9 import ( 10 "crypto/tls" 11 "crypto/x509" 12 "encoding/pem" 13 "errors" 14 "fmt" 15 "net" 16 "sync" 17 18 "google.golang.org/grpc" 19 ) 20 21 //A SecureServerConfig structure is used to configure security (e.g. TLS) for a 22 //GRPCServer instance 23 type SecureServerConfig struct { 24 //PEM-encoded X509 public key to be used by the server for TLS communication 25 ServerCertificate []byte 26 //PEM-encoded private key to be used by the server for TLS communication 27 ServerKey []byte 28 //Set of PEM-encoded X509 certificate authorities to optionally send 29 //as part of the server handshake 30 ServerRootCAs [][]byte 31 //Set of PEM-encoded X509 certificate authorities to use when verifying 32 //client certificates 33 ClientRootCAs [][]byte 34 //Whether or not to use TLS for communication 35 UseTLS bool 36 //Whether or not TLS client must present certificates for authentication 37 RequireClientCert bool 38 } 39 40 //GRPCServer defines an interface representing a GRPC-based server 41 type GRPCServer interface { 42 //Address returns the listen address for the GRPCServer 43 Address() string 44 //Start starts the underlying grpc.Server 45 Start() error 46 //Stop stops the underlying grpc.Server 47 Stop() 48 //Server returns the grpc.Server instance for the GRPCServer 49 Server() *grpc.Server 50 //Listener returns the net.Listener instance for the GRPCServer 51 Listener() net.Listener 52 //ServerCertificate returns the tls.Certificate used by the grpc.Server 53 ServerCertificate() tls.Certificate 54 //TLSEnabled is a flag indicating whether or not TLS is enabled for this 55 //GRPCServer instance 56 TLSEnabled() bool 57 //AppendClientRootCAs appends PEM-encoded X509 certificate authorities to 58 //the list of authorities used to verify client certificates 59 AppendClientRootCAs(clientRoots [][]byte) error 60 //RemoveClientRootCAs removes PEM-encoded X509 certificate authorities from 61 //the list of authorities used to verify client certificates 62 RemoveClientRootCAs(clientRoots [][]byte) error 63 //SetClientRootCAs sets the list of authorities used to verify client 64 //certificates based on a list of PEM-encoded X509 certificate authorities 65 SetClientRootCAs(clientRoots [][]byte) error 66 } 67 68 type grpcServerImpl struct { 69 //Listen address for the server specified as hostname:port 70 address string 71 //Listener for handling network requests 72 listener net.Listener 73 //GRPC server 74 server *grpc.Server 75 //Certificate presented by the server for TLS communication 76 serverCertificate tls.Certificate 77 //Key used by the server for TLS communication 78 serverKeyPEM []byte 79 //List of certificate authorities to optionally pass to the client during 80 //the TLS handshake 81 serverRootCAs []tls.Certificate 82 //lock to protect concurrent access to append / remove 83 lock *sync.Mutex 84 //Set of PEM-encoded X509 certificate authorities used to populate 85 //the tlsConfig.ClientCAs indexed by subject 86 clientRootCAs map[string]*x509.Certificate 87 //TLS configuration used by the grpc server 88 tlsConfig *tls.Config 89 //Is TLS enabled? 90 tlsEnabled bool 91 } 92 93 //NewGRPCServer creates a new implementation of a GRPCServer given a 94 //listen address. 95 func NewGRPCServer(address string, secureConfig SecureServerConfig) (GRPCServer, error) { 96 97 if address == "" { 98 return nil, errors.New("Missing address parameter") 99 } 100 //create our listener 101 lis, err := net.Listen("tcp", address) 102 103 if err != nil { 104 return nil, err 105 } 106 107 return NewGRPCServerFromListener(lis, secureConfig) 108 109 } 110 111 //NewGRPCServerFromListener creates a new implementation of a GRPCServer given 112 //an existing net.Listener instance. 113 func NewGRPCServerFromListener(listener net.Listener, secureConfig SecureServerConfig) (GRPCServer, error) { 114 115 grpcServer := &grpcServerImpl{ 116 address: listener.Addr().String(), 117 listener: listener, 118 lock: &sync.Mutex{}, 119 } 120 121 //set up our server options 122 var serverOpts []grpc.ServerOption 123 //check secureConfig 124 if secureConfig.UseTLS { 125 //both key and cert are required 126 if secureConfig.ServerKey != nil && secureConfig.ServerCertificate != nil { 127 grpcServer.tlsEnabled = true 128 //load server public and private keys 129 cert, err := tls.X509KeyPair(secureConfig.ServerCertificate, secureConfig.ServerKey) 130 if err != nil { 131 return nil, err 132 } 133 grpcServer.serverCertificate = cert 134 135 //set up our TLS config 136 137 //base server certificate 138 certificates := []tls.Certificate{grpcServer.serverCertificate} 139 grpcServer.tlsConfig = &tls.Config{ 140 Certificates: certificates, 141 SessionTicketsDisabled: true, 142 } 143 grpcServer.tlsConfig.ClientAuth = tls.RequestClientCert 144 //checkif client authentication is required 145 if secureConfig.RequireClientCert { 146 //require TLS client auth 147 grpcServer.tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert 148 //if we have client root CAs, create a certPool 149 if len(secureConfig.ClientRootCAs) > 0 { 150 grpcServer.clientRootCAs = make(map[string]*x509.Certificate) 151 grpcServer.tlsConfig.ClientCAs = x509.NewCertPool() 152 for _, clientRootCA := range secureConfig.ClientRootCAs { 153 err = grpcServer.appendClientRootCA(clientRootCA) 154 if err != nil { 155 return nil, err 156 } 157 } 158 } 159 } 160 161 // create credentials and add to server options 162 creds := NewServerTransportCredentials(grpcServer.tlsConfig) 163 serverOpts = append(serverOpts, grpc.Creds(creds)) 164 } else { 165 return nil, errors.New("secureConfig must contain both ServerKey and " + 166 "ServerCertificate when UseTLS is true") 167 } 168 } 169 // set max send and recv msg sizes 170 serverOpts = append(serverOpts, grpc.MaxSendMsgSize(MaxSendMsgSize())) 171 serverOpts = append(serverOpts, grpc.MaxRecvMsgSize(MaxRecvMsgSize())) 172 // set the keepalive options 173 serverOpts = append(serverOpts, ServerKeepaliveOptions()...) 174 175 grpcServer.server = grpc.NewServer(serverOpts...) 176 177 return grpcServer, nil 178 } 179 180 //Address returns the listen address for this GRPCServer instance 181 func (gServer *grpcServerImpl) Address() string { 182 return gServer.address 183 } 184 185 //Listener returns the net.Listener for the GRPCServer instance 186 func (gServer *grpcServerImpl) Listener() net.Listener { 187 return gServer.listener 188 } 189 190 //Server returns the grpc.Server for the GRPCServer instance 191 func (gServer *grpcServerImpl) Server() *grpc.Server { 192 return gServer.server 193 } 194 195 //ServerCertificate returns the tls.Certificate used by the grpc.Server 196 func (gServer *grpcServerImpl) ServerCertificate() tls.Certificate { 197 return gServer.serverCertificate 198 } 199 200 //TLSEnabled is a flag indicating whether or not TLS is enabled for the 201 //GRPCServer instance 202 func (gServer *grpcServerImpl) TLSEnabled() bool { 203 return gServer.tlsEnabled 204 } 205 206 //Start starts the underlying grpc.Server 207 func (gServer *grpcServerImpl) Start() error { 208 return gServer.server.Serve(gServer.listener) 209 } 210 211 //Stop stops the underlying grpc.Server 212 func (gServer *grpcServerImpl) Stop() { 213 gServer.server.Stop() 214 } 215 216 //AppendClientRootCAs appends PEM-encoded X509 certificate authorities to 217 //the list of authorities used to verify client certificates 218 func (gServer *grpcServerImpl) AppendClientRootCAs(clientRoots [][]byte) error { 219 gServer.lock.Lock() 220 defer gServer.lock.Unlock() 221 for _, clientRoot := range clientRoots { 222 err := gServer.appendClientRootCA(clientRoot) 223 if err != nil { 224 return err 225 } 226 } 227 return nil 228 } 229 230 //internal function to add a PEM-encoded clientRootCA 231 func (gServer *grpcServerImpl) appendClientRootCA(clientRoot []byte) error { 232 233 errMsg := "Failed to append client root certificate(s): %s" 234 //convert to x509 235 certs, subjects, err := pemToX509Certs(clientRoot) 236 if err != nil { 237 return fmt.Errorf(errMsg, err.Error()) 238 } 239 240 if len(certs) < 1 { 241 return fmt.Errorf(errMsg, "No client root certificates found") 242 } 243 244 for i, cert := range certs { 245 //first add to the ClientCAs 246 gServer.tlsConfig.ClientCAs.AddCert(cert) 247 //add it to our clientRootCAs map using subject as key 248 gServer.clientRootCAs[subjects[i]] = cert 249 } 250 return nil 251 } 252 253 //RemoveClientRootCAs removes PEM-encoded X509 certificate authorities from 254 //the list of authorities used to verify client certificates 255 func (gServer *grpcServerImpl) RemoveClientRootCAs(clientRoots [][]byte) error { 256 gServer.lock.Lock() 257 defer gServer.lock.Unlock() 258 //remove from internal map 259 for _, clientRoot := range clientRoots { 260 err := gServer.removeClientRootCA(clientRoot) 261 if err != nil { 262 return err 263 } 264 } 265 266 //create a new CertPool and populate with current clientRootCAs 267 certPool := x509.NewCertPool() 268 for _, clientRoot := range gServer.clientRootCAs { 269 certPool.AddCert(clientRoot) 270 } 271 272 //replace the current ClientCAs pool 273 gServer.tlsConfig.ClientCAs = certPool 274 return nil 275 } 276 277 //internal function to remove a PEM-encoded clientRootCA 278 func (gServer *grpcServerImpl) removeClientRootCA(clientRoot []byte) error { 279 280 errMsg := "Failed to remove client root certificate(s): %s" 281 //convert to x509 282 certs, subjects, err := pemToX509Certs(clientRoot) 283 if err != nil { 284 return fmt.Errorf(errMsg, err.Error()) 285 } 286 287 if len(certs) < 1 { 288 return fmt.Errorf(errMsg, "No client root certificates found") 289 } 290 291 for i, subject := range subjects { 292 //remove it from our clientRootCAs map using subject as key 293 //check to see if we have match 294 if certs[i].Equal(gServer.clientRootCAs[subject]) { 295 delete(gServer.clientRootCAs, subject) 296 } 297 } 298 return nil 299 } 300 301 //SetClientRootCAs sets the list of authorities used to verify client 302 //certificates based on a list of PEM-encoded X509 certificate authorities 303 func (gServer *grpcServerImpl) SetClientRootCAs(clientRoots [][]byte) error { 304 gServer.lock.Lock() 305 defer gServer.lock.Unlock() 306 307 errMsg := "Failed to set client root certificate(s): %s" 308 309 //create a new map and CertPool 310 clientRootCAs := make(map[string]*x509.Certificate) 311 for _, clientRoot := range clientRoots { 312 certs, subjects, err := pemToX509Certs(clientRoot) 313 if err != nil { 314 return fmt.Errorf(errMsg, err.Error()) 315 } 316 if len(certs) >= 1 { 317 for i, cert := range certs { 318 //add it to our clientRootCAs map using subject as key 319 clientRootCAs[subjects[i]] = cert 320 } 321 } 322 } 323 324 //create a new CertPool and populate with the new clientRootCAs 325 certPool := x509.NewCertPool() 326 for _, clientRoot := range clientRootCAs { 327 certPool.AddCert(clientRoot) 328 } 329 //replace the internal map 330 gServer.clientRootCAs = clientRootCAs 331 //replace the current ClientCAs pool 332 gServer.tlsConfig.ClientCAs = certPool 333 return nil 334 } 335 336 //utility function to parse PEM-encoded certs 337 func pemToX509Certs(pemCerts []byte) ([]*x509.Certificate, []string, error) { 338 339 //it's possible that multiple certs are encoded 340 certs := []*x509.Certificate{} 341 subjects := []string{} 342 for len(pemCerts) > 0 { 343 var block *pem.Block 344 block, pemCerts = pem.Decode(pemCerts) 345 if block == nil { 346 break 347 } 348 /** TODO: check why msp does not add type to PEM header 349 if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { 350 continue 351 } 352 */ 353 354 cert, err := x509.ParseCertificate(block.Bytes) 355 if err != nil { 356 return nil, subjects, err 357 } else { 358 certs = append(certs, cert) 359 //extract and append the subject 360 subjects = append(subjects, string(cert.RawSubject)) 361 } 362 } 363 return certs, subjects, nil 364 }