blob: ce2bbc10a14276987fac753bee6aa94bb15e0edf [file] [log] [blame]
khenaidoo5fc5cea2021-08-11 17:39:16 -04001/*
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
19package credentials
20
21import (
22 "context"
23 "crypto/tls"
24 "crypto/x509"
25 "fmt"
26 "io/ioutil"
27 "net"
28 "net/url"
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.
35type 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.
43func (t TLSInfo) AuthType() string {
44 return "tls"
45}
46
47// GetSecurityValue returns security info requested by channelz.
48func (t TLSInfo) GetSecurityValue() ChannelzSecurityValue {
49 v := &TLSChannelzSecurityValue{
50 StandardName: cipherSuiteLookup[t.State.CipherSuite],
51 }
52 // Currently there's no way to get LocalCertificate info from tls package.
53 if len(t.State.PeerCertificates) > 0 {
54 v.RemoteCertificate = t.State.PeerCertificates[0].Raw
55 }
56 return v
57}
58
59// tlsCreds is the credentials required for authenticating a connection using TLS.
60type tlsCreds struct {
61 // TLS configuration
62 config *tls.Config
63}
64
65func (c tlsCreds) Info() ProtocolInfo {
66 return ProtocolInfo{
67 SecurityProtocol: "tls",
68 SecurityVersion: "1.2",
69 ServerName: c.config.ServerName,
70 }
71}
72
73func (c *tlsCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (_ net.Conn, _ AuthInfo, err error) {
74 // use local cfg to avoid clobbering ServerName if using multiple endpoints
75 cfg := credinternal.CloneTLSConfig(c.config)
76 if cfg.ServerName == "" {
77 serverName, _, err := net.SplitHostPort(authority)
78 if err != nil {
79 // If the authority had no host port or if the authority cannot be parsed, use it as-is.
80 serverName = authority
81 }
82 cfg.ServerName = serverName
83 }
84 conn := tls.Client(rawConn, cfg)
85 errChannel := make(chan error, 1)
86 go func() {
87 errChannel <- conn.Handshake()
88 close(errChannel)
89 }()
90 select {
91 case err := <-errChannel:
92 if err != nil {
93 conn.Close()
94 return nil, nil, err
95 }
96 case <-ctx.Done():
97 conn.Close()
98 return nil, nil, ctx.Err()
99 }
100 tlsInfo := TLSInfo{
101 State: conn.ConnectionState(),
102 CommonAuthInfo: CommonAuthInfo{
103 SecurityLevel: PrivacyAndIntegrity,
104 },
105 }
106 id := credinternal.SPIFFEIDFromState(conn.ConnectionState())
107 if id != nil {
108 tlsInfo.SPIFFEID = id
109 }
110 return credinternal.WrapSyscallConn(rawConn, conn), tlsInfo, nil
111}
112
113func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) {
114 conn := tls.Server(rawConn, c.config)
115 if err := conn.Handshake(); err != nil {
116 conn.Close()
117 return nil, nil, err
118 }
119 tlsInfo := TLSInfo{
120 State: conn.ConnectionState(),
121 CommonAuthInfo: CommonAuthInfo{
122 SecurityLevel: PrivacyAndIntegrity,
123 },
124 }
125 id := credinternal.SPIFFEIDFromState(conn.ConnectionState())
126 if id != nil {
127 tlsInfo.SPIFFEID = id
128 }
129 return credinternal.WrapSyscallConn(rawConn, conn), tlsInfo, nil
130}
131
132func (c *tlsCreds) Clone() TransportCredentials {
133 return NewTLS(c.config)
134}
135
136func (c *tlsCreds) OverrideServerName(serverNameOverride string) error {
137 c.config.ServerName = serverNameOverride
138 return nil
139}
140
141// NewTLS uses c to construct a TransportCredentials based on TLS.
142func NewTLS(c *tls.Config) TransportCredentials {
143 tc := &tlsCreds{credinternal.CloneTLSConfig(c)}
144 tc.config.NextProtos = credinternal.AppendH2ToNextProtos(tc.config.NextProtos)
145 return tc
146}
147
148// NewClientTLSFromCert constructs TLS credentials from the provided root
149// certificate authority certificate(s) to validate server connections. If
150// certificates to establish the identity of the client need to be included in
151// the credentials (eg: for mTLS), use NewTLS instead, where a complete
152// tls.Config can be specified.
153// serverNameOverride is for testing only. If set to a non empty string,
154// it will override the virtual host name of authority (e.g. :authority header
155// field) in requests.
156func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) TransportCredentials {
157 return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp})
158}
159
160// NewClientTLSFromFile constructs TLS credentials from the provided root
161// certificate authority certificate file(s) to validate server connections. If
162// certificates to establish the identity of the client need to be included in
163// the credentials (eg: for mTLS), use NewTLS instead, where a complete
164// tls.Config can be specified.
165// serverNameOverride is for testing only. If set to a non empty string,
166// it will override the virtual host name of authority (e.g. :authority header
167// field) in requests.
168func NewClientTLSFromFile(certFile, serverNameOverride string) (TransportCredentials, error) {
169 b, err := ioutil.ReadFile(certFile)
170 if err != nil {
171 return nil, err
172 }
173 cp := x509.NewCertPool()
174 if !cp.AppendCertsFromPEM(b) {
175 return nil, fmt.Errorf("credentials: failed to append certificates")
176 }
177 return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}), nil
178}
179
180// NewServerTLSFromCert constructs TLS credentials from the input certificate for server.
181func NewServerTLSFromCert(cert *tls.Certificate) TransportCredentials {
182 return NewTLS(&tls.Config{Certificates: []tls.Certificate{*cert}})
183}
184
185// NewServerTLSFromFile constructs TLS credentials from the input certificate file and key
186// file for server.
187func NewServerTLSFromFile(certFile, keyFile string) (TransportCredentials, error) {
188 cert, err := tls.LoadX509KeyPair(certFile, keyFile)
189 if err != nil {
190 return nil, err
191 }
192 return NewTLS(&tls.Config{Certificates: []tls.Certificate{cert}}), nil
193}
194
195// TLSChannelzSecurityValue defines the struct that TLS protocol should return
196// from GetSecurityValue(), containing security info like cipher and certificate used.
197//
Joey Armstrongba3d9d12024-01-15 14:22:11 -0500198// # Experimental
khenaidoo5fc5cea2021-08-11 17:39:16 -0400199//
200// Notice: This type is EXPERIMENTAL and may be changed or removed in a
201// later release.
202type TLSChannelzSecurityValue struct {
203 ChannelzSecurityValue
204 StandardName string
205 LocalCertificate []byte
206 RemoteCertificate []byte
207}
208
209var cipherSuiteLookup = map[uint16]string{
210 tls.TLS_RSA_WITH_RC4_128_SHA: "TLS_RSA_WITH_RC4_128_SHA",
211 tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
212 tls.TLS_RSA_WITH_AES_128_CBC_SHA: "TLS_RSA_WITH_AES_128_CBC_SHA",
213 tls.TLS_RSA_WITH_AES_256_CBC_SHA: "TLS_RSA_WITH_AES_256_CBC_SHA",
214 tls.TLS_RSA_WITH_AES_128_GCM_SHA256: "TLS_RSA_WITH_AES_128_GCM_SHA256",
215 tls.TLS_RSA_WITH_AES_256_GCM_SHA384: "TLS_RSA_WITH_AES_256_GCM_SHA384",
216 tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
217 tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
218 tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
219 tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA: "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
220 tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
221 tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
222 tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
223 tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
224 tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
225 tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
226 tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
227 tls.TLS_FALLBACK_SCSV: "TLS_FALLBACK_SCSV",
228 tls.TLS_RSA_WITH_AES_128_CBC_SHA256: "TLS_RSA_WITH_AES_128_CBC_SHA256",
229 tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
230 tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
231 tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
232 tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
233 tls.TLS_AES_128_GCM_SHA256: "TLS_AES_128_GCM_SHA256",
234 tls.TLS_AES_256_GCM_SHA384: "TLS_AES_256_GCM_SHA384",
235 tls.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256",
236}