github.com/hashicorp/vault/sdk@v0.11.0/helper/pluginutil/tls.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package pluginutil
     5  
     6  import (
     7  	"context"
     8  	"crypto/ecdsa"
     9  	"crypto/elliptic"
    10  	"crypto/rand"
    11  	"crypto/tls"
    12  	"crypto/x509"
    13  	"crypto/x509/pkix"
    14  	"time"
    15  
    16  	"github.com/hashicorp/errwrap"
    17  	"github.com/hashicorp/go-uuid"
    18  	"github.com/hashicorp/vault/sdk/helper/certutil"
    19  )
    20  
    21  // generateCert is used internally to create certificates for the plugin
    22  // client and server.
    23  func generateCert() ([]byte, *ecdsa.PrivateKey, error) {
    24  	key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
    25  	if err != nil {
    26  		return nil, nil, err
    27  	}
    28  
    29  	host, err := uuid.GenerateUUID()
    30  	if err != nil {
    31  		return nil, nil, err
    32  	}
    33  
    34  	sn, err := certutil.GenerateSerialNumber()
    35  	if err != nil {
    36  		return nil, nil, err
    37  	}
    38  
    39  	template := &x509.Certificate{
    40  		Subject: pkix.Name{
    41  			CommonName: host,
    42  		},
    43  		DNSNames: []string{host},
    44  		ExtKeyUsage: []x509.ExtKeyUsage{
    45  			x509.ExtKeyUsageClientAuth,
    46  			x509.ExtKeyUsageServerAuth,
    47  		},
    48  		KeyUsage:     x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement,
    49  		SerialNumber: sn,
    50  		NotBefore:    time.Now().Add(-30 * time.Second),
    51  		NotAfter:     time.Now().Add(262980 * time.Hour),
    52  		IsCA:         true,
    53  	}
    54  
    55  	certBytes, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key)
    56  	if err != nil {
    57  		return nil, nil, errwrap.Wrapf("unable to generate client certificate: {{err}}", err)
    58  	}
    59  
    60  	return certBytes, key, nil
    61  }
    62  
    63  // createClientTLSConfig creates a signed certificate and returns a configured
    64  // TLS config.
    65  func createClientTLSConfig(certBytes []byte, key *ecdsa.PrivateKey) (*tls.Config, error) {
    66  	clientCert, err := x509.ParseCertificate(certBytes)
    67  	if err != nil {
    68  		return nil, errwrap.Wrapf("error parsing generated plugin certificate: {{err}}", err)
    69  	}
    70  
    71  	cert := tls.Certificate{
    72  		Certificate: [][]byte{certBytes},
    73  		PrivateKey:  key,
    74  		Leaf:        clientCert,
    75  	}
    76  
    77  	clientCertPool := x509.NewCertPool()
    78  	clientCertPool.AddCert(clientCert)
    79  
    80  	tlsConfig := &tls.Config{
    81  		Certificates: []tls.Certificate{cert},
    82  		RootCAs:      clientCertPool,
    83  		ClientCAs:    clientCertPool,
    84  		ClientAuth:   tls.RequireAndVerifyClientCert,
    85  		ServerName:   clientCert.Subject.CommonName,
    86  		MinVersion:   tls.VersionTLS12,
    87  	}
    88  
    89  	return tlsConfig, nil
    90  }
    91  
    92  // wrapServerConfig is used to create a server certificate and private key, then
    93  // wrap them in an unwrap token for later retrieval by the plugin.
    94  func wrapServerConfig(ctx context.Context, sys RunnerUtil, certBytes []byte, key *ecdsa.PrivateKey) (string, error) {
    95  	rawKey, err := x509.MarshalECPrivateKey(key)
    96  	if err != nil {
    97  		return "", err
    98  	}
    99  
   100  	wrapInfo, err := sys.ResponseWrapData(ctx, map[string]interface{}{
   101  		"ServerCert": certBytes,
   102  		"ServerKey":  rawKey,
   103  	}, time.Second*60, true)
   104  	if err != nil {
   105  		return "", err
   106  	}
   107  
   108  	return wrapInfo.Token, nil
   109  }