Beispiel #1
0
func main() {
	configPath := flag.String("config", "config.yml", "Path to configuration file")
	flag.Parse()

	configBytes, err := ioutil.ReadFile(*configPath)
	cmd.FailOnError(err, fmt.Sprintf("Failed to read configuration file from '%s'", *configPath))
	var c config
	err = yaml.Unmarshal(configBytes, &c)
	cmd.FailOnError(err, fmt.Sprintf("Failed to parse configuration file from '%s'", *configPath))

	go cmd.DebugServer(c.DebugAddr)

	stats, err := statsd.NewClient(c.StatsdServer, c.StatsdPrefix)
	cmd.FailOnError(err, "Failed to create StatsD client")
	scope := metrics.NewStatsdScope(stats, "caa-service")

	resolver := bdns.NewDNSResolverImpl(
		c.DNSTimeout.Duration,
		[]string{c.DNSResolver},
		scope,
		clock.Default(),
		5,
	)

	s, l, err := bgrpc.NewServer(&c.GRPC, scope)
	cmd.FailOnError(err, "Failed to setup gRPC server")
	ccs := &caaCheckerServer{resolver, scope}
	pb.RegisterCAACheckerServer(s, ccs)
	err = s.Serve(l)
	cmd.FailOnError(err, "gRPC service failed")
}
Beispiel #2
0
func main() {
	app := cmd.NewAppShell("boulder-ocsp-responder", "Handles OCSP requests")
	app.Action = func(c cmd.Config, stats metrics.Statter, logger blog.Logger) {
		go cmd.DebugServer(c.OCSPResponder.DebugAddr)

		go cmd.ProfileCmd("OCSP", stats)

		config := c.OCSPResponder
		var source cfocsp.Source

		// DBConfig takes precedence over Source, if present.
		dbConnect, err := config.DBConfig.URL()
		cmd.FailOnError(err, "Reading DB config")
		if dbConnect == "" {
			dbConnect = config.Source
		}
		url, err := url.Parse(dbConnect)
		cmd.FailOnError(err, fmt.Sprintf("Source was not a URL: %s", config.Source))

		if url.Scheme == "mysql+tcp" {
			logger.Info(fmt.Sprintf("Loading OCSP Database for CA Cert: %s", c.Common.IssuerCert))
			dbMap, err := sa.NewDbMap(config.Source)
			cmd.FailOnError(err, "Could not connect to database")
			sa.SetSQLDebug(dbMap, logger)
			source, err = makeDBSource(dbMap, c.Common.IssuerCert, logger)
			cmd.FailOnError(err, "Couldn't load OCSP DB")
		} else if url.Scheme == "file" {
			filename := url.Path
			// Go interprets cwd-relative file urls (file:test/foo.txt) as having the
			// relative part of the path in the 'Opaque' field.
			if filename == "" {
				filename = url.Opaque
			}
			source, err = cfocsp.NewSourceFromFile(filename)
			cmd.FailOnError(err, fmt.Sprintf("Couldn't read file: %s", url.Path))
		} else {
			cmd.FailOnError(errors.New(`"source" parameter not found in JSON config`), "unable to start ocsp-responder")
		}

		stopTimeout, err := time.ParseDuration(c.OCSPResponder.ShutdownStopTimeout)
		cmd.FailOnError(err, "Couldn't parse shutdown stop timeout")
		killTimeout, err := time.ParseDuration(c.OCSPResponder.ShutdownKillTimeout)
		cmd.FailOnError(err, "Couldn't parse shutdown kill timeout")
		m := mux(stats, c.OCSPResponder.Path, source)
		srv := &http.Server{
			Addr:    c.OCSPResponder.ListenAddress,
			Handler: m,
		}

		hd := &httpdown.HTTP{
			StopTimeout: stopTimeout,
			KillTimeout: killTimeout,
			Stats:       metrics.NewFBAdapter(stats, "OCSP", clock.Default()),
		}
		err = httpdown.ListenAndServe(srv, hd)
		cmd.FailOnError(err, "Error starting HTTP server")
	}

	app.Run()
}
func TestDNSValidationInvalid(t *testing.T) {
	var notDNS = core.AcmeIdentifier{
		Type:  core.IdentifierType("iris"),
		Value: "790DB180-A274-47A4-855F-31C428CB1072",
	}

	chalDNS := core.DNSChallenge01(accountKey)
	chalDNS.ProvidedKeyAuthorization, _ = chalDNS.ExpectedKeyAuthorization()

	var authz = core.Authorization{
		ID:             core.NewToken(),
		RegistrationID: 1,
		Identifier:     notDNS,
		Challenges:     []core.Challenge{chalDNS},
	}

	stats, _ := statsd.NewNoopClient()
	va := NewValidationAuthorityImpl(&cmd.PortConfig{}, nil, nil, stats, clock.Default())
	va.DNSResolver = &bdns.MockDNSResolver{}
	mockRA := &MockRegistrationAuthority{}
	va.RA = mockRA

	va.validate(ctx, authz, 0)

	test.AssertNotNil(t, mockRA.lastAuthz, "Should have gotten an authorization")
	test.Assert(t, authz.Challenges[0].Status == core.StatusInvalid, "Should be invalid.")
	test.AssertEquals(t, authz.Challenges[0].Error.Type, probs.MalformedProblem)
}
func TestDNSValidationNotSane(t *testing.T) {
	stats, _ := statsd.NewNoopClient()
	va := NewValidationAuthorityImpl(&cmd.PortConfig{}, nil, nil, stats, clock.Default())
	va.DNSResolver = &bdns.MockDNSResolver{}
	mockRA := &MockRegistrationAuthority{}
	va.RA = mockRA

	chal0 := core.DNSChallenge01(accountKey)
	chal0.Token = ""

	chal1 := core.DNSChallenge01(accountKey)
	chal1.Token = "yfCBb-bRTLz8Wd1C0lTUQK3qlKj3-t2tYGwx5Hj7r_"

	chal2 := core.DNSChallenge01(accountKey)
	chal2.ProvidedKeyAuthorization = ""

	chal3 := core.DNSChallenge01(accountKey)
	chal3.ProvidedKeyAuthorization = "a.a"

	var authz = core.Authorization{
		ID:             core.NewToken(),
		RegistrationID: 1,
		Identifier:     ident,
		Challenges:     []core.Challenge{chal0, chal1, chal2, chal3},
	}

	for i := 0; i < len(authz.Challenges); i++ {
		va.validate(ctx, authz, i)
		test.AssertEquals(t, authz.Challenges[i].Status, core.StatusInvalid)
		test.AssertEquals(t, authz.Challenges[i].Error.Type, probs.MalformedProblem)
		if !strings.Contains(authz.Challenges[i].Error.Error(), "Challenge failed sanity check.") {
			t.Errorf("Got wrong error: %s", authz.Challenges[i].Error)
		}
	}
}
func TestValidateHTTPResponseDocument(t *testing.T) {
	chall := core.HTTPChallenge01(accountKey)
	setChallengeToken(&chall, core.NewToken())

	hs := httpSrv(t, `a.StartOfLine.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.PastTruncationPoint.aaaaaaaaaaaaaaaaaaaa`)
	port, err := getPort(hs)
	test.AssertNotError(t, err, "failed to get test server port")
	stats, _ := statsd.NewNoopClient()
	va := NewValidationAuthorityImpl(&cmd.PortConfig{HTTPPort: port}, nil, nil, stats, clock.Default())
	va.DNSResolver = &bdns.MockDNSResolver{}
	mockRA := &MockRegistrationAuthority{}
	va.RA = mockRA

	defer hs.Close()

	var authz = core.Authorization{
		ID:             core.NewToken(),
		RegistrationID: 1,
		Identifier:     ident,
		Challenges:     []core.Challenge{chall},
	}
	va.validate(ctx, authz, 0)

	test.AssertEquals(t, core.StatusInvalid, mockRA.lastAuthz.Challenges[0].Status)
	test.Assert(t, len(log.GetAllMatching("StartOfLine")) > 1, "Beginning of response body not logged")
	test.Assert(t, len(log.GetAllMatching("…")) > 1, "Ellipsis not logged")
	test.AssertEquals(t, len(log.GetAllMatching("PastTruncationPoint")), 0) // End of response body was logged

}
func TestUpdateValidations(t *testing.T) {
	stats, _ := statsd.NewNoopClient()
	va := NewValidationAuthorityImpl(&cmd.PortConfig{}, nil, nil, stats, clock.Default())
	va.DNSResolver = &bdns.MockDNSResolver{}
	mockRA := &MockRegistrationAuthority{}
	va.RA = mockRA

	chall := core.HTTPChallenge01(accountKey)
	chall.ValidationRecord = []core.ValidationRecord{}
	setChallengeToken(&chall, core.NewToken())

	var authz = core.Authorization{
		ID:             core.NewToken(),
		RegistrationID: 1,
		Identifier:     ident,
		Challenges:     []core.Challenge{chall},
	}

	started := time.Now()
	err := va.UpdateValidations(ctx, authz, 0)
	if err != nil {
		test.AssertNotError(t, err, "UpdateValidations failed")
	}
	took := time.Since(started)

	// Check that the call to va.UpdateValidations didn't block for 3 seconds
	test.Assert(t, (took < (time.Second * 3)), "UpdateValidations blocked")
}
func TestValidateHTTP(t *testing.T) {
	chall := core.HTTPChallenge01(accountKey)
	setChallengeToken(&chall, core.NewToken())

	hs := httpSrv(t, chall.Token)
	port, err := getPort(hs)
	test.AssertNotError(t, err, "failed to get test server port")
	stats, _ := statsd.NewNoopClient()
	va := NewValidationAuthorityImpl(&cmd.PortConfig{HTTPPort: port}, nil, nil, stats, clock.Default())
	va.DNSResolver = &bdns.MockDNSResolver{}
	mockRA := &MockRegistrationAuthority{}
	va.RA = mockRA

	defer hs.Close()

	var authz = core.Authorization{
		ID:             core.NewToken(),
		RegistrationID: 1,
		Identifier:     ident,
		Challenges:     []core.Challenge{chall},
	}
	va.validate(ctx, authz, 0)

	test.AssertEquals(t, core.StatusValid, mockRA.lastAuthz.Challenges[0].Status)
}
func TestHTTPRedirectUserAgent(t *testing.T) {
	chall := core.HTTPChallenge01(accountKey)
	setChallengeToken(&chall, expectedToken)

	hs := httpSrv(t, expectedToken)
	defer hs.Close()
	port, err := getPort(hs)
	test.AssertNotError(t, err, "failed to get test server port")
	stats, _ := statsd.NewNoopClient()
	va := NewValidationAuthorityImpl(&cmd.PortConfig{HTTPPort: port}, nil, nil, stats, clock.Default())
	va.DNSResolver = &bdns.MockDNSResolver{}
	va.UserAgent = rejectUserAgent

	setChallengeToken(&chall, pathMoved)
	_, prob := va.validateHTTP01(ctx, ident, chall)
	if prob == nil {
		t.Fatalf("Challenge with rejectUserAgent should have failed (%s).", pathMoved)
	}

	setChallengeToken(&chall, pathFound)
	_, prob = va.validateHTTP01(ctx, ident, chall)
	if prob == nil {
		t.Fatalf("Challenge with rejectUserAgent should have failed (%s).", pathFound)
	}
}
Beispiel #9
0
func main() {
	app := cmd.NewAppShell("boulder-sa", "Handles SQL operations")
	app.Action = func(c cmd.Config, stats metrics.Statter, logger blog.Logger) {
		saConf := c.SA
		go cmd.DebugServer(saConf.DebugAddr)

		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, metrics.NewStatsdScope(stats, "SA"))

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

		go cmd.ProfileCmd("SA", stats)

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

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

	app.Run()
}
func TestDNSValidationServFail(t *testing.T) {
	stats, _ := statsd.NewNoopClient()
	va := NewValidationAuthorityImpl(&cmd.PortConfig{}, nil, nil, stats, clock.Default())
	va.DNSResolver = &bdns.MockDNSResolver{}
	mockRA := &MockRegistrationAuthority{}
	va.RA = mockRA

	chalDNS := createChallenge(core.ChallengeTypeDNS01)

	badIdent := core.AcmeIdentifier{
		Type:  core.IdentifierDNS,
		Value: "servfail.com",
	}
	var authz = core.Authorization{
		ID:             core.NewToken(),
		RegistrationID: 1,
		Identifier:     badIdent,
		Challenges:     []core.Challenge{chalDNS},
	}
	va.validate(ctx, authz, 0)

	test.AssertNotNil(t, mockRA.lastAuthz, "Should have gotten an authorization")
	test.Assert(t, authz.Challenges[0].Status == core.StatusInvalid, "Should be invalid.")
	test.AssertEquals(t, authz.Challenges[0].Error.Type, probs.ConnectionProblem)
}
Beispiel #11
0
func TestCheckCAAFallback(t *testing.T) {
	testSrv := httptest.NewServer(http.HandlerFunc(mocks.GPDNSHandler))
	defer testSrv.Close()

	stats := mocks.NewStatter()
	scope := metrics.NewStatsdScope(stats, "VA")
	logger := blog.NewMock()
	caaDR, err := cdr.New(metrics.NewNoopScope(), time.Second, 1, nil, blog.NewMock())
	test.AssertNotError(t, err, "Failed to create CAADistributedResolver")
	caaDR.URI = testSrv.URL
	caaDR.Clients["1.1.1.1"] = new(http.Client)
	va := NewValidationAuthorityImpl(
		&cmd.PortConfig{},
		nil,
		caaDR,
		&bdns.MockDNSResolver{},
		"user agent 1.0",
		"ca.com",
		scope,
		clock.Default(),
		logger)

	prob := va.checkCAA(ctx, core.AcmeIdentifier{Value: "bad-local-resolver.com", Type: "dns"})
	test.Assert(t, prob == nil, fmt.Sprintf("returned ProblemDetails was non-nil: %#v", prob))

	va.caaDR = nil
	prob = va.checkCAA(ctx, core.AcmeIdentifier{Value: "bad-local-resolver.com", Type: "dns"})
	test.Assert(t, prob != nil, "returned ProblemDetails was nil")
	test.AssertEquals(t, prob.Type, probs.ConnectionProblem)
	test.AssertEquals(t, prob.Detail, "server failure at resolver")
}
Beispiel #12
0
// NewCachePurgeClient constructs a new CachePurgeClient
func NewCachePurgeClient(
	endpoint,
	clientToken,
	clientSecret,
	accessToken string,
	retries int,
	retryBackoff time.Duration,
	log blog.Logger,
	stats metrics.Scope,
) (*CachePurgeClient, error) {
	stats = stats.NewScope("CCU")
	if strings.HasSuffix(endpoint, "/") {
		endpoint = endpoint[:len(endpoint)-1]
	}
	apiURL, err := url.Parse(endpoint)
	if err != nil {
		return nil, err
	}
	return &CachePurgeClient{
		client:       new(http.Client),
		apiEndpoint:  endpoint,
		apiHost:      apiURL.Host,
		apiScheme:    strings.ToLower(apiURL.Scheme),
		clientToken:  clientToken,
		clientSecret: clientSecret,
		accessToken:  accessToken,
		retries:      retries,
		retryBackoff: retryBackoff,
		log:          log,
		stats:        stats,
		clk:          clock.Default(),
	}, nil
}
// NewServer loads various TLS certificates and creates a
// gRPC Server that verifies the client certificate was
// issued by the provided issuer certificate and presents a
// a server TLS certificate.
func NewServer(c *cmd.GRPCServerConfig, stats metrics.Scope) (*grpc.Server, net.Listener, error) {
	cert, err := tls.LoadX509KeyPair(c.ServerCertificatePath, c.ServerKeyPath)
	if err != nil {
		return nil, nil, err
	}
	clientIssuerBytes, err := ioutil.ReadFile(c.ClientIssuerPath)
	if err != nil {
		return nil, nil, err
	}
	clientCAs := x509.NewCertPool()
	if ok := clientCAs.AppendCertsFromPEM(clientIssuerBytes); !ok {
		return nil, nil, errors.New("Failed to parse client issuer certificates")
	}
	servConf := &tls.Config{
		Certificates: []tls.Certificate{cert},
		ClientAuth:   tls.RequireAndVerifyClientCert,
		ClientCAs:    clientCAs,
	}
	creds := credentials.NewTLS(servConf)
	l, err := net.Listen("tcp", c.Address)
	if err != nil {
		return nil, nil, err
	}
	si := &serverInterceptor{stats, clock.Default()}
	return grpc.NewServer(grpc.Creds(creds), grpc.UnaryInterceptor(si.intercept)), l, nil
}
Beispiel #14
0
// NewAmqpRPCServer creates a new RPC server for the given queue and will begin
// consuming requests from the queue. To start the server you must call Start().
func NewAmqpRPCServer(
	amqpConf *cmd.AMQPConfig,
	maxConcurrentRPCServerRequests int64,
	stats metrics.Scope,
	log blog.Logger,
) (*AmqpRPCServer, error) {
	stats = stats.NewScope("RPC")

	reconnectBase := amqpConf.ReconnectTimeouts.Base.Duration
	if reconnectBase == 0 {
		reconnectBase = 20 * time.Millisecond
	}
	reconnectMax := amqpConf.ReconnectTimeouts.Max.Duration
	if reconnectMax == 0 {
		reconnectMax = time.Minute
	}

	return &AmqpRPCServer{
		serverQueue:                    amqpConf.ServiceQueue,
		connection:                     newAMQPConnector(amqpConf.ServiceQueue, reconnectBase, reconnectMax),
		log:                            log,
		dispatchTable:                  make(map[string]messageHandler),
		maxConcurrentRPCServerRequests: maxConcurrentRPCServerRequests,
		clk:   clock.Default(),
		stats: stats,
	}, nil
}
Beispiel #15
0
// New constructs a Mailer to represent an account on a particular mail
// transfer agent.
func New(
	server,
	port,
	username,
	password string,
	from mail.Address,
	logger blog.Logger,
	stats metrics.Scope,
	reconnectBase time.Duration,
	reconnectMax time.Duration) *MailerImpl {
	return &MailerImpl{
		dialer: &dialerImpl{
			username: username,
			password: password,
			server:   server,
			port:     port,
		},
		log:           logger,
		from:          from,
		clk:           clock.Default(),
		csprgSource:   realSource{},
		stats:         stats.NewScope("Mailer"),
		reconnectBase: reconnectBase,
		reconnectMax:  reconnectMax,
	}
}
Beispiel #16
0
// ClientSetup loads various TLS certificates and creates a
// gRPC TransportCredentials that presents the client certificate
// and validates the certificate presented by the server is for a
// specific hostname and issued by the provided issuer certificate
// thens dials and returns a grpc.ClientConn to the remote service.
func ClientSetup(c *cmd.GRPCClientConfig, stats metrics.Scope) (*grpc.ClientConn, error) {
	if len(c.ServerAddresses) == 0 {
		return nil, fmt.Errorf("boulder/grpc: ServerAddresses is empty")
	}
	if stats == nil {
		return nil, errNilScope
	}
	serverIssuerBytes, err := ioutil.ReadFile(c.ServerIssuerPath)
	if err != nil {
		return nil, err
	}
	rootCAs := x509.NewCertPool()
	if ok := rootCAs.AppendCertsFromPEM(serverIssuerBytes); !ok {
		return nil, fmt.Errorf("Failed to parse server issues from '%s'", c.ServerIssuerPath)
	}
	clientCert, err := tls.LoadX509KeyPair(c.ClientCertificatePath, c.ClientKeyPath)
	if err != nil {
		return nil, err
	}

	grpc_prometheus.EnableHandlingTimeHistogram()

	ci := clientInterceptor{stats.NewScope("gRPCClient"), clock.Default(), c.Timeout.Duration}
	creds := bcreds.NewClientCredentials(rootCAs, []tls.Certificate{clientCert})
	return grpc.Dial(
		"", // Since our staticResolver provides addresses we don't need to pass an address here
		grpc.WithTransportCredentials(creds),
		grpc.WithBalancer(grpc.RoundRobin(newStaticResolver(c.ServerAddresses))),
		grpc.WithUnaryInterceptor(ci.intercept),
	)
}
func TestCAAFailure(t *testing.T) {
	chall := createChallenge(core.ChallengeTypeTLSSNI01)
	hs := tlssniSrv(t, chall)
	defer hs.Close()

	port, err := getPort(hs)
	test.AssertNotError(t, err, "failed to get test server port")

	stats, _ := statsd.NewNoopClient()
	va := NewValidationAuthorityImpl(&cmd.PortConfig{TLSPort: port}, nil, nil, stats, clock.Default())
	va.DNSResolver = &bdns.MockDNSResolver{}
	mockRA := &MockRegistrationAuthority{}
	va.RA = mockRA

	ident.Value = "reserved.com"
	var authz = core.Authorization{
		ID:             core.NewToken(),
		RegistrationID: 1,
		Identifier:     ident,
		Challenges:     []core.Challenge{chall},
	}
	va.validate(ctx, authz, 0)

	test.AssertEquals(t, core.StatusInvalid, mockRA.lastAuthz.Challenges[0].Status)
}
Beispiel #18
0
// HandleFunc registers a handler at the given path. It's
// http.HandleFunc(), but with a wrapper around the handler that
// provides some generic per-request functionality:
//
// * Set a Replay-Nonce header.
//
// * Respond to OPTIONS requests, including CORS preflight requests.
//
// * Set a no cache header
//
// * Respond http.StatusMethodNotAllowed for HTTP methods other than
// those listed.
//
// * Set CORS headers when responding to CORS "actual" requests.
//
// * Never send a body in response to a HEAD request. Anything
// written by the handler will be discarded if the method is HEAD.
// Also, all handlers that accept GET automatically accept HEAD.
func (wfe *WebFrontEndImpl) HandleFunc(mux *http.ServeMux, pattern string, h wfeHandlerFunc, methods ...string) {
	methodsMap := make(map[string]bool)
	for _, m := range methods {
		methodsMap[m] = true
	}
	if methodsMap["GET"] && !methodsMap["HEAD"] {
		// Allow HEAD for any resource that allows GET
		methods = append(methods, "HEAD")
		methodsMap["HEAD"] = true
	}
	methodsStr := strings.Join(methods, ", ")
	handler := http.StripPrefix(pattern, &topHandler{
		log: wfe.log,
		clk: clock.Default(),
		wfe: wfeHandlerFunc(func(ctx context.Context, logEvent *requestEvent, response http.ResponseWriter, request *http.Request) {
			// We do not propagate errors here, because (1) they should be
			// transient, and (2) they fail closed.
			nonce, err := wfe.nonceService.Nonce()
			if err == nil {
				response.Header().Set("Replay-Nonce", nonce)
				logEvent.ResponseNonce = nonce
			} else {
				logEvent.AddError("unable to make nonce: %s", err)
			}

			switch request.Method {
			case "HEAD":
				// Go's net/http (and httptest) servers will strip out the body
				// of responses for us. This keeps the Content-Length for HEAD
				// requests as the same as GET requests per the spec.
			case "OPTIONS":
				wfe.Options(response, request, methodsStr, methodsMap)
				return
			}

			// No cache header is set for all requests, succeed or fail.
			addNoCacheHeader(response)

			if !methodsMap[request.Method] {
				response.Header().Set("Allow", methodsStr)
				wfe.sendError(response, logEvent, probs.MethodNotAllowed(), nil)
				return
			}

			wfe.setCORSHeaders(response, request, "")

			timeout := wfe.RequestTimeout
			if timeout == 0 {
				timeout = 5 * time.Minute
			}
			ctx, cancel := context.WithTimeout(ctx, timeout)
			// TODO(riking): add request context using WithValue

			// Call the wrapped handler.
			h(ctx, logEvent, response, request)
			cancel()
		}),
	})
	mux.Handle(pattern, handler)
}
func BenchmarkCheckCert(b *testing.B) {
	saDbMap, err := sa.NewDbMap(vars.DBConnSA, 0)
	if err != nil {
		fmt.Println("Couldn't connect to database")
		return
	}
	defer func() {
		test.ResetSATestDatabase(b)()
	}()

	checker := newChecker(saDbMap, clock.Default(), pa, expectedValidityPeriod)
	testKey, _ := rsa.GenerateKey(rand.Reader, 1024)
	expiry := time.Now().AddDate(0, 0, 1)
	serial := big.NewInt(1337)
	rawCert := x509.Certificate{
		Subject: pkix.Name{
			CommonName: "example.com",
		},
		NotAfter:     expiry,
		DNSNames:     []string{"example-a.com"},
		SerialNumber: serial,
	}
	certDer, _ := x509.CreateCertificate(rand.Reader, &rawCert, &rawCert, &testKey.PublicKey, testKey)
	cert := core.Certificate{
		Serial:  core.SerialToString(serial),
		Digest:  core.Fingerprint256(certDer),
		DER:     certDer,
		Issued:  time.Now(),
		Expires: expiry,
	}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		checker.checkCert(cert)
	}
}
func TestDNSValidationNoAuthorityOK(t *testing.T) {
	stats, _ := statsd.NewNoopClient()
	va := NewValidationAuthorityImpl(&cmd.PortConfig{}, nil, nil, stats, clock.Default())
	va.DNSResolver = &bdns.MockDNSResolver{}
	mockRA := &MockRegistrationAuthority{}
	va.RA = mockRA

	// create a challenge with well known token
	chalDNS := core.DNSChallenge01(accountKey)
	chalDNS.Token = expectedToken

	chalDNS.ProvidedKeyAuthorization, _ = chalDNS.ExpectedKeyAuthorization()

	goodIdent := core.AcmeIdentifier{
		Type:  core.IdentifierDNS,
		Value: "no-authority-dns01.com",
	}

	var authz = core.Authorization{
		ID:             core.NewToken(),
		RegistrationID: 1,
		Identifier:     goodIdent,
		Challenges:     []core.Challenge{chalDNS},
	}
	va.validate(ctx, authz, 0)

	test.AssertNotNil(t, mockRA.lastAuthz, "Should have gotten an authorization")
	test.Assert(t, authz.Challenges[0].Status == core.StatusValid, "Should be valid.")
}
Beispiel #21
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")

	conf := c.OCSPUpdater

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

	// Configure DB
	dbURL, err := conf.DBConfig.URL()
	cmd.FailOnError(err, "Couldn't load DB URL")
	dbMap, err := sa.NewDbMap(dbURL, conf.DBConfig.MaxDBConns)
	cmd.FailOnError(err, "Could not connect to database")
	go sa.ReportDbConnCount(dbMap, scope)

	cac, pubc, sac := setupClients(conf, scope)

	updater, err := newUpdater(
		scope,
		clock.Default(),
		dbMap,
		cac,
		pubc,
		sac,
		// Necessary evil for now
		conf,
		c.Common.CT.Logs,
		c.Common.IssuerCert,
		auditlogger,
	)

	cmd.FailOnError(err, "Failed to create updater")

	for _, l := range updater.loops {
		go func(loop *looper) {
			err = loop.loop()
			if err != nil {
				auditlogger.AuditErr(err.Error())
			}
		}(l)
	}

	go cmd.DebugServer(conf.DebugAddr)
	go cmd.ProfileCmd(scope)

	// Sleep forever (until signaled)
	select {}
}
// New constructs a Mailer suitable for doing a dry run. It simply logs each
// command that would have been run, at debug level.
func NewDryRun(from mail.Address, logger blog.Logger) *MailerImpl {
	return &MailerImpl{
		dialer:      dryRunClient{logger},
		from:        from,
		clk:         clock.Default(),
		csprgSource: realSource{},
	}
}
Beispiel #23
0
// New returns a new Logger that uses the given syslog.Writer as a backend.
func New(log *syslog.Writer, stdoutLogLevel int, syslogLogLevel int) (Logger, error) {
	if log == nil {
		return nil, errors.New("Attempted to use a nil System Logger.")
	}
	return &impl{
		&bothWriter{log, stdoutLogLevel, syslogLogLevel, clock.Default()},
	}, nil
}
func TestHTTPRedirectLookup(t *testing.T) {
	chall := core.HTTPChallenge01(accountKey)
	setChallengeToken(&chall, expectedToken)

	hs := httpSrv(t, expectedToken)
	defer hs.Close()
	port, err := getPort(hs)
	test.AssertNotError(t, err, "failed to get test server port")
	stats, _ := statsd.NewNoopClient()
	va := NewValidationAuthorityImpl(&cmd.PortConfig{HTTPPort: port}, nil, nil, stats, clock.Default())
	va.DNSResolver = &bdns.MockDNSResolver{}

	log.Clear()
	setChallengeToken(&chall, pathMoved)
	_, prob := va.validateHTTP01(ctx, ident, chall)
	if prob != nil {
		t.Fatalf("Unexpected failure in redirect (%s): %s", pathMoved, prob)
	}
	test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1)
	test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 2)

	log.Clear()
	setChallengeToken(&chall, pathFound)
	_, prob = va.validateHTTP01(ctx, ident, chall)
	if prob != nil {
		t.Fatalf("Unexpected failure in redirect (%s): %s", pathFound, prob)
	}
	test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathFound+`" to ".*/`+pathMoved+`"`)), 1)
	test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1)
	test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 3)

	log.Clear()
	setChallengeToken(&chall, pathReLookupInvalid)
	_, err = va.validateHTTP01(ctx, ident, chall)
	test.AssertError(t, err, chall.Token)
	test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1)
	test.AssertEquals(t, len(log.GetAllMatching(`No IPv4 addresses found for invalid.invalid`)), 1)

	log.Clear()
	setChallengeToken(&chall, pathReLookup)
	_, prob = va.validateHTTP01(ctx, ident, chall)
	if prob != nil {
		t.Fatalf("Unexpected error in redirect (%s): %s", pathReLookup, prob)
	}
	test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathReLookup+`" to ".*other.valid:\d+/path"`)), 1)
	test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1)
	test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for other.valid \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1)

	log.Clear()
	setChallengeToken(&chall, pathRedirectPort)
	_, err = va.validateHTTP01(ctx, ident, chall)
	test.AssertError(t, err, chall.Token)
	test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/port-redirect" to ".*other.valid:8080/path"`)), 1)
	test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1)
	test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for other.valid \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1)
}
Beispiel #25
0
func main() {
	app := cmd.NewAppShell("boulder-ca", "Handles issuance operations")
	app.Action = func(c cmd.Config, stats metrics.Statter, logger blog.Logger) {
		// Validate PA config and set defaults if needed
		cmd.FailOnError(c.PA.CheckChallenges(), "Invalid PA configuration")

		go cmd.DebugServer(c.CA.DebugAddr)

		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(),
			stats,
			issuers,
			c.KeyPolicy(),
			logger)
		cmd.FailOnError(err, "Failed to create CA impl")
		cai.PA = pa

		go cmd.ProfileCmd("CA", stats)

		amqpConf := c.CA.AMQP
		cai.SA, err = rpc.NewStorageAuthorityClient(clientName, amqpConf, stats)
		cmd.FailOnError(err, "Failed to create SA client")

		if c.CA.PublisherService != nil {
			conn, err := bgrpc.ClientSetup(c.CA.PublisherService)
			cmd.FailOnError(err, "Failed to load credentials and create connection to service")
			cai.Publisher = bgrpc.NewPublisherClientWrapper(pubPB.NewPublisherClient(conn), c.CA.PublisherService.Timeout.Duration)
		} else {
			cai.Publisher, err = rpc.NewPublisherClient(clientName, amqpConf, stats)
			cmd.FailOnError(err, "Failed to create Publisher client")
		}

		cas, err := rpc.NewAmqpRPCServer(amqpConf, c.CA.MaxConcurrentRPCServerRequests, stats, logger)
		cmd.FailOnError(err, "Unable to create CA RPC server")
		err = rpc.NewCertificateAuthorityServer(cas, cai)
		cmd.FailOnError(err, "Failed to create Certificate Authority RPC server")

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

	app.Run()
}
Beispiel #26
0
// New constructs a Mailer suitable for doing a dry run. It simply logs each
// command that would have been run, at debug level.
func NewDryRun(from mail.Address, logger blog.Logger) *MailerImpl {
	stats := metrics.NewNoopScope()
	return &MailerImpl{
		dialer:      dryRunClient{logger},
		from:        from,
		clk:         clock.Default(),
		csprgSource: realSource{},
		stats:       stats,
	}
}
Beispiel #27
0
// New constructs a Mailer to represent an account on a particular mail
// transfer agent.
func New(server, port, username, password, from string) MailerImpl {
	auth := smtp.PlainAuth("", username, password, server)
	return MailerImpl{
		server:      server,
		port:        port,
		auth:        auth,
		from:        from,
		clk:         clock.Default(),
		csprgSource: realSource{},
	}
}
// Clock functions similarly to clock.Default(), but the returned value can be
// changed using the FAKECLOCK environment variable if the 'integration' build
// flag is set.
//
// The FAKECLOCK env var is in the time.UnixDate format, returned by `date -d`.
func Clock() clock.Clock {
	if tgt := os.Getenv("FAKECLOCK"); tgt != "" {
		targetTime, err := time.Parse(time.UnixDate, tgt)
		FailOnError(err, fmt.Sprintf("cmd.Clock: bad format for FAKECLOCK: %v\n", err))

		cl := clock.NewFake()
		cl.Set(targetTime)
		blog.Get().Info(fmt.Sprintf("Time was set to %v via FAKECLOCK", targetTime))
		return cl
	}
	return clock.Default()
}
func TestDNSValidationNoServer(t *testing.T) {
	c, _ := statsd.NewNoopClient()
	stats := metrics.NewNoopScope()
	va := NewValidationAuthorityImpl(&cmd.PortConfig{}, nil, nil, c, clock.Default())
	va.DNSResolver = bdns.NewTestDNSResolverImpl(time.Second*5, []string{}, stats, clock.Default(), 1)
	mockRA := &MockRegistrationAuthority{}
	va.RA = mockRA

	chalDNS := createChallenge(core.ChallengeTypeDNS01)

	var authz = core.Authorization{
		ID:             core.NewToken(),
		RegistrationID: 1,
		Identifier:     ident,
		Challenges:     []core.Challenge{chalDNS},
	}
	va.validate(ctx, authz, 0)

	test.AssertNotNil(t, mockRA.lastAuthz, "Should have gotten an authorization")
	test.Assert(t, authz.Challenges[0].Status == core.StatusInvalid, "Should be invalid.")
	test.AssertEquals(t, authz.Challenges[0].Error.Type, probs.ConnectionProblem)
}
// New constructs a Mailer to represent an account on a particular mail
// transfer agent.
func New(server, port, username, password string, from mail.Address) *MailerImpl {
	return &MailerImpl{
		dialer: &dialerImpl{
			username: username,
			password: password,
			server:   server,
			port:     port,
		},
		from:        from,
		clk:         clock.Default(),
		csprgSource: realSource{},
	}
}