Example #1
0
func TestAddCertificate(t *testing.T) {
	// Enable the feature for the `CertStatusOptimizationsMigrated` flag so that
	// adding a new certificate will populate the `certificateStatus.NotAfter`
	// field correctly. This will let the unit test assertion for `NotAfter`
	// pass provided everything is working as intended. Note: this must be done
	// **before** the DbMap is created in `initSA()` or the feature flag won't be
	// set correctly at the time the table maps are set up.
	_ = features.Set(map[string]bool{"CertStatusOptimizationsMigrated": true})
	defer features.Reset()

	sa, _, cleanUp := initSA(t)
	defer cleanUp()

	reg := satest.CreateWorkingRegistration(t, sa)

	// An example cert taken from EFF's website
	certDER, err := ioutil.ReadFile("www.eff.org.der")
	test.AssertNotError(t, err, "Couldn't read example cert DER")

	digest, err := sa.AddCertificate(ctx, certDER, reg.ID)
	test.AssertNotError(t, err, "Couldn't add www.eff.org.der")
	test.AssertEquals(t, digest, "qWoItDZmR4P9eFbeYgXXP3SR4ApnkQj8x4LsB_ORKBo")

	retrievedCert, err := sa.GetCertificate(ctx, "000000000000000000000000000000021bd4")
	test.AssertNotError(t, err, "Couldn't get www.eff.org.der by full serial")
	test.AssertByteEquals(t, certDER, retrievedCert.DER)

	certificateStatus, err := sa.GetCertificateStatus(ctx, "000000000000000000000000000000021bd4")
	test.AssertNotError(t, err, "Couldn't get status for www.eff.org.der")
	test.Assert(t, !certificateStatus.SubscriberApproved, "SubscriberApproved should be false")
	test.Assert(t, certificateStatus.Status == core.OCSPStatusGood, "OCSP Status should be good")
	test.Assert(t, certificateStatus.OCSPLastUpdated.IsZero(), "OCSPLastUpdated should be nil")
	test.AssertEquals(t, certificateStatus.NotAfter, retrievedCert.Expires)

	// Test cert generated locally by Boulder / CFSSL, names [example.com,
	// www.example.com, admin.example.com]
	certDER2, err := ioutil.ReadFile("test-cert.der")
	test.AssertNotError(t, err, "Couldn't read example cert DER")
	serial := "ffdd9b8a82126d96f61d378d5ba99a0474f0"

	digest2, err := sa.AddCertificate(ctx, certDER2, reg.ID)
	test.AssertNotError(t, err, "Couldn't add test-cert.der")
	test.AssertEquals(t, digest2, "vrlPN5wIPME1D2PPsCy-fGnTWh8dMyyYQcXPRkjHAQI")

	retrievedCert2, err := sa.GetCertificate(ctx, serial)
	test.AssertNotError(t, err, "Couldn't get test-cert.der")
	test.AssertByteEquals(t, certDER2, retrievedCert2.DER)

	certificateStatus2, err := sa.GetCertificateStatus(ctx, serial)
	test.AssertNotError(t, err, "Couldn't get status for test-cert.der")
	test.Assert(t, !certificateStatus2.SubscriberApproved, "SubscriberApproved should be false")
	test.Assert(t, certificateStatus2.Status == core.OCSPStatusGood, "OCSP Status should be good")
	test.Assert(t, certificateStatus2.OCSPLastUpdated.IsZero(), "OCSPLastUpdated should be nil")
}
Example #2
0
func TestDeactivateAccount(t *testing.T) {
	_ = features.Set(map[string]bool{"AllowAccountDeactivation": true})
	defer features.Reset()
	sa, _, cleanUp := initSA(t)
	defer cleanUp()

	reg := satest.CreateWorkingRegistration(t, sa)

	err := sa.DeactivateRegistration(context.Background(), reg.ID)
	test.AssertNotError(t, err, "DeactivateRegistration failed")

	dbReg, err := sa.GetRegistration(context.Background(), reg.ID)
	test.AssertNotError(t, err, "GetRegistration failed")
	test.AssertEquals(t, dbReg.Status, core.StatusDeactivated)
}
Example #3
0
func TestModelToRegistrationNilContact(t *testing.T) {
	_ = features.Set(map[string]bool{"AllowAccountDeactivation": true})
	defer features.Reset()
	reg, err := modelToRegistration(&regModelv2{
		regModelv1: regModelv1{
			Key:     []byte(`{"kty":"RSA","n":"AQAB","e":"AQAB"}`),
			Contact: nil,
		}})
	if err != nil {
		t.Errorf("Got error from modelToRegistration: %s", err)
	}
	if reg.Contact == nil {
		t.Errorf("Expected non-nil Contact field, got %#v", reg.Contact)
	}
	if len(*reg.Contact) != 0 {
		t.Errorf("Expected empty Contact field, got %#v", reg.Contact)
	}
}
Example #4
0
func main() {
	configFile := flag.String("config", "", "File path to the configuration file for this service")
	flag.Parse()
	if *configFile == "" {
		flag.Usage()
		os.Exit(1)
	}

	var c config
	err := cmd.ReadConfigFile(*configFile, &c)
	cmd.FailOnError(err, "Reading JSON config file into config structure")

	err = features.Set(c.WFE.Features)
	cmd.FailOnError(err, "Failed to set feature flags")

	stats, logger := cmd.StatsAndLogging(c.Statsd, c.Syslog)
	scope := metrics.NewStatsdScope(stats, "WFE")
	defer logger.AuditPanic()
	logger.Info(cmd.VersionString(clientName))

	wfe, err := wfe.NewWebFrontEndImpl(scope, clock.Default(), goodkey.NewKeyPolicy(), logger)
	cmd.FailOnError(err, "Unable to create WFE")
	rac, sac := setupWFE(c, logger, scope)
	wfe.RA = rac
	wfe.SA = sac

	// TODO: remove this check once the production config uses the SubscriberAgreementURL in the wfe section
	if c.WFE.SubscriberAgreementURL != "" {
		wfe.SubscriberAgreementURL = c.WFE.SubscriberAgreementURL
	} else {
		wfe.SubscriberAgreementURL = c.SubscriberAgreementURL
	}

	wfe.AllowOrigins = c.WFE.AllowOrigins
	wfe.AcceptRevocationReason = c.WFE.AcceptRevocationReason
	wfe.AllowAuthzDeactivation = c.WFE.AllowAuthzDeactivation

	wfe.CertCacheDuration = c.WFE.CertCacheDuration.Duration
	wfe.CertNoCacheExpirationWindow = c.WFE.CertNoCacheExpirationWindow.Duration
	wfe.IndexCacheDuration = c.WFE.IndexCacheDuration.Duration
	wfe.IssuerCacheDuration = c.WFE.IssuerCacheDuration.Duration

	wfe.IssuerCert, err = cmd.LoadCert(c.Common.IssuerCert)
	cmd.FailOnError(err, fmt.Sprintf("Couldn't read issuer cert [%s]", c.Common.IssuerCert))

	logger.Info(fmt.Sprintf("WFE using key policy: %#v", goodkey.NewKeyPolicy()))

	// Set up paths
	wfe.BaseURL = c.Common.BaseURL
	h := wfe.Handler()

	httpMonitor := metrics.NewHTTPMonitor(scope, h)

	logger.Info(fmt.Sprintf("Server running, listening on %s...\n", c.WFE.ListenAddress))
	srv := &http.Server{
		Addr:    c.WFE.ListenAddress,
		Handler: httpMonitor,
	}

	go cmd.DebugServer(c.WFE.DebugAddr)
	go cmd.ProfileCmd(scope)

	hd := &httpdown.HTTP{
		StopTimeout: c.WFE.ShutdownStopTimeout.Duration,
		KillTimeout: c.WFE.ShutdownKillTimeout.Duration,
		Stats:       metrics.NewFBAdapter(scope, clock.Default()),
	}
	hdSrv, err := hd.ListenAndServe(srv)
	cmd.FailOnError(err, "Error starting HTTP server")

	go cmd.CatchSignals(logger, func() { _ = hdSrv.Stop() })

	forever := make(chan struct{}, 1)
	<-forever
}
Example #5
0
func main() {
	configFile := flag.String("config", "", "File path to the configuration file for this service")
	workers := flag.Int("workers", runtime.NumCPU(), "The number of concurrent workers used to process certificates")
	badResultsOnly := flag.Bool("bad-results-only", false, "Only collect and display bad results")
	connect := flag.String("db-connect", "", "SQL URI if not provided in the configuration file")
	cp := flag.Duration("check-period", time.Hour*2160, "How far back to check")
	unexpiredOnly := flag.Bool("unexpired-only", false, "Only check currently unexpired certificates")

	flag.Parse()
	if *configFile == "" {
		flag.Usage()
		os.Exit(1)
	}

	var config config
	err := cmd.ReadConfigFile(*configFile, &config)
	cmd.FailOnError(err, "Reading JSON config file into config structure")

	err = features.Set(config.CertChecker.Features)
	cmd.FailOnError(err, "Failed to set feature flags")

	stats, err := metrics.NewStatter(config.Statsd.Server, config.Statsd.Prefix)
	cmd.FailOnError(err, "Failed to create StatsD client")
	syslogger, err := syslog.Dial("", "", syslog.LOG_INFO|syslog.LOG_LOCAL0, "")
	cmd.FailOnError(err, "Failed to dial syslog")
	logger, err := blog.New(syslogger, 0, 0)
	cmd.FailOnError(err, "Failed to construct logger")
	err = blog.Set(logger)
	cmd.FailOnError(err, "Failed to set audit logger")

	if *connect != "" {
		config.CertChecker.DBConnect = *connect
	}
	if *workers != 0 {
		config.CertChecker.Workers = *workers
	}
	config.CertChecker.UnexpiredOnly = *unexpiredOnly
	config.CertChecker.BadResultsOnly = *badResultsOnly
	config.CertChecker.CheckPeriod.Duration = *cp

	// Validate PA config and set defaults if needed
	cmd.FailOnError(config.PA.CheckChallenges(), "Invalid PA configuration")

	saDbURL, err := config.CertChecker.DBConfig.URL()
	cmd.FailOnError(err, "Couldn't load DB URL")
	saDbMap, err := sa.NewDbMap(saDbURL, config.CertChecker.DBConfig.MaxDBConns)
	cmd.FailOnError(err, "Could not connect to database")
	go sa.ReportDbConnCount(saDbMap, metrics.NewStatsdScope(stats, "CertChecker"))

	pa, err := policy.New(config.PA.Challenges)
	cmd.FailOnError(err, "Failed to create PA")
	err = pa.SetHostnamePolicyFile(config.CertChecker.HostnamePolicyFile)
	cmd.FailOnError(err, "Failed to load HostnamePolicyFile")

	checker := newChecker(
		saDbMap,
		clock.Default(),
		pa,
		config.CertChecker.CheckPeriod.Duration,
	)
	fmt.Fprintf(os.Stderr, "# Getting certificates issued in the last %s\n", config.CertChecker.CheckPeriod)

	// Since we grab certificates in batches we don't want this to block, when it
	// is finished it will close the certificate channel which allows the range
	// loops in checker.processCerts to break
	go func() {
		err = checker.getCerts(config.CertChecker.UnexpiredOnly)
		cmd.FailOnError(err, "Batch retrieval of certificates failed")
	}()

	fmt.Fprintf(os.Stderr, "# Processing certificates using %d workers\n", config.CertChecker.Workers)
	wg := new(sync.WaitGroup)
	for i := 0; i < config.CertChecker.Workers; i++ {
		wg.Add(1)
		go func() {
			s := checker.clock.Now()
			checker.processCerts(wg, config.CertChecker.BadResultsOnly)
			stats.TimingDuration("certChecker.processingLatency", time.Since(s), 1.0)
		}()
	}
	wg.Wait()
	fmt.Fprintf(
		os.Stderr,
		"# Finished processing certificates, sample: %d, good: %d, bad: %d\n",
		len(checker.issuedReport.Entries),
		checker.issuedReport.GoodCerts,
		checker.issuedReport.BadCerts,
	)
	err = checker.issuedReport.dump()
	cmd.FailOnError(err, "Failed to dump results: %s\n")

}
Example #6
0
func TestWillingToIssue(t *testing.T) {
	testCases := []struct {
		domain string
		err    error
	}{
		{``, errEmptyName},                    // Empty name
		{`zomb!.com`, errInvalidDNSCharacter}, // ASCII character out of range
		{`[email protected]`, errInvalidDNSCharacter},
		{`user:[email protected]`, errInvalidDNSCharacter},
		{`zömbo.com`, errInvalidDNSCharacter},                              // non-ASCII character
		{`127.0.0.1`, errIPAddress},                                        // IPv4 address
		{`fe80::1:1`, errInvalidDNSCharacter},                              // IPv6 addresses
		{`[2001:db8:85a3:8d3:1319:8a2e:370:7348]`, errInvalidDNSCharacter}, // unexpected IPv6 variants
		{`[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443`, errInvalidDNSCharacter},
		{`2001:db8::/32`, errInvalidDNSCharacter},
		{`a.b.c.d.e.f.g.h.i.j.k`, errTooManyLabels}, // Too many labels (>10)

		{`www.0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef012345.com`, errNameTooLong}, // Too long (254 characters)

		{`www.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz.com`, errLabelTooLong}, // Label too long (>63 characters)

		{`www.-ombo.com`, errInvalidDNSCharacter}, // Label starts with '-'
		{`www.zomb-.com`, errInvalidDNSCharacter}, // Label ends with '-'
		{`xn--.net`, errInvalidDNSCharacter},      // Label ends with '-'
		{`0`, errTooFewLabels},
		{`1`, errTooFewLabels},
		{`*`, errInvalidDNSCharacter},
		{`**`, errInvalidDNSCharacter},
		{`*.*`, errInvalidDNSCharacter},
		{`zombo*com`, errInvalidDNSCharacter},
		{`*.com`, errInvalidDNSCharacter},
		{`*.zombo.com`, errInvalidDNSCharacter},
		{`..a`, errLabelTooShort},
		{`a..a`, errLabelTooShort},
		{`.a..a`, errLabelTooShort},
		{`..foo.com`, errLabelTooShort},
		{`.`, errNameEndsInDot},
		{`..`, errNameEndsInDot},
		{`a..`, errNameEndsInDot},
		{`.....`, errNameEndsInDot},
		{`.a.`, errNameEndsInDot},
		{`www.zombo.com.`, errNameEndsInDot},
		{`www.zombo_com.com`, errInvalidDNSCharacter},
		{`\uFEFF`, errInvalidDNSCharacter}, // Byte order mark
		{`\uFEFFwww.zombo.com`, errInvalidDNSCharacter},
		{`www.zom\u202Ebo.com`, errInvalidDNSCharacter}, // Right-to-Left Override
		{`\u202Ewww.zombo.com`, errInvalidDNSCharacter},
		{`www.zom\u200Fbo.com`, errInvalidDNSCharacter}, // Right-to-Left Mark
		{`\u200Fwww.zombo.com`, errInvalidDNSCharacter},
		// Underscores are technically disallowed in DNS. Some DNS
		// implementations accept them but we will be conservative.
		{`www.zom_bo.com`, errInvalidDNSCharacter},
		{`zombocom`, errTooFewLabels},
		{`localhost`, errTooFewLabels},
		{`mail`, errTooFewLabels},

		// disallow capitalized letters for #927
		{`CapitalizedLetters.com`, errInvalidDNSCharacter},

		{`example.acting`, errNonPublic},
		{`example.internal`, errNonPublic},
		// All-numeric final label not okay.
		{`www.zombo.163`, errNonPublic},
	}

	shouldBeTLDError := []string{
		`co.uk`,
		`foo.bn`,
	}

	shouldBeBlacklisted := []string{
		`highvalue.website1.org`,
		`website2.co.uk`,
		`www.website3.com`,
		`lots.of.labels.website4.com`,
	}
	blacklistContents := []string{
		`website2.com`,
		`website2.org`,
		`website2.co.uk`,
		`website3.com`,
		`website4.com`,
	}
	exactBlacklistContents := []string{
		`www.website1.org`,
		`highvalue.website1.org`,
		`dl.website1.org`,
	}

	shouldBeAccepted := []string{
		`lowvalue.website1.org`,
		`website4.sucks`,
		"www.unrelated.com",
		"unrelated.com",
		"www.8675309.com",
		"8675309.com",
		"web5ite2.com",
		"www.web-site2.com",
	}

	pa := paImpl(t)

	blacklistBytes, err := json.Marshal(blacklistJSON{
		Blacklist:      blacklistContents,
		ExactBlacklist: exactBlacklistContents,
	})
	test.AssertNotError(t, err, "Couldn't serialize blacklist")
	f, _ := ioutil.TempFile("", "test-blacklist.txt")
	defer os.Remove(f.Name())
	err = ioutil.WriteFile(f.Name(), blacklistBytes, 0640)
	test.AssertNotError(t, err, "Couldn't write blacklist")
	err = pa.SetHostnamePolicyFile(f.Name())
	test.AssertNotError(t, err, "Couldn't load rules")

	// Test for invalid identifier type
	identifier := core.AcmeIdentifier{Type: "ip", Value: "example.com"}
	err = pa.WillingToIssue(identifier)
	if err != errInvalidIdentifier {
		t.Error("Identifier was not correctly forbidden: ", identifier)
	}

	// Test syntax errors
	for _, tc := range testCases {
		identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: tc.domain}
		err := pa.WillingToIssue(identifier)
		if err != tc.err {
			t.Errorf("WillingToIssue(%q) = %q, expected %q", tc.domain, err, tc.err)
		}
	}

	// Test IDNs
	err = pa.WillingToIssue(core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "www.xn--mnich-kva.com"})
	test.AssertError(t, err, "WillingToIssue didn't fail on a IDN with features.IDNASupport disabled")
	_ = features.Set(map[string]bool{"IDNASupport": true})
	// Invalid encoding
	err = pa.WillingToIssue(core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "www.xn--m.com"})
	test.AssertError(t, err, "WillingToIssue didn't fail on a malformed IDN")
	// Valid encoding
	err = pa.WillingToIssue(core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "www.xn--mnich-kva.com"})
	test.AssertNotError(t, err, "WillingToIssue failed on a properly formed IDN")
	// IDN TLD
	err = pa.WillingToIssue(core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "xn--example--3bhk5a.xn--p1ai"})
	test.AssertNotError(t, err, "WillingToIssue failed on a properly formed domain with IDN TLD")
	features.Reset()

	// Test domains that are equal to public suffixes
	for _, domain := range shouldBeTLDError {
		identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: domain}
		err := pa.WillingToIssue(identifier)
		if err != errICANNTLD {
			t.Error("Identifier was not correctly forbidden: ", identifier, err)
		}
	}

	// Test blacklisting
	for _, domain := range shouldBeBlacklisted {
		identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: domain}
		err := pa.WillingToIssue(identifier)
		if err != errBlacklisted {
			t.Error("Identifier was not correctly forbidden: ", identifier, err)
		}
	}

	// Test acceptance of good names
	for _, domain := range shouldBeAccepted {
		identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: domain}
		if err := pa.WillingToIssue(identifier); err != nil {
			t.Error("Identifier was incorrectly forbidden: ", identifier, err)
		}
	}
}
Example #7
0
func main() {
	configFile := flag.String("config", "", "File path to the configuration file for this service")
	flag.Parse()
	if *configFile == "" {
		flag.Usage()
		os.Exit(1)
	}

	var c config
	err := cmd.ReadConfigFile(*configFile, &c)
	cmd.FailOnError(err, "Reading JSON config file into config structure")

	err = features.Set(c.SA.Features)
	cmd.FailOnError(err, "Failed to set feature flags")

	stats, logger := cmd.StatsAndLogging(c.Statsd, c.Syslog)
	scope := metrics.NewStatsdScope(stats, "SA")
	defer logger.AuditPanic()
	logger.Info(cmd.VersionString(clientName))

	saConf := c.SA

	dbURL, err := saConf.DBConfig.URL()
	cmd.FailOnError(err, "Couldn't load DB URL")

	dbMap, err := sa.NewDbMap(dbURL, saConf.DBConfig.MaxDBConns)
	cmd.FailOnError(err, "Couldn't connect to SA database")

	go sa.ReportDbConnCount(dbMap, scope)

	sai, err := sa.NewSQLStorageAuthority(dbMap, clock.Default(), logger)
	cmd.FailOnError(err, "Failed to create SA impl")

	var grpcSrv *grpc.Server
	if c.SA.GRPC != nil {
		var listener net.Listener
		grpcSrv, listener, err = bgrpc.NewServer(c.SA.GRPC, scope)
		cmd.FailOnError(err, "Unable to setup SA gRPC server")
		gw := bgrpc.NewStorageAuthorityServer(sai)
		sapb.RegisterStorageAuthorityServer(grpcSrv, gw)
		go func() {
			err = grpcSrv.Serve(listener)
			cmd.FailOnError(err, "SA gRPC service failed")
		}()
	}

	amqpConf := saConf.AMQP
	sas, err := rpc.NewAmqpRPCServer(amqpConf, c.SA.MaxConcurrentRPCServerRequests, scope, logger)
	cmd.FailOnError(err, "Unable to create SA RPC server")

	go cmd.CatchSignals(logger, func() {
		sas.Stop()
		if grpcSrv != nil {
			grpcSrv.GracefulStop()
		}
	})

	err = rpc.NewStorageAuthorityServer(sas, sai)
	cmd.FailOnError(err, "Unable to setup SA RPC server")

	go cmd.DebugServer(c.SA.DebugAddr)
	go cmd.ProfileCmd(scope)

	err = sas.Start(amqpConf)
	cmd.FailOnError(err, "Unable to run SA RPC server")
}
Example #8
0
func main() {
	configFile := flag.String("config", "", "File path to the configuration file for this service")
	flag.Parse()
	if *configFile == "" {
		flag.Usage()
		os.Exit(1)
	}

	var c config
	err := cmd.ReadConfigFile(*configFile, &c)
	cmd.FailOnError(err, "Reading JSON config file into config structure")

	err = features.Set(c.CA.Features)
	cmd.FailOnError(err, "Failed to set feature flags")

	stats, logger := cmd.StatsAndLogging(c.Statsd, c.Syslog)
	scope := metrics.NewStatsdScope(stats, "CA")
	defer logger.AuditPanic()
	logger.Info(cmd.VersionString(clientName))

	cmd.FailOnError(c.PA.CheckChallenges(), "Invalid PA configuration")

	pa, err := policy.New(c.PA.Challenges)
	cmd.FailOnError(err, "Couldn't create PA")

	if c.CA.HostnamePolicyFile == "" {
		cmd.FailOnError(fmt.Errorf("HostnamePolicyFile was empty."), "")
	}
	err = pa.SetHostnamePolicyFile(c.CA.HostnamePolicyFile)
	cmd.FailOnError(err, "Couldn't load hostname policy file")

	issuers, err := loadIssuers(c)
	cmd.FailOnError(err, "Couldn't load issuers")

	cai, err := ca.NewCertificateAuthorityImpl(
		c.CA,
		clock.Default(),
		scope,
		issuers,
		goodkey.NewKeyPolicy(),
		logger)
	cmd.FailOnError(err, "Failed to create CA impl")
	cai.PA = pa

	amqpConf := c.CA.AMQP
	if c.CA.SAService != nil {
		conn, err := bgrpc.ClientSetup(c.CA.SAService, scope)
		cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
		cai.SA = bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
	} else {
		cai.SA, err = rpc.NewStorageAuthorityClient(clientName, amqpConf, scope)
		cmd.FailOnError(err, "Failed to create SA client")
	}

	if amqpConf.Publisher != nil {
		cai.Publisher, err = rpc.NewPublisherClient(clientName, amqpConf, scope)
		cmd.FailOnError(err, "Failed to create Publisher client")
	}

	var grpcSrv *grpc.Server
	if c.CA.GRPC != nil {
		s, l, err := bgrpc.NewServer(c.CA.GRPC, scope)
		cmd.FailOnError(err, "Unable to setup CA gRPC server")
		caWrapper := bgrpc.NewCertificateAuthorityServer(cai)
		caPB.RegisterCertificateAuthorityServer(s, caWrapper)
		go func() {
			err = s.Serve(l)
			cmd.FailOnError(err, "CA gRPC service failed")
		}()
		grpcSrv = s
	}

	cas, err := rpc.NewAmqpRPCServer(amqpConf, c.CA.MaxConcurrentRPCServerRequests, scope, logger)
	cmd.FailOnError(err, "Unable to create CA RPC server")

	go cmd.CatchSignals(logger, func() {
		cas.Stop()
		if grpcSrv != nil {
			grpcSrv.GracefulStop()
		}
	})

	err = rpc.NewCertificateAuthorityServer(cas, cai)
	cmd.FailOnError(err, "Failed to create Certificate Authority RPC server")

	go cmd.DebugServer(c.CA.DebugAddr)
	go cmd.ProfileCmd(scope)

	err = cas.Start(amqpConf)
	cmd.FailOnError(err, "Unable to run CA RPC server")
}
Example #9
0
func main() {
	configFile := flag.String("config", "", "File path to the configuration file for this service")
	flag.Parse()
	if *configFile == "" {
		flag.Usage()
		os.Exit(1)
	}

	var c config
	err := cmd.ReadConfigFile(*configFile, &c)
	cmd.FailOnError(err, "Reading JSON config file into config structure")

	err = features.Set(c.RA.Features)
	cmd.FailOnError(err, "Failed to set feature flags")

	stats, logger := cmd.StatsAndLogging(c.Statsd, c.Syslog)
	scope := metrics.NewStatsdScope(stats, "RA")
	defer logger.AuditPanic()
	logger.Info(cmd.VersionString(clientName))

	// Validate PA config and set defaults if needed
	cmd.FailOnError(c.PA.CheckChallenges(), "Invalid PA configuration")

	pa, err := policy.New(c.PA.Challenges)
	cmd.FailOnError(err, "Couldn't create PA")

	if c.RA.HostnamePolicyFile == "" {
		cmd.FailOnError(fmt.Errorf("HostnamePolicyFile must be provided."), "")
	}
	err = pa.SetHostnamePolicyFile(c.RA.HostnamePolicyFile)
	cmd.FailOnError(err, "Couldn't load hostname policy file")

	amqpConf := c.RA.AMQP
	var vac core.ValidationAuthority
	if c.RA.VAService != nil {
		conn, err := bgrpc.ClientSetup(c.RA.VAService, scope)
		cmd.FailOnError(err, "Unable to create VA client")
		vac = bgrpc.NewValidationAuthorityGRPCClient(conn)
	} else {
		vac, err = rpc.NewValidationAuthorityClient(clientName, amqpConf, scope)
		cmd.FailOnError(err, "Unable to create VA client")
	}

	var cac core.CertificateAuthority
	if c.RA.CAService != nil {
		conn, err := bgrpc.ClientSetup(c.RA.CAService, scope)
		cmd.FailOnError(err, "Unable to create CA client")
		cac = bgrpc.NewCertificateAuthorityClient(caPB.NewCertificateAuthorityClient(conn))
	} else {
		cac, err = rpc.NewCertificateAuthorityClient(clientName, amqpConf, scope)
		cmd.FailOnError(err, "Unable to create CA client")
	}

	var pubc core.Publisher
	if c.RA.PublisherService != nil {
		conn, err := bgrpc.ClientSetup(c.RA.PublisherService, scope)
		cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to Publisher")
		pubc = bgrpc.NewPublisherClientWrapper(pubPB.NewPublisherClient(conn))
	}

	var sac core.StorageAuthority
	if c.RA.SAService != nil {
		conn, err := bgrpc.ClientSetup(c.RA.SAService, scope)
		cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
		sac = bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
	} else {
		sac, err = rpc.NewStorageAuthorityClient(clientName, amqpConf, scope)
		cmd.FailOnError(err, "Unable to create SA client")
	}

	// TODO(patf): remove once RA.authorizationLifetimeDays is deployed
	authorizationLifetime := 300 * 24 * time.Hour
	if c.RA.AuthorizationLifetimeDays != 0 {
		authorizationLifetime = time.Duration(c.RA.AuthorizationLifetimeDays) * 24 * time.Hour
	}

	// TODO(patf): remove once RA.pendingAuthorizationLifetimeDays is deployed
	pendingAuthorizationLifetime := 7 * 24 * time.Hour
	if c.RA.PendingAuthorizationLifetimeDays != 0 {
		pendingAuthorizationLifetime = time.Duration(c.RA.PendingAuthorizationLifetimeDays) * 24 * time.Hour
	}

	rai := ra.NewRegistrationAuthorityImpl(
		clock.Default(),
		logger,
		scope,
		c.RA.MaxContactsPerRegistration,
		goodkey.NewKeyPolicy(),
		c.RA.MaxNames,
		c.RA.DoNotForceCN,
		c.RA.ReuseValidAuthz,
		authorizationLifetime,
		pendingAuthorizationLifetime,
		pubc)

	policyErr := rai.SetRateLimitPoliciesFile(c.RA.RateLimitPoliciesFilename)
	cmd.FailOnError(policyErr, "Couldn't load rate limit policies file")
	rai.PA = pa

	raDNSTimeout, err := time.ParseDuration(c.Common.DNSTimeout)
	cmd.FailOnError(err, "Couldn't parse RA DNS timeout")
	dnsTries := c.RA.DNSTries
	if dnsTries < 1 {
		dnsTries = 1
	}
	if !c.Common.DNSAllowLoopbackAddresses {
		rai.DNSResolver = bdns.NewDNSResolverImpl(
			raDNSTimeout,
			[]string{c.Common.DNSResolver},
			nil,
			scope,
			clock.Default(),
			dnsTries)
	} else {
		rai.DNSResolver = bdns.NewTestDNSResolverImpl(
			raDNSTimeout,
			[]string{c.Common.DNSResolver},
			scope,
			clock.Default(),
			dnsTries)
	}

	rai.VA = vac
	rai.CA = cac
	rai.SA = sac

	err = rai.UpdateIssuedCountForever()
	cmd.FailOnError(err, "Updating total issuance count")

	var grpcSrv *grpc.Server
	if c.RA.GRPC != nil {
		var listener net.Listener
		grpcSrv, listener, err = bgrpc.NewServer(c.RA.GRPC, scope)
		cmd.FailOnError(err, "Unable to setup RA gRPC server")
		gw := bgrpc.NewRegistrationAuthorityServer(rai)
		rapb.RegisterRegistrationAuthorityServer(grpcSrv, gw)
		go func() {
			err = grpcSrv.Serve(listener)
			cmd.FailOnError(err, "RA gRPC service failed")
		}()
	}

	ras, err := rpc.NewAmqpRPCServer(amqpConf, c.RA.MaxConcurrentRPCServerRequests, scope, logger)
	cmd.FailOnError(err, "Unable to create RA RPC server")

	go cmd.CatchSignals(logger, func() {
		ras.Stop()
		if grpcSrv != nil {
			grpcSrv.GracefulStop()
		}
	})

	err = rpc.NewRegistrationAuthorityServer(ras, rai, logger)
	cmd.FailOnError(err, "Unable to setup RA RPC server")

	go cmd.DebugServer(c.RA.DebugAddr)
	go cmd.ProfileCmd(scope)

	err = ras.Start(amqpConf)
	cmd.FailOnError(err, "Unable to run RA RPC server")
}