mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-10 13:37:08 +08:00
vendor: update buildkit to master@31c870e82a48
Signed-off-by: Justin Chadwell <me@jedevc.com>
This commit is contained in:
670
vendor/github.com/in-toto/in-toto-golang/in_toto/keylib.go
generated
vendored
Normal file
670
vendor/github.com/in-toto/in-toto-golang/in_toto/keylib.go
generated
vendored
Normal file
@ -0,0 +1,670 @@
|
||||
package in_toto
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/secure-systems-lab/go-securesystemslib/cjson"
|
||||
)
|
||||
|
||||
// ErrFailedPEMParsing gets returned when PKCS1, PKCS8 or PKIX key parsing fails
|
||||
var ErrFailedPEMParsing = errors.New("failed parsing the PEM block: unsupported PEM type")
|
||||
|
||||
// ErrNoPEMBlock gets triggered when there is no PEM block in the provided file
|
||||
var ErrNoPEMBlock = errors.New("failed to decode the data as PEM block (are you sure this is a pem file?)")
|
||||
|
||||
// ErrUnsupportedKeyType is returned when we are dealing with a key type different to ed25519 or RSA
|
||||
var ErrUnsupportedKeyType = errors.New("unsupported key type")
|
||||
|
||||
// ErrInvalidSignature is returned when the signature is invalid
|
||||
var ErrInvalidSignature = errors.New("invalid signature")
|
||||
|
||||
// ErrInvalidKey is returned when a given key is none of RSA, ECDSA or ED25519
|
||||
var ErrInvalidKey = errors.New("invalid key")
|
||||
|
||||
const (
|
||||
rsaKeyType string = "rsa"
|
||||
ecdsaKeyType string = "ecdsa"
|
||||
ed25519KeyType string = "ed25519"
|
||||
rsassapsssha256Scheme string = "rsassa-pss-sha256"
|
||||
ecdsaSha2nistp224 string = "ecdsa-sha2-nistp224"
|
||||
ecdsaSha2nistp256 string = "ecdsa-sha2-nistp256"
|
||||
ecdsaSha2nistp384 string = "ecdsa-sha2-nistp384"
|
||||
ecdsaSha2nistp521 string = "ecdsa-sha2-nistp521"
|
||||
ed25519Scheme string = "ed25519"
|
||||
pemPublicKey string = "PUBLIC KEY"
|
||||
pemPrivateKey string = "PRIVATE KEY"
|
||||
pemRSAPrivateKey string = "RSA PRIVATE KEY"
|
||||
)
|
||||
|
||||
/*
|
||||
getSupportedKeyIDHashAlgorithms returns a string slice of supported
|
||||
KeyIDHashAlgorithms. We need to use this function instead of a constant,
|
||||
because Go does not support global constant slices.
|
||||
*/
|
||||
func getSupportedKeyIDHashAlgorithms() Set {
|
||||
return NewSet("sha256", "sha512")
|
||||
}
|
||||
|
||||
/*
|
||||
getSupportedRSASchemes returns a string slice of supported RSA Key schemes.
|
||||
We need to use this function instead of a constant because Go does not support
|
||||
global constant slices.
|
||||
*/
|
||||
func getSupportedRSASchemes() []string {
|
||||
return []string{rsassapsssha256Scheme}
|
||||
}
|
||||
|
||||
/*
|
||||
getSupportedEcdsaSchemes returns a string slice of supported ecdsa Key schemes.
|
||||
We need to use this function instead of a constant because Go does not support
|
||||
global constant slices.
|
||||
*/
|
||||
func getSupportedEcdsaSchemes() []string {
|
||||
return []string{ecdsaSha2nistp224, ecdsaSha2nistp256, ecdsaSha2nistp384, ecdsaSha2nistp521}
|
||||
}
|
||||
|
||||
/*
|
||||
getSupportedEd25519Schemes returns a string slice of supported ed25519 Key
|
||||
schemes. We need to use this function instead of a constant because Go does
|
||||
not support global constant slices.
|
||||
*/
|
||||
func getSupportedEd25519Schemes() []string {
|
||||
return []string{ed25519Scheme}
|
||||
}
|
||||
|
||||
/*
|
||||
generateKeyID creates a partial key map and generates the key ID
|
||||
based on the created partial key map via the SHA256 method.
|
||||
The resulting keyID will be directly saved in the corresponding key object.
|
||||
On success generateKeyID will return nil, in case of errors while encoding
|
||||
there will be an error.
|
||||
*/
|
||||
func (k *Key) generateKeyID() error {
|
||||
// Create partial key map used to create the keyid
|
||||
// Unfortunately, we can't use the Key object because this also carries
|
||||
// yet unwanted fields, such as KeyID and KeyVal.Private and therefore
|
||||
// produces a different hash. We generate the keyID exactly as we do in
|
||||
// the securesystemslib to keep interoperability between other in-toto
|
||||
// implementations.
|
||||
var keyToBeHashed = map[string]interface{}{
|
||||
"keytype": k.KeyType,
|
||||
"scheme": k.Scheme,
|
||||
"keyid_hash_algorithms": k.KeyIDHashAlgorithms,
|
||||
"keyval": map[string]string{
|
||||
"public": k.KeyVal.Public,
|
||||
},
|
||||
}
|
||||
keyCanonical, err := cjson.EncodeCanonical(keyToBeHashed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// calculate sha256 and return string representation of keyID
|
||||
keyHashed := sha256.Sum256(keyCanonical)
|
||||
k.KeyID = fmt.Sprintf("%x", keyHashed)
|
||||
err = validateKey(*k)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
generatePEMBlock creates a PEM block from scratch via the keyBytes and the pemType.
|
||||
If successful it returns a PEM block as []byte slice. This function should always
|
||||
succeed, if keyBytes is empty the PEM block will have an empty byte block.
|
||||
Therefore only header and footer will exist.
|
||||
*/
|
||||
func generatePEMBlock(keyBytes []byte, pemType string) []byte {
|
||||
// construct PEM block
|
||||
pemBlock := &pem.Block{
|
||||
Type: pemType,
|
||||
Headers: nil,
|
||||
Bytes: keyBytes,
|
||||
}
|
||||
return pem.EncodeToMemory(pemBlock)
|
||||
}
|
||||
|
||||
/*
|
||||
setKeyComponents sets all components in our key object.
|
||||
Furthermore it makes sure to remove any trailing and leading whitespaces or newlines.
|
||||
We treat key types differently for interoperability reasons to the in-toto python
|
||||
implementation and the securesystemslib.
|
||||
*/
|
||||
func (k *Key) setKeyComponents(pubKeyBytes []byte, privateKeyBytes []byte, keyType string, scheme string, KeyIDHashAlgorithms []string) error {
|
||||
// assume we have a privateKey if the key size is bigger than 0
|
||||
|
||||
switch keyType {
|
||||
case rsaKeyType:
|
||||
if len(privateKeyBytes) > 0 {
|
||||
k.KeyVal = KeyVal{
|
||||
Private: strings.TrimSpace(string(generatePEMBlock(privateKeyBytes, pemRSAPrivateKey))),
|
||||
Public: strings.TrimSpace(string(generatePEMBlock(pubKeyBytes, pemPublicKey))),
|
||||
}
|
||||
} else {
|
||||
k.KeyVal = KeyVal{
|
||||
Public: strings.TrimSpace(string(generatePEMBlock(pubKeyBytes, pemPublicKey))),
|
||||
}
|
||||
}
|
||||
case ecdsaKeyType:
|
||||
if len(privateKeyBytes) > 0 {
|
||||
k.KeyVal = KeyVal{
|
||||
Private: strings.TrimSpace(string(generatePEMBlock(privateKeyBytes, pemPrivateKey))),
|
||||
Public: strings.TrimSpace(string(generatePEMBlock(pubKeyBytes, pemPublicKey))),
|
||||
}
|
||||
} else {
|
||||
k.KeyVal = KeyVal{
|
||||
Public: strings.TrimSpace(string(generatePEMBlock(pubKeyBytes, pemPublicKey))),
|
||||
}
|
||||
}
|
||||
case ed25519KeyType:
|
||||
if len(privateKeyBytes) > 0 {
|
||||
k.KeyVal = KeyVal{
|
||||
Private: strings.TrimSpace(hex.EncodeToString(privateKeyBytes)),
|
||||
Public: strings.TrimSpace(hex.EncodeToString(pubKeyBytes)),
|
||||
}
|
||||
} else {
|
||||
k.KeyVal = KeyVal{
|
||||
Public: strings.TrimSpace(hex.EncodeToString(pubKeyBytes)),
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("%w: %s", ErrUnsupportedKeyType, keyType)
|
||||
}
|
||||
k.KeyType = keyType
|
||||
k.Scheme = scheme
|
||||
k.KeyIDHashAlgorithms = KeyIDHashAlgorithms
|
||||
if err := k.generateKeyID(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
parseKey tries to parse a PEM []byte slice. Using the following standards
|
||||
in the given order:
|
||||
|
||||
- PKCS8
|
||||
- PKCS1
|
||||
- PKIX
|
||||
|
||||
On success it returns the parsed key and nil.
|
||||
On failure it returns nil and the error ErrFailedPEMParsing
|
||||
*/
|
||||
func parseKey(data []byte) (interface{}, error) {
|
||||
key, err := x509.ParsePKCS8PrivateKey(data)
|
||||
if err == nil {
|
||||
return key, nil
|
||||
}
|
||||
key, err = x509.ParsePKCS1PrivateKey(data)
|
||||
if err == nil {
|
||||
return key, nil
|
||||
}
|
||||
key, err = x509.ParsePKIXPublicKey(data)
|
||||
if err == nil {
|
||||
return key, nil
|
||||
}
|
||||
key, err = x509.ParseCertificate(data)
|
||||
if err == nil {
|
||||
return key, nil
|
||||
}
|
||||
key, err = x509.ParseECPrivateKey(data)
|
||||
if err == nil {
|
||||
return key, nil
|
||||
}
|
||||
return nil, ErrFailedPEMParsing
|
||||
}
|
||||
|
||||
/*
|
||||
decodeAndParse receives potential PEM bytes decodes them via pem.Decode
|
||||
and pushes them to parseKey. If any error occurs during this process,
|
||||
the function will return nil and an error (either ErrFailedPEMParsing
|
||||
or ErrNoPEMBlock). On success it will return the decoded pemData, the
|
||||
key object interface and nil as error. We need the decoded pemData,
|
||||
because LoadKey relies on decoded pemData for operating system
|
||||
interoperability.
|
||||
*/
|
||||
func decodeAndParse(pemBytes []byte) (*pem.Block, interface{}, error) {
|
||||
// pem.Decode returns the parsed pem block and a rest.
|
||||
// The rest is everything, that could not be parsed as PEM block.
|
||||
// Therefore we can drop this via using the blank identifier "_"
|
||||
data, _ := pem.Decode(pemBytes)
|
||||
if data == nil {
|
||||
return nil, nil, ErrNoPEMBlock
|
||||
}
|
||||
|
||||
// Try to load private key, if this fails try to load
|
||||
// key as public key
|
||||
key, err := parseKey(data.Bytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return data, key, nil
|
||||
}
|
||||
|
||||
/*
|
||||
LoadKey loads the key file at specified file path into the key object.
|
||||
It automatically derives the PEM type and the key type.
|
||||
Right now the following PEM types are supported:
|
||||
|
||||
- PKCS1 for private keys
|
||||
- PKCS8 for private keys
|
||||
- PKIX for public keys
|
||||
|
||||
The following key types are supported and will be automatically assigned to
|
||||
the key type field:
|
||||
|
||||
- ed25519
|
||||
- rsa
|
||||
- ecdsa
|
||||
|
||||
The following schemes are supported:
|
||||
|
||||
- ed25519 -> ed25519
|
||||
- rsa -> rsassa-pss-sha256
|
||||
- ecdsa -> ecdsa-sha256-nistp256
|
||||
|
||||
Note that, this behavior is consistent with the securesystemslib, except for
|
||||
ecdsa. We do not use the scheme string as key type in in-toto-golang.
|
||||
Instead we are going with a ecdsa/ecdsa-sha2-nistp256 pair.
|
||||
|
||||
On success it will return nil. The following errors can happen:
|
||||
|
||||
- path not found or not readable
|
||||
- no PEM block in the loaded file
|
||||
- no valid PKCS8/PKCS1 private key or PKIX public key
|
||||
- errors while marshalling
|
||||
- unsupported key types
|
||||
*/
|
||||
func (k *Key) LoadKey(path string, scheme string, KeyIDHashAlgorithms []string) error {
|
||||
pemFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer pemFile.Close()
|
||||
|
||||
err = k.LoadKeyReader(pemFile, scheme, KeyIDHashAlgorithms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return pemFile.Close()
|
||||
}
|
||||
|
||||
func (k *Key) LoadKeyDefaults(path string) error {
|
||||
pemFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer pemFile.Close()
|
||||
|
||||
err = k.LoadKeyReaderDefaults(pemFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return pemFile.Close()
|
||||
}
|
||||
|
||||
// LoadKeyReader loads the key from a supplied reader. The logic matches LoadKey otherwise.
|
||||
func (k *Key) LoadKeyReader(r io.Reader, scheme string, KeyIDHashAlgorithms []string) error {
|
||||
if r == nil {
|
||||
return ErrNoPEMBlock
|
||||
}
|
||||
// Read key bytes
|
||||
pemBytes, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// decodeAndParse returns the pemData for later use
|
||||
// and a parsed key object (for operations on that key, like extracting the public Key)
|
||||
pemData, key, err := decodeAndParse(pemBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return k.loadKey(key, pemData, scheme, KeyIDHashAlgorithms)
|
||||
}
|
||||
|
||||
func (k *Key) LoadKeyReaderDefaults(r io.Reader) error {
|
||||
if r == nil {
|
||||
return ErrNoPEMBlock
|
||||
}
|
||||
// Read key bytes
|
||||
pemBytes, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// decodeAndParse returns the pemData for later use
|
||||
// and a parsed key object (for operations on that key, like extracting the public Key)
|
||||
pemData, key, err := decodeAndParse(pemBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scheme, keyIDHashAlgorithms, err := getDefaultKeyScheme(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return k.loadKey(key, pemData, scheme, keyIDHashAlgorithms)
|
||||
}
|
||||
|
||||
func getDefaultKeyScheme(key interface{}) (scheme string, keyIDHashAlgorithms []string, err error) {
|
||||
keyIDHashAlgorithms = []string{"sha256", "sha512"}
|
||||
|
||||
switch key.(type) {
|
||||
case *rsa.PublicKey, *rsa.PrivateKey:
|
||||
scheme = rsassapsssha256Scheme
|
||||
case ed25519.PrivateKey, ed25519.PublicKey:
|
||||
scheme = ed25519Scheme
|
||||
case *ecdsa.PrivateKey, *ecdsa.PublicKey:
|
||||
scheme = ecdsaSha2nistp256
|
||||
case *x509.Certificate:
|
||||
return getDefaultKeyScheme(key.(*x509.Certificate).PublicKey)
|
||||
default:
|
||||
err = ErrUnsupportedKeyType
|
||||
}
|
||||
|
||||
return scheme, keyIDHashAlgorithms, err
|
||||
}
|
||||
|
||||
func (k *Key) loadKey(key interface{}, pemData *pem.Block, scheme string, keyIDHashAlgorithms []string) error {
|
||||
|
||||
switch key.(type) {
|
||||
case *rsa.PublicKey:
|
||||
pubKeyBytes, err := x509.MarshalPKIXPublicKey(key.(*rsa.PublicKey))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := k.setKeyComponents(pubKeyBytes, []byte{}, rsaKeyType, scheme, keyIDHashAlgorithms); err != nil {
|
||||
return err
|
||||
}
|
||||
case *rsa.PrivateKey:
|
||||
// Note: RSA Public Keys will get stored as X.509 SubjectPublicKeyInfo (RFC5280)
|
||||
// This behavior is consistent to the securesystemslib
|
||||
pubKeyBytes, err := x509.MarshalPKIXPublicKey(key.(*rsa.PrivateKey).Public())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := k.setKeyComponents(pubKeyBytes, pemData.Bytes, rsaKeyType, scheme, keyIDHashAlgorithms); err != nil {
|
||||
return err
|
||||
}
|
||||
case ed25519.PublicKey:
|
||||
if err := k.setKeyComponents(key.(ed25519.PublicKey), []byte{}, ed25519KeyType, scheme, keyIDHashAlgorithms); err != nil {
|
||||
return err
|
||||
}
|
||||
case ed25519.PrivateKey:
|
||||
pubKeyBytes := key.(ed25519.PrivateKey).Public()
|
||||
if err := k.setKeyComponents(pubKeyBytes.(ed25519.PublicKey), key.(ed25519.PrivateKey), ed25519KeyType, scheme, keyIDHashAlgorithms); err != nil {
|
||||
return err
|
||||
}
|
||||
case *ecdsa.PrivateKey:
|
||||
pubKeyBytes, err := x509.MarshalPKIXPublicKey(key.(*ecdsa.PrivateKey).Public())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := k.setKeyComponents(pubKeyBytes, pemData.Bytes, ecdsaKeyType, scheme, keyIDHashAlgorithms); err != nil {
|
||||
return err
|
||||
}
|
||||
case *ecdsa.PublicKey:
|
||||
pubKeyBytes, err := x509.MarshalPKIXPublicKey(key.(*ecdsa.PublicKey))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := k.setKeyComponents(pubKeyBytes, []byte{}, ecdsaKeyType, scheme, keyIDHashAlgorithms); err != nil {
|
||||
return err
|
||||
}
|
||||
case *x509.Certificate:
|
||||
err := k.loadKey(key.(*x509.Certificate).PublicKey, pemData, scheme, keyIDHashAlgorithms)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k.KeyVal.Certificate = string(pem.EncodeToMemory(pemData))
|
||||
|
||||
default:
|
||||
// We should never get here, because we implement all from Go supported Key Types
|
||||
return errors.New("unexpected Error in LoadKey function")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
GenerateSignature will automatically detect the key type and sign the signable data
|
||||
with the provided key. If everything goes right GenerateSignature will return
|
||||
a for the key valid signature and err=nil. If something goes wrong it will
|
||||
return a not initialized signature and an error. Possible errors are:
|
||||
|
||||
- ErrNoPEMBlock
|
||||
- ErrUnsupportedKeyType
|
||||
|
||||
Currently supported is only one scheme per key.
|
||||
|
||||
Note that in-toto-golang has different requirements to an ecdsa key.
|
||||
In in-toto-golang we use the string 'ecdsa' as string for the key type.
|
||||
In the key scheme we use: ecdsa-sha2-nistp256.
|
||||
*/
|
||||
func GenerateSignature(signable []byte, key Key) (Signature, error) {
|
||||
err := validateKey(key)
|
||||
if err != nil {
|
||||
return Signature{}, err
|
||||
}
|
||||
var signature Signature
|
||||
var signatureBuffer []byte
|
||||
hashMapping := getHashMapping()
|
||||
// The following switch block is needed for keeping interoperability
|
||||
// with the securesystemslib and the python implementation
|
||||
// in which we are storing RSA keys in PEM format, but ed25519 keys hex encoded.
|
||||
switch key.KeyType {
|
||||
case rsaKeyType:
|
||||
// We do not need the pemData here, so we can throw it away via '_'
|
||||
_, parsedKey, err := decodeAndParse([]byte(key.KeyVal.Private))
|
||||
if err != nil {
|
||||
return Signature{}, err
|
||||
}
|
||||
parsedKey, ok := parsedKey.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
return Signature{}, ErrKeyKeyTypeMismatch
|
||||
}
|
||||
switch key.Scheme {
|
||||
case rsassapsssha256Scheme:
|
||||
hashed := hashToHex(hashMapping["sha256"](), signable)
|
||||
// We use rand.Reader as secure random source for rsa.SignPSS()
|
||||
signatureBuffer, err = rsa.SignPSS(rand.Reader, parsedKey.(*rsa.PrivateKey), crypto.SHA256, hashed,
|
||||
&rsa.PSSOptions{SaltLength: sha256.Size, Hash: crypto.SHA256})
|
||||
if err != nil {
|
||||
return signature, err
|
||||
}
|
||||
default:
|
||||
// supported key schemes will get checked in validateKey
|
||||
panic("unexpected Error in GenerateSignature function")
|
||||
}
|
||||
case ecdsaKeyType:
|
||||
// We do not need the pemData here, so we can throw it away via '_'
|
||||
_, parsedKey, err := decodeAndParse([]byte(key.KeyVal.Private))
|
||||
if err != nil {
|
||||
return Signature{}, err
|
||||
}
|
||||
parsedKey, ok := parsedKey.(*ecdsa.PrivateKey)
|
||||
if !ok {
|
||||
return Signature{}, ErrKeyKeyTypeMismatch
|
||||
}
|
||||
curveSize := parsedKey.(*ecdsa.PrivateKey).Curve.Params().BitSize
|
||||
var hashed []byte
|
||||
if err := matchEcdsaScheme(curveSize, key.Scheme); err != nil {
|
||||
return Signature{}, ErrCurveSizeSchemeMismatch
|
||||
}
|
||||
// implement https://tools.ietf.org/html/rfc5656#section-6.2.1
|
||||
// We determine the curve size and choose the correct hashing
|
||||
// method based on the curveSize
|
||||
switch {
|
||||
case curveSize <= 256:
|
||||
hashed = hashToHex(hashMapping["sha256"](), signable)
|
||||
case 256 < curveSize && curveSize <= 384:
|
||||
hashed = hashToHex(hashMapping["sha384"](), signable)
|
||||
case curveSize > 384:
|
||||
hashed = hashToHex(hashMapping["sha512"](), signable)
|
||||
default:
|
||||
panic("unexpected Error in GenerateSignature function")
|
||||
}
|
||||
// Generate the ecdsa signature on the same way, as we do in the securesystemslib
|
||||
// We are marshalling the ecdsaSignature struct as ASN.1 INTEGER SEQUENCES
|
||||
// into an ASN.1 Object.
|
||||
signatureBuffer, err = ecdsa.SignASN1(rand.Reader, parsedKey.(*ecdsa.PrivateKey), hashed[:])
|
||||
if err != nil {
|
||||
return signature, err
|
||||
}
|
||||
case ed25519KeyType:
|
||||
// We do not need a scheme switch here, because ed25519
|
||||
// only consist of sha256 and curve25519.
|
||||
privateHex, err := hex.DecodeString(key.KeyVal.Private)
|
||||
if err != nil {
|
||||
return signature, ErrInvalidHexString
|
||||
}
|
||||
// Note: We can directly use the key for signing and do not
|
||||
// need to use ed25519.NewKeyFromSeed().
|
||||
signatureBuffer = ed25519.Sign(privateHex, signable)
|
||||
default:
|
||||
// We should never get here, because we call validateKey in the first
|
||||
// line of the function.
|
||||
panic("unexpected Error in GenerateSignature function")
|
||||
}
|
||||
signature.Sig = hex.EncodeToString(signatureBuffer)
|
||||
signature.KeyID = key.KeyID
|
||||
signature.Certificate = key.KeyVal.Certificate
|
||||
return signature, nil
|
||||
}
|
||||
|
||||
/*
|
||||
VerifySignature will verify unverified byte data via a passed key and signature.
|
||||
Supported key types are:
|
||||
|
||||
- rsa
|
||||
- ed25519
|
||||
- ecdsa
|
||||
|
||||
When encountering an RSA key, VerifySignature will decode the PEM block in the key
|
||||
and will call rsa.VerifyPSS() for verifying the RSA signature.
|
||||
When encountering an ed25519 key, VerifySignature will decode the hex string encoded
|
||||
public key and will use ed25519.Verify() for verifying the ed25519 signature.
|
||||
When the given key is an ecdsa key, VerifySignature will unmarshall the ASN1 object
|
||||
and will use the retrieved ecdsa components 'r' and 's' for verifying the signature.
|
||||
On success it will return nil. In case of an unsupported key type or any other error
|
||||
it will return an error.
|
||||
|
||||
Note that in-toto-golang has different requirements to an ecdsa key.
|
||||
In in-toto-golang we use the string 'ecdsa' as string for the key type.
|
||||
In the key scheme we use: ecdsa-sha2-nistp256.
|
||||
*/
|
||||
func VerifySignature(key Key, sig Signature, unverified []byte) error {
|
||||
err := validateKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sigBytes, err := hex.DecodeString(sig.Sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hashMapping := getHashMapping()
|
||||
switch key.KeyType {
|
||||
case rsaKeyType:
|
||||
// We do not need the pemData here, so we can throw it away via '_'
|
||||
_, parsedKey, err := decodeAndParse([]byte(key.KeyVal.Public))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parsedKey, ok := parsedKey.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return ErrKeyKeyTypeMismatch
|
||||
}
|
||||
switch key.Scheme {
|
||||
case rsassapsssha256Scheme:
|
||||
hashed := hashToHex(hashMapping["sha256"](), unverified)
|
||||
err = rsa.VerifyPSS(parsedKey.(*rsa.PublicKey), crypto.SHA256, hashed, sigBytes, &rsa.PSSOptions{SaltLength: sha256.Size, Hash: crypto.SHA256})
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w: %s", ErrInvalidSignature, err)
|
||||
}
|
||||
default:
|
||||
// supported key schemes will get checked in validateKey
|
||||
panic("unexpected Error in VerifySignature function")
|
||||
}
|
||||
case ecdsaKeyType:
|
||||
// We do not need the pemData here, so we can throw it away via '_'
|
||||
_, parsedKey, err := decodeAndParse([]byte(key.KeyVal.Public))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parsedKey, ok := parsedKey.(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
return ErrKeyKeyTypeMismatch
|
||||
}
|
||||
curveSize := parsedKey.(*ecdsa.PublicKey).Curve.Params().BitSize
|
||||
var hashed []byte
|
||||
if err := matchEcdsaScheme(curveSize, key.Scheme); err != nil {
|
||||
return ErrCurveSizeSchemeMismatch
|
||||
}
|
||||
// implement https://tools.ietf.org/html/rfc5656#section-6.2.1
|
||||
// We determine the curve size and choose the correct hashing
|
||||
// method based on the curveSize
|
||||
switch {
|
||||
case curveSize <= 256:
|
||||
hashed = hashToHex(hashMapping["sha256"](), unverified)
|
||||
case 256 < curveSize && curveSize <= 384:
|
||||
hashed = hashToHex(hashMapping["sha384"](), unverified)
|
||||
case curveSize > 384:
|
||||
hashed = hashToHex(hashMapping["sha512"](), unverified)
|
||||
default:
|
||||
panic("unexpected Error in VerifySignature function")
|
||||
}
|
||||
if ok := ecdsa.VerifyASN1(parsedKey.(*ecdsa.PublicKey), hashed[:], sigBytes); !ok {
|
||||
return ErrInvalidSignature
|
||||
}
|
||||
case ed25519KeyType:
|
||||
// We do not need a scheme switch here, because ed25519
|
||||
// only consist of sha256 and curve25519.
|
||||
pubHex, err := hex.DecodeString(key.KeyVal.Public)
|
||||
if err != nil {
|
||||
return ErrInvalidHexString
|
||||
}
|
||||
if ok := ed25519.Verify(pubHex, unverified, sigBytes); !ok {
|
||||
return fmt.Errorf("%w: ed25519", ErrInvalidSignature)
|
||||
}
|
||||
default:
|
||||
// We should never get here, because we call validateKey in the first
|
||||
// line of the function.
|
||||
panic("unexpected Error in VerifySignature function")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
VerifyCertificateTrust verifies that the certificate has a chain of trust
|
||||
to a root in rootCertPool, possibly using any intermediates in
|
||||
intermediateCertPool
|
||||
*/
|
||||
func VerifyCertificateTrust(cert *x509.Certificate, rootCertPool, intermediateCertPool *x509.CertPool) ([][]*x509.Certificate, error) {
|
||||
verifyOptions := x509.VerifyOptions{
|
||||
Roots: rootCertPool,
|
||||
Intermediates: intermediateCertPool,
|
||||
}
|
||||
chains, err := cert.Verify(verifyOptions)
|
||||
if len(chains) == 0 || err != nil {
|
||||
return nil, fmt.Errorf("cert cannot be verified by provided roots and intermediates")
|
||||
}
|
||||
return chains, nil
|
||||
}
|
Reference in New Issue
Block a user