Пример #1
0
 def test_serialize_request(self):
     req_bytes = load_vectors_from_file(filename=os.path.join(
         "x509", "ocsp", "req-sha1.der"),
                                        loader=lambda data: data.read(),
                                        mode="rb")
     req = ocsp.load_der_ocsp_request(req_bytes)
     assert req.public_bytes(serialization.Encoding.DER) == req_bytes
Пример #2
0
 def test_serialize_request(self):
     req_bytes = load_vectors_from_file(
         filename=os.path.join("x509", "ocsp", "req-sha1.der"),
         loader=lambda data: data.read(),
         mode="rb"
     )
     req = ocsp.load_der_ocsp_request(req_bytes)
     assert req.public_bytes(serialization.Encoding.DER) == req_bytes
Пример #3
0
    def do_POST(self):
        request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediate-keys/0',
                               verify=False)
        issuer_key = serialization.load_pem_private_key(
            request.content, None, default_backend())

        request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediates/0',
                               verify=False)
        issuer_cert = x509.load_pem_x509_certificate(request.content,
                                                     default_backend())

        try:
            content_len = int(self.headers.getheader('content-length', 0))
        except AttributeError:
            content_len = int(self.headers.get('Content-Length'))

        ocsp_request = ocsp.load_der_ocsp_request(self.rfile.read(content_len))
        response = requests.get('{0}/cert-status-by-serial/{1}'.format(
            PEBBLE_MANAGEMENT_URL,
            str(hex(ocsp_request.serial_number)).replace('0x', '')),
                                verify=False)

        if not response.ok:
            ocsp_response = ocsp.OCSPResponseBuilder.build_unsuccessful(
                ocsp.OCSPResponseStatus.UNAUTHORIZED)
        else:
            data = response.json()

            now = datetime.datetime.utcnow()
            cert = x509.load_pem_x509_certificate(data['Certificate'].encode(),
                                                  default_backend())
            if data['Status'] != 'Revoked':
                ocsp_status = ocsp.OCSPCertStatus.GOOD
                revocation_time = None
                revocation_reason = None
            else:
                ocsp_status = ocsp.OCSPCertStatus.REVOKED
                revocation_reason = x509.ReasonFlags.unspecified
                # "... +0000 UTC" => "+0000"
                revoked_at = re.sub(r'( \+\d{4}).*$', r'\1', data['RevokedAt'])
                revocation_time = parser.parse(revoked_at)

            ocsp_response = ocsp.OCSPResponseBuilder().add_response(
                cert=cert,
                issuer=issuer_cert,
                algorithm=hashes.SHA1(),
                cert_status=ocsp_status,
                this_update=now,
                next_update=now + datetime.timedelta(hours=1),
                revocation_time=revocation_time,
                revocation_reason=revocation_reason).responder_id(
                    ocsp.OCSPResponderEncoding.NAME,
                    issuer_cert).sign(issuer_key, hashes.SHA256())

        self.send_response(200)
        self.end_headers()
        self.wfile.write(ocsp_response.public_bytes(
            serialization.Encoding.DER))
Пример #4
0
def ocsp_response(id=None):
    '''
    payload could be found in
     - request.data
     - path

    :param id:
    :return:
    '''

    payload = request.data or id
    if not payload:
        # @todo return invalid ocsp response
        return "This OCSP Endpoint"

    req = ocsp.load_der_ocsp_request(payload)
    cert = Certificate.objects(serial_number=str(req.serial_number)).get()
    ca_cert = Certificate.objects(id=cert.pid).get()

    builder = ocsp.OCSPResponseBuilder()

    if cert.revoked:
        builder = builder.add_response(cert=cert.cert,
                                       issuer=ca_cert.cert,
                                       algorithm=hashes.SHA1(),
                                       cert_status=ocsp.OCSPCertStatus.REVOKED,
                                       this_update=datetime.utcnow(),
                                       next_update=datetime.utcnow(),
                                       revocation_time=cert.revoked_at,
                                       revocation_reason=None)
    else:
        builder = builder.add_response(cert=cert.cert,
                                       issuer=ca_cert.cert,
                                       algorithm=hashes.SHA1(),
                                       cert_status=ocsp.OCSPCertStatus.GOOD,
                                       this_update=datetime.utcnow(),
                                       next_update=datetime.utcnow(),
                                       revocation_time=None,
                                       revocation_reason=None)

    builder = builder.responder_id(ocsp.OCSPResponderEncoding.HASH,
                                   ca_cert.cert)
    response_object = builder.sign(ca_cert.key, hashes.SHA256())
    response = make_response(
        response_object.public_bytes(serialization.Encoding.DER))
    response.headers['Content-Type'] = 'application/ocsp-response'

    return response
