// 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(), "") }
func signRequest(t *testing.T, req string, nonceService *core.NonceService) string { accountKeyJSON := []byte(`{"kty":"RSA","n":"z2NsNdHeqAiGdPP8KuxfQXat_uatOK9y12SyGpfKw1sfkizBIsNxERjNDke6Wp9MugN9srN3sr2TDkmQ-gK8lfWo0v1uG_QgzJb1vBdf_hH7aejgETRGLNJZOdaKDsyFnWq1WGJq36zsHcd0qhggTk6zVwqczSxdiWIAZzEakIUZ13KxXvoepYLY0Q-rEEQiuX71e4hvhfeJ4l7m_B-awn22UUVvo3kCqmaRlZT-36vmQhDGoBsoUo1KBEU44jfeK5PbNRk7vDJuH0B7qinr_jczHcvyD-2TtPzKaCioMtNh_VZbPNDaG67sYkQlC15-Ff3HPzKKJW2XvkVG91qMvQ","e":"AQAB","d":"BhAmDbzBAbCeHbU0Xhzi_Ar4M0eTMOEQPnPXMSfW6bc0SRW938JO_-z1scEvFY8qsxV_C0Zr7XHVZsmHz4dc9BVmhiSan36XpuOS85jLWaY073e7dUVN9-l-ak53Ys9f6KZB_v-BmGB51rUKGB70ctWiMJ1C0EzHv0h6Moog-LCd_zo03uuZD5F5wtnPrAB3SEM3vRKeZHzm5eiGxNUsaCEzGDApMYgt6YkQuUlkJwD8Ky2CkAE6lLQSPwddAfPDhsCug-12SkSIKw1EepSHz86ZVfJEnvY-h9jHIdI57mR1v7NTCDcWqy6c6qIzxwh8n2X94QTbtWT3vGQ6HXM5AQ","p":"2uhvZwNS5i-PzeI9vGx89XbdsVmeNjVxjH08V3aRBVY0dzUzwVDYk3z7sqBIj6de53Lx6W1hjmhPIqAwqQgjIKH5Z3uUCinGguKkfGDL3KgLCzYL2UIvZMvTzr9NWLc0AHMZdee5utxWKCGnZBOqy1Rd4V-6QrqjEDBvanoqA60","q":"8odNkMEiriaDKmvwDv-vOOu3LaWbu03yB7VhABu-hK5Xx74bHcvDP2HuCwDGGJY2H-xKdMdUPs0HPwbfHMUicD2vIEUDj6uyrMMZHtbcZ3moh3-WESg3TaEaJ6vhwcWXWG7Wc46G-HbCChkuVenFYYkoi68BAAjloqEUl1JBT1E"}`) var accountKey jose.JsonWebKey err := json.Unmarshal(accountKeyJSON, &accountKey) test.AssertNotError(t, err, "Failed to unmarshal key") signer, err := jose.NewSigner("RS256", &accountKey) test.AssertNotError(t, err, "Failed to make signer") nonce, err := nonceService.Nonce() test.AssertNotError(t, err, "Failed to make nonce") result, err := signer.Sign([]byte(req), nonce) test.AssertNotError(t, err, "Failed to sign req") ret := result.FullSerialize() return ret }
// 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 TestNewRegistration(t *testing.T) { wfe := setupWFE(t) mux, err := wfe.Handler() test.AssertNotError(t, err, "Problem setting up HTTP handlers") wfe.RA = &MockRegistrationAuthority{} wfe.SA = &MockSA{} wfe.Stats, _ = statsd.NewNoopClient() wfe.SubscriberAgreementURL = agreementURL responseWriter := httptest.NewRecorder() // GET instead of POST should be rejected mux.ServeHTTP(responseWriter, &http.Request{ Method: "GET", URL: mustParseURL(NewRegPath), }) 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":"AQAB"},"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") links := responseWriter.Header()["Link"] test.AssertEquals(t, contains(links, "</acme/new-authz>;rel=\"next\""), true) test.AssertEquals(t, contains(links, "<"+agreementURL+">;rel=\"terms-of-service\""), true) 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") // Reset the body and status code responseWriter = httptest.NewRecorder() // POST, Valid JSON, Key already in use 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\"}") test.AssertEquals( t, responseWriter.Header().Get("Location"), "/acme/reg/1") test.AssertEquals(t, responseWriter.Code, 409) }
func TestRegistration(t *testing.T) { wfe := setupWFE(t) mux, err := wfe.Handler() test.AssertNotError(t, err, "Problem setting up HTTP handlers") wfe.RA = &MockRegistrationAuthority{} wfe.SA = &MockSA{} wfe.Stats, _ = statsd.NewNoopClient() wfe.SubscriberAgreementURL = agreementURL responseWriter := httptest.NewRecorder() // Test invalid method mux.ServeHTTP(responseWriter, &http.Request{ Method: "MAKE-COFFEE", URL: mustParseURL(RegPath), Body: makeBody("invalid"), }) test.AssertEquals(t, responseWriter.Body.String(), "{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Method not allowed\"}") responseWriter.Body.Reset() // Test GET proper entry returns 405 mux.ServeHTTP(responseWriter, &http.Request{ Method: "GET", URL: mustParseURL(RegPath), }) 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") links := responseWriter.Header()["Link"] test.AssertEquals(t, contains(links, "</acme/new-authz>;rel=\"next\""), true) test.AssertEquals(t, contains(links, "<"+agreementURL+">;rel=\"terms-of-service\""), true) responseWriter.Body.Reset() }