<commit_before>package hippo

import (
	"fmt"
)

// ErrPreviousVerifier is returned when adding an already added verifier to a
// pool.
var ErrPreviousVerifier = fmt.Errorf("Verifier exists")

// ErrNoVerifier is returned when no verifier with a specified ID exists in a
// pool.
var ErrNoVerifier = fmt.Errorf("Invalid verifier")

// ErrInvalidCertificate is returned when attempting to verify an invalid
// certificate.
var ErrInvalidCertificate = fmt.Errorf("Invalid certificate")

// ErrUnrecognizedCertificate is returned when none of the signers in a
// certificate are in a verifier pool.
var ErrUnrecognizedCertificate = fmt.Errorf("Unrecognized certificate")

// ErrBrokenCertificateChain is returned when a declaration's subject doesn't
// match the previous declarations signer when verifying.
var ErrBrokenCertificateChain = fmt.Errorf("Broken certificate chain")

// ErrNotCertificateAuthority is returned when a chained declaration does not
// have the "CertificateAuthority" claim.
var ErrNotCertificateAuthority = fmt.Errorf("Chained declaration does not confirm certificate authority")

// VerifierPool is a collection of verifiers.  Typically these are
// used to group a set of keys for trusted entities that may be used
// to verify incoming data, etc..
type VerifierPool struct {
	verifiers map[string]Verifier
}

// NewVerifierPool creates an empty VerifierPool.
func NewVerifierPool() *VerifierPool {

	x := new(VerifierPool)
	x.verifiers = make(map[string]Verifier)

	return x

}

// Add adds to given verifier to the pool under the given identifier.
func (x VerifierPool) Add(id string, v Verifier) error {

	_, ok := x.verifiers[id]
	if ok {
		return ErrPreviousVerifier
	}

	x.verifiers[id] = v

	return nil

}

// VerifySpecific looks up the given identifier in the pool and
// confirms that the signature was created from the data by the
// private key associated with that verifier's public key.
func (x VerifierPool) VerifySpecific(id string, data []byte, signature Signature) error {

	verifier, ok := x.verifiers[id]
	if !ok {
		return ErrNoVerifier
	}

	return verifier.Verify(data, signature)

}

// VerifyAny checks if any entry in the pool can verify that the
// signature was created from the data by the private key associated
// with that verifier's public key.
func (x VerifierPool) VerifyAny(data []byte, signature Signature) error {

	var err error
	for _, verifier := range x.verifiers {
		err = verifier.Verify(data, signature)
		if err == nil {
			return nil
		}
	}

	return ErrUnverifiedSignature

}

// VerifyDeclaration confirms that the declaration can be verified by
// the entry in the pool under the included signer identity if it is
// not blank, or by entry in the pool if it is.
func (x VerifierPool) VerifyDeclaration(declaration *Declaration) error {

	if declaration.Signer == "" {
		return x.VerifyAny([]byte(declaration.Claim), declaration.Signature)
	}

	return x.VerifySpecific(declaration.Signer, []byte(declaration.Claim), declaration.Signature)

}

// Verify confirms that each Declaration in the Certificate Chain was
// signed by the entitiy associated with the subsequent entry, that
// each intermediate signer was indicated by its successor to be a
// certificate authority, and that the chain at some point leads to an
// entry in the verifier pool.
func (x VerifierPool) Verify(cert *Certificate) error {

	// If there's no certificate, fail
	if len(cert.Declarations) <= 0 {
		return ErrInvalidCertificate
	}

	// If the first signer is in the pool, approve
	err := x.VerifyDeclaration(cert.Declarations[0])
	if err == nil {
		return nil
	}

	prev := cert.Declarations[0]

	for index := 1; index < len(cert.Declarations); index++ {

		current := cert.Declarations[index]
		currtestament, err := UnpackTestament(current.Claim)

		// If a chained declaration is not for a certificate authority, fail
		val, ok := currtestament.Claims["CertificateAuthority"]
		if !ok {
			return ErrNotCertificateAuthority
		}

		switch t := val.(type) {
		case bool:
			if !t {
				return ErrNotCertificateAuthority
			}
		default:<commit_msg>Check for errors when unpacking testaments in Verify.<commit_after>package hippo

import (
	"fmt"
)

// ErrPreviousVerifier is returned when adding an already added verifier to a
// pool.
var ErrPreviousVerifier = fmt.Errorf("Verifier exists")

// ErrNoVerifier is returned when no verifier with a specified ID exists in a
// pool.
var ErrNoVerifier = fmt.Errorf("Invalid verifier")

// ErrInvalidCertificate is returned when attempting to verify an invalid
// certificate.
var ErrInvalidCertificate = fmt.Errorf("Invalid certificate")

// ErrUnrecognizedCertificate is returned when none of the signers in a
// certificate are in a verifier pool.
var ErrUnrecognizedCertificate = fmt.Errorf("Unrecognized certificate")

// ErrBrokenCertificateChain is returned when a declaration's subject doesn't
// match the previous declarations signer when verifying.
var ErrBrokenCertificateChain = fmt.Errorf("Broken certificate chain")

// ErrNotCertificateAuthority is returned when a chained declaration does not
// have the "CertificateAuthority" claim.
var ErrNotCertificateAuthority = fmt.Errorf("Chained declaration does not confirm certificate authority")

// VerifierPool is a collection of verifiers.  Typically these are
// used to group a set of keys for trusted entities that may be used
// to verify incoming data, etc..
type VerifierPool struct {
	verifiers map[string]Verifier
}

// NewVerifierPool creates an empty VerifierPool.
func NewVerifierPool() *VerifierPool {

	x := new(VerifierPool)
	x.verifiers = make(map[string]Verifier)

	return x

}

// Add adds to given verifier to the pool under the given identifier.
func (x VerifierPool) Add(id string, v Verifier) error {

	_, ok := x.verifiers[id]
	if ok {
		return ErrPreviousVerifier
	}

	x.verifiers[id] = v

	return nil

}

// VerifySpecific looks up the given identifier in the pool and
// confirms that the signature was created from the data by the
// private key associated with that verifier's public key.
func (x VerifierPool) VerifySpecific(id string, data []byte, signature Signature) error {

	verifier, ok := x.verifiers[id]
	if !ok {
		return ErrNoVerifier
	}

	return verifier.Verify(data, signature)

}

// VerifyAny checks if any entry in the pool can verify that the
// signature was created from the data by the private key associated
// with that verifier's public key.
func (x VerifierPool) VerifyAny(data []byte, signature Signature) error {

	var err error
	for _, verifier := range x.verifiers {
		err = verifier.Verify(data, signature)
		if err == nil {
			return nil
		}
	}

	return ErrUnverifiedSignature

}

// VerifyDeclaration confirms that the declaration can be verified by
// the entry in the pool under the included signer identity if it is
// not blank, or by entry in the pool if it is.
func (x VerifierPool) VerifyDeclaration(declaration *Declaration) error {

	if declaration.Signer == "" {
		return x.VerifyAny([]byte(declaration.Claim), declaration.Signature)
	}

	return x.VerifySpecific(declaration.Signer, []byte(declaration.Claim), declaration.Signature)

}

// Verify confirms that each Declaration in the Certificate Chain was
// signed by the entitiy associated with the subsequent entry, that
// each intermediate signer was indicated by its successor to be a
// certificate authority, and that the chain at some point leads to an
// entry in the verifier pool.
func (x VerifierPool) Verify(cert *Certificate) error {

	// If there's no certificate, fail
	if len(cert.Declarations) <= 0 {
		return ErrInvalidCertificate
	}

	// If the first signer is in the pool, approve
	err := x.VerifyDeclaration(cert.Declarations[0])
	if err == nil {
		return nil
	}

	prev := cert.Declarations[0]

	for index := 1; index < len(cert.Declarations); index++ {

		current := cert.Declarations[index]
		currtestament, err := UnpackTestament(current.Claim)
		if err != nil {
			return err
		}

		// If a chained declaration is not for a certificate authority, fail
		val, ok := currtestament.Claims["CertificateAuthority"]
		if !ok {
			return ErrNotCertificateAuthority
		}

		switch t := val.(type) {
		case bool:
			if !t {
				return ErrNotCertificateAuthority
			}
		default:
{'fraction_non_alphanumeric': 0.08158085569253082, 'fraction_numerical': 0.0009668842156151801, 'mean_word_length': 4.16541822721598, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2919238', 'n_tokens_mistral': 2421, 'n_tokens_neox': 2298, 'n_words': 935}