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 }