Example #1
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")

}