...

Source file src/github.com/secure-systems-lab/go-securesystemslib/dsse/verify.go

Documentation: github.com/secure-systems-lab/go-securesystemslib/dsse

     1  package dsse
     2  
     3  import (
     4  	"context"
     5  	"crypto"
     6  	"errors"
     7  	"fmt"
     8  
     9  	"golang.org/x/crypto/ssh"
    10  )
    11  
    12  // ErrNoSignature indicates that an envelope did not contain any signatures.
    13  var ErrNoSignature = errors.New("no signature found")
    14  
    15  type EnvelopeVerifier struct {
    16  	providers []Verifier
    17  	threshold int
    18  }
    19  
    20  type AcceptedKey struct {
    21  	Public crypto.PublicKey
    22  	KeyID  string
    23  	Sig    Signature
    24  }
    25  
    26  func (ev *EnvelopeVerifier) Verify(ctx context.Context, e *Envelope) ([]AcceptedKey, error) {
    27  	if e == nil {
    28  		return nil, errors.New("cannot verify a nil envelope")
    29  	}
    30  
    31  	if len(e.Signatures) == 0 {
    32  		return nil, ErrNoSignature
    33  	}
    34  
    35  	// Decode payload (i.e serialized body)
    36  	body, err := e.DecodeB64Payload()
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  	// Generate PAE(payloadtype, serialized body)
    41  	paeEnc := PAE(e.PayloadType, body)
    42  
    43  	// If *any* signature is found to be incorrect, it is skipped
    44  	var acceptedKeys []AcceptedKey
    45  	usedKeyids := make(map[string]string)
    46  	unverified_providers := ev.providers
    47  	for _, s := range e.Signatures {
    48  		sig, err := b64Decode(s.Sig)
    49  		if err != nil {
    50  			return nil, err
    51  		}
    52  
    53  		// Loop over the providers.
    54  		// If provider and signature include key IDs but do not match skip.
    55  		// If a provider recognizes the key, we exit
    56  		// the loop and use the result.
    57  		providers := unverified_providers
    58  		for i, v := range providers {
    59  			keyID, err := v.KeyID()
    60  
    61  			// Verifiers that do not provide a keyid will be generated one using public.
    62  			if err != nil || keyID == "" {
    63  				keyID, err = SHA256KeyID(v.Public())
    64  				if err != nil {
    65  					keyID = ""
    66  				}
    67  			}
    68  
    69  			if s.KeyID != "" && keyID != "" && err == nil && s.KeyID != keyID {
    70  				continue
    71  			}
    72  
    73  			err = v.Verify(ctx, paeEnc, sig)
    74  			if err != nil {
    75  				continue
    76  			}
    77  
    78  			acceptedKey := AcceptedKey{
    79  				Public: v.Public(),
    80  				KeyID:  keyID,
    81  				Sig:    s,
    82  			}
    83  			unverified_providers = removeIndex(providers, i)
    84  
    85  			// See https://github.com/in-toto/in-toto/pull/251
    86  			if _, ok := usedKeyids[keyID]; ok {
    87  				fmt.Printf("Found envelope signed by different subkeys of the same main key, Only one of them is counted towards the step threshold, KeyID=%s\n", keyID)
    88  				continue
    89  			}
    90  
    91  			usedKeyids[keyID] = ""
    92  			acceptedKeys = append(acceptedKeys, acceptedKey)
    93  			break
    94  		}
    95  	}
    96  
    97  	// Sanity if with some reflect magic this happens.
    98  	if ev.threshold <= 0 || ev.threshold > len(ev.providers) {
    99  		return nil, errors.New("invalid threshold")
   100  	}
   101  
   102  	if len(usedKeyids) < ev.threshold {
   103  		return acceptedKeys, fmt.Errorf("accepted signatures do not match threshold, Found: %d, Expected %d", len(acceptedKeys), ev.threshold)
   104  	}
   105  
   106  	return acceptedKeys, nil
   107  }
   108  
   109  func NewEnvelopeVerifier(v ...Verifier) (*EnvelopeVerifier, error) {
   110  	return NewMultiEnvelopeVerifier(1, v...)
   111  }
   112  
   113  func NewMultiEnvelopeVerifier(threshold int, p ...Verifier) (*EnvelopeVerifier, error) {
   114  	if threshold <= 0 || threshold > len(p) {
   115  		return nil, errors.New("invalid threshold")
   116  	}
   117  
   118  	ev := EnvelopeVerifier{
   119  		providers: p,
   120  		threshold: threshold,
   121  	}
   122  
   123  	return &ev, nil
   124  }
   125  
   126  func SHA256KeyID(pub crypto.PublicKey) (string, error) {
   127  	// Generate public key fingerprint
   128  	sshpk, err := ssh.NewPublicKey(pub)
   129  	if err != nil {
   130  		return "", err
   131  	}
   132  	fingerprint := ssh.FingerprintSHA256(sshpk)
   133  	return fingerprint, nil
   134  }
   135  
   136  func removeIndex(v []Verifier, index int) []Verifier {
   137  	return append(v[:index], v[index+1:]...)
   138  }
   139  

View as plain text