// TruncateAttestation cuts off a delegation chain at its "Program" subprincipal // extension and replaces its prefix with the given key principal. It also // returns the PrinExt that represents exactly the program hash. func TruncateAttestation(kprin auth.Prin, a *Attestation) (auth.Says, auth.PrinExt, error) { // This attestation must have a top-level delegation to a key. Return an // authorization for this program rooted in the policy key. I don't like // this, since it seems like it's much riskier, since this doesn't say // anything about the context in which the program is running. Fortunately, // local policy rules: if a peer won't accept this cert, then the other // program will have to fall back on the longer attestation. stmt, err := auth.UnmarshalForm(a.SerializedStatement) if err != nil { return auth.Says{}, auth.PrinExt{}, err } says, ok := stmt.(auth.Says) if !ok { return auth.Says{}, auth.PrinExt{}, fmt.Errorf("the serialized statement must be a says") } // Replace the message with one that uses the new principal, taking the last // Program subprinicpal, and all its following elements. It should say: // policyKey.Program(...)... says key(...) speaksfor // policyKey.Program(...)..., signed policyKey. sf, ok := says.Message.(auth.Speaksfor) if !ok { return auth.Says{}, auth.PrinExt{}, fmt.Errorf("the message in the statement must be a speaksfor") } delegator, ok := sf.Delegator.(auth.Prin) if !ok { return auth.Says{}, auth.PrinExt{}, fmt.Errorf("the delegator must be a principal") } var prog auth.PrinExt found := false for _, sprin := range delegator.Ext { if !found && (sprin.Name == "Program") { found = true prog = sprin } if found { kprin.Ext = append(kprin.Ext, sprin) } } // TODO(tmroeder): make sure that the delegate is a key and is not, e.g., // the policy key. truncSpeaksfor := auth.Speaksfor{ Delegate: sf.Delegate, Delegator: kprin, } truncSays := auth.Says{ Speaker: kprin, Time: says.Time, Expiration: says.Expiration, Message: truncSpeaksfor, } return truncSays, prog, nil }
// RuleDebugString returns a debug string for the ith policy rule, if it exists. func (g *DatalogGuard) RuleDebugString(i int) string { if i < 0 || i >= len(g.db.Rules) { return "" } rule := g.db.Rules[i] r, err := auth.UnmarshalForm(rule) if err != nil { return "" } return r.ShortString() }
// ReloadIfModified reads all persistent policy data from disk if the file // timestamp is more recent than the last time it was read. func (g *DatalogGuard) ReloadIfModified() error { if g.Key == nil { return nil } file, err := os.Open(g.Config.GetSignedRulesPath()) if err != nil { return err } defer file.Close() // before parsing, check the timestamp info, err := file.Stat() if err != nil { return err } if !info.ModTime().After(g.modTime) { return nil } serialized, err := ioutil.ReadAll(file) if err != nil { return err } var sdb SignedDatalogRules if err := proto.Unmarshal(serialized, &sdb); err != nil { return err } if ok, err := g.Key.Verify(sdb.SerializedRules, DatalogRulesSigningContext, sdb.Signature); !ok { if err != nil { return err } return newError("datalog rule signature did not verify") } var db DatalogRules if err := proto.Unmarshal(sdb.SerializedRules, &db); err != nil { return err } // Only clear the rules set, since g.assert already skips datalog rules that // are already present in the engine. g.db.Rules = nil g.modTime = info.ModTime() for _, rule := range db.Rules { r, err := auth.UnmarshalForm(rule) if err != nil { return err } err = g.assert(r) if err != nil { return err } } return nil }
// AddEndorsements reads the SerializedEndorsements in an attestation and adds // the ones that are predicates signed by the 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, err := auth.UnmarshalPrin(ea.Signer) if err != nil { return err } if !signerPrin.Identical(says.Speaker) { return fmt.Errorf("the speaker of an endorsement must be the signer") } if !v.ToPrincipal().Identical(signerPrin) { return fmt.Errorf("the signer of an endorsement must be the 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 }
// Create a Program Public/Private key. func CreateSigningKey(t tao.Tao) (*tao.Keys, []byte, error) { self, err := t.GetTaoName() k, err := tao.NewTemporaryKeys(tao.Signing) if k == nil || err != nil { return nil, nil, errors.New("Can't generate signing key") } publicString := strings.Replace(self.String(), "(", "", -1) publicString = strings.Replace(publicString, ")", "", -1) // publicString is now a canonicalized Tao Principal name us := "US" google := "Google" details := tao.X509Details{ Country: &us, Organization: &google, CommonName: &publicString} subjectname := tao.NewX509Name(&details) derCert, err := k.SigningKey.CreateSelfSignedDER(subjectname) if err != nil { return nil, nil, errors.New("Can't self sign cert\n") } cert, err := x509.ParseCertificate(derCert) if err != nil { return nil, nil, err } // Construct statement: "ProgramKey (new key) speaksfor Principal Name" // ToPrincipal retrieves key's Tao Principal Name. k.Cert = cert s := &auth.Speaksfor{ Delegate: k.SigningKey.ToPrincipal(), Delegator: self} if s == nil { return nil, nil, errors.New("Can't produce speaksfor") } // Sign attestation statement k.Delegation, err = t.Attest(&self, nil, nil, s) if err != nil { return nil, nil, err } _, _ = auth.UnmarshalForm(k.Delegation.SerializedStatement) return k, derCert, nil }
func NewMarshalledDatalogGuard(ser []byte) (*DatalogGuard, error) { var db DatalogRules if err := proto.Unmarshal(ser, &db); err != nil { return nil, err } g := NewTemporaryDatalogGuard().(*DatalogGuard) for _, rule := range db.Rules { r, err := auth.UnmarshalForm(rule) if err != nil { return nil, err } err = g.assert(r) if err != nil { return nil, err } } return g, nil }
// Attest is the server stub for Tao.Attest. func (server linuxHostTaoServerStub) Attest(r *RPCRequest, s *RPCResponse) error { stmt, err := auth.UnmarshalForm(r.Data) if err != nil { return err } var issuer *auth.Prin if r.Issuer != nil { p, err := auth.UnmarshalPrin(r.Issuer) if err != nil { return err } issuer = &p } a, err := server.lh.Attest(server.child, issuer, r.Time, r.Expiration, stmt) if err != nil { return err } s.Data, err = proto.Marshal(a) return err }
func (g *DatalogGuard) findRule(f auth.Form) (string, int, error) { rule, err := g.formToDatalogRule(f) if err != nil { return "", -1, err } for i, ser := range g.db.Rules { f2, err := auth.UnmarshalForm(ser) if err != nil { continue } rule2, err := g.formToDatalogRule(f2) if err != nil { continue } if rule == rule2 { return rule, i, nil } } return rule, -1, nil }
// RequestTruncatedAttestation connects to a CA instance, sends the attestation // for an X.509 certificate, and gets back a truncated attestation with a new // principal name based on the policy key. func RequestTruncatedAttestation(network, addr string, keys *Keys, v *Verifier) (*Attestation, error) { a, err := RequestAttestation(network, addr, keys, v) if err != nil { return nil, err } truncStmt, err := auth.UnmarshalForm(a.SerializedStatement) if err != nil { return nil, err } says, _, err := TruncateAttestation(v.ToPrincipal(), keys.Delegation) if err != nil { return nil, err } if !IdenticalDelegations(says, truncStmt) { return nil, fmt.Errorf("the statement returned by the TaoCA was different than what we expected") } return a, nil }
// EstablishCert contacts a CA to get a certificate signed by the policy key. It // replaces the current delegation and cert on k with the new delegation and // cert from the response. func EstablishCert(network, addr string, k *tao.Keys, v *tao.Verifier) error { na, err := tao.RequestAttestation(network, addr, k, v) if err != nil { return err } k.Delegation = na pa, err := auth.UnmarshalForm(na.SerializedStatement) if err != nil { return err } // Parse the received statement. var saysStatement *auth.Says if ptr, ok := pa.(*auth.Says); ok { saysStatement = ptr } else if val, ok := pa.(auth.Says); ok { saysStatement = &val } sf, ok := saysStatement.Message.(auth.Speaksfor) if ok != true { return errors.New("says doesn't have speaksfor message") } kprin, ok := sf.Delegate.(auth.Term) if ok != true { return errors.New("speaksfor message doesn't have Delegate") } newCert := auth.Bytes(kprin.(auth.Bytes)) cert, err := x509.ParseCertificate(newCert) if err != nil { return err } k.Cert["default"] = cert return nil }
// Reload requests the policy from the remote TaoCA and instantiates a // new guard. func (cg *CachedGuard) Reload() error { switch cg.guardType { case Datalog: datalogGuard := NewDatalogGuard(cg.verifier) db, err := RequestDatalogRules(cg.network, cg.address, cg.verifier) if err != nil { return err } datalogGuard.db = *db for _, marshaledForm := range db.Rules { f, _ := auth.UnmarshalForm(marshaledForm) rule, _, err := datalogGuard.findRule(f) if err != nil { return err } datalogGuard.dl.Assert(rule) } cg.guard = datalogGuard case ACLs: // TODO(cjpatton) return errors.New("CacheGuard: ACL set reload not implemented") } cg.timeUpdated = time.Now().Unix() return nil }
// 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()) } }
// First return is terminate flag. func DomainRequest(conn net.Conn, policyKey *tao.Keys, guard tao.Guard) (bool, error) { fmt.Printf("DomainRequest\n") log.Printf("DomainRequest\n") // Expect a request with attestation from client. ms := util.NewMessageStream(conn) var request domain_policy.DomainCertRequest err := ms.ReadMessage(&request) if err != nil { log.Printf("DomainRequest: Couldn't read attestation from channel:", err) log.Printf("\n") return false, err } var a tao.Attestation err = proto.Unmarshal(request.Attestation, &a) if request.KeyType == nil { log.Printf("Domain: Empty key type") return false, errors.New("Empty key type") } if *request.KeyType != "ECDSA" { log.Printf("Domain: bad key type") return false, errors.New("Domain: bad key type") } subjectPublicKey, err := domain_policy.GetEcdsaKeyFromDer(request.SubjectPublicKey) if err != nil { log.Printf("DomainRequest: can't get key from der") return false, errors.New("DomainRequest: can't get key from der") } // Get hash of the public key subject. serializedKey, err := domain_policy.SerializeEcdsaKeyToInternalName(subjectPublicKey.(*ecdsa.PublicKey)) if err != nil || serializedKey == nil { log.Printf("DomainRequest: Can't serialize key to internal format\n") return false, errors.New("DomainRequest: Can't serialize key to internal format") } subjectKeyHash := domain_policy.GetKeyHash(serializedKey) peerCert := conn.(*tls.Conn).ConnectionState().PeerCertificates[0] err = tao.ValidatePeerAttestation(&a, peerCert, guard) /* if err != nil { log.Printf("Domain: RequestCouldn't validate peer attestation:", err) return false, err } fmt.Printf("DomainRequest, peerCert: %x\n", peerCert) */ // Sign cert // Get Program name and key info from delegation. f, err := auth.UnmarshalForm(a.SerializedStatement) if err != nil { log.Printf("DomainRequest: Can't unmarshal a.SerializedStatement\n") return false, err } var saysStatement *auth.Says if ptr, ok := f.(*auth.Says); ok { saysStatement = ptr } else if val, ok := f.(auth.Says); ok { saysStatement = &val } sf, ok := saysStatement.Message.(auth.Speaksfor) if ok != true { log.Printf("DomainRequest: says doesnt have speaksfor message\n") return false, err } // this in the new key principal clientKeyPrincipal, ok := sf.Delegate.(auth.Prin) if ok != true { log.Printf("DomainRequest: speaksfor Delegate is not auth.Prin\n") return false, err } programPrincipal, ok := sf.Delegator.(auth.Prin) if ok != true { log.Printf("DomainRequest: Can't get subject principal\n") return false, errors.New("Can't get principal name from verifier") } programPrincipalName := programPrincipal.String() verified := IsAuthenticationValid(&programPrincipalName) if !verified { log.Printf("DomainRequest: name verification failed\n") return false, err } fmt.Printf("\nSimpleDomainService: key principal: %s, program principal: %s\n", clientKeyPrincipal, programPrincipalName) // Is the delegate the same key as was presented in the name in the request? namedHash := clientKeyPrincipal.KeyHash.(auth.Bytes) fmt.Printf("\nkeyhash: %x\n", namedHash) if bytes.Compare(subjectKeyHash[:], namedHash) != 0 { log.Printf("DomainRequest: named hash is wrong\n") fmt.Printf("DomainRequest: named hash is wrong, named: %x, computed: %x\n", namedHash, subjectKeyHash) return false, errors.New("DomainRequest: named hash is wrong") } // Sign program certificate. notBefore := time.Now() validFor := 365 * 24 * time.Hour notAfter := notBefore.Add(validFor) us := "US" issuerName := "Google" localhost := "localhost" x509SubjectName := &pkix.Name{ Organization: []string{programPrincipalName}, OrganizationalUnit: []string{programPrincipalName}, CommonName: localhost, Country: []string{us}, } x509IssuerName := &pkix.Name{ Organization: []string{issuerName}, OrganizationalUnit: []string{issuerName}, CommonName: localhost, Country: []string{us}, } // issuerName := tao.NewX509Name(&details) SerialNumber = SerialNumber + 1 var sn big.Int certificateTemplate := x509.Certificate{ SerialNumber: &sn, Issuer: *x509IssuerName, Subject: *x509SubjectName, NotBefore: notBefore, NotAfter: notAfter, KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageKeyAgreement | x509.KeyUsageDigitalSignature, } clientCert, err := x509.CreateCertificate(rand.Reader, &certificateTemplate, policyKey.Cert, subjectPublicKey, policyKey.SigningKey.GetSigner()) if err != nil { fmt.Printf("Can't create client certificate: ", err, "\n") return false, err } zero := int32(0) var ra domain_policy.DomainCertResponse ra.Error = &zero ra.SignedCert = clientCert // Add cert chain (just policy cert for now). ra.CertChain = append(ra.CertChain, policyKey.Cert.Raw) _, err = ms.WriteMessage(&ra) if err != nil { log.Printf("DomainRequest: Couldn't return the attestation on the channel: ", err) log.Printf("\n") return false, err } return false, nil }
// First return is terminate flag. func handleRequest(conn net.Conn, policyKey *tao.Keys, guard tao.Guard) error { // Expect an attestation from the client. ms := util.NewMessageStream(conn) var a tao.Attestation if err := ms.ReadMessage(&a); err != nil { return err } peerCert := conn.(*tls.Conn).ConnectionState().PeerCertificates[0] p, err := tao.ValidatePeerAttestation(&a, peerCert) if err != nil { return err } // TODO(kwalsh) most of this duplicates the work of tao.Conn if !guard.IsAuthorized(p, "Execute", nil) { return fmt.Errorf("peer is not authorized to execute, hence not authorized to connect either") } // Sign cert and put it in attestation statement // a consists of serialized statement, sig and SignerInfo // a is a says speaksfor, Delegate of speaksfor is cert and should be DER encoded // Get underlying says f, err := auth.UnmarshalForm(a.SerializedStatement) if err != nil { return err } var saysStatement *auth.Says if ptr, ok := f.(*auth.Says); ok { saysStatement = ptr } else if val, ok := f.(auth.Says); ok { saysStatement = &val } sf, ok := saysStatement.Message.(auth.Speaksfor) if ok != true { return fmt.Errorf("keynegoserver: says doesn't have a speaksfor message\n") } kprin, ok := sf.Delegate.(auth.Prin) if ok != true { return fmt.Errorf("keynegoserver: speaksfor Delegate is not auth.Prin\n") } subjectPrin, ok := sf.Delegator.(auth.Prin) if ok != true { return fmt.Errorf("keynegoserver: can't get subject principal\n") } subjectName := subjectPrin.String() details := &tao.X509Details{ Country: proto.String("US"), Organization: proto.String("Google"), OrganizationalUnit: proto.String(subjectName), CommonName: proto.String("localhost"), } subjectname := tao.NewX509Name(details) SerialNumber = SerialNumber + 1 verifier, err := tao.FromPrincipal(kprin) if err != nil { return errors.New("can't get principal from kprin") } template := policyKey.SigningKey.X509Template(subjectname) template.IsCA = false clientCert, err := policyKey.CreateSignedX509(verifier, template, "default") if err != nil { return fmt.Errorf("keynegoserver: can't create client certificate: %s\n", err) } clientDERCert := clientCert.Raw err = ioutil.WriteFile("ClientCert", clientDERCert, os.ModePerm) nowTime := time.Now().UnixNano() expireTime := time.Now().AddDate(1, 0, 0).UnixNano() // Replace self signed cert in attest request newSpeaksFor := &auth.Speaksfor{ Delegate: auth.Bytes(clientDERCert), Delegator: sf.Delegator, } keyNegoSays := auth.Says{ Speaker: policyKey.SigningKey.ToPrincipal(), Time: &nowTime, Expiration: &expireTime, Message: newSpeaksFor, } delegator, ok := sf.Delegator.(auth.Prin) if !ok { return fmt.Errorf("keynegoserver: the delegator must be a principal") } found := false for _, sprin := range delegator.Ext { if !found && (sprin.Name == "Program") { found = true } if found { kprin.Ext = append(kprin.Ext, sprin) } } ra, err := tao.GenerateAttestation(policyKey.SigningKey, nil, keyNegoSays) if err != nil { return fmt.Errorf("Couldn't attest to the new says statement: %s", err) } if _, err := ms.WriteMessage(ra); err != nil { return fmt.Errorf("Couldn't return the attestation on the channel: %s", err) } return nil }
// ValidSigner checks the signature on an attestation and, if so, returns the signer. func (a *Attestation) ValidSigner() (auth.Prin, error) { signer, err := auth.UnmarshalPrin(a.Signer) if err != nil { return auth.Prin{}, err } if len(signer.Ext) != 0 { return auth.Prin{}, newError("tao: attestation signer principal malformed: %s", signer) } switch signer.Type { 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 PCRs from the signer: %s", err) } pk, err := ExtractAIK(speaker) if err != nil { return auth.Prin{}, newError("tao: couldn't extract the AIK from the signer: %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 "key": // Signer is ECDSA key, use Tao signature verification. v, err := FromPrincipal(signer) 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()) } }
// Validate checks whether an attestation is valid and, if so, it returns the // statement conveyed by the attestation. func (a *Attestation) Validate() (auth.Says, error) { signer, err := a.ValidSigner() if err != nil { return auth.Says{}, err } f, err := auth.UnmarshalForm(a.SerializedStatement) if err != nil { return auth.Says{}, err } var stmt *auth.Says if ptr, ok := f.(*auth.Says); ok { stmt = ptr } else if val, ok := f.(auth.Says); ok { stmt = &val } else { return auth.Says{}, newError("tao: attestation statement has wrong type: %T", f) } if a.SerializedDelegation == nil { // Case (1), no delegation present. // Require that stmt.Speaker be a subprincipal of (or identical to) a.signer. if !auth.SubprinOrIdentical(stmt.Speaker, signer) { return auth.Says{}, newError("tao: attestation statement signer (%v) does not evidently speak for issuer (%v)", signer, stmt.Speaker) } } else { // Case (2), delegation present. // Require that: // - delegation conveys delegator says delegate speaksfor delegator, // - a.signer speaks for delegate // - and delegator speaks for s.Speaker var da Attestation if err := proto.Unmarshal(a.SerializedDelegation, &da); err != nil { return auth.Says{}, err } delegationStatement, err := da.Validate() if err != nil { return auth.Says{}, err } var delegation *auth.Speaksfor if ptr, ok := delegationStatement.Message.(*auth.Speaksfor); ok { delegation = ptr } else if val, ok := delegationStatement.Message.(auth.Speaksfor); ok { delegation = &val } else { return auth.Says{}, newError("tao: attestation delegation is wrong type") } if !delegationStatement.Speaker.Identical(delegation.Delegator) { return auth.Says{}, newError("tao: attestation delegation is invalid") } if !auth.SubprinOrIdentical(delegation.Delegate, signer) { return auth.Says{}, newError("tao: attestation delegation irrelevant to signer") } if !auth.SubprinOrIdentical(stmt.Speaker, delegation.Delegator) { return auth.Says{}, newError("tao: attestation delegation irrelevant to issuer") } if stmt.Time == nil { stmt.Time = delegationStatement.Time } else if delegationStatement.Time != nil && *stmt.Time < *delegationStatement.Time { stmt.Time = delegationStatement.Time } if stmt.Expiration == nil { stmt.Expiration = delegationStatement.Expiration } else if delegationStatement.Expiration != nil && *stmt.Expiration > *delegationStatement.Expiration { stmt.Expiration = delegationStatement.Expiration } } return *stmt, nil }
// This function performs the following checks on a secret disclosure directive. // (1) the directive signature is valid with respect to signerKey of directive // (2) Either // - policyKey matches the signerKey of directive // - directive cert is a valid program cert (signed by policyKey) certifying the signerKey // of directive as belonging to 'delegator' // (3) the directive message is a statement of the form: // 'policyKey/'delegator' says delegate can read protectedObjectId' // where delegate is a Tao Principal and protectedObjectId is a (serialized) protected // object message id. func VerifySecretDisclosureDirective(policyKey *tao.Keys, directive *DirectiveMessage) (*auth.Prin, *auth.Prin, *string, *po.ObjectIdMessage, error) { // Check type of directive if directive.Type == nil || *(directive.Type) != DirectiveMessage_SECRET_DISCLOSURE { return nil, nil, nil, nil, errors.New( "secret_disclosure: directive not of secret disclosure type.") } var verifier *tao.Verifier var delegatorStr string // Check directive signer matches policy key. if bytes.Compare( auth.Marshal(policyKey.SigningKey.ToPrincipal()), directive.GetSigner()) == 0 { verifier = policyKey.SigningKey.GetVerifier() delegatorStr = verifier.ToPrincipal().String() } else { // Check if program cert is valid, signed by policy key, // cert public key matches signer and cert name matches speaker // of says statement. cert, err := x509.ParseCertificate(directive.Cert) if err != nil { return nil, nil, nil, nil, errors.New( "error parsing directive program cert") } rootCert := x509.NewCertPool() rootCert.AddCert(policyKey.Cert) verifyOptions := x509.VerifyOptions{Roots: rootCert} _, err = cert.Verify(verifyOptions) if err != nil { return nil, nil, nil, nil, errors.New( "program cert not valid") } verifier, err = tao.FromX509(cert) delegatorStr = cert.Subject.CommonName if err != nil { return nil, nil, nil, nil, err } if bytes.Compare(auth.Marshal(verifier.ToPrincipal()), directive.GetSigner()) != 0 { return nil, nil, nil, nil, errors.New( "secret_disclosure: directive signer doesn't match program key.") } } // Verify signature. ok, err := verifier.Verify(directive.GetSerializedStatement(), SigningContext, directive.GetSignature()) if err != nil { return nil, nil, nil, nil, err } if !ok { return nil, nil, nil, nil, errors.New("secret_disclosure: directive signature check failed.") } // Validate and return statement. statement, err := auth.UnmarshalForm(directive.GetSerializedStatement()) if err != nil { return nil, nil, nil, nil, err } var saysStatement *auth.Says if ptr, ok := statement.(*auth.Says); ok { saysStatement = ptr } else if val, ok := statement.(auth.Says); ok { saysStatement = &val } else { return nil, nil, nil, nil, errors.New("secret_disclosure: directive statement not a 'Says'") } stmtSpeaker, ok := saysStatement.Speaker.(auth.Prin) if !ok { return nil, nil, nil, nil, errors.New("secret_disclosure: directive speaker not a 'Prin'") } if stmtSpeaker.String() != delegatorStr { return nil, nil, nil, nil, errors.New( "secret_disclosure: directive statement speaker does not match signer") } pred, ok := saysStatement.Message.(auth.Pred) if !ok { return nil, nil, nil, nil, errors.New("secret_disclosure: directive message not a 'Pred'") } predName := pred.Name if predName == "" { return nil, nil, nil, nil, errors.New("secret_disclosure: directive predicate name is empty") } if len(pred.Arg) != 2 { return nil, nil, nil, nil, errors.New("secret_disclosure: directive predicate doesn't have 2 terms") } delegateName, ok := pred.Arg[0].(auth.Prin) if !ok { return nil, nil, nil, nil, errors.New( "secret_disclosure: directive delegateName Term not of type auth.Prin.") } serializedObjId, ok := pred.Arg[1].(auth.Bytes) if !ok { return nil, nil, nil, nil, errors.New( "secret_disclosure: directive ObjId Term not of type []byte.") } protectedObjId := po.ObjectIdMessage{} err = proto.Unmarshal(serializedObjId, &protectedObjId) if err != nil { return nil, nil, nil, nil, errors.New( "secret_disclosure: error deserializing protected ObjId.") } return &stmtSpeaker, &delegateName, &predName, &protectedObjId, nil }