Fix race condition in revocation integration tests (#6253)
Add a new filter to mail-test-srv, allowing test processes to query for messages sent from a specific address, not just ones sent to a specific address. This fixes a race condition in the revocation integration tests where the number of messages sent to a cert's contact address would be higher than expected because expiration mailer sent a message while the test was running. Also reduce bad-key-revoker's maximum backoff to 2 seconds to ensure that it continues to run frequently during the integration tests, despite usually not having any work to do. While we're here, also improve the comments on various revocation integration tests, remove some unnecessary cruft, and split the tests out to explicitly test functionality with the MozRevocationReasons flag both enabled and disabled. Also, change ocsp_helper's default output from os.Stdout to ioutil.Discard to prevent hundreds of lines of log spam when the integration tests fail during a test that uses that library. Fixes #6248
This commit is contained in:
parent
e7bf6383d8
commit
9ae16edf51
3
ra/ra.go
3
ra/ra.go
|
|
@ -2178,8 +2178,7 @@ func (ra *RegistrationAuthorityImpl) RevokeCertByKey(ctx context.Context, req *r
|
|||
}
|
||||
|
||||
// RevokeCertificateWithReg terminates trust in the certificate provided.
|
||||
// DEPRECATED: use RevokeCertBySubscriber, RevokeCertByController, or
|
||||
// RevokeCertByKey instead.
|
||||
// DEPRECATED: use RevokeCertByApplicant or RevokeCertByKey instead.
|
||||
func (ra *RegistrationAuthorityImpl) RevokeCertificateWithReg(ctx context.Context, req *rapb.RevokeCertificateWithRegRequest) (*emptypb.Empty, error) {
|
||||
if req == nil || req.Cert == nil {
|
||||
return nil, errIncompleteGRPCRequest
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
"server": "localhost",
|
||||
"port": "9380",
|
||||
"username": "cert-manager@example.com",
|
||||
"from": "bad key revoker <test@example.com>",
|
||||
"from": "bad key revoker <bad-key-revoker@test.org>",
|
||||
"passwordFile": "test/secrets/smtp_password",
|
||||
"SMTPTrustedRootFile": "test/mail-test-srv/minica.pem",
|
||||
"emailSubject": "Certificates you've issued have been revoked due to key compromise",
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
"maximumRevocations": 15,
|
||||
"findCertificatesBatchSize": 10,
|
||||
"interval": "1s",
|
||||
"backoffIntervalMax": "60s"
|
||||
"backoffIntervalMax": "2s"
|
||||
},
|
||||
"syslog": {
|
||||
"stdoutlevel": 4,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"server": "localhost",
|
||||
"port": "9380",
|
||||
"username": "cert-manager@example.com",
|
||||
"from": "Expiry bot <test@example.com>",
|
||||
"from": "Expiry bot <expiration-mailer@test.org>",
|
||||
"passwordFile": "test/secrets/smtp_password",
|
||||
"db": {
|
||||
"dbConnectFile": "test/secrets/mailer_dburl",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
"server": "localhost",
|
||||
"port": "9380",
|
||||
"username": "cert-manager@example.com",
|
||||
"from": "bad key revoker <test@example.com>",
|
||||
"from": "bad key revoker <bad-key-revoker@test.org>",
|
||||
"passwordFile": "test/secrets/smtp_password",
|
||||
"SMTPTrustedRootFile": "test/mail-test-srv/minica.pem",
|
||||
"emailSubject": "Certificates you've issued have been revoked due to key compromise",
|
||||
|
|
@ -26,7 +26,8 @@
|
|||
},
|
||||
"maximumRevocations": 15,
|
||||
"findCertificatesBatchSize": 10,
|
||||
"interval": "1s"
|
||||
"interval": "1s",
|
||||
"backoffIntervalMax": "2s"
|
||||
},
|
||||
"syslog": {
|
||||
"stdoutlevel": 4,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"server": "localhost",
|
||||
"port": "9380",
|
||||
"username": "cert-manager@example.com",
|
||||
"from": "Expiry bot <test@example.com>",
|
||||
"from": "Expiry bot <expiration-mailer@test.org>",
|
||||
"passwordFile": "test/secrets/smtp_password",
|
||||
"db": {
|
||||
"dbConnectFile": "test/secrets/mailer_dburl",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
|
@ -51,10 +50,9 @@ func TestOCSPBadSerialPrefix(t *testing.T) {
|
|||
// prefix invalid. This works because ocsp_helper.Req (and the underlying
|
||||
// ocsp.CreateRequest) completely ignore the cert's .Raw value.
|
||||
serialStr := []byte(core.SerialToString(cert.SerialNumber))
|
||||
ocspConfig := ocsp_helper.DefaultConfig.WithOutput(ioutil.Discard)
|
||||
serialStr[0] = serialStr[0] + 1
|
||||
cert.SerialNumber.SetString(string(serialStr), 16)
|
||||
_, err = ocsp_helper.Req(cert, ocspConfig)
|
||||
_, err = ocsp_helper.Req(cert, ocsp_helper.DefaultConfig)
|
||||
if err == nil {
|
||||
t.Fatal("Expected error getting OCSP for request with invalid serial")
|
||||
}
|
||||
|
|
@ -95,7 +93,7 @@ func TestOCSPRejectedPrecertificate(t *testing.T) {
|
|||
t.Fatalf("couldn't find rejected precert for %q", domain)
|
||||
}
|
||||
|
||||
ocspConfig := ocsp_helper.DefaultConfig.WithExpectStatus(ocsp.Good).WithOutput(ioutil.Discard)
|
||||
ocspConfig := ocsp_helper.DefaultConfig.WithExpectStatus(ocsp.Good)
|
||||
_, err = ocsp_helper.ReqDER(cert.Raw, ocspConfig)
|
||||
if err != nil {
|
||||
t.Errorf("requesting OCSP for rejected precertificate: %s", err)
|
||||
|
|
|
|||
|
|
@ -226,10 +226,9 @@ func TestMozRevocation(t *testing.T) {
|
|||
)
|
||||
|
||||
type testCase struct {
|
||||
method authMethod
|
||||
reason int
|
||||
kind certKind
|
||||
expectError bool
|
||||
method authMethod
|
||||
reason int
|
||||
kind certKind
|
||||
}
|
||||
|
||||
var testCases []testCase
|
||||
|
|
@ -240,6 +239,13 @@ func TestMozRevocation(t *testing.T) {
|
|||
method: method,
|
||||
reason: reason,
|
||||
kind: kind,
|
||||
// We do not expect any of these revocation requests to error.
|
||||
// The ones done byAccount will succeed as requested, but will not
|
||||
// result in the key being blocked for future issuance.
|
||||
// The ones done byAuth will succeed, but will be overwritten to have
|
||||
// reason code 5 (cessationOfOperation).
|
||||
// The ones done byKey will succeed, but will be overwritten to have
|
||||
// reason code 1 (keyCompromise), and will block the key.
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -338,8 +344,19 @@ func TestMozRevocation(t *testing.T) {
|
|||
test.AssertNotError(t, err, "revocation should have succeeded")
|
||||
|
||||
// Check the OCSP response for the certificate again. It should now be
|
||||
// revoked.
|
||||
// revoked. If the request was made by demonstrating control over the
|
||||
// names, the reason should be overwritten to CessationOfOperation (5),
|
||||
// and if the request was made by key, then the reason should be set to
|
||||
// KeyCompromise (1).
|
||||
ocspConfig = ocsp_helper.DefaultConfig.WithExpectStatus(ocsp.Revoked)
|
||||
switch tc.method {
|
||||
case byAuth:
|
||||
ocspConfig = ocspConfig.WithExpectReason(ocsp.CessationOfOperation)
|
||||
case byKey:
|
||||
ocspConfig = ocspConfig.WithExpectReason(ocsp.KeyCompromise)
|
||||
default:
|
||||
ocspConfig = ocspConfig.WithExpectReason(tc.reason)
|
||||
}
|
||||
_, err = ocsp_helper.ReqDER(cert.Raw, ocspConfig)
|
||||
test.AssertNotError(t, err, "requesting OCSP for revoked cert")
|
||||
})
|
||||
|
|
@ -541,110 +558,230 @@ func TestDoubleRevocationOn(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRevokeWithKeyCompromise(t *testing.T) {
|
||||
func TestRevokeWithKeyCompromiseBlocksKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
os.Setenv("DIRECTORY", "http://boulder:4001/directory")
|
||||
c, err := makeClient("mailto:example@letsencrypt.org")
|
||||
test.AssertNotError(t, err, "creating acme client")
|
||||
|
||||
certKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
test.AssertNotError(t, err, "failed to generate cert key")
|
||||
|
||||
res, err := authAndIssue(c, certKey, []string{random_domain()})
|
||||
test.AssertNotError(t, err, "authAndIssue failed")
|
||||
|
||||
cert := res.certs[0]
|
||||
|
||||
err = c.RevokeCertificate(
|
||||
acme.Account{},
|
||||
cert,
|
||||
certKey,
|
||||
ocsp.KeyCompromise,
|
||||
type authMethod string
|
||||
var (
|
||||
byAccount authMethod = "byAccount"
|
||||
byKey authMethod = "byKey"
|
||||
)
|
||||
test.AssertNotError(t, err, "failed to revoke certificate")
|
||||
|
||||
// attempt to create a new account using the blocklisted key
|
||||
_, err = c.NewAccount(certKey, false, true)
|
||||
test.AssertError(t, err, "NewAccount didn't fail with a blocklisted key")
|
||||
test.AssertEquals(t, err.Error(), `acme: error code 400 "urn:ietf:params:acme:error:badPublicKey": public key is forbidden`)
|
||||
// If the MozRevocationReasons flag is *not* set, only run this test with the
|
||||
// byKey authorization method, because revoking for reason Key Compromise via
|
||||
// any other method is forbidden. If the MozRevocationReasons flag *is* set,
|
||||
// test both byKey and byAccount, but expect slightly different results.
|
||||
methods := []authMethod{byKey}
|
||||
if strings.Contains(os.Getenv("BOULDER_CONFIG_DIR"), "test/config-next") {
|
||||
methods = append(methods, byAccount)
|
||||
}
|
||||
|
||||
// Check the OCSP response. It should be revoked with reason = 1 (keyCompromise)
|
||||
ocspConfig := ocsp_helper.DefaultConfig.WithExpectStatus(ocsp.Revoked)
|
||||
response, err := ocsp_helper.ReqDER(cert.Raw, ocspConfig)
|
||||
test.AssertNotError(t, err, "requesting OCSP for revoked cert")
|
||||
test.AssertEquals(t, response.RevocationReason, 1)
|
||||
for _, method := range methods {
|
||||
c, err := makeClient("mailto:example@letsencrypt.org")
|
||||
test.AssertNotError(t, err, "creating acme client")
|
||||
|
||||
certKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
test.AssertNotError(t, err, "failed to generate cert key")
|
||||
|
||||
res, err := authAndIssue(c, certKey, []string{random_domain()})
|
||||
test.AssertNotError(t, err, "authAndIssue failed")
|
||||
cert := res.certs[0]
|
||||
|
||||
// Revoke the cert with reason keyCompromise, either authenticated via the
|
||||
// issuing account, or via the certificate key itself.
|
||||
switch method {
|
||||
case byAccount:
|
||||
err = c.RevokeCertificate(c.Account, cert, c.PrivateKey, ocsp.KeyCompromise)
|
||||
case byKey:
|
||||
err = c.RevokeCertificate(acme.Account{}, cert, certKey, ocsp.KeyCompromise)
|
||||
}
|
||||
test.AssertNotError(t, err, "failed to revoke certificate")
|
||||
|
||||
// Check the OCSP response. It should be revoked with reason = 1 (keyCompromise).
|
||||
ocspConfig := ocsp_helper.DefaultConfig.WithExpectStatus(ocsp.Revoked).WithExpectReason(ocsp.KeyCompromise)
|
||||
_, err = ocsp_helper.ReqDER(cert.Raw, ocspConfig)
|
||||
test.AssertNotError(t, err, "requesting OCSP for revoked cert")
|
||||
|
||||
// Attempt to create a new account using the compromised key. This should
|
||||
// work when the key was just *reported* as compromised, but fail when
|
||||
// the compromise was demonstrated/proven.
|
||||
_, err = c.NewAccount(certKey, false, true)
|
||||
switch method {
|
||||
case byAccount:
|
||||
test.AssertNotError(t, err, "NewAccount failed with a non-blocklisted key")
|
||||
case byKey:
|
||||
test.AssertError(t, err, "NewAccount didn't fail with a blocklisted key")
|
||||
test.AssertEquals(t, err.Error(), `acme: error code 400 "urn:ietf:params:acme:error:badPublicKey": public key is forbidden`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadKeyRevoker(t *testing.T) {
|
||||
t.Parallel()
|
||||
os.Setenv("DIRECTORY", "http://boulder:4001/directory")
|
||||
cA, err := makeClient("mailto:bad-key-revoker-revoker@letsencrypt.org", "mailto:bad-key-revoker-revoker-2@letsencrypt.org")
|
||||
|
||||
// Both accounts have two email addresses, one of which is shared between
|
||||
// them. All three addresses should receive mail, because the revocation
|
||||
// request is signed by the certificate key, not an account key, so we don't
|
||||
// know who requested the revocation. Finally, a third account with no address
|
||||
// to ensure the bad-key-revoker handles that gracefully.
|
||||
revokerClient, err := makeClient("mailto:revoker@letsencrypt.org", "mailto:shared@letsencrypt.org")
|
||||
test.AssertNotError(t, err, "creating acme client")
|
||||
cB, err := makeClient("mailto:bad-key-revoker-revoker-2@letsencrypt.org")
|
||||
revokeeClient, err := makeClient("mailto:shared@letsencrypt.org", "mailto:revokee@letsencrypt.org")
|
||||
test.AssertNotError(t, err, "creating acme client")
|
||||
cC, err := makeClient("mailto:bad-key-revoker-revokee@letsencrypt.org", "mailto:bad-key-revoker-revokee-2@letsencrypt.org")
|
||||
test.AssertNotError(t, err, "creating acme client")
|
||||
cD, err := makeClient("mailto:bad-key-revoker-revokee-2@letsencrypt.org", "mailto:bad-key-revoker-revokee@letsencrypt.org")
|
||||
test.AssertNotError(t, err, "creating acme client")
|
||||
cE, err := makeClient()
|
||||
noContactClient, err := makeClient()
|
||||
test.AssertNotError(t, err, "creating acme client")
|
||||
|
||||
certKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
test.AssertNotError(t, err, "failed to generate cert key")
|
||||
|
||||
badCert, err := authAndIssue(cA, certKey, []string{random_domain()})
|
||||
res, err := authAndIssue(revokerClient, certKey, []string{random_domain()})
|
||||
test.AssertNotError(t, err, "authAndIssue failed")
|
||||
badCert := res.certs[0]
|
||||
t.Logf("Generated to-be-revoked cert with serial %x", badCert.SerialNumber)
|
||||
|
||||
certs := []*x509.Certificate{}
|
||||
for _, c := range []*client{cA, cB, cC, cD, cE} {
|
||||
for i := 0; i < 2; i++ {
|
||||
cert, err := authAndIssue(c, certKey, []string{random_domain()})
|
||||
test.AssertNotError(t, err, "authAndIssue failed")
|
||||
certs = append(certs, cert.certs[0])
|
||||
}
|
||||
for _, c := range []*client{revokerClient, revokeeClient, noContactClient} {
|
||||
cert, err := authAndIssue(c, certKey, []string{random_domain()})
|
||||
t.Logf("TestBadKeyRevoker: Issued cert with serial %x", cert.certs[0].SerialNumber)
|
||||
test.AssertNotError(t, err, "authAndIssue failed")
|
||||
certs = append(certs, cert.certs[0])
|
||||
}
|
||||
|
||||
err = cA.RevokeCertificate(
|
||||
err = revokerClient.RevokeCertificate(
|
||||
acme.Account{},
|
||||
badCert.certs[0],
|
||||
badCert,
|
||||
certKey,
|
||||
ocsp.KeyCompromise,
|
||||
)
|
||||
test.AssertNotError(t, err, "failed to revoke certificate")
|
||||
ocspConfig := ocsp_helper.DefaultConfig.WithExpectStatus(ocsp.Revoked)
|
||||
_, err = ocsp_helper.ReqDER(badCert.certs[0].Raw, ocspConfig)
|
||||
|
||||
ocspConfig := ocsp_helper.DefaultConfig.WithExpectStatus(ocsp.Revoked).WithExpectReason(ocsp.KeyCompromise)
|
||||
_, err = ocsp_helper.ReqDER(badCert.Raw, ocspConfig)
|
||||
test.AssertNotError(t, err, "ReqDER failed")
|
||||
|
||||
for _, cert := range certs {
|
||||
for i := 0; i < 5; i++ {
|
||||
_, err = ocsp_helper.ReqDER(cert.Raw, ocspConfig)
|
||||
if err == nil {
|
||||
break
|
||||
t.Logf("TestBadKeyRevoker: Requesting OCSP for cert with serial %x (attempt %d)", cert.SerialNumber, i)
|
||||
_, err := ocsp_helper.ReqDER(cert.Raw, ocspConfig)
|
||||
if err != nil {
|
||||
t.Logf("TestBadKeyRevoker: Got bad response: %s", err.Error())
|
||||
if i >= 4 {
|
||||
t.Fatal("timed out waiting for correct OCSP status")
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
if i == 5 {
|
||||
t.Fatal("timed out waiting for revoked OCSP status")
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
countResp, err := http.Get("http://boulder:9381/count?to=bad-key-revoker-revokee@letsencrypt.org")
|
||||
revokeeCount, err := http.Get("http://boulder:9381/count?to=revokee@letsencrypt.org&from=bad-key-revoker@test.org")
|
||||
test.AssertNotError(t, err, "mail-test-srv GET /count failed")
|
||||
defer func() { _ = countResp.Body.Close() }()
|
||||
body, err := ioutil.ReadAll(countResp.Body)
|
||||
test.AssertNotError(t, err, "failed to read body")
|
||||
test.AssertEquals(t, string(body), "1\n")
|
||||
otherCountResp, err := http.Get("http://boulder:9381/count?to=bad-key-revoker-revokee-2@letsencrypt.org")
|
||||
test.AssertNotError(t, err, "mail-test-srv GET /count failed")
|
||||
defer func() { _ = otherCountResp.Body.Close() }()
|
||||
body, err = ioutil.ReadAll(otherCountResp.Body)
|
||||
defer func() { _ = revokeeCount.Body.Close() }()
|
||||
body, err := ioutil.ReadAll(revokeeCount.Body)
|
||||
test.AssertNotError(t, err, "failed to read body")
|
||||
test.AssertEquals(t, string(body), "1\n")
|
||||
|
||||
zeroCountResp, err := http.Get("http://boulder:9381/count?to=bad-key-revoker-revoker@letsencrypt.org")
|
||||
revokerCount, err := http.Get("http://boulder:9381/count?to=revoker@letsencrypt.org&from=bad-key-revoker@test.org")
|
||||
test.AssertNotError(t, err, "mail-test-srv GET /count failed")
|
||||
defer func() { _ = zeroCountResp.Body.Close() }()
|
||||
body, err = ioutil.ReadAll(zeroCountResp.Body)
|
||||
defer func() { _ = revokerCount.Body.Close() }()
|
||||
body, err = ioutil.ReadAll(revokerCount.Body)
|
||||
test.AssertNotError(t, err, "failed to read body")
|
||||
test.AssertEquals(t, string(body), "1\n")
|
||||
|
||||
sharedCount, err := http.Get("http://boulder:9381/count?to=shared@letsencrypt.org&from=bad-key-revoker@test.org")
|
||||
test.AssertNotError(t, err, "mail-test-srv GET /count failed")
|
||||
defer func() { _ = sharedCount.Body.Close() }()
|
||||
body, err = ioutil.ReadAll(sharedCount.Body)
|
||||
test.AssertNotError(t, err, "failed to read body")
|
||||
test.AssertEquals(t, string(body), "1\n")
|
||||
}
|
||||
|
||||
func TestBadKeyRevokerByAccount(t *testing.T) {
|
||||
os.Setenv("DIRECTORY", "http://boulder:4001/directory")
|
||||
|
||||
// This test is gated on the MozRevocationReasons feature flag being set.
|
||||
// It does not replace the test above, it complements it by testing new
|
||||
// behavior enabled by this flag.
|
||||
if !strings.Contains(os.Getenv("BOULDER_CONFIG_DIR"), "test/config-next") {
|
||||
return
|
||||
}
|
||||
|
||||
// Both accounts have two email addresses, one of which is shared between
|
||||
// them. No accounts should receive any mail, because the revocation request
|
||||
// is signed by the account key (not the cert key) and so will not be
|
||||
// propagated to other certs sharing the same key.
|
||||
revokerClient, err := makeClient("mailto:revoker-moz@letsencrypt.org", "mailto:shared-moz@letsencrypt.org")
|
||||
test.AssertNotError(t, err, "creating acme client")
|
||||
revokeeClient, err := makeClient("mailto:shared-moz@letsencrypt.org", "mailto:revokee-moz@letsencrypt.org")
|
||||
test.AssertNotError(t, err, "creating acme client")
|
||||
noContactClient, err := makeClient()
|
||||
test.AssertNotError(t, err, "creating acme client")
|
||||
|
||||
certKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
test.AssertNotError(t, err, "failed to generate cert key")
|
||||
|
||||
res, err := authAndIssue(revokerClient, certKey, []string{random_domain()})
|
||||
test.AssertNotError(t, err, "authAndIssue failed")
|
||||
badCert := res.certs[0]
|
||||
t.Logf("Generated to-be-revoked cert with serial %x", badCert.SerialNumber)
|
||||
|
||||
certs := []*x509.Certificate{}
|
||||
for _, c := range []*client{revokerClient, revokeeClient, noContactClient} {
|
||||
cert, err := authAndIssue(c, certKey, []string{random_domain()})
|
||||
t.Logf("TestBadKeyRevokerByAccount: Issued cert with serial %x", cert.certs[0].SerialNumber)
|
||||
test.AssertNotError(t, err, "authAndIssue failed")
|
||||
certs = append(certs, cert.certs[0])
|
||||
}
|
||||
|
||||
err = revokerClient.RevokeCertificate(
|
||||
revokerClient.Account,
|
||||
badCert,
|
||||
revokerClient.PrivateKey,
|
||||
ocsp.KeyCompromise,
|
||||
)
|
||||
test.AssertNotError(t, err, "failed to revoke certificate")
|
||||
|
||||
ocspConfig := ocsp_helper.DefaultConfig.WithExpectStatus(ocsp.Revoked).WithExpectReason(ocsp.KeyCompromise)
|
||||
_, err = ocsp_helper.ReqDER(badCert.Raw, ocspConfig)
|
||||
test.AssertNotError(t, err, "ReqDER failed")
|
||||
|
||||
ocspConfig = ocsp_helper.DefaultConfig.WithExpectStatus(ocsp.Good)
|
||||
for _, cert := range certs {
|
||||
for i := 0; i < 5; i++ {
|
||||
t.Logf("TestBadKeyRevoker: Requesting OCSP for cert with serial %x (attempt %d)", cert.SerialNumber, i)
|
||||
_, err := ocsp_helper.ReqDER(cert.Raw, ocspConfig)
|
||||
if err != nil {
|
||||
t.Logf("TestBadKeyRevoker: Got bad response: %s", err.Error())
|
||||
if i >= 4 {
|
||||
t.Fatal("timed out waiting for correct OCSP status")
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
revokeeCount, err := http.Get("http://boulder:9381/count?to=revokee-moz@letsencrypt.org&from=bad-key-revoker@test.org")
|
||||
test.AssertNotError(t, err, "mail-test-srv GET /count failed")
|
||||
defer func() { _ = revokeeCount.Body.Close() }()
|
||||
body, err := ioutil.ReadAll(revokeeCount.Body)
|
||||
test.AssertNotError(t, err, "failed to read body")
|
||||
test.AssertEquals(t, string(body), "0\n")
|
||||
|
||||
revokerCount, err := http.Get("http://boulder:9381/count?to=revoker-moz@letsencrypt.org&from=bad-key-revoker@test.org")
|
||||
test.AssertNotError(t, err, "mail-test-srv GET /count failed")
|
||||
defer func() { _ = revokerCount.Body.Close() }()
|
||||
body, err = ioutil.ReadAll(revokerCount.Body)
|
||||
test.AssertNotError(t, err, "failed to read body")
|
||||
test.AssertEquals(t, string(body), "0\n")
|
||||
|
||||
sharedCount, err := http.Get("http://boulder:9381/count?to=shared-moz@letsencrypt.org&from=bad-key-revoker@test.org")
|
||||
test.AssertNotError(t, err, "mail-test-srv GET /count failed")
|
||||
defer func() { _ = sharedCount.Body.Close() }()
|
||||
body, err = ioutil.ReadAll(sharedCount.Body)
|
||||
test.AssertNotError(t, err, "failed to read body")
|
||||
test.AssertEquals(t, string(body), "0\n")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,27 +9,33 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// toFilter filters mails based on the To: field.
|
||||
// filter filters mails based on the To: and From: fields.
|
||||
// The zero value matches all mails.
|
||||
type toFilter struct {
|
||||
To string
|
||||
type filter struct {
|
||||
To string
|
||||
From string
|
||||
}
|
||||
|
||||
func (f *toFilter) Match(m rcvdMail) bool {
|
||||
func (f *filter) Match(m rcvdMail) bool {
|
||||
if f.To != "" && f.To != m.To {
|
||||
return false
|
||||
}
|
||||
if f.From != "" && f.From != m.From {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
/count - number of mails
|
||||
/count?to=foo@bar.com - number of mails for foo@bar.com
|
||||
/count?from=service@test.org - number of mails sent by service@test.org
|
||||
/clear - clear the mail list
|
||||
/mail/0 - first mail
|
||||
/mail/1 - second mail
|
||||
/mail/0?to=foo@bar.com - first mail for foo@bar.com
|
||||
/mail/1?to=foo@bar.com - second mail for foo@bar.com
|
||||
/mail/1?to=foo@bar.com&from=service@test.org - second mail for foo@bar.com from service@test.org
|
||||
*/
|
||||
|
||||
func (srv *mailSrv) setupHTTP(serveMux *http.ServeMux) {
|
||||
|
|
@ -79,13 +85,12 @@ func (srv *mailSrv) httpGetMail(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func extractFilter(r *http.Request) toFilter {
|
||||
func extractFilter(r *http.Request) filter {
|
||||
values := r.URL.Query()
|
||||
to := values.Get("to")
|
||||
return toFilter{To: to}
|
||||
return filter{To: values.Get("to"), From: values.Get("from")}
|
||||
}
|
||||
|
||||
func (srv *mailSrv) iterMail(f toFilter, cb func(rcvdMail) bool) bool {
|
||||
func (srv *mailSrv) iterMail(f filter, cb func(rcvdMail) bool) bool {
|
||||
srv.allMailMutex.Lock()
|
||||
defer srv.allMailMutex.Unlock()
|
||||
for _, v := range srv.allReceivedMail {
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ type Config struct {
|
|||
issuerFile string
|
||||
}
|
||||
|
||||
// DefaultConfig is a Config populated with the same defaults as if no
|
||||
// command-line had been provided, so all retain their default value.
|
||||
// DefaultConfig is a Config populated with a set of curated default values
|
||||
// intended for library test usage of this package.
|
||||
var DefaultConfig = Config{
|
||||
method: *method,
|
||||
urlOverride: *urlOverride,
|
||||
|
|
@ -56,14 +56,16 @@ var DefaultConfig = Config{
|
|||
ignoreExpiredCerts: *ignoreExpiredCerts,
|
||||
expectStatus: *expectStatus,
|
||||
expectReason: *expectReason,
|
||||
output: os.Stdout,
|
||||
output: ioutil.Discard,
|
||||
issuerFile: *issuerFile,
|
||||
}
|
||||
|
||||
var parseFlagsOnce sync.Once
|
||||
|
||||
// ConfigFromFlags returns a Config whose values are populated from
|
||||
// any command line flags passed by the user, or default values if not passed.
|
||||
// ConfigFromFlags returns a Config whose values are populated from any command
|
||||
// line flags passed by the user, or default values if not passed. However, it
|
||||
// replaces ioutil.Discard with os.Stdout so that CLI usages of this package
|
||||
// will produce output on stdout by default.
|
||||
func ConfigFromFlags() Config {
|
||||
parseFlagsOnce.Do(func() {
|
||||
flag.Parse()
|
||||
|
|
@ -372,16 +374,16 @@ func parseAndPrint(respBytes []byte, cert, issuer *x509.Certificate, config Conf
|
|||
fmt.Fprint(config.output, PrettyResponse(resp))
|
||||
|
||||
if len(errs) > 0 {
|
||||
fmt.Print("Errors:\n")
|
||||
fmt.Fprint(config.output, "Errors:\n")
|
||||
err := errs[0]
|
||||
fmt.Printf(" %v\n", err.Error())
|
||||
fmt.Fprintf(config.output, " %v\n", err.Error())
|
||||
for _, e := range errs[1:] {
|
||||
err = fmt.Errorf("%w; %v", err, e)
|
||||
fmt.Printf(" %v\n", e.Error())
|
||||
fmt.Fprintf(config.output, " %v\n", e.Error())
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
fmt.Print("No errors found.\n")
|
||||
fmt.Fprint(config.output, "No errors found.\n")
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue