...

Source file src/github.com/secure-systems-lab/go-securesystemslib/signerverifier/rsa.go

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

     1  package signerverifier
     2  
     3  import (
     4  	"context"
     5  	"crypto"
     6  	"crypto/rand"
     7  	"crypto/rsa"
     8  	"crypto/sha256"
     9  	"crypto/x509"
    10  	"fmt"
    11  	"os"
    12  	"strings"
    13  )
    14  
    15  const (
    16  	RSAKeyType       = "rsa"
    17  	RSAKeyScheme     = "rsassa-pss-sha256"
    18  	RSAPrivateKeyPEM = "RSA PRIVATE KEY"
    19  )
    20  
    21  // RSAPSSSignerVerifier is a dsse.SignerVerifier compliant interface to sign and
    22  // verify signatures using RSA keys following the RSA-PSS scheme.
    23  type RSAPSSSignerVerifier struct {
    24  	keyID   string
    25  	private *rsa.PrivateKey
    26  	public  *rsa.PublicKey
    27  }
    28  
    29  // NewRSAPSSSignerVerifierFromSSLibKey creates an RSAPSSSignerVerifier from an
    30  // SSLibKey.
    31  func NewRSAPSSSignerVerifierFromSSLibKey(key *SSLibKey) (*RSAPSSSignerVerifier, error) {
    32  	if len(key.KeyVal.Public) == 0 {
    33  		return nil, ErrInvalidKey
    34  	}
    35  
    36  	_, publicParsedKey, err := decodeAndParsePEM([]byte(key.KeyVal.Public))
    37  	if err != nil {
    38  		return nil, fmt.Errorf("unable to create RSA-PSS signerverifier: %w", err)
    39  	}
    40  
    41  	if len(key.KeyVal.Private) > 0 {
    42  		_, privateParsedKey, err := decodeAndParsePEM([]byte(key.KeyVal.Private))
    43  		if err != nil {
    44  			return nil, fmt.Errorf("unable to create RSA-PSS signerverifier: %w", err)
    45  		}
    46  
    47  		return &RSAPSSSignerVerifier{
    48  			keyID:   key.KeyID,
    49  			public:  publicParsedKey.(*rsa.PublicKey),
    50  			private: privateParsedKey.(*rsa.PrivateKey),
    51  		}, nil
    52  	}
    53  
    54  	return &RSAPSSSignerVerifier{
    55  		keyID:   key.KeyID,
    56  		public:  publicParsedKey.(*rsa.PublicKey),
    57  		private: nil,
    58  	}, nil
    59  }
    60  
    61  // Sign creates a signature for `data`.
    62  func (sv *RSAPSSSignerVerifier) Sign(ctx context.Context, data []byte) ([]byte, error) {
    63  	if sv.private == nil {
    64  		return nil, ErrNotPrivateKey
    65  	}
    66  
    67  	hashedData := hashBeforeSigning(data, sha256.New())
    68  
    69  	return rsa.SignPSS(rand.Reader, sv.private, crypto.SHA256, hashedData, &rsa.PSSOptions{SaltLength: sha256.Size, Hash: crypto.SHA256})
    70  }
    71  
    72  // Verify verifies the `sig` value passed in against `data`.
    73  func (sv *RSAPSSSignerVerifier) Verify(ctx context.Context, data []byte, sig []byte) error {
    74  	hashedData := hashBeforeSigning(data, sha256.New())
    75  
    76  	if err := rsa.VerifyPSS(sv.public, crypto.SHA256, hashedData, sig, &rsa.PSSOptions{SaltLength: sha256.Size, Hash: crypto.SHA256}); err != nil {
    77  		return ErrSignatureVerificationFailed
    78  	}
    79  
    80  	return nil
    81  }
    82  
    83  // KeyID returns the identifier of the key used to create the
    84  // RSAPSSSignerVerifier instance.
    85  func (sv *RSAPSSSignerVerifier) KeyID() (string, error) {
    86  	return sv.keyID, nil
    87  }
    88  
    89  // Public returns the public portion of the key used to create the
    90  // RSAPSSSignerVerifier instance.
    91  func (sv *RSAPSSSignerVerifier) Public() crypto.PublicKey {
    92  	return sv.public
    93  }
    94  
    95  // LoadRSAPSSKeyFromFile returns an SSLibKey instance for an RSA key stored in a
    96  // file.
    97  func LoadRSAPSSKeyFromFile(path string) (*SSLibKey, error) {
    98  	contents, err := os.ReadFile(path)
    99  	if err != nil {
   100  		return nil, fmt.Errorf("unable to load RSA key from file: %w", err)
   101  	}
   102  
   103  	return LoadRSAPSSKeyFromBytes(contents)
   104  }
   105  
   106  // LoadRSAPSSKeyFromBytes is a function that takes a byte array as input. This byte array should represent a PEM encoded RSA key, as PEM encoding is required.
   107  // The function returns an SSLibKey instance, which is a struct that holds the key data.
   108  
   109  func LoadRSAPSSKeyFromBytes(contents []byte) (*SSLibKey, error) {
   110  	pemData, keyObj, err := decodeAndParsePEM(contents)
   111  	if err != nil {
   112  		return nil, fmt.Errorf("unable to load RSA key from file: %w", err)
   113  	}
   114  
   115  	key := &SSLibKey{
   116  		KeyType:             RSAKeyType,
   117  		Scheme:              RSAKeyScheme,
   118  		KeyIDHashAlgorithms: KeyIDHashAlgorithms,
   119  		KeyVal:              KeyVal{},
   120  	}
   121  
   122  	pubKeyBytes, err := marshalAndGeneratePEM(keyObj)
   123  	if err != nil {
   124  		return nil, fmt.Errorf("unable to load RSA key from file: %w", err)
   125  	}
   126  	key.KeyVal.Public = strings.TrimSpace(string(pubKeyBytes))
   127  
   128  	if _, ok := keyObj.(*rsa.PrivateKey); ok {
   129  		key.KeyVal.Private = strings.TrimSpace(string(generatePEMBlock(pemData.Bytes, RSAPrivateKeyPEM)))
   130  	}
   131  
   132  	if len(key.KeyID) == 0 {
   133  		keyID, err := calculateKeyID(key)
   134  		if err != nil {
   135  			return nil, fmt.Errorf("unable to load RSA key from file: %w", err)
   136  		}
   137  		key.KeyID = keyID
   138  	}
   139  
   140  	return key, nil
   141  }
   142  
   143  func marshalAndGeneratePEM(key interface{}) ([]byte, error) {
   144  	var pubKeyBytes []byte
   145  	var err error
   146  
   147  	switch k := key.(type) {
   148  	case *rsa.PublicKey:
   149  		pubKeyBytes, err = x509.MarshalPKIXPublicKey(k)
   150  	case *rsa.PrivateKey:
   151  		pubKeyBytes, err = x509.MarshalPKIXPublicKey(k.Public())
   152  	default:
   153  		return nil, fmt.Errorf("unexpected key type: %T", k)
   154  	}
   155  
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  
   160  	return generatePEMBlock(pubKeyBytes, PublicKeyPEM), nil
   161  }
   162  

View as plain text