google.golang.org/grpc@v1.62.1/credentials/tls.go (about) 1 /* 2 * 3 * Copyright 2014 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package credentials 20 21 import ( 22 "context" 23 "crypto/tls" 24 "crypto/x509" 25 "fmt" 26 "net" 27 "net/url" 28 "os" 29 30 credinternal "google.golang.org/grpc/internal/credentials" 31 ) 32 33 // TLSInfo contains the auth information for a TLS authenticated connection. 34 // It implements the AuthInfo interface. 35 type TLSInfo struct { 36 State tls.ConnectionState 37 CommonAuthInfo 38 // This API is experimental. 39 SPIFFEID *url.URL 40 } 41 42 // AuthType returns the type of TLSInfo as a string. 43 func (t TLSInfo) AuthType() string { 44 return "tls" 45 } 46 47 // cipherSuiteLookup returns the string version of a TLS cipher suite ID. 48 func cipherSuiteLookup(cipherSuiteID uint16) string { 49 for _, s := range tls.CipherSuites() { 50 if s.ID == cipherSuiteID { 51 return s.Name 52 } 53 } 54 for _, s := range tls.InsecureCipherSuites() { 55 if s.ID == cipherSuiteID { 56 return s.Name 57 } 58 } 59 return fmt.Sprintf("unknown ID: %v", cipherSuiteID) 60 } 61 62 // GetSecurityValue returns security info requested by channelz. 63 func (t TLSInfo) GetSecurityValue() ChannelzSecurityValue { 64 v := &TLSChannelzSecurityValue{ 65 StandardName: cipherSuiteLookup(t.State.CipherSuite), 66 } 67 // Currently there's no way to get LocalCertificate info from tls package. 68 if len(t.State.PeerCertificates) > 0 { 69 v.RemoteCertificate = t.State.PeerCertificates[0].Raw 70 } 71 return v 72 } 73 74 // tlsCreds is the credentials required for authenticating a connection using TLS. 75 type tlsCreds struct { 76 // TLS configuration 77 config *tls.Config 78 } 79 80 func (c tlsCreds) Info() ProtocolInfo { 81 return ProtocolInfo{ 82 SecurityProtocol: "tls", 83 SecurityVersion: "1.2", 84 ServerName: c.config.ServerName, 85 } 86 } 87 88 func (c *tlsCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (_ net.Conn, _ AuthInfo, err error) { 89 // use local cfg to avoid clobbering ServerName if using multiple endpoints 90 cfg := credinternal.CloneTLSConfig(c.config) 91 if cfg.ServerName == "" { 92 serverName, _, err := net.SplitHostPort(authority) 93 if err != nil { 94 // If the authority had no host port or if the authority cannot be parsed, use it as-is. 95 serverName = authority 96 } 97 cfg.ServerName = serverName 98 } 99 conn := tls.Client(rawConn, cfg) 100 errChannel := make(chan error, 1) 101 go func() { 102 errChannel <- conn.Handshake() 103 close(errChannel) 104 }() 105 select { 106 case err := <-errChannel: 107 if err != nil { 108 conn.Close() 109 return nil, nil, err 110 } 111 case <-ctx.Done(): 112 conn.Close() 113 return nil, nil, ctx.Err() 114 } 115 tlsInfo := TLSInfo{ 116 State: conn.ConnectionState(), 117 CommonAuthInfo: CommonAuthInfo{ 118 SecurityLevel: PrivacyAndIntegrity, 119 }, 120 } 121 id := credinternal.SPIFFEIDFromState(conn.ConnectionState()) 122 if id != nil { 123 tlsInfo.SPIFFEID = id 124 } 125 return credinternal.WrapSyscallConn(rawConn, conn), tlsInfo, nil 126 } 127 128 func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) { 129 conn := tls.Server(rawConn, c.config) 130 if err := conn.Handshake(); err != nil { 131 conn.Close() 132 return nil, nil, err 133 } 134 tlsInfo := TLSInfo{ 135 State: conn.ConnectionState(), 136 CommonAuthInfo: CommonAuthInfo{ 137 SecurityLevel: PrivacyAndIntegrity, 138 }, 139 } 140 id := credinternal.SPIFFEIDFromState(conn.ConnectionState()) 141 if id != nil { 142 tlsInfo.SPIFFEID = id 143 } 144 return credinternal.WrapSyscallConn(rawConn, conn), tlsInfo, nil 145 } 146 147 func (c *tlsCreds) Clone() TransportCredentials { 148 return NewTLS(c.config) 149 } 150 151 func (c *tlsCreds) OverrideServerName(serverNameOverride string) error { 152 c.config.ServerName = serverNameOverride 153 return nil 154 } 155 156 // The following cipher suites are forbidden for use with HTTP/2 by 157 // https://datatracker.ietf.org/doc/html/rfc7540#appendix-A 158 var tls12ForbiddenCipherSuites = map[uint16]struct{}{ 159 tls.TLS_RSA_WITH_AES_128_CBC_SHA: {}, 160 tls.TLS_RSA_WITH_AES_256_CBC_SHA: {}, 161 tls.TLS_RSA_WITH_AES_128_GCM_SHA256: {}, 162 tls.TLS_RSA_WITH_AES_256_GCM_SHA384: {}, 163 tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: {}, 164 tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: {}, 165 tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: {}, 166 tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: {}, 167 } 168 169 // NewTLS uses c to construct a TransportCredentials based on TLS. 170 func NewTLS(c *tls.Config) TransportCredentials { 171 tc := &tlsCreds{credinternal.CloneTLSConfig(c)} 172 tc.config.NextProtos = credinternal.AppendH2ToNextProtos(tc.config.NextProtos) 173 // If the user did not configure a MinVersion and did not configure a 174 // MaxVersion < 1.2, use MinVersion=1.2, which is required by 175 // https://datatracker.ietf.org/doc/html/rfc7540#section-9.2 176 if tc.config.MinVersion == 0 && (tc.config.MaxVersion == 0 || tc.config.MaxVersion >= tls.VersionTLS12) { 177 tc.config.MinVersion = tls.VersionTLS12 178 } 179 // If the user did not configure CipherSuites, use all "secure" cipher 180 // suites reported by the TLS package, but remove some explicitly forbidden 181 // by https://datatracker.ietf.org/doc/html/rfc7540#appendix-A 182 if tc.config.CipherSuites == nil { 183 for _, cs := range tls.CipherSuites() { 184 if _, ok := tls12ForbiddenCipherSuites[cs.ID]; !ok { 185 tc.config.CipherSuites = append(tc.config.CipherSuites, cs.ID) 186 } 187 } 188 } 189 return tc 190 } 191 192 // NewClientTLSFromCert constructs TLS credentials from the provided root 193 // certificate authority certificate(s) to validate server connections. If 194 // certificates to establish the identity of the client need to be included in 195 // the credentials (eg: for mTLS), use NewTLS instead, where a complete 196 // tls.Config can be specified. 197 // serverNameOverride is for testing only. If set to a non empty string, 198 // it will override the virtual host name of authority (e.g. :authority header 199 // field) in requests. 200 func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) TransportCredentials { 201 return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}) 202 } 203 204 // NewClientTLSFromFile constructs TLS credentials from the provided root 205 // certificate authority certificate file(s) to validate server connections. If 206 // certificates to establish the identity of the client need to be included in 207 // the credentials (eg: for mTLS), use NewTLS instead, where a complete 208 // tls.Config can be specified. 209 // serverNameOverride is for testing only. If set to a non empty string, 210 // it will override the virtual host name of authority (e.g. :authority header 211 // field) in requests. 212 func NewClientTLSFromFile(certFile, serverNameOverride string) (TransportCredentials, error) { 213 b, err := os.ReadFile(certFile) 214 if err != nil { 215 return nil, err 216 } 217 cp := x509.NewCertPool() 218 if !cp.AppendCertsFromPEM(b) { 219 return nil, fmt.Errorf("credentials: failed to append certificates") 220 } 221 return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}), nil 222 } 223 224 // NewServerTLSFromCert constructs TLS credentials from the input certificate for server. 225 func NewServerTLSFromCert(cert *tls.Certificate) TransportCredentials { 226 return NewTLS(&tls.Config{Certificates: []tls.Certificate{*cert}}) 227 } 228 229 // NewServerTLSFromFile constructs TLS credentials from the input certificate file and key 230 // file for server. 231 func NewServerTLSFromFile(certFile, keyFile string) (TransportCredentials, error) { 232 cert, err := tls.LoadX509KeyPair(certFile, keyFile) 233 if err != nil { 234 return nil, err 235 } 236 return NewTLS(&tls.Config{Certificates: []tls.Certificate{cert}}), nil 237 } 238 239 // TLSChannelzSecurityValue defines the struct that TLS protocol should return 240 // from GetSecurityValue(), containing security info like cipher and certificate used. 241 // 242 // # Experimental 243 // 244 // Notice: This type is EXPERIMENTAL and may be changed or removed in a 245 // later release. 246 type TLSChannelzSecurityValue struct { 247 ChannelzSecurityValue 248 StandardName string 249 LocalCertificate []byte 250 RemoteCertificate []byte 251 }