grpc.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package tls
  2. import (
  3. "context"
  4. gotls "crypto/tls"
  5. "net"
  6. "net/url"
  7. "strconv"
  8. utls "github.com/refraction-networking/utls"
  9. "google.golang.org/grpc/credentials"
  10. )
  11. // grpcUtlsInfo contains the auth information for a TLS authenticated connection.
  12. // It implements the AuthInfo interface.
  13. type grpcUtlsInfo struct {
  14. State utls.ConnectionState
  15. credentials.CommonAuthInfo
  16. // This API is experimental.
  17. SPIFFEID *url.URL
  18. }
  19. // AuthType returns the type of TLSInfo as a string.
  20. func (t grpcUtlsInfo) AuthType() string {
  21. return "utls"
  22. }
  23. // GetSecurityValue returns security info requested by channelz.
  24. func (t grpcUtlsInfo) GetSecurityValue() credentials.ChannelzSecurityValue {
  25. v := &credentials.TLSChannelzSecurityValue{
  26. StandardName: "0x" + strconv.FormatUint(uint64(t.State.CipherSuite), 16),
  27. }
  28. // Currently there's no way to get LocalCertificate info from tls package.
  29. if len(t.State.PeerCertificates) > 0 {
  30. v.RemoteCertificate = t.State.PeerCertificates[0].Raw
  31. }
  32. return v
  33. }
  34. // grpcUtls is the credentials required for authenticating a connection using TLS.
  35. type grpcUtls struct {
  36. config *gotls.Config
  37. fingerprint *utls.ClientHelloID
  38. }
  39. func (c grpcUtls) Info() credentials.ProtocolInfo {
  40. return credentials.ProtocolInfo{
  41. SecurityProtocol: "tls",
  42. SecurityVersion: "1.2",
  43. ServerName: c.config.ServerName,
  44. }
  45. }
  46. func (c *grpcUtls) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (_ net.Conn, _ credentials.AuthInfo, err error) {
  47. // use local cfg to avoid clobbering ServerName if using multiple endpoints
  48. cfg := c.config.Clone()
  49. if cfg.ServerName == "" {
  50. serverName, _, err := net.SplitHostPort(authority)
  51. if err != nil {
  52. // If the authority had no host port or if the authority cannot be parsed, use it as-is.
  53. serverName = authority
  54. }
  55. cfg.ServerName = serverName
  56. }
  57. conn := UClient(rawConn, cfg, c.fingerprint).(*UConn)
  58. errChannel := make(chan error, 1)
  59. go func() {
  60. errChannel <- conn.Handshake()
  61. close(errChannel)
  62. }()
  63. select {
  64. case err := <-errChannel:
  65. if err != nil {
  66. conn.Close()
  67. return nil, nil, err
  68. }
  69. case <-ctx.Done():
  70. conn.Close()
  71. return nil, nil, ctx.Err()
  72. }
  73. tlsInfo := grpcUtlsInfo{
  74. State: conn.ConnectionState(),
  75. CommonAuthInfo: credentials.CommonAuthInfo{
  76. SecurityLevel: credentials.PrivacyAndIntegrity,
  77. },
  78. }
  79. return conn, tlsInfo, nil
  80. }
  81. // ServerHandshake will always panic. We don't support running uTLS as server.
  82. func (c *grpcUtls) ServerHandshake(net.Conn) (net.Conn, credentials.AuthInfo, error) {
  83. panic("not available!")
  84. }
  85. func (c *grpcUtls) Clone() credentials.TransportCredentials {
  86. return NewGrpcUtls(c.config, c.fingerprint)
  87. }
  88. func (c *grpcUtls) OverrideServerName(serverNameOverride string) error {
  89. c.config.ServerName = serverNameOverride
  90. return nil
  91. }
  92. // NewGrpcUtls uses c to construct a TransportCredentials based on uTLS.
  93. func NewGrpcUtls(c *gotls.Config, fingerprint *utls.ClientHelloID) credentials.TransportCredentials {
  94. tc := &grpcUtls{c.Clone(), fingerprint}
  95. return tc
  96. }