// 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") }