Пример #5
0
def cert_status_response(req):
    ocsp_req = ocsp.load_der_ocsp_request(req)

    try:
        sn = str(ocsp_req.serial_number)
        record = Record.query.filter_by(sn=sn).one()

        if record.revoked_at:
            status = ocsp.OCSPCertStatus.REVOKED
            revocation_time = record.revoked_at
            if record.reason:
                revocation_reason = REASON_FLAGS[record.reason]
            else:
                revocation_reason = ReasonFlags.unspecified
        else:
            status = ocsp.OCSPCertStatus.GOOD
            revocation_time, revocation_reason = None, None

    except NoResultFound:
        raise RuntimeError('Unknown certificate.')

    cert: Certificate = load_pem_x509_certificate(data=record.cert,
                                                  backend=default_backend())

    issuer = app.config['ISSUERS'][record.issuer_sn]
    responder_cert = app.config['CERT']
    responder_key = app.config['KEY']

    builder = ocsp.OCSPResponseBuilder()
    builder = builder.add_response(
        cert=cert,
        issuer=issuer,
        algorithm=ocsp_req.hash_algorithm,
        cert_status=status,
        this_update=datetime.datetime.now(),
        next_update=None,
        revocation_time=revocation_time,
        revocation_reason=revocation_reason).responder_id(
            ocsp.OCSPResponderEncoding.HASH, responder_cert)

    response = builder.sign(responder_key, hashes.SHA256())
    return response.public_bytes(serialization.Encoding.DER)
Пример #6
0
 def test_bad_request(self):
     with pytest.raises(ValueError):
         ocsp.load_der_ocsp_request(b"invalid")
Пример #7
0
def _get_ocsp_response(data, pebble_urlopen, log):
    try:
        ocsp_request = ocsp.load_der_ocsp_request(data)
    except Exception:
        log('Error while decoding OCSP request')
        return ocsp.OCSPResponseBuilder.build_unsuccessful(
            ocsp.OCSPResponseStatus.MALFORMED_REQUEST)

    log('OCSP request for certificate # {0}'.format(
        ocsp_request.serial_number))

    # Process possible extensions
    nonce = None
    for ext in ocsp_request.extensions:
        if isinstance(ext.value, x509.OCSPNonce):
            nonce = ext.value.nonce
            continue
        if ext.critical:
            return ocsp.OCSPResponseBuilder.build_unsuccessful(
                ocsp.OCSPResponseStatus.MALFORMED_REQUEST)

    # Determine issuer
    root_count = int(os.environ.get('PEBBLE_ALTERNATE_ROOTS') or '0') + 1
    for root in range(root_count):
        req, intermediate, intermediate_key = _get_sample_request_for_root(
            root, ocsp_request.hash_algorithm, pebble_urlopen)
        if req.issuer_key_hash == ocsp_request.issuer_key_hash and req.issuer_name_hash == ocsp_request.issuer_name_hash:
            log('Identified intermediate certificate {0}'.format(
                intermediate.subject))
            break
        intermediate = None
        intermediate_key = None
    if intermediate is None or intermediate_key is None:
        log(ocsp_request.issuer_key_hash, ocsp_request.issuer_name_hash)
        log('Cannot identify intermediate certificate')
        return ocsp.OCSPResponseBuilder.build_unsuccessful(
            ocsp.OCSPResponseStatus.UNAUTHORIZED)

    serial_hex = hex(ocsp_request.serial_number)[2:]
    if len(serial_hex) % 2 == 1:
        serial_hex = '0' + serial_hex
    try:
        url = pebble_urlopen("/cert-status-by-serial/{0}".format(serial_hex))
    except urllib.error.HTTPError as e:
        if e.code == 404:
            log('Unknown certificate with # {0}'.format(
                ocsp_request.serial_number))
            return ocsp.OCSPResponseBuilder.build_unsuccessful(
                ocsp.OCSPResponseStatus.UNAUTHORIZED)
        raise

    data = json.loads(url.read())
    log('Pebble result on certificate:',
        json.dumps(data, sort_keys=True, indent=2))

    cert = x509.load_pem_x509_certificate(data['Certificate'].encode('utf-8'),
                                          backend=default_backend())

    now = datetime.datetime.now()
    if data['Status'] == 'Revoked':
        cert_status = ocsp.OCSPCertStatus.REVOKED
        revoked_at = data.get('RevokedAt')
        if revoked_at is not None:
            revoked_at = ' '.join(
                revoked_at.split(' ')[:2])  # remove time zones
            if '.' in revoked_at:
                revoked_at = revoked_at[:revoked_at.index(
                    '.')]  # remove milli- or nanoseconds
            revoked_at = datetime.datetime.strptime(revoked_at,
                                                    '%Y-%m-%d %H:%M:%S')
        revocation_time = revoked_at,
        revocation_reason = RECOVATION_REASONS.get(
            data.get('Reason'), x509.ReasonFlags.unspecified)
    elif data['Status'] == 'Valid':
        cert_status = ocsp.OCSPCertStatus.GOOD
        revocation_time = None
        revocation_reason = None
    else:
        log('Unknown certificate status "{0}"'.format(data['Status']))
        return ocsp.OCSPResponseBuilder.build_unsuccessful(
            ocsp.OCSPResponseStatus.INTERNAL_ERROR)

    response = ocsp.OCSPResponseBuilder()
    response = response.add_response(cert=cert,
                                     issuer=intermediate,
                                     algorithm=ocsp_request.hash_algorithm,
                                     cert_status=cert_status,
                                     this_update=now,
                                     next_update=None,
                                     revocation_time=revocation_time,
                                     revocation_reason=revocation_reason)
    response = response.responder_id(ocsp.OCSPResponderEncoding.HASH,
                                     intermediate)
    if nonce is not None:
        response = response.add_extension(x509.OCSPNonce(nonce), False)
    return response.sign(intermediate_key, hashes.SHA256())
