Skip to content

Commit

Permalink
CA: use mockable clock in CA's OCSP signer. (letsencrypt#4539)
Browse files Browse the repository at this point in the history
This brings OCSP signing into alignment with the other components of the
CA in that they use ca.clk, which can be mocked out in unittests.

This tweaks test_ocsp_exp_unauth to be compatible with the change.

Fixes letsencrypt#4441.
  • Loading branch information
jsha authored and Daniel McCarney committed Nov 11, 2019
1 parent a44f346 commit 2ab1729
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 11 deletions.
11 changes: 1 addition & 10 deletions ca/ca.go
Expand Up @@ -412,16 +412,7 @@ func (ca *CertificateAuthorityImpl) GenerateOCSP(ctx context.Context, xferObj co
core.SerialToString(cert.SerialNumber), cn, err)
}

// We use time.Now() rather than ca.clk.Now() here as we use openssl
// to verify the validity of the OCSP responses we generate during testing
// and openssl doesn't understand our concept of fake time so it thinks
// our responses are expired when we are doing things with our fake clock
// time set in the past. Since we don't rely on fake clock time for any
// OCSP unit tests always using the real time doesn't cause any problems.
// Currently the only integration test case that triggers this is
// ocsp_exp_unauth_setup, but any other integration test introduced that
// sets the fake clock into the past and verifies OCSP will also do so.
now := time.Now().Truncate(time.Hour)
now := ca.clk.Now().Truncate(time.Hour)
tbsResponse := ocsp.Response{
Status: ocspStatusToCode[xferObj.Status],
SerialNumber: cert.SerialNumber,
Expand Down
25 changes: 24 additions & 1 deletion test/v2_integration.py
Expand Up @@ -1173,6 +1173,25 @@ def test_auth_deactivation_v2():
raise Exception("unexpected authorization status")


def check_ocsp_basic_oid(cert_file, issuer_file, url):
"""
This function checks if an OCSP response was successful, but doesn't verify
the signature or timestamp. This is useful when simulating the past, so we
don't incorrectly reject a response for being in the past.
"""
ocsp_request = make_ocsp_req(cert_file, issuer_file)
responses = fetch_ocsp(ocsp_request, url)
# An unauthorized response (for instance, if the OCSP responder doesn't know
# about this cert) will just be 30 03 0A 01 06. A "good" or "revoked"
# response will contain, among other things, the id-pkix-ocsp-basic OID
# identifying the response type. We look for that OID to confirm we got a
# succesful response.
expected = bytearray.fromhex("06 09 2B 06 01 05 05 07 30 01 01")
for resp in responses:
if not expected in bytearray(resp):
raise Exception("Did not receive successful OCSP response: %s doesn't contain %s" %
(base64.b64encode(resp), base64.b64encode(expected)))

expired_cert_name = ""
@register_six_months_ago
def ocsp_exp_unauth_setup():
Expand All @@ -1184,7 +1203,11 @@ def ocsp_exp_unauth_setup():
with open(cert_file_pem, "w") as f:
f.write(OpenSSL.crypto.dump_certificate(
OpenSSL.crypto.FILETYPE_PEM, cert).decode())
verify_ocsp(cert_file_pem, "test/test-ca2.pem", "http://localhost:4002", "good")

# Since we're pretending to be in the past, we'll get an expired OCSP
# response. Just check that it exists; don't do the full verification (which
# would fail).
check_ocsp_basic_oid(cert_file_pem, "test/test-ca2.pem", "http://localhost:4002")
global expired_cert_name
expired_cert_name = cert_file_pem

Expand Down

0 comments on commit 2ab1729

Please sign in to comment.