package credentials
import (
credinternal
)
const alpnFailureHelpMessage = "If you upgraded from a grpc-go version earlier than 1.67, your TLS connections may have stopped working due to ALPN enforcement. For more details, see: https://github.com/grpc/grpc-go/issues/434"
var logger = grpclog.Component("credentials")
type TLSInfo struct {
State tls.ConnectionState
CommonAuthInfo
SPIFFEID *url.URL
}
func ( TLSInfo) () string {
return "tls"
}
func ( TLSInfo) ( string) error {
var []error
for , := range .State.PeerCertificates {
var error
if = .VerifyHostname(); == nil {
return nil
}
= append(, )
}
return fmt.Errorf("credentials: invalid authority %q: %v", , errors.Join(...))
}
func ( uint16) string {
for , := range tls.CipherSuites() {
if .ID == {
return .Name
}
}
for , := range tls.InsecureCipherSuites() {
if .ID == {
return .Name
}
}
return fmt.Sprintf("unknown ID: %v", )
}
func ( TLSInfo) () ChannelzSecurityValue {
:= &TLSChannelzSecurityValue{
StandardName: cipherSuiteLookup(.State.CipherSuite),
}
if len(.State.PeerCertificates) > 0 {
.RemoteCertificate = .State.PeerCertificates[0].Raw
}
return
}
type tlsCreds struct {
config *tls.Config
}
func ( tlsCreds) () ProtocolInfo {
return ProtocolInfo{
SecurityProtocol: "tls",
SecurityVersion: "1.2",
ServerName: .config.ServerName,
}
}
func ( *tlsCreds) ( context.Context, string, net.Conn) ( net.Conn, AuthInfo, error) {
:= credinternal.CloneTLSConfig(.config)
, , := net.SplitHostPort()
if != nil {
=
}
.ServerName =
:= tls.Client(, )
:= make(chan error, 1)
go func() {
<- .Handshake()
close()
}()
select {
case := <-:
if != nil {
.Close()
return nil, nil,
}
case <-.Done():
.Close()
return nil, nil, .Err()
}
:= .ConnectionState().NegotiatedProtocol
if == "" {
if envconfig.EnforceALPNEnabled {
.Close()
return nil, nil, fmt.Errorf("credentials: cannot check peer: missing selected ALPN property. %s", alpnFailureHelpMessage)
}
logger.Warningf("Allowing TLS connection to server %q with ALPN disabled. TLS connections to servers with ALPN disabled will be disallowed in future grpc-go releases", .ServerName)
}
:= TLSInfo{
State: .ConnectionState(),
CommonAuthInfo: CommonAuthInfo{
SecurityLevel: PrivacyAndIntegrity,
},
}
:= credinternal.SPIFFEIDFromState(.ConnectionState())
if != nil {
.SPIFFEID =
}
return credinternal.WrapSyscallConn(, ), , nil
}
func ( *tlsCreds) ( net.Conn) (net.Conn, AuthInfo, error) {
:= tls.Server(, .config)
if := .Handshake(); != nil {
.Close()
return nil, nil,
}
:= .ConnectionState()
if .NegotiatedProtocol == "" {
if envconfig.EnforceALPNEnabled {
.Close()
return nil, nil, fmt.Errorf("credentials: cannot check peer: missing selected ALPN property. %s", alpnFailureHelpMessage)
} else if logger.V(2) {
logger.Info("Allowing TLS connection from client with ALPN disabled. TLS connections with ALPN disabled will be disallowed in future grpc-go releases")
}
}
:= TLSInfo{
State: ,
CommonAuthInfo: CommonAuthInfo{
SecurityLevel: PrivacyAndIntegrity,
},
}
:= credinternal.SPIFFEIDFromState(.ConnectionState())
if != nil {
.SPIFFEID =
}
return credinternal.WrapSyscallConn(, ), , nil
}
func ( *tlsCreds) () TransportCredentials {
return NewTLS(.config)
}
func ( *tlsCreds) ( string) error {
.config.ServerName =
return nil
}
var tls12ForbiddenCipherSuites = map[uint16]struct{}{
tls.TLS_RSA_WITH_AES_128_CBC_SHA: {},
tls.TLS_RSA_WITH_AES_256_CBC_SHA: {},
tls.TLS_RSA_WITH_AES_128_GCM_SHA256: {},
tls.TLS_RSA_WITH_AES_256_GCM_SHA384: {},
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: {},
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: {},
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: {},
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: {},
}
func ( *tls.Config) TransportCredentials {
:= applyDefaults()
if .GetConfigForClient != nil {
:= .GetConfigForClient
.GetConfigForClient = func( *tls.ClientHelloInfo) (*tls.Config, error) {
, := ()
if != nil || == nil {
return ,
}
return applyDefaults(), nil
}
}
return &tlsCreds{config: }
}
func ( *tls.Config) *tls.Config {
:= credinternal.CloneTLSConfig()
.NextProtos = credinternal.AppendH2ToNextProtos(.NextProtos)
if .MinVersion == 0 && (.MaxVersion == 0 || .MaxVersion >= tls.VersionTLS12) {
.MinVersion = tls.VersionTLS12
}
if .CipherSuites == nil {
for , := range tls.CipherSuites() {
if , := tls12ForbiddenCipherSuites[.ID]; ! {
.CipherSuites = append(.CipherSuites, .ID)
}
}
}
return
}
func ( *x509.CertPool, string) TransportCredentials {
return NewTLS(&tls.Config{ServerName: , RootCAs: })
}
func (, string) (TransportCredentials, error) {
, := os.ReadFile()
if != nil {
return nil,
}
:= x509.NewCertPool()
if !.AppendCertsFromPEM() {
return nil, fmt.Errorf("credentials: failed to append certificates")
}
return NewTLS(&tls.Config{ServerName: , RootCAs: }), nil
}
func ( *tls.Certificate) TransportCredentials {
return NewTLS(&tls.Config{Certificates: []tls.Certificate{*}})
}
func (, string) (TransportCredentials, error) {
, := tls.LoadX509KeyPair(, )
if != nil {
return nil,
}
return NewTLS(&tls.Config{Certificates: []tls.Certificate{}}), nil
}
type TLSChannelzSecurityValue struct {
ChannelzSecurityValue
StandardName string
LocalCertificate []byte
RemoteCertificate []byte
}