github.com/koko1123/flow-go-1@v0.29.6/utils/grpcutils/grpc.go (about) 1 package grpcutils 2 3 import ( 4 "crypto/tls" 5 "crypto/x509" 6 "encoding/hex" 7 "fmt" 8 9 libp2ptls "github.com/libp2p/go-libp2p-tls" 10 lcrypto "github.com/libp2p/go-libp2p/core/crypto" 11 12 "github.com/koko1123/flow-go-1/network/p2p/keyutils" 13 "github.com/onflow/flow-go/crypto" 14 ) 15 16 // DefaultMaxMsgSize use 16MB as the default message size limit. 17 // grpc library default is 4MB 18 const DefaultMaxMsgSize = 1024 * 1024 * 16 19 20 // X509Certificate generates a self-signed x509 TLS certificate from the given key. The generated certificate 21 // includes a libp2p extension that specifies the public key and the signature. The certificate does not include any 22 // SAN extension. 23 func X509Certificate(privKey crypto.PrivateKey) (*tls.Certificate, error) { 24 25 // convert the Flow crypto private key to a Libp2p private crypto key 26 libP2PKey, err := keyutils.LibP2PPrivKeyFromFlow(privKey) 27 if err != nil { 28 return nil, fmt.Errorf("could not convert Flow key to libp2p key: %w", err) 29 } 30 31 // create a libp2p Identity from the libp2p private key 32 id, err := libp2ptls.NewIdentity(libP2PKey) 33 if err != nil { 34 return nil, fmt.Errorf("could not generate identity: %w", err) 35 } 36 37 // extract the TLSConfig from it which will contain the generated x509 certificate 38 // (ignore the public key that is returned - it is the public key of the private key used to generate the ID) 39 libp2pTlsConfig, _ := id.ConfigForPeer("") 40 41 // verify that exactly one certificate was generated for the given key 42 certCount := len(libp2pTlsConfig.Certificates) 43 if certCount != 1 { 44 return nil, fmt.Errorf("invalid count for the generated x509 certificate: %d", certCount) 45 } 46 47 return &libp2pTlsConfig.Certificates[0], nil 48 } 49 50 // DefaultServerTLSConfig returns the default TLS server config with the given cert for a secure GRPC server 51 func DefaultServerTLSConfig(cert *tls.Certificate) *tls.Config { 52 tlsConfig := &tls.Config{ 53 MinVersion: tls.VersionTLS13, 54 Certificates: []tls.Certificate{*cert}, 55 ClientAuth: tls.NoClientCert, 56 } 57 return tlsConfig 58 } 59 60 // ServerAuthError is an error returned when the server authentication fails 61 type ServerAuthError struct { 62 message string 63 } 64 65 // newServerAuthError constructs a new ServerAuthError 66 func newServerAuthError(msg string, args ...interface{}) *ServerAuthError { 67 return &ServerAuthError{message: fmt.Sprintf(msg, args...)} 68 } 69 70 func (e ServerAuthError) Error() string { 71 return e.message 72 } 73 74 // IsServerAuthError checks if the input error is of a ServerAuthError type 75 func IsServerAuthError(err error) bool { 76 _, ok := err.(*ServerAuthError) 77 return ok 78 } 79 80 // DefaultClientTLSConfig returns the default TLS client config with the given public key for a secure GRPC client 81 // The TLSConfig verifies that the server certifcate is valid and has the correct signature 82 func DefaultClientTLSConfig(publicKey crypto.PublicKey) (*tls.Config, error) { 83 84 // #nosec G402 85 config := &tls.Config{ 86 MinVersion: tls.VersionTLS13, 87 // This is not insecure here. We will verify the cert chain ourselves. 88 InsecureSkipVerify: true, 89 ClientAuth: tls.RequireAnyClientCert, 90 } 91 92 verifyPeerCertFunc, err := verifyPeerCertificateFunc(publicKey) 93 if err != nil { 94 return nil, err 95 } 96 config.VerifyPeerCertificate = verifyPeerCertFunc 97 98 return config, nil 99 } 100 101 func verifyPeerCertificateFunc(expectedPublicKey crypto.PublicKey) (func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error, error) { 102 103 // convert the Flow.crypto key to LibP2P key for easy comparision using LibP2P TLS utils 104 remotePeerLibP2PID, err := keyutils.PeerIDFromFlowPublicKey(expectedPublicKey) 105 if err != nil { 106 return nil, fmt.Errorf("failed to derive the libp2p Peer ID from the Flow key: %w", err) 107 } 108 109 // We're using InsecureSkipVerify, so the verifiedChains parameter will always be empty. 110 // We need to parse the certificates ourselves from the raw certs. 111 verifyFunc := func(rawCerts [][]byte, _ [][]*x509.Certificate) error { 112 113 chain := make([]*x509.Certificate, len(rawCerts)) 114 for i := 0; i < len(rawCerts); i++ { 115 cert, err := x509.ParseCertificate(rawCerts[i]) 116 if err != nil { 117 return newServerAuthError(err.Error()) 118 } 119 chain[i] = cert 120 } 121 122 // libp2ptls.PubKeyFromCertChain verifies the certificate, verifies that the certificate contains the special libp2p 123 // extension, extract the remote's public key and finally verifies the signature included in the certificate 124 actualLibP2PKey, err := libp2ptls.PubKeyFromCertChain(chain) 125 if err != nil { 126 return newServerAuthError(err.Error()) 127 } 128 129 // verify that the public key received is the one that is expected 130 if !remotePeerLibP2PID.MatchesPublicKey(actualLibP2PKey) { 131 actualKeyHex, err := libP2PKeyToHexString(actualLibP2PKey) 132 if err != nil { 133 return err 134 } 135 return newServerAuthError("invalid public key received: expected %s, got %s", expectedPublicKey.String(), actualKeyHex) 136 } 137 return nil 138 } 139 140 return verifyFunc, nil 141 } 142 143 func libP2PKeyToHexString(key lcrypto.PubKey) (string, *ServerAuthError) { 144 keyRaw, err := key.Raw() 145 if err != nil { 146 return "", newServerAuthError(err.Error()) 147 } 148 return hex.EncodeToString(keyRaw), nil 149 }