diff --git a/ca/certificate-authority_test.go b/ca/certificate-authority_test.go index 106f8730e..c7985cf8a 100644 --- a/ca/certificate-authority_test.go +++ b/ca/certificate-authority_test.go @@ -353,10 +353,10 @@ func TestIssueCertificate(t *testing.T) { } // Verify that the cert got stored in the DB - shortSerial := fmt.Sprintf("%016x", cert.SerialNumber)[0:16] + shortSerial := fmt.Sprintf("%032x", cert.SerialNumber)[0:16] _, err = sa.GetCertificate(shortSerial) test.AssertNotError(t, err, - fmt.Sprintf("Certificate %016x not found in database", shortSerial)) + fmt.Sprintf("Certificate %032x not found in database", cert.SerialNumber)) } // Test that the CA rejects CSRs with no names diff --git a/log/audit-logger.go b/log/audit-logger.go index 221885bcc..aa231e7cf 100644 --- a/log/audit-logger.go +++ b/log/audit-logger.go @@ -116,3 +116,9 @@ func (log *AuditLogger) Warning(msg string) (err error) { log.Stats.Inc("Logging.Warning", 1, 1.0) return log.Writer.Warning(msg) } + +func (log *AuditLogger) Notice(msg string) (err error) { + fmt.Println(msg) + log.Stats.Inc("Logging.Notice", 1, 1.0) + return log.Writer.Notice(msg) +} diff --git a/ra/registration-authority_test.go b/ra/registration-authority_test.go index 51eaa48af..79657c376 100644 --- a/ra/registration-authority_test.go +++ b/ra/registration-authority_test.go @@ -244,11 +244,12 @@ func TestNewCertificate(t *testing.T) { test.AssertNotError(t, err, "Failed to issue certificate") parsedCert, err := x509.ParseCertificate(cert.DER) test.AssertNotError(t, err, "Failed to parse certificate") - shortSerial := fmt.Sprintf("%016x", parsedCert.SerialNumber)[0:16] + shortSerial := fmt.Sprintf("%032x", parsedCert.SerialNumber)[0:16] // Verify that cert shows up and is as expected dbCert, err := sa.GetCertificate(shortSerial) - test.AssertNotError(t, err, "Could not fetch certificate from database") + test.AssertNotError(t, err, fmt.Sprintf("Could not fetch certificate %032x from database", + parsedCert.SerialNumber)) test.Assert(t, bytes.Compare(cert.DER, dbCert) == 0, "Certificates differ") // TODO Test failure cases diff --git a/sa/storage-authority.go b/sa/storage-authority.go index 26103fc0c..826935d49 100644 --- a/sa/storage-authority.go +++ b/sa/storage-authority.go @@ -374,7 +374,7 @@ func (ssa *SQLStorageAuthority) AddCertificate(certDER []byte) (digest string, e if err != nil { return } - serial := fmt.Sprintf("%016x", parsedCertificate.SerialNumber) + serial := fmt.Sprintf("%032x", parsedCertificate.SerialNumber) tx, err := ssa.db.Begin() if err != nil { diff --git a/test.sh b/test.sh index 3102d6b07..0967a92c7 100755 --- a/test.sh +++ b/test.sh @@ -44,7 +44,10 @@ doTest wfe [ -e $GOBIN/gover ] && run $GOBIN/gover if [ "${TRAVIS}" == "true" ] ; then - run $GOBIN/goveralls -coverprofile=gover.coverprofile -service=travis-ci + # We don't use the run function here because sometimes goveralls fails to + # contact the server and exits with non-zero status, but we don't want to + # treat that as a failure. + $GOBIN/goveralls -coverprofile=gover.coverprofile -service=travis-ci fi exit ${FAILURE} diff --git a/test/js/package.json b/test/js/package.json index 0e499937b..a85289a7b 100644 --- a/test/js/package.json +++ b/test/js/package.json @@ -6,6 +6,7 @@ "dependencies": { "cli": "^0.6.5", "inquirer": "^0.8.2", - "node-forge": "^0.6.21" + "node-forge": "^0.6.21", + "request": "^2.55.0" } } diff --git a/test/js/test.js b/test/js/test.js index bc04cdc45..67dac282f 100644 --- a/test/js/test.js +++ b/test/js/test.js @@ -2,16 +2,28 @@ // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// To test against a Boulder running on localhost in test mode: +// cd boulder/test/js +// npm install +// js test.js +// +// To test against a live or demo Boulder, edit this file to change +// newRegistrationURL, then run: +// sudo js test.js. "use strict"; -var inquirer = require("inquirer"); var cli = require("cli"); -var http = require('http'); +var crypto = require("./crypto-util"); +var child_process = require('child_process'); var fs = require('fs'); +var http = require('http'); +var https = require('https'); +var inquirer = require("inquirer"); +var request = require('request'); var url = require('url'); var util = require("./acme-util"); -var crypto = require("./crypto-util"); var questions = { email: [{ @@ -32,7 +44,7 @@ var questions = { type: "confirm", name: "terms", message: "Do you agree to these terms?", - default: false, + default: true, }], domain: [{ @@ -64,14 +76,14 @@ var questions = { type: "input", name: "certFile", message: "Name for certificate file", - default: "cert.pem" + default: "cert.der" }], }; var state = { - keyPairBits: 512, keyPair: null, + //newRegistrationURL: "https://www.letsencrypt-demo.org/acme/new-reg", newRegistrationURL: "http://localhost:4000/acme/new-reg", registrationURL: "", @@ -89,6 +101,8 @@ var state = { newCertificateURL: "", certificateURL: "", + certFile: "", + keyFile: "" }; function parseLink(link) { @@ -152,10 +166,23 @@ saveFiles */ function main() { + inquirer.prompt(questions.files, makeKeyPair); +} + +function makeKeyPair(answers) { + state.certFile = answers.certFile; + state.keyFile = answers.keyFile; console.log("Generating key pair..."); - state.keyPair = crypto.generateKeyPair(state.keyPairBits); - console.log(); - inquirer.prompt(questions.email, register) + child_process.exec("openssl req -newkey rsa:2048 -keyout " + state.keyFile + " -days 3650 -subj /CN=foo -nodes -x509 -out temp-cert.pem", function (error, stdout, stderr) { + if (error) { + console.log(error); + process.exit(1); + } + state.keyPair = crypto.importPemPrivateKey(fs.readFileSync(state.keyFile)); + + console.log(); + inquirer.prompt(questions.email, register) + }); } function register(answers) { @@ -169,17 +196,15 @@ function register(answers) { var jws = crypto.generateSignature(state.keyPair, new Buffer(registerMessage)); var payload = JSON.stringify(jws); - var options = url.parse(state.newRegistrationURL); - options.method = "POST"; - var req = http.request(options, getTerms); + var req = request.post(state.newRegistrationURL, {}, getTerms); req.write(payload) req.end(); } -function getTerms(resp) { - if (Math.floor(resp.statusCode / 100) != 2) { +function getTerms(err, resp) { + if (err || Math.floor(resp.statusCode / 100) != 2) { // Non-2XX response - console.log("Registration request failed with code " + resp.statusCode); + console.log("Registration request failed:" + err); return; } @@ -196,28 +221,24 @@ function getTerms(resp) { if (state.termsRequired) { state.termsURL = links["terms-of-service"]; console.log(state.termsURL); - http.get(state.termsURL, getAgreement) + request.get(state.termsURL, getAgreement) } else { inquirer.prompt(questions.domain, getChallenges); } } -function getAgreement(resp) { - var body = ""; - resp.on("data", function(chunk) { - body += chunk; - }); - resp.on("end", function(chunk) { - if (chunk) { body += chunk; } +function getAgreement(err, resp, body) { + if (err) { + console.log("getAgreement error:", err); + process.exit(1); + } + // TODO: Check content-type + console.log("The CA requires your agreement to terms."); + console.log(); + console.log(body); + console.log(); - // TODO: Check content-type - console.log("The CA requires your agreement to terms (not supported)."); - console.log(); - console.log(body); - console.log(); - - inquirer.prompt(questions.terms, sendAgreement); - }); + inquirer.prompt(questions.terms, sendAgreement); } function sendAgreement(answers) { @@ -234,20 +255,13 @@ function sendAgreement(answers) { var payload = JSON.stringify(jws); console.log("Posting agreement to: " + state.registrationURL) - var options = url.parse(state.registrationURL); - options.method = "POST"; - var req = http.request(options, function(resp) { - var body = ""; - resp.on("data", function(chunk) { body += chunk; }); - resp.on("end", function() { - if (Math.floor(resp.statusCode / 100) != 2) { - // Non-2XX response - console.log("Couldn't POST agreement back to server, aborting."); - console.log("Code: "+ resp.statusCode); - console.log(body); - process.exit(1); - } - }); + var req = request.post(state.registrationURL, function(err, resp, body) { + if (err) { + console.log("Couldn't POST agreement back to server, aborting."); + console.log("error: " + err); + console.log(body); + process.exit(1); + } inquirer.prompt(questions.domain, getChallenges); }); @@ -268,15 +282,13 @@ function getChallenges(answers) { var jws = crypto.generateSignature(state.keyPair, new Buffer(authzMessage)); var payload = JSON.stringify(jws); - var options = url.parse(state.newAuthorizationURL); - options.method = "POST"; - var req = http.request(options, getReadyToValidate); + var req = request.post(state.newAuthorizationURL, {}, getReadyToValidate); req.write(payload) req.end(); } -function getReadyToValidate(resp) { - if (Math.floor(resp.statusCode / 100) != 2) { +function getReadyToValidate(err, resp, body) { + if (err || Math.floor(resp.statusCode / 100) != 2) { // Non-2XX response console.log("Authorization request failed with code " + resp.statusCode) return; @@ -291,42 +303,48 @@ function getReadyToValidate(resp) { state.authorizationURL = resp.headers["location"]; state.newCertificateURL = links["next"]; - var body = "" - resp.on('data', function(chunk) { - body += chunk; - }); - resp.on('end', function(chunk) { - if (chunk) { body += chunk; } + var authz = JSON.parse(body); - var authz = JSON.parse(body); + var simpleHttps = authz.challenges.filter(function(x) { return x.type == "simpleHttps"; }); + if (simpleHttps.length == 0) { + console.log("The server didn't offer any challenges we can handle."); + return; + } - var simpleHttps = authz.challenges.filter(function(x) { return x.type == "simpleHttps"; }); - if (simpleHttps.length == 0) { - console.log("The server didn't offer any challenges we can handle."); - return; + var challenge = simpleHttps[0]; + var path = crypto.randomString(8) + ".txt"; + var challengePath = ".well-known/acme-challenge/" + path; + fs.writeFileSync(challengePath, challenge.token); + state.responseURL = challenge["uri"]; + state.path = path; + + // For local, test-mode validation + function httpResponder(req, response) { + console.log("Got request for", req.url); + var host = req.headers["host"]; + if ((host === state.domain || /localhost/.test(state.newRegistrationURL)) && + req.method === "GET" && + req.url == "/" + challengePath) { + response.writeHead(200, {"Content-Type": "text/plain"}); + response.end(challenge.token); + } else { + console.log("Got invalid request for", req.method, host, req.url); + response.writeHead(404, {"Content-Type": "text/plain"}); + response.end(""); } + }; + if (/localhost/.test(state.newRegistrationURL)) { + var httpServer = http.createServer(httpResponder) + httpServer.listen(5001) + } else { + var httpServer = https.createServer({ + cert: fs.readFileSync("temp-cert.pem"), + key: fs.readFileSync(state.keyFile) + }, httpResponder) + httpServer.listen(443) + } - var challenge = simpleHttps[0]; - var path = crypto.randomString(8) + ".txt"; - fs.writeFileSync(".well-known/acme-challenge/" + path, challenge.token); - state.responseURL = challenge["uri"]; - state.path = path; - - console.log(); - console.log("To validate that you own "+ state.domain +", the CA has\n" + - "asked you to provision a file on your server. I've saved\n" + - "the file here for you.\n"); - console.log(" File: " + path); - console.log(" URL: http://"+ state.domain +"/.well-known/acme-challenge/"+ path); - console.log(); - - // To do this locally (boulder connects to port 5001) - // > mkdir -p .well-known/acme-challenge/ - // > mv $CHALLENGE_FILE ./well-known/acme-challenge/ - // > python -m SimpleHTTPServer 5001 - - inquirer.prompt(questions.readyToValidate, sendResponse); - }); + inquirer.prompt(questions.readyToValidate, sendResponse); } function sendResponse() { @@ -340,44 +358,36 @@ function sendResponse() { var options = url.parse(state.responseURL); options.method = "POST"; - var req = http.request(options, ensureValidation); + var req = request.post(state.responseURL, {}, ensureValidation); req.write(payload) req.end(); } -function ensureValidation(resp) { +function ensureValidation(err, resp, body) { if (Math.floor(resp.statusCode / 100) != 2) { // Non-2XX response console.log("Authorization status request failed with code " + resp.statusCode) return; } - var body = ""; - resp.on('data', function(chunk) { - body += chunk; - }); - resp.on('end', function(chunk) { - if (chunk) { body += chunk; } + var authz = JSON.parse(body); - var authz = JSON.parse(body); - - if (authz.status == "pending") { - setTimeout(function() { - http.get(state.authorizationURL, ensureValidation); - }, state.retryDelay); - } else if (authz.status == "valid") { - cli.spinner("Validating domain ... done", true); - console.log(); - getCertificate(); - } else if (authz.status == "invalid") { - console.log("The CA was unable to validate the file you provisioned:" + authz); - return; - } else { - console.log("The CA returned an authorization in an unexpected state"); - console.log(JSON.stringify(authz, null, " ")); - return; - } - }); + if (authz.status == "pending") { + setTimeout(function() { + request.get(state.authorizationURL, {}, ensureValidation); + }, state.retryDelay); + } else if (authz.status == "valid") { + cli.spinner("Validating domain ... done", true); + console.log(); + getCertificate(); + } else if (authz.status == "invalid") { + console.log("The CA was unable to validate the file you provisioned:" + body); + return; + } else { + console.log("The CA returned an authorization in an unexpected state"); + console.log(JSON.stringify(authz, null, " ")); + return; + } } function getCertificate() { @@ -392,49 +402,57 @@ function getCertificate() { cli.spinner("Requesting certificate"); - var options = url.parse(state.newCertificateURL); - options.method = "POST"; - var req = http.request(options, downloadCertificate); + var req = request.post({ + url: state.newCertificateURL, + encoding: null // Return body as buffer. + }, downloadCertificate); req.write(payload) req.end(); } -function downloadCertificate(resp) { - var chunks = []; - resp.on('data', function(chunk) { - chunks.push(chunk); - }); - resp.on('end', function(chunk) { - if (chunk) { chunks.push(chunk); } - var body = Buffer.concat(chunks); +function downloadCertificate(err, resp, body) { + if (err || Math.floor(resp.statusCode / 100) != 2) { + // Non-2XX response + console.log("Certificate request failed with code " + resp.statusCode); + console.log(body.toString()); + return; + } - if (Math.floor(resp.statusCode / 100) != 2) { - // Non-2XX response - console.log("Certificate request failed with code " + resp.statusCode); - console.log(body.toString()); - return; + cli.spinner("Requesting certificate ... done", true); + console.log(); + + state.certificate = body; + console.log() + var certURL = resp.headers['location']; + request.get({ + url: certURL, + encoding: null // Return body as buffer. + }, function(err, res, body) { + if (err) { + console.log("Error: Failed to fetch certificate from", certURL, ":", err); + process.exit(1); + } + if (res.statusCode !== 200) { + console.log("Error: Failed to fetch certificate from", certURL, ":", res.statusCode, res.body.toString()); + fs.writeFileSync(state.certFile, state.certificate); + process.exit(1); + } + if (body.toString() !== state.certificate.toString()) { + console.log("Error: cert at", certURL, "did not match returned cert."); + } else { + console.log("Successfully verified cert at", certURL); + saveFiles() } - - cli.spinner("Requesting certificate ... done", true); - console.log(); - var certB64 = util.b64enc(body); - - state.certificate = certB64; - inquirer.prompt(questions.files, saveFiles); }); } function saveFiles(answers) { - var keyPEM = crypto.privateKeyToPem(state.keyPair.privateKey); - fs.writeFileSync(answers.keyFile, keyPEM); - - var certPEM = crypto.certificateToPem(state.certificate); - fs.writeFileSync(answers.certFile, certPEM); + fs.writeFileSync(state.certFile, state.certificate); console.log("Done!") console.log("To try it out:"); - console.log("openssl s_server -accept 8080 -www -key "+ - answers.keyFile +" -cert "+ answers.certFile); + console.log("openssl s_server -accept 8080 -www -certform der -key "+ + state.keyFile +" -cert "+ state.certFile); // XXX: Explicitly exit, since something's tenacious here process.exit(0); diff --git a/va/validation-authority.go b/va/validation-authority.go index 5b427f0d9..c0d9024b7 100644 --- a/va/validation-authority.go +++ b/va/validation-authority.go @@ -39,27 +39,48 @@ func (va ValidationAuthorityImpl) validateSimpleHTTPS(identifier core.AcmeIdenti return } - url := "" + if identifier.Type != core.IdentifierDNS { + challenge.Status = core.StatusInvalid + return + } + hostName := identifier.Value + protocol := "https" if va.TestMode { - url = fmt.Sprintf("http://localhost:5001/.well-known/acme-challenge/%s", challenge.Path) - } else { - url = fmt.Sprintf("https://%s/.well-known/acme-challenge/%s", identifier, challenge.Path) + hostName = "localhost:5001" + protocol = "http" } + url := fmt.Sprintf("%s://%s/.well-known/acme-challenge/%s", protocol, hostName, challenge.Path) + + va.log.Notice(fmt.Sprintf("Attempting to validate SimpleHTTPS for %s %s", hostName, url)) httpRequest, err := http.NewRequest("GET", url, nil) if err != nil { + va.log.Notice(fmt.Sprintf("Error validating SimpleHTTPS for %s %s: %s", hostName, url, err)) challenge.Status = core.StatusInvalid return } - httpRequest.Host = identifier.Value - client := http.Client{Timeout: 5 * time.Second} + httpRequest.Host = hostName + tr := &http.Transport{ + // We are talking to a client that does not yet have a certificate, + // so we accept a temporary, invalid one. TODO: We may want to change this + // to just be over HTTP. + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + // We don't expect to make multiple requests to a client, so close + // connection immediately. + DisableKeepAlives: true, + } + client := http.Client{ + Transport: tr, + Timeout: 5 * time.Second, + } httpResponse, err := client.Do(httpRequest) if err == nil && httpResponse.StatusCode == 200 { // Read body & test body, err := ioutil.ReadAll(httpResponse.Body) if err != nil { + va.log.Notice(fmt.Sprintf("Error validating SimpleHTTPS for %s %s: %s", hostName, url, err)) challenge.Status = core.StatusInvalid return } @@ -67,14 +88,25 @@ func (va ValidationAuthorityImpl) validateSimpleHTTPS(identifier core.AcmeIdenti if subtle.ConstantTimeCompare(body, []byte(challenge.Token)) == 1 { challenge.Status = core.StatusValid return + } else { + va.log.Notice(fmt.Sprintf("Incorrect token validating SimpleHTTPS for %s %s", hostName, url)) } + } else if err != nil { + va.log.Notice(fmt.Sprintf("Error validating SimpleHTTPS for %s %s: %s", hostName, url, err)) + challenge.Status = core.StatusInvalid + } else { + va.log.Notice(fmt.Sprintf("Error validating SimpleHTTPS for %s %s: %d", hostName, url, httpResponse.StatusCode)) + challenge.Status = core.StatusInvalid } - - challenge.Status = core.StatusInvalid return } func (va ValidationAuthorityImpl) validateDvsni(identifier core.AcmeIdentifier, input core.Challenge) (challenge core.Challenge) { + if identifier.Type != "dns" { + challenge.Status = core.StatusInvalid + return + } + challenge = input const DVSNI_SUFFIX = ".acme.invalid" @@ -93,20 +125,16 @@ func (va ValidationAuthorityImpl) validateDvsni(identifier core.AcmeIdentifier, RS := append(R, S...) z := sha256.Sum256(RS) - zName := fmt.Sprintf("%x.acme.invalid", z) + zName := fmt.Sprintf("%064x.acme.invalid", z) // Make a connection with SNI = nonceName - hostPort := "" + hostPort := identifier.Value + ":443" if va.TestMode { hostPort = "localhost:5001" - } else { - if identifier.Type != "dns" { - challenge.Status = core.StatusInvalid - return - } - hostPort = identifier.Value + ":443" } + va.log.Notice(fmt.Sprintf("Attempting to validate DVSNI for %s %s %s", + identifier, hostPort, zName)) conn, err := tls.Dial("tcp", hostPort, &tls.Config{ ServerName: nonceName, InsecureSkipVerify: true, @@ -116,6 +144,7 @@ func (va ValidationAuthorityImpl) validateDvsni(identifier core.AcmeIdentifier, challenge.Status = core.StatusInvalid return } + defer conn.Close() // Check that zName is a dNSName SAN in the server's certificate certs := conn.ConnectionState().PeerCertificates diff --git a/wfe/web-front-end.go b/wfe/web-front-end.go index a155118f9..ef38a3294 100644 --- a/wfe/web-front-end.go +++ b/wfe/web-front-end.go @@ -125,12 +125,13 @@ type problem struct { Instance string `json:"instance,omitempty"` } -func sendError(response http.ResponseWriter, message string, code int) { +func (wfe *WebFrontEndImpl) sendError(response http.ResponseWriter, message string, code int) { problem := problem{Detail: message} problemDoc, err := json.Marshal(problem) if err != nil { - return + problemDoc = []byte("{\"detail\": \"Problem marshalling error message.\"}") } + wfe.log.Debug("Sending error to client: " + string(problemDoc)) // Paraphrased from // https://golang.org/src/net/http/server.go#L1272 response.Header().Set("Content-Type", "application/problem+json") @@ -144,26 +145,26 @@ func link(url, relation string) string { func (wfe *WebFrontEndImpl) NewRegistration(response http.ResponseWriter, request *http.Request) { if request.Method != "POST" { - sendError(response, "Method not allowed", http.StatusMethodNotAllowed) + wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed) return } body, key, err := verifyPOST(request) if err != nil { - sendError(response, fmt.Sprintf("Unable to read/verify body: %v", err), http.StatusBadRequest) + wfe.sendError(response, fmt.Sprintf("Unable to read/verify body: %v", err), http.StatusBadRequest) return } var init core.Registration err = json.Unmarshal(body, &init) if err != nil { - sendError(response, "Error unmarshaling JSON", http.StatusBadRequest) + wfe.sendError(response, "Error unmarshaling JSON", http.StatusBadRequest) return } reg, err := wfe.RA.NewRegistration(init, key) if err != nil { - sendError(response, + wfe.sendError(response, fmt.Sprintf("Error creating new registration: %+v", err), http.StatusInternalServerError) return @@ -173,7 +174,7 @@ func (wfe *WebFrontEndImpl) NewRegistration(response http.ResponseWriter, reques reg.ID = "" responseBody, err := json.Marshal(reg) if err != nil { - sendError(response, "Error marshaling authz", http.StatusInternalServerError) + wfe.sendError(response, "Error marshaling authz", http.StatusInternalServerError) return } @@ -193,26 +194,26 @@ func (wfe *WebFrontEndImpl) NewRegistration(response http.ResponseWriter, reques func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, request *http.Request) { if request.Method != "POST" { - sendError(response, "Method not allowed", http.StatusMethodNotAllowed) + wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed) return } body, key, err := verifyPOST(request) if err != nil { - sendError(response, "Unable to read/verify body", http.StatusBadRequest) + wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest) return } var init core.Authorization if err = json.Unmarshal(body, &init); err != nil { - sendError(response, "Error unmarshaling JSON", http.StatusBadRequest) + wfe.sendError(response, "Error unmarshaling JSON", http.StatusBadRequest) return } // Create new authz and return authz, err := wfe.RA.NewAuthorization(init, key) if err != nil { - sendError(response, + wfe.sendError(response, fmt.Sprintf("Error creating new authz: %+v", err), http.StatusInternalServerError) return @@ -223,7 +224,7 @@ func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, reque authz.ID = "" responseBody, err := json.Marshal(authz) if err != nil { - sendError(response, "Error marshaling authz", http.StatusInternalServerError) + wfe.sendError(response, "Error marshaling authz", http.StatusInternalServerError) return } @@ -240,20 +241,20 @@ func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, reque func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request *http.Request) { if request.Method != "POST" { - sendError(response, "Method not allowed", http.StatusMethodNotAllowed) + wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed) return } body, key, err := verifyPOST(request) if err != nil { - sendError(response, "Unable to read/verify body", http.StatusBadRequest) + wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest) return } var init core.CertificateRequest if err = json.Unmarshal(body, &init); err != nil { fmt.Println(err) - sendError(response, "Error unmarshaling certificate request", http.StatusBadRequest) + wfe.sendError(response, "Error unmarshaling certificate request", http.StatusBadRequest) return } @@ -268,7 +269,7 @@ func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request // RA for secondary validation. cert, err := wfe.RA.NewCertificate(init, key) if err != nil { - sendError(response, + wfe.sendError(response, fmt.Sprintf("Error creating new cert: %+v", err), http.StatusBadRequest) return @@ -307,7 +308,7 @@ func (wfe *WebFrontEndImpl) Challenge(authz core.Authorization, response http.Re } if !found { - sendError(response, + wfe.sendError(response, fmt.Sprintf("Unable to find challenge"), http.StatusNotFound) return @@ -315,38 +316,38 @@ func (wfe *WebFrontEndImpl) Challenge(authz core.Authorization, response http.Re switch request.Method { default: - sendError(response, "Method not allowed", http.StatusMethodNotAllowed) + wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed) return case "POST": body, key, err := verifyPOST(request) if err != nil { - sendError(response, "Unable to read/verify body", http.StatusBadRequest) + wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest) return } var challengeResponse core.Challenge if err = json.Unmarshal(body, &challengeResponse); err != nil { - sendError(response, "Error unmarshaling authorization", http.StatusBadRequest) + wfe.sendError(response, "Error unmarshaling authorization", http.StatusBadRequest) return } // Check that the signing key is the right key if !key.Equals(authz.Key) { - sendError(response, "Signing key does not match key in authorization", http.StatusForbidden) + wfe.sendError(response, "Signing key does not match key in authorization", http.StatusForbidden) return } // Ask the RA to update this authorization updatedAuthz, err := wfe.RA.UpdateAuthorization(authz, challengeIndex, challengeResponse) if err != nil { - sendError(response, "Unable to update authorization", http.StatusInternalServerError) + wfe.sendError(response, "Unable to update authorization", http.StatusInternalServerError) return } jsonReply, err := json.Marshal(updatedAuthz) if err != nil { - sendError(response, "Failed to marshal authz", http.StatusInternalServerError) + wfe.sendError(response, "Failed to marshal authz", http.StatusInternalServerError) return } response.Header().Set("Content-Type", "application/json") @@ -363,7 +364,7 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request * id := parseIDFromPath(request.URL.Path) reg, err := wfe.SA.GetRegistration(id) if err != nil { - sendError(response, + wfe.sendError(response, fmt.Sprintf("Unable to find registration: %+v", err), http.StatusNotFound) return @@ -372,13 +373,13 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request * switch request.Method { default: - sendError(response, "Method not allowed", http.StatusMethodNotAllowed) + wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed) return case "GET": jsonReply, err := json.Marshal(reg) if err != nil { - sendError(response, "Failed to marshal authz", http.StatusInternalServerError) + wfe.sendError(response, "Failed to marshal authz", http.StatusInternalServerError) return } response.Header().Set("Content-Type", "application/json") @@ -388,20 +389,20 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request * case "POST": body, key, err := verifyPOST(request) if err != nil { - sendError(response, "Unable to read/verify body", http.StatusBadRequest) + wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest) return } var update core.Registration err = json.Unmarshal(body, &update) if err != nil { - sendError(response, "Error unmarshaling registration", http.StatusBadRequest) + wfe.sendError(response, "Error unmarshaling registration", http.StatusBadRequest) return } // Check that the signing key is the right key if !key.Equals(reg.Key) { - sendError(response, "Signing key does not match key in registration", http.StatusForbidden) + wfe.sendError(response, "Signing key does not match key in registration", http.StatusForbidden) return } @@ -409,13 +410,13 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request * updatedReg, err := wfe.RA.UpdateRegistration(reg, update) if err != nil { fmt.Println(err) - sendError(response, "Unable to update registration", http.StatusInternalServerError) + wfe.sendError(response, "Unable to update registration", http.StatusInternalServerError) return } jsonReply, err := json.Marshal(updatedReg) if err != nil { - sendError(response, "Failed to marshal authz", http.StatusInternalServerError) + wfe.sendError(response, "Failed to marshal authz", http.StatusInternalServerError) return } response.Header().Set("Content-Type", "application/json") @@ -430,7 +431,7 @@ func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request id := parseIDFromPath(request.URL.Path) authz, err := wfe.SA.GetAuthorization(id) if err != nil { - sendError(response, + wfe.sendError(response, fmt.Sprintf("Unable to find authorization: %+v", err), http.StatusNotFound) return @@ -444,13 +445,13 @@ func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request switch request.Method { default: - sendError(response, "Method not allowed", http.StatusMethodNotAllowed) + wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed) return case "GET": jsonReply, err := json.Marshal(authz) if err != nil { - sendError(response, "Failed to marshal authz", http.StatusInternalServerError) + wfe.sendError(response, "Failed to marshal authz", http.StatusInternalServerError) return } response.Header().Set("Content-Type", "application/json") @@ -463,34 +464,34 @@ func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request var allHex = regexp.MustCompile("^[0-9a-f]+$") -func notFound(response http.ResponseWriter) { - sendError(response, "Not found", http.StatusNotFound) +func (wfe *WebFrontEndImpl) notFound(response http.ResponseWriter) { + wfe.sendError(response, "Not found", http.StatusNotFound) } func (wfe *WebFrontEndImpl) Certificate(response http.ResponseWriter, request *http.Request) { path := request.URL.Path switch request.Method { default: - sendError(response, "Method not allowed", http.StatusMethodNotAllowed) + wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed) return case "GET": // Certificate paths consist of the CertBase path, plus exactly sixteen hex // digits. if !strings.HasPrefix(path, wfe.CertPath) { - notFound(response) + wfe.notFound(response) return } serial := path[len(wfe.CertPath):] if len(serial) != 16 || !allHex.Match([]byte(serial)) { - notFound(response) + wfe.notFound(response) return } wfe.log.Notice(fmt.Sprintf("Requested certificate ID %s", serial)) cert, err := wfe.SA.GetCertificate(serial) if err != nil { - notFound(response) + wfe.notFound(response) return }