Remove new-cert and new-authz handlers from wfe2 (#2987)
This commit is contained in:
parent
6962bfe1a6
commit
e17175a851
166
wfe2/wfe.go
166
wfe2/wfe.go
|
|
@ -36,10 +36,8 @@ const (
|
|||
directoryPath = "/directory"
|
||||
newRegPath = "/acme/new-reg"
|
||||
regPath = "/acme/reg/"
|
||||
newAuthzPath = "/acme/new-authz"
|
||||
authzPath = "/acme/authz/"
|
||||
challengePath = "/acme/challenge/"
|
||||
newCertPath = "/acme/new-cert"
|
||||
certPath = "/acme/cert/"
|
||||
revokeCertPath = "/acme/revoke-cert"
|
||||
termsPath = "/terms"
|
||||
|
|
@ -300,8 +298,6 @@ func (wfe *WebFrontEndImpl) Handler() http.Handler {
|
|||
m := http.NewServeMux()
|
||||
wfe.HandleFunc(m, directoryPath, wfe.Directory, "GET")
|
||||
wfe.HandleFunc(m, newRegPath, wfe.NewRegistration, "POST")
|
||||
wfe.HandleFunc(m, newAuthzPath, wfe.NewAuthorization, "POST")
|
||||
wfe.HandleFunc(m, newCertPath, wfe.NewCertificate, "POST")
|
||||
wfe.HandleFunc(m, regPath, wfe.Registration, "POST")
|
||||
wfe.HandleFunc(m, authzPath, wfe.Authorization, "GET", "POST")
|
||||
wfe.HandleFunc(m, challengePath, wfe.Challenge, "GET", "POST")
|
||||
|
|
@ -372,8 +368,6 @@ func addRequesterHeader(w http.ResponseWriter, requester int64) {
|
|||
func (wfe *WebFrontEndImpl) Directory(ctx context.Context, logEvent *requestEvent, response http.ResponseWriter, request *http.Request) {
|
||||
directoryEndpoints := map[string]interface{}{
|
||||
"new-reg": newRegPath,
|
||||
"new-authz": newAuthzPath,
|
||||
"new-cert": newCertPath,
|
||||
"revoke-cert": revokeCertPath,
|
||||
}
|
||||
|
||||
|
|
@ -503,7 +497,6 @@ func (wfe *WebFrontEndImpl) NewRegistration(ctx context.Context, logEvent *reque
|
|||
regURL := wfe.relativeEndpoint(request, fmt.Sprintf("%s%d", regPath, reg.ID))
|
||||
|
||||
response.Header().Add("Location", regURL)
|
||||
response.Header().Add("Link", link(wfe.relativeEndpoint(request, newAuthzPath), "next"))
|
||||
if len(wfe.SubscriberAgreementURL) > 0 {
|
||||
response.Header().Add("Link", link(wfe.SubscriberAgreementURL, "terms-of-service"))
|
||||
}
|
||||
|
|
@ -518,55 +511,6 @@ func (wfe *WebFrontEndImpl) NewRegistration(ctx context.Context, logEvent *reque
|
|||
}
|
||||
}
|
||||
|
||||
// NewAuthorization is used by clients to submit a new ID Authorization
|
||||
func (wfe *WebFrontEndImpl) NewAuthorization(ctx context.Context, logEvent *requestEvent, response http.ResponseWriter, request *http.Request) {
|
||||
body, currReg, prob := wfe.validPOSTForAccount(request, ctx, logEvent)
|
||||
addRequesterHeader(response, logEvent.Requester)
|
||||
if prob != nil {
|
||||
// validPOSTforAccount handles its own setting of logEvent.Errors
|
||||
wfe.sendError(response, logEvent, prob, nil)
|
||||
return
|
||||
}
|
||||
// Any version of the agreement is acceptable here. Version match is enforced in
|
||||
// wfe.Registration when agreeing the first time. Agreement updates happen
|
||||
// by mailing subscribers and don't require a registration update.
|
||||
if currReg.Agreement == "" {
|
||||
wfe.sendError(response, logEvent, probs.Unauthorized("Must agree to subscriber agreement before any further actions"), nil)
|
||||
return
|
||||
}
|
||||
|
||||
var init core.Authorization
|
||||
if err := json.Unmarshal(body, &init); err != nil {
|
||||
logEvent.AddError("unable to JSON unmarshal Authorization: %s", err)
|
||||
wfe.sendError(response, logEvent, probs.Malformed("Error unmarshaling JSON"), err)
|
||||
return
|
||||
}
|
||||
logEvent.Extra["Identifier"] = init.Identifier
|
||||
|
||||
// Create new authz and return
|
||||
authz, err := wfe.RA.NewAuthorization(ctx, init, currReg.ID)
|
||||
if err != nil {
|
||||
logEvent.AddError("unable to create new authz: %s", err)
|
||||
wfe.sendError(response, logEvent, problemDetailsForError(err, "Error creating new authz"), err)
|
||||
return
|
||||
}
|
||||
logEvent.Extra["AuthzID"] = authz.ID
|
||||
|
||||
// Make a URL for this authz, then blow away the ID and RegID before serializing
|
||||
authzURL := wfe.relativeEndpoint(request, authzPath+string(authz.ID))
|
||||
wfe.prepAuthorizationForDisplay(request, &authz)
|
||||
|
||||
response.Header().Add("Location", authzURL)
|
||||
response.Header().Add("Link", link(wfe.relativeEndpoint(request, newCertPath), "next"))
|
||||
|
||||
err = wfe.writeJsonResponse(response, logEvent, http.StatusCreated, authz)
|
||||
if err != nil {
|
||||
// ServerInternal because we generated the authz, it should be OK
|
||||
wfe.sendError(response, logEvent, probs.ServerInternal("Error marshaling authz"), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (wfe *WebFrontEndImpl) regHoldsAuthorizations(ctx context.Context, regID int64, names []string) (bool, error) {
|
||||
authz, err := wfe.SA.GetValidAuthorizations(ctx, regID, names, wfe.clk.Now())
|
||||
if err != nil {
|
||||
|
|
@ -606,113 +550,6 @@ func (wfe *WebFrontEndImpl) logCsr(request *http.Request, cr core.CertificateReq
|
|||
wfe.log.AuditObject("Certificate request", csrLog)
|
||||
}
|
||||
|
||||
// NewCertificate is used by clients to request the issuance of a cert for an
|
||||
// authorized identifier.
|
||||
func (wfe *WebFrontEndImpl) NewCertificate(ctx context.Context, logEvent *requestEvent, response http.ResponseWriter, request *http.Request) {
|
||||
body, reg, prob := wfe.validPOSTForAccount(request, ctx, logEvent)
|
||||
addRequesterHeader(response, logEvent.Requester)
|
||||
if prob != nil {
|
||||
// validPOSTForAccount handles its own setting of logEvent.Errors
|
||||
wfe.sendError(response, logEvent, prob, nil)
|
||||
return
|
||||
}
|
||||
// Any version of the agreement is acceptable here. Version match is enforced in
|
||||
// wfe.Registration when agreeing the first time. Agreement updates happen
|
||||
// by mailing subscribers and don't require a registration update.
|
||||
if reg.Agreement == "" {
|
||||
wfe.sendError(response, logEvent, probs.Unauthorized("Must agree to subscriber agreement before any further actions"), nil)
|
||||
return
|
||||
}
|
||||
|
||||
var rawCSR core.RawCertificateRequest
|
||||
err := json.Unmarshal(body, &rawCSR)
|
||||
if err != nil {
|
||||
logEvent.AddError("unable to JSON unmarshal CertificateRequest: %s", err)
|
||||
wfe.sendError(response, logEvent, probs.Malformed("Error unmarshaling certificate request"), err)
|
||||
return
|
||||
}
|
||||
// Assuming a properly formatted CSR there should be two four byte SEQUENCE
|
||||
// declarations then a two byte integer declaration which defines the version
|
||||
// of the CSR. If those two bytes (at offset 8 and 9) and equal to 2 and 0
|
||||
// then the CSR was generated by a pre-1.0.2 version of OpenSSL with a client
|
||||
// which didn't explicitly set the version causing the integer to be malformed
|
||||
// and encoding/asn1 will refuse to parse it. If this is the case exit early
|
||||
// with a more useful error message.
|
||||
if len(rawCSR.CSR) >= 10 && rawCSR.CSR[8] == 2 && rawCSR.CSR[9] == 0 {
|
||||
logEvent.AddError("Pre-1.0.2 OpenSSL malformed CSR")
|
||||
wfe.sendError(
|
||||
response,
|
||||
logEvent,
|
||||
probs.Malformed("CSR generated using a pre-1.0.2 OpenSSL with a client that doesn't properly specify the CSR version. See https://community.letsencrypt.org/t/openssl-bug-information/19591"),
|
||||
nil,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
certificateRequest := core.CertificateRequest{Bytes: rawCSR.CSR}
|
||||
certificateRequest.CSR, err = x509.ParseCertificateRequest(rawCSR.CSR)
|
||||
if err != nil {
|
||||
logEvent.AddError("unable to parse certificate request: %s", err)
|
||||
wfe.sendError(response, logEvent, probs.Malformed("Error parsing certificate request: %s", err), err)
|
||||
return
|
||||
}
|
||||
wfe.logCsr(request, certificateRequest, *reg)
|
||||
// Check that the key in the CSR is good. This will also be checked in the CA
|
||||
// component, but we want to discard CSRs with bad keys as early as possible
|
||||
// because (a) it's an easy check and we can save unnecessary requests and
|
||||
// bytes on the wire, and (b) the CA logs all rejections as audit events, but
|
||||
// a bad key from the client is just a malformed request and doesn't need to
|
||||
// be audited.
|
||||
if err := wfe.keyPolicy.GoodKey(certificateRequest.CSR.PublicKey); err != nil {
|
||||
logEvent.AddError("CSR public key failed GoodKey: %s", err)
|
||||
wfe.sendError(response, logEvent, probs.Malformed("Invalid key in certificate request :: %s", err), err)
|
||||
return
|
||||
}
|
||||
logEvent.Extra["CSRDNSNames"] = certificateRequest.CSR.DNSNames
|
||||
logEvent.Extra["CSREmailAddresses"] = certificateRequest.CSR.EmailAddresses
|
||||
logEvent.Extra["CSRIPAddresses"] = certificateRequest.CSR.IPAddresses
|
||||
|
||||
// Create new certificate and return
|
||||
// TODO IMPORTANT: The RA trusts the WFE to provide the correct key. If the
|
||||
// WFE is compromised, *and* the attacker knows the public key of an account
|
||||
// authorized for target site, they could cause issuance for that site by
|
||||
// lying to the RA. We should probably pass a copy of the whole request to the
|
||||
// RA for secondary validation.
|
||||
cert, err := wfe.RA.NewCertificate(ctx, certificateRequest, reg.ID)
|
||||
if err != nil {
|
||||
logEvent.AddError("unable to create new cert: %s", err)
|
||||
wfe.sendError(response, logEvent, problemDetailsForError(err, "Error creating new cert"), err)
|
||||
return
|
||||
}
|
||||
|
||||
// Make a URL for this certificate.
|
||||
// We use only the sequential part of the serial number, because it should
|
||||
// uniquely identify the certificate, and this makes it easy for anybody to
|
||||
// enumerate and mirror our certificates.
|
||||
parsedCertificate, err := x509.ParseCertificate([]byte(cert.DER))
|
||||
if err != nil {
|
||||
logEvent.AddError("unable to parse certificate: %s", err)
|
||||
wfe.sendError(response, logEvent, probs.ServerInternal("Unable to parse certificate"), err)
|
||||
return
|
||||
}
|
||||
serial := parsedCertificate.SerialNumber
|
||||
certURL := wfe.relativeEndpoint(request, certPath+core.SerialToString(serial))
|
||||
|
||||
// TODO Content negotiation
|
||||
response.Header().Add("Location", certURL)
|
||||
if err = wfe.addIssuingCertificateURLs(response, parsedCertificate.IssuingCertificateURL); err != nil {
|
||||
logEvent.AddError("unable to parse IssuingCertificateURL: %s", err)
|
||||
wfe.sendError(response, logEvent, probs.ServerInternal("unable to parse IssuingCertificateURL"), err)
|
||||
return
|
||||
}
|
||||
response.Header().Set("Content-Type", "application/pkix-cert")
|
||||
response.WriteHeader(http.StatusCreated)
|
||||
if _, err = response.Write(cert.DER); err != nil {
|
||||
logEvent.AddError(err.Error())
|
||||
wfe.log.Warning(fmt.Sprintf("Could not write response: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
// Challenge handles POST requests to challenge URLs. Such requests are clients'
|
||||
// responses to the server's challenges.
|
||||
func (wfe *WebFrontEndImpl) Challenge(
|
||||
|
|
@ -980,7 +817,6 @@ func (wfe *WebFrontEndImpl) Registration(
|
|||
return
|
||||
}
|
||||
|
||||
response.Header().Add("Link", link(wfe.relativeEndpoint(request, newAuthzPath), "next"))
|
||||
if len(wfe.SubscriberAgreementURL) > 0 {
|
||||
response.Header().Add("Link", link(wfe.SubscriberAgreementURL, "terms-of-service"))
|
||||
}
|
||||
|
|
@ -1074,8 +910,6 @@ func (wfe *WebFrontEndImpl) Authorization(ctx context.Context, logEvent *request
|
|||
|
||||
wfe.prepAuthorizationForDisplay(request, &authz)
|
||||
|
||||
response.Header().Add("Link", link(wfe.relativeEndpoint(request, newCertPath), "next"))
|
||||
|
||||
err = wfe.writeJsonResponse(response, logEvent, http.StatusOK, authz)
|
||||
if err != nil {
|
||||
// InternalServerError because this is a failure to decode from our DB.
|
||||
|
|
|
|||
337
wfe2/wfe_test.go
337
wfe2/wfe_test.go
|
|
@ -33,7 +33,6 @@ import (
|
|||
"github.com/letsencrypt/boulder/mocks"
|
||||
"github.com/letsencrypt/boulder/nonce"
|
||||
"github.com/letsencrypt/boulder/probs"
|
||||
"github.com/letsencrypt/boulder/ra"
|
||||
rapb "github.com/letsencrypt/boulder/ra/proto"
|
||||
"github.com/letsencrypt/boulder/revocation"
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
|
|
@ -661,8 +660,6 @@ func TestDirectory(t *testing.T) {
|
|||
"meta": {
|
||||
"terms-of-service": "http://example.invalid/terms"
|
||||
},
|
||||
"new-authz": "http://localhost:4300/acme/new-authz",
|
||||
"new-cert": "http://localhost:4300/acme/new-cert",
|
||||
"new-reg": "http://localhost:4300/acme/new-reg",
|
||||
"revoke-cert": "http://localhost:4300/acme/revoke-cert",
|
||||
"AAAAAAAAAAA": "https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417"
|
||||
|
|
@ -702,15 +699,15 @@ func TestRelativeDirectory(t *testing.T) {
|
|||
result string
|
||||
}{
|
||||
// Test '' (No host header) with no proto header
|
||||
{"", "", `{"key-change":"http://localhost/acme/key-change","new-authz":"http://localhost/acme/new-authz","new-cert":"http://localhost/acme/new-cert","new-reg":"http://localhost/acme/new-reg","revoke-cert":"http://localhost/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||
{"", "", `{"key-change":"http://localhost/acme/key-change","new-reg":"http://localhost/acme/new-reg","revoke-cert":"http://localhost/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||
// Test localhost:4300 with no proto header
|
||||
{"localhost:4300", "", `{"key-change":"http://localhost:4300/acme/key-change","new-authz":"http://localhost:4300/acme/new-authz","new-cert":"http://localhost:4300/acme/new-cert","new-reg":"http://localhost:4300/acme/new-reg","revoke-cert":"http://localhost:4300/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||
{"localhost:4300", "", `{"key-change":"http://localhost:4300/acme/key-change","new-reg":"http://localhost:4300/acme/new-reg","revoke-cert":"http://localhost:4300/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||
// Test 127.0.0.1:4300 with no proto header
|
||||
{"127.0.0.1:4300", "", `{"key-change":"http://127.0.0.1:4300/acme/key-change","new-authz":"http://127.0.0.1:4300/acme/new-authz","new-cert":"http://127.0.0.1:4300/acme/new-cert","new-reg":"http://127.0.0.1:4300/acme/new-reg","revoke-cert":"http://127.0.0.1:4300/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||
{"127.0.0.1:4300", "", `{"key-change":"http://127.0.0.1:4300/acme/key-change","new-reg":"http://127.0.0.1:4300/acme/new-reg","revoke-cert":"http://127.0.0.1:4300/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||
// Test localhost:4300 with HTTP proto header
|
||||
{"localhost:4300", "http", `{"key-change":"http://localhost:4300/acme/key-change","new-authz":"http://localhost:4300/acme/new-authz","new-cert":"http://localhost:4300/acme/new-cert","new-reg":"http://localhost:4300/acme/new-reg","revoke-cert":"http://localhost:4300/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||
{"localhost:4300", "http", `{"key-change":"http://localhost:4300/acme/key-change","new-reg":"http://localhost:4300/acme/new-reg","revoke-cert":"http://localhost:4300/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||
// Test localhost:4300 with HTTPS proto header
|
||||
{"localhost:4300", "https", `{"key-change":"https://localhost:4300/acme/key-change","new-authz":"https://localhost:4300/acme/new-authz","new-cert":"https://localhost:4300/acme/new-cert","new-reg":"https://localhost:4300/acme/new-reg","revoke-cert":"https://localhost:4300/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||
{"localhost:4300", "https", `{"key-change":"https://localhost:4300/acme/key-change","new-reg":"https://localhost:4300/acme/new-reg","revoke-cert":"https://localhost:4300/acme/revoke-cert","AAAAAAAAAAA":"https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417","meta":{"terms-of-service": "http://example.invalid/terms"}}`},
|
||||
}
|
||||
|
||||
for _, tt := range dirTests {
|
||||
|
|
@ -765,11 +762,6 @@ func TestHTTPMethods(t *testing.T) {
|
|||
Path: newRegPath,
|
||||
Allowed: postOnly,
|
||||
},
|
||||
{
|
||||
Name: "NewAuthz path should be POST only",
|
||||
Path: newAuthzPath,
|
||||
Allowed: postOnly,
|
||||
},
|
||||
{
|
||||
Name: "NewReg path should be POST only",
|
||||
Path: newRegPath,
|
||||
|
|
@ -877,188 +869,6 @@ func TestHTTPMethods(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Write additional test cases for:
|
||||
// - RA returns with a failure
|
||||
func TestIssueCertificate(t *testing.T) {
|
||||
wfe, fc := setupWFE(t)
|
||||
mockLog := wfe.log.(*blog.Mock)
|
||||
|
||||
// The mock CA we use always returns the same test certificate, with a Not
|
||||
// Before of 2015-09-22. Since we're currently using a real RA instead of a
|
||||
// mock (see below), that date would trigger failures for excessive
|
||||
// backdating. So we set the fake clock's time to a time that matches that
|
||||
// test certificate.
|
||||
testTime := time.Date(2015, 9, 9, 22, 56, 0, 0, time.UTC)
|
||||
fc.Add(fc.Now().Sub(testTime))
|
||||
|
||||
mockCertPEM, err := ioutil.ReadFile("test/not-an-example.com.crt")
|
||||
test.AssertNotError(t, err, "Could not load mock cert")
|
||||
|
||||
// TODO: Use a mock RA so we can test various conditions of authorized, not
|
||||
// authorized, etc.
|
||||
stats := metrics.NewNoopScope()
|
||||
ra := ra.NewRegistrationAuthorityImpl(
|
||||
fc,
|
||||
wfe.log,
|
||||
stats,
|
||||
0,
|
||||
testKeyPolicy,
|
||||
0,
|
||||
true,
|
||||
false,
|
||||
300*24*time.Hour,
|
||||
7*24*time.Hour,
|
||||
nil,
|
||||
0,
|
||||
)
|
||||
ra.SA = mocks.NewStorageAuthority(fc)
|
||||
ra.CA = &mocks.MockCA{
|
||||
PEM: mockCertPEM,
|
||||
}
|
||||
ra.PA = &mockPA{}
|
||||
wfe.RA = ra
|
||||
|
||||
targetHost := "localhost"
|
||||
targetPath := "new-cert"
|
||||
signedURL := fmt.Sprintf("http://%s/%s", targetHost, targetPath)
|
||||
|
||||
// Valid, signed JWS body, payload has an invalid signature on CSR and no authorizations:
|
||||
// alias b64url="base64 -w0 | sed -e 's,+,-,g' -e 's,/,_,g'"
|
||||
// openssl req -outform der -new -nodes -key wfe/test/178.key -subj /CN=foo.com | \
|
||||
// sed 's/foo.com/fob.com/' | b64url
|
||||
brokenCSRSignaturePayload := `{
|
||||
"csr": "MIICVzCCAT8CAQAwEjEQMA4GA1UEAwwHZm9iLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKzHhqcMSTVjBu61vufGVmIYM4mMbWXgndHOUWnIqSKcNtFtPQ465tcZRT5ITIZWXGjsmgDrj31qvG3t5qLwyaF5hsTvFHK72nLMAQhdgM6481Qe9yaoaulWpkGr_9LVz4jQ9pGAaLVamXGpSxV-ipTOo79Sev4aZE8ksD9atEfWtcOD9w8_zj74vpWjTAHN49Q88chlChVqakn0zSfHPfS-jF8g0UTddBuF0Ti3sZChjxzbo6LwZ4182xX7XPnOLav3AGj0Su7j5XMl3OpenOrlWulWJeZIHq5itGW321j306XiGdbrdWH4K7JygICFds6oolwQRGBY6yinAtCgkTcCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQBxPiHOtKuBxtvecMNtLkTSuTyEkusQGnjoFDaKe5oqwGYQgy0YBii2-BbaPmqS4ZaDc-vDz_RLeKH5ZiH-NliYR1V_CRtpFLQi18g_2pLQnZLVO3ENs-SM37nU_nBGn9O93t2bkssoM3fZmtgp3R2W7I_wvx7Z8oWKa4boTeBAg_q9Gmi6QskZBddK7A4S_vOR0frU6QSPK_ksPhvovp9fwb6CVKrlJWf556UwRPWgbkW39hvTxK2KHhrUEg3oawNkWde2jZtnZ9e-9zpw8-_5O0X7-YN0ucbFTfQybce_ReuLlGepiHT5bvVavBZoIvqw1XOgSMvGgZFU8tAWMBlj"
|
||||
}`
|
||||
|
||||
// Valid, signed JWS body, payload has a valid CSR but no authorizations:
|
||||
// openssl req -outform der -new -nodes -key wfe/test/178.key -subj /CN=meep.com | b64url
|
||||
noAuthorizationsCSRPayload := `{
|
||||
"resource":"new-cert",
|
||||
"csr": "MIICWDCCAUACAQAwEzERMA8GA1UEAwwIbWVlcC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaqzue57mgXEoGTZZoVkkCZraebWgXI8irX2BgQB1A3iZa9onxGPMcWQMxhSuUisbEJi4UkMcVST12HX01rUwhj41UuBxJvI1w4wvdstssTAaa9c9tsQ5-UED2bFRL1MsyBdbmCF_-pu3i-ZIYqWgiKbjVBe3nlAVbo77zizwp3Y4Tp1_TBOwTAuFkHePmkNT63uPm9My_hNzsSm1o-Q519Cf7ry-JQmOVgz_jIgFVGFYJ17EV3KUIpUuDShuyCFATBQspgJSN2DoXRUlQjXXkNTj23OxxdT_cVLcLJjytyG6e5izME2R2aCkDBWIc1a4_sRJ0R396auPXG6KhJ7o_AgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEALu046p76aKgvoAEHFINkMTgKokPXf9mZ4IZx_BKz-qs1MPMxVtPIrQDVweBH6tYT7Hfj2naLry6SpZ3vUNP_FYeTFWgW1V03LiqacX-QQgbEYtn99Dt3ScGyzb7EH833ztb3vDJ_-ha_CJplIrg-kHBBrlLFWXhh-I9K1qLRTNpbhZ18ooFde4Sbhkw9o9fKivGhx9aYr7ZbjRsNtKit_DsG1nwEXz53TMJ2vB9IQY29coJv_n5NFLkvBfzbG5faRNiFcimPYBO2jFdaA2mWzfxltLtwMF_dBwzTXDpMo3TVT9zEdV8YpsWqr63igqGDZVpKenlkqvRTeGJVayVuMA"
|
||||
}`
|
||||
|
||||
// CSR from an < 1.0.2 OpenSSL
|
||||
oldOpenSSLCSRPayload := `{
|
||||
"resource": "new-cert",
|
||||
"csr": "MIICWjCCAUICADAWMRQwEgYDVQQDEwtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMpwCSKfLhKC3SnvLNpVayAEyAHVixkusgProAPZRBH0VAog_r4JOfoJez7ABiZ2ZIXXA2gg65_05HkGNl9ww-sa0EY8eCty_8WcHxqzafUnyXOJZuLMPJjaJ2oiBv_3BM7PZgpFzyNZ0_0ZuRKdFGtEY-vX9GXZUV0A3sxZMOpce0lhHAiBk_vNARJyM2-O-cZ7WjzZ7R1T9myAyxtsFhWy3QYvIwiKVVF3lDp3KXlPZ_7wBhVIBcVSk0bzhseotyUnKg-aL5qZIeB1ci7IT5qA_6C1_bsCSJSbQ5gnQwIQ0iaUV_SgUBpKNqYbmnSdZmDxvvW8FzhuL6JSDLfBR2kCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQBxxkchTXfjv07aSWU9brHnRziNYOLvsSNiOWmWLNlZg9LKdBy6j1xwM8IQRCfTOVSkbuxVV-kU5p-Cg9UF_UGoerl3j8SiupurTovK9-L_PdX0wTKbK9xkh7OUq88jp32Rw0eAT87gODJRD-M1NXlTvm-j896e60hUmL-DIe3iPbFl8auUS-KROAWjci-LJZYVdomm9Iw47E-zr4Hg27EdZhvCZvSyPMK8ioys9mNg5TthHB6ExepKP1YW3HpQa1EdUVYWGEvyVL4upQZOxuEA1WJqHv6iVDzsQqkl5kkahK87NKTPS59k1TFetjw2GLnQ09-g_L7kT8dpq3Bk5Wo="
|
||||
}`
|
||||
|
||||
// openssl req -outform der -new -nodes -key wfe/test/178.key -subj /CN=not-an-example.com | b64url
|
||||
// a valid CSR with authorizations for all of its names
|
||||
goodCertCSRPayload := `{
|
||||
"resource":"new-cert",
|
||||
"csr": "MIICYjCCAUoCAQAwHTEbMBkGA1UEAwwSbm90LWFuLWV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmqs7nue5oFxKBk2WaFZJAma2nm1oFyPIq19gYEAdQN4mWvaJ8RjzHFkDMYUrlIrGxCYuFJDHFUk9dh19Na1MIY-NVLgcSbyNcOML3bLbLEwGmvXPbbEOflBA9mxUS9TLMgXW5ghf_qbt4vmSGKloIim41QXt55QFW6O-84s8Kd2OE6df0wTsEwLhZB3j5pDU-t7j5vTMv4Tc7EptaPkOdfQn-68viUJjlYM_4yIBVRhWCdexFdylCKVLg0obsghQEwULKYCUjdg6F0VJUI115DU49tzscXU_3FS3CyY8rchunuYszBNkdmgpAwViHNWuP7ESdEd_emrj1xuioSe6PwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAE_T1nWU38XVYL28hNVSXU0rW5IBUKtbvr0qAkD4kda4HmQRTYkt-LNSuvxoZCC9lxijjgtJi-OJe_DCTdZZpYzewlVvcKToWSYHYQ6Wm1-fxxD_XzphvZOujpmBySchdiz7QSVWJmVZu34XD5RJbIcrmj_cjRt42J1hiTFjNMzQu9U6_HwIMmliDL-soFY2RTvvZf-dAFvOUQ-Wbxt97eM1PbbmxJNWRhbAmgEpe9PWDPTpqV5AK56VAa991cQ1P8ZVmPss5hvwGWhOtpnpTZVHN3toGNYFKqxWPboirqushQlfKiFqT9rpRgM3-mFjOHidGqsKEkTdmfSVlVEk3oo="
|
||||
}`
|
||||
|
||||
cert, err := core.LoadCert("test/not-an-example.com.crt")
|
||||
test.AssertNotError(t, err, "Could not load cert")
|
||||
|
||||
goodCertAIAHeaders := map[string]string{
|
||||
"Location": "http://localhost/acme/cert/0000ff0000000000000e4b4f67d86e818c46",
|
||||
"Link": `<https://localhost:4000/acme/issuer-cert>;rel="up"`,
|
||||
"Content-Type": "application/pkix-cert",
|
||||
}
|
||||
goodCertLogParts := []string{
|
||||
`INFO: `,
|
||||
`[AUDIT] `,
|
||||
`"CommonName":"not-an-example.com",`,
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Request *http.Request
|
||||
ExpectedProblem string
|
||||
ExpectedCert string
|
||||
AssertCSRLogged bool
|
||||
ExpectedHeaders map[string]string
|
||||
ExpectedLogParts []string
|
||||
}{
|
||||
{
|
||||
Name: "POST, but no body",
|
||||
Request: &http.Request{
|
||||
Method: "POST",
|
||||
Header: map[string][]string{
|
||||
"Content-Length": {"0"},
|
||||
},
|
||||
},
|
||||
ExpectedProblem: `{"type":"urn:acme:error:malformed","detail":"No body on POST","status":400}`,
|
||||
},
|
||||
{
|
||||
Name: "POST, with an invalid JWS body",
|
||||
Request: makePostRequestWithPath("hi", "hi"),
|
||||
ExpectedProblem: `{"type":"urn:acme:error:malformed","detail":"Parse error reading JWS","status":400}`,
|
||||
},
|
||||
{
|
||||
Name: "POST, properly signed JWS, payload isn't valid",
|
||||
Request: signAndPost(t, targetPath, signedURL, "foo", 1, wfe.nonceService),
|
||||
ExpectedProblem: `{"type":"urn:acme:error:malformed","detail":"Request payload did not parse as JSON","status":400}`,
|
||||
},
|
||||
{
|
||||
Name: "POST, properly signed JWS, trivial JSON payload",
|
||||
Request: signAndPost(t, targetPath, signedURL, "{}", 1, wfe.nonceService),
|
||||
ExpectedProblem: `{"type":"urn:acme:error:malformed","detail":"Error parsing certificate request: asn1: syntax error: sequence truncated","status":400}`,
|
||||
},
|
||||
{
|
||||
Name: "POST, properly signed JWS, broken signature on CSR",
|
||||
Request: signAndPost(t, targetPath, signedURL, brokenCSRSignaturePayload, 1, wfe.nonceService),
|
||||
ExpectedProblem: `{"type":"urn:acme:error:malformed","detail":"Error creating new cert :: invalid signature on CSR","status":400}`,
|
||||
},
|
||||
{
|
||||
Name: "POST, properly signed JWS, CSR from an old OpenSSL",
|
||||
Request: signAndPost(t, targetPath, signedURL, oldOpenSSLCSRPayload, 1, wfe.nonceService),
|
||||
ExpectedProblem: `{"type":"urn:acme:error:malformed","detail":"CSR generated using a pre-1.0.2 OpenSSL with a client that doesn't properly specify the CSR version. See https://community.letsencrypt.org/t/openssl-bug-information/19591","status":400}`,
|
||||
},
|
||||
{
|
||||
Name: "POST, properly signed JWS, no authorizations for names in CSR",
|
||||
Request: signAndPost(t, targetPath, signedURL, noAuthorizationsCSRPayload, 1, wfe.nonceService),
|
||||
ExpectedProblem: `{"type":"urn:acme:error:unauthorized","detail":"Error creating new cert :: authorizations for these names not found or expired: meep.com","status":403}`,
|
||||
AssertCSRLogged: true,
|
||||
},
|
||||
{
|
||||
Name: "POST, properly signed JWS, authorizations for all names in CSR, using AIAIssuer",
|
||||
Request: signAndPost(t, targetPath, signedURL, goodCertCSRPayload, 1, wfe.nonceService),
|
||||
ExpectedCert: string(cert.Raw),
|
||||
AssertCSRLogged: true,
|
||||
ExpectedHeaders: goodCertAIAHeaders,
|
||||
ExpectedLogParts: goodCertLogParts,
|
||||
},
|
||||
}
|
||||
|
||||
responseWriter := httptest.NewRecorder()
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
responseWriter.Body.Reset()
|
||||
responseWriter.HeaderMap = http.Header{}
|
||||
mockLog.Clear()
|
||||
|
||||
wfe.NewCertificate(ctx, newRequestEvent(), responseWriter, tc.Request)
|
||||
if len(tc.ExpectedProblem) > 0 {
|
||||
test.AssertUnmarshaledEquals(t, responseWriter.Body.String(), tc.ExpectedProblem)
|
||||
} else if len(tc.ExpectedCert) > 0 {
|
||||
test.AssertEquals(t, responseWriter.Body.String(), tc.ExpectedCert)
|
||||
}
|
||||
|
||||
if tc.AssertCSRLogged {
|
||||
assertCsrLogged(t, mockLog)
|
||||
}
|
||||
|
||||
headers := responseWriter.Header()
|
||||
for k, v := range tc.ExpectedHeaders {
|
||||
test.AssertEquals(t, headers.Get(k), v)
|
||||
}
|
||||
|
||||
if len(tc.ExpectedLogParts) > 0 {
|
||||
reqlogs := mockLog.GetAllMatching(`Certificate request - successful`)
|
||||
test.AssertEquals(t, len(reqlogs), 1)
|
||||
for _, msg := range tc.ExpectedLogParts {
|
||||
test.AssertContains(t, reqlogs[0], msg)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetChallenge(t *testing.T) {
|
||||
wfe, _ := setupWFE(t)
|
||||
|
||||
|
|
@ -1356,13 +1166,8 @@ func TestNewRegistration(t *testing.T) {
|
|||
t, responseWriter.Header().Get("Location"),
|
||||
"http://localhost/acme/reg/0")
|
||||
links := responseWriter.Header()["Link"]
|
||||
test.AssertEquals(t, contains(links, "<http://localhost/acme/new-authz>;rel=\"next\""), true)
|
||||
test.AssertEquals(t, contains(links, "<"+agreementURL+">;rel=\"terms-of-service\""), true)
|
||||
|
||||
test.AssertEquals(
|
||||
t, responseWriter.Header().Get("Link"),
|
||||
`<http://localhost/acme/new-authz>;rel="next"`)
|
||||
|
||||
key = loadKeys(t, []byte(test1KeyPrivatePEM))
|
||||
_, ok = key.(*rsa.PrivateKey)
|
||||
test.Assert(t, ok, "Couldn't load test1 key")
|
||||
|
|
@ -1409,80 +1214,6 @@ func makeRevokeRequestJSON(reason *revocation.Reason) ([]byte, error) {
|
|||
return revokeRequestJSON, nil
|
||||
}
|
||||
|
||||
func TestAuthorization(t *testing.T) {
|
||||
wfe, _ := setupWFE(t)
|
||||
authzURL := fmt.Sprintf("http://localhost%s", authzPath)
|
||||
|
||||
_, _, jwsInvalidBody := signRequestKeyID(t, 1, nil, authzURL, "foo", wfe.nonceService)
|
||||
jwsInvalidSig := `{"payload":"Zm9x","protected":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjEiLCJub25jZSI6ImdMTE90QlJCeXl4V3Y2RExQRUJFUERsS05DV294NzdjYzBRLXdTSVdYY1UiLCJ1cmwiOiJodHRwOi8vbG9jYWxob3N0L2FjbWUvYXV0aHovIn0","signature":"Xn2yTyn1eIgbv1HOnl8_OuDMrHRlacje_fhAYyOlVmFGrb9vzTTYQ-TXdXpjrtQzcIRX7z0v1Wv3DJJryMAMwm-I9DN-Gmd_h1HG6KXK61vHIqMWlUen2WoBBNdeE00S5UI0iP-zY5E_jfW0ByLzAqoZeMN_vTJG40Ji9hfvaPaQBGLEcz6xw0Mc7EgacY6m_JGPBkCDvrDstHTTqIu5tZ3Dw7tif33aakONDKXVE0WOHjfHNP-jW4tkeCrlIDajWpU074AGmCMyBDXK5ii6Pv6tztcMPqg8SvL9_I7RyCsjQGCymNCr_XoJkRwS6GBoaKS5Jqmb-qt-O_-rcpq-Fw"}`
|
||||
goodPayload := `{"identifier":{"type":"dns","value":"test.com"}}`
|
||||
_, _, goodJWSBody := signRequestKeyID(t, 1, nil, authzURL, goodPayload, wfe.nonceService)
|
||||
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Request *http.Request
|
||||
ExpectedBody string
|
||||
ExpectedHeaders map[string]string
|
||||
UnmarshalAuthz bool
|
||||
}{
|
||||
{
|
||||
Name: "POST with no body",
|
||||
Request: &http.Request{
|
||||
Method: "POST",
|
||||
Header: map[string][]string{
|
||||
"Content-Length": {"0"},
|
||||
},
|
||||
},
|
||||
ExpectedBody: `{"type":"urn:acme:error:malformed","detail":"No body on POST","status":400}`,
|
||||
},
|
||||
{
|
||||
Name: "POST with invalid JWS",
|
||||
Request: makePostRequestWithPath("hi", "hi"),
|
||||
ExpectedBody: `{"type":"urn:acme:error:malformed","detail":"Parse error reading JWS","status":400}`,
|
||||
},
|
||||
{
|
||||
Name: "POST JWS with invalid payload",
|
||||
Request: makePostRequestWithPath(authzPath, jwsInvalidBody),
|
||||
ExpectedBody: `{"type":"urn:acme:error:malformed","detail":"Request payload did not parse as JSON","status":400}`,
|
||||
},
|
||||
{
|
||||
Name: "POST JWS with a broken signature",
|
||||
Request: makePostRequestWithPath(authzPath, jwsInvalidSig),
|
||||
ExpectedBody: `{"type":"urn:acme:error:malformed","detail":"JWS verification error","status":400}`,
|
||||
},
|
||||
{
|
||||
Name: "Valid POST",
|
||||
Request: makePostRequestWithPath(authzPath, goodJWSBody),
|
||||
ExpectedBody: `{"identifier":{"type":"dns","value":"test.com"}}`,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"Location": "http://localhost/acme/authz/bkrPh2u0JUf18-rVBZtOOWWb3GuIiliypL-hBM9Ak1Q",
|
||||
"Link": `<http://localhost/acme/new-cert>;rel="next"`,
|
||||
},
|
||||
UnmarshalAuthz: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
responseWriter := httptest.NewRecorder()
|
||||
wfe.NewAuthorization(ctx, newRequestEvent(), responseWriter, tc.Request)
|
||||
body := responseWriter.Body.String()
|
||||
headers := responseWriter.Header()
|
||||
test.AssertUnmarshaledEquals(t, body, tc.ExpectedBody)
|
||||
for h, v := range tc.ExpectedHeaders {
|
||||
test.AssertEquals(t, headers.Get(h), v)
|
||||
}
|
||||
// If the test case instructs, also ensure the response body unmarshals into an authz
|
||||
if tc.UnmarshalAuthz {
|
||||
var authz core.Authorization
|
||||
err := json.Unmarshal([]byte(body), &authz)
|
||||
test.AssertNotError(t, err, "Couldn't unmarshal returned authorization object")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetAuthorization(t *testing.T) {
|
||||
wfe, _ := setupWFE(t)
|
||||
|
||||
|
|
@ -1581,7 +1312,6 @@ func TestRegistration(t *testing.T) {
|
|||
wfe.Registration(ctx, newRequestEvent(), responseWriter, request)
|
||||
test.AssertNotContains(t, responseWriter.Body.String(), "urn:acme:error")
|
||||
links := responseWriter.Header()["Link"]
|
||||
test.AssertEquals(t, contains(links, "<http://localhost/acme/new-authz>;rel=\"next\""), true)
|
||||
test.AssertEquals(t, contains(links, "<"+agreementURL+">;rel=\"terms-of-service\""), true)
|
||||
responseWriter.Body.Reset()
|
||||
|
||||
|
|
@ -1607,7 +1337,6 @@ func TestRegistration(t *testing.T) {
|
|||
wfe.Registration(ctx, newRequestEvent(), responseWriter, request)
|
||||
test.AssertNotContains(t, responseWriter.Body.String(), "urn:acme:error")
|
||||
links = responseWriter.Header()["Link"]
|
||||
test.AssertEquals(t, contains(links, "<http://localhost/acme/new-authz>;rel=\"next\""), true)
|
||||
test.AssertEquals(t, contains(links, "<http://example.invalid/new-terms>;rel=\"terms-of-service\""), true)
|
||||
responseWriter.Body.Reset()
|
||||
}
|
||||
|
|
@ -1741,62 +1470,6 @@ func TestGetCertificate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func assertCsrLogged(t *testing.T, mockLog *blog.Mock) {
|
||||
matches := mockLog.GetAllMatching("^INFO: \\[AUDIT\\] Certificate request JSON=")
|
||||
test.Assert(t, len(matches) == 1,
|
||||
fmt.Sprintf("Incorrect number of certificate request log entries: %d",
|
||||
len(matches)))
|
||||
}
|
||||
|
||||
func TestLogCsrPem(t *testing.T) {
|
||||
const certificateRequestJSON = `{
|
||||
"csr": "MIICWTCCAUECAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAycX3ca-fViOuRWF38mssORISFxbJvspDfhPGRBZDxJ63NIqQzupB-6dp48xkcX7Z_KDaRJStcpJT2S0u33moNT4FHLklQBETLhExDk66cmlz6Xibp3LGZAwhWuec7wJoEwIgY8oq4rxihIyGq7HVIJoq9DqZGrUgfZMDeEJqbphukQOaXGEop7mD-eeu8-z5EVkB1LiJ6Yej6R8MAhVPHzG5fyOu6YVo6vY6QgwjRLfZHNj5XthxgPIEETZlUbiSoI6J19GYHvLURBTy5Ys54lYAPIGfNwcIBAH4gtH9FrYcDY68R22rp4iuxdvkf03ZWiT0F2W1y7_C9B2jayTzvQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAHd6Do9DIZ2hvdt1GwBXYjsqprZidT_DYOMfYcK17KlvdkFT58XrBH88ulLZ72NXEpiFMeTyzfs3XEyGq_Bbe7TBGVYZabUEh-LOskYwhgcOuThVN7tHnH5rhN-gb7cEdysjTb1QL-vOUwYgV75CB6PE5JVYK-cQsMIVvo0Kz4TpNgjJnWzbcH7h0mtvub-fCv92vBPjvYq8gUDLNrok6rbg05tdOJkXsF2G_W-Q6sf2Fvx0bK5JeH4an7P7cXF9VG9nd4sRt5zd-L3IcyvHVKxNhIJXZVH0AOqh_1YrKI9R0QKQiZCEy0xN1okPlcaIVaFhb7IKAHPxTI3r5f72LXY"
|
||||
}`
|
||||
wfe, fc := setupWFE(t)
|
||||
var certificateRequest core.CertificateRequest
|
||||
err := json.Unmarshal([]byte(certificateRequestJSON), &certificateRequest)
|
||||
test.AssertNotError(t, err, "Unable to parse certificateRequest")
|
||||
|
||||
mockSA := mocks.NewStorageAuthority(fc)
|
||||
reg, err := mockSA.GetRegistration(ctx, 789)
|
||||
test.AssertNotError(t, err, "Unable to get registration")
|
||||
|
||||
req, err := http.NewRequest("GET", "http://[::1]/", nil)
|
||||
test.AssertNotError(t, err, "NewRequest failed")
|
||||
req.RemoteAddr = "12.34.98.76"
|
||||
req.Header.Set("X-Forwarded-For", "10.0.0.1,172.16.0.1")
|
||||
|
||||
mockLog := wfe.log.(*blog.Mock)
|
||||
mockLog.Clear()
|
||||
|
||||
wfe.logCsr(req, certificateRequest, reg)
|
||||
|
||||
assertCsrLogged(t, mockLog)
|
||||
}
|
||||
|
||||
func TestBadKeyCSR(t *testing.T) {
|
||||
wfe, _ := setupWFE(t)
|
||||
responseWriter := httptest.NewRecorder()
|
||||
|
||||
payload := `{
|
||||
"resource":"new-cert",
|
||||
"csr": "MIHLMHcCAQAwEjEQMA4GA1UEAwwHZm9vLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDCZftp4x4owgjBnwOKfzihIPedT-BUmV2fuQPMqaUlc8yJUp13vcO5uxUlaBm8leM7Dj_sgTDP_JgykorlYo73AgMBAAGgADANBgkqhkiG9w0BAQsFAANBAEaQ2QBhweK-kp1ejQCedUhMit_wG-uTBtKnc3M82f6_fztLkhg1vWQ782nmhbEI5orXp6QtNHgJYnBpqA9Ut00"
|
||||
}`
|
||||
signedURL := fmt.Sprintf("http://localhost%s", newCertPath)
|
||||
// Sign a request using test1key
|
||||
_, _, body := signRequestKeyID(t, 1, nil, signedURL, payload, wfe.nonceService)
|
||||
request := makePostRequestWithPath(newCertPath, body)
|
||||
|
||||
// CSR with a bad (512 bit RSA) key.
|
||||
// openssl req -outform der -new -newkey rsa:512 -nodes -keyout foo.com.key
|
||||
// -subj /CN=foo.com | base64 -w0 | sed -e 's,+,-,g' -e 's,/,_,g'
|
||||
wfe.NewCertificate(ctx, newRequestEvent(), responseWriter, request)
|
||||
|
||||
test.AssertUnmarshaledEquals(t,
|
||||
responseWriter.Body.String(),
|
||||
`{"type":"urn:acme:error:malformed","detail":"Invalid key in certificate request :: key too small: 512","status":400}`)
|
||||
}
|
||||
|
||||
// This uses httptest.NewServer because ServeMux.ServeHTTP won't prevent the
|
||||
// body from being sent like the net/http Server's actually do.
|
||||
func TestGetCertificateHEADHasCorrectBodyLength(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue