func TestDvsni(t *testing.T) { va := NewValidationAuthorityImpl(true) va.DNSResolver = core.NewDNSResolver(time.Second*5, []string{"8.8.8.8:53"}) a := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0} ba := core.B64enc(a) chall := core.Challenge{R: ba, S: ba} invalidChall, err := va.validateDvsni(ident, chall) test.AssertEquals(t, invalidChall.Status, core.StatusInvalid) test.AssertError(t, err, "Server's not up yet; expected refusal. Where did we connect?") test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem) waitChan := make(chan bool, 1) stopChan := make(chan bool, 1) go dvsniSrv(t, a, a, stopChan, waitChan) defer func() { stopChan <- true }() <-waitChan finChall, err := va.validateDvsni(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertNotError(t, err, "") invalidChall, err = va.validateDvsni(core.AcmeIdentifier{Type: core.IdentifierType("ip"), Value: "127.0.0.1"}, 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) va.TestMode = false invalidChall, err = va.validateDvsni(core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "always.invalid"}, chall) test.AssertEquals(t, invalidChall.Status, core.StatusInvalid) test.AssertError(t, err, "Domain name is invalid.") test.AssertEquals(t, invalidChall.Error.Type, core.UnknownHostProblem) va.TestMode = true chall.R = ba[5:] invalidChall, err = va.validateDvsni(ident, chall) test.AssertEquals(t, invalidChall.Status, core.StatusInvalid) test.AssertError(t, err, "R Should be illegal Base64") test.AssertEquals(t, invalidChall.Error.Type, core.MalformedProblem) chall.R = ba chall.S = "!@#" invalidChall, err = va.validateDvsni(ident, chall) test.AssertEquals(t, invalidChall.Status, core.StatusInvalid) test.AssertError(t, err, "S Should be illegal Base64") test.AssertEquals(t, invalidChall.Error.Type, core.MalformedProblem) chall.S = ba chall.Nonce = "wait-long" started := time.Now() invalidChall, err = va.validateDvsni(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) }
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 TestNewAuthorization(t *testing.T) { _, sa, ra, cleanUp := initAuthorities(t) defer cleanUp() _, err := ra.NewAuthorization(AuthzRequest, 0) test.AssertError(t, err, "Authorization cannot have registrationID == 0") authz, err := ra.NewAuthorization(AuthzRequest, Registration.ID) test.AssertNotError(t, err, "NewAuthorization failed") // Verify that returned authz same as DB dbAuthz, err := sa.GetAuthorization(authz.ID) test.AssertNotError(t, err, "Could not fetch authorization from database") assertAuthzEqual(t, authz, dbAuthz) // Verify that the returned authz has the right information test.Assert(t, authz.RegistrationID == Registration.ID, "Initial authz did not get the right registration ID") test.Assert(t, authz.Identifier == AuthzRequest.Identifier, "Initial authz had wrong identifier") test.Assert(t, authz.Status == core.StatusPending, "Initial authz not pending") // TODO Verify that challenges are correct test.Assert(t, len(authz.Challenges) == 3, "Incorrect number of challenges returned") test.Assert(t, authz.Challenges[0].Type == core.ChallengeTypeSimpleHTTP, "Challenge 0 not SimpleHTTP") test.Assert(t, authz.Challenges[1].Type == core.ChallengeTypeDVSNI, "Challenge 1 not DVSNI") test.Assert(t, authz.Challenges[2].Type == core.ChallengeTypeDNS, "Challenge 2 not DNS") test.Assert(t, authz.Challenges[0].IsSane(false), "Challenge 0 is not sane") test.Assert(t, authz.Challenges[1].IsSane(false), "Challenge 1 is not sane") test.Assert(t, authz.Challenges[2].IsSane(false), "Challenge 2 is not sane") t.Log("DONE TestNewAuthorization") }
func TestStandardHeaders(t *testing.T) { wfe := setupWFE(t) mux, err := wfe.Handler() test.AssertNotError(t, err, "Problem setting up HTTP handlers") cases := []struct { path string allowed []string }{ {"/", []string{"GET"}}, {wfe.NewReg, []string{"POST"}}, {wfe.RegBase, []string{"POST"}}, {wfe.NewAuthz, []string{"POST"}}, {wfe.AuthzBase, []string{"GET", "POST"}}, {wfe.NewCert, []string{"POST"}}, {wfe.CertBase, []string{"GET"}}, {wfe.SubscriberAgreementURL, []string{"GET"}}, } for _, c := range cases { responseWriter := httptest.NewRecorder() mux.ServeHTTP(responseWriter, &http.Request{ Method: "BOGUS", URL: mustParseURL(c.path), }) acao := responseWriter.Header().Get("Access-Control-Allow-Origin") nonce := responseWriter.Header().Get("Replay-Nonce") allow := responseWriter.Header().Get("Allow") test.Assert(t, responseWriter.Code == http.StatusMethodNotAllowed, "Bogus method allowed") test.Assert(t, acao == "*", "Bad CORS header") test.Assert(t, len(nonce) > 0, "Bad Replay-Nonce header") test.Assert(t, len(allow) > 0 && allow == strings.Join(c.allowed, ", "), "Bad Allow header") } }
func TestNewRegistrationNoFieldOverwrite(t *testing.T) { _, _, _, ra := initAuthorities(t) mailto, _ := url.Parse("mailto:[email protected]") input := core.Registration{ ID: 23, Key: AccountKeyC, RecoveryToken: "RecoverMe", Contact: []core.AcmeURL{core.AcmeURL(*mailto)}, Agreement: "I agreed", } result, err := ra.NewRegistration(input) test.AssertNotError(t, err, "Could not create new registration") test.Assert(t, result.ID != 23, "ID shouldn't be set by user") // TODO: Enable this test case once we validate terms agreement. //test.Assert(t, result.Agreement != "I agreed", "Agreement shouldn't be set with invalid URL") test.Assert(t, result.RecoveryToken != "RecoverMe", "Recovery token shouldn't be set by user") result2, err := ra.UpdateRegistration(result, core.Registration{ ID: 33, Key: ShortKey, RecoveryToken: "RecoverMe2", }) test.AssertNotError(t, err, "Could not update registration") test.Assert(t, result2.ID != 33, "ID shouldn't be overwritten.") test.Assert(t, !core.KeyDigestEquals(result2.Key, ShortKey), "Key shouldn't be overwritten") test.Assert(t, result2.RecoveryToken != "RecoverMe2", "Recovery token shouldn't be overwritten by user") }
func TestDNSLookupHost(t *testing.T) { obj := NewTestDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}, testStats, clock.NewFake(), 1) ip, err := obj.LookupHost(context.Background(), "servfail.com") t.Logf("servfail.com - IP: %s, Err: %s", ip, err) test.AssertError(t, err, "Server failure") test.Assert(t, len(ip) == 0, "Should not have IPs") ip, err = obj.LookupHost(context.Background(), "nonexistent.letsencrypt.org") t.Logf("nonexistent.letsencrypt.org - IP: %s, Err: %s", ip, err) test.AssertNotError(t, err, "Not an error to not exist") test.Assert(t, len(ip) == 0, "Should not have IPs") // Single IPv4 address ip, err = obj.LookupHost(context.Background(), "cps.letsencrypt.org") t.Logf("cps.letsencrypt.org - IP: %s, Err: %s", ip, err) test.AssertNotError(t, err, "Not an error to exist") test.Assert(t, len(ip) == 1, "Should have IP") ip, err = obj.LookupHost(context.Background(), "cps.letsencrypt.org") t.Logf("cps.letsencrypt.org - IP: %s, Err: %s", ip, err) test.AssertNotError(t, err, "Not an error to exist") test.Assert(t, len(ip) == 1, "Should have IP") // No IPv6 ip, err = obj.LookupHost(context.Background(), "v6.letsencrypt.org") t.Logf("v6.letsencrypt.org - IP: %s, Err: %s", ip, err) test.AssertNotError(t, err, "Not an error to exist") test.Assert(t, len(ip) == 0, "Should not have IPs") }
func TestAddRegistration(t *testing.T) { sa, clk, cleanUp := initSA(t) defer cleanUp() jwk := satest.GoodJWK() contact, err := core.ParseAcmeURL("mailto:[email protected]") if err != nil { t.Fatalf("unable to parse contact link: %s", err) } contacts := []*core.AcmeURL{contact} reg, err := sa.NewRegistration(core.Registration{ Key: jwk, Contact: contacts, InitialIP: net.ParseIP("43.34.43.34"), }) if err != nil { t.Fatalf("Couldn't create new registration: %s", err) } test.Assert(t, reg.ID != 0, "ID shouldn't be 0") test.AssertDeepEquals(t, reg.Contact, contacts) _, err = sa.GetRegistration(0) test.AssertError(t, err, "Registration object for ID 0 was returned") dbReg, err := sa.GetRegistration(reg.ID) test.AssertNotError(t, err, fmt.Sprintf("Couldn't get registration with ID %v", reg.ID)) expectedReg := core.Registration{ ID: reg.ID, Key: jwk, InitialIP: net.ParseIP("43.34.43.34"), CreatedAt: clk.Now(), } test.AssertEquals(t, dbReg.ID, expectedReg.ID) test.Assert(t, core.KeyDigestEquals(dbReg.Key, expectedReg.Key), "Stored key != expected") u, _ := core.ParseAcmeURL("test.com") newReg := core.Registration{ ID: reg.ID, Key: jwk, Contact: []*core.AcmeURL{u}, InitialIP: net.ParseIP("72.72.72.72"), Agreement: "yes", } err = sa.UpdateRegistration(newReg) test.AssertNotError(t, err, fmt.Sprintf("Couldn't get registration with ID %v", reg.ID)) dbReg, err = sa.GetRegistrationByKey(jwk) test.AssertNotError(t, err, "Couldn't get registration by key") test.AssertEquals(t, dbReg.ID, newReg.ID) test.AssertEquals(t, dbReg.Agreement, newReg.Agreement) var anotherJWK jose.JsonWebKey err = json.Unmarshal([]byte(anotherKey), &anotherJWK) test.AssertNotError(t, err, "couldn't unmarshal anotherJWK") _, err = sa.GetRegistrationByKey(anotherJWK) test.AssertError(t, err, "Registration object for invalid key was returned") }
func TestStandardHeaders(t *testing.T) { wfe := setupWFE(t) cases := []struct { path string handler func(http.ResponseWriter, *http.Request) allowed []string }{ {"/", wfe.Index, []string{"GET"}}, {wfe.NewReg, wfe.NewRegistration, []string{"POST"}}, {wfe.RegBase, wfe.Registration, []string{"POST"}}, {wfe.NewAuthz, wfe.NewAuthorization, []string{"POST"}}, {wfe.AuthzBase, wfe.Authorization, []string{"GET", "POST"}}, {wfe.NewCert, wfe.NewCertificate, []string{"POST"}}, {wfe.CertBase, wfe.Certificate, []string{"GET", "POST"}}, {wfe.SubscriberAgreementURL, wfe.Terms, []string{"GET"}}, } for _, c := range cases { responseWriter := httptest.NewRecorder() url, _ := url.Parse(c.path) c.handler(responseWriter, &http.Request{ Method: "BOGUS", URL: url, }) acao := responseWriter.Header().Get("Access-Control-Allow-Origin") nonce := responseWriter.Header().Get("Replay-Nonce") allow := responseWriter.Header().Get("Allow") test.Assert(t, responseWriter.Code == http.StatusMethodNotAllowed, "Bogus method allowed") test.Assert(t, acao == "*", "Bad CORS header") test.Assert(t, len(nonce) > 0, "Bad Replay-Nonce header") test.Assert(t, len(allow) > 0 && allow == strings.Join(c.allowed, ", "), "Bad Allow header") } }
func TestNewRegistration(t *testing.T) { _, sa, ra, _, cleanUp := initAuthorities(t) defer cleanUp() mailto, _ := core.ParseAcmeURL("mailto:[email protected]") input := core.Registration{ Contact: []*core.AcmeURL{mailto}, Key: AccountKeyB, InitialIP: net.ParseIP("7.6.6.5"), } result, err := ra.NewRegistration(input) if err != nil { t.Fatalf("could not create new registration: %s", err) } test.Assert(t, core.KeyDigestEquals(result.Key, AccountKeyB), "Key didn't match") test.Assert(t, len(result.Contact) == 1, "Wrong number of contacts") test.Assert(t, mailto.String() == result.Contact[0].String(), "Contact didn't match") test.Assert(t, result.Agreement == "", "Agreement didn't default empty") reg, err := sa.GetRegistration(result.ID) test.AssertNotError(t, err, "Failed to retrieve registration") test.Assert(t, core.KeyDigestEquals(reg.Key, AccountKeyB), "Retrieved registration differed.") }
func TestNewRegistrationNoFieldOverwrite(t *testing.T) { _, _, _, ra, cleanUp := initAuthorities(t) defer cleanUp() mailto, _ := core.ParseAcmeURL("mailto:[email protected]") input := core.Registration{ ID: 23, Key: AccountKeyC, Contact: []*core.AcmeURL{mailto}, Agreement: "I agreed", } result, err := ra.NewRegistration(input) test.AssertNotError(t, err, "Could not create new registration") test.Assert(t, result.ID != 23, "ID shouldn't be set by user") // TODO: Enable this test case once we validate terms agreement. //test.Assert(t, result.Agreement != "I agreed", "Agreement shouldn't be set with invalid URL") id := result.ID result2, err := ra.UpdateRegistration(result, core.Registration{ ID: 33, Key: ShortKey, }) test.AssertNotError(t, err, "Could not update registration") test.Assert(t, result2.ID != 33, fmt.Sprintf("ID shouldn't be overwritten. expected %d, got %d", id, result2.ID)) test.Assert(t, !core.KeyDigestEquals(result2.Key, ShortKey), "Key shouldn't be overwritten") }
func TestProblemDetails(t *testing.T) { pb, err := problemDetailsToPB(nil) test.AssertNotEquals(t, err, "problemDetailToPB failed") test.Assert(t, pb == nil, "Returned corepb.ProblemDetails is not nil") prob := &probs.ProblemDetails{Type: probs.TLSProblem, Detail: "asd", HTTPStatus: 200} pb, err = problemDetailsToPB(prob) test.AssertNotError(t, err, "problemDetailToPB failed") test.Assert(t, pb != nil, "return corepb.ProblemDetails is nill") test.AssertDeepEquals(t, *pb.ProblemType, string(prob.Type)) test.AssertEquals(t, *pb.Detail, prob.Detail) test.AssertEquals(t, int(*pb.HttpStatus), prob.HTTPStatus) recon, err := pbToProblemDetails(pb) test.AssertNotError(t, err, "pbToProblemDetails failed") test.AssertDeepEquals(t, recon, prob) recon, err = pbToProblemDetails(nil) test.AssertNotError(t, err, "pbToProblemDetails failed") test.Assert(t, recon == nil, "Returned core.PRoblemDetails is not nil") _, err = pbToProblemDetails(&corepb.ProblemDetails{}) test.AssertError(t, err, "pbToProblemDetails did not fail") test.AssertEquals(t, err, ErrMissingParameters) empty := "" _, err = pbToProblemDetails(&corepb.ProblemDetails{ProblemType: &empty}) test.AssertError(t, err, "pbToProblemDetails did not fail") test.AssertEquals(t, err, ErrMissingParameters) _, err = pbToProblemDetails(&corepb.ProblemDetails{Detail: &empty}) test.AssertError(t, err, "pbToProblemDetails did not fail") test.AssertEquals(t, err, ErrMissingParameters) }
func TestDNSServFail(t *testing.T) { obj := NewTestDNSResolverImpl(time.Second*10, []string{dnsLoopbackAddr}, testStats, clock.NewFake(), 1) bad := "servfail.com" _, _, err := obj.LookupTXT(context.Background(), bad) test.AssertError(t, err, "LookupTXT didn't return an error") _, err = obj.LookupHost(context.Background(), bad) test.AssertError(t, err, "LookupHost didn't return an error") // CAA lookup ignores validation failures from the resolver for now // and returns an empty list of CAA records. emptyCaa, err := obj.LookupCAA(context.Background(), bad) test.Assert(t, len(emptyCaa) == 0, "Query returned non-empty list of CAA records") test.AssertNotError(t, err, "LookupCAA returned an error") // When we turn on enforceCAASERVFAIL, such lookups should fail. obj.caaSERVFAILExceptions = map[string]bool{"servfailexception.example.com": true} emptyCaa, err = obj.LookupCAA(context.Background(), bad) test.Assert(t, len(emptyCaa) == 0, "Query returned non-empty list of CAA records") test.AssertError(t, err, "LookupCAA should have returned an error") // Unless they are on the exception list emptyCaa, err = obj.LookupCAA(context.Background(), "servfailexception.example.com") test.Assert(t, len(emptyCaa) == 0, "Query returned non-empty list of CAA records") test.AssertNotError(t, err, "LookupCAA for servfail exception returned an error") }
func TestChallengesFor(t *testing.T) { pa := paImpl(t) var accountKey *jose.JsonWebKey err := json.Unmarshal([]byte(accountKeyJSON), &accountKey) if err != nil { t.Errorf("Error unmarshaling JWK: %v", err) } challenges, combinations := pa.ChallengesFor(core.AcmeIdentifier{}, accountKey) test.Assert(t, len(challenges) == len(enabledChallenges), "Wrong number of challenges returned") test.Assert(t, len(combinations) == len(enabledChallenges), "Wrong number of combinations returned") seenChalls := make(map[string]bool) // Expected only if the pseudo-RNG is seeded with 99. expectedCombos := [][]int{{1}, {2}, {0}} for _, challenge := range challenges { test.Assert(t, !seenChalls[challenge.Type], "should not already have seen this type") seenChalls[challenge.Type] = true test.Assert(t, enabledChallenges[challenge.Type], "Unsupported challenge returned") } test.AssertEquals(t, len(seenChalls), len(enabledChallenges)) test.AssertDeepEquals(t, expectedCombos, combinations) }
func TestAuthzMeta(t *testing.T) { authz := core.Authorization{ID: "asd", RegistrationID: 10} pb, err := authzMetaToPB(authz) test.AssertNotError(t, err, "authzMetaToPB failed") test.Assert(t, pb != nil, "return vapb.AuthzMeta is nill") test.Assert(t, pb.Id != nil, "Id field is nil") test.AssertEquals(t, *pb.Id, authz.ID) test.Assert(t, pb.RegID != nil, "RegistrationID field is nil") test.AssertEquals(t, *pb.RegID, authz.RegistrationID) recon, err := pbToAuthzMeta(pb) test.AssertNotError(t, err, "pbToAuthzMeta failed") test.AssertEquals(t, recon.ID, authz.ID) test.AssertEquals(t, recon.RegistrationID, authz.RegistrationID) _, err = pbToAuthzMeta(nil) test.AssertError(t, err, "pbToAuthzMeta did not fail") test.AssertEquals(t, err, ErrMissingParameters) _, err = pbToAuthzMeta(&vapb.AuthzMeta{}) test.AssertError(t, err, "pbToAuthzMeta did not fail") test.AssertEquals(t, err, ErrMissingParameters) empty := "" one := int64(1) _, err = pbToAuthzMeta(&vapb.AuthzMeta{Id: &empty}) test.AssertError(t, err, "pbToAuthzMeta did not fail") test.AssertEquals(t, err, ErrMissingParameters) _, err = pbToAuthzMeta(&vapb.AuthzMeta{RegID: &one}) test.AssertError(t, err, "pbToAuthzMeta did not fail") test.AssertEquals(t, err, ErrMissingParameters) }
func TestRecordSanityCheck(t *testing.T) { rec := []ValidationRecord{ ValidationRecord{ URL: "http://localhost/test", Hostname: "localhost", Port: "80", AddressesResolved: []net.IP{net.IP{127, 0, 0, 1}}, AddressUsed: net.IP{127, 0, 0, 1}, }, } chall := Challenge{Type: ChallengeTypeSimpleHTTP, ValidationRecord: rec} test.Assert(t, chall.RecordsSane(), "Record should be sane") chall.ValidationRecord[0].URL = "" test.Assert(t, !chall.RecordsSane(), "Record should not be sane") chall = Challenge{Type: ChallengeTypeDVSNI, ValidationRecord: rec} chall.ValidationRecord[0].URL = "" test.Assert(t, chall.RecordsSane(), "Record should be sane") chall.ValidationRecord[0].Hostname = "" test.Assert(t, !chall.RecordsSane(), "Record should not be sane") chall.ValidationRecord = append(chall.ValidationRecord, rec...) test.Assert(t, !chall.RecordsSane(), "Record should not be sane") }
func TestCAAChecking(t *testing.T) { type CAATest struct { Domain string Present bool Valid bool } tests := []CAATest{ // Reserved CAATest{"reserved.com", true, false}, // Critical CAATest{"critical.com", true, false}, CAATest{"nx.critical.com", true, false}, CAATest{"cname-critical.com", true, false}, CAATest{"nx.cname-critical.com", true, false}, // Good (absent) CAATest{"absent.com", false, true}, CAATest{"cname-absent.com", false, true}, CAATest{"nx.cname-absent.com", false, true}, CAATest{"cname-nx.com", false, true}, CAATest{"example.co.uk", false, true}, // Good (present) CAATest{"present.com", true, true}, CAATest{"cname-present.com", true, true}, CAATest{"cname2-present.com", true, true}, CAATest{"nx.cname2-present.com", true, true}, CAATest{"dname-present.com", true, true}, CAATest{"dname2cname.com", true, true}, // CNAME to critical } va := NewValidationAuthorityImpl(true) va.DNSResolver = &mocks.MockDNS{} va.IssuerDomain = "letsencrypt.org" for _, caaTest := range tests { present, valid, err := va.CheckCAARecords(core.AcmeIdentifier{Type: "dns", Value: caaTest.Domain}) test.AssertNotError(t, err, caaTest.Domain) fmt.Println(caaTest.Domain, caaTest.Present == present, caaTest.Valid == valid) test.AssertEquals(t, caaTest.Present, present) test.AssertEquals(t, caaTest.Valid, valid) } present, valid, err := va.CheckCAARecords(core.AcmeIdentifier{Type: "dns", Value: "servfail.com"}) test.AssertError(t, err, "servfail.com") test.Assert(t, !present, "Present should be false") test.Assert(t, !valid, "Valid should be false") for _, name := range []string{ "www.caa-loop.com", "a.cname-loop.com", "a.dname-loop.com", "cname-servfail.com", "cname2servfail.com", "dname-servfail.com", "cname-and-dname.com", "servfail.com", } { _, _, err = va.CheckCAARecords(core.AcmeIdentifier{Type: "dns", Value: name}) test.AssertError(t, err, name) } }
func TestUpdateAuthorization(t *testing.T) { va, sa, ra, _, cleanUp := initAuthorities(t) defer cleanUp() // We know this is OK because of TestNewAuthorization authz, err := ra.NewAuthorization(AuthzRequest, Registration.ID) test.AssertNotError(t, err, "NewAuthorization failed") response, err := makeResponse(authz.Challenges[ResponseIndex]) test.AssertNotError(t, err, "Unable to construct response to challenge") authz, err = ra.UpdateAuthorization(authz, ResponseIndex, response) test.AssertNotError(t, err, "UpdateAuthorization failed") // Verify that returned authz same as DB dbAuthz, err := sa.GetAuthorization(authz.ID) test.AssertNotError(t, err, "Could not fetch authorization from database") assertAuthzEqual(t, authz, dbAuthz) // Verify that the VA got the authz, and it's the same as the others test.Assert(t, va.Called, "Authorization was not passed to the VA") assertAuthzEqual(t, authz, va.Argument) // Verify that the responses are reflected test.Assert(t, len(va.Argument.Challenges) > 0, "Authz passed to VA has no challenges") t.Log("DONE TestUpdateAuthorization") }
func TestDvsni(t *testing.T) { chall := createChallenge(core.ChallengeTypeDVSNI) hs := dvsniSrv(t, chall) port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") va := NewValidationAuthorityImpl(&PortConfig{DVSNIPort: port}) va.DNSResolver = &mocks.MockDNS{} log.Clear() finChall, err := va.validateDvsni(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.validateDvsni(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.validateDvsni(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 re-sign to get an unknown SNI (from the signature value) chall.Token = core.NewToken() validationPayload, _ := json.Marshal(map[string]interface{}{ "type": chall.Type, "token": chall.Token, }) signer, _ := jose.NewSigner(jose.RS256, &TheKey) chall.Validation, _ = signer.Sign(validationPayload, "") log.Clear() started := time.Now() invalidChall, err = va.validateDvsni(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 DVSNI validation server and check that validation fails. hs.Close() invalidChall, err = va.validateDvsni(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 TestChecking(t *testing.T) { type CAATest struct { Domain string Present bool Valid bool } tests := []CAATest{ // Reserved {"reserved.com", true, false}, // Critical {"critical.com", true, false}, {"nx.critical.com", true, false}, // Good (absent) {"absent.com", false, true}, {"example.co.uk", false, true}, // Good (present) {"present.com", true, true}, {"present.servfail.com", true, true}, // Good (multiple critical, one matching) {"multi-crit-present.com", true, true}, // Bad (unknown critical) {"unknown-critical.com", true, false}, {"unknown-critical2.com", true, false}, // Good (unknown noncritical, no issue/issuewild records) {"unknown-noncritical.com", true, true}, // Good (issue record with unknown parameters) {"present-with-parameter.com", true, true}, // Bad (unsatisfiable issue record) {"unsatisfiable.com", true, false}, } stats, _ := statsd.NewNoopClient() ccs := &caaCheckerServer{&bdns.MockDNSResolver{}, stats} issuerDomain := "letsencrypt.org" ctx := context.Background() for _, caaTest := range tests { result, err := ccs.ValidForIssuance(ctx, &pb.Check{Name: &caaTest.Domain, IssuerDomain: &issuerDomain}) if err != nil { t.Errorf("CheckCAARecords error for %s: %s", caaTest.Domain, err) } if *result.Present != caaTest.Present { t.Errorf("CheckCAARecords presence mismatch for %s: got %t expected %t", caaTest.Domain, *result.Present, caaTest.Present) } if *result.Valid != caaTest.Valid { t.Errorf("CheckCAARecords presence mismatch for %s: got %t expected %t", caaTest.Domain, *result.Valid, caaTest.Valid) } } servfail := "servfail.com" servfailPresent := "servfail.present.com" result, err := ccs.ValidForIssuance(ctx, &pb.Check{Name: &servfail, IssuerDomain: &issuerDomain}) test.AssertError(t, err, "servfail.com") test.Assert(t, result == nil, "result should be nil") result, err = ccs.ValidForIssuance(ctx, &pb.Check{Name: &servfailPresent, IssuerDomain: &issuerDomain}) test.AssertError(t, err, "servfail.present.com") test.Assert(t, result == nil, "result should be nil") }
func assertAuthzEqual(t *testing.T, a1, a2 core.Authorization) { test.Assert(t, a1.ID == a2.ID, "ret != DB: ID") test.Assert(t, a1.Identifier == a2.Identifier, "ret != DB: Identifier") test.Assert(t, a1.Status == a2.Status, "ret != DB: Status") test.Assert(t, a1.RegistrationID == a2.RegistrationID, "ret != DB: RegID") // Not testing: Challenges }
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") }
func TestChallenges(t *testing.T) { var accountKey *jose.JsonWebKey err := json.Unmarshal([]byte(accountKeyJSON), &accountKey) if err != nil { t.Errorf("Error unmarshaling JWK: %v", err) } http01 := HTTPChallenge01() if !http01.IsSane(false) { t.Errorf("New http-01 challenge is not sane: %v", http01) } tlssni01 := TLSSNIChallenge01() if !tlssni01.IsSane(false) { t.Errorf("New tls-sni-01 challenge is not sane: %v", tlssni01) } dns01 := DNSChallenge01() if !dns01.IsSane(false) { t.Errorf("New dns-01 challenge is not sane: %v", dns01) } test.Assert(t, ValidChallenge(ChallengeTypeHTTP01), "Refused valid challenge") test.Assert(t, ValidChallenge(ChallengeTypeTLSSNI01), "Refused valid challenge") test.Assert(t, ValidChallenge(ChallengeTypeDNS01), "Refused valid challenge") test.Assert(t, !ValidChallenge("nonsense-71"), "Accepted invalid challenge") }
func TestUpdateAuthorization(t *testing.T) { _, va, sa, ra := initAuthorities(t) AuthzInitial.ID, _ = sa.NewPendingAuthorization() sa.UpdatePendingAuthorization(AuthzInitial) authz, err := ra.UpdateAuthorization(AuthzInitial, ResponseIndex, Response) test.AssertNotError(t, err, "UpdateAuthorization failed") // Verify that returned authz same as DB dbAuthz, err := sa.GetAuthorization(authz.ID) test.AssertNotError(t, err, "Could not fetch authorization from database") assertAuthzEqual(t, authz, dbAuthz) // Verify that the VA got the authz, and it's the same as the others test.Assert(t, va.Called, "Authorization was not passed to the VA") assertAuthzEqual(t, authz, va.Argument) // Verify that the responses are reflected test.Assert(t, len(va.Argument.Challenges) > 0, "Authz passed to VA has no challenges") simpleHttps := va.Argument.Challenges[0] test.Assert(t, simpleHttps.Path == Response.Path, "simpleHttps changed") // If we get to here, we'll use this authorization for the next test AuthzUpdated = authz // TODO Test failure cases t.Log("DONE TestUpdateAuthorization") }
func TestUpdateAuthorizationNewRPC(t *testing.T) { va, sa, ra, _, cleanUp := initAuthorities(t) defer cleanUp() // We know this is OK because of TestNewAuthorization authz, err := ra.NewAuthorization(ctx, AuthzRequest, Registration.ID) test.AssertNotError(t, err, "NewAuthorization failed") response, err := makeResponse(authz.Challenges[ResponseIndex]) test.AssertNotError(t, err, "Unable to construct response to challenge") authz.Challenges[ResponseIndex].Type = core.ChallengeTypeDNS01 va.RecordsReturn = []core.ValidationRecord{ {Hostname: "example.com"}} va.ProblemReturn = nil authz, err = ra.UpdateAuthorization(ctx, authz, ResponseIndex, response) test.AssertNotError(t, err, "UpdateAuthorization failed") // Verify that returned authz same as DB dbAuthz, err := sa.GetAuthorization(ctx, authz.ID) test.AssertNotError(t, err, "Could not fetch authorization from database") assertAuthzEqual(t, authz, dbAuthz) // Verify that the VA got the authz, and it's the same as the others test.Assert(t, va.Called, "Authorization was not passed to the VA") assertAuthzEqual(t, authz, va.Argument) // Verify that the responses are reflected test.Assert(t, len(va.Argument.Challenges) > 0, "Authz passed to VA has no challenges") test.Assert(t, authz.Challenges[ResponseIndex].Status == core.StatusValid, "challenge was not marked as valid") t.Log("DONE TestUpdateAuthorizationNewRPC") }
// Valid revocation request for existing, non-revoked cert func TestRevokeCertificate(t *testing.T) { keyPemBytes, err := ioutil.ReadFile("test/238.key") test.AssertNotError(t, err, "Failed to load key") key, err := jose.LoadPrivateKey(keyPemBytes) test.AssertNotError(t, err, "Failed to load key") rsaKey, ok := key.(*rsa.PrivateKey) test.Assert(t, ok, "Couldn't load RSA key") signer, err := jose.NewSigner("RS256", rsaKey) test.AssertNotError(t, err, "Failed to make signer") certPemBytes, err := ioutil.ReadFile("test/238.crt") test.AssertNotError(t, err, "Failed to load cert") certBlock, _ := pem.Decode(certPemBytes) test.Assert(t, certBlock != nil, "Failed to decode PEM") var revokeRequest struct { CertificateDER core.JSONBuffer `json:"certificate"` } revokeRequest.CertificateDER = certBlock.Bytes revokeRequestJSON, err := json.Marshal(revokeRequest) test.AssertNotError(t, err, "Failed to marshal request") // POST, Properly JWS-signed, but payload is "foo", not base64-encoded JSON. wfe := setupWFE(t) wfe.RA = &MockRegistrationAuthority{} wfe.SA = &MockSA{} wfe.Stats, _ = statsd.NewNoopClient() wfe.SubscriberAgreementURL = agreementURL responseWriter := httptest.NewRecorder() responseWriter.Body.Reset() nonce, err := wfe.nonceService.Nonce() test.AssertNotError(t, err, "Unable to create nonce") result, _ := signer.Sign(revokeRequestJSON, nonce) wfe.RevokeCertificate(responseWriter, &http.Request{ Method: "POST", Body: makeBody(result.FullSerialize()), }) test.AssertEquals(t, responseWriter.Code, 200) test.AssertEquals(t, responseWriter.Body.String(), "") // Try the revoke request again, signed by account key associated with cert. // Should also succeed. responseWriter.Body.Reset() test1JWK, err := jose.LoadPrivateKey([]byte(test1KeyPrivatePEM)) test.AssertNotError(t, err, "Failed to load key") test1Key, ok := test1JWK.(*rsa.PrivateKey) test.Assert(t, ok, "Couldn't load RSA key") accountKeySigner, err := jose.NewSigner("RS256", test1Key) test.AssertNotError(t, err, "Failed to make signer") nonce, err = wfe.nonceService.Nonce() test.AssertNotError(t, err, "Unable to create nonce") result, _ = accountKeySigner.Sign(revokeRequestJSON, nonce) wfe.RevokeCertificate(responseWriter, &http.Request{ Method: "POST", Body: makeBody(result.FullSerialize()), }) test.AssertEquals(t, responseWriter.Code, 200) test.AssertEquals(t, responseWriter.Body.String(), "") }
func TestDupeNames(t *testing.T) { unique := []string{"a", "b"} notUnique := []string{"a", "a"} test.Assert(t, !dupeNames([]string{}), "Empty list can't contain duplicates") test.Assert(t, !dupeNames(unique), "Unique list doesn't have duplicates") test.Assert(t, dupeNames(notUnique), "Non-unique list does have duplicates") }
func TestAlreadyUsed(t *testing.T) { ns, err := NewNonceService() test.AssertNotError(t, err, "Could not create nonce service") n, err := ns.Nonce() test.AssertNotError(t, err, "Could not create nonce") test.Assert(t, ns.Valid(n), "Did not recognize fresh nonce") test.Assert(t, !ns.Valid(n), "Recognized the same nonce twice") }
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") va, _, log := setup() va.tlsPort = port _, prob := va.validateTLSSNI01(ctx, ident, chall) if prob != nil { t.Fatalf("Unexpected failre in validateTLSSNI01: %s", prob) } test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) log.Clear() _, prob = va.validateTLSSNI01(ctx, core.AcmeIdentifier{ Type: core.IdentifierType("ip"), Value: net.JoinHostPort("127.0.0.1", fmt.Sprintf("%d", port)), }, chall) if prob == nil { t.Fatalf("IdentifierType IP shouldn't have worked.") } test.AssertEquals(t, prob.Type, probs.MalformedProblem) log.Clear() _, prob = va.validateTLSSNI01(ctx, core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "always.invalid"}, chall) if prob == nil { t.Fatalf("Domain name was supposed to be invalid.") } test.AssertEquals(t, prob.Type, probs.UnknownHostProblem) // Need to create a new authorized keys object to get an unknown SNI (from the signature value) chall.Token = core.NewToken() chall.ProvidedKeyAuthorization, _ = chall.ExpectedKeyAuthorization() log.Clear() started := time.Now() _, prob = va.validateTLSSNI01(ctx, 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") if prob == nil { t.Fatalf("Connection should've timed out") } test.AssertEquals(t, prob.Type, probs.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() _, err = va.validateTLSSNI01(ctx, ident, chall) if err == nil { t.Fatalf("Server's down; expected refusal. Where did we connect?") } test.AssertEquals(t, prob.Type, probs.ConnectionProblem) }
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 TestKeyDigestEquals(t *testing.T) { var jwk1, jwk2 jose.JsonWebKey json.Unmarshal([]byte(JWK1JSON), &jwk1) json.Unmarshal([]byte(JWK2JSON), &jwk2) test.Assert(t, KeyDigestEquals(jwk1, jwk1), "Key digests for same key should match") test.Assert(t, !KeyDigestEquals(jwk1, jwk2), "Key digests for different keys should not match") test.Assert(t, !KeyDigestEquals(jwk1, struct{}{}), "Unknown key types should not match anything") test.Assert(t, !KeyDigestEquals(struct{}{}, struct{}{}), "Unknown key types should not match anything") }