diff --git a/ra/registration-authority.go b/ra/registration-authority.go index dab3ad543..9699d466f 100644 --- a/ra/registration-authority.go +++ b/ra/registration-authority.go @@ -166,7 +166,14 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest, logEvent.CommonName = csr.Subject.CommonName logEvent.Names = csr.DNSNames - csrPreviousDenied, err := ra.SA.AlreadyDeniedCSR(append(csr.DNSNames, csr.Subject.CommonName)) + // Validate that authorization key is authorized for all domains + names := make([]string, len(csr.DNSNames)) + copy(names, csr.DNSNames) + if len(csr.Subject.CommonName) > 0 { + names = append(names, csr.Subject.CommonName) + } + + csrPreviousDenied, err := ra.SA.AlreadyDeniedCSR(names) if err != nil { logEvent.Error = err.Error() return emptyCert, err @@ -220,12 +227,6 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest, } logEvent.VerificationMethods = verificationMethods - // Validate that authorization key is authorized for all domains - names := csr.DNSNames - if len(csr.Subject.CommonName) > 0 { - names = append(names, csr.Subject.CommonName) - } - // Validate all domains for _, name := range names { if !authorizedDomains[name] { diff --git a/ra/registration-authority_test.go b/ra/registration-authority_test.go index d95bdc793..6bd2f80c7 100644 --- a/ra/registration-authority_test.go +++ b/ra/registration-authority_test.go @@ -112,11 +112,33 @@ var ( ExampleCSR = &x509.CertificateRequest{} // These values are populated by the tests as we go - AuthzInitial = core.Authorization{} - AuthzUpdated = core.Authorization{} - AuthzFromVA = core.Authorization{} - AuthzFinal = core.Authorization{} - AuthzFinalWWW = core.Authorization{} + 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: "simpleHttps", + 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 initAuthorities(t *testing.T) (core.CertificateAuthority, *DummyValidationAuthority, *sa.SQLStorageAuthority, core.RegistrationAuthority) { @@ -148,13 +170,24 @@ func initAuthorities(t *testing.T) (core.CertificateAuthority, *DummyValidationA ExampleCSR, _ = x509.ParseCertificateRequest(csrDER) // This registration implicitly gets ID = 1 - sa.NewRegistration(core.Registration{Key: AccountKey}) + Registration, _ = sa.NewRegistration(core.Registration{Key: AccountKey}) ra := NewRegistrationAuthorityImpl() ra.SA = sa ra.VA = va ra.CA = &ca ra.PA = pa + ra.AuthzBase = "http://acme.invalid/authz/" + + AuthzInitial.RegistrationID = Registration.ID + + AuthzUpdated = AuthzInitial + AuthzUpdated.Challenges[0].Path = "Hf5GrX4Q7EBax9hc2jJnfw" + + AuthzFinal = AuthzUpdated + AuthzFinal.Status = "valid" + AuthzFinal.Expires = time.Now().Add(24 * time.Hour) + AuthzFinal.Challenges[0].Status = "valid" return &ca, va, sa, &ra } @@ -164,7 +197,7 @@ func assertAuthzEqual(t *testing.T, a1, a2 core.Authorization) { 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: Contact, Challenges + // Not testing: Challenges } func TestNewRegistration(t *testing.T) { @@ -217,7 +250,6 @@ func TestNewRegistrationNoFieldOverwrite(t *testing.T) { 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") } @@ -258,6 +290,7 @@ func TestNewAuthorization(t *testing.T) { test.Assert(t, authz.Challenges[1].Type == core.ChallengeTypeDVSNI, "Challenge 1 not DVSNI") // If we get to here, we'll use this authorization for the next test + fmt.Printf("AuthzInitial: %+v\n", authz) AuthzInitial = authz // TODO Test failure cases @@ -286,9 +319,6 @@ func TestUpdateAuthorization(t *testing.T) { 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") } @@ -299,22 +329,19 @@ func TestOnValidationUpdate(t *testing.T) { sa.UpdatePendingAuthorization(AuthzUpdated) // Simulate a successful simpleHTTPS challenge - AuthzFromVA = AuthzUpdated - AuthzFromVA.Challenges[0].Status = core.StatusValid + authzFromVA := AuthzUpdated + authzFromVA.Challenges[0].Status = core.StatusValid - ra.OnValidationUpdate(AuthzFromVA) + ra.OnValidationUpdate(authzFromVA) // Verify that the Authz in the DB is the same except for Status->StatusValid - AuthzFromVA.Status = core.StatusValid - dbAuthz, err := sa.GetAuthorization(AuthzFromVA.ID) + authzFromVA.Status = core.StatusValid + dbAuthz, err := sa.GetAuthorization(authzFromVA.ID) test.AssertNotError(t, err, "Could not fetch authorization from database") - assertAuthzEqual(t, AuthzFromVA, dbAuthz) - t.Log(" ~~> from VA: ", AuthzFromVA.Status) + assertAuthzEqual(t, authzFromVA, dbAuthz) + t.Log(" ~~> from VA: ", authzFromVA.Status) t.Log(" ~~> from DB: ", dbAuthz.Status) - // If we get to here, we'll use this authorization for the next test - AuthzFinal = dbAuthz - // TODO Test failure cases t.Log("DONE TestOnValidationUpdate") } @@ -348,6 +375,31 @@ func TestCertificateKeyNotEqualAccountKey(t *testing.T) { _, 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") + + t.Log("DONE TestCertificateKeyNotEqualAccountKey") +} + +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 TestNewCertificate(t *testing.T) { @@ -358,14 +410,14 @@ func TestNewCertificate(t *testing.T) { sa.FinalizeAuthorization(AuthzFinal) // Inject another final authorization to cover www.example.com - AuthzFinalWWW = AuthzFinal - AuthzFinalWWW.Identifier.Value = "www.example.com" - AuthzFinalWWW, _ = sa.NewPendingAuthorization(AuthzFinalWWW) - sa.FinalizeAuthorization(AuthzFinalWWW) + 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) + url2, _ := url.Parse("http://doesnt.matter/" + authzFinalWWW.ID) certRequest := core.CertificateRequest{ CSR: ExampleCSR, @@ -374,16 +426,25 @@ func TestNewCertificate(t *testing.T) { 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) == 0, "Certificates differ") - // TODO Test failure cases t.Log("DONE TestOnValidationUpdate") } @@ -476,7 +537,8 @@ var CA_CERT_PEM = "-----BEGIN CERTIFICATE-----\n" + // CSR generated by Go: // * Random public key // * CN = not-example.com -// * DNSNames = not-example.com +// * DNSNames = not-example.com, www.not-example.com +/* var CSR_HEX = "3082028c30820174020100301a311830160603550403130f" + "6e6f742d6578616d706c652e636f6d30820122300d06092a" + "864886f70d01010105000382010f003082010a0282010100" + @@ -505,3 +567,34 @@ var CSR_HEX = "3082028c30820174020100301a311830160603550403130f" + "53f07e1654e6077f4aaaf5c5b27edaf0385b48e0fc281424" + "6363a01370c89e666169276eb133731cff2379d46d2fff9d" + "f277b6d23fa24f9b" +*/ + +var CSR_HEX = "308202ae308201960201003027310b300906035504061302" + + "5553311830160603550403130f6e6f742d6578616d706c65" + + "2e636f6d30820122300d06092a864886f70d010101050003" + + "82010f003082010a0282010100a4f507b52ca2766e2cea7b" + + "aaada9c3e08ea3423d6617ae84df65b6ed7e6c031605851b" + + "f0a14f3461a9f1882de9808b8e59d639c85eec58dbe653e3" + + "855e94d81904b7ce6675a1930e0ea6537aa3936fdc9d9780" + + "bc9596e5ec183811b137f83f28781d619fae8471ff3db1ad" + + "5a4b5cbf96d127d0f16e3c6ccbb97c48b43a7ddfcc17fdf3" + + "eac049cc81e4703ba90ce15d3cdfd9d0a3b0ec138f1c06e0" + + "8212c94e6884480d4b8f16fcf38f1b10d942cfca558b322e" + + "d8896be3104fb40e6851f3b414929b4f54fae89668ab0cbf" + + "76b7eb94703b17a73c9189409b088e7d61f39560a413562e" + + "64f26b650aede2d27bd2bacfc55d6a106243ba6ce07046d4" + + "fda618881b0203010001a042304006092a864886f70d0109" + + "0e31333031302f0603551d1104283026820f6e6f742d6578" + + "616d706c652e636f6d82137777772e6e6f742d6578616d70" + + "6c652e636f6d300d06092a864886f70d01010b0500038201" + + "01006e168e521ea37595698ceab29a3815c57b301dcd9c86" + + "6fdc7cfb966afde87da52c699f43133a6abfbbeb031f1b02" + + "cb072c8543b73fdffff6ee002ed367fe3b09992ac496c4ef" + + "1b7487e68c25f66b8d1223a07feebfad8fd7f19727bff7b4" + + "02bf6bef705c0a48e800e15bafbc622cb62ee446814234a3" + + "ebf9b8ba3c094d64b64aaa1b2b955f769ce60e9e304f7781" + + "57814f2f1cb1c4e2ee58bcdc0640dd2f0ff387ddb61ed479" + + "7ea935e79638a63dd64bd36723f34c1e6725ae57d8ff63f8" + + "749ac154cfaa55b3d3cccd7d42994c922cbb171a43c7ab68" + + "5170d833829d28a574fb25ffcf0fd5d3f19becaef2223541" + + "c2a8e596a80c8cde27bc78e20d7171fe43d8"