github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/tao/domain.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 tao
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"io"
    21  	"io/ioutil"
    22  	"os"
    23  	"path"
    24  	"strings"
    25  
    26  	"github.com/golang/protobuf/proto"
    27  	"github.com/jlmucb/cloudproxy/go/tao/auth"
    28  	"github.com/jlmucb/cloudproxy/go/util"
    29  )
    30  
    31  // Domain manages domain-wide authorization policies and configuration for a
    32  // single Tao administrative domain. Configuration includes a name, domain guard
    33  // type, ACLs or other guard-specific policy data, and a key pair for signing
    34  // policy data.
    35  //
    36  // Except for a password used to encrypt the policy private key, top-level
    37  // configuration data for Domain is stored in a text file, typically named
    38  // "tao.config". This configuration file contains the locations of all other
    39  // files and directories, e.g. configuration files for the domain guard. File
    40  // and directory paths within the tao.config file are relative to the location
    41  // of the tao.config file itself.
    42  type Domain struct {
    43  	Config     DomainConfig
    44  	ConfigPath string
    45  	Keys       *Keys
    46  	Guard      Guard
    47  }
    48  
    49  func PrintDomainDetails(x *DomainDetails) {
    50  	if x.Name != nil {
    51  		fmt.Printf("Domain Name: %s\n", *x.Name)
    52  	}
    53  	if x.PolicyKeysPath != nil {
    54  		fmt.Printf("PolicyKeysPath: %s\n", *x.PolicyKeysPath)
    55  	}
    56  	if x.GuardType != nil {
    57  		fmt.Printf("GuardType: %s\n", *x.GuardType)
    58  	}
    59  	if x.GuardNetwork != nil {
    60  		fmt.Printf("GuardNetwork: %s\n", *x.GuardNetwork)
    61  	}
    62  	if x.GuardAddress != nil {
    63  		fmt.Printf("GuardAddress: %s\n", *x.GuardAddress)
    64  	}
    65  	if x.GuardTtl != nil {
    66  		fmt.Printf("GuardTtl: %d\n", *x.GuardTtl)
    67  	}
    68  	if x.CipherSuite != nil {
    69  		fmt.Printf("CipherSuite: %s\n", *x.CipherSuite)
    70  	}
    71  
    72  }
    73  
    74  func PrintX509Details(x *X509Details) {
    75  	if x.CommonName != nil {
    76  		fmt.Printf("CommonName: %s\n", *x.CommonName)
    77  	}
    78  	if x.Country != nil {
    79  		fmt.Printf("Country: %s\n", *x.Country)
    80  	}
    81  	if x.State != nil {
    82  		fmt.Printf("State: %s\n", *x.State)
    83  	}
    84  	if x.Organization != nil {
    85  		fmt.Printf("Organization: %s\n", *x.Organization)
    86  	}
    87  	if x.OrganizationalUnit != nil {
    88  		fmt.Printf("OrganizationalUnit: %s\n", *x.OrganizationalUnit)
    89  	}
    90  	if x.SerialNumber != nil {
    91  		fmt.Printf("SerialNumber: %d\n", *x.SerialNumber)
    92  	}
    93  }
    94  
    95  func PrintACLGuardDetails(x *ACLGuardDetails) {
    96  	if x.SignedAclsPath != nil {
    97  		fmt.Printf("SignedAclsPath : %s\n", *x.SignedAclsPath)
    98  	}
    99  }
   100  
   101  func PrintDatalogGuardDetails(x *DatalogGuardDetails) {
   102  	if x.SignedRulesPath != nil {
   103  		fmt.Printf("SignedRulesPath: %s\n", *x.SignedRulesPath)
   104  	}
   105  }
   106  
   107  func PrintTPMDetails(x *TPMDetails) {
   108  	if x.TpmPath != nil {
   109  		fmt.Printf("TpmPath: %s\n", *x.TpmPath)
   110  	}
   111  	if x.AikPath != nil {
   112  		fmt.Printf("AikPath: %s\n", *x.AikPath)
   113  	}
   114  	if x.AikCertPath != nil {
   115  		fmt.Printf("AikCertPath: %s\n", *x.AikCertPath)
   116  	}
   117  }
   118  
   119  func PrintTPM2Details(x *TPM2Details) {
   120  	if x.Tpm2InfoDir != nil {
   121  		fmt.Printf("Tpm2InfoDir: %s\n", *x.Tpm2InfoDir)
   122  	}
   123  	if x.Tpm2Device != nil {
   124  		fmt.Printf("Tpm2Device: %s\n", *x.Tpm2Device)
   125  	}
   126  	if x.Tpm2EkCert != nil {
   127  		fmt.Printf("Tpm2EkCert: %s\n", *x.Tpm2EkCert)
   128  	}
   129  	if x.Tpm2QuoteCert != nil {
   130  		fmt.Printf("Tpm2QuoteCert: %s\n", *x.Tpm2QuoteCert)
   131  	}
   132  	if x.Tpm2SealCert != nil {
   133  		fmt.Printf("Tpm2SealCert: %s\n", *x.Tpm2SealCert)
   134  	}
   135  }
   136  
   137  func PrintDomainConfig(cf *DomainConfig) {
   138  	if cf.DomainInfo != nil {
   139  		PrintDomainDetails(cf.DomainInfo)
   140  	}
   141  	if cf.X509Info != nil {
   142  		PrintX509Details(cf.X509Info)
   143  	}
   144  	if cf.X509Info != nil {
   145  		PrintX509Details(cf.X509Info)
   146  	}
   147  	if cf.AclGuardInfo != nil {
   148  		PrintACLGuardDetails(cf.AclGuardInfo)
   149  	}
   150  	if cf.DatalogGuardInfo != nil {
   151  		PrintDatalogGuardDetails(cf.DatalogGuardInfo)
   152  	}
   153  	if cf.TpmInfo != nil {
   154  		PrintTPMDetails(cf.TpmInfo)
   155  	}
   156  	if cf.Tpm2Info != nil {
   157  		PrintTPM2Details(cf.Tpm2Info)
   158  	}
   159  }
   160  
   161  func PrintDomain(d *Domain) {
   162  	fmt.Printf("ConfigPath: %s\n", d.ConfigPath)
   163  	PrintDomainConfig(&d.Config)
   164  	if d.Keys != nil {
   165  		PrintKeys(d.Keys)
   166  	}
   167  }
   168  
   169  var errUnknownGuardType = errors.New("unknown guard type")
   170  
   171  // SetDefaults sets each blank field of cfg to a reasonable default value.
   172  func (cfg *DomainConfig) SetDefaults() {
   173  	if cfg.DomainInfo == nil {
   174  		cfg.DomainInfo = &DomainDetails{}
   175  	}
   176  
   177  	if cfg.DomainInfo.Name == nil {
   178  		cfg.DomainInfo.Name = proto.String("Tao example domain")
   179  	}
   180  	if cfg.DomainInfo.PolicyKeysPath == nil {
   181  		cfg.DomainInfo.PolicyKeysPath = proto.String("policy_keys")
   182  	}
   183  	if cfg.DomainInfo.GuardType == nil {
   184  		cfg.DomainInfo.GuardType = proto.String("DenyAll")
   185  	}
   186  
   187  	if cfg.X509Info == nil {
   188  		cfg.X509Info = &X509Details{}
   189  	}
   190  	if cfg.X509Info.CommonName == nil {
   191  		cfg.X509Info.CommonName = cfg.DomainInfo.Name
   192  	}
   193  
   194  	if cfg.TpmInfo == nil {
   195  		cfg.TpmInfo = &TPMDetails{}
   196  	}
   197  
   198  	if cfg.TpmInfo.TpmPath == nil {
   199  		cfg.TpmInfo.TpmPath = proto.String("/dev/tpm0")
   200  	}
   201  
   202  	if cfg.TpmInfo.AikPath == nil {
   203  		cfg.TpmInfo.AikPath = proto.String("aikblob")
   204  	}
   205  
   206  	if cfg.TpmInfo.Pcrs == nil {
   207  		cfg.TpmInfo.Pcrs = proto.String("17,18")
   208  	}
   209  
   210  	if cfg.Tpm2Info == nil {
   211  		cfg.Tpm2Info = &TPM2Details{}
   212  	}
   213  
   214  	if cfg.Tpm2Info.Tpm2Device == nil {
   215  		cfg.Tpm2Info.Tpm2Device = proto.String("/dev/tpm0")
   216  	}
   217  
   218  	if cfg.Tpm2Info.Tpm2Pcrs == nil {
   219  		cfg.Tpm2Info.Tpm2Pcrs = proto.String("17,18")
   220  	}
   221  }
   222  
   223  // String returns the name of the domain.
   224  func (d *Domain) String() string {
   225  	return d.Config.DomainInfo.GetName()
   226  }
   227  
   228  // Subprincipal returns a subprincipal suitable for contextualizing a program.
   229  func (d *Domain) Subprincipal() auth.SubPrin {
   230  	e := auth.PrinExt{
   231  		Name: "Domain",
   232  		Arg: []auth.Term{
   233  			d.Keys.VerifyingKey.ToPrincipal(),
   234  			auth.Str(d.Config.DomainInfo.GetGuardType()),
   235  		},
   236  	}
   237  	return auth.SubPrin{e}
   238  }
   239  
   240  // CreateDomain initializes a new Domain, writing its configuration files to
   241  // a directory. This creates the directory if needed, creates a policy key pair
   242  // (encrypted with the given password when stored on disk), and initializes a
   243  // default guard of the appropriate type if needed. Any parameters left empty in
   244  // cfg will be set to reasonable default values.
   245  func CreateDomain(cfg DomainConfig, configPath string, password []byte) (*Domain, error) {
   246  	cfg.SetDefaults()
   247  
   248  	configDir := path.Dir(configPath)
   249  	err := os.MkdirAll(configDir, 0777)
   250  	if err != nil {
   251  		return nil, err
   252  	}
   253  
   254  	keypath := path.Join(configDir, cfg.DomainInfo.GetPolicyKeysPath())
   255  	// This creates a keyset if it doesn't exist, and it reads the keyset
   256  	// otherwise.
   257  	keys, err := NewOnDiskPBEKeys(Signing, password, keypath, NewX509Name(cfg.X509Info))
   258  	if err != nil {
   259  		return nil, err
   260  	}
   261  
   262  	var guard Guard
   263  	switch cfg.DomainInfo.GetGuardType() {
   264  	case "ACLs":
   265  		if cfg.AclGuardInfo == nil {
   266  			return nil, fmt.Errorf("must supply ACL info for the ACL guard")
   267  		}
   268  		aclsPath := cfg.AclGuardInfo.GetSignedAclsPath()
   269  		agi := ACLGuardDetails{
   270  			SignedAclsPath: proto.String(path.Join(configDir, aclsPath)),
   271  		}
   272  		guard = NewACLGuard(keys.VerifyingKey, agi)
   273  	case "Datalog":
   274  		if cfg.DatalogGuardInfo == nil {
   275  			return nil, fmt.Errorf("must supply Datalog info for the Datalog guard")
   276  		}
   277  		rulesPath := cfg.DatalogGuardInfo.GetSignedRulesPath()
   278  		dgi := DatalogGuardDetails{
   279  			SignedRulesPath: proto.String(path.Join(configDir, rulesPath)),
   280  		}
   281  		// Fix?
   282  		if keys.VerifyingKey == nil {
   283  			return nil, errors.New("Empty verifying key")
   284  		}
   285  		guard, err = NewDatalogGuardFromConfig(keys.VerifyingKey, dgi)
   286  		if err != nil {
   287  			return nil, err
   288  		}
   289  	case "AllowAll":
   290  		guard = LiberalGuard
   291  	case "DenyAll":
   292  		guard = ConservativeGuard
   293  	default:
   294  		return nil, newError("unrecognized guard type: %s", cfg.DomainInfo.GetGuardType())
   295  	}
   296  
   297  	d := &Domain{cfg, configPath, keys, guard}
   298  	err = d.Save()
   299  	if err != nil {
   300  		return nil, err
   301  	}
   302  	return d, nil
   303  }
   304  
   305  // Create a public domain with a CachedGuard.
   306  // TODO(cjpatton) create a net.Conn here. defer Close() somehow. Add new
   307  // constructor from a net.Conn that doesn't save the domain to disk.
   308  // Refactor Request's in ca.go to use already existing connection.
   309  func (d *Domain) CreatePublicCachedDomain(network, addr string, ttl int64) (*Domain, error) {
   310  	newDomain := &Domain{
   311  		Config: d.Config,
   312  	}
   313  	configDir, configName := path.Split(d.ConfigPath) // '/path/to/', 'file'
   314  
   315  	// Load public key from domain.
   316  	keyPath := path.Join(configDir, d.Config.DomainInfo.GetPolicyKeysPath())
   317  	keys, err := NewOnDiskPBEKeys(Signing, make([]byte, 0), keyPath,
   318  		NewX509Name(d.Config.X509Info))
   319  	if err != nil {
   320  		return nil, err
   321  	}
   322  	newDomain.Keys = keys
   323  
   324  	// Set up a CachedGuard.
   325  	newDomain.Guard = NewCachedGuard(newDomain.Keys.VerifyingKey,
   326  		Datalog /*TODO(cjpatton) hardcoded*/, network, addr, ttl)
   327  	newDomain.Config.DomainInfo.GuardNetwork = proto.String(network)
   328  	newDomain.Config.DomainInfo.GuardAddress = proto.String(addr)
   329  	newDomain.Config.DomainInfo.GuardTtl = proto.Int64(ttl)
   330  
   331  	// Create domain directory ending with ".pub".
   332  	configDir = strings.TrimRight(configDir, "/") + ".pub"
   333  	err = os.MkdirAll(configDir, 0777)
   334  	if err != nil {
   335  		return nil, err
   336  	}
   337  	newDomain.ConfigPath = path.Join(configDir, configName)
   338  	newDomain.Keys.dir = path.Join(configDir, d.Config.DomainInfo.GetPolicyKeysPath())
   339  
   340  	// Save public key. Copy certificate from the old to new directory.
   341  	// TODO(tmroeder) this is a bit hacky, but the best we can do short
   342  	// of refactoring the NewOnDiskPBEKey() code. In particular, there is
   343  	// currently no way to *just* save the keys.
   344  	err = os.MkdirAll(newDomain.Keys.dir, 0777)
   345  	if err != nil {
   346  		return nil, err
   347  	}
   348  
   349  	inFile, err := os.Open(d.Keys.X509VerifierPath())
   350  	if err != nil {
   351  		return nil, err
   352  	}
   353  	defer inFile.Close()
   354  	outFile, err := os.Create(newDomain.Keys.X509VerifierPath())
   355  	if err != nil {
   356  		return nil, err
   357  	}
   358  	defer outFile.Close()
   359  	_, err = io.Copy(outFile, inFile)
   360  	if err != nil {
   361  		return nil, err
   362  	}
   363  
   364  	// Save domain.
   365  	err = newDomain.Save()
   366  	return newDomain, err
   367  }
   368  
   369  // Save writes all domain configuration and policy data.
   370  func (d *Domain) Save() error {
   371  	file, err := util.CreatePath(d.ConfigPath, 0777, 0666)
   372  	if err != nil {
   373  		return err
   374  	}
   375  	ds := proto.MarshalTextString(&d.Config)
   376  	fmt.Fprint(file, ds)
   377  	file.Close()
   378  	return d.Guard.Save(d.Keys.SigningKey)
   379  }
   380  
   381  // LoadDomain initializes a Domain from an existing configuration file. If
   382  // password is nil, the object will be "locked", meaning that the policy private
   383  // signing key will not be available, new ACL entries or attestations can not be
   384  // signed, etc. Otherwise, password will be used to unlock the policy private
   385  // signing key.
   386  func LoadDomain(configPath string, password []byte) (*Domain, error) {
   387  	var cfg DomainConfig
   388  	d, err := ioutil.ReadFile(configPath)
   389  	if err != nil {
   390  		return nil, err
   391  	}
   392  	if err := proto.UnmarshalText(string(d), &cfg); err != nil {
   393  		return nil, err
   394  	}
   395  
   396  	configDir := path.Dir(configPath)
   397  	keypath := path.Join(configDir, cfg.DomainInfo.GetPolicyKeysPath())
   398  	keys, err := NewOnDiskPBEKeys(Signing, password, keypath, nil)
   399  	if err != nil {
   400  		return nil, err
   401  	}
   402  
   403  	// Fix?
   404  	if keys.VerifyingKey == nil {
   405  		keys.VerifyingKey = keys.SigningKey.GetVerifierFromSigner()
   406  		if keys.VerifyingKey == nil {
   407  			return nil, errors.New("Can't GetVeriferFromSigner")
   408  		}
   409  	}
   410  
   411  	var guard Guard
   412  
   413  	if cfg.DomainInfo.GetGuardAddress() != "" && cfg.DomainInfo.GetGuardNetwork() != "" {
   414  		// Use CachedGuard to fetch policy from a remote TaoCA.
   415  		var guardType CachedGuardType
   416  		switch cfg.DomainInfo.GetGuardType() {
   417  		case "ACLs":
   418  			guardType = ACLs
   419  		case "Datalog":
   420  			guardType = Datalog
   421  		default:
   422  			return nil, errUnknownGuardType
   423  		}
   424  		guard = NewCachedGuard(keys.VerifyingKey, guardType,
   425  			cfg.DomainInfo.GetGuardNetwork(),
   426  			cfg.DomainInfo.GetGuardAddress(),
   427  			cfg.DomainInfo.GetGuardTtl())
   428  
   429  	} else {
   430  		// Policy stored locally on disk, or using a trivial guard.
   431  		switch cfg.DomainInfo.GetGuardType() {
   432  		case "ACLs":
   433  			var err error
   434  			if cfg.AclGuardInfo == nil {
   435  				return nil, fmt.Errorf("must supply ACL info for the ACL guard")
   436  			}
   437  			agi := ACLGuardDetails{
   438  				SignedAclsPath: proto.String(path.Join(configDir,
   439  					cfg.AclGuardInfo.GetSignedAclsPath())),
   440  			}
   441  			guard, err = LoadACLGuard(keys.VerifyingKey, agi)
   442  			if err != nil {
   443  				return nil, err
   444  			}
   445  		case "Datalog":
   446  			var err error
   447  			if cfg.DatalogGuardInfo == nil {
   448  				return nil, fmt.Errorf("must supply Datalog info for the Datalog guard")
   449  			}
   450  			dgi := DatalogGuardDetails{
   451  				SignedRulesPath: proto.String(path.Join(configDir,
   452  					cfg.DatalogGuardInfo.GetSignedRulesPath())),
   453  			}
   454  			datalogGuard, err := NewDatalogGuardFromConfig(keys.VerifyingKey, dgi)
   455  			if err != nil {
   456  				return nil, err
   457  			}
   458  			if err := datalogGuard.ReloadIfModified(); err != nil {
   459  				return nil, err
   460  			}
   461  			guard = datalogGuard
   462  		case "AllowAll":
   463  			guard = LiberalGuard
   464  		case "DenyAll":
   465  			guard = ConservativeGuard
   466  		default:
   467  			return nil, errUnknownGuardType
   468  		}
   469  	}
   470  	return &Domain{cfg, configPath, keys, guard}, nil
   471  }
   472  
   473  // ExtendTaoName uses a Domain's Verifying key to extend the Tao with a
   474  // subprincipal PolicyKey([...]).
   475  func (d *Domain) ExtendTaoName(tao Tao) error {
   476  	if d.Keys == nil || d.Keys.VerifyingKey == nil {
   477  		return newError("no verifying key to use for name extension")
   478  	}
   479  
   480  	// This is a key Prin with type "key" and auth.Bytes as its Term
   481  	p := d.Keys.VerifyingKey.ToPrincipal()
   482  	b, ok := p.KeyHash.(auth.Bytes)
   483  	if !ok {
   484  		return newError("couldn't get an auth.Bytes value from the key")
   485  	}
   486  
   487  	sp := auth.SubPrin{
   488  		auth.PrinExt{
   489  			Name: "PolicyKey",
   490  			Arg:  []auth.Term{b},
   491  		},
   492  	}
   493  
   494  	return tao.ExtendTaoName(sp)
   495  }
   496  
   497  // RulesPath returns the path that should be used for the rules/acls for a given
   498  // domain. If the guard is not Datalog or ACLs, then it returns the empty
   499  // string.
   500  func (d *Domain) RulesPath() string {
   501  	switch d.Config.DomainInfo.GetGuardType() {
   502  	case "Datalog":
   503  		if d.Config.DatalogGuardInfo == nil {
   504  			return ""
   505  		}
   506  		return d.Config.DatalogGuardInfo.GetSignedRulesPath()
   507  	case "ACLs":
   508  		if d.Config.AclGuardInfo == nil {
   509  			return ""
   510  		}
   511  		return d.Config.AclGuardInfo.GetSignedAclsPath()
   512  	default:
   513  		return ""
   514  	}
   515  }