github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/apps/tao_admin/tao_admin.go (about)

     1  // Copyright (c) 2014, Kevin Walsh.  All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"crypto/rand"
    19  	"crypto/rsa"
    20  	"crypto/sha256"
    21  	"flag"
    22  	"fmt"
    23  	"io"
    24  	"io/ioutil"
    25  	"os"
    26  	"path"
    27  	"strconv"
    28  	"strings"
    29  	"syscall"
    30  	"text/tabwriter"
    31  	"time"
    32  
    33  	"github.com/golang/protobuf/proto"
    34  	"github.com/google/go-tpm/tpm"
    35  	"github.com/jlmucb/cloudproxy/go/tao"
    36  	"github.com/jlmucb/cloudproxy/go/tao/auth"
    37  	"github.com/jlmucb/cloudproxy/go/util/options"
    38  	// "github.com/golang/crypto/ssh/terminal"
    39  	"golang.org/x/crypto/ssh/terminal"
    40  )
    41  
    42  var opts = []options.Option{
    43  	// Flags for all/most commands
    44  	{"tao_domain", "", "<dir>", "Tao domain configuration directory", "all"},
    45  	{"quiet", false, "", "Be more quiet", "all"},
    46  	{"pass", "", "<password>", "Password for policy private key (Testing only!)", "all"},
    47  
    48  	// Flags for miscellaneous commands
    49  	{"config_template", "", "<file>", "Configuration template", "init,newsoft,policy"},
    50  
    51  	// Flags for 'newsoft', used to create soft tao keys.
    52  	{"soft_pass", "", "<pass>", "A password to encrypt the new soft Tao keys", "newsoft"},
    53  
    54  	// Flags for 'init'. If these flags are specified, a public cached version
    55  	// of the domain will also be created.
    56  	{"pub_domain_address", "", "<adddress>", "Address of TaoCA for public cached domain", "init"},
    57  	{"pub_domain_network", "tcp", "<network>", "Network of TaoCA for public cached domain", "init"},
    58  	{"pub_domain_ttl", 30 * time.Second, "<duration>", "Time-to-live of cached policy", "init"},
    59  
    60  	// Flags for 'policy' command, used to change and query the policy rules
    61  	// used for principal authorization. The strings passed to these rules
    62  	// depend on the Guard given in the domain/tao.
    63  	{"canexecute", "", "<prog>", "Path of a program to be authorized to execute", "policy"},
    64  	{"retractcanexecute", "", "<prog>", "Path of a program to retract authorization to execute", "policy"},
    65  	{"add", "", "<rule>", "A policy rule to be added", "policy"},
    66  	{"retract", "", "<rule>", "A policy rule to be retracted", "policy"},
    67  	{"show", false, "", "Print the policy after all other policy commands have executed", "policy"},
    68  	{"query", "", "<rule>", "A policy query to be checked", "policy"},
    69  	{"clear", false, "", "Clear all policy rules before other changes", "policy"},
    70  	{"add_programs", false, "", "Add the program hashes to the policy", "policy"},
    71  	{"add_containers", false, "", "Add the container hashes to the policy", "policy"},
    72  	{"add_host", false, "", "Add the host to the policy", "policy"},
    73  	{"add_vms", false, "", "Add VMs to the policy", "policy"},
    74  	{"add_linux_host", false, "", "Add LinuxHost to the policy", "policy"},
    75  	{"add_guard", false, "", "Add a trusted guard to the policy", "policy"},
    76  	{"add_tpm", false, "", "Add trusted platform module to the policy", "policy"},
    77  	{"add_tpm2", false, "", "Add trusted platform module 2.0 to the policy", "policy"},
    78  
    79  	// Flags for 'user' command, used to create new user keys.
    80  	{"user_key_details", "", "<file>", "File containing an X509Details proto", "user"},
    81  	{"user_key_path", "usercreds", "<file>", "Key path", "user"},
    82  	{"user_pass", "", "<pass>", "A password for the new user (Testing only!)", "user"},
    83  
    84  	// Flags for the 'principal' option, used to compute principal hashes.
    85  	{"program", "", "<file>", "Path to a program to be hashed", "principal"},
    86  	{"container", "", "<file>", "Path to a container to be hashed", "principal"},
    87  	{"tpm", false, "", "Show the TPM principal name", "principal"},
    88  	{"soft", "", "<dir>", "Path to a linux host directory with a soft Tao key", "principal"},
    89  }
    90  
    91  func init() {
    92  	options.Add(opts...)
    93  }
    94  
    95  var noise = ioutil.Discard
    96  
    97  func help() {
    98  	w := new(tabwriter.Writer)
    99  	w.Init(os.Stderr, 4, 0, 2, ' ', 0)
   100  	av0 := path.Base(os.Args[0])
   101  
   102  	fmt.Fprintf(w, "Administrative utility for Tao Domain.\n")
   103  	fmt.Fprintf(w, "Usage:\n")
   104  	fmt.Fprintf(w, "  %s newsoft [options] <dir>\t Create a soft tao key set\n", av0)
   105  	fmt.Fprintf(w, "  %s init [options]\t Initialize a new domain\n", av0)
   106  	fmt.Fprintf(w, "  %s policy [options]\t Manage authorization policies\n", av0)
   107  	fmt.Fprintf(w, "  %s user [options]\t Create user keys\n", av0)
   108  	fmt.Fprintf(w, "  %s principal [options]\t Display principal names/hashes\n", av0)
   109  	fmt.Fprintf(w, "\n")
   110  
   111  	categories := []options.Category{
   112  		{"all", "Basic options for most commands"},
   113  		{"newsoft", "Options for 'newsoft' command"},
   114  		{"init", "Options for 'init' command"},
   115  		{"policy", "Options for 'policy' command"},
   116  		{"user", "Options for 'user' command"},
   117  		{"principal", "Options for 'principal' command"},
   118  		{"logging", "Options to control log output"},
   119  	}
   120  	options.ShowRelevant(w, categories...)
   121  
   122  	w.Flush()
   123  }
   124  
   125  func main() {
   126  	flag.Usage = help
   127  
   128  	// Get options before the command verb
   129  	flag.Parse()
   130  	// Get command verb
   131  	cmd := "help"
   132  	if flag.NArg() > 0 {
   133  		cmd = flag.Arg(0)
   134  	}
   135  	// Get options after the command verb
   136  	if flag.NArg() > 1 {
   137  		flag.CommandLine.Parse(flag.Args()[1:])
   138  	}
   139  
   140  	if !*options.Bool["quiet"] {
   141  		noise = os.Stdout
   142  	}
   143  
   144  	switch cmd {
   145  	case "help":
   146  		help()
   147  	case "newsoft":
   148  		createSoftTaoKeys()
   149  	case "init":
   150  		createDomain()
   151  	case "policy":
   152  		managePolicy()
   153  	case "user":
   154  		createUserKeys()
   155  	case "principal":
   156  		outputPrincipal()
   157  	default:
   158  		options.Usage("Unrecognized command: %s", cmd)
   159  	}
   160  }
   161  
   162  // Read the tao_admin domain template for default configuration info.
   163  var savedTemplate *tao.DomainTemplate
   164  
   165  func template() *tao.DomainTemplate {
   166  	if savedTemplate == nil {
   167  		configTemplate := *options.String["config_template"]
   168  		if configTemplate == "" {
   169  			options.Usage("Must supply -config_template")
   170  		}
   171  		savedTemplate = new(tao.DomainTemplate)
   172  		pbtext, err := ioutil.ReadFile(configTemplate)
   173  		options.FailIf(err, "Can't read config template")
   174  		err = proto.UnmarshalText(string(pbtext), savedTemplate)
   175  		options.FailIf(err, "Can't parse config template: %s", configTemplate)
   176  	}
   177  	return savedTemplate
   178  }
   179  
   180  func domainPath() string {
   181  	if path := *options.String["tao_domain"]; path != "" {
   182  		return path
   183  	}
   184  	if path := os.Getenv("TAO_DOMAIN"); path != "" {
   185  		return path
   186  	}
   187  	options.Usage("Must supply -tao_domain or set $TAO_DOMAIN")
   188  	return ""
   189  }
   190  
   191  func configPath() string {
   192  	return path.Join(domainPath(), "tao.config")
   193  }
   194  
   195  func managePolicy() {
   196  
   197  	// Handle queries first
   198  	if query := *options.String["query"]; query != "" {
   199  		queryGuard(query)
   200  		return
   201  	}
   202  
   203  	// Load domain
   204  	pwd := getKey("domain policy key password", "pass")
   205  	domain, err := tao.LoadDomain(configPath(), pwd)
   206  	options.FailIf(err, "Can't load domain")
   207  
   208  	// Clear all the policy stored by the Guard.
   209  	if *options.Bool["clear"] {
   210  		domain.Guard.Clear()
   211  		err := domain.Save()
   212  		options.FailIf(err, "Can't save domain")
   213  	}
   214  
   215  	// Add permissions
   216  	if canExecute := *options.String["canexecute"]; canExecute != "" {
   217  		host := template().GetHostName()
   218  		addExecute(canExecute, host, domain)
   219  	}
   220  	if add := *options.String["add"]; add != "" {
   221  		fmt.Fprintf(noise, "Adding policy rule: %s\n", add)
   222  		err := domain.Guard.AddRule(add)
   223  		options.FailIf(err, "Can't add rule to domain")
   224  		err = domain.Save()
   225  		options.FailIf(err, "Can't save domain")
   226  	}
   227  	if *options.Bool["add_programs"] {
   228  		host := template().GetHostName()
   229  		addProgramRules(host, domain)
   230  	}
   231  	if *options.Bool["add_containers"] {
   232  		host := template().GetHostName()
   233  		addContainerRules(host, domain)
   234  	}
   235  	if domain.Config.DomainInfo.GetGuardType() == "Datalog" {
   236  		if *options.Bool["add_vms"] {
   237  			addVMRules(domain)
   238  		}
   239  		if *options.Bool["add_linux_host"] {
   240  			addLinuxHostRules(domain)
   241  		}
   242  		if *options.Bool["add_host"] {
   243  			host := template().GetHostName()
   244  			addHostRules(host, domain)
   245  		}
   246  		if *options.Bool["add_guard"] {
   247  			addGuardRules(domain)
   248  		}
   249  		if *options.Bool["add_tpm"] {
   250  			addTPMRules(domain)
   251  		}
   252  		if *options.Bool["add_tpm2"] {
   253  			addTPM2Rules(domain)
   254  		}
   255  	}
   256  
   257  	// Retract permissions
   258  	if retract := *options.String["retract"]; retract != "" {
   259  		fmt.Fprintf(noise, "Retracting policy rule: %s\n", retract)
   260  		err := domain.Guard.RetractRule(retract)
   261  		options.FailIf(err, "Can't retract rule from domain")
   262  		err = domain.Save()
   263  		options.FailIf(err, "Can't save domain")
   264  	}
   265  	if retractCanExecute := *options.String["retractcanexecute"]; retractCanExecute != "" {
   266  		host := template().GetHostName()
   267  		retractExecute(retractCanExecute, host, domain)
   268  	}
   269  
   270  	// Print the policy after all commands are executed.
   271  	if *options.Bool["show"] {
   272  		fmt.Print(domain.Guard.String())
   273  	}
   274  }
   275  
   276  func hash(p string) ([]byte, error) {
   277  	// If the path is not absolute, then try $GOPATH/bin/path if it exists.
   278  	realPath := p
   279  	if !path.IsAbs(p) {
   280  		// TODO(kwalsh) handle case where GOPATH has multiple paths
   281  		gopath := os.Getenv("GOPATH")
   282  		if gopath != "" {
   283  			realPath = path.Join(path.Join(gopath, "bin"), realPath)
   284  		}
   285  	}
   286  	file, err := os.Open(realPath)
   287  	if err != nil {
   288  		return nil, err
   289  	}
   290  	hasher := sha256.New()
   291  	_, err = io.Copy(hasher, file)
   292  	options.FailIf(err, "Can't hash file")
   293  	return hasher.Sum(nil), nil
   294  }
   295  
   296  func makeHostPrin(host string) auth.Prin {
   297  	if host == "" {
   298  		options.Usage("The domain template must contain a Tao host in host_name")
   299  	}
   300  	var prin auth.Prin
   301  	_, err := fmt.Sscanf(host, "%v", &prin)
   302  	options.FailIf(err, "Can't create host principal")
   303  	return prin
   304  }
   305  
   306  func makeProgramSubPrin(prog string) (auth.SubPrin, error) {
   307  	// TODO(tmroeder): This assumes no IDs, and it assumes linux hosts.
   308  	id := uint(0)
   309  	h, err := hash(prog)
   310  	if err != nil {
   311  		return auth.SubPrin{}, err
   312  	}
   313  	return tao.FormatProcessSubprin(id, h), nil
   314  }
   315  
   316  func makeVMSubPrin(prog string) (auth.SubPrin, error) {
   317  	// TODO(tmroeder): This assumes no IDs, and it assumes linux hosts.
   318  	id := uint(0)
   319  	h, err := hash(prog)
   320  	if err != nil {
   321  		return auth.SubPrin{}, err
   322  	}
   323  	return tao.FormatCoreOSSubprin(id, h), nil
   324  }
   325  
   326  func makeLinuxHostSubPrin(prog string) (auth.SubPrin, error) {
   327  	// TODO(tmroeder): This assumes no IDs, and it assumes linux hosts.
   328  	id := uint(0)
   329  	h, err := hash(prog)
   330  	if err != nil {
   331  		return auth.SubPrin{}, err
   332  	}
   333  	return tao.FormatLinuxHostSubprin(id, h), nil
   334  }
   335  
   336  func makeContainerSubPrin(prog string) (auth.SubPrin, error) {
   337  	// TODO(tmroeder): This assumes no IDs
   338  	id := uint(0)
   339  	h, err := hash(prog)
   340  	if err != nil {
   341  		return auth.SubPrin{}, err
   342  	}
   343  	return tao.FormatDockerSubprin(id, h), nil
   344  }
   345  
   346  // TODO(tmroeder): The keys for the TPM2 have to already be created here so
   347  // that we can produce the name of the TPM2 key. For now, this just returns a
   348  // dummy key.
   349  func makeTPM2Prin(tpmPath string, pcrNums []int) auth.Prin {
   350  	// TODO(tmroeder): The following key is generated on the spot. This should
   351  	// instead be the key read from a file.
   352  	privKey, err := rsa.GenerateKey(rand.Reader, 2048)
   353  	options.FailIf(err, "Can't generate a temp RSA key")
   354  
   355  	// Open a connection to the TPM.
   356  	tpmFile, err := os.OpenFile(tpmPath, os.O_RDWR, 0)
   357  	options.FailIf(err, "Can't access TPM")
   358  
   359  	pcrVals, err := tao.ReadTPM2PCRs(tpmFile, pcrNums)
   360  	tpmFile.Close()
   361  	options.FailIf(err, "Can't get the PCRs from a TPM 2.0")
   362  
   363  	prin, err := tao.MakeTPM2Prin(&privKey.PublicKey, pcrNums, pcrVals)
   364  	options.FailIf(err, "Can't create a TPM2 principal")
   365  	return prin
   366  }
   367  
   368  func makeTPMPrin(tpmPath, aikFile string, pcrNums []int) auth.Prin {
   369  	// Read AIK blob (TPM's public key).
   370  	aikblob, err := ioutil.ReadFile(aikFile)
   371  	options.FailIf(err, "Can't read TPM aik file")
   372  
   373  	verifier, err := tpm.UnmarshalRSAPublicKey(aikblob)
   374  	options.FailIf(err, "Can't parse TPM key")
   375  
   376  	// Open a connection to the TPM.
   377  	tpmFile, err := os.OpenFile(tpmPath, os.O_RDWR, 0)
   378  	options.FailIf(err, "Can't access TPM")
   379  
   380  	// Read registers corresponding to pcrNums.
   381  	pcrVals, err := tao.ReadPCRs(tpmFile, pcrNums)
   382  	tpmFile.Close()
   383  	options.FailIf(err, "Can't read PCRs from TPM")
   384  
   385  	// Construct a TPM principal.
   386  	prin, err := tao.MakeTPMPrin(verifier, pcrNums, pcrVals)
   387  	options.FailIf(err, "Can't create TPM principal")
   388  
   389  	return prin
   390  }
   391  
   392  func getKey(prompt, name string) []byte {
   393  	if input := *options.String[name]; input != "" {
   394  		fmt.Fprintf(os.Stderr, "Warning: Passwords on the command line are not secure. Use -%s option only for testing.\n", name)
   395  		return []byte(input)
   396  	} else {
   397  		// Get the password from the user.
   398  		fmt.Print(prompt + ": ")
   399  		pwd, err := terminal.ReadPassword(syscall.Stdin)
   400  		options.FailIf(err, "Can't get password")
   401  		fmt.Println()
   402  		return pwd
   403  	}
   404  }
   405  
   406  func createSoftTaoKeys() {
   407  	dt := template()
   408  
   409  	args := flag.Args()
   410  	if len(args) != 1 {
   411  		options.Usage("Must supply a path for the new key set")
   412  	}
   413  	keypath := args[0]
   414  
   415  	pwd := getKey("soft tao key password", "soft_pass")
   416  
   417  	k, err := tao.NewOnDiskPBEKeys(tao.Signing|tao.Crypting|tao.Deriving, pwd, keypath, tao.NewX509Name(dt.Config.X509Info))
   418  	options.FailIf(err, "Can't create keys")
   419  
   420  	fmt.Println(k.VerifyingKey.ToPrincipal())
   421  }
   422  
   423  func createDomain() {
   424  	dt := template()
   425  	if dt.Config.DomainInfo.GetPolicyKeysPath() == "" {
   426  		options.Usage("Must supply a policy_keys_path in the domain configuration")
   427  	}
   428  
   429  	pwd := getKey("domain policy key password", "pass")
   430  
   431  	domain, err := tao.CreateDomain(*dt.Config, configPath(), pwd)
   432  	options.FailIf(err, "Can't create domain")
   433  
   434  	if domain.Config.DomainInfo.GetGuardType() == "Datalog" {
   435  		// Add any rules specified in the domain template.
   436  		for _, rule := range dt.DatalogRules {
   437  			err := domain.Guard.AddRule(rule)
   438  			options.FailIf(err, "Can't add rule to domain")
   439  		}
   440  	} else if domain.Config.DomainInfo.GetGuardType() == "ACLs" {
   441  		for _, rule := range dt.AclRules {
   442  			err := domain.Guard.AddRule(rule)
   443  			options.FailIf(err, "Can't add rule to domain")
   444  		}
   445  	}
   446  
   447  	err = domain.Save()
   448  	options.FailIf(err, "Can't save domain")
   449  
   450  	// Optionally, create a public cached domain.
   451  	if addr := *options.String["pub_domain_address"]; addr != "" {
   452  		net := *options.String["pub_domain_network"]
   453  		ttl := *options.Duration["pub_domain_ttl"]
   454  		_, err = domain.CreatePublicCachedDomain(net, addr, int64(ttl))
   455  		options.FailIf(err, "Can't create public cached domain")
   456  	}
   457  }
   458  
   459  func queryGuard(query string) {
   460  	domain, err := tao.LoadDomain(configPath(), nil)
   461  	options.FailIf(err, "Can't load domain")
   462  
   463  	ok, err := domain.Guard.Query(query)
   464  	options.FailIf(err, "Can't process query")
   465  	if ok {
   466  		fmt.Println("The policy implies the statement.")
   467  	} else {
   468  		fmt.Println("The policy does not imply the statement")
   469  	}
   470  }
   471  
   472  func addExecute(path, host string, domain *tao.Domain) {
   473  	prin := makeHostPrin(host)
   474  	subprin, err := makeProgramSubPrin(path)
   475  	if err == nil {
   476  		prog := prin.MakeSubprincipal(subprin)
   477  		fmt.Fprintf(noise, "Authorizing program to execute:\n"+
   478  			"  path: %s\n"+
   479  			"  host: %s\n"+
   480  			"  name: %s\n", path, prin, subprin)
   481  		err := domain.Guard.Authorize(prog, "Execute", nil)
   482  		options.FailIf(err, "Can't authorize program in domain")
   483  		err = domain.Save()
   484  		options.FailIf(err, "Can't save domain")
   485  	}
   486  }
   487  
   488  func retractExecute(path, host string, domain *tao.Domain) {
   489  	prin := makeHostPrin(host)
   490  	subprin, err := makeProgramSubPrin(path)
   491  	if err == nil {
   492  		prog := prin.MakeSubprincipal(subprin)
   493  		fmt.Fprintf(noise, "Retracting program authorization to execute:\n"+
   494  			"  path: %s\n"+
   495  			"  host: %s\n"+
   496  			"  name: %s\n", path, prin, subprin)
   497  		err := domain.Guard.Retract(prog, "Execute", nil)
   498  		options.FailIf(err, "Can't retract program authorization from domain")
   499  	}
   500  }
   501  
   502  func addACLPrograms(host string, domain *tao.Domain) {
   503  	if host == "" {
   504  		return
   505  	}
   506  	dt := template()
   507  	prin := makeHostPrin(host)
   508  	for _, p := range dt.ProgramPaths {
   509  		subprin, err := makeProgramSubPrin(p)
   510  		if err != nil {
   511  			continue
   512  		}
   513  		prog := prin.MakeSubprincipal(subprin)
   514  		err = domain.Guard.Authorize(prog, "Execute", nil)
   515  		options.FailIf(err, "Can't authorize program in domain")
   516  	}
   517  	for _, vm := range dt.VmPaths {
   518  		vmPrin, err := makeVMSubPrin(vm)
   519  		if err != nil {
   520  			continue
   521  		}
   522  		for _, lh := range dt.LinuxHostPaths {
   523  			lhPrin, err := makeLinuxHostSubPrin(lh)
   524  			if err != nil {
   525  				continue
   526  			}
   527  			var lsp auth.SubPrin
   528  			lsp = append(lsp, vmPrin...)
   529  			lsp = append(lsp, lhPrin...)
   530  			lprog := prin.MakeSubprincipal(lsp)
   531  			err = domain.Guard.Authorize(lprog, "Execute", nil)
   532  			options.FailIf(err, "Can't authorize program in domain")
   533  
   534  			for _, p := range dt.ProgramPaths {
   535  				subprin, err := makeProgramSubPrin(p)
   536  				if err != nil {
   537  					continue
   538  				}
   539  				var sp auth.SubPrin
   540  				sp = append(sp, vmPrin...)
   541  				sp = append(sp, lhPrin...)
   542  				sp = append(sp, subprin...)
   543  				prog := prin.MakeSubprincipal(sp)
   544  				err = domain.Guard.Authorize(prog, "Execute", nil)
   545  				options.FailIf(err, "Can't authorize program in domain")
   546  
   547  				var gsp auth.SubPrin
   548  				gsp = append(gsp, vmPrin...)
   549  				gsp = append(gsp, lhPrin...)
   550  				gsp = append(gsp, domain.Guard.Subprincipal()...)
   551  				gsp = append(gsp, subprin...)
   552  				gprog := prin.MakeSubprincipal(gsp)
   553  				err = domain.Guard.Authorize(gprog, "Execute", nil)
   554  				options.FailIf(err, "Can't authorize program in domain")
   555  			}
   556  		}
   557  	}
   558  }
   559  
   560  func addProgramRules(host string, domain *tao.Domain) {
   561  	dt := template()
   562  	if domain.Config.DomainInfo.GetGuardType() == "Datalog" {
   563  		// Add the hashes of any programs given in the template.
   564  		for _, p := range dt.ProgramPaths {
   565  			prin, err := makeProgramSubPrin(p)
   566  			if err != nil {
   567  				continue
   568  			}
   569  			pt := auth.PrinTail{Ext: prin}
   570  			pred := auth.MakePredicate(dt.GetProgramPredicateName(), pt)
   571  			err = domain.Guard.AddRule(fmt.Sprint(pred))
   572  			options.FailIf(err, "Can't add rule to domain")
   573  		}
   574  	} else if domain.Config.DomainInfo.GetGuardType() == "ACLs" {
   575  		addACLPrograms(host, domain)
   576  	}
   577  	err := domain.Save()
   578  	options.FailIf(err, "Can't save domain")
   579  }
   580  
   581  func addContainerRules(host string, domain *tao.Domain) {
   582  	dt := template()
   583  	if domain.Config.DomainInfo.GetGuardType() == "Datalog" {
   584  		for _, c := range dt.ContainerPaths {
   585  			prin, err := makeContainerSubPrin(c)
   586  			if err != nil {
   587  				continue
   588  			}
   589  			pt := auth.PrinTail{Ext: prin}
   590  			pred := auth.MakePredicate(dt.GetContainerPredicateName(), pt)
   591  			err = domain.Guard.AddRule(fmt.Sprint(pred))
   592  			options.FailIf(err, "Can't add rule to domain")
   593  		}
   594  	} else if domain.Config.DomainInfo.GetGuardType() == "ACLs" && host != "" {
   595  		prin := makeHostPrin(host)
   596  		for _, p := range dt.ContainerPaths {
   597  			subprin, err := makeContainerSubPrin(p)
   598  			if err != nil {
   599  				continue
   600  			}
   601  			prog := prin.MakeSubprincipal(subprin)
   602  			err = domain.Guard.Authorize(prog, "Execute", nil)
   603  			options.FailIf(err, "Can't authorize program in domain")
   604  		}
   605  	}
   606  	err := domain.Save()
   607  	options.FailIf(err, "Can't save domain")
   608  }
   609  
   610  func addVMRules(domain *tao.Domain) {
   611  	dt := template()
   612  	for _, c := range dt.VmPaths {
   613  		prin, err := makeVMSubPrin(c)
   614  		if err != nil {
   615  			continue
   616  		}
   617  		pt := auth.PrinTail{Ext: prin}
   618  		pred := auth.MakePredicate(dt.GetVmPredicateName(), pt)
   619  		err = domain.Guard.AddRule(fmt.Sprint(pred))
   620  		options.FailIf(err, "Can't add rule to domain")
   621  	}
   622  	// The ACLs need the full name, so that only happens for containers and
   623  	// programs.
   624  	err := domain.Save()
   625  	options.FailIf(err, "Can't save domain")
   626  }
   627  
   628  func addLinuxHostRules(domain *tao.Domain) {
   629  	dt := template()
   630  	for _, c := range dt.LinuxHostPaths {
   631  		prin, err := makeLinuxHostSubPrin(c)
   632  		if err != nil {
   633  			continue
   634  		}
   635  		pt := auth.PrinTail{Ext: prin}
   636  		pred := auth.MakePredicate(dt.GetLinuxHostPredicateName(), pt)
   637  		err = domain.Guard.AddRule(fmt.Sprint(pred))
   638  		options.FailIf(err, "Can't add rule to domain")
   639  	}
   640  	// The ACLs need the full name, so that only happens for containers and
   641  	// programs.
   642  	err := domain.Save()
   643  	options.FailIf(err, "Can't save domain")
   644  }
   645  
   646  func addHostRules(host string, domain *tao.Domain) {
   647  	if host == "" {
   648  		return
   649  	}
   650  	dt := template()
   651  	prin := makeHostPrin(host)
   652  	pred := auth.MakePredicate(dt.GetHostPredicateName(), prin)
   653  	err := domain.Guard.AddRule(fmt.Sprint(pred))
   654  	options.FailIf(err, "Can't add rule to domain")
   655  	err = domain.Save()
   656  	options.FailIf(err, "Can't save domain")
   657  }
   658  
   659  func addGuardRules(domain *tao.Domain) {
   660  	dt := template()
   661  	subprin := domain.Guard.Subprincipal()
   662  	pt := auth.PrinTail{Ext: subprin}
   663  	pred := auth.Pred{
   664  		Name: dt.GetGuardPredicateName(),
   665  		Arg:  []auth.Term{pt},
   666  	}
   667  	err := domain.Guard.AddRule(fmt.Sprint(pred))
   668  	options.FailIf(err, "Can't add rule to domain")
   669  	err = domain.Save()
   670  	options.FailIf(err, "Can't save domain")
   671  }
   672  
   673  func addTPMRules(domain *tao.Domain) {
   674  	dt := template()
   675  	tpmPath, aikFile, pcrNums := getTPMConfig()
   676  	prin := makeTPMPrin(tpmPath, aikFile, pcrNums)
   677  
   678  	// TrustedOS predicate from PCR principal tail.
   679  	prinPCRs := auth.PrinTail{Ext: prin.Ext}
   680  	predTrustedOS := auth.MakePredicate(dt.GetOsPredicateName(), prinPCRs)
   681  	err := domain.Guard.AddRule(fmt.Sprint(predTrustedOS))
   682  	options.FailIf(err, "Can't add rule to domain")
   683  
   684  	// TrustedTPM predicate from TPM principal.
   685  	prin.Ext = nil
   686  	predTrustedTPM := auth.MakePredicate(dt.GetTpmPredicateName(), prin)
   687  	err = domain.Guard.AddRule(fmt.Sprint(predTrustedTPM))
   688  	options.FailIf(err, "Can't add rule to domain")
   689  
   690  	err = domain.Save()
   691  	options.FailIf(err, "Can't save domain")
   692  }
   693  
   694  func addTPM2Rules(domain *tao.Domain) {
   695  	dt := template()
   696  	tpmPath, pcrNums := getTPM2Config()
   697  	prin := makeTPM2Prin(tpmPath, pcrNums)
   698  
   699  	// TrustedOS predicate from PCR principal tail.
   700  	prinPCRs := auth.PrinTail{Ext: prin.Ext}
   701  	predTrustedOS := auth.MakePredicate(dt.GetOsPredicateName(), prinPCRs)
   702  	err := domain.Guard.AddRule(fmt.Sprint(predTrustedOS))
   703  	options.FailIf(err, "Can't add rule to domain")
   704  
   705  	// TrustedTPM predicate from TPM principal.
   706  	prin.Ext = nil
   707  	predTrustedTPM2 := auth.MakePredicate(dt.GetTpm2PredicateName(), prin)
   708  	err = domain.Guard.AddRule(fmt.Sprint(predTrustedTPM2))
   709  	options.FailIf(err, "Can't add rule to domain")
   710  
   711  	err = domain.Save()
   712  	options.FailIf(err, "Can't save domain")
   713  }
   714  
   715  func createUserKeys() {
   716  	// Read the X509Details for this user from a text protobuf file.
   717  	userKeyDetails := *options.String["user_key_details"]
   718  	xdb, err := ioutil.ReadFile(userKeyDetails)
   719  	options.FailIf(err, "Can't read user details")
   720  	var xd tao.X509Details
   721  	err = proto.UnmarshalText(string(xdb), &xd)
   722  	options.FailIf(err, "Can't parse user details: %s", userKeyDetails)
   723  
   724  	upwd := getKey("user password", "user_pass")
   725  	pwd := getKey("domain policy key password", "pass")
   726  
   727  	domain, err := tao.LoadDomain(configPath(), pwd)
   728  	options.FailIf(err, "Can't load domain")
   729  	policyKey := domain.Keys
   730  
   731  	subjectName := tao.NewX509Name(&xd)
   732  	userKeyPath := *options.String["user_key_path"]
   733  	_, err = tao.NewSignedOnDiskPBEKeys(tao.Signing, upwd, userKeyPath, subjectName, int(xd.GetSerialNumber()), policyKey)
   734  	options.FailIf(err, "Can't create user signing key")
   735  }
   736  
   737  func getTPMConfig() (string, string, []int) {
   738  	domain, err := tao.LoadDomain(configPath(), nil)
   739  	options.FailIf(err, "Can't load domain")
   740  	tpmPath := domain.Config.GetTpmInfo().GetTpmPath()
   741  	aikFile := domain.Config.GetTpmInfo().GetAikPath()
   742  	pcrVals := domain.Config.GetTpmInfo().GetPcrs()
   743  	var pcrNums []int
   744  	for _, s := range strings.Split(pcrVals, ",") {
   745  		v, err := strconv.ParseInt(s, 10, 32)
   746  		options.FailIf(err, "Can't parse TPM PCR spec")
   747  
   748  		pcrNums = append(pcrNums, int(v))
   749  	}
   750  
   751  	return tpmPath, aikFile, pcrNums
   752  }
   753  
   754  func getTPM2Config() (string, []int) {
   755  	domain, err := tao.LoadDomain(configPath(), nil)
   756  	options.FailIf(err, "Can't load domain")
   757  	// TODO(tmroeder): This ignores the info path, since it ignores the cert
   758  	// files.
   759  	tpmPath := domain.Config.GetTpm2Info().GetTpm2Device()
   760  	pcrVals := domain.Config.GetTpm2Info().GetTpm2Pcrs()
   761  	// TODO(tmroeder): This currently ignores the paths to the ek_cert and
   762  	// quote_cert, since it creates its own keys.
   763  	var pcrNums []int
   764  	for _, s := range strings.Split(pcrVals, ",") {
   765  		v, err := strconv.ParseInt(s, 10, 32)
   766  		options.FailIf(err, "Can't parse TPM PCR spec")
   767  
   768  		pcrNums = append(pcrNums, int(v))
   769  	}
   770  
   771  	return tpmPath, pcrNums
   772  }
   773  
   774  func outputPrincipal() {
   775  	if path := *options.String["program"]; path != "" {
   776  		subprin, err := makeProgramSubPrin(path)
   777  		options.FailIf(err, "Can't create program principal")
   778  		pt := auth.PrinTail{Ext: subprin}
   779  		fmt.Println(pt)
   780  	}
   781  	if path := *options.String["container"]; path != "" {
   782  		subprin, err := makeContainerSubPrin(path)
   783  		options.FailIf(err, "Can't create container principal")
   784  		pt := auth.PrinTail{Ext: subprin}
   785  		fmt.Println(pt)
   786  	}
   787  	if *options.Bool["tpm"] {
   788  		tpmPath, aikFile, pcrVals := getTPMConfig()
   789  		prin := makeTPMPrin(tpmPath, aikFile, pcrVals)
   790  		// In the domain template the host name is in quotes. We need to escape
   791  		// quote strings in the Principal string so that domain_template.pb gets
   792  		// parsed correctly.
   793  		name := strings.Replace(prin.String(), "\"", "\\\"", -1)
   794  		fmt.Println(name)
   795  	}
   796  	if *options.Bool["tpm2"] {
   797  		tpmPath, pcrVals := getTPM2Config()
   798  		prin := makeTPM2Prin(tpmPath, pcrVals)
   799  		// In the domain template the host name is in quotes. We need to escape
   800  		// quote strings in the Principal string so that domain_template.pb gets
   801  		// parsed correctly.
   802  		name := strings.Replace(prin.String(), "\"", "\\\"", -1)
   803  		fmt.Println(name)
   804  	}
   805  	if lhpath := *options.String["soft"]; lhpath != "" {
   806  		if !path.IsAbs(lhpath) {
   807  			lhpath = path.Join(domainPath(), lhpath)
   808  		}
   809  		k, err := tao.NewOnDiskPBEKeys(tao.Signing, nil, lhpath, nil)
   810  		options.FailIf(err, "Can't create soft tao keys")
   811  		fmt.Println(k.VerifyingKey.ToPrincipal())
   812  	}
   813  }