You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/internal/cmd/commands/connect/client_tls_config.go

73 lines
2.1 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package connect
import (
"crypto/ed25519"
"crypto/tls"
"crypto/x509"
"fmt"
targetspb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets"
)
// ClientTlsConfig creates a TLS configuration from the session authorization
// data and host
func ClientTlsConfig(sessionAuthzData *targetspb.SessionAuthorizationData, host string) (*tls.Config, error) {
const op = "connect.ClientTlsConfig"
if sessionAuthzData == nil {
return nil, fmt.Errorf("%s: nil session authorization data", op)
}
parsedCert, err := x509.ParseCertificate(sessionAuthzData.Certificate)
if err != nil {
return nil, fmt.Errorf("unable to decode mTLS certificate: %w", err)
}
certPool := x509.NewCertPool()
certPool.AddCert(parsedCert)
tlsConf := &tls.Config{
Certificates: []tls.Certificate{
{
Certificate: [][]byte{sessionAuthzData.Certificate},
PrivateKey: ed25519.PrivateKey(sessionAuthzData.PrivateKey),
Leaf: parsedCert,
},
},
ServerName: host,
MinVersion: tls.VersionTLS13,
NextProtos: []string{"http/1.1", sessionAuthzData.SessionId},
// This is set this way so we can make use of VerifyConnection, which we
// set on this TLS config below. We are not skipping verification!
InsecureSkipVerify: true,
}
if host == "" {
tlsConf.ServerName = parsedCert.DNSNames[0]
}
// We disable normal DNS SAN behavior as we don't rely on DNS or IP
// addresses for security and want to avoid issues with including localhost
// etc.
verifyOpts := x509.VerifyOptions{
DNSName: sessionAuthzData.SessionId,
Roots: certPool,
KeyUsages: []x509.ExtKeyUsage{
x509.ExtKeyUsageClientAuth,
x509.ExtKeyUsageServerAuth,
},
}
tlsConf.VerifyConnection = func(cs tls.ConnectionState) error {
// Go will not run this without at least one peer certificate, but
// doesn't hurt to check
if len(cs.PeerCertificates) == 0 {
return fmt.Errorf("%s: no peer certificates provided", op)
}
_, err := cs.PeerCertificates[0].Verify(verifyOpts)
return err
}
return tlsConf, nil
}