Пример #8
0
    def process_ocsp_request(self, data: bytes) -> HttpResponse:
        """Process OCSP request data."""

        try:
            ocsp_req = ocsp.load_der_ocsp_request(data)
        except Exception as e:  # pylint: disable=broad-except; we really need to catch everything here
            log.exception(e)
            return self.malformed_request()

        # Fail if there are any critical extensions that we do not understand
        for ext in ocsp_req.extensions:
            if ext.critical and not isinstance(ext.value, OCSPNonce):  # pragma: no cover
                # It seems impossible to get cryptography to create such a request, so it's not tested
                return self.malformed_request()

        # Get CA and certificate
        try:
            ca = self.get_ca()
        except CertificateAuthority.DoesNotExist:
            log.error("%s: Certificate Authority could not be found.", self.ca)
            return self.fail()

        try:
            cert = self.get_cert(ca, int_to_hex(ocsp_req.serial_number))
        except Certificate.DoesNotExist:
            log.warning("OCSP request for unknown cert received.")
            return self.fail()
        except CertificateAuthority.DoesNotExist:
            log.warning("OCSP request for unknown CA received.")
            return self.fail()

        # get key/cert for OCSP responder
        try:
            responder_key = self.get_responder_key()
            responder_cert = self.get_responder_cert()
        except Exception:  # pylint: disable=broad-except; we really need to catch everything here
            log.error("Could not read responder key/cert.")
            return self.fail()

        # get the certificate status
        if cert.revoked:
            status = ocsp.OCSPCertStatus.REVOKED
        else:
            status = ocsp.OCSPCertStatus.GOOD

        now = datetime.utcnow()
        builder = ocsp.OCSPResponseBuilder()
        expires = datetime.utcnow() + timedelta(seconds=self.expires)
        builder = builder.add_response(
            cert=cert.pub.loaded,
            issuer=ca.pub.loaded,
            algorithm=hashes.SHA1(),
            cert_status=status,
            this_update=now,
            next_update=expires,
            revocation_time=cert.get_revocation_time(),
            revocation_reason=cert.get_revocation_reason(),
        ).responder_id(ocsp.OCSPResponderEncoding.HASH, responder_cert)

        # Add the responder cert to the response, necessary because we (so far) always use delegate
        # certificates
        builder = builder.certificates([responder_cert])

        # Add OCSP nonce if present
        try:
            nonce = ocsp_req.extensions.get_extension_for_class(OCSPNonce)
            builder = builder.add_extension(nonce.value, critical=nonce.critical)
        except ExtensionNotFound:
            pass

        response = builder.sign(responder_key, hashes.SHA256())
        return self.http_response(response.public_bytes(Encoding.DER))
Пример #9
0
#!/bin/python3

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.hashes import SHA1
from cryptography.x509 import load_pem_x509_certificate, ocsp
import base64

#OCSP
cert1 = open("pubkey.crt", "r")
authority1 = open("pubkey.crt", "r")
cert = cert1.read().encode()
authority = authority1.read().encode()

certloader = load_pem_x509_certificate(cert, default_backend())
authorityloader = load_pem_x509_certificate(authority, default_backend())
builder = ocsp.OCSPRequestBuilder()

builder = builder.add_certificate(certloader, authorityloader, SHA1())
prereq = builder.build()

request = base64.b64encode(prereq.public_bytes(serialization.Encoding.DER))

#Load the request:
ocsp_req = ocsp.load_der_ocsp_request(request)
#E.g. show serial
print(ocsp_req.serial_number)

#Response
ocsp_resp = ocsp.load_der_ocsp_response(request)
Пример #10
0
 def test_bad_request(self):
     with pytest.raises(ValueError):
         ocsp.load_der_ocsp_request(b"invalid")