Example #1
0
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")
}
Example #2
0
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)
	}
}