// This function helps process a certificate revocation request. // It expects serAtt to be a serialized attestation signed by the domain policy key, // with a statement of the form: // policyKey says revoke certificateSerialNumber // This function gets a list of revoked certificates, updates it if the cert revocation // request is valid, and returns the updated list. func RevokeCertificate(serAtt []byte, revokedCerts []pkix.RevokedCertificate, domain *tao.Domain) ([]pkix.RevokedCertificate, error) { var policyAtt tao.Attestation err := proto.Unmarshal(serAtt, &policyAtt) if err != nil { return revokedCerts, err } if signer, err := policyAtt.ValidSigner(); err != nil { return revokedCerts, err } else if !signer.Identical(domain.Keys.SigningKey.ToPrincipal()) { return revokedCerts, errors.New("revoke cert request not signed by the policy key") } saysStmt, err := policyAtt.Validate() if err != nil { return revokedCerts, err } if saysStmt.Message == nil { return revokedCerts, errors.New("policy attestation 'Says' does not have a message") } pred, ok := saysStmt.Message.(auth.Pred) if !ok { return revokedCerts, errors.New("policy attestation 'Says' does not have a auth.Pred message") } if pred.Name != "revoke" { return revokedCerts, errors.New("policy attestation predicate name is not 'revoke'") } if len(pred.Arg) != 1 { return revokedCerts, errors.New("policy attestation predicate has more or less than one Arg") } serialNumberBytes, ok := pred.Arg[0].(auth.Bytes) if !ok { return revokedCerts, errors.New("policy attestation serial number is not bytes") } serialNumber := new(big.Int) serialNumber.SetBytes(serialNumberBytes) revokedCert := pkix.RevokedCertificate{ SerialNumber: serialNumber, RevocationTime: time.Now()} return append(revokedCerts, revokedCert), nil }
// 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 }
// 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") }