github.com/linuxboot/fiano@v1.2.0/pkg/amd/psb/signature.go (about)

     1  // Copyright 2023 the LinuxBoot Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package psb
     6  
     7  import (
     8  	"crypto"
     9  	"crypto/rsa"
    10  	"crypto/sha256"
    11  	"crypto/sha512"
    12  	"fmt"
    13  	"strings"
    14  )
    15  
    16  // SignedBlob represents an object whose signature is guaranteed to be validated
    17  type SignedBlob struct {
    18  	signature  *Signature
    19  	signedData []byte
    20  }
    21  
    22  // SignedData returns a buffer of signed data held by the SignedBlob object
    23  func (b *SignedBlob) SignedData() []byte {
    24  	return b.signedData
    25  }
    26  
    27  // Signature returns the signature of the blob
    28  func (b *SignedBlob) Signature() *Signature {
    29  	return b.signature
    30  }
    31  
    32  // NewSignedBlob creates a new signed blob object and validates its signature
    33  func NewSignedBlob(signature []byte, signedData []byte, signingKey *Key) (*SignedBlob, error) {
    34  	structuredKey, err := signingKey.Get()
    35  	if err != nil {
    36  		return nil, &SignatureCheckError{signingKey: signingKey, err: fmt.Errorf("could not get structured key data from key in signature object: %w", err)}
    37  	}
    38  
    39  	switch rsaKey := structuredKey.(type) {
    40  	case *rsa.PublicKey:
    41  		var (
    42  			hashAlg crypto.Hash
    43  			digest  []byte
    44  		)
    45  		switch size := rsaKey.Size(); size {
    46  		case sha512.Size * 8:
    47  			hashAlg = crypto.SHA384
    48  			hash := sha512.New384()
    49  			hash.Write(signedData)
    50  			digest = hash.Sum(nil)
    51  		case sha256.Size * 8:
    52  			hashAlg = crypto.SHA256
    53  			hash := sha256.New()
    54  			hash.Write(signedData)
    55  			digest = hash.Sum(nil)
    56  		default:
    57  			return nil, fmt.Errorf("signature validation for RSA key with size != 4096/2048 bit (%d) is not supported", size)
    58  		}
    59  
    60  		if err := rsa.VerifyPSS(rsaKey, hashAlg, digest, signature, nil); err != nil {
    61  			return nil, &SignatureCheckError{signingKey: signingKey, err: err}
    62  		}
    63  		signature := NewSignature(signature, signingKey)
    64  		return &SignedBlob{signedData: signedData, signature: &signature}, nil
    65  	}
    66  	return nil, fmt.Errorf("signature validation with key type != RSA is not supported")
    67  }
    68  
    69  // NewMultiKeySignedBlob validates the signature of a blob against multiple possible keys stored in a KeySet,
    70  // returning the key which validates the signature of the blob
    71  func NewMultiKeySignedBlob(signature []byte, signedData []byte, keySet KeySet) (*SignedBlob, *Key, error) {
    72  	allKeyIDs := keySet.AllKeyIDs()
    73  	for _, keyID := range allKeyIDs {
    74  		key := keySet.GetKey(keyID)
    75  		if key == nil {
    76  			return nil, nil, fmt.Errorf("KeySet is inconsistent, KeyID %s was returned but corresponding key is not present", keyID.Hex())
    77  		}
    78  
    79  		blob, err := NewSignedBlob(signature, signedData, key)
    80  		if err == nil {
    81  			return blob, key, nil
    82  		}
    83  	}
    84  
    85  	return nil, nil, fmt.Errorf("cannot validate signed blob with any of the %d keys available (%s)", len(allKeyIDs), allKeyIDs.String())
    86  }
    87  
    88  // Signature represents the raw signature bytes of a blob
    89  type Signature struct {
    90  	signature  []byte
    91  	signingKey *Key
    92  }
    93  
    94  // String returns a string representation of the signature
    95  func (s *Signature) String() string {
    96  	keyID := s.signingKey.data.KeyID
    97  	var str strings.Builder
    98  	fmt.Fprintf(&str, "KeyID: %s\n", keyID.Hex())
    99  	fmt.Fprintf(&str, "Signature: 0x%x\n", s.signature)
   100  	return str.String()
   101  }
   102  
   103  // SigningKey returns the signing key associated to the signature
   104  func (s *Signature) SigningKey() *Key {
   105  	return s.signingKey
   106  }
   107  
   108  // NewSignature creates a new signature object
   109  func NewSignature(signature []byte, signingKey *Key) Signature {
   110  	return Signature{signature: signature, signingKey: signingKey}
   111  }
   112  
   113  // SignatureValidationResult represents the result of a signature validate
   114  type SignatureValidationResult struct {
   115  	signingKey    *Key
   116  	signedElement string
   117  	err           error
   118  }
   119  
   120  // String returns a string representation of the signature validation result
   121  func (v *SignatureValidationResult) String() string {
   122  
   123  	var str strings.Builder
   124  	fmt.Fprintf(&str, "Signed element: %s\n", v.signedElement)
   125  	if v.signingKey != nil {
   126  		keyID := v.signingKey.data.KeyID
   127  		fmt.Fprintf(&str, "Signing key ID: 0x%s\n", keyID.Hex())
   128  	} else {
   129  		fmt.Fprintf(&str, "Signing key ID: UNKNOWN\n")
   130  	}
   131  	if v.err != nil {
   132  		fmt.Fprintf(&str, "Signature: FAIL (%s)\n", v.err.Error())
   133  	} else {
   134  		fmt.Fprintf(&str, "Signature: OK\n")
   135  	}
   136  	return str.String()
   137  }
   138  
   139  // SigningKey returns a key that was used to validate the signature
   140  func (v *SignatureValidationResult) SigningKey() *Key {
   141  	return v.signingKey
   142  }
   143  
   144  // Error returns a signature verification error if any
   145  func (v *SignatureValidationResult) Error() error {
   146  	return v.err
   147  }