// Valid revocation request for existing, non-revoked cert func TestRevokeCertificate(t *testing.T) { keyPemBytes, err := ioutil.ReadFile("test/238.key") test.AssertNotError(t, err, "Failed to load key") key, err := jose.LoadPrivateKey(keyPemBytes) test.AssertNotError(t, err, "Failed to load key") rsaKey, ok := key.(*rsa.PrivateKey) test.Assert(t, ok, "Couldn't load RSA key") signer, err := jose.NewSigner("RS256", rsaKey) test.AssertNotError(t, err, "Failed to make signer") certPemBytes, err := ioutil.ReadFile("test/238.crt") test.AssertNotError(t, err, "Failed to load cert") certBlock, _ := pem.Decode(certPemBytes) test.Assert(t, certBlock != nil, "Failed to decode PEM") var revokeRequest struct { CertificateDER core.JSONBuffer `json:"certificate"` } revokeRequest.CertificateDER = certBlock.Bytes revokeRequestJSON, err := json.Marshal(revokeRequest) test.AssertNotError(t, err, "Failed to marshal request") // POST, Properly JWS-signed, but payload is "foo", not base64-encoded JSON. wfe := setupWFE(t) wfe.RA = &MockRegistrationAuthority{} wfe.SA = &MockSA{} wfe.Stats, _ = statsd.NewNoopClient() wfe.SubscriberAgreementURL = agreementURL responseWriter := httptest.NewRecorder() responseWriter.Body.Reset() nonce, err := wfe.nonceService.Nonce() test.AssertNotError(t, err, "Unable to create nonce") result, _ := signer.Sign(revokeRequestJSON, nonce) wfe.RevokeCertificate(responseWriter, &http.Request{ Method: "POST", Body: makeBody(result.FullSerialize()), }) test.AssertEquals(t, responseWriter.Code, 200) test.AssertEquals(t, responseWriter.Body.String(), "") // Try the revoke request again, signed by account key associated with cert. // Should also succeed. responseWriter.Body.Reset() test1JWK, err := jose.LoadPrivateKey([]byte(test1KeyPrivatePEM)) test.AssertNotError(t, err, "Failed to load key") test1Key, ok := test1JWK.(*rsa.PrivateKey) test.Assert(t, ok, "Couldn't load RSA key") accountKeySigner, err := jose.NewSigner("RS256", test1Key) test.AssertNotError(t, err, "Failed to make signer") nonce, err = wfe.nonceService.Nonce() test.AssertNotError(t, err, "Unable to create nonce") result, _ = accountKeySigner.Sign(revokeRequestJSON, nonce) wfe.RevokeCertificate(responseWriter, &http.Request{ Method: "POST", Body: makeBody(result.FullSerialize()), }) test.AssertEquals(t, responseWriter.Code, 200) test.AssertEquals(t, responseWriter.Body.String(), "") }
// Valid revocation request for already-revoked cert func TestRevokeCertificateAlreadyRevoked(t *testing.T) { keyPemBytes, err := ioutil.ReadFile("test/178.key") test.AssertNotError(t, err, "Failed to load key") key, err := jose.LoadPrivateKey(keyPemBytes) test.AssertNotError(t, err, "Failed to load key") rsaKey, ok := key.(*rsa.PrivateKey) test.Assert(t, ok, "Couldn't load RSA key") signer, err := jose.NewSigner("RS256", rsaKey) test.AssertNotError(t, err, "Failed to make signer") certPemBytes, err := ioutil.ReadFile("test/178.crt") test.AssertNotError(t, err, "Failed to load cert") certBlock, _ := pem.Decode(certPemBytes) test.Assert(t, certBlock != nil, "Failed to decode PEM") var revokeRequest struct { CertificateDER core.JSONBuffer `json:"certificate"` } revokeRequest.CertificateDER = certBlock.Bytes revokeRequestJSON, err := json.Marshal(revokeRequest) test.AssertNotError(t, err, "Failed to marshal request") // POST, Properly JWS-signed, but payload is "foo", not base64-encoded JSON. wfe := setupWFE(t) wfe.RA = &MockRegistrationAuthority{} wfe.SA = &MockSA{} wfe.Stats, _ = statsd.NewNoopClient() wfe.SubscriberAgreementURL = agreementURL responseWriter := httptest.NewRecorder() responseWriter.Body.Reset() nonce, err := wfe.nonceService.Nonce() test.AssertNotError(t, err, "Unable to create nonce") result, _ := signer.Sign(revokeRequestJSON, nonce) wfe.RevokeCertificate(responseWriter, &http.Request{ Method: "POST", Body: makeBody(result.FullSerialize()), }) test.AssertEquals(t, responseWriter.Code, 409) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Certificate already revoked\"}") }
func TestRegistration(t *testing.T) { wfe := setupWFE(t) wfe.RA = &MockRegistrationAuthority{} wfe.SA = &MockSA{} wfe.Stats, _ = statsd.NewNoopClient() wfe.SubscriberAgreementURL = agreementURL responseWriter := httptest.NewRecorder() // Test invalid method path, _ := url.Parse("/1") wfe.Registration(responseWriter, &http.Request{ Method: "MAKE-COFFEE", Body: makeBody("invalid"), URL: path, }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Method not allowed\"}") responseWriter.Body.Reset() // Test GET proper entry returns 405 path, _ = url.Parse("/1") wfe.Registration(responseWriter, &http.Request{ Method: "GET", URL: path, }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Method not allowed\"}") responseWriter.Body.Reset() // Test POST invalid JSON path, _ = url.Parse("/2") wfe.Registration(responseWriter, &http.Request{ Method: "POST", Body: makeBody("invalid"), URL: path, }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Unable to read/verify body\"}") responseWriter.Body.Reset() key, err := jose.LoadPrivateKey([]byte(test2KeyPrivatePEM)) test.AssertNotError(t, err, "Failed to load key") rsaKey, ok := key.(*rsa.PrivateKey) test.Assert(t, ok, "Couldn't load RSA key") signer, err := jose.NewSigner("RS256", rsaKey) test.AssertNotError(t, err, "Failed to make signer") // Test POST valid JSON but key is not registered nonce, err := wfe.nonceService.Nonce() test.AssertNotError(t, err, "Unable to create nonce") result, err := signer.Sign([]byte("{\"agreement\":\""+agreementURL+"\"}"), nonce) path, _ = url.Parse("/2") wfe.Registration(responseWriter, &http.Request{ Method: "POST", Body: makeBody(result.FullSerialize()), URL: path, }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:unauthorized\",\"detail\":\"No registration exists matching provided key\"}") responseWriter.Body.Reset() key, err = jose.LoadPrivateKey([]byte(test1KeyPrivatePEM)) test.AssertNotError(t, err, "Failed to load key") rsaKey, ok = key.(*rsa.PrivateKey) test.Assert(t, ok, "Couldn't load RSA key") signer, err = jose.NewSigner("RS256", rsaKey) test.AssertNotError(t, err, "Failed to make signer") path, _ = url.Parse("/2") // Test POST valid JSON with registration up in the mock (with incorrect agreement URL) nonce, err = wfe.nonceService.Nonce() test.AssertNotError(t, err, "Unable to create nonce") result, err = signer.Sign([]byte("{\"agreement\":\"https://letsencrypt.org/im-bad\"}"), nonce) // 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()), URL: path, }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Provided agreement URL [https://letsencrypt.org/im-bad] does not match current agreement URL ["+agreementURL+"]\"}") responseWriter.Body.Reset() // Test POST valid JSON with registration up in the mock (with correct agreement URL) nonce, err = wfe.nonceService.Nonce() test.AssertNotError(t, err, "Unable to create nonce") result, err = signer.Sign([]byte("{\"agreement\":\""+agreementURL+"\"}"), nonce) wfe.Registration(responseWriter, &http.Request{ Method: "POST", Body: makeBody(result.FullSerialize()), URL: path, }) test.AssertNotContains(t, responseWriter.Body.String(), "urn:acme:error") responseWriter.Body.Reset() }
func TestNewRegistration(t *testing.T) { wfe := setupWFE(t) wfe.RA = &MockRegistrationAuthority{} wfe.SA = &MockSA{} wfe.Stats, _ = statsd.NewNoopClient() wfe.SubscriberAgreementURL = agreementURL responseWriter := httptest.NewRecorder() // GET instead of POST should be rejected wfe.NewRegistration(responseWriter, &http.Request{ Method: "GET", }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Method not allowed\"}") // POST, but no body. responseWriter.Body.Reset() wfe.NewRegistration(responseWriter, &http.Request{ Method: "POST", }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Unable to read/verify body\"}") // POST, but body that isn't valid JWS responseWriter.Body.Reset() wfe.NewRegistration(responseWriter, &http.Request{ Method: "POST", Body: makeBody("hi"), }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Unable to read/verify body\"}") key, err := jose.LoadPrivateKey([]byte(test2KeyPrivatePEM)) test.AssertNotError(t, err, "Failed to load key") rsaKey, ok := key.(*rsa.PrivateKey) test.Assert(t, ok, "Couldn't load RSA key") signer, err := jose.NewSigner("RS256", rsaKey) test.AssertNotError(t, err, "Failed to make signer") // POST, Properly JWS-signed, but payload is "foo", not base64-encoded JSON. responseWriter.Body.Reset() nonce, err := wfe.nonceService.Nonce() test.AssertNotError(t, err, "Unable to create nonce") result, err := signer.Sign([]byte("foo"), nonce) wfe.NewRegistration(responseWriter, &http.Request{ Method: "POST", Body: makeBody(result.FullSerialize()), }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Error unmarshaling JSON\"}") // Same signed body, but payload modified by one byte, breaking signature. // should fail JWS verification. responseWriter.Body.Reset() wfe.NewRegistration(responseWriter, &http.Request{ Method: "POST", Body: makeBody(` { "header": { "alg": "RS256", "jwk": { "e": "AQAB", "kty": "RSA", "n": "vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw" } }, "payload": "xm9vCg", "signature": "RjUQ679fxJgeAJlxqgvDP_sfGZnJ-1RgWF2qmcbnBWljs6h1qp63pLnJOl13u81bP_bCSjaWkelGG8Ymx_X-aQ" } `), }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Unable to read/verify body\"}") responseWriter.Body.Reset() nonce, err = wfe.nonceService.Nonce() test.AssertNotError(t, err, "Unable to create nonce") result, err = signer.Sign( []byte("{\"contact\":[\"tel:123456789\"],\"agreement\":\"https://letsencrypt.org/im-bad\"}"), nonce) wfe.NewRegistration(responseWriter, &http.Request{ Method: "POST", Body: makeBody(result.FullSerialize()), }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Provided agreement URL [https://letsencrypt.org/im-bad] does not match current agreement URL ["+agreementURL+"]\"}") responseWriter.Body.Reset() nonce, err = wfe.nonceService.Nonce() test.AssertNotError(t, err, "Unable to create nonce") result, err = signer.Sign([]byte("{\"contact\":[\"tel:123456789\"],\"agreement\":\""+agreementURL+"\"}"), nonce) wfe.NewRegistration(responseWriter, &http.Request{ Method: "POST", Body: makeBody(result.FullSerialize()), }) test.AssertEquals(t, responseWriter.Body.String(), `{"id":0,"key":{"kty":"RSA","n":"qnARLrT7Xz4gRcKyLdydmCr-ey9OuPImX4X40thk3on26FkMznR3fRjs66eLK7mmPcBZ6uOJseURU6wAaZNmemoYx1dMvqvWWIyiQleHSD7Q8vBrhR6uIoO4jAzJZR-ChzZuSDt7iHN-3xUVspu5XGwXU_MVJZshTwp4TaFx5elHIT_ObnTvTOU3Xhish07AbgZKmWsVbXh5s-CrIicU4OexJPgunWZ_YJJueOKmTvnLlTV4MzKR2oZlBKZ27S0-SfdV_QDx_ydle5oMAyKVtlAV35cyPMIsYNwgUGBCdY_2Uzi5eX0lTc7MPRwz6qR1kip-i59VcGcUQgqHV6Fyqw","e":"AAEAAQ"},"recoveryToken":"","contact":["tel:123456789"],"agreement":"http://example.invalid/terms"}`) var reg core.Registration err = json.Unmarshal([]byte(responseWriter.Body.String()), ®) test.AssertNotError(t, err, "Couldn't unmarshal returned registration object") test.Assert(t, len(reg.Contact) >= 1, "No contact field in registration") uu := url.URL(reg.Contact[0]) test.AssertEquals(t, uu.String(), "tel:123456789") test.AssertEquals( t, responseWriter.Header().Get("Location"), "/acme/reg/0") test.AssertEquals( t, responseWriter.Header().Get("Link"), "</acme/new-authz>;rel=\"next\"") key, err = jose.LoadPrivateKey([]byte(test1KeyPrivatePEM)) test.AssertNotError(t, err, "Failed to load key") rsaKey, ok = key.(*rsa.PrivateKey) test.Assert(t, ok, "Couldn't load RSA key") signer, err = jose.NewSigner("RS256", rsaKey) test.AssertNotError(t, err, "Failed to make signer") // POST, Valid JSON, Key already in use responseWriter.Body.Reset() nonce, err = wfe.nonceService.Nonce() test.AssertNotError(t, err, "Unable to create nonce") result, err = signer.Sign([]byte("{\"contact\":[\"tel:123456789\"],\"agreement\":\""+agreementURL+"\"}"), nonce) wfe.NewRegistration(responseWriter, &http.Request{ Method: "POST", Body: makeBody(result.FullSerialize()), }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Registration key is already in use\"}") }
func TestRegistration(t *testing.T) { wfe := NewWebFrontEndImpl() wfe.RA = &MockRegistrationAuthority{} wfe.SA = &MockSA{} wfe.Stats, _ = statsd.NewNoopClient() wfe.SubscriberAgreementURL = "https://letsencrypt.org/be-good" responseWriter := httptest.NewRecorder() // Test invalid method path, _ := url.Parse("/1") wfe.Registration(responseWriter, &http.Request{ Method: "MAKE-COFFEE", Body: makeBody("invalid"), URL: path, }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Method not allowed\"}") responseWriter.Body.Reset() // Test GET proper entry returns 405 path, _ = url.Parse("/1") wfe.Registration(responseWriter, &http.Request{ Method: "GET", URL: path, }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Method not allowed\"}") responseWriter.Body.Reset() // Test POST invalid JSON path, _ = url.Parse("/2") wfe.Registration(responseWriter, &http.Request{ Method: "POST", Body: makeBody("invalid"), URL: path, }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Unable to read/verify body\"}") responseWriter.Body.Reset() // Test POST valid JSON but key is not registered path, _ = url.Parse("/2") wfe.Registration(responseWriter, &http.Request{ Method: "POST", Body: makeBody(`{ "payload" : "ewogICJjb250YWN0IjogWwogICAgIm1haWx0bzpjZXJ0LWFkbWluQGV4YW1wbGUuY28ubnoiLAogICAgInRlbDorMjQ5NTU1MTIxMiIKICBdLAogICJhZ3JlZW1lbnQiOiAieWVzIgp9Cg", "protected" : "eyJhbGciOiJQUzI1NiIsImp3ayI6eyJrdHkiOiJSU0EiLCJuIjoibTVDcHgzdlowQ2pBVGlyRHBiSUx2cTc4Zm0zRHY1UkJrTzFWTFdGbUpqNU1iNTR2YzlvWVpXYzFWMWstTEpvRVN1dVBIaGFOTzJFdThUOXRzbFFXY1pTenI1TklteEF3TWs5NzBnVlFhLUhxdi1KcjZ4c3RyQnBxN1RLcFhIVHgyRm5mQTJ3UXJmSVFTbEJYdTB0NGpkVU9yM29KaC1RWHZtYThuTElUZHRqcEMwQVpOdHFkMFFrUkpYXzkwU2FOcmwxOFJyXzBKckJIOVptVVNGY2YzbW9fQnRMMEd4MGpFM24taXdDSThyUXRmeVZQX185LW5fX3I0SWhhbEtMemFlaW82by1xcmRlbWgwRVpnaktHQ1MxX1JwVEllQXJrTzh1aWExS2dPcS16LUdmZW1LRW00czA3V09fYTBfOWRMcWJ2cG55eVp2VWk0MDVtM3ZHRGZRIiwiZSI6IkFBRUFBUSJ9fQ", "signature" : "exg0HJRHk-oSDiaOlgtTkT_COqDRyIAJr4g9fDAJh5GF5evXAfT0Hbkfy4TYzqvF6oOldIaCylYhXjYtve4JLXEMdAj1DaR7kGVALskLg-XbiZ0-IaFBiDDaT6mwyLBTfstX4DD2OL7x0vyuTK16bHEIF0hncwHYVSoX5eFOBQLVu_gjxc7J5OZK4ugSJxZEilTVta0A9EdXdUxth0qqbZg_hJDmGOyNge03C71GbhMs-DF-rujlhe7L4VhcV3U0Wj8kSuAGn_DIHBJ1zM0H46PRgyz_9DgkJ6XnE5W8ZA3kF0VPFSp4ofqBhkFUXLXPPJJUEurAQxBJMaU31ef8bg" }`), URL: path, }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:unauthorized\",\"detail\":\"No registration exists matching provided key\"}") responseWriter.Body.Reset() key, err := jose.LoadPrivateKey([]byte(test1KeyPrivatePEM)) test.AssertNotError(t, err, "Failed to load key") rsaKey, ok := key.(*rsa.PrivateKey) test.Assert(t, ok, "Couldn't load RSA key") signer, err := jose.NewSigner("RS256", rsaKey) test.AssertNotError(t, err, "Failed to make signer") path, _ = url.Parse("/2") // 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()), URL: path, }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Provided agreement URL [https://letsencrypt.org/im-bad] does not match current agreement URL [https://letsencrypt.org/be-good]\"}") responseWriter.Body.Reset() // Test POST valid JSON with registration up in the mock (with correct agreement URL) result, err = signer.Sign([]byte("{\"agreement\":\"https://letsencrypt.org/be-good\"}")) wfe.Registration(responseWriter, &http.Request{ Method: "POST", Body: makeBody(result.FullSerialize()), URL: path, }) test.AssertNotContains(t, responseWriter.Body.String(), "urn:acme:error") responseWriter.Body.Reset() }