Merge upstream/master

This commit is contained in:
Roland Shoemaker 2015-05-20 13:03:43 -07:00
commit 74ecad349b
8 changed files with 102 additions and 117 deletions

View File

@ -96,11 +96,9 @@ func NewCertificateAuthorityImpl(cadb core.CertificateAuthorityDatabase, config
return nil, err
}
// In test mode, load a private key from a file. In production, use an HSM.
if !config.TestMode {
err = errors.New("OCSP signing with a PKCS#11 key not yet implemented.")
return nil, err
}
// In test mode, load a private key from a file.
// TODO: This should rely on the CFSSL config, to make it easy to use a key
// from a file vs an HSM. https://github.com/letsencrypt/boulder/issues/163
issuerKey, err := loadIssuerKey(config.IssuerKey)
if err != nil {
return nil, err

View File

@ -352,13 +352,6 @@ func TestFailNoSerial(t *testing.T) {
test.AssertError(t, err, "CA should have failed with no SerialPrefix")
}
func TestFailNoTestMode(t *testing.T) {
cadb, _, caConfig := setup(t)
caConfig.TestMode = false
_, err := NewCertificateAuthorityImpl(cadb, caConfig)
test.AssertError(t, err, "CA should have failed with TestMode = false, but key provided")
}
func TestRevoke(t *testing.T) {
cadb, storageAuthority, caConfig := setup(t)
ca, err := NewCertificateAuthorityImpl(cadb, caConfig)

View File

@ -77,15 +77,16 @@ func (ra *RegistrationAuthorityImpl) NewRegistration(init core.Registration, key
}
func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization, regID int64) (authz core.Authorization, err error) {
if regID == 0 {
err = fmt.Errorf("Registration ID cannot be 0")
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
return authz, err
}
// Create validations
@ -93,7 +94,7 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
challenges, combinations := ra.PA.ChallengesFor(identifier)
authID, err := ra.SA.NewPendingAuthorization()
if err != nil {
return
return authz, err
}
for i := range challenges {
// Ignoring these errors because we construct the URLs to be correct
@ -102,7 +103,7 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
if !challenges[i].IsSane(false) {
err = fmt.Errorf("Challenge didn't pass sanity check: %+v", challenges[i])
return
return authz, err
}
}
@ -118,7 +119,7 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
// Store the authorization object, then return it
err = ra.SA.UpdatePendingAuthorization(authz)
return
return authz, err
}
func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest, regID int64) (core.Certificate, error) {
@ -150,6 +151,11 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest,
ra.log.Audit(fmt.Sprintf("Certificate request %s - %s", logEventResult, string(jsonLogEvent)))
}()
if regID <= 0 {
err = fmt.Errorf("Invalid registration ID")
return emptyCert, err
}
// Verify the CSR
// TODO: Verify that other aspects of the CSR are appropriate
csr := req.CSR

View File

