func TestValidateHTTP(t *testing.T) { tls := false challHTTP := core.SimpleHTTPChallenge() challHTTP.TLS = &tls challHTTP.ValidationRecord = []core.ValidationRecord{} challHTTP.AccountKey = accountKey hs := simpleSrv(t, challHTTP.Token, tls) port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{SimpleHTTPPort: port}, stats, clock.Default()) va.DNSResolver = &mocks.MockDNS{} mockRA := &MockRegistrationAuthority{} va.RA = mockRA defer hs.Close() var authz = core.Authorization{ ID: core.NewToken(), RegistrationID: 1, Identifier: ident, Challenges: []core.Challenge{challHTTP}, } va.validate(authz, 0) test.AssertEquals(t, core.StatusValid, mockRA.lastAuthz.Challenges[0].Status) }
func TestUpdateValidations(t *testing.T) { stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default()) va.DNSResolver = &mocks.MockDNS{} mockRA := &MockRegistrationAuthority{} va.RA = mockRA tls := false challHTTP := core.SimpleHTTPChallenge() challHTTP.TLS = &tls challHTTP.ValidationRecord = []core.ValidationRecord{} var authz = core.Authorization{ ID: core.NewToken(), RegistrationID: 1, Identifier: ident, Challenges: []core.Challenge{challHTTP}, } started := time.Now() va.UpdateValidations(authz, 0) 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) err := setChallengeToken(&chall, core.NewToken()) test.AssertNotError(t, err, "Failed to complete HTTP challenge") hs := httpSrv(t, chall.Token) port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} 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(authz, 0) test.AssertEquals(t, core.StatusValid, mockRA.lastAuthz.Challenges[0].Status) }
// TODO(https://github.com/letsencrypt/boulder/issues/894): Remove this method func TestSimpleHttpTLS(t *testing.T) { chall := core.Challenge{ Type: core.ChallengeTypeSimpleHTTP, Token: expectedToken, ValidationRecord: []core.ValidationRecord{}, AccountKey: accountKey, } hs := simpleSrv(t, expectedToken, true) defer hs.Close() port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{HTTPSPort: port}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} log.Clear() finChall, err := va.validateSimpleHTTP(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertNotError(t, err, "Error validating simpleHttp") logs := log.GetAllMatching(`^\[AUDIT\] Attempting to validate simpleHttp for `) test.AssertEquals(t, len(logs), 1) test.AssertEquals(t, logs[0].Priority, syslog.LOG_NOTICE) }
func TestUpdateValidations(t *testing.T) { stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} mockRA := &MockRegistrationAuthority{} va.RA = mockRA chall := core.HTTPChallenge01(accountKey) chall.ValidationRecord = []core.ValidationRecord{} err := setChallengeToken(&chall, core.NewToken()) test.AssertNotError(t, err, "Failed to complete HTTP challenge") var authz = core.Authorization{ ID: core.NewToken(), RegistrationID: 1, Identifier: ident, Challenges: []core.Challenge{chall}, } started := time.Now() va.UpdateValidations(authz, 0) 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 TestDNSValidationNoAuthorityOK(t *testing.T) { stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{}, 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 keyAuthorization, _ := core.NewKeyAuthorization(chalDNS.Token, accountKey) chalDNS.KeyAuthorization = &keyAuthorization 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(context.Background(), authz, 0) test.AssertNotNil(t, mockRA.lastAuthz, "Should have gotten an authorization") test.Assert(t, authz.Challenges[0].Status == core.StatusValid, "Should be valid.") }
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(&PortConfig{TLSPort: port}, 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(context.Background(), authz, 0) test.AssertEquals(t, core.StatusInvalid, mockRA.lastAuthz.Challenges[0].Status) }
func TestHTTPRedirectUserAgent(t *testing.T) { chall := core.HTTPChallenge01(accountKey) err := setChallengeToken(&chall, expectedToken) test.AssertNotError(t, err, "Failed to complete HTTP challenge") 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(&PortConfig{HTTPPort: port}, nil, stats, clock.Default()) va.DNSResolver = &bdns.MockDNSResolver{} va.UserAgent = rejectUserAgent setChallengeToken(&chall, pathMoved) _, prob := va.validateHTTP01(context.Background(), ident, chall) if prob == nil { t.Fatalf("Challenge with rejectUserAgent should have failed (%s).", pathMoved) } setChallengeToken(&chall, pathFound) _, prob = va.validateHTTP01(context.Background(), ident, chall) if prob == nil { t.Fatalf("Challenge with rejectUserAgent should have failed (%s).", pathFound) } }
func TestDNSValidationNotSane(t *testing.T) { stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} 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.TLS = new(bool) *chal2.TLS = true var authz = core.Authorization{ ID: core.NewToken(), RegistrationID: 1, Identifier: ident, Challenges: []core.Challenge{chal0, chal1, chal2}, } for i := 0; i < len(authz.Challenges); i++ { va.validate(authz, i) test.AssertEquals(t, authz.Challenges[i].Status, core.StatusInvalid) test.AssertEquals(t, authz.Challenges[i].Error.Type, core.MalformedProblem) } }
// NewCachePurgeClient constructs a new CachePurgeClient func NewCachePurgeClient( endpoint, clientToken, clientSecret, accessToken string, retries int, retryBackoff time.Duration, log *blog.AuditLogger, stats statsd.Statter, ) (*CachePurgeClient, error) { 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 }
func main() { app := cmd.NewAppShell("ocsp-updater", "Generates and updates OCSP responses") app.Action = func(c cmd.Config) { // Set up logging stats, err := statsd.NewClient(c.Statsd.Server, c.Statsd.Prefix) cmd.FailOnError(err, "Couldn't connect to statsd") auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats) cmd.FailOnError(err, "Could not connect to Syslog") auditlogger.Info(app.VersionString()) blog.SetAuditLogger(auditlogger) // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 defer auditlogger.AuditPanic() go cmd.DebugServer(c.OCSPUpdater.DebugAddr) go cmd.ProfileCmd("OCSP-Updater", stats) // Configure DB dbMap, err := sa.NewDbMap(c.OCSPUpdater.DBConnect) cmd.FailOnError(err, "Could not connect to database") cac, pubc, sac, closeChan := setupClients(c, stats) updater, err := newUpdater( stats, clock.Default(), dbMap, cac, pubc, sac, // Necessary evil for now c.OCSPUpdater, len(c.Common.CT.Logs), ) for _, l := range updater.loops { go func(loop *looper) { err = loop.loop() if err != nil { auditlogger.AuditErr(err) } }(l) } cmd.FailOnError(err, "Failed to create updater") // TODO(): When the channel falls over so do we for now, if the AMQP channel // has already closed there is no real cleanup we can do. This is due to // really needing to change the underlying AMQP Server/Client reconnection // logic. err = <-closeChan auditlogger.AuditErr(fmt.Errorf(" [!] AMQP Channel closed, exiting: [%s]", err)) os.Exit(1) } app.Run() }
func main() { app := cmd.NewAppShell("boulder-sa", "Handles SQL operations") app.Action = func(c cmd.Config, stats statsd.Statter, auditlogger *blog.AuditLogger) { saConf := c.SA go cmd.DebugServer(saConf.DebugAddr) dbMap, err := sa.NewDbMap(saConf.DBConnect) cmd.FailOnError(err, "Couldn't connect to SA database") sai, err := sa.NewSQLStorageAuthority(dbMap, clock.Default()) cmd.FailOnError(err, "Failed to create SA impl") sai.SetSQLDebug(c.SQL.SQLDebug) go cmd.ProfileCmd("SA", stats) amqpConf := saConf.AMQP sas, err := rpc.NewAmqpRPCServer(amqpConf, c.SA.MaxConcurrentRPCServerRequests, stats) cmd.FailOnError(err, "Unable to create SA RPC server") rpc.NewStorageAuthorityServer(sas, sai) err = sas.Start(amqpConf) cmd.FailOnError(err, "Unable to run SA RPC 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) var authz = core.Authorization{ ID: core.NewToken(), RegistrationID: 1, Identifier: notDNS, Challenges: []core.Challenge{chalDNS}, } stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} mockRA := &MockRegistrationAuthority{} va.RA = mockRA va.validate(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, core.MalformedProblem) }
func TestDNSValidationServFail(t *testing.T) { stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} 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(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, core.ConnectionProblem) }
// 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(serverQueue string, maxConcurrentRPCServerRequests int64, c cmd.Config) (*AmqpRPCServer, error) { log := blog.GetAuditLogger() reconnectBase := c.AMQP.ReconnectTimeouts.Base.Duration if reconnectBase == 0 { reconnectBase = 20 * time.Millisecond } reconnectMax := c.AMQP.ReconnectTimeouts.Max.Duration if reconnectMax == 0 { reconnectMax = time.Minute } stats, err := statsd.NewClient(c.Statsd.Server, c.Statsd.Prefix) if err != nil { return nil, err } return &AmqpRPCServer{ serverQueue: serverQueue, connection: newAMQPConnector(serverQueue, reconnectBase, reconnectMax), log: log, dispatchTable: make(map[string]func([]byte) ([]byte, error)), maxConcurrentRPCServerRequests: maxConcurrentRPCServerRequests, clk: clock.Default(), stats: stats, }, nil }
func main() { app := cmd.NewAppShell("boulder-ocsp-responder", "Handles OCSP requests") app.Action = func(c cmd.Config, stats statsd.Statter, auditlogger *blog.AuditLogger) { go cmd.DebugServer(c.OCSPResponder.DebugAddr) go cmd.ProfileCmd("OCSP", stats) config := c.OCSPResponder var source cfocsp.Source url, err := url.Parse(config.Source) cmd.FailOnError(err, fmt.Sprintf("Source was not a URL: %s", config.Source)) if url.Scheme == "mysql+tcp" { auditlogger.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") if c.SQL.SQLDebug { sa.SetSQLDebug(dbMap, true) } source, err = makeDBSource(dbMap, c.Common.IssuerCert, auditlogger) 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 := http.StripPrefix(c.OCSPResponder.Path, handler(source, c.OCSPResponder.MaxAge.Duration)) httpMonitor := metrics.NewHTTPMonitor(stats, m, "OCSP") srv := &http.Server{ Addr: c.OCSPResponder.ListenAddress, Handler: httpMonitor.Handle(), } 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 main() { app := cmd.NewAppShell("boulder-ra", "Handles service orchestration") app.Action = func(c cmd.Config, stats statsd.Statter, auditlogger *blog.AuditLogger) { // Validate PA config and set defaults if needed cmd.FailOnError(c.PA.CheckChallenges(), "Invalid PA configuration") c.PA.SetDefaultChallengesIfEmpty() go cmd.DebugServer(c.RA.DebugAddr) paDbMap, err := sa.NewDbMap(c.PA.DBConnect) cmd.FailOnError(err, "Couldn't connect to policy database") pa, err := policy.NewPolicyAuthorityImpl(paDbMap, c.PA.EnforcePolicyWhitelist, c.PA.Challenges) cmd.FailOnError(err, "Couldn't create PA") rateLimitPolicies, err := cmd.LoadRateLimitPolicies(c.RA.RateLimitPoliciesFilename) cmd.FailOnError(err, "Couldn't load rate limit policies file") go cmd.ProfileCmd("RA", stats) amqpConf := c.RA.AMQP vac, err := rpc.NewValidationAuthorityClient(clientName, amqpConf, stats) cmd.FailOnError(err, "Unable to create VA client") cac, err := rpc.NewCertificateAuthorityClient(clientName, amqpConf, stats) cmd.FailOnError(err, "Unable to create CA client") sac, err := rpc.NewStorageAuthorityClient(clientName, amqpConf, stats) cmd.FailOnError(err, "Unable to create SA client") var dc *ra.DomainCheck if c.RA.UseIsSafeDomain { dc = &ra.DomainCheck{VA: vac} } rai := ra.NewRegistrationAuthorityImpl(clock.Default(), auditlogger, stats, dc, rateLimitPolicies, c.RA.MaxContactsPerRegistration) rai.PA = pa raDNSTimeout, err := time.ParseDuration(c.Common.DNSTimeout) cmd.FailOnError(err, "Couldn't parse RA DNS timeout") if !c.Common.DNSAllowLoopbackAddresses { rai.DNSResolver = core.NewDNSResolverImpl(raDNSTimeout, []string{c.Common.DNSResolver}) } else { rai.DNSResolver = core.NewTestDNSResolverImpl(raDNSTimeout, []string{c.Common.DNSResolver}) } rai.VA = vac rai.CA = cac rai.SA = sac ras, err := rpc.NewAmqpRPCServer(amqpConf, c.RA.MaxConcurrentRPCServerRequests, stats) cmd.FailOnError(err, "Unable to create RA RPC server") rpc.NewRegistrationAuthorityServer(ras, rai) err = ras.Start(amqpConf) cmd.FailOnError(err, "Unable to run RA RPC server") } app.Run() }
func TestHTTPRedirectLookup(t *testing.T) { chall := core.HTTPChallenge01(accountKey) err := setChallengeToken(&chall, expectedToken) test.AssertNotError(t, err, "Failed to complete HTTP challenge") 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(&PortConfig{HTTPPort: port}, nil, stats, clock.Default()) va.DNSResolver = &bdns.MockDNSResolver{} log.Clear() setChallengeToken(&chall, pathMoved) _, prob := va.validateHTTP01(context.Background(), 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(context.Background(), 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(context.Background(), 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(context.Background(), 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(context.Background(), 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) }
func main() { app := cmd.NewAppShell("boulder-ca", "Handles issuance operations") app.Action = func(c cmd.Config) { stats, err := statsd.NewClient(c.Statsd.Server, c.Statsd.Prefix) cmd.FailOnError(err, "Couldn't connect to statsd") // Set up logging auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats) cmd.FailOnError(err, "Could not connect to Syslog") // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 defer auditlogger.AuditPanic() blog.SetAuditLogger(auditlogger) go cmd.DebugServer(c.CA.DebugAddr) dbMap, err := sa.NewDbMap(c.CA.DBConnect) cmd.FailOnError(err, "Couldn't connect to CA database") cadb, err := ca.NewCertificateAuthorityDatabaseImpl(dbMap) cmd.FailOnError(err, "Failed to create CA database") paDbMap, err := sa.NewDbMap(c.PA.DBConnect) cmd.FailOnError(err, "Couldn't connect to policy database") pa, err := policy.NewPolicyAuthorityImpl(paDbMap, c.PA.EnforcePolicyWhitelist) cmd.FailOnError(err, "Couldn't create PA") cai, err := ca.NewCertificateAuthorityImpl(cadb, c.CA, clock.Default(), c.Common.IssuerCert) cmd.FailOnError(err, "Failed to create CA impl") cai.MaxKeySize = c.Common.MaxKeySize cai.PA = pa go cmd.ProfileCmd("CA", stats) connectionHandler := func(srv *rpc.AmqpRPCServer) { saRPC, err := rpc.NewAmqpRPCClient("CA->SA", c.AMQP.SA.Server, srv.Channel) cmd.FailOnError(err, "Unable to create RPC client") sac, err := rpc.NewStorageAuthorityClient(saRPC) cmd.FailOnError(err, "Failed to create SA client") cai.SA = &sac } cas, err := rpc.NewAmqpRPCServer(c.AMQP.CA.Server, connectionHandler) cmd.FailOnError(err, "Unable to create CA RPC server") rpc.NewCertificateAuthorityServer(cas, cai) auditlogger.Info(app.VersionString()) err = cas.Start(c) cmd.FailOnError(err, "Unable to run CA RPC server") } app.Run() }
func TestHTTPRedirectLookup(t *testing.T) { chall := core.HTTPChallenge01(accountKey) err := setChallengeToken(&chall, expectedToken) test.AssertNotError(t, err, "Failed to complete HTTP challenge") 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(&PortConfig{HTTPPort: port}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} log.Clear() setChallengeToken(&chall, pathMoved) finChall, err := va.validateHTTP01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertNotError(t, err, chall.Token) 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) finChall, err = va.validateHTTP01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertNotError(t, err, chall.Token) 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) finChall, err = va.validateHTTP01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusInvalid) 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) finChall, err = va.validateHTTP01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertNotError(t, err, chall.Token) 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) finChall, err = va.validateHTTP01(ident, chall) fmt.Println(finChall.ValidationRecord) test.AssertEquals(t, finChall.Status, core.StatusInvalid) 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) }
func TestTLSSNI(t *testing.T) { chall := createChallenge(core.ChallengeTypeTLSSNI01) hs := tlssniSrv(t, chall) port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{TLSPort: port}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} log.Clear() finChall, err := va.validateTLSSNI01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertNotError(t, err, "") test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) log.Clear() invalidChall, err := va.validateTLSSNI01(core.AcmeIdentifier{ Type: core.IdentifierType("ip"), Value: net.JoinHostPort("127.0.0.1", fmt.Sprintf("%d", port)), }, chall) test.AssertEquals(t, invalidChall.Status, core.StatusInvalid) test.AssertError(t, err, "IdentifierType IP shouldn't have worked.") test.AssertEquals(t, invalidChall.Error.Type, core.MalformedProblem) log.Clear() invalidChall, err = va.validateTLSSNI01(core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "always.invalid"}, chall) test.AssertEquals(t, invalidChall.Status, core.StatusInvalid) test.AssertError(t, err, "Domain name was supposed to be invalid.") test.AssertEquals(t, invalidChall.Error.Type, core.UnknownHostProblem) // Need to create a new authorized keys object to get an unknown SNI (from the signature value) chall.Token = core.NewToken() keyAuthorization, _ := core.NewKeyAuthorization(chall.Token, accountKey) chall.KeyAuthorization = &keyAuthorization log.Clear() started := time.Now() invalidChall, err = va.validateTLSSNI01(ident, chall) took := time.Since(started) // Check that the HTTP connection times out after 5 seconds and doesn't block for 10 seconds test.Assert(t, (took > (time.Second * 5)), "HTTP timed out before 5 seconds") test.Assert(t, (took < (time.Second * 10)), "HTTP connection didn't timeout after 5 seconds") test.AssertEquals(t, invalidChall.Status, core.StatusInvalid) test.AssertError(t, err, "Connection should've timed out") test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) // Take down validation server and check that validation fails. hs.Close() invalidChall, err = va.validateTLSSNI01(ident, chall) test.AssertEquals(t, invalidChall.Status, core.StatusInvalid) test.AssertError(t, err, "Server's down; expected refusal. Where did we connect?") test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem) }
func main() { app := cmd.NewAppShell("ocsp-updater", "Generates and updates OCSP responses") app.Action = func(c cmd.Config) { // Set up logging stats, err := statsd.NewClient(c.Statsd.Server, c.Statsd.Prefix) cmd.FailOnError(err, "Couldn't connect to statsd") auditlogger, err := blog.Dial(c.Syslog.Network, c.Syslog.Server, c.Syslog.Tag, stats) cmd.FailOnError(err, "Could not connect to Syslog") auditlogger.Info(app.VersionString()) blog.SetAuditLogger(auditlogger) // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 defer auditlogger.AuditPanic() go cmd.DebugServer(c.OCSPUpdater.DebugAddr) go cmd.ProfileCmd("OCSP-Updater", stats) // Configure DB dbMap, err := sa.NewDbMap(c.OCSPUpdater.DBConnect) cmd.FailOnError(err, "Could not connect to database") cac, pubc, sac := setupClients(c, stats) updater, err := newUpdater( stats, clock.Default(), dbMap, cac, pubc, sac, // Necessary evil for now c.OCSPUpdater, len(c.Common.CT.Logs), c.Common.IssuerCert, ) 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) } }(l) } // Sleep forever (until signaled) select {} } app.Run() }
func newChecker(dbMap *gorp.DbMap) certChecker { c := certChecker{ pa: policy.NewPolicyAuthorityImpl(), dbMap: dbMap, certs: make(chan core.Certificate, batchSize), clock: clock.Default(), } c.issuedReport.Entries = make(map[string]reportEntry) return c }
func main() { app := cmd.NewAppShell("boulder-va", "Handles challenge validation") app.Action = func(c cmd.Config, stats statsd.Statter, auditlogger *blog.AuditLogger) { go cmd.DebugServer(c.VA.DebugAddr) go cmd.ProfileCmd("VA", stats) pc := &va.PortConfig{ HTTPPort: 80, HTTPSPort: 443, TLSPort: 443, } if c.VA.PortConfig.HTTPPort != 0 { pc.HTTPPort = c.VA.PortConfig.HTTPPort } if c.VA.PortConfig.HTTPSPort != 0 { pc.HTTPSPort = c.VA.PortConfig.HTTPSPort } if c.VA.PortConfig.TLSPort != 0 { pc.TLSPort = c.VA.PortConfig.TLSPort } clk := clock.Default() sbc := newGoogleSafeBrowsing(c.VA.GoogleSafeBrowsing) vai := va.NewValidationAuthorityImpl(pc, sbc, stats, clk) dnsTimeout, err := time.ParseDuration(c.Common.DNSTimeout) cmd.FailOnError(err, "Couldn't parse DNS timeout") scoped := metrics.NewStatsdScope(stats, "VA", "DNS") dnsTries := c.VA.DNSTries if dnsTries < 1 { dnsTries = 1 } if !c.Common.DNSAllowLoopbackAddresses { vai.DNSResolver = bdns.NewDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver}, scoped, clk, dnsTries) } else { vai.DNSResolver = bdns.NewTestDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver}, scoped, clk, dnsTries) } vai.UserAgent = c.VA.UserAgent vai.IssuerDomain = c.VA.IssuerDomain amqpConf := c.VA.AMQP rac, err := rpc.NewRegistrationAuthorityClient(clientName, amqpConf, stats) cmd.FailOnError(err, "Unable to create RA client") vai.RA = rac vas, err := rpc.NewAmqpRPCServer(amqpConf, c.VA.MaxConcurrentRPCServerRequests, stats) cmd.FailOnError(err, "Unable to create VA RPC server") rpc.NewValidationAuthorityServer(vas, vai) err = vas.Start(amqpConf) cmd.FailOnError(err, "Unable to run VA RPC server") } app.Run() }
func main() { app := cmd.NewAppShell("boulder-ca", "Handles issuance operations") app.Action = func(c cmd.Config, stats statsd.Statter, auditlogger *blog.AuditLogger) { // Validate PA config and set defaults if needed cmd.FailOnError(c.PA.CheckChallenges(), "Invalid PA configuration") // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 defer auditlogger.AuditPanic() blog.SetAuditLogger(auditlogger) go cmd.DebugServer(c.CA.DebugAddr) dbURL, err := c.PA.DBConfig.URL() cmd.FailOnError(err, "Couldn't load DB URL") paDbMap, err := sa.NewDbMap(dbURL) cmd.FailOnError(err, "Couldn't connect to policy database") pa, err := policy.NewPolicyAuthorityImpl(paDbMap, c.PA.EnforcePolicyWhitelist, c.PA.Challenges) cmd.FailOnError(err, "Couldn't create PA") priv, err := loadPrivateKey(c.CA.Key) cmd.FailOnError(err, "Couldn't load private key") issuer, err := core.LoadCert(c.Common.IssuerCert) cmd.FailOnError(err, "Couldn't load issuer cert") cai, err := ca.NewCertificateAuthorityImpl( c.CA, clock.Default(), stats, issuer, priv, c.KeyPolicy()) 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") 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) cmd.FailOnError(err, "Unable to create CA RPC server") rpc.NewCertificateAuthorityServer(cas, cai) err = cas.Start(amqpConf) cmd.FailOnError(err, "Unable to run CA RPC server") } app.Run() }
// 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{}, } }
func newAMQPConnector( queueName string, retryTimeoutBase time.Duration, retryTimeoutMax time.Duration, ) *amqpConnector { return &amqpConnector{ queueName: queueName, chMaker: defaultChannelMaker{}, clk: clock.Default(), retryTimeoutBase: retryTimeoutBase, retryTimeoutMax: retryTimeoutMax, } }
func TestDNSValidationNoServer(t *testing.T) { c, _ := statsd.NewNoopClient() stats := metrics.NewNoopScope() va := NewValidationAuthorityImpl(&PortConfig{}, 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(context.Background(), 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) }
// TestDNSValidationLive is an integration test, depending on // the existance of some Internet resources. Because of that, // it asserts nothing; it is intended for coverage. func TestDNSValidationLive(t *testing.T) { stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} mockRA := &MockRegistrationAuthority{} va.RA = mockRA goodChalDNS := core.DNSChallenge01(accountKey) // This token is set at _acme-challenge.good.bin.coffee goodChalDNS.Token = "yfCBb-bRTLz8Wd1C0lTUQK3qlKj3-t2tYGwx5Hj7r_w" var goodIdent = core.AcmeIdentifier{ Type: core.IdentifierDNS, Value: "good.bin.coffee", } var badIdent = core.AcmeIdentifier{ Type: core.IdentifierType("dns"), Value: "bad.bin.coffee", } var authzGood = core.Authorization{ ID: core.NewToken(), RegistrationID: 1, Identifier: goodIdent, Challenges: []core.Challenge{goodChalDNS}, } va.validate(authzGood, 0) if authzGood.Challenges[0].Status != core.StatusValid { t.Logf("TestDNSValidationLive on Good did not succeed.") } badChalDNS := core.DNSChallenge01(accountKey) // This token is NOT set at _acme-challenge.bad.bin.coffee badChalDNS.Token = "yfCBb-bRTLz8Wd1C0lTUQK3qlKj3-t2tYGwx5Hj7r_w" var authzBad = core.Authorization{ ID: core.NewToken(), RegistrationID: 1, Identifier: badIdent, Challenges: []core.Challenge{badChalDNS}, } va.validate(authzBad, 0) if authzBad.Challenges[0].Status != core.StatusInvalid { t.Logf("TestDNSValidationLive on Bad did succeed inappropriately.") } }
func main() { app := cmd.NewAppShell("boulder-va", "Handles challenge validation") app.Action = func(c cmd.Config, stats statsd.Statter, auditlogger *blog.AuditLogger) { go cmd.DebugServer(c.VA.DebugAddr) go cmd.ProfileCmd("VA", stats) pc := &va.PortConfig{ HTTPPort: 80, HTTPSPort: 443, TLSPort: 443, } if c.VA.PortConfig.HTTPPort != 0 { pc.HTTPPort = c.VA.PortConfig.HTTPPort } if c.VA.PortConfig.HTTPSPort != 0 { pc.HTTPSPort = c.VA.PortConfig.HTTPSPort } if c.VA.PortConfig.TLSPort != 0 { pc.TLSPort = c.VA.PortConfig.TLSPort } sbc := newGoogleSafeBrowsing(c.VA.GoogleSafeBrowsing) vai := va.NewValidationAuthorityImpl(pc, sbc, stats, clock.Default()) dnsTimeout, err := time.ParseDuration(c.Common.DNSTimeout) cmd.FailOnError(err, "Couldn't parse DNS timeout") if !c.Common.DNSAllowLoopbackAddresses { vai.DNSResolver = core.NewDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver}) } else { vai.DNSResolver = core.NewTestDNSResolverImpl(dnsTimeout, []string{c.Common.DNSResolver}) } vai.UserAgent = c.VA.UserAgent raRPC, err := rpc.NewAmqpRPCClient("VA->RA", c.AMQP.RA.Server, c, stats) cmd.FailOnError(err, "Unable to create RPC client") rac, err := rpc.NewRegistrationAuthorityClient(raRPC) cmd.FailOnError(err, "Unable to create RA client") vai.RA = &rac vas, err := rpc.NewAmqpRPCServer(c.AMQP.VA.Server, c.VA.MaxConcurrentRPCServerRequests, c) cmd.FailOnError(err, "Unable to create VA RPC server") rpc.NewValidationAuthorityServer(vas, vai) err = vas.Start(c) cmd.FailOnError(err, "Unable to run VA RPC server") } app.Run() }