Ejemplo n.º 1
0
    def test_fetch_ocsp(self):
        with open(os.path.join(fixtures_dir, 'GeoTrust_EV_SSL_CA_-_G4.crt'), 'rb') as f:
            cert_bytes = f.read()
            if pem.detect(cert_bytes):
                _, _, cert_bytes = pem.unarmor(cert_bytes)
            intermediate = x509.Certificate.load(cert_bytes)

        registry = CertificateRegistry()
        path = registry.build_paths(intermediate)[0]
        issuer = path.find_issuer(intermediate)

        ocsp_response = ocsp_client.fetch(intermediate, issuer, timeout=3)
        context = ValidationContext(ocsps=[ocsp_response])
        verify_ocsp_response(intermediate, path, context)
Ejemplo n.º 2
0
    def test_build_paths_custom_ca_certs(self):
        with open(os.path.join(fixtures_dir, 'codex.crt'), 'rb') as f:
            cert_bytes = f.read()
            if pem.detect(cert_bytes):
                _, _, cert_bytes = pem.unarmor(cert_bytes)
            cert = x509.Certificate.load(cert_bytes)

        with open(os.path.join(fixtures_dir, 'GeoTrust_EV_SSL_CA_-_G4.crt'),
                  'rb') as f:
            other_certs = [f.read()]

        repo = CertificateRegistry(trust_roots=other_certs)
        paths = repo.build_paths(cert)
        self.assertEqual(1, len(paths))

        path = paths[0]
        self.assertEqual(2, len(path))
        self.assertEqual([
            b'\xaa+\x03\x14\xafd.\x13\x0e\xd6\x92%\xe3\xff*\xba\xd7=b0',
            b"\xfcq\x7f\x98='\xcc\xb3D\xfbK\x85\xf0\x81\x8f\xab\xcb\xf0\x9b\x14"
        ], [item.subject.sha1 for item in path])
Ejemplo n.º 3
0
    def test_build_paths_custom_ca_certs(self):
        with open(os.path.join(fixtures_dir, 'mozilla.org.crt'), 'rb') as f:
            cert_bytes = f.read()
            if pem.detect(cert_bytes):
                _, _, cert_bytes = pem.unarmor(cert_bytes)
            cert = x509.Certificate.load(cert_bytes)

        with open(
                os.path.join(fixtures_dir,
                             'digicert-sha2-secure-server-ca.crt'), 'rb') as f:
            other_certs = [f.read()]

        repo = CertificateRegistry(trust_roots=other_certs)
        paths = repo.build_paths(cert)
        self.assertEqual(1, len(paths))

        path = paths[0]
        self.assertEqual(2, len(path))
        self.assertEqual([
            b"\x10_\xa6z\x80\x08\x9d\xb5'\x9f5\xce\x83\x0bC\x88\x9e\xa3\xc7\r",
            b'I\xac\x03\xf8\xf3Km\xca)V)\xf2I\x9a\x98\xbe\x98\xdc.\x81'
        ], [item.subject.sha1 for item in path])
Ejemplo n.º 4
0
    def test_build_paths_custom_ca_certs(self):
        with open(os.path.join(fixtures_dir, 'codex.crt'), 'rb') as f:
            cert_bytes = f.read()
            if pem.detect(cert_bytes):
                _, _, cert_bytes = pem.unarmor(cert_bytes)
            cert = x509.Certificate.load(cert_bytes)

        with open(os.path.join(fixtures_dir, 'GeoTrust_EV_SSL_CA_-_G4.crt'), 'rb') as f:
            other_certs = [f.read()]

        repo = CertificateRegistry(trust_roots=other_certs)
        paths = repo.build_paths(cert)
        self.assertEqual(1, len(paths))

        path = paths[0]
        self.assertEqual(2, len(path))
        self.assertEqual(
            [
                b'\xaa+\x03\x14\xafd.\x13\x0e\xd6\x92%\xe3\xff*\xba\xd7=b0',
                b"\xfcq\x7f\x98='\xcc\xb3D\xfbK\x85\xf0\x81\x8f\xab\xcb\xf0\x9b\x14"
            ],
            [item.subject.sha1 for item in path]
        )
