// GenerateAttestation uses the signing key to generate an attestation for this // statement. func GenerateAttestation(s *Signer, delegation []byte, stmt auth.Says) (*Attestation, error) { signer := s.ToPrincipal() t := time.Now() if stmt.Time == nil { i := t.UnixNano() stmt.Time = &i } if stmt.Expiration == nil { i := t.Add(365 * 24 * time.Hour).UnixNano() stmt.Expiration = &i } ser := auth.Marshal(stmt) sig, err := s.Sign(ser, AttestationSigningContext) if err != nil { return nil, err } a := &Attestation{ SerializedStatement: ser, Signature: sig, Signer: auth.Marshal(signer), } if len(delegation) > 0 { a.SerializedDelegation = delegation } return a, nil }
// This function returns a secret disclosure directive signed by key with the statement: // 'delegator says delegate predicate protectedObjectId'. func CreateSecretDisclosureDirective(key *tao.Keys, delegator, delegate *auth.Prin, predicate string, protectedObjId *po.ObjectIdMessage) (*DirectiveMessage, error) { // Construct serialized 'says' statement. serializedObjId, err := proto.Marshal(protectedObjId) if err != nil { return nil, err } pred := auth.MakePredicate(predicate, *delegate, serializedObjId) statement := auth.Says{ Speaker: *delegator, Time: nil, // TODO: For now, time and exp not implemented. Expiration: nil, Message: pred, } serializedStatement := auth.Marshal(statement) // Sign serialized statement. signature, err := key.SigningKey.Sign(serializedStatement, SigningContext) if err != nil { return nil, err } // Construct and return directive. directive := &DirectiveMessage{ Type: DirectiveMessage_SECRET_DISCLOSURE.Enum(), SerializedStatement: serializedStatement, Signature: signature, Signer: auth.Marshal(key.SigningKey.ToPrincipal()), Cert: key.Cert.Raw, } return directive, nil }
// Attest requests the Tao host sign a statement on behalf of the caller. The // optional issuer, time and expiration will be given default values if nil. func (tt *TPMTao) Attest(issuer *auth.Prin, start, expiration *int64, message auth.Form) (*Attestation, error) { if issuer == nil { issuer = &tt.name } else if !auth.SubprinOrIdentical(*issuer, tt.name) { return nil, errors.New("invalid issuer in statement") } // TODO(tmroeder): we assume here that the PCRs haven't changed (e.g., been // extended) since this TPMTao was created. If they have, then the PCRs will // be wrong when we extend the principal here with them as the first // component. This doesn't matter at the moment, since we don't currently // support extending the PCRs or clearing them, but it will need to be // changed when we do. stmt := auth.Says{ Speaker: *issuer, Time: start, Expiration: expiration, Message: message, } // This is done in GenerateAttestation, but the TPM attestation is signed // differently, so we do the time calculations here. t := time.Now() if stmt.Time == nil { i := t.UnixNano() stmt.Time = &i } if stmt.Expiration == nil { i := t.Add(365 * 24 * time.Hour).UnixNano() stmt.Expiration = &i } ser := auth.Marshal(stmt) // TODO(tmroeder): check the pcrVals for sanity once we support extending or // clearing the PCRs. sig, _, err := tpm.Quote(tt.tpmfile, tt.aikHandle, ser, tt.pcrNums, tt.srkAuth[:]) if err != nil { return nil, err } // Pull off the extensions from the name to get the bare TPM key for the // signer. signer := auth.Prin{ Type: tt.name.Type, Key: tt.name.Key, } a := &Attestation{ SerializedStatement: ser, Signature: sig, Signer: auth.Marshal(signer), } return a, nil }
// GenerateAttestation uses the signing key to generate an attestation for this // statement. func GenerateAttestation(s *Signer, delegation []byte, stmt auth.Says) (*Attestation, error) { t := time.Now() if stmt.Time == nil { i := t.UnixNano() stmt.Time = &i } if stmt.Expiration == nil { i := t.Add(365 * 24 * time.Hour).UnixNano() stmt.Expiration = &i } ser := auth.Marshal(stmt) sig, err := s.Sign(ser, AttestationSigningContext) if err != nil { return nil, err } a := &Attestation{ SerializedStatement: ser, Signature: sig, SignerType: proto.String("key"), SignerKey: s.GetVerifier().MarshalKey(), } if len(delegation) > 0 { a.SerializedDelegation = delegation } return a, nil }
// StopHostedProgram is the client stub for LinuxHost.StopHostedProgram. func (client LinuxHostAdminClient) StopHostedProgram(subprin auth.SubPrin) error { req := &LinuxHostAdminRPCRequest{ Subprin: auth.Marshal(subprin), } resp := new(LinuxHostAdminRPCResponse) err := client.Call("LinuxHost.StopHostedProgram", req, resp) if err != nil { return err } return nil }
// WaitHostedProgram is the client stub for LinuxHost.WaitHostedProgram. func (client LinuxHostAdminClient) WaitHostedProgram(pid int, subprin auth.SubPrin) (int, error) { req := &LinuxHostAdminRPCRequest{ Pid: proto.Int32(int32(pid)), Subprin: auth.Marshal(subprin), } resp := new(LinuxHostAdminRPCResponse) err := client.Call("LinuxHost.WaitHostedProgram", req, resp) if err != nil { return -1, err } return int(*resp.Status), nil }
// Attest implements part of the Tao interface. func (t *RPC) Attest(issuer *auth.Prin, time, expiration *int64, message auth.Form) (*Attestation, error) { var issuerBytes []byte if issuer != nil { issuerBytes = auth.Marshal(*issuer) } r := &RPCRequest{ Issuer: issuerBytes, Time: time, Expiration: expiration, Data: auth.Marshal(message), } bytes, _, err := t.call(t.serviceName+".Attest", r, wantData) if err != nil { return nil, err } var a Attestation err = proto.Unmarshal(bytes, &a) if err != nil { return nil, err } return &a, nil }
// StartHostedProgram is the server stub for LinuxHost.StartHostedProgram. func (server linuxHostAdminServerStub) StartHostedProgram(r *LinuxHostAdminRPCRequest, s *LinuxHostAdminRPCResponse) error { files := server.oob.SharedFiles() defer func() { for _, f := range files { f.Close() } }() ucred := server.oob.PeerCred() if r.Path == nil { return newError("missing path") } spec := HostedProgramSpec{ Path: *r.Path, Args: r.Args, ContainerArgs: r.ContainerArgs, Dir: *r.Dir, Uid: int(ucred.Uid), Gid: int(ucred.Gid), } // We do allow superuser here, since we trust the oob credentials spec.Superuser = (ucred.Uid == 0 || ucred.Gid == 0) if r.Stdin != nil { if int(*r.Stdin) >= len(files) { return newError("missing stdin") } spec.Stdin = files[*r.Stdin] } if r.Stdout != nil { if int(*r.Stdout) >= len(files) { return newError("missing stdout") } spec.Stdout = files[*r.Stdout] } if r.Stderr != nil { if int(*r.Stderr) >= len(files) { return newError("missing stderr") } spec.Stderr = files[*r.Stderr] } subprin, pid, err := server.lh.StartHostedProgram(spec) if err != nil { return err } s.Child = make([]*LinuxHostAdminRPCHostedProgram, 1) s.Child[0] = &LinuxHostAdminRPCHostedProgram{ Subprin: auth.Marshal(subprin), Pid: proto.Int32(int32(pid)), } return nil }
func (g *DatalogGuard) assert(f auth.Form) error { rule, idx, err := g.findRule(f) if err != nil { return err } if idx >= 0 { return nil } err = g.dl.Assert(rule) if err != nil { return err } g.db.Rules = append(g.db.Rules, auth.Marshal(f)) return nil }
// ListHostedPrograms is the server stub for LinuxHost.ListHostedPrograms. func (server linuxHostAdminServerStub) ListHostedPrograms(r *LinuxHostAdminRPCRequest, s *LinuxHostAdminRPCResponse) error { names, pids, err := server.lh.ListHostedPrograms() if err != nil { return err } if len(names) != len(pids) { return newError("invalid response") } s.Child = make([]*LinuxHostAdminRPCHostedProgram, len(names)) for i := range names { s.Child[i] = &LinuxHostAdminRPCHostedProgram{ Subprin: auth.Marshal(names[i]), Pid: proto.Int32(int32(pids[i])), } } return nil }
// ExtendTaoName implements part of the Tao interface. func (t *RPC) ExtendTaoName(subprin auth.SubPrin) error { r := &RPCRequest{Data: auth.Marshal(subprin)} _, _, err := t.call(t.serviceName+".ExtendTaoName", r, wantNothing) return err }
// Attest requests the Tao host seal a statement on behalf of the caller. The // optional issuer, time and expiration will be given default values if nil. func (tt *TPM2Tao) Attest(issuer *auth.Prin, start, expiration *int64, message auth.Form) (*Attestation, error) { fmt.Fprintf(os.Stderr, "About to load the quote key in attest\n") qh, err := tt.loadQuote() if err != nil { return nil, err } defer tpm2.FlushContext(tt.rw, qh) if issuer == nil { issuer = &tt.name } else if !auth.SubprinOrIdentical(*issuer, tt.name) { return nil, errors.New("invalid issuer in statement") } // TODO(tmroeder): we assume here that the PCRs haven't changed (e.g., been // extended) since this TPM2Tao was created. If they have, then the PCRs will // be wrong when we extend the principal here with them as the first // component. This doesn't matter at the moment, since we don't currently // support extending the PCRs or clearing them, but it will need to be // changed when we do. stmt := auth.Says{ Speaker: *issuer, Time: start, Expiration: expiration, Message: message, } // This is done in GenerateAttestation, but the TPM attestation is sealed // differently, so we do the time calculations here. t := time.Now() if stmt.Time == nil { i := t.UnixNano() stmt.Time = &i } if stmt.Expiration == nil { i := t.Add(365 * 24 * time.Hour).UnixNano() stmt.Expiration = &i } ser := auth.Marshal(stmt) var pcrVals [][]byte toQuote, err := tpm2.FormatTpm2Quote(ser, tt.pcrs, pcrVals) if err != nil { return nil, errors.New("Can't format tpm2 Quote") } // TODO(tmroeder): check the pcrVals for sanity once we support extending or // clearing the PCRs. quote_struct, sig, err := tpm2.Quote(tt.rw, qh, "", tt.password, toQuote, tt.pcrs, uint16(tpm2.AlgTPM_ALG_NULL)) if err != nil { return nil, err } fmt.Printf("toQuote: %x\n", toQuote) fmt.Printf("Quote: %x\n", quote_struct) fmt.Printf("sig: %x\n", sig) quoteKey, err := x509.MarshalPKIXPublicKey(tt.verifier) if err != nil { return nil, err } // TODO(kwalsh) remove Tpm2QuoteStructure from Attestation structure a := &Attestation{ SerializedStatement: ser, Signature: sig, SignerType: proto.String("tpm2"), SignerKey: quoteKey, Tpm2QuoteStructure: quote_struct, } return a, nil }
// GetTaoName is the server stub for Tao.GetTaoName. func (server linuxHostTaoServerStub) GetTaoName(r *RPCRequest, s *RPCResponse) error { s.Data = auth.Marshal(server.lh.GetTaoName(server.child)) return nil }
// HostName is the server stub for LinuxHost.HostName. func (server linuxHostAdminServerStub) HostName(r *LinuxHostAdminRPCRequest, s *LinuxHostAdminRPCResponse) error { prin := server.lh.HostName() s.Prin = auth.Marshal(prin) return nil }
// StartHostedProgram is the server stub for LinuxHost.StartHostedProgram. func (server linuxHostAdminServerStub) StartHostedProgram(r *LinuxHostAdminRPCRequest, s *LinuxHostAdminRPCResponse) error { defer RecoverTPMResources() files := server.oob.SharedFiles() defer func() { for _, f := range files { if f != nil { f.Close() } } }() ucred := server.oob.PeerCred() if ucred == nil { // TODO(kwalsh): Some kernels don't pass a ucred. Figure this // out later... ucred = &syscall.Ucred{0, 0, 0} } if r.Path == nil { return newError("missing path") } spec := HostedProgramSpec{ Path: *r.Path, Args: r.Args, ContainerType: *r.ContainerType, ContainerArgs: r.ContainerArgs, Dir: *r.Dir, Uid: int(ucred.Uid), Gid: int(ucred.Gid), } // We do allow superuser here, since we trust the oob credentials spec.Superuser = (ucred.Uid == 0 || ucred.Gid == 0) if r.Stdin != nil { if int(*r.Stdin) >= len(files) { return newError("missing stdin") } spec.Stdin = files[*r.Stdin] files[*r.Stdin] = nil } if r.Stdout != nil { if int(*r.Stdout) >= len(files) { return newError("missing stdout") } spec.Stdout = files[*r.Stdout] files[*r.Stdout] = nil } if r.Stderr != nil { if int(*r.Stderr) >= len(files) { return newError("missing stderr") } spec.Stderr = files[*r.Stderr] files[*r.Stderr] = nil } subprin, pid, err := server.lh.StartHostedProgram(spec) if err != nil { spec.Cleanup() return err } s.Child = make([]*LinuxHostAdminRPCHostedProgram, 1) s.Child[0] = &LinuxHostAdminRPCHostedProgram{ Subprin: auth.Marshal(subprin), Pid: proto.Int32(int32(pid)), } return nil }
func generatePolicyKeyAndSignedDirective(params Params) (*tao.Keys, *DirectiveMessage, error) { var programName auth.Term if params.Delegate != nil { programName = params.Delegate } else { programName = Delegate } var serializedObjectId auth.Term if params.SerializedObjectId != nil { serializedObjectId = params.SerializedObjectId } else { bytes, err := proto.Marshal(&ProtectedObjectId) if err != nil { return nil, nil, err } serializedObjectId = auth.Bytes(bytes) } terms := []auth.Term{programName, serializedObjectId} if params.CanReadTerms != nil { terms = params.CanReadTerms } var canRead auth.Form if params.CanRead != nil { canRead = params.CanRead } else { canRead = auth.Pred{ Name: ReadPredicate, Arg: terms, } } policyKey, err := tao.NewTemporaryKeys(tao.Signing) if err != nil { return nil, nil, err } info := x509Info name := policyKey.SigningKey.ToPrincipal().String() info.CommonName = &name subject := tao.NewX509Name(&info) policyKey.Cert, err = policyKey.SigningKey.CreateSelfSignedX509(subject) if err != nil { return nil, nil, err } var says auth.Form if params.Says != nil { says = params.Says } else { says = auth.Says{ Speaker: policyKey.SigningKey.ToPrincipal(), Time: nil, Expiration: nil, Message: canRead, } } serializedSays := auth.Marshal(says) var directiveType *DirectiveMessageDirectiveType if params.DirectiveType != nil { directiveType = params.DirectiveType } else { directiveType = DirectiveMessage_SECRET_DISCLOSURE.Enum() } var signature []byte if params.Signature != nil { signature = params.Signature } else { signature, err = policyKey.SigningKey.Sign(serializedSays, SigningContext) if err != nil { return nil, nil, err } } var signer []byte if params.Signer != nil { signer = params.Signer } else { signer = auth.Marshal(policyKey.SigningKey.ToPrincipal()) } directive := &DirectiveMessage{ Type: directiveType, SerializedStatement: serializedSays, Signature: signature, Signer: signer, } return policyKey, directive, 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 }