func main() { verbose.Set(true) options.Parse() profiling.ProfilePath = *options.String["profile"] if !verbose.Enabled { taoca.ConfirmNames = false } if *options.String["config"] != "" && !*options.Bool["init"] { err := options.Load(*options.String["config"]) options.FailIf(err, "Can't load configuration") } fmt.Println("https/tls Certificate Authority") manualMode = *options.Bool["manual"] learnMode = *options.Bool["learn"] if !manualMode && tao.Parent() == nil { options.Fail(nil, "can't continue: automatic mode, but no host Tao available") } if *options.Bool["root"] == (*options.String["subsidiary"] != "") { options.Usage("must supply exactly one of -root or -subsidiary options") } host := *options.String["host"] port := *options.String["port"] addr := net.JoinHostPort(host, port) // TODO(kwalsh) extend tao name with operating mode and policy cpath := *options.String["config"] kdir := *options.String["keys"] if kdir == "" && cpath != "" { kdir = path.Dir(cpath) } else if kdir == "" { options.Fail(nil, "Option -keys or -config is required") } ppath := path.Join(kdir, "policy") var err error if *options.Bool["init"] { if cpath != "" { err := options.Save(cpath, "HTTPS/TLS certificate authority configuration", "persistent") options.FailIf(err, "Can't save configuration") } fmt.Println("" + "Initializing fresh HTTP/TLS CA signing key. Provide the following information,\n" + "to be include in the CA's own x509 certificate. Leave the response blank to\n" + "accept the default value.\n" + "\n" + "Configuration file: " + cpath + "\n" + "Keys directory: " + kdir + "\n") var caName *pkix.Name if taoca.ConfirmNames { if *options.Bool["root"] { caName = taoca.ConfirmName(caRootName) } else { caName = taoca.ConfirmName(caSubsidiaryName) } } else { if *options.Bool["root"] { caName = caRootName } else { caName = caSubsidiaryName } } if manualMode { pwd := options.Password("Choose an HTTPS/TLS CA signing key password", "pass") caKeys, err = tao.InitOnDiskPBEKeys(tao.Signing, pwd, kdir, caName) tao.ZeroBytes(pwd) } else { caKeys, err = tao.InitOnDiskTaoSealedKeys(tao.Signing, caName, tao.Parent(), kdir, tao.SealPolicyDefault) } options.FailIf(err, "Can't initialize fresh HTTPS/TLS CA signing key") if *options.Bool["root"] { fmt.Printf(""+ "Note: To install this CA's key in the Chrome browser, go to\n"+ " 'Settings', 'Show advanced settings...', 'Manage Certificates...', 'Authorities'\n"+ " then import the following file:\n"+ " %s\n"+ " Select 'Trust this certificate for identifying websites' and/or other\n"+ " options, then click 'OK'\n", caKeys.X509Path("default")) } else { csr := taoca.NewCertificateSigningRequest(caKeys.VerifyingKey, caName) *csr.IsCa = true srv := *options.String["subsidiary"] taoca.DefaultServerName = srv taoca.SubmitAndInstall(caKeys, csr) } if !manualMode { f, err := os.Open(ppath) if err == nil { f.Close() fmt.Printf("Using existing certificate-granting policy: %s\n", ppath) } else { fmt.Printf("Creating default certificate-granting policy: %s\n", ppath) fmt.Printf("Edit that file to define the certificate-granting policy.\n") err := util.WritePath(ppath, []byte(policy.Default), 0755, 0755) options.FailIf(err, "Can't save policy rules") } } } else { if manualMode { pwd := options.Password("HTTPS/TLS CA signing key password", "pass") caKeys, err = tao.LoadOnDiskPBEKeys(tao.Signing, pwd, kdir) tao.ZeroBytes(pwd) } else { caKeys, err = tao.LoadOnDiskTaoSealedKeys(tao.Signing, tao.Parent(), kdir, tao.SealPolicyDefault) } options.FailIf(err, "Can't load HTTP/TLS CA signing key") } netlog.Log("https_ca: start") netlog.Log("https_ca: manual? %v", manualMode) if !manualMode { guard, err = policy.Load(ppath) options.FailIf(err, "Can't load certificate-granting policy") } var prin auth.Prin if tao.Parent() != nil { prin, err = tao.Parent().GetTaoName() options.FailIf(err, "Can't get tao name") } else { rendezvous.DefaultServer.Connect(caKeys) prin = caKeys.SigningKey.ToPrincipal() } name := *options.String["name"] if name != "" { err = rendezvous.Register(rendezvous.Binding{ Name: proto.String(name), Host: proto.String(host), Port: proto.String(port), Protocol: proto.String("protoc/rpc/https_ca"), Principal: proto.String(prin.String()), }) options.FailIf(err, "Can't register with rendezvous service") } statsdelay := *options.String["stats"] var srv *tao.Server if statsdelay != "" { go profiling.ShowStats(&stats, statsdelay, "sign certificates") srv = tao.NewOpenServer(tao.ConnHandlerFunc(doResponseWithStats)) } else { srv = tao.NewOpenServer(tao.ConnHandlerFunc(doResponseWithoutStats)) } srv.Keys = caKeys fmt.Printf("Listening at %s using Tao-authenticated channels\n", addr) err = srv.ListenAndServe(addr) options.FailIf(err, "server died") fmt.Println("Server Done") netlog.Log("https_ca: done") }
func loadHost(domain *tao.Domain, cfg *tao.LinuxHostConfig) (*tao.LinuxHost, error) { var tc tao.Config // Sanity check host type var stacked bool switch cfg.GetType() { case "root": stacked = false case "stacked": stacked = true case "": options.Usage("Must supply -root or -stacked flag") default: options.Usage("Invalid host type: %s", cfg.GetType()) } // Sanity check hosting type hosting := make(map[string]bool) for _, h := range cfg.GetHosting() { switch h { case "process", "docker", "kvm_coreos", "kvm_coreos_linuxhost": hosting[h] = true default: options.Usage("Invalid hosting type: %s", cfg.GetHosting()) } } if len(hosting) == 0 { options.Usage("Must supply -hosting flag") } // For stacked hosts, figure out the channel type: TPM, pipe, file, or unix if stacked { switch cfg.GetParentType() { case "TPM": tc.HostChannelType = "tpm" case "pipe": tc.HostChannelType = "pipe" case "file": tc.HostChannelType = "file" case "unix": tc.HostChannelType = "unix" case "": // leave channel type blank, tao may find it in env vars tc.HostChannelType = "" default: options.Usage("Invalid parent type: %s", cfg.GetParentType()) } // For stacked hosts, we may also have a parent spec from command line tc.HostSpec = cfg.GetParentSpec() // For stacked hosts on a TPM, we may also have tpm info from domain config if domain.Config.TpmInfo != nil { tc.TPMAIKPath = path.Join(apps.TaoDomainPath(), domain.Config.TpmInfo.GetAikPath()) tc.TPMPCRs = domain.Config.TpmInfo.GetPcrs() tc.TPMDevice = domain.Config.TpmInfo.GetTpmPath() } } rulesPath := "" if p := domain.RulesPath(); p != "" { rulesPath = path.Join(apps.TaoDomainPath(), p) } // Create the hosted program factory socketPath := hostPath() if subPath := cfg.GetSocketDir(); subPath != "" { if path.IsAbs(subPath) { socketPath = subPath } else { socketPath = path.Join(socketPath, subPath) } } // TODO(cjpatton) How do the NewLinuxDockerContainterFactory and the // NewLinuxKVMCoreOSHostFactory need to be modified to support the new // CachedGuard? They probably don't. childFactory := make(map[string]tao.HostedProgramFactory) if hosting["process"] { childFactory["process"] = tao.NewLinuxProcessFactory("pipe", socketPath) } if hosting["docker"] { childFactory["docker"] = tao.NewLinuxDockerContainerFactory(socketPath, rulesPath) } if hosting["kvm_coreos"] { // TODO(kwalsh) re-enable this code path in new kvm factory // sshFile := cfg.GetKvmCoreosSshAuthKeys() // if sshFile != "" { // if !path.IsAbs(sshFile) { // sshFile = path.Join(apps.TaoDomainPath(), sshFile) // } // sshKeysCfg, err := io.ReadFile(sshFile) // options.FailIf(err, "Can't read ssh authorized keys") coreOSImage := cfg.GetKvmCoreosImg() if coreOSImage == "" { options.Usage("Must specify -kvm_coreos_image for hosting QEMU/KVM CoreOS") } if !path.IsAbs(coreOSImage) { coreOSImage = path.Join(apps.TaoDomainPath(), coreOSImage) } // TODO(kwalsh) re-enable this code path in new kvm factory // vmMemory := cfg.GetKvmCoreosVmMemory() // if vmMemory == 0 { // vmMemory = 1024 // } var err error childFactory["kvm_coreos"], err = tao.NewKVMCoreOSFactory(coreOSImage, false) options.FailIf(err, "Can't create KVM CoreOS factory") } if hosting["kvm_coreos_linuxhost"] { sshFile := cfg.GetKvmCoreosSshAuthKeys() if sshFile == "" { options.Usage("Must specify -kvm_coreos_ssh_auth_keys for hosting QEMU/KVM CoreOS") } if !path.IsAbs(sshFile) { sshFile = path.Join(apps.TaoDomainPath(), sshFile) } sshKeysCfg, err := tao.CloudConfigFromSSHKeys(sshFile) options.FailIf(err, "Can't read ssh keys") coreOSImage := cfg.GetKvmCoreosImg() if coreOSImage == "" { options.Usage("Must specify -kvm_coreos_image for hosting QEMU/KVM CoreOS") } if !path.IsAbs(coreOSImage) { coreOSImage = path.Join(apps.TaoDomainPath(), coreOSImage) } vmMemory := cfg.GetKvmCoreosVmMemory() if vmMemory == 0 { vmMemory = 1024 } cfg := &tao.CoreOSLinuxhostConfig{ ImageFile: coreOSImage, Memory: int(vmMemory), RulesPath: rulesPath, SSHKeysCfg: sshKeysCfg, } childFactory["kvm_coreos_linuxhost"], err = tao.NewLinuxKVMCoreOSHostFactory(socketPath, cfg) options.FailIf(err, "Can't create KVM CoreOS LinuxHost factory") } if !stacked { pwd := options.Password("root host key password", "pass") return tao.NewRootLinuxHost(hostPath(), domain.Guard, pwd, childFactory) } else { parent := tao.ParentFromConfig(tc) if parent == nil { options.Usage("No host tao available, verify -parent_type (or $%s) and associated variables\n", tao.HostChannelTypeEnvVar) } return tao.NewStackedLinuxHost(hostPath(), domain.Guard, parent, childFactory) } }