Ejemplo n.º 5
0
def validate_ocsp_response(cert, issuer, ocsp_request_obj, ocsp_response_objs,
                           current_time):
    #print(cert.ocsp_urls) # Just to see how many urls there are
    subject = cert['tbs_certificate']['subject'].native
    errors = {}
    warnings = {}
    lints_list = []
    count = 0
    lints = {}

    for (ocsp_url, ocsp_response_obj) in ocsp_response_objs:
        count += 1
        lints['domain'] = subject['common_name']
        lints['ocsp_url'] = ocsp_url
        lints['response_count'] = count
        #print(ocsp_response_obj.native)
        errors = {}
        warnings = {}
        if isinstance(ocsp_response_obj, urllib.error.HTTPError):
            errors['HTTPError'] = str(ocsp_response_obj)
            lints['errors'] = errors
            lints['warnings'] = warnings
            lints_list.append(lints)
            return lints_list

        if isinstance(ocsp_response_obj, ValueError):
            errors['ValueError'] = str(ocsp_response_obj)
            lints['errors'] = errors
            lints['warnings'] = warnings
            lints_list.append(lints)
            return lints_list

        if (ocsp_response_obj['response_status'].native == 'unauthorized'):
            errors['Unauthorized'] = 'Responder returned unauthorized'
            lints['errors'] = errors
            lints['warnings'] = warnings
            lints_list.append(lints)
            continue

        if (ocsp_response_obj['response_status'].native == 'malformed_request'
            ):
            errors['ResponseFailure'] = 'Responder returned malformed request'
            lints['errors'] = errors
            lints['warnings'] = warnings
            lints_list.append(lints)
            continue

        request_nonce = ocsp_request_obj.nonce_value
        #print (ocsp_response_obj.native)
        response_nonce = ocsp_response_obj.nonce_value
        if request_nonce and response_nonce and request_nonce.native != response_nonce.native:
            errors[
                'NonceVerificationFailure'] = 'Unable to verify OCSP response since the request and response nonces do not match'

        if ocsp_response_obj['response_status'].native != 'successful':
            errors['OCSPCheckFailure'] = 'OCSP check returned as failed'

        response_bytes = ocsp_response_obj['response_bytes']
        if response_bytes['response_type'].native != 'basic_ocsp_response':
            errors[
                'ResponseTypeFailure'] = 'OCSP response is not Basic OCSP Response'

        parsed_response = response_bytes['response'].parsed
        tbs_response = parsed_response['tbs_response_data']
        certificate_response = tbs_response['responses'][0]

        certificate_id = certificate_response['cert_id']
        algo = certificate_id['hash_algorithm']['algorithm'].native

        certificate_issuer_name_hash = certificate_id[
            'issuer_name_hash'].native
        certificate_issuer_key_hash = certificate_id['issuer_key_hash'].native
        certificate_serial_number = certificate_id['serial_number'].native

        certificate_issuer_name_hash_from_file = getattr(cert.issuer, algo)
        certificate_issuer_key_hash_from_file = getattr(
            issuer.public_key, algo)
        certificate_serial_number_from_file = cert.serial_number

        if certificate_serial_number != certificate_serial_number_from_file:
            errors['CertificateSerialMismatchFailure'] = \
            'OCSP response certificate serial number does not match request certificate serial number'

        if certificate_issuer_key_hash != certificate_issuer_key_hash_from_file:
            errors[
                'IssuerKeyMismatchFailure'] = 'OCSP response issuer key hash does not match request certificate issuer key hash'

        if certificate_issuer_name_hash != certificate_issuer_name_hash_from_file:
            errors['IssuerNameHashMismatchFailure'] = \
                'OCSP response issuer name hash does not match request certificate issuer name hash'

        this_update_time = certificate_response['this_update'].native
        if current_time < this_update_time:
            errors[
                'ThisUpdateTimeError'] = 'OCSP reponse update time is from the future'

        if "next_update" not in certificate_response or certificate_response[
                'next_update'].native is None:
            warnings[
                'NextUpdateTimeMissing'] = 'OCSP response does not contain next update time'
        else:
            next_update_time = certificate_response['next_update'].native
            if current_time > next_update_time:
                errors[
                    'NextUpdateTimeFailure'] = 'OCSP reponse next update time is in the past'

        registry = CertificateRegistry(trust_roots=[issuer])

        if tbs_response['responder_id'].name == 'by_key':
            key_identifier = tbs_response['responder_id'].native
            signing_cert = registry.retrieve_by_key_identifier(key_identifier)

        elif tbs_response['responder_id'].name == 'by_name':
            signing_certs = registry.retrieve_by_name(
                tbs_response['responder_id'].chosen, None)
            if signing_certs is not None and len(signing_certs) > 0:
                signing_cert = signing_certs[0]
            else:
                signing_cert = None

        if signing_cert is None:
            errors[
                'SigningCetificateNotFoundFailure'] = 'OCSP response signing certificate not found'
            lints['errors'] = errors
            lints['warnings'] = warnings
            lints_list.append(lints)
            continue

        if issuer.issuer_serial != signing_cert.issuer_serial:
            if signing_cert_issuer.issuer_serial != issuer.issuer_serial:
                errors[
                    'UnauthorizedSigningCertificateFailure'] = 'OCSP response signed by unauthorized certificate'

            extended_key_usage = signing_cert.extended_key_usage_value
            if 'ocsp_signing' not in extended_key_usage.native:
                errors['ExtendedKeyUsageExtensionValueFailure'] = \
                    'OCSP response signing certificate is not the issuing certificate and it does not have value "ocsp_signing"\
                    for the extended key usage extension'

        sig_algo = parsed_response['signature_algorithm'].signature_algo
        hash_algo = parsed_response['signature_algorithm'].hash_algo
        try:
            check_cert = asymmetric.load_certificate(signing_cert)
            if sig_algo == 'rsassa_pkcs1v15':
                asymmetric.rsa_pkcs1v15_verify(
                    check_cert, parsed_response['signature'].native,
                    tbs_response.dump(), hash_algo)
            elif sig_algo == 'dsa':
                asymmetric.dsa_verify(check_cert,
                                      parsed_response['signature'].native,
                                      tbs_response.dump(), hash_algo)
            elif sig_algo == 'ecdsa':
                asymmetric.ecdsa_verify(check_cert,
                                        parsed_response['signature'].native,
                                        tbs_response.dump(), hash_algo)
            else:
                errors[
                    'UnsupportedAlgorithmFailure'] = 'OCSP response signature uses unsupported algorithm'

        except (oscrypto.errors.SignatureError):
            errors[
                'SignatureVerificationFailure'] = 'OCSP response signature could not be verified'

        if certificate_response['cert_status'].name == 'revoked':
            revocation_data = certificate_response['cert_status'].chosen
            if revocation_data['revocation_reason'].native is None:
                errors[
                    'CertificateValidityFailure'] = 'Certificate revoked due to unknown reason'
            else:
                errors[
                    'CertificateValidityFailure'] = 'Certicate revoked due to ' + revocation_data[
                        'revocation_reason'].human_friendly

        if 'certs' in parsed_response and parsed_response[
                'certs'].native != None:
            #TODO Check for legit certs
            pass


#            print(parsed_response['certs'].native)

        if len(errors) == 0:
            errors['NoFailure'] = 'No errors in OCSP response'
        if len(warnings) == 0:
            warnings['NoWarning'] = 'No warnings in OCSP response'

        lints['errors'] = errors
        lints['warnings'] = warnings
        lints_list.append(lints)

    return lints_list