@ -154,6 +154,9 @@ func assertAuthzEqual(t *testing.T, a1, a2 core.Authorization) {
func TestNewAuthorization(t *testing.T) {
_, _, sa, ra := initAuthorities(t)
_, err := ra.NewAuthorization(AuthzRequest, 0)
test.AssertError(t, err, "Authorization cannot have registrationID == 0")
authz, err := ra.NewAuthorization(AuthzRequest, 1)
test.AssertNotError(t, err, "NewAuthorization failed")

View File

@ -56,6 +56,9 @@ func TestAddRegistration(t *testing.T) {
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))
@ -74,11 +77,15 @@ func TestAddRegistration(t *testing.T) {
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 update registration by key")
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 TestAddAuthorization(t *testing.T) {

View File

@ -132,12 +132,17 @@ function parseLink(link) {
}
function post(url, body, callback) {
var jws = crypto.generateSignature(state.accountPrivateKey, new Buffer(JSON.stringify(body)));
var payload = JSON.stringify(jws);
var payload = JSON.stringify(body, null, 2);
var jws = crypto.generateSignature(state.accountPrivateKey, new Buffer(payload));
var signed = JSON.stringify(jws, null, 2);
var req = request.post(url, callback);
console.log('Posting to', url, ':\n', payload);
req.write(payload)
console.log('Posting to', url, ':\n', signed);
console.log('Payload:', payload);
req.on('response', function(response) {
console.log(response.headers)
})
req.write(signed)
req.end();
return req;
}
@ -276,13 +281,13 @@ function sendAgreement(answers) {
post(state.registrationURL, state.registration,
function(err, resp, body) {
if (err || Math.floor(resp.statusCode / 100) != 2) {
console.log("Couldn't POST agreement back to server, aborting.");
console.log("error: " + err);
console.log(body);
console.log("error: " + err);
console.log("Couldn't POST agreement back to server, aborting.");
process.exit(1);
} else {
inquirer.prompt(questions.domain, getChallenges);
}
inquirer.prompt(questions.domain, getChallenges);
});
}

View File

@ -275,7 +275,7 @@ func (wfe *WebFrontEndImpl) NewRegistration(response http.ResponseWriter, reques
return
}
regURL := wfe.RegBase + string(reg.ID)
regURL := fmt.Sprintf("%s%d", wfe.RegBase, reg.ID)
responseBody, err := json.Marshal(reg)
if err != nil {
wfe.sendError(response, "Error marshaling authz", err, http.StatusInternalServerError)
@ -485,7 +485,7 @@ func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request
// TODO The spec says a client should send an Accept: application/pkix-cert
// header; either explicitly insist or tolerate
response.Header().Add("Location", certURL)
response.Header().Add("Link", link(wfe.IssuerPath, "up"))
response.Header().Add("Link", link(wfe.BaseURL+wfe.IssuerPath, "up"))
response.Header().Set("Content-Type", "application/pkix-cert")
response.WriteHeader(http.StatusCreated)
if _, err = response.Write(cert.DER); err != nil {
@ -577,6 +577,24 @@ func (wfe *WebFrontEndImpl) Challenge(authz core.Authorization, response http.Re
}
func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *http.Request) {
if request.Method != "POST" {
wfe.sendError(response, "Method not allowed", request.Method, http.StatusMethodNotAllowed)
return
}
body, _, currReg, err := wfe.verifyPOST(request, true)
if err != nil {
if err == sql.ErrNoRows {
wfe.sendError(response,
"No registration exists matching provided key",
err, http.StatusForbidden)
} else {
wfe.sendError(response,
"Unable to read/verify body", err, http.StatusBadRequest)
}
return
}
// Requests to this handler should have a path that leads to a known
// registration
idStr := parseIDFromPath(request.URL.Path)
@ -587,71 +605,43 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *
} else if id <= 0 {
wfe.sendError(response, "Registration ID must be a positive non-zero integer", id, http.StatusBadRequest)
return
} else if id != currReg.ID {
wfe.sendError(response, "Request signing key did not match registration key", "", http.StatusForbidden)
return
}
reg, err := wfe.SA.GetRegistration(id)
var update core.Registration
err = json.Unmarshal(body, &update)
if err != nil {
wfe.sendError(response,
"Unable to find registration", err,
http.StatusNotFound)
wfe.sendError(response, "Error unmarshaling registration", err, http.StatusBadRequest)
return
}
reg.ID = id
switch request.Method {
default:
wfe.sendError(response, "Method not allowed", "", http.StatusMethodNotAllowed)
if len(update.Agreement) > 0 && update.Agreement != wfe.SubscriberAgreementURL {
wfe.sendError(response, fmt.Sprintf("Provided agreement URL [%s] does not match current agreement URL [%s]", update.Agreement, wfe.SubscriberAgreementURL), nil, http.StatusBadRequest)
return
case "GET":
jsonReply, err := json.Marshal(reg)
if err != nil {
wfe.sendError(response, "Failed to marshal authz", err, http.StatusInternalServerError)
return
}
response.Header().Set("Content-Type", "application/json")
response.WriteHeader(http.StatusOK)
response.Write(jsonReply)
case "POST":
body, _, currReg, err := wfe.verifyPOST(request, true)
if err != nil {
if err == sql.ErrNoRows {
wfe.sendError(response, "No registration exists matching provided key", err, http.StatusForbidden)
} else {
wfe.sendError(response, "Unable to read/verify body", err, http.StatusBadRequest)
}
return
}
var update core.Registration
err = json.Unmarshal(body, &update)
if err != nil {
wfe.sendError(response, "Error unmarshaling registration", err, http.StatusBadRequest)
return
}
if len(update.Agreement) > 0 && update.Agreement != wfe.SubscriberAgreementURL {
wfe.sendError(response, fmt.Sprintf("Provided agreement URL [%s] does not match current agreement URL [%s]", update.Agreement, wfe.SubscriberAgreementURL), nil, http.StatusBadRequest)
return
}
// Ask the RA to update this authorization
updatedReg, err := wfe.RA.UpdateRegistration(currReg, update)
if err != nil {
wfe.sendError(response, "Unable to update registration", err, http.StatusInternalServerError)
return
}
jsonReply, err := json.Marshal(updatedReg)
if err != nil {
wfe.sendError(response, "Failed to marshal authz", err, http.StatusInternalServerError)
return
}
response.Header().Set("Content-Type", "application/json")
response.WriteHeader(http.StatusAccepted)
response.Write(jsonReply)
}
// MergeUpdate copies over only the fields that a client is allowed to modify.
// Note: The RA will also use MergeUpdate to filter out non-updateable fields,
// but we do it here too, so that/ input filtering happens as early in the
// request processing as possible.
currReg.MergeUpdate(update)
// Ask the RA to update this authorization.
updatedReg, err := wfe.RA.UpdateRegistration(currReg, currReg)
if err != nil {
wfe.sendError(response, "Unable to update registration", err, http.StatusInternalServerError)
return
}
jsonReply, err := json.Marshal(updatedReg)
if err != nil {
wfe.sendError(response, "Failed to marshal authz", err, http.StatusInternalServerError)
return
}
response.Header().Set("Content-Type", "application/json")
response.WriteHeader(http.StatusAccepted)
response.Write(jsonReply)
}
func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request *http.Request) {

View File

@ -92,7 +92,7 @@ func (sa *MockSA) GetRegistration(id int64) (core.Registration, error) {
var parsedKey jose.JsonWebKey
parsedKey.UnmarshalJSON(keyJSON)
return core.Registration{Key: parsedKey, Agreement: "yup"}, nil
return core.Registration{ID: id, Key: parsedKey, Agreement: "yup"}, nil
}
func (sa *MockSA) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration, error) {
@ -102,16 +102,16 @@ func (sa *MockSA) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration,
test2KeyPublic.UnmarshalJSON([]byte(test2KeyPublicJSON))
if core.KeyDigestEquals(jwk, test1KeyPublic) {
return core.Registration{Key: jwk}, nil
return core.Registration{ID: 1, Key: jwk}, nil
}
if core.KeyDigestEquals(jwk, test2KeyPublic) {
// No key found
return core.Registration{}, sql.ErrNoRows
return core.Registration{ID: 2}, sql.ErrNoRows
}
// Return a fake registration
return core.Registration{Agreement: "yup"}, nil
return core.Registration{ID: 1, Agreement: "yup"}, nil
}
func (sa *MockSA) GetAuthorization(string) (core.Authorization, error) {
@ -374,7 +374,7 @@ func TestChallenge(t *testing.T) {
URI: core.AcmeURL(*challengeURL),
},
},
RegistrationID: 0,
RegistrationID: 1,
}
wfe.Challenge(authz, responseWriter, &http.Request{
@ -614,35 +614,15 @@ func TestRegistration(t *testing.T) {
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Method not allowed\"}")
responseWriter.Body.Reset()
// Test GET missing entry
path, _ = url.Parse("/100")
wfe.Registration(responseWriter, &http.Request{
Method: "GET",
URL: path,
})
test.AssertEquals(t,
responseWriter.Body.String(),
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Unable to find registration\"}")
responseWriter.Body.Reset()
// Test GET malformed entry
path, _ = url.Parse("/101")
wfe.Registration(responseWriter, &http.Request{
Method: "GET",
URL: path,
})
test.AssertEquals(t,
responseWriter.Body.String(),
"{\"type\":\"urn:acme:error:serverInternal\",\"detail\":\"Failed to marshal authz\"}")
responseWriter.Body.Reset()
// Test GET proper entry
// Test GET proper entry returns 405
path, _ = url.Parse("/1")
wfe.Registration(responseWriter, &http.Request{
Method: "GET",
URL: path,
})
test.AssertNotContains(t, responseWriter.Body.String(), "urn:acme:error")
test.AssertEquals(t,
responseWriter.Body.String(),
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Method not allowed\"}")
responseWriter.Body.Reset()
// Test POST invalid JSON
@ -658,7 +638,7 @@ func TestRegistration(t *testing.T) {
responseWriter.Body.Reset()
// Test POST valid JSON but key is not registered
path, _ = url.Parse("/1")
path, _ = url.Parse("/2")
wfe.Registration(responseWriter, &http.Request{
Method: "POST",
Body: makeBody(`{
@ -684,6 +664,9 @@ func TestRegistration(t *testing.T) {
// Test POST valid JSON with registration up in the mock (with incorrect agreement URL)
result, err := signer.Sign([]byte("{\"agreement\":\"https://letsencrypt.org/im-bad\"}"))
// Test POST valid JSON with registration up in the mock
path, _ = url.Parse("/1")
wfe.Registration(responseWriter, &http.Request{
Method: "POST",
Body: makeBody(result.FullSerialize()),