Example #1
0
// AddEndorsements reads the SerializedEndorsements in an attestation and adds
// the ones that are predicates signed by a guard's policy key.
func AddEndorsements(guard Guard, a *Attestation, v *Verifier) error {
	// Before validating against the guard, check to see if there are any
	// predicates endorsed by the policy key. This allows truncated principals
	// to get the Tao CA to sign a statement of the form
	// TrustedHash(ext.Program(...)).
	for _, e := range a.SerializedEndorsements {
		var ea Attestation
		if err := proto.Unmarshal(e, &ea); err != nil {
			return err
		}

		f, err := auth.UnmarshalForm(ea.SerializedStatement)
		if err != nil {
			return err
		}

		says, ok := f.(auth.Says)
		if !ok {
			return fmt.Errorf("a serialized endorsement must be an auth.Says")
		}

		// TODO(tmroeder): check that this endorsement hasn't expired.
		pred, ok := says.Message.(auth.Pred)
		if !ok {
			return fmt.Errorf("the message in an endorsement must be a predicate")
		}

		signerPrin := auth.NewPrin(*ea.SignerType, ea.SignerKey)

		if !signerPrin.Identical(says.Speaker) {
			return fmt.Errorf("the speaker of an endorsement must be the signer: %v vs %v", signerPrin, says.Speaker)
		}
		if !v.ToPrincipal().Identical(signerPrin) {
			return fmt.Errorf("the signer of an endorsement must be the guard's policy key")
		}
		if ok, err := v.Verify(ea.SerializedStatement, AttestationSigningContext, ea.Signature); (err != nil) || !ok {
			return fmt.Errorf("the signature on an endorsement didn't pass verification")
		}

		return guard.AddRule(pred.String())
	}

	return nil
}
Example #2
0
// Checks the following:
// (1) the endorsement attestation is valid
// (2) the key being endorsed is kPrin
// (3) the subject being endorsed is a trusted host
// Finally the function returns the key principal signing the endorsement
func validateEndorsementAttestation(attestation *tao.Attestation, guard tao.Guard,
	kPrin *auth.Prin) (*auth.Prin, error) {
	saysStatement, err := attestation.Validate()
	if err != nil {
		return nil, err
	}
	_, key, host, err := parseSaysStatement(&saysStatement)
	if err != nil {
		return nil, err
	}
	if !key.Identical(kPrin) {
		return nil, errors.New("endorsement does not endorse signer of (previous) attestaton")
	}
	if !guard.IsAuthorized(*host, "Host", []string{}) {
		return nil, errors.New("endorsement host not authorized to run in this domain")
	}
	signerType := attestation.SignerType
	if signerType == nil {
		return nil, errors.New("endorsement chain has attestation with missing SignerType")
	}
	signerPrin := auth.NewPrin(*signerType, attestation.SignerKey)
	return &signerPrin, nil
}
Example #3
0
// ValidSigner checks the signature on an attestation and, if so, returns the
// principal name for the signer.
func (a *Attestation) ValidSigner() (auth.Prin, error) {
	signer := auth.NewPrin(*a.SignerType, a.SignerKey)
	switch *a.SignerType {
	case "tpm":
		// The PCRs are contained in the Speaker of an auth.Says statement that
		// makes up the a.SerializedStatement.
		f, err := auth.UnmarshalForm(a.SerializedStatement)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't unmarshal the statement: %s", err)
		}

		// A TPM attestation must be an auth.Says.
		says, ok := f.(auth.Says)
		if !ok {
			return auth.Prin{}, newError("tao: the attestation statement was not an auth.Says statement")
		}

		// Signer is tpm; use tpm-specific signature verification. Extract the
		// PCRs from the issuer name, unmarshal the key as an RSA key, and call
		// tpm.VerifyQuote().
		speaker, ok := says.Speaker.(auth.Prin)
		if !ok {
			return auth.Prin{}, newError("tao: the speaker of an attestation must be an auth.Prin")
		}
		pcrNums, pcrVals, err := extractPCRs(speaker)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't extract TPM PCRs from attestation: %s", err)
		}

		pk, err := extractTPMKey(a.SignerKey)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't extract TPM key from attestation: %s", err)
		}
		if err := tpm.VerifyQuote(pk, a.SerializedStatement, a.Signature, pcrNums, pcrVals); err != nil {
			return auth.Prin{}, newError("tao: TPM quote failed verification: %s", err)
		}

		return signer, nil
	case "tpm2":
		// TODO -- tpm2
		// The PCRs are contained in the Speaker of an auth.Says statement that
		// makes up the a.SerializedStatement.
		f, err := auth.UnmarshalForm(a.SerializedStatement)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't unmarshal the statement: %s", err)
		}

		// put this back in
		// A TPM attestation must be an auth.Says.
		says, ok := f.(auth.Says)
		if !ok {
			return auth.Prin{}, newError("tao: the attestation statement was not an auth.Says statement")
		}

		// Signer is tpm; use tpm-specific signature verification. Extract the
		// PCRs from the issuer name, unmarshal the key as an RSA key, and call
		// tpm2.VerifyQuote().
		speaker, ok := says.Speaker.(auth.Prin)
		if !ok {
			return auth.Prin{}, newError("tao: the speaker of an attestation must be an auth.Prin")
		}

		key, err := extractTPM2Key(a.SignerKey)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't extract TPM key from attestation: %s", err)
		}
		pcrNums, pcrVal, err := extractTpm2PCRs(speaker)
		if err != nil {
			return auth.Prin{}, newError("tao: couldn't extract TPM PCRs from attestation: %s", err)
		}

		ok, err = tpm2.VerifyTpm2Quote(a.SerializedStatement,
			pcrNums, pcrVal, a.Tpm2QuoteStructure, a.Signature,
			key)
		if err != nil {
			return auth.Prin{}, newError("tao: TPM quote verification error")
		}
		if !ok {
			return auth.Prin{}, newError("tao: TPM quote failed verification")
		}
		return signer, nil
	case "key":
		// Signer is ECDSA key, use Tao signature verification.
		v, err := UnmarshalKey(a.SignerKey)
		if err != nil {
			return auth.Prin{}, err
		}
		ok, err := v.Verify(a.SerializedStatement, AttestationSigningContext, a.Signature)
		if err != nil {
			return auth.Prin{}, err
		}
		if !ok {
			return auth.Prin{}, newError("tao: attestation signature invalid")
		}
		return signer, nil
	default:
		return auth.Prin{}, newError("tao: attestation signer principal unrecognized: %s", signer.String())
	}
}
Example #4
0
// This function makes the following checks
// (1) Checks if the attestation signature is valid and the statement is of the form
//     'Speaker says Key speaks for Program'.
// (2) Checks that 'Program' in the above statement is allowed to Execute in the domain policy.
//     In particular, the policy should allow the predicate:
//     Authorized(ProgramTaoName, "Execute")
// (3) Checks that 'Speaker' in the above statement is a key principal endorsed by the policy key,
//     or rootCerts, via an endorsement chain. Each endorsement in this chain endorses the key
//     signing the previous endorsement (starting with the 'Speaker' key).
//
//     An endorsement endorses either a host key, in which case it is an attestation,
//     or the root hardware key, in which case it is certificate.
//     This function also checks that each host or root hardware encoutered along this endorsement
//     chain is allowed as per domain policy. In particular the policy should allow the predicates
//     Authorized(HostTaoName, "Host") and Authorized(EncodedMachineInformation, "Root")
//
//     A valid attestation chain must either end in a attestation signed by the policy key
//     or a certificate signed by one of the rootCerts.
//
// If all above checks go through, the function returns the principals: Speaker, Key, Program.
func VerifyHostAttestation(serializedHostAttestation []byte, domain *tao.Domain,
	rootCerts *x509.CertPool) (*auth.Prin, *auth.Prin, *auth.Prin, error) {
	var hostAttestation tao.Attestation
	err := proto.Unmarshal(serializedHostAttestation, &hostAttestation)
	if err != nil {
		return nil, nil, nil, errors.New(
			"domain_service: error deserialiaizng host attestation: " + err.Error())
	}

	// First check if attestation is valid.
	statement, err := hostAttestation.Validate()
	if err != nil {
		return nil, nil, nil, errors.New(
			"host attestation fails validation check: " + err.Error())
	}

	// Next, check if SpeaksFor delegator is authorized to execute (i.e. the program is allowed to
	// run as per policy).
	speaker, key, prog, err := parseSaysStatement(&statement)
	if err != nil {
		return nil, nil, nil, err
	}
	if !domain.Guard.IsAuthorized(*prog, "Execute", []string{}) {
		return nil, nil, nil, errors.New(
			"program not authorized to run in this domain")
	}

	// Look for endorsement cert(s), rooted in the policy key, that ultimately certify the
	// key of the signer.
	signingKey := hostAttestation.GetSignerKey()
	if hostAttestation.SignerType == nil {
		return nil, nil, nil, errors.New("host attestation missing SignerType field")
	}
	signingPrin := auth.NewPrin(*hostAttestation.SignerType, signingKey)
	if !speaker.Identical(signingPrin) {
		// TODO: endorsement endorses speaker or signer?
	}

	// Look for endorsement(s) of signer, rooted in policy key.
	serializedEndorsements := hostAttestation.GetSerializedEndorsements()
	var realErr error
	var kPrin *auth.Prin
	kPrin = &signingPrin
	for _, serializedEndorsement := range serializedEndorsements {
		// serializedEndorsement could be X.509 certificate or Tao attestation.
		var attestation tao.Attestation
		err := proto.Unmarshal(serializedEndorsement, &attestation)
		if err == nil {
			kPrin, realErr = validateEndorsementAttestation(&attestation, domain.Guard, kPrin)
			if realErr != nil {
				return nil, nil, nil, realErr
			}
		} else if cert, err1 := x509.ParseCertificate(serializedEndorsement); err1 == nil {
			realErr = validateEndorsementCertificate(cert, domain.Guard, kPrin, rootCerts)
			if realErr != nil {
				return nil, nil, nil, realErr
			} else {
				// Endorsement certs are the root of the endorsement chain.
				// If they are valid, then no more checking is required.
				return speaker, key, prog, nil
			}

		} else {
			return nil, nil, nil, errors.New("error parsing host endorsement")
		}
	}
	if domain.Keys.SigningKey.ToPrincipal().Identical(*kPrin) {
		return speaker, key, prog, nil
	}
	return nil, nil, nil, errors.New("endorsement chain does not terminate in policy key")

}