boulder/grpc/creds/creds.go

78 lines
2.4 KiB
Go

package creds
import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"net"
"time"
"golang.org/x/net/context"
"google.golang.org/grpc/credentials"
)
// transportCredentials is a grpc/credentials.TransportCredentials which supports
// connecting to, and verifying multiple DNS names
type transportCredentials struct {
roots *x509.CertPool
clients []tls.Certificate
}
// New returns a new initialized grpc/credentials.TransportCredentials
func New(rootCAs *x509.CertPool, clientCerts []tls.Certificate) credentials.TransportCredentials {
return &transportCredentials{rootCAs, clientCerts}
}
// ClientHandshake performs the TLS handshake for a client -> server connection
func (tc *transportCredentials) ClientHandshake(addr string, rawConn net.Conn, timeout time.Duration) (net.Conn, credentials.AuthInfo, error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, nil, err
}
conn := tls.Client(rawConn, &tls.Config{
ServerName: host,
RootCAs: tc.roots,
Certificates: tc.clients,
MinVersion: tls.VersionTLS12, // Override default of tls.VersionTLS10
MaxVersion: tls.VersionTLS12, // Same as default in golang <= 1.6
})
errChan := make(chan error, 1)
go func() {
errChan <- conn.Handshake()
}()
select {
case <-time.After(timeout):
return nil, nil, errors.New("boulder/grpc/creds: TLS handshake timed out")
case err := <-errChan:
if err != nil {
_ = rawConn.Close()
return nil, nil, fmt.Errorf("boulder/grpc/creds: TLS handshake failed: %s", err)
}
return conn, nil, nil
}
}
// ServerHandshake performs the TLS handshake for a server <- client connection
func (tc *transportCredentials) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
return nil, nil, fmt.Errorf("boulder/grpc/creds: Server-side handshakes are not implemented")
}
// Info returns information about the transport protocol used
func (tc *transportCredentials) Info() credentials.ProtocolInfo {
return credentials.ProtocolInfo{
SecurityProtocol: "tls",
SecurityVersion: "1.2", // We *only* support TLS 1.2
}
}
// GetRequestMetadata returns nil, nil since TLS credentials do not have metadata.
func (tc *transportCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return nil, nil
}
// RequireTransportSecurity always returns true because TLS is transport security
func (tc *transportCredentials) RequireTransportSecurity() bool {
return true
}