...

Source file src/github.com/in-toto/in-toto-golang/internal/spiffe/spiffe.go

Documentation: github.com/in-toto/in-toto-golang/internal/spiffe

     1  package spiffe
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto"
     7  	"crypto/x509"
     8  	"encoding/pem"
     9  	"fmt"
    10  
    11  	intoto "github.com/in-toto/in-toto-golang/in_toto"
    12  	"github.com/spiffe/go-spiffe/v2/workloadapi"
    13  )
    14  
    15  /*
    16  SVIDDetails captures the Private Key, Root and Intermediate Certificate
    17  from the SVID provided by spire for the workload.
    18  */
    19  type SVIDDetails struct {
    20  	PrivateKey    crypto.Signer
    21  	Certificate   *x509.Certificate
    22  	Intermediates []*x509.Certificate
    23  }
    24  
    25  /*
    26  SVIDFetcher uses the context to connect to the spire and get the SVID associated with
    27  the workload.
    28  */
    29  type SVIDFetcher interface {
    30  	FetchX509Context(ctx context.Context) (*workloadapi.X509Context, error)
    31  	Close() error
    32  }
    33  
    34  /*
    35  NewClient takes the context and the provided spire agent socket path in order to initialize
    36  the workload API.
    37  */
    38  func NewClient(ctx context.Context, socketPath string) (SVIDFetcher, error) {
    39  	return workloadapi.New(ctx, workloadapi.WithAddr(socketPath))
    40  }
    41  
    42  /*
    43  GetSVID attempts to request an SVID from the provided SPIRE Workload API socket.
    44  If attestation succeeds and an SVID is acquired the resulting X509 key &
    45  certificate pair will be returned as well as any intermediate certificates
    46  needed to establish trust to trust domain's root.
    47  */
    48  func GetSVID(ctx context.Context, client SVIDFetcher) (SVIDDetails, error) {
    49  	s := SVIDDetails{}
    50  	svidContext, err := client.FetchX509Context(ctx)
    51  	if err != nil {
    52  		return s, fmt.Errorf("error fetching spiffe x.509 context: %w", err)
    53  	}
    54  
    55  	svid := svidContext.DefaultSVID()
    56  	if len(svid.Certificates) <= 0 {
    57  		return s, fmt.Errorf("no certificates in svid")
    58  	}
    59  
    60  	if svid.PrivateKey == nil {
    61  		return s, fmt.Errorf("svid has no key")
    62  	}
    63  
    64  	s.PrivateKey = svid.PrivateKey
    65  	s.Certificate = svid.Certificates[0]
    66  	s.Intermediates = svid.Certificates[1:]
    67  	return s, nil
    68  }
    69  
    70  /*
    71  InTotoKey uses the private key and certificate obtained from Spire to initialize
    72  intoto.key to be used for signing.
    73  */
    74  func (s SVIDDetails) InTotoKey() (intoto.Key, error) {
    75  	key := intoto.Key{}
    76  	keyBytes, err := x509.MarshalPKCS8PrivateKey(s.PrivateKey)
    77  	if err != nil {
    78  		return key, fmt.Errorf("failed to marshal svid key: %w", err)
    79  	}
    80  
    81  	keyPemBytes := pem.EncodeToMemory(&pem.Block{
    82  		Type:  "PRIVATE KEY",
    83  		Bytes: keyBytes,
    84  	})
    85  
    86  	err = key.LoadKeyReaderDefaults(bytes.NewReader(keyPemBytes))
    87  	if err != nil {
    88  		return key, fmt.Errorf("failed to load key from spire: %w", err)
    89  	}
    90  
    91  	key.KeyVal.Certificate = string(pem.EncodeToMemory(&pem.Block{Bytes: s.Certificate.Raw, Type: "CERTIFICATE"}))
    92  	return key, nil
    93  }
    94  

View as plain text