package controller import ( "context" "crypto/tls" "crypto/x509" "encoding/base64" "encoding/json" "errors" "net" "strings" "github.com/hashicorp/boundary/internal/cmd/base" wrapping "github.com/hashicorp/go-kms-wrapping" "google.golang.org/protobuf/proto" ) type workerAuthEntry struct { *base.WorkerAuthInfo conn net.Conn } func (c Controller) validateWorkerTls(hello *tls.ClientHelloInfo) (*tls.Config, error) { for _, p := range hello.SupportedProtos { switch { case strings.HasPrefix(p, "v1workerauth-"): tlsConf, workerInfo, err := c.v1WorkerAuthConfig(hello.SupportedProtos) if err == nil { // Set the info we need to prevent replays c.workerAuthCache.Set(workerInfo.ConnectionNonce, &workerAuthEntry{ WorkerAuthInfo: workerInfo, }, 0) } return tlsConf, err } } return nil, nil } func (c Controller) v1WorkerAuthConfig(protos []string) (*tls.Config, *base.WorkerAuthInfo, error) { var firstMatchProto string var encString string for _, p := range protos { if strings.HasPrefix(p, "v1workerauth-") { // Strip that and the number encString += strings.TrimPrefix(p, "v1workerauth-")[3:] if firstMatchProto == "" { firstMatchProto = p } } } if firstMatchProto == "" { return nil, nil, errors.New("no matching proto found") } marshaledEncInfo, err := base64.RawStdEncoding.DecodeString(encString) if err != nil { return nil, nil, err } encInfo := new(wrapping.EncryptedBlobInfo) if err := proto.Unmarshal(marshaledEncInfo, encInfo); err != nil { return nil, nil, err } marshaledInfo, err := c.conf.WorkerAuthKms.Decrypt(context.Background(), encInfo, nil) if err != nil { return nil, nil, err } info := new(base.WorkerAuthInfo) if err := json.Unmarshal(marshaledInfo, info); err != nil { return nil, nil, err } rootCAs := x509.NewCertPool() if ok := rootCAs.AppendCertsFromPEM(info.CACertPEM); !ok { return nil, info, errors.New("unable to add ca cert to cert pool") } tlsCert, err := tls.X509KeyPair(info.CertPEM, info.KeyPEM) if err != nil { return nil, info, err } tlsConfig := &tls.Config{ Certificates: []tls.Certificate{tlsCert}, ClientCAs: rootCAs, ClientAuth: tls.RequireAndVerifyClientCert, NextProtos: []string{firstMatchProto}, MinVersion: tls.VersionTLS13, } return tlsConfig, info, nil }