...

Source file src/github.com/in-toto/in-toto-golang/in_toto/keylib.go

Documentation: github.com/in-toto/in-toto-golang/in_toto

     1  package in_toto
     2  
     3  import (
     4  	"crypto"
     5  	"crypto/ecdsa"
     6  	"crypto/ed25519"
     7  	"crypto/rand"
     8  	"crypto/rsa"
     9  	"crypto/sha256"
    10  	"crypto/x509"
    11  	"encoding/hex"
    12  	"encoding/pem"
    13  	"errors"
    14  	"fmt"
    15  	"io"
    16  	"os"
    17  	"strings"
    18  
    19  	"github.com/secure-systems-lab/go-securesystemslib/cjson"
    20  )
    21  
    22  // ErrFailedPEMParsing gets returned when PKCS1, PKCS8 or PKIX key parsing fails
    23  var ErrFailedPEMParsing = errors.New("failed parsing the PEM block: unsupported PEM type")
    24  
    25  // ErrNoPEMBlock gets triggered when there is no PEM block in the provided file
    26  var ErrNoPEMBlock = errors.New("failed to decode the data as PEM block (are you sure this is a pem file?)")
    27  
    28  // ErrUnsupportedKeyType is returned when we are dealing with a key type different to ed25519 or RSA
    29  var ErrUnsupportedKeyType = errors.New("unsupported key type")
    30  
    31  // ErrInvalidSignature is returned when the signature is invalid
    32  var ErrInvalidSignature = errors.New("invalid signature")
    33  
    34  // ErrInvalidKey is returned when a given key is none of RSA, ECDSA or ED25519
    35  var ErrInvalidKey = errors.New("invalid key")
    36  
    37  const (
    38  	rsaKeyType            string = "rsa"
    39  	ecdsaKeyType          string = "ecdsa"
    40  	ed25519KeyType        string = "ed25519"
    41  	rsassapsssha256Scheme string = "rsassa-pss-sha256"
    42  	ecdsaSha2nistp224     string = "ecdsa-sha2-nistp224"
    43  	ecdsaSha2nistp256     string = "ecdsa-sha2-nistp256"
    44  	ecdsaSha2nistp384     string = "ecdsa-sha2-nistp384"
    45  	ecdsaSha2nistp521     string = "ecdsa-sha2-nistp521"
    46  	ed25519Scheme         string = "ed25519"
    47  	pemPublicKey          string = "PUBLIC KEY"
    48  	pemPrivateKey         string = "PRIVATE KEY"
    49  	pemRSAPrivateKey      string = "RSA PRIVATE KEY"
    50  )
    51  
    52  /*
    53  getSupportedKeyIDHashAlgorithms returns a string slice of supported
    54  KeyIDHashAlgorithms. We need to use this function instead of a constant,
    55  because Go does not support global constant slices.
    56  */
    57  func getSupportedKeyIDHashAlgorithms() Set {
    58  	return NewSet("sha256", "sha512")
    59  }
    60  
    61  /*
    62  getSupportedRSASchemes returns a string slice of supported RSA Key schemes.
    63  We need to use this function instead of a constant because Go does not support
    64  global constant slices.
    65  */
    66  func getSupportedRSASchemes() []string {
    67  	return []string{rsassapsssha256Scheme}
    68  }
    69  
    70  /*
    71  getSupportedEcdsaSchemes returns a string slice of supported ecdsa Key schemes.
    72  We need to use this function instead of a constant because Go does not support
    73  global constant slices.
    74  */
    75  func getSupportedEcdsaSchemes() []string {
    76  	return []string{ecdsaSha2nistp224, ecdsaSha2nistp256, ecdsaSha2nistp384, ecdsaSha2nistp521}
    77  }
    78  
    79  /*
    80  getSupportedEd25519Schemes returns a string slice of supported ed25519 Key
    81  schemes. We need to use this function instead of a constant because Go does
    82  not support global constant slices.
    83  */
    84  func getSupportedEd25519Schemes() []string {
    85  	return []string{ed25519Scheme}
    86  }
    87  
    88  /*
    89  generateKeyID creates a partial key map and generates the key ID
    90  based on the created partial key map via the SHA256 method.
    91  The resulting keyID will be directly saved in the corresponding key object.
    92  On success generateKeyID will return nil, in case of errors while encoding
    93  there will be an error.
    94  */
    95  func (k *Key) generateKeyID() error {
    96  	// Create partial key map used to create the keyid
    97  	// Unfortunately, we can't use the Key object because this also carries
    98  	// yet unwanted fields, such as KeyID and KeyVal.Private and therefore
    99  	// produces a different hash. We generate the keyID exactly as we do in
   100  	// the securesystemslib  to keep interoperability between other in-toto
   101  	// implementations.
   102  	var keyToBeHashed = map[string]interface{}{
   103  		"keytype":               k.KeyType,
   104  		"scheme":                k.Scheme,
   105  		"keyid_hash_algorithms": k.KeyIDHashAlgorithms,
   106  		"keyval": map[string]string{
   107  			"public": k.KeyVal.Public,
   108  		},
   109  	}
   110  	keyCanonical, err := cjson.EncodeCanonical(keyToBeHashed)
   111  	if err != nil {
   112  		return err
   113  	}
   114  	// calculate sha256 and return string representation of keyID
   115  	keyHashed := sha256.Sum256(keyCanonical)
   116  	k.KeyID = fmt.Sprintf("%x", keyHashed)
   117  	err = validateKey(*k)
   118  	if err != nil {
   119  		return err
   120  	}
   121  	return nil
   122  }
   123  
   124  /*
   125  generatePEMBlock creates a PEM block from scratch via the keyBytes and the pemType.
   126  If successful it returns a PEM block as []byte slice. This function should always
   127  succeed, if keyBytes is empty the PEM block will have an empty byte block.
   128  Therefore only header and footer will exist.
   129  */
   130  func generatePEMBlock(keyBytes []byte, pemType string) []byte {
   131  	// construct PEM block
   132  	pemBlock := &pem.Block{
   133  		Type:    pemType,
   134  		Headers: nil,
   135  		Bytes:   keyBytes,
   136  	}
   137  	return pem.EncodeToMemory(pemBlock)
   138  }
   139  
   140  /*
   141  setKeyComponents sets all components in our key object.
   142  Furthermore it makes sure to remove any trailing and leading whitespaces or newlines.
   143  We treat key types differently for interoperability reasons to the in-toto python
   144  implementation and the securesystemslib.
   145  */
   146  func (k *Key) setKeyComponents(pubKeyBytes []byte, privateKeyBytes []byte, keyType string, scheme string, KeyIDHashAlgorithms []string) error {
   147  	// assume we have a privateKey if the key size is bigger than 0
   148  
   149  	switch keyType {
   150  	case rsaKeyType:
   151  		if len(privateKeyBytes) > 0 {
   152  			k.KeyVal = KeyVal{
   153  				Private: strings.TrimSpace(string(generatePEMBlock(privateKeyBytes, pemRSAPrivateKey))),
   154  				Public:  strings.TrimSpace(string(generatePEMBlock(pubKeyBytes, pemPublicKey))),
   155  			}
   156  		} else {
   157  			k.KeyVal = KeyVal{
   158  				Public: strings.TrimSpace(string(generatePEMBlock(pubKeyBytes, pemPublicKey))),
   159  			}
   160  		}
   161  	case ecdsaKeyType:
   162  		if len(privateKeyBytes) > 0 {
   163  			k.KeyVal = KeyVal{
   164  				Private: strings.TrimSpace(string(generatePEMBlock(privateKeyBytes, pemPrivateKey))),
   165  				Public:  strings.TrimSpace(string(generatePEMBlock(pubKeyBytes, pemPublicKey))),
   166  			}
   167  		} else {
   168  			k.KeyVal = KeyVal{
   169  				Public: strings.TrimSpace(string(generatePEMBlock(pubKeyBytes, pemPublicKey))),
   170  			}
   171  		}
   172  	case ed25519KeyType:
   173  		if len(privateKeyBytes) > 0 {
   174  			k.KeyVal = KeyVal{
   175  				Private: strings.TrimSpace(hex.EncodeToString(privateKeyBytes)),
   176  				Public:  strings.TrimSpace(hex.EncodeToString(pubKeyBytes)),
   177  			}
   178  		} else {
   179  			k.KeyVal = KeyVal{
   180  				Public: strings.TrimSpace(hex.EncodeToString(pubKeyBytes)),
   181  			}
   182  		}
   183  	default:
   184  		return fmt.Errorf("%w: %s", ErrUnsupportedKeyType, keyType)
   185  	}
   186  	k.KeyType = keyType
   187  	k.Scheme = scheme
   188  	k.KeyIDHashAlgorithms = KeyIDHashAlgorithms
   189  	if err := k.generateKeyID(); err != nil {
   190  		return err
   191  	}
   192  	return nil
   193  }
   194  
   195  /*
   196  parseKey tries to parse a PEM []byte slice. Using the following standards
   197  in the given order:
   198  
   199    - PKCS8
   200    - PKCS1
   201    - PKIX
   202  
   203  On success it returns the parsed key and nil.
   204  On failure it returns nil and the error ErrFailedPEMParsing
   205  */
   206  func parseKey(data []byte) (interface{}, error) {
   207  	key, err := x509.ParsePKCS8PrivateKey(data)
   208  	if err == nil {
   209  		return key, nil
   210  	}
   211  	key, err = x509.ParsePKCS1PrivateKey(data)
   212  	if err == nil {
   213  		return key, nil
   214  	}
   215  	key, err = x509.ParsePKIXPublicKey(data)
   216  	if err == nil {
   217  		return key, nil
   218  	}
   219  	key, err = x509.ParseCertificate(data)
   220  	if err == nil {
   221  		return key, nil
   222  	}
   223  	key, err = x509.ParseECPrivateKey(data)
   224  	if err == nil {
   225  		return key, nil
   226  	}
   227  	return nil, ErrFailedPEMParsing
   228  }
   229  
   230  /*
   231  decodeAndParse receives potential PEM bytes decodes them via pem.Decode
   232  and pushes them to parseKey. If any error occurs during this process,
   233  the function will return nil and an error (either ErrFailedPEMParsing
   234  or ErrNoPEMBlock). On success it will return the decoded pemData, the
   235  key object interface and nil as error. We need the decoded pemData,
   236  because LoadKey relies on decoded pemData for operating system
   237  interoperability.
   238  */
   239  func decodeAndParse(pemBytes []byte) (*pem.Block, interface{}, error) {
   240  	// pem.Decode returns the parsed pem block and a rest.
   241  	// The rest is everything, that could not be parsed as PEM block.
   242  	// Therefore we can drop this via using the blank identifier "_"
   243  	data, _ := pem.Decode(pemBytes)
   244  	if data == nil {
   245  		return nil, nil, ErrNoPEMBlock
   246  	}
   247  
   248  	// Try to load private key, if this fails try to load
   249  	// key as public key
   250  	key, err := parseKey(data.Bytes)
   251  	if err != nil {
   252  		return nil, nil, err
   253  	}
   254  	return data, key, nil
   255  }
   256  
   257  /*
   258  LoadKey loads the key file at specified file path into the key object.
   259  It automatically derives the PEM type and the key type.
   260  Right now the following PEM types are supported:
   261  
   262    - PKCS1 for private keys
   263    - PKCS8	for private keys
   264    - PKIX for public keys
   265  
   266  The following key types are supported and will be automatically assigned to
   267  the key type field:
   268  
   269    - ed25519
   270    - rsa
   271    - ecdsa
   272  
   273  The following schemes are supported:
   274  
   275    - ed25519 -> ed25519
   276    - rsa -> rsassa-pss-sha256
   277    - ecdsa -> ecdsa-sha256-nistp256
   278  
   279  Note that, this behavior is consistent with the securesystemslib, except for
   280  ecdsa. We do not use the scheme string as key type in in-toto-golang.
   281  Instead we are going with a ecdsa/ecdsa-sha2-nistp256 pair.
   282  
   283  On success it will return nil. The following errors can happen:
   284  
   285    - path not found or not readable
   286    - no PEM block in the loaded file
   287    - no valid PKCS8/PKCS1 private key or PKIX public key
   288    - errors while marshalling
   289    - unsupported key types
   290  */
   291  func (k *Key) LoadKey(path string, scheme string, KeyIDHashAlgorithms []string) error {
   292  	pemFile, err := os.Open(path)
   293  	if err != nil {
   294  		return err
   295  	}
   296  	defer pemFile.Close()
   297  
   298  	err = k.LoadKeyReader(pemFile, scheme, KeyIDHashAlgorithms)
   299  	if err != nil {
   300  		return err
   301  	}
   302  
   303  	return pemFile.Close()
   304  }
   305  
   306  func (k *Key) LoadKeyDefaults(path string) error {
   307  	pemFile, err := os.Open(path)
   308  	if err != nil {
   309  		return err
   310  	}
   311  	defer pemFile.Close()
   312  
   313  	err = k.LoadKeyReaderDefaults(pemFile)
   314  	if err != nil {
   315  		return err
   316  	}
   317  
   318  	return pemFile.Close()
   319  }
   320  
   321  // LoadKeyReader loads the key from a supplied reader. The logic matches LoadKey otherwise.
   322  func (k *Key) LoadKeyReader(r io.Reader, scheme string, KeyIDHashAlgorithms []string) error {
   323  	if r == nil {
   324  		return ErrNoPEMBlock
   325  	}
   326  	// Read key bytes
   327  	pemBytes, err := io.ReadAll(r)
   328  	if err != nil {
   329  		return err
   330  	}
   331  	// decodeAndParse returns the pemData for later use
   332  	// and a parsed key object (for operations on that key, like extracting the public Key)
   333  	pemData, key, err := decodeAndParse(pemBytes)
   334  	if err != nil {
   335  		return err
   336  	}
   337  
   338  	return k.loadKey(key, pemData, scheme, KeyIDHashAlgorithms)
   339  }
   340  
   341  func (k *Key) LoadKeyReaderDefaults(r io.Reader) error {
   342  	if r == nil {
   343  		return ErrNoPEMBlock
   344  	}
   345  	// Read key bytes
   346  	pemBytes, err := io.ReadAll(r)
   347  	if err != nil {
   348  		return err
   349  	}
   350  	// decodeAndParse returns the pemData for later use
   351  	// and a parsed key object (for operations on that key, like extracting the public Key)
   352  	pemData, key, err := decodeAndParse(pemBytes)
   353  	if err != nil {
   354  		return err
   355  	}
   356  
   357  	scheme, keyIDHashAlgorithms, err := getDefaultKeyScheme(key)
   358  	if err != nil {
   359  		return err
   360  	}
   361  
   362  	return k.loadKey(key, pemData, scheme, keyIDHashAlgorithms)
   363  }
   364  
   365  func getDefaultKeyScheme(key interface{}) (scheme string, keyIDHashAlgorithms []string, err error) {
   366  	keyIDHashAlgorithms = []string{"sha256", "sha512"}
   367  
   368  	switch k := key.(type) {
   369  	case *rsa.PublicKey, *rsa.PrivateKey:
   370  		scheme = rsassapsssha256Scheme
   371  	case ed25519.PrivateKey, ed25519.PublicKey:
   372  		scheme = ed25519Scheme
   373  	case *ecdsa.PrivateKey, *ecdsa.PublicKey:
   374  		scheme = ecdsaSha2nistp256
   375  	case *x509.Certificate:
   376  		return getDefaultKeyScheme(k.PublicKey)
   377  	default:
   378  		err = ErrUnsupportedKeyType
   379  	}
   380  
   381  	return scheme, keyIDHashAlgorithms, err
   382  }
   383  
   384  func (k *Key) loadKey(keyObj interface{}, pemData *pem.Block, scheme string, keyIDHashAlgorithms []string) error {
   385  	switch key := keyObj.(type) {
   386  	case *rsa.PublicKey:
   387  		pubKeyBytes, err := x509.MarshalPKIXPublicKey(key)
   388  		if err != nil {
   389  			return err
   390  		}
   391  		if err := k.setKeyComponents(pubKeyBytes, []byte{}, rsaKeyType, scheme, keyIDHashAlgorithms); err != nil {
   392  			return err
   393  		}
   394  	case *rsa.PrivateKey:
   395  		// Note: RSA Public Keys will get stored as X.509 SubjectPublicKeyInfo (RFC5280)
   396  		// This behavior is consistent to the securesystemslib
   397  		pubKeyBytes, err := x509.MarshalPKIXPublicKey(key.Public())
   398  		if err != nil {
   399  			return err
   400  		}
   401  		if err := k.setKeyComponents(pubKeyBytes, pemData.Bytes, rsaKeyType, scheme, keyIDHashAlgorithms); err != nil {
   402  			return err
   403  		}
   404  	case ed25519.PublicKey:
   405  		if err := k.setKeyComponents(key, []byte{}, ed25519KeyType, scheme, keyIDHashAlgorithms); err != nil {
   406  			return err
   407  		}
   408  	case ed25519.PrivateKey:
   409  		pubKeyBytes := key.Public()
   410  		if err := k.setKeyComponents(pubKeyBytes.(ed25519.PublicKey), key, ed25519KeyType, scheme, keyIDHashAlgorithms); err != nil {
   411  			return err
   412  		}
   413  	case *ecdsa.PrivateKey:
   414  		pubKeyBytes, err := x509.MarshalPKIXPublicKey(key.Public())
   415  		if err != nil {
   416  			return err
   417  		}
   418  		if err := k.setKeyComponents(pubKeyBytes, pemData.Bytes, ecdsaKeyType, scheme, keyIDHashAlgorithms); err != nil {
   419  			return err
   420  		}
   421  	case *ecdsa.PublicKey:
   422  		pubKeyBytes, err := x509.MarshalPKIXPublicKey(key)
   423  		if err != nil {
   424  			return err
   425  		}
   426  		if err := k.setKeyComponents(pubKeyBytes, []byte{}, ecdsaKeyType, scheme, keyIDHashAlgorithms); err != nil {
   427  			return err
   428  		}
   429  	case *x509.Certificate:
   430  		err := k.loadKey(key.PublicKey, pemData, scheme, keyIDHashAlgorithms)
   431  		if err != nil {
   432  			return err
   433  		}
   434  
   435  		k.KeyVal.Certificate = string(pem.EncodeToMemory(pemData))
   436  
   437  	default:
   438  		// We should never get here, because we implement all from Go supported Key Types
   439  		return errors.New("unexpected Error in LoadKey function")
   440  	}
   441  
   442  	return nil
   443  }
   444  
   445  /*
   446  GenerateSignature will automatically detect the key type and sign the signable data
   447  with the provided key. If everything goes right GenerateSignature will return
   448  a for the key valid signature and err=nil. If something goes wrong it will
   449  return a not initialized signature and an error. Possible errors are:
   450  
   451    - ErrNoPEMBlock
   452    - ErrUnsupportedKeyType
   453  
   454  Currently supported is only one scheme per key.
   455  
   456  Note that in-toto-golang has different requirements to an ecdsa key.
   457  In in-toto-golang we use the string 'ecdsa' as string for the key type.
   458  In the key scheme we use: ecdsa-sha2-nistp256.
   459  */
   460  func GenerateSignature(signable []byte, key Key) (Signature, error) {
   461  	err := validateKey(key)
   462  	if err != nil {
   463  		return Signature{}, err
   464  	}
   465  	var signature Signature
   466  	var signatureBuffer []byte
   467  	hashMapping := getHashMapping()
   468  	// The following switch block is needed for keeping interoperability
   469  	// with the securesystemslib and the python implementation
   470  	// in which we are storing RSA keys in PEM format, but ed25519 keys hex encoded.
   471  	switch key.KeyType {
   472  	case rsaKeyType:
   473  		// We do not need the pemData here, so we can throw it away via '_'
   474  		_, parsedKey, err := decodeAndParse([]byte(key.KeyVal.Private))
   475  		if err != nil {
   476  			return Signature{}, err
   477  		}
   478  		parsedKey, ok := parsedKey.(*rsa.PrivateKey)
   479  		if !ok {
   480  			return Signature{}, ErrKeyKeyTypeMismatch
   481  		}
   482  		switch key.Scheme {
   483  		case rsassapsssha256Scheme:
   484  			hashed := hashToHex(hashMapping["sha256"](), signable)
   485  			// We use rand.Reader as secure random source for rsa.SignPSS()
   486  			signatureBuffer, err = rsa.SignPSS(rand.Reader, parsedKey.(*rsa.PrivateKey), crypto.SHA256, hashed,
   487  				&rsa.PSSOptions{SaltLength: sha256.Size, Hash: crypto.SHA256})
   488  			if err != nil {
   489  				return signature, err
   490  			}
   491  		default:
   492  			// supported key schemes will get checked in validateKey
   493  			panic("unexpected Error in GenerateSignature function")
   494  		}
   495  	case ecdsaKeyType:
   496  		// We do not need the pemData here, so we can throw it away via '_'
   497  		_, parsedKey, err := decodeAndParse([]byte(key.KeyVal.Private))
   498  		if err != nil {
   499  			return Signature{}, err
   500  		}
   501  		parsedKey, ok := parsedKey.(*ecdsa.PrivateKey)
   502  		if !ok {
   503  			return Signature{}, ErrKeyKeyTypeMismatch
   504  		}
   505  		curveSize := parsedKey.(*ecdsa.PrivateKey).Curve.Params().BitSize
   506  		var hashed []byte
   507  		if err := matchEcdsaScheme(curveSize, key.Scheme); err != nil {
   508  			return Signature{}, ErrCurveSizeSchemeMismatch
   509  		}
   510  		// implement https://tools.ietf.org/html/rfc5656#section-6.2.1
   511  		// We determine the curve size and choose the correct hashing
   512  		// method based on the curveSize
   513  		switch {
   514  		case curveSize <= 256:
   515  			hashed = hashToHex(hashMapping["sha256"](), signable)
   516  		case 256 < curveSize && curveSize <= 384:
   517  			hashed = hashToHex(hashMapping["sha384"](), signable)
   518  		case curveSize > 384:
   519  			hashed = hashToHex(hashMapping["sha512"](), signable)
   520  		default:
   521  			panic("unexpected Error in GenerateSignature function")
   522  		}
   523  		// Generate the ecdsa signature on the same way, as we do in the securesystemslib
   524  		// We are marshalling the ecdsaSignature struct as ASN.1 INTEGER SEQUENCES
   525  		// into an ASN.1 Object.
   526  		signatureBuffer, err = ecdsa.SignASN1(rand.Reader, parsedKey.(*ecdsa.PrivateKey), hashed[:])
   527  		if err != nil {
   528  			return signature, err
   529  		}
   530  	case ed25519KeyType:
   531  		// We do not need a scheme switch here, because ed25519
   532  		// only consist of sha256 and curve25519.
   533  		privateHex, err := hex.DecodeString(key.KeyVal.Private)
   534  		if err != nil {
   535  			return signature, ErrInvalidHexString
   536  		}
   537  		// Note: We can directly use the key for signing and do not
   538  		// need to use ed25519.NewKeyFromSeed().
   539  		signatureBuffer = ed25519.Sign(privateHex, signable)
   540  	default:
   541  		// We should never get here, because we call validateKey in the first
   542  		// line of the function.
   543  		panic("unexpected Error in GenerateSignature function")
   544  	}
   545  	signature.Sig = hex.EncodeToString(signatureBuffer)
   546  	signature.KeyID = key.KeyID
   547  	signature.Certificate = key.KeyVal.Certificate
   548  	return signature, nil
   549  }
   550  
   551  /*
   552  VerifySignature will verify unverified byte data via a passed key and signature.
   553  Supported key types are:
   554  
   555    - rsa
   556    - ed25519
   557    - ecdsa
   558  
   559  When encountering an RSA key, VerifySignature will decode the PEM block in the key
   560  and will call rsa.VerifyPSS() for verifying the RSA signature.
   561  When encountering an ed25519 key, VerifySignature will decode the hex string encoded
   562  public key and will use ed25519.Verify() for verifying the ed25519 signature.
   563  When the given key is an ecdsa key, VerifySignature will unmarshall the ASN1 object
   564  and will use the retrieved ecdsa components 'r' and 's' for verifying the signature.
   565  On success it will return nil. In case of an unsupported key type or any other error
   566  it will return an error.
   567  
   568  Note that in-toto-golang has different requirements to an ecdsa key.
   569  In in-toto-golang we use the string 'ecdsa' as string for the key type.
   570  In the key scheme we use: ecdsa-sha2-nistp256.
   571  */
   572  func VerifySignature(key Key, sig Signature, unverified []byte) error {
   573  	err := validateKey(key)
   574  	if err != nil {
   575  		return err
   576  	}
   577  	sigBytes, err := hex.DecodeString(sig.Sig)
   578  	if err != nil {
   579  		return err
   580  	}
   581  	hashMapping := getHashMapping()
   582  	switch key.KeyType {
   583  	case rsaKeyType:
   584  		// We do not need the pemData here, so we can throw it away via '_'
   585  		_, parsedKey, err := decodeAndParse([]byte(key.KeyVal.Public))
   586  		if err != nil {
   587  			return err
   588  		}
   589  		parsedKey, ok := parsedKey.(*rsa.PublicKey)
   590  		if !ok {
   591  			return ErrKeyKeyTypeMismatch
   592  		}
   593  		switch key.Scheme {
   594  		case rsassapsssha256Scheme:
   595  			hashed := hashToHex(hashMapping["sha256"](), unverified)
   596  			err = rsa.VerifyPSS(parsedKey.(*rsa.PublicKey), crypto.SHA256, hashed, sigBytes, &rsa.PSSOptions{SaltLength: sha256.Size, Hash: crypto.SHA256})
   597  			if err != nil {
   598  				return fmt.Errorf("%w: %s", ErrInvalidSignature, err)
   599  			}
   600  		default:
   601  			// supported key schemes will get checked in validateKey
   602  			panic("unexpected Error in VerifySignature function")
   603  		}
   604  	case ecdsaKeyType:
   605  		// We do not need the pemData here, so we can throw it away via '_'
   606  		_, parsedKey, err := decodeAndParse([]byte(key.KeyVal.Public))
   607  		if err != nil {
   608  			return err
   609  		}
   610  		parsedKey, ok := parsedKey.(*ecdsa.PublicKey)
   611  		if !ok {
   612  			return ErrKeyKeyTypeMismatch
   613  		}
   614  		curveSize := parsedKey.(*ecdsa.PublicKey).Curve.Params().BitSize
   615  		var hashed []byte
   616  		if err := matchEcdsaScheme(curveSize, key.Scheme); err != nil {
   617  			return ErrCurveSizeSchemeMismatch
   618  		}
   619  		// implement https://tools.ietf.org/html/rfc5656#section-6.2.1
   620  		// We determine the curve size and choose the correct hashing
   621  		// method based on the curveSize
   622  		switch {
   623  		case curveSize <= 256:
   624  			hashed = hashToHex(hashMapping["sha256"](), unverified)
   625  		case 256 < curveSize && curveSize <= 384:
   626  			hashed = hashToHex(hashMapping["sha384"](), unverified)
   627  		case curveSize > 384:
   628  			hashed = hashToHex(hashMapping["sha512"](), unverified)
   629  		default:
   630  			panic("unexpected Error in VerifySignature function")
   631  		}
   632  		if ok := ecdsa.VerifyASN1(parsedKey.(*ecdsa.PublicKey), hashed[:], sigBytes); !ok {
   633  			return ErrInvalidSignature
   634  		}
   635  	case ed25519KeyType:
   636  		// We do not need a scheme switch here, because ed25519
   637  		// only consist of sha256 and curve25519.
   638  		pubHex, err := hex.DecodeString(key.KeyVal.Public)
   639  		if err != nil {
   640  			return ErrInvalidHexString
   641  		}
   642  		if ok := ed25519.Verify(pubHex, unverified, sigBytes); !ok {
   643  			return fmt.Errorf("%w: ed25519", ErrInvalidSignature)
   644  		}
   645  	default:
   646  		// We should never get here, because we call validateKey in the first
   647  		// line of the function.
   648  		panic("unexpected Error in VerifySignature function")
   649  	}
   650  	return nil
   651  }
   652  
   653  /*
   654  VerifyCertificateTrust verifies that the certificate has a chain of trust
   655  to a root in rootCertPool, possibly using any intermediates in
   656  intermediateCertPool
   657  */
   658  func VerifyCertificateTrust(cert *x509.Certificate, rootCertPool, intermediateCertPool *x509.CertPool) ([][]*x509.Certificate, error) {
   659  	verifyOptions := x509.VerifyOptions{
   660  		Roots:         rootCertPool,
   661  		Intermediates: intermediateCertPool,
   662  	}
   663  	chains, err := cert.Verify(verifyOptions)
   664  	if len(chains) == 0 || err != nil {
   665  		return nil, fmt.Errorf("cert cannot be verified by provided roots and intermediates")
   666  	}
   667  	return chains, nil
   668  }
   669  

View as plain text