func TestValidateContacts(t *testing.T) { tel, _ := url.Parse("tel:") ansible, _ := url.Parse("ansible:earth.sol.milkyway.laniakea/letsencrypt") validEmail, _ := url.Parse("mailto:[email protected]") invalidEmail, _ := url.Parse("mailto:[email protected]") malformedEmail, _ := url.Parse("mailto:admin.com") err := validateContacts([]core.AcmeURL{}, &mocks.MockDNS{}) test.AssertNotError(t, err, "No Contacts") err = validateContacts([]core.AcmeURL{core.AcmeURL(*tel)}, &mocks.MockDNS{}) test.AssertNotError(t, err, "Simple Telephone") err = validateContacts([]core.AcmeURL{core.AcmeURL(*validEmail)}, &mocks.MockDNS{}) test.AssertNotError(t, err, "Valid Email") err = validateContacts([]core.AcmeURL{core.AcmeURL(*invalidEmail)}, &mocks.MockDNS{}) test.AssertError(t, err, "Invalid Email") err = validateContacts([]core.AcmeURL{core.AcmeURL(*malformedEmail)}, &mocks.MockDNS{}) test.AssertError(t, err, "Malformed Email") err = validateContacts([]core.AcmeURL{core.AcmeURL(*ansible)}, &mocks.MockDNS{}) test.AssertError(t, err, "Unknown scehme") }
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 TestCertificateKeyNotEqualAccountKey(t *testing.T) { _, _, sa, ra := initAuthorities(t) authz := core.Authorization{} authz.ID, _ = sa.NewPendingAuthorization() authz.Identifier = core.AcmeIdentifier{ Type: core.IdentifierDNS, Value: "www.example.com", } csr := x509.CertificateRequest{ SignatureAlgorithm: x509.SHA256WithRSA, PublicKey: AccountKey.Key, DNSNames: []string{"www.example.com"}, } csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &csr, AccountPrivateKey.Key) test.AssertNotError(t, err, "Failed to sign CSR") parsedCsr, err := x509.ParseCertificateRequest(csrBytes) test.AssertNotError(t, err, "Failed to parse CSR") sa.UpdatePendingAuthorization(authz) sa.FinalizeAuthorization(authz) authzURL, _ := url.Parse("http://doesnt.matter/" + authz.ID) certRequest := core.CertificateRequest{ CSR: parsedCsr, Authorizations: []core.AcmeURL{core.AcmeURL(*authzURL)}, } // Registration id 1 has key == AccountKey _, err = ra.NewCertificate(certRequest, 1) test.AssertError(t, err, "Should have rejected cert with key = account key") test.AssertEquals(t, err.Error(), "Certificate public key must be different than account key") }
func CreateDomainAuth(t *testing.T, domainName string, sa *SQLStorageAuthority) (authz core.Authorization) { // create pending auth authz, err := sa.NewPendingAuthorization(core.Authorization{}) test.AssertNotError(t, err, "Couldn't create new pending authorization") test.Assert(t, authz.ID != "", "ID shouldn't be blank") // prepare challenge for auth uu, err := url.Parse(domainName) test.AssertNotError(t, err, "Couldn't parse domainName "+domainName) u := core.AcmeURL(*uu) chall := core.Challenge{Type: "simpleHttp", Status: core.StatusValid, URI: u, Token: "THISWOULDNTBEAGOODTOKEN"} combos := make([][]int, 1) combos[0] = []int{0, 1} exp := time.Now().AddDate(0, 0, 1) // expire in 1 day // validate pending auth authz.Status = core.StatusPending authz.Identifier = core.AcmeIdentifier{Type: core.IdentifierDNS, Value: domainName} authz.RegistrationID = 42 authz.Expires = &exp authz.Challenges = []core.Challenge{chall} authz.Combinations = combos // save updated auth err = sa.UpdatePendingAuthorization(authz) test.AssertNotError(t, err, "Couldn't update pending authorization with ID "+authz.ID) return }
func TestChallenge(t *testing.T) { wfe := NewWebFrontEndImpl() wfe.RA = &MockRegistrationAuthority{} wfe.SA = &MockSA{} wfe.HandlePaths() responseWriter := httptest.NewRecorder() var key jose.JsonWebKey err := json.Unmarshal([]byte(`{ "e": "AQAB", "kty": "RSA", "n": "tSwgy3ORGvc7YJI9B2qqkelZRUC6F1S5NwXFvM4w5-M0TsxbFsH5UH6adigV0jzsDJ5imAechcSoOhAh9POceCbPN1sTNwLpNbOLiQQ7RD5mY_pSUHWXNmS9R4NZ3t2fQAzPeW7jOfF0LKuJRGkekx6tXP1uSnNibgpJULNc4208dgBaCHo3mvaE2HV2GmVl1yxwWX5QZZkGQGjNDZYnjFfa2DKVvFs0QbAk21ROm594kAxlRlMMrvqlf24Eq4ERO0ptzpZgm_3j_e4hGRD39gJS7kAzK-j2cacFQ5Qi2Y6wZI2p-FCq_wiYsfEAIkATPBiLKl_6d_Jfcvs_impcXQ" }`), &key) test.AssertNotError(t, err, "Could not unmarshal testing key") challengeURL, _ := url.Parse("/acme/authz/asdf?challenge=foo") authz := core.Authorization{ ID: "asdf", Identifier: core.AcmeIdentifier{ Type: "dns", Value: "letsencrypt.org", }, Challenges: []core.Challenge{ core.Challenge{ Type: "dns", URI: core.AcmeURL(*challengeURL), }, }, RegistrationID: 1, } wfe.Challenge(authz, responseWriter, &http.Request{ Method: "POST", URL: challengeURL, Body: makeBody(` { "header": { "alg": "RS256", "jwk": { "e": "AQAB", "kty": "RSA", "n": "tSwgy3ORGvc7YJI9B2qqkelZRUC6F1S5NwXFvM4w5-M0TsxbFsH5UH6adigV0jzsDJ5imAechcSoOhAh9POceCbPN1sTNwLpNbOLiQQ7RD5mY_pSUHWXNmS9R4NZ3t2fQAzPeW7jOfF0LKuJRGkekx6tXP1uSnNibgpJULNc4208dgBaCHo3mvaE2HV2GmVl1yxwWX5QZZkGQGjNDZYnjFfa2DKVvFs0QbAk21ROm594kAxlRlMMrvqlf24Eq4ERO0ptzpZgm_3j_e4hGRD39gJS7kAzK-j2cacFQ5Qi2Y6wZI2p-FCq_wiYsfEAIkATPBiLKl_6d_Jfcvs_impcXQ" } }, "payload": "e30K", "signature": "JXYA_pin91Bc5oz5I6dqCNNWDrBaYTB31EnWorrj4JEFRaidafC9mpLDLLA9jR9kX_Vy2bA5b6pPpXVKm0w146a0L551OdL8JrrLka9q6LypQdDLLQa76XD03hSBOFcC-Oo5FLPa3WRWS1fQ37hYAoLxtS3isWXMIq_4Onx5bq8bwKyu-3E3fRb_lzIZ8hTIWwcblCTOfufUe6AoK4m6MfBjz0NGhyyk4lEZZw6Sttm2VuZo3xmWoRTJEyJG5AOJ6fkNJ9iQQ1kVhMr0ZZ7NVCaOZAnxrwv2sCjY6R3f4HuEVe1yzT75Mq2IuXq-tadGyFujvUxF6BWHCulbEnss7g" } `), }) test.AssertEquals( t, responseWriter.Header().Get("Location"), "/acme/authz/asdf?challenge=foo") test.AssertEquals( t, responseWriter.Header().Get("Link"), "</acme/authz/asdf>;rel=\"up\"") test.AssertEquals( t, responseWriter.Body.String(), "{\"type\":\"dns\",\"uri\":\"/acme/authz/asdf?challenge=foo\"}") }
func TestNewCertificate(t *testing.T) { _, _, sa, ra := initAuthorities(t) AuthzFinal.RegistrationID = 1 AuthzFinal, _ = sa.NewPendingAuthorization(AuthzFinal) sa.UpdatePendingAuthorization(AuthzFinal) sa.FinalizeAuthorization(AuthzFinal) // Inject another final authorization to cover www.example.com authzFinalWWW := AuthzFinal authzFinalWWW.Identifier.Value = "www.not-example.com" authzFinalWWW, _ = sa.NewPendingAuthorization(authzFinalWWW) sa.FinalizeAuthorization(authzFinalWWW) // Construct a cert request referencing the two authorizations url1, _ := url.Parse("http://doesnt.matter/" + AuthzFinal.ID) url2, _ := url.Parse("http://doesnt.matter/" + authzFinalWWW.ID) certRequest := core.CertificateRequest{ CSR: ExampleCSR, Authorizations: []core.AcmeURL{core.AcmeURL(*url1), core.AcmeURL(*url2)}, } cert, err := ra.NewCertificate(certRequest, 1) test.AssertNotError(t, err, "Failed to issue certificate") if err != nil { return } parsedCert, err := x509.ParseCertificate(cert.DER) test.AssertNotError(t, err, "Failed to parse certificate") if err != nil { return } // Verify that cert shows up and is as expected dbCert, err := sa.GetCertificate(core.SerialToString(parsedCert.SerialNumber)) test.AssertNotError(t, err, fmt.Sprintf("Could not fetch certificate %032x from database", parsedCert.SerialNumber)) if err != nil { return } test.Assert(t, bytes.Compare(cert.DER, dbCert.DER) == 0, "Certificates differ") t.Log("DONE TestOnValidationUpdate") }
func TestNewRegistrationBadKey(t *testing.T) { _, _, _, ra := initAuthorities(t) mailto, _ := url.Parse("mailto:[email protected]") input := core.Registration{ Contact: []core.AcmeURL{core.AcmeURL(*mailto)}, Key: ShortKey, } _, err := ra.NewRegistration(input) test.AssertError(t, err, "Should have rejected authorization with short key") }
func TestSendNags(t *testing.T) { tmpl, err := template.New("expiry-email").Parse(testTmpl) test.AssertNotError(t, err, "Couldn't parse test email template") stats, _ := statsd.NewNoopClient(nil) mc := mockMail{} m := mailer{ stats: stats, mailer: &mc, emailTemplate: tmpl, } cert := &x509.Certificate{ Subject: pkix.Name{ CommonName: "happy", }, NotAfter: time.Now().AddDate(0, 0, 2), DNSNames: []string{"example.com"}, } email, _ := url.Parse("mailto:[email protected]") emailB, _ := url.Parse("mailto:[email protected]") err = m.sendNags(cert, []core.AcmeURL{core.AcmeURL(*email)}) test.AssertNotError(t, err, "Failed to send warning messages") test.AssertEquals(t, len(mc.Messages), 1) test.AssertEquals(t, fmt.Sprintf(`hi, cert for DNS names example.com is going to expire in 2 days (%s)`, cert.NotAfter), mc.Messages[0]) mc.Clear() err = m.sendNags(cert, []core.AcmeURL{core.AcmeURL(*email), core.AcmeURL(*emailB)}) test.AssertNotError(t, err, "Failed to send warning messages") test.AssertEquals(t, len(mc.Messages), 2) test.AssertEquals(t, fmt.Sprintf(`hi, cert for DNS names example.com is going to expire in 2 days (%s)`, cert.NotAfter), mc.Messages[0]) test.AssertEquals(t, fmt.Sprintf(`hi, cert for DNS names example.com is going to expire in 2 days (%s)`, cert.NotAfter), mc.Messages[1]) mc.Clear() err = m.sendNags(cert, []core.AcmeURL{}) test.AssertNotError(t, err, "Not an error to pass no email contacts") test.AssertEquals(t, len(mc.Messages), 0) }
func TestChallenge(t *testing.T) { wfe := setupWFE(t) wfe.RA = &MockRegistrationAuthority{} wfe.SA = &MockSA{} responseWriter := httptest.NewRecorder() var key jose.JsonWebKey err := json.Unmarshal([]byte(` { "e": "AQAB", "kty": "RSA", "n": "tSwgy3ORGvc7YJI9B2qqkelZRUC6F1S5NwXFvM4w5-M0TsxbFsH5UH6adigV0jzsDJ5imAechcSoOhAh9POceCbPN1sTNwLpNbOLiQQ7RD5mY_pSUHWXNmS9R4NZ3t2fQAzPeW7jOfF0LKuJRGkekx6tXP1uSnNibgpJULNc4208dgBaCHo3mvaE2HV2GmVl1yxwWX5QZZkGQGjNDZYnjFfa2DKVvFs0QbAk21ROm594kAxlRlMMrvqlf24Eq4ERO0ptzpZgm_3j_e4hGRD39gJS7kAzK-j2cacFQ5Qi2Y6wZI2p-FCq_wiYsfEAIkATPBiLKl_6d_Jfcvs_impcXQ" } `), &key) test.AssertNotError(t, err, "Could not unmarshal testing key") challengeURL, _ := url.Parse("/acme/authz/asdf?challenge=foo") authz := core.Authorization{ ID: "asdf", Identifier: core.AcmeIdentifier{ Type: "dns", Value: "letsencrypt.org", }, Challenges: []core.Challenge{ core.Challenge{ Type: "dns", URI: core.AcmeURL(*challengeURL), }, }, RegistrationID: 1, } wfe.challenge(authz, responseWriter, &http.Request{ Method: "POST", URL: challengeURL, Body: makeBody(signRequest(t, "{}", &wfe.nonceService)), }, requestEvent{}) test.AssertEquals( t, responseWriter.Header().Get("Location"), "/acme/authz/asdf?challenge=foo") test.AssertEquals( t, responseWriter.Header().Get("Link"), "</acme/authz/asdf>;rel=\"up\"") test.AssertEquals( t, responseWriter.Body.String(), "{\"type\":\"dns\",\"uri\":\"/acme/authz/asdf?challenge=foo\"}") }
func TestAddRegistration(t *testing.T) { sa := initSA(t) var jwk jose.JsonWebKey err := json.Unmarshal([]byte(theKey), &jwk) if err != nil { t.Errorf("JSON unmarshal error: %+v", err) return } reg, err := sa.NewRegistration(core.Registration{ Key: jwk, }) test.AssertNotError(t, err, "Couldn't create new registration") test.Assert(t, reg.ID != 0, "ID shouldn't be 0") _, 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, } test.AssertEquals(t, dbReg.ID, expectedReg.ID) test.Assert(t, core.KeyDigestEquals(dbReg.Key, expectedReg.Key), "Stored key != expected") uu, err := url.Parse("test.com") u := core.AcmeURL(*uu) newReg := core.Registration{ID: reg.ID, Key: jwk, RecoveryToken: "RBNvo1WzZ4oRRq0W9", Contact: []core.AcmeURL{u}, 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.RecoveryToken, newReg.RecoveryToken) test.AssertEquals(t, dbReg.Agreement, newReg.Agreement) jwk.KeyID = "bad" _, err = sa.GetRegistrationByKey(jwk) test.AssertError(t, err, "Registration object for invalid key was returned") }
func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization, regID int64) (authz core.Authorization, err error) { if regID <= 0 { err = fmt.Errorf("Invalid registration ID") return authz, err } identifier := request.Identifier // Check that the identifier is present and appropriate if err = ra.PA.WillingToIssue(identifier); err != nil { return authz, err } // Create validations // TODO: Assign URLs challenges, combinations := ra.PA.ChallengesFor(identifier) authID, err := ra.SA.NewPendingAuthorization() if err != nil { return authz, err } for i := range challenges { // Ignoring these errors because we construct the URLs to be correct challengeURI, _ := url.Parse(ra.AuthzBase + authID + "?challenge=" + strconv.Itoa(i)) challenges[i].URI = core.AcmeURL(*challengeURI) if !challenges[i].IsSane(false) { err = fmt.Errorf("Challenge didn't pass sanity check: %+v", challenges[i]) return authz, err } } // Create a new authorization object authz = core.Authorization{ ID: authID, Identifier: identifier, RegistrationID: regID, Status: core.StatusPending, Challenges: challenges, Combinations: combinations, } // Store the authorization object, then return it err = ra.SA.UpdatePendingAuthorization(authz) return authz, err }
func TestCountRegistrationsByIP(t *testing.T) { sa, fc, cleanUp := initSA(t) defer cleanUp() contact := core.AcmeURL(url.URL{ Scheme: "mailto", Opaque: "*****@*****.**", }) _, err := sa.NewRegistration(core.Registration{ Key: jose.JsonWebKey{Key: &rsa.PublicKey{N: big.NewInt(1), E: 1}}, Contact: []*core.AcmeURL{&contact}, InitialIP: net.ParseIP("43.34.43.34"), }) test.AssertNotError(t, err, "Couldn't insert registration") _, err = sa.NewRegistration(core.Registration{ Key: jose.JsonWebKey{Key: &rsa.PublicKey{N: big.NewInt(2), E: 1}}, Contact: []*core.AcmeURL{&contact}, InitialIP: net.ParseIP("2001:cdba:1234:5678:9101:1121:3257:9652"), }) test.AssertNotError(t, err, "Couldn't insert registration") _, err = sa.NewRegistration(core.Registration{ Key: jose.JsonWebKey{Key: &rsa.PublicKey{N: big.NewInt(3), E: 1}}, Contact: []*core.AcmeURL{&contact}, InitialIP: net.ParseIP("2001:cdba:1234:5678:9101:1121:3257:9653"), }) test.AssertNotError(t, err, "Couldn't insert registration") earliest := fc.Now().Add(-time.Hour * 24) latest := fc.Now() count, err := sa.CountRegistrationsByIP(net.ParseIP("1.1.1.1"), earliest, latest) test.AssertNotError(t, err, "Failed to count registrations") test.AssertEquals(t, count, 0) count, err = sa.CountRegistrationsByIP(net.ParseIP("43.34.43.34"), earliest, latest) test.AssertNotError(t, err, "Failed to count registrations") test.AssertEquals(t, count, 1) count, err = sa.CountRegistrationsByIP(net.ParseIP("2001:cdba:1234:5678:9101:1121:3257:9652"), earliest, latest) test.AssertNotError(t, err, "Failed to count registrations") test.AssertEquals(t, count, 2) count, err = sa.CountRegistrationsByIP(net.ParseIP("2001:cdba:1234:0000:0000:0000:0000:0000"), earliest, latest) test.AssertNotError(t, err, "Failed to count registrations") test.AssertEquals(t, count, 2) }
func TestAddAuthorization(t *testing.T) { sa := initSA(t) PA := core.Authorization{} PA, err := sa.NewPendingAuthorization(PA) test.AssertNotError(t, err, "Couldn't create new pending authorization") test.Assert(t, PA.ID != "", "ID shouldn't be blank") dbPa, err := sa.GetAuthorization(PA.ID) test.AssertNotError(t, err, "Couldn't get pending authorization with ID "+PA.ID) test.AssertMarshaledEquals(t, PA, dbPa) expectedPa := core.Authorization{ID: PA.ID} test.AssertMarshaledEquals(t, dbPa.ID, expectedPa.ID) var jwk jose.JsonWebKey err = json.Unmarshal([]byte(theKey), &jwk) if err != nil { t.Errorf("JSON unmarshal error: %+v", err) return } uu, err := url.Parse("test.com") u := core.AcmeURL(*uu) chall := core.Challenge{Type: "simpleHttp", Status: core.StatusPending, URI: u, Token: "THISWOULDNTBEAGOODTOKEN", Path: "test-me"} combos := make([][]int, 1) combos[0] = []int{0, 1} exp := time.Now().AddDate(0, 0, 1) newPa := core.Authorization{ID: PA.ID, Identifier: core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "wut.com"}, RegistrationID: 0, Status: core.StatusPending, Expires: &exp, Challenges: []core.Challenge{chall}, Combinations: combos} err = sa.UpdatePendingAuthorization(newPa) test.AssertNotError(t, err, "Couldn't update pending authorization with ID "+PA.ID) newPa.Status = core.StatusValid err = sa.FinalizeAuthorization(newPa) test.AssertNotError(t, err, "Couldn't finalize pending authorization with ID "+PA.ID) dbPa, err = sa.GetAuthorization(PA.ID) test.AssertNotError(t, err, "Couldn't get authorization with ID "+PA.ID) }
func TestAuthorizationRequired(t *testing.T) { _, _, sa, ra := initAuthorities(t) AuthzFinal.RegistrationID = 1 AuthzFinal, _ = sa.NewPendingAuthorization(AuthzFinal) sa.UpdatePendingAuthorization(AuthzFinal) sa.FinalizeAuthorization(AuthzFinal) // Construct a cert request referencing the authorization url1, _ := url.Parse("http://doesnt.matter/" + AuthzFinal.ID) // ExampleCSR requests not-example.com and www.not-example.com, // but the authorization only covers not-example.com certRequest := core.CertificateRequest{ CSR: ExampleCSR, Authorizations: []core.AcmeURL{core.AcmeURL(*url1)}, } _, err := ra.NewCertificate(certRequest, 1) test.Assert(t, err != nil, "Issued certificate with insufficient authorization") t.Log("DONE TestAuthorizationRequired") }
func TestNewRegistration(t *testing.T) { _, _, sa, ra := initAuthorities(t) mailto, _ := url.Parse("mailto:[email protected]") input := core.Registration{ Contact: []core.AcmeURL{core.AcmeURL(*mailto)}, Key: AccountKeyB, } result, err := ra.NewRegistration(input) test.AssertNotError(t, err, "Could not create new registration") 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") test.Assert(t, result.RecoveryToken != "", "Recovery token not filled") 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.") }
// NewAuthorization constuct a new Authz from a request. func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization, regID int64) (authz core.Authorization, err error) { if regID <= 0 { err = core.MalformedRequestError(fmt.Sprintf("Invalid registration ID: %d", regID)) return authz, err } identifier := request.Identifier // Check that the identifier is present and appropriate if err = ra.PA.WillingToIssue(identifier); err != nil { err = core.UnauthorizedError(err.Error()) return authz, err } // Check CAA records for the requested identifier present, valid, err := ra.VA.CheckCAARecords(identifier) if err != nil { return authz, err } // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ra.log.Audit(fmt.Sprintf("Checked CAA records for %s, registration ID %d [Present: %t, Valid for issuance: %t]", identifier.Value, regID, present, valid)) if !valid { err = errors.New("CAA check for identifier failed") return authz, err } // Create validations, but we have to update them with URIs later challenges, combinations := ra.PA.ChallengesFor(identifier) // Partially-filled object authz = core.Authorization{ Identifier: identifier, RegistrationID: regID, Status: core.StatusPending, Combinations: combinations, } // Get a pending Auth first so we can get our ID back, then update with challenges authz, err = ra.SA.NewPendingAuthorization(authz) if err != nil { // InternalServerError since the user-data was validated before being // passed to the SA. err = core.InternalServerError(fmt.Sprintf("Invalid authorization request: %s", err)) return authz, err } // Construct all the challenge URIs for i := range challenges { // Ignoring these errors because we construct the URLs to be correct challengeURI, _ := url.Parse(ra.AuthzBase + authz.ID + "?challenge=" + strconv.Itoa(i)) challenges[i].URI = core.AcmeURL(*challengeURI) if !challenges[i].IsSane(false) { // InternalServerError because we generated these challenges, they should // be OK. err = core.InternalServerError(fmt.Sprintf("Challenge didn't pass sanity check: %+v", challenges[i])) return authz, err } } // Update object authz.Challenges = challenges // Store the authorization object, then return it err = ra.SA.UpdatePendingAuthorization(authz) if err != nil { // InternalServerError because we created the authorization just above, // and adding Sane challenges should not break it. err = core.InternalServerError(err.Error()) } return authz, err }
ExampleCSR = &x509.CertificateRequest{} // These values are populated by the tests as we go url0, _ = url.Parse("http://acme.invalid/authz/60p2Dc_XmUB2UUJBV4wYkF7BJbPD9KlDnUL3SmFMuTE?challenge=0") url1, _ = url.Parse("http://acme.invalid/authz/60p2Dc_XmUB2UUJBV4wYkF7BJbPD9KlDnUL3SmFMuTE?challenge=0") Registration = core.Registration{} AuthzInitial = core.Authorization{ ID: "60p2Dc_XmUB2UUJBV4wYkF7BJbPD9KlDnUL3SmFMuTE", Identifier: core.AcmeIdentifier{Type: "dns", Value: "not-example.com"}, RegistrationID: 1, Status: "pending", Challenges: []core.Challenge{ core.Challenge{ Type: "simpleHttp", Status: "pending", URI: core.AcmeURL(*url0), Token: "pDX9vBFJ043_gEc9Wyp8of-SqZMN2H3-fvj5iUgP7mg", }, core.Challenge{ Type: "dvsni", Status: "pending", URI: core.AcmeURL(*url1), R: "AI83O7gCMPDr4z7OIdl8T6axx6nui4HV1aAFQ5LJvVs", Nonce: "f011c9a0ce1a4fe0f18f2252d64c4239", }, }, Combinations: [][]int{[]int{0}, []int{1}}, } AuthzUpdated = core.Authorization{} AuthzFinal = core.Authorization{}
func TestFindExpiringCertificates(t *testing.T) { dbMap, err := sa.NewDbMap("sqlite3", ":memory:") test.AssertNotError(t, err, "Couldn't connect to SQLite") err = dbMap.CreateTablesIfNotExists() test.AssertNotError(t, err, "Couldn't create tables") tmpl, err := template.New("expiry-email").Parse(testTmpl) test.AssertNotError(t, err, "Couldn't parse test email template") stats, _ := statsd.NewNoopClient(nil) mc := mockMail{} m := mailer{ log: blog.GetAuditLogger(), stats: stats, mailer: &mc, emailTemplate: tmpl, dbMap: dbMap, nagTimes: []time.Duration{time.Hour * 24, time.Hour * 24 * 4, time.Hour * 24 * 7}, limit: 100, } log.Clear() err = m.findExpiringCertificates() test.AssertNotError(t, err, "Failed on no certificates") test.AssertEquals(t, len(log.GetAllMatching("Searching for certificates that expire between.*")), 3) // Add some expiring certificates and registrations emailA, _ := url.Parse("mailto:[email protected]") emailB, _ := url.Parse("mailto:[email protected]") var keyA jose.JsonWebKey var keyB jose.JsonWebKey err = json.Unmarshal(jsonKeyA, &keyA) test.AssertNotError(t, err, "Failed to unmarshal public JWK") err = json.Unmarshal(jsonKeyB, &keyB) test.AssertNotError(t, err, "Failed to unmarshal public JWK") regA := &core.Registration{ ID: 1, Contact: []core.AcmeURL{ core.AcmeURL(*emailA), }, Key: keyA, } regB := &core.Registration{ ID: 2, Contact: []core.AcmeURL{ core.AcmeURL(*emailB), }, Key: keyB, } rawCertA := x509.Certificate{ Subject: pkix.Name{ CommonName: "happy A", }, NotAfter: time.Now().AddDate(0, 0, 1), DNSNames: []string{"example-a.com"}, SerialNumber: big.NewInt(1337), } certDerA, _ := x509.CreateCertificate(rand.Reader, &rawCertA, &rawCertA, &testKey.PublicKey, &testKey) certA := &core.Certificate{ RegistrationID: 1, Status: core.StatusValid, Serial: "001", Expires: time.Now().AddDate(0, 0, 1), DER: certDerA, } // Already sent a nag but too long ago certStatusA := &core.CertificateStatus{Serial: "001", LastExpirationNagSent: time.Now().Add(-time.Hour * 24 * 3)} rawCertB := x509.Certificate{ Subject: pkix.Name{ CommonName: "happy B", }, NotAfter: time.Now().AddDate(0, 0, 3), DNSNames: []string{"example-b.com"}, SerialNumber: big.NewInt(1337), } certDerB, _ := x509.CreateCertificate(rand.Reader, &rawCertB, &rawCertB, &testKey.PublicKey, &testKey) certB := &core.Certificate{ RegistrationID: 1, Status: core.StatusValid, Serial: "002", Expires: time.Now().AddDate(0, 0, 3), DER: certDerB, } // Already sent a nag for this period certStatusB := &core.CertificateStatus{Serial: "002", LastExpirationNagSent: time.Now().Add(-time.Hour * 24 * 3)} rawCertC := x509.Certificate{ Subject: pkix.Name{ CommonName: "happy C", }, NotAfter: time.Now().AddDate(0, 0, 7), DNSNames: []string{"example-c.com"}, SerialNumber: big.NewInt(1337), } certDerC, _ := x509.CreateCertificate(rand.Reader, &rawCertC, &rawCertC, &testKey.PublicKey, &testKey) certC := &core.Certificate{ RegistrationID: 2, Status: core.StatusValid, Serial: "003", Expires: time.Now().AddDate(0, 0, 7), DER: certDerC, } certStatusC := &core.CertificateStatus{Serial: "003"} err = dbMap.Insert(regA) test.AssertNotError(t, err, "Couldn't add regA") err = dbMap.Insert(regB) test.AssertNotError(t, err, "Couldn't add regB") err = dbMap.Insert(certA) test.AssertNotError(t, err, "Couldn't add certA") err = dbMap.Insert(certB) test.AssertNotError(t, err, "Couldn't add certB") err = dbMap.Insert(certC) test.AssertNotError(t, err, "Couldn't add certC") err = dbMap.Insert(certStatusA) test.AssertNotError(t, err, "Couldn't add certStatusA") err = dbMap.Insert(certStatusB) test.AssertNotError(t, err, "Couldn't add certStatusB") err = dbMap.Insert(certStatusC) test.AssertNotError(t, err, "Couldn't add certStatusC") log.Clear() err = m.findExpiringCertificates() test.AssertNotError(t, err, "Failed to find expiring certs") // Should get 001 and 003 test.AssertEquals(t, len(mc.Messages), 2) test.AssertEquals(t, fmt.Sprintf(`hi, cert for DNS names example-a.com is going to expire in 1 days (%s)`, rawCertA.NotAfter.UTC().Format("2006-01-02 15:04:05 -0700 MST")), mc.Messages[0]) test.AssertEquals(t, fmt.Sprintf(`hi, cert for DNS names example-c.com is going to expire in 7 days (%s)`, rawCertC.NotAfter.UTC().Format("2006-01-02 15:04:05 -0700 MST")), mc.Messages[1]) // A consecutive run shouldn't find anything mc.Clear() log.Clear() err = m.findExpiringCertificates() test.AssertNotError(t, err, "Failed to find expiring certs") test.AssertEquals(t, len(mc.Messages), 0) }