def _load_cert_object(self, *path_components):
     with open(os.path.join(fixtures_dir, *path_components), 'rb') as f:
         cert_bytes = f.read()
         if pem.detect(cert_bytes):
             _, _, cert_bytes = pem.unarmor(cert_bytes)
         cert = x509.Certificate.load(cert_bytes)
     return cert
Exemple #2
0
 def _sign_string(self, string_to_sign):
     try:
         # We expect the private key to be the an PKCS8 pem formatted string.
         pem_bytes = self.credentials.private_key.encode('utf-8')
         if pem.detect(pem_bytes):
             _, _, der_bytes = pem.unarmor(pem_bytes)
             # In PKCS8 the key is wrapped in a container that describes it
             info = keys.PrivateKeyInfo.load(der_bytes, strict=True)
             # The unwrapped key is equivalent to pkcs1 contents
             key = rsa.PrivateKey.load_pkcs1(info.unwrap().dump(), 'DER')
         else:
             raise Exception('Not a PEM file')
     except:
         message = \
             "Failed to import private key from: '%s'. The private key is " \
             "corrupted or it is not in PKCS8 PEM format. The private key " \
             "was extracted either from 'env' (environment variables), " \
             "'shared-credentials-file' (a profile in the shared " \
             "credential file, by default under ~/.altus/credentials), or " \
             "'auth-config-file' (a file containing the credentials whose " \
             "location was supplied on the command line.)" % \
             self.credentials.method
         LOG.debug(message, exc_info=True)
         raise Exception(message)
     # We sign the hash.
     signature = rsa.sign(string_to_sign.encode('utf-8'), key, 'SHA-256')
     return urlsafe_b64encode(signature).strip().decode('utf-8')
Exemple #3
0
    def test_invalid_csr(self):
        csr_pem = b'-----BEGIN CERTIFICATE REQUEST-----\nMIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx\nITAfBgNVBAoMGEludgVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBAOX7xMqjolAJ39LsPdhPRTxlHxowKyqd6wnHKdT7\nRVjmc9oY2+awntbkxS6qd8xsTipiL69G/eALMZxoWVIJQ6RGjN1ZA/y1IYXDybYc\nIe3vlobMNcuj1a1Oa9JkS9eg4Hd1xRRsREqsIv0rcMXWLOBBAGGfJrTVCTp0YsHG\nOlKWm9pqSLfSZta2R8ULIMyBEYgAi410LNxGdWXbaxbhlZAMS+POrofVQBKwjPzD\nnZhXrE3NKGPy3YW2Shgx/hAwXf4qXWdcA8zpfsgX3xUwhrLCjTFipaKkCJP1s+kc\nsRJ/Ou9RJhvgQqqOFQB6tCL1bPK3OzsGWaTlbEAHRcc7AYUCAwEAAaAAMA0GCSqG\nSIb3DQEBCwUAA4IBAQBtG7zuAHbcHNPd7ZYqqxNFWn0mFw6TuEfF+77aSQnUgk1a\nt2LaxJg+cTVVtC0dE03ita0eWfTF23WItqiDxk2kSaI4HQWgNV6M0EYVYhykrBhe\ngUTS3g3b2ibDVdgrUDQesaF2EEMRXjtYlyA2LimKPrfsPmybFBOosJPrH+YMHpK+\ndTB5X66qDdwuFo0CB3sfadIrSGdDYHurARheM83WS6qCe+UDydduBbzDC2QfBcje\n8XK1ZU7+pKD8XDefVlsWxYyjcKbQlfv7m1FBlHTH8fFNlrvof+slPChLafLvFW1G\n8LaF8Z5pcfz+3opsCMjgNLxZNO28yOAREjTouqiY\n-----END CERTIFICATE REQUEST-----\n'

        req = csr.CertificationRequest.load(pem.unarmor(csr_pem)[2])
        verified = verify_csr(req)

        self.assertFalse(verified)
Exemple #4
0
    def test_verify_ecdsa_csr(self):
        csr_pem = b'-----BEGIN CERTIFICATE REQUEST-----\nMIIBiDCB6gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh\nMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGbMBAGByqGSM49AgEG\nBSuBBAAjA4GGAAQBi2M5M4iMZhmBeXx+tGTdqP3MOcDwARhz9we41DHD4GLL7sKO\nR2erxXJbO0L1kpe2EKPWfP9xF1cmMjqoi6K15lgAV5uGTetsr7ITFrNzC+k2mEWX\ntpS/9l3goWq6icrSziZQBNNSqGAeCGbMxrtiblxGpKHE7jLN+ErdX2Jh064in3Gg\nADAKBggqhkjOPQQDAgOBjAAwgYgCQgGtS2jmm4lM38Xxt1aXu8/rTbw+W2gsSQMx\nMLBoyaVJ5sbKpQNgvyNN17MvLnyR0J7NYJSmR+3n7jrWl3S9Q4s85AJCANqjvXn+\nHjCGebrPBF7eaw1dInjDLmO4NqK8+ro028JEEj/JO8aYkZZjUFDFJM3G57Ja/p41\n5ozzR5r8dQ64K/aX\n-----END CERTIFICATE REQUEST-----\n'

        req = csr.CertificationRequest.load(pem.unarmor(csr_pem)[2])
        verified = verify_csr(req)

        self.assertTrue(verified)
Exemple #5
0
def _grab_crl(user_agent, url, timeout):
    """
    Fetches a CRL and parses it

    :param user_agent:
        A unicode string of the user agent to use when fetching the URL

    :param url:
        A unicode string of the URL to fetch the CRL from

    :param timeout:
        The number of seconds after which an HTTP request should timeout

    :return:
        An asn1crypto.crl.CertificateList object
    """

    if sys.version_info < (3,):
        url = util.iri_to_uri(url)
    request = Request(url)
    request.add_header(b'Accept', b'application/pkix-crl')
    request.add_header(b'User-Agent', user_agent.encode('iso-8859-1'))
    response = urlopen(request, None, timeout)
    data = response.read()
    if pem.detect(data):
        _, _, data = pem.unarmor(data)
    return crl.CertificateList.load(data)
Exemple #6
0
    def _validate_unarmor(self, certs, var_name):
        """
        Takes a list of byte strings or asn1crypto.x509.Certificates objects,
        validates and loads them while unarmoring any PEM-encoded contents

        :param certs:
            A list of byte strings or asn1crypto.x509.Certificate objects

        :param var_name:
            A unicode variable name to use in any TypeError exceptions

        :return:
            A list of asn1crypto.x509.Certificate objects
        """

        output = []
        for cert in certs:
            if isinstance(cert, x509.Certificate):
                output.append(cert)
            else:
                if not isinstance(cert, byte_cls):
                    raise TypeError(pretty_message(
                        '''
                        %s must contain only byte strings or
                        asn1crypto.x509.Certificate objects, not %s
                        ''',
                        var_name,
                        type_name(cert)
                    ))
                if pem.detect(cert):
                    _, _, cert = pem.unarmor(cert)
                output.append(x509.Certificate.load(cert))
        return output
Exemple #7
0
    def prepend(self, cert):
        """
        Prepends a cert to the path. This should be the issuer of the previously
        prepended cert.

        :param cert:
            An asn1crypto.x509.Certificate object or a byte string

        :return:
            The current ValidationPath object, for chaining
        """

        if not isinstance(cert, x509.Certificate):
            if not isinstance(cert, byte_cls):
                raise TypeError(pretty_message(
                    '''
                    cert must be a byte string or an
                    asn1crypto.x509.Certificate object, not %s
                    ''',
                    type_name(cert)
                ))
            if pem.detect(cert):
                _, _, cert = pem.unarmor(cert)
            cert = x509.Certificate.load(cert)

        if cert.issuer_serial in self._cert_hashes:
            raise DuplicateCertificateError()

        self._cert_hashes.add(cert.issuer_serial)
        self._certs.insert(0, cert)

        return self
Exemple #8
0
def extract_from_system(cert_callback=None):
    """
    Extracts trusted CA certs from the system CA cert bundle

    :param cert_callback:
        A callback that is called once for each certificate in the trust store.
        It should accept two parameters: an asn1crypto.x509.Certificate object,
        and a reason. The reason will be None if the certificate is being
        exported, otherwise it will be a unicode string of the reason it won't.

    :return:
        A list of 3-element tuples:
         - 0: a byte string of a DER-encoded certificate
         - 1: a set of unicode strings that are OIDs of purposes to trust the
              certificate for
         - 2: a set of unicode strings that are OIDs of purposes to reject the
              certificate for
    """

    all_purposes = '2.5.29.37.0'
    ca_path = system_path()

    output = []
    with open(ca_path, 'rb') as f:
        for armor_type, _, cert_bytes in unarmor(f.read(), multiple=True):
            # Without more info, a certificate is trusted for all purposes
            if armor_type == 'CERTIFICATE':
                if cert_callback:
                    cert_callback(Certificate.load(cert_bytes), None)
                output.append((cert_bytes, set(), set()))

            # The OpenSSL TRUSTED CERTIFICATE construct adds OIDs for trusted
            # and rejected purposes, so we extract that info.
            elif armor_type == 'TRUSTED CERTIFICATE':
                cert, aux = TrustedCertificate.load(cert_bytes)
                reject_all = False
                trust_oids = set()
                reject_oids = set()
                for purpose in aux['trust']:
                    if purpose.dotted == all_purposes:
                        trust_oids = set([purpose.dotted])
                        break
                    trust_oids.add(purpose.dotted)
                for purpose in aux['reject']:
                    if purpose.dotted == all_purposes:
                        reject_all = True
                        break
                    reject_oids.add(purpose.dotted)
                if reject_all:
                    if cert_callback:
                        cert_callback(cert, 'explicitly distrusted')
                    continue
                if cert_callback:
                    cert_callback(cert, None)
                output.append((cert.dump(), trust_oids, reject_oids))

    return output
Exemple #9
0
    def test_get_list_mutate(self):
        certs = trust_list.get_list()
        certs2 = trust_list.get_list()

        with open(digicert_ca_path, 'rb') as f:
            _, _, digicert_ca_bytes = pem.unarmor(f.read())
            digicert_ca_cert = x509.Certificate.load(digicert_ca_bytes)
        certs.append(digicert_ca_cert)

        self.assertNotEqual(certs2, certs)
Exemple #10
0
    def unarmor(self, relative_path, expected_bytes_filename, expected_type_name, expected_headers):
        with open(os.path.join(fixtures_dir, relative_path), 'rb') as f:
            byte_string = f.read()

        type_name, headers, decoded_bytes = pem.unarmor(byte_string)
        self.assertEqual(expected_type_name, type_name)
        self.assertEqual(expected_headers, headers)
        with open(os.path.join(fixtures_dir, expected_bytes_filename), 'rb') as f:
            expected_bytes = f.read()
            self.assertEqual(expected_bytes, decoded_bytes)
Exemple #11
0
    def from_pem(cls, pem_string):
        """Read a single PEM-encoded certificate from a string.

        Args:
            pem_string: the certificate string.

        Returns:
            a Certificate object.
        """
        _, _, der_bytes = pem.unarmor(pem_string)
        return cls.from_der(der_bytes)
Exemple #12
0
    def test_verify_dsa_csr(self):
        """
        I don't know why this fails, but I don't think we actually care about
        DSA.
        """
        csr_pem = b'-----BEGIN CERTIFICATE REQUEST-----\nMIICSzCCAggCAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx\nITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCAbgwggEsBgcqhkjO\nOAQBMIIBHwKBgQD4dXOBuPkpOYn3HBjnzSgfZ6+rTNJxfHHebNRH6JkeojvVvssq\ngMeUjJwldVygHM3ewJbHcCTsUYSFXZwtR1F3CHY7NnC8ybYuot4djmDPNcSGNPRY\nmuNfcTaK7VLRGY396kRrL1ExqtZ0eb/1uOFcHz9s3udhqTLRyOWy9GiYiQIVAPZQ\njMRMUgQbAnsfgqFrSXDXhgXrAoGBAI5FAQN8NN++QJUlnEVSIDtdihIwNJ2tAKgS\nFViPne5IDzcKRqIYxwr1Ci7OxinsGMFZqXjT5Y7IlhYosONMzoPXxYXV0gJjS0bj\nxMZrCMHpyuXPN0AyScJpw/hWbVuHcfOVM8/2Nwzpx8VaLYhXTPtWuIsYrP4+CMWI\njr0nzRwaA4GFAAKBgQDl+UDgDprQdutjIhmjEdsyB36rANFoOQDjKVL/Vj6uDbqi\nWfn54qNV7MnI3pAk/nZPh30OmcpSnl0m5E522b63q7WV2tzLlKO7vPOipJyX9GH8\nP/71H/g6UGRbLSVkApWqOw3z+ijxN9bvM+zB8ihXTwlQ96OO+3XmZc1QWjP63aAA\nMAsGCWCGSAFlAwQDAgMwADAtAhUAmYbJM2jyLqRxWO2hgJNC2zqbnsACFDKcB0gM\nW/IY3ZafXVi27kP4dEmr\n-----END CERTIFICATE REQUEST-----\n'

        req = csr.CertificationRequest.load(pem.unarmor(csr_pem)[2])
        verified = verify_csr(req)

        self.assertTrue(verified)
Exemple #13
0
def certs_from_pem(pem_string):
    """Read multiple PEM-encoded certificates from a string.

    Args:
        pem_string: the certificate string.

    Yields:
        Certificate objects.
    """
    for _, _, der_bytes in pem.unarmor(pem_string, multiple=True):
        yield Certificate.from_der(der_bytes)
    def test_fetch_crl(self):
        with open(os.path.join(fixtures_dir, 'GeoTrust_EV_SSL_CA_-_G4.crt'), 'rb') as f:
            file_bytes = f.read()
            if pem.detect(file_bytes):
                _, _, file_bytes = pem.unarmor(file_bytes)
            intermediate = x509.Certificate.load(file_bytes)

        crls = crl_client.fetch(intermediate, timeout=3)
        context = ValidationContext(crls=crls)
        registry = context.certificate_registry
        path = registry.build_paths(intermediate)[0]

        verify_crl(intermediate, path, context)
    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)
Exemple #16
0
def _unarmor_pem(data, password=None):
    """
    Removes PEM-encoding from a public key, private key or certificate. If the
    private key is encrypted, the password will be used to decrypt it.

    :param data:
        A byte string of the PEM-encoded data

    :param password:
        A byte string of the encryption password, or None

    :return:
        A 3-element tuple in the format: (key_type, algorithm, der_bytes). The
        key_type will be a unicode string of "public key", "private key" or
        "certificate". The algorithm will be a unicode string of "rsa", "dsa"
        or "ec".
    """

    object_type, headers, der_bytes = pem.unarmor(data)

    type_regex = '^((DSA|EC|RSA) PRIVATE KEY|ENCRYPTED PRIVATE KEY|PRIVATE KEY|PUBLIC KEY|RSA PUBLIC KEY|CERTIFICATE)'
    armor_type = re.match(type_regex, object_type)
    if not armor_type:
        raise ValueError(pretty_message(
            '''
            data does not seem to contain a PEM-encoded certificate, private
            key or public key
            '''
        ))

    pem_header = armor_type.group(1)

    data = data.strip()

    # RSA private keys are encrypted after being DER-encoded, but before base64
    # encoding, so they need to be hanlded specially
    if pem_header in set(['RSA PRIVATE KEY', 'DSA PRIVATE KEY', 'EC PRIVATE KEY']):
        algo = armor_type.group(2).lower()
        return ('private key', algo, _unarmor_pem_openssl_private(headers, der_bytes, password))

    key_type = pem_header.lower()
    algo = None
    if key_type == 'encrypted private key':
        key_type = 'private key'
    elif key_type == 'rsa public key':
        key_type = 'public key'
        algo = 'rsa'

    return (key_type, algo, der_bytes)
 def read_cert_bundle(self, ca_bundle_file, storage=None):
     """
     Reads a certificate file including certificates in PEM format
     """
     if storage is None:
         storage = SnowflakeOCSP.ROOT_CERTIFICATES_DICT
     logger.debug('reading certificate bundle: %s', ca_bundle_file)
     with open(ca_bundle_file, 'rb') as all_certs:
         # don't lock storage
         from asn1crypto import pem
         pem_certs = pem.unarmor(all_certs.read(), multiple=True)
         for type_name, _, der_bytes in pem_certs:
             if type_name == 'CERTIFICATE':
                 crt = Certificate.load(der_bytes)
                 storage[crt.subject.sha256] = crt
Exemple #18
0
def _list_certificates(directory):
    for filename in os.listdir(directory):
        if filename.endswith(".pem"):
            path = os.path.join(directory, filename)
            with open(path, "rb") as fh:
                buf = fh.read()
                header, _, der_bytes = pem.unarmor(buf)
                cert = x509.Certificate.load(der_bytes)
                server = False
                for extension in cert["tbs_certificate"]["extensions"]:
                    if extension["extn_id"].native == "extended_key_usage":
                        if "server_auth" in extension["extn_value"].native:
                            server = True
                yield cert.subject.native[
                    "common_name"], path, buf, cert, server
Exemple #19
0
 def __init__(
     self,
     expected_measurement=None,
     accept_debug=False,
     accept_configuration_needed=False,
     accept_group_out_of_date=False,
 ):
     self.expected_measurement = expected_measurement
     self.accept_debug = accept_debug
     self.accept_configuration_needed = accept_configuration_needed
     self.accept_group_out_of_date = accept_group_out_of_date
     trust_roots = []
     for _, _, der_bytes in pem.unarmor(intel_sgx_root_ca, multiple=True):
         trust_roots.append(der_bytes)
     self.context = ValidationContext(trust_roots=trust_roots)
Exemple #20
0
    def test_fetch_crl(self):
        with open(
                os.path.join(fixtures_dir,
                             'digicert-sha2-secure-server-ca.crt'), 'rb') as f:
            file_bytes = f.read()
            if pem.detect(file_bytes):
                _, _, file_bytes = pem.unarmor(file_bytes)
            intermediate = x509.Certificate.load(file_bytes)

        crls = crl_client.fetch(intermediate, timeout=3)
        context = ValidationContext(crls=crls)
        registry = context.certificate_registry
        path = registry.build_paths(intermediate)[0]

        verify_crl(intermediate, path, context)
Exemple #21
0
    def __init__(self, end_entity_cert, intermediate_certs=None, validation_context=None):
        """
        :param end_entity_cert:
            An asn1crypto.x509.Certificate object or a byte string of the DER or
            PEM-encoded X.509 end-entity certificate to validate

        :param intermediate_certs:
            None or a list of asn1crypto.x509.Certificate objects or a byte
            string of a DER or PEM-encoded X.509 certificate. Used in
            constructing certificate paths for validation.

        :param validation_context:
            A certvalidator.context.ValidationContext() object that controls
            validation options
        """

        if not isinstance(end_entity_cert, Certificate):
            if not isinstance(end_entity_cert, byte_cls):
                raise TypeError(pretty_message(
                    '''
                    end_entity_cert must be a byte string or an instance of
                    asn1crypto.x509.Certificate, not %s
                    ''',
                    type_name(end_entity_cert)
                ))
            if pem.detect(end_entity_cert):
                _, _, end_entity_cert = pem.unarmor(end_entity_cert)
            end_entity_cert = Certificate.load(end_entity_cert)

        if validation_context is None:
            validation_context = ValidationContext()

        if not isinstance(validation_context, ValidationContext):
            raise TypeError(pretty_message(
                '''
                validation_context must be an instance of
                certvalidator.context.ValidationContext, not %s
                ''',
                type_name(validation_context)
            ))

        if intermediate_certs is not None:
            certificate_registry = validation_context.certificate_registry
            for intermediate_cert in intermediate_certs:
                certificate_registry.add_other_cert(intermediate_cert)

        self._context = validation_context
        self._certificate = end_entity_cert
Exemple #22
0
    def __init__(self, end_entity_cert, intermediate_certs=None, validation_context=None):
        """
        :param end_entity_cert:
            An asn1crypto.x509.Certificate object or a byte string of the DER or
            PEM-encoded X.509 end-entity certificate to validate

        :param intermediate_certs:
            None or a list of asn1crypto.x509.Certificate objects or a byte
            string of a DER or PEM-encoded X.509 certificate. Used in
            constructing certificate paths for validation.

        :param validation_context:
            A certvalidator.context.ValidationContext() object that controls
            validation options
        """

        if not isinstance(end_entity_cert, Certificate):
            if not isinstance(end_entity_cert, byte_cls):
                raise TypeError(pretty_message(
                    '''
                    end_entity_cert must be a byte string or an instance of
                    asn1crypto.x509.Certificate, not %s
                    ''',
                    type_name(end_entity_cert)
                ))
            if pem.detect(end_entity_cert):
                _, _, end_entity_cert = pem.unarmor(end_entity_cert)
            end_entity_cert = Certificate.load(end_entity_cert)

        if validation_context is None:
            validation_context = ValidationContext()

        if not isinstance(validation_context, ValidationContext):
            raise TypeError(pretty_message(
                '''
                validation_context must be an instance of
                certvalidator.context.ValidationContext, not %s
                ''',
                type_name(validation_context)
            ))

        if intermediate_certs is not None:
            certificate_registry = validation_context.certificate_registry
            for intermediate_cert in intermediate_certs:
                certificate_registry.add_other_cert(intermediate_cert)

        self._context = validation_context
        self._certificate = end_entity_cert
Exemple #23
0
    def build_paths(self, end_entity_cert):
        """
        Builds a list of ValidationPath objects from a certificate in the
        operating system trust store to the end-entity certificate

        :param end_entity_cert:
            A byte string of a DER or PEM-encoded X.509 certificate, or an
            instance of asn1crypto.x509.Certificate

        :return:
            A list of certvalidator.path.ValidationPath objects that represent
            the possible paths from the end-entity certificate to one of the CA
            certs.
        """

        if not isinstance(end_entity_cert, byte_cls) and not isinstance(end_entity_cert, x509.Certificate):
            raise TypeError(pretty_message(
                '''
                end_entity_cert must be a byte string or an instance of
                asn1crypto.x509.Certificate, not %s
                ''',
                type_name(end_entity_cert)
            ))

        if isinstance(end_entity_cert, byte_cls):
            if pem.detect(end_entity_cert):
                _, _, end_entity_cert = pem.unarmor(end_entity_cert)
            end_entity_cert = x509.Certificate.load(end_entity_cert)

        path = ValidationPath(end_entity_cert)
        paths = []
        failed_paths = []

        self._walk_issuers(path, paths, failed_paths)

        if len(paths) == 0:
            cert_name = end_entity_cert.subject.human_friendly
            missing_issuer_name = failed_paths[0].first.issuer.human_friendly
            raise PathBuildingError(pretty_message(
                '''
                Unable to build a validation path for the certificate "%s" - no
                issuer matching "%s" was found
                ''',
                cert_name,
                missing_issuer_name
            ))

        return paths
Exemple #24
0
def sign(common_name, overwrite=False):
    """
    Sign certificate signing request by it's common name
    """

    req_path = os.path.join(config.REQUESTS_DIR, common_name + ".pem")
    with open(req_path) as fh:
        csr_buf = fh.read()
        header, _, der_bytes = pem.unarmor(csr_buf)
        csr = CertificationRequest.load(der_bytes)

    # Sign with function below
    cert, buf = _sign(csr, csr_buf, overwrite)

    os.unlink(req_path)
    return cert, buf
Exemple #25
0
def pem_to_der(cert: bytes, return_multiple: bool = True):
    """Convert a given certificate or list to PEM format."""
    # initialize the certificate array
    cert_list = []

    # If certificate is in DER then un-armour it
    if pem.detect(cert):
        for _, _, der_bytes in pem.unarmor(cert, multiple=True):
            cert_list.append(der_bytes)
    else:
        cert_list.append(cert)

    # return multiple if return_multiple is set else first element
    if return_multiple:
        return cert_list
    return cert_list.pop()
Exemple #26
0
    def _check_certificate(self, certificate):

        _, _, certificate_bytes = pem.unarmor(
            certificate.encode(), multiple=False)
        certificate = x509.Certificate.load(certificate_bytes)
        serialnumber = certificate.serial_number

        cert_client = pki.cert.CertClient(self.get_connection())
        res = cert_client.review_cert(serialnumber)
        logger.debug("Dogtag: Respuesta Validano certificado: "+repr(res))
        ca_cert_info = self.issuer_dn_to_dic(res.issuer_dn)
        user_cert_info = self.extract_dic_from_X509Name(
            certificate.issuer.native, ca_cert_info)
        dev = res.status == 'VALID' and ca_cert_info == user_cert_info
        logger.info("Dogtag: validate cert %r == %r" % (serialnumber, dev))
        return dev
    def test_fetch_ocsp(self):
        with open(
                os.path.join(fixtures_dir,
                             'digicert-sha2-secure-server-ca.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)
Exemple #28
0
    def revoke_certificate(self, certificate):
        # Fixme: Esta función abre y reconstruye el crl
        # El problema es que la concurrencia puede afectar la reconstrucción
        # del crl.
        # Esto podría ayudar https://github.com/ambitioninc/django-db-mutex
        # Fixme: Este método no es eficiente pues requiere reconstruir otra
        # lista y pasar los valores de la anterior cuando debería ser
        # solamente agregar el nuevo valor, pero  no logré descifrar como
        # hacerlo
        _, _, certificate_bytes = pem.unarmor(
            certificate.encode(), multiple=False)
        certificate = x509.Certificate.load(certificate_bytes)

        ca_private_key = asymmetric.load_private_key(
            self.ca_key,
            password=settings.CA_KEY_PASSWD)
        ca_certificate = asymmetric.load_certificate(self.ca_crt)

        with open(settings.CA_CRL, 'rb') as f:
            cert_list = crl.CertificateList.load(f.read())

        builder = CertificateListBuilder(
            cert_list.issuing_distribution_point_value.native[
                'distribution_point'][0],
            ca_certificate,
            1000
        )

        for revoked_cert in cert_list[
                'tbs_cert_list']['revoked_certificates']:
            revoked_cert_serial = revoked_cert['user_certificate'].native
            revoked_time = revoked_cert['revocation_date'].native
            reason = revoked_cert['crl_entry_extensions'][0][
                'extn_value'].native
            builder.add_certificate(revoked_cert_serial, revoked_time,
                                    reason)

        builder.add_certificate(certificate.serial_number,
                                timezone.now(),
                                "cessation_of_operation")

        crl_list = builder.build(ca_private_key)

        with open(settings.CA_CRL, 'wb') as f:
            f.write(crl_list.dump())

        logger.info("SimpleCA: revoke certificate, don't make anything")
Exemple #29
0
def store_request(buf, overwrite=False, address="", user=""):
    """
    Store CSR for later processing
    """

    if not buf:
        raise ValueError("No signing request supplied")

    if pem.detect(buf):
        header, _, der_bytes = pem.unarmor(buf)
        csr = CertificationRequest.load(der_bytes)
    else:
        csr = CertificationRequest.load(buf)
        buf =  pem_armor_csr(csr)

    common_name = csr["certification_request_info"]["subject"].native["common_name"]

    if not re.match(const.RE_COMMON_NAME, common_name):
        raise ValueError("Invalid common name %s" % repr(common_name))

    request_path = os.path.join(config.REQUESTS_DIR, common_name + ".pem")


    # If there is cert, check if it's the same
    if os.path.exists(request_path) and not overwrite:
        if open(request_path, "rb").read() == buf:
            raise errors.RequestExists("Request already exists")
        else:
            raise errors.DuplicateCommonNameError("Another request with same common name already exists")
    else:
        with open(request_path + ".part", "wb") as fh:
            fh.write(buf)
        os.rename(request_path + ".part", request_path)

    attach_csr = buf, "application/x-pem-file", common_name + ".csr"
    mailer.send("request-stored.md",
        attachments=(attach_csr,),
        common_name=common_name)
    setxattr(request_path, "user.request.address", address)
    setxattr(request_path, "user.request.user", user)
    try:
        hostname, aliaslist, ipaddrlist = socket.gethostbyaddr(address)
    except (socket.herror, OSError): # Failed to resolve hostname or resolved to multiple
        pass
    else:
        setxattr(request_path, "user.request.hostname", hostname)
    return request_path, csr, common_name
Exemple #30
0
def unwrap_pkcs8(blob):
    if not pem.detect(blob):
        return

    _, _, der_bytes = pem.unarmor(blob)
    data = EncryptedPrivateKeyInfo.load(der_bytes).native

    if "encryption_algorithm" not in data:
        return
    if "encrypted_data" not in data:
        return
    if "algorithm" not in data["encryption_algorithm"]:
        return
    if data["encryption_algorithm"]["algorithm"] != "pbes2":
        sys.stderr.write(
            "[%s] encryption_algorithm <%s> is not supported currently!\n" %
            (sys.argv[0], data["encryption_algorithm"]["algorithm"]))
        return

    # encryption data
    encrypted_data = data["encrypted_data"]

    # KDF
    params = data["encryption_algorithm"]["parameters"]
    kdf = params["key_derivation_func"]
    if kdf["algorithm"] != "pbkdf2":
        sys.stderr.write(
            "[%s] kdf algorithm <%s> is not supported currently!\n" %
            (sys.argv[0], kdf["algorithm"]))
        return
    kdf_params = kdf["parameters"]
    salt = kdf_params["salt"]
    iterations = kdf_params["iteration_count"]

    # Cipher
    cipher_params = params["encryption_scheme"]
    cipher = cipher_params["algorithm"]
    iv = cipher_params["parameters"]

    if cipher != "tripledes_3key":
        sys.stderr.write("[%s] cipher <%s> is not supported currently!\n" %
                         (sys.argv[0], cipher))
        return

    sys.stdout.write("$PEM$1$1$%s$%s$%s$%d$%s\n" %
                     (salt.encode("hex"), iterations, iv.encode("hex"),
                      len(encrypted_data), encrypted_data.encode("hex")))
    def build_paths(self, end_entity_cert):
        """
        Builds a list of ValidationPath objects from a certificate in the
        operating system trust store to the end-entity certificate

        :param end_entity_cert:
            A byte string of a DER or PEM-encoded X.509 certificate, or an
            instance of asn1crypto.x509.Certificate

        :return:
            A list of pyhanko_certvalidator.path.ValidationPath objects that represent
            the possible paths from the end-entity certificate to one of the CA
            certs.
        """

        if not isinstance(end_entity_cert, byte_cls) and not isinstance(
                end_entity_cert, x509.Certificate):
            raise TypeError(
                pretty_message(
                    '''
                end_entity_cert must be a byte string or an instance of
                asn1crypto.x509.Certificate, not %s
                ''', type_name(end_entity_cert)))

        if isinstance(end_entity_cert, byte_cls):
            if pem.detect(end_entity_cert):
                _, _, end_entity_cert = pem.unarmor(end_entity_cert)
            end_entity_cert = x509.Certificate.load(end_entity_cert)

        path = ValidationPath(end_entity_cert)
        paths = []
        failed_paths = []

        self._walk_issuers(path, paths, failed_paths)

        if len(paths) == 0:
            cert_name = end_entity_cert.subject.human_friendly
            missing_issuer_name = failed_paths[0].first.issuer.human_friendly
            raise PathBuildingError(
                pretty_message(
                    '''
                Unable to build a validation path for the certificate "%s" - no
                issuer matching "%s" was found
                ''', cert_name, missing_issuer_name))

        return paths
def get_revoked(serial):
    if isinstance(serial, str):
        serial = int(serial, 16)
    path = os.path.join(config.REVOKED_DIR, "%040x.pem" % serial)
    with open(path, "rb") as fh:
        buf = fh.read()
        header, _, der_bytes = pem.unarmor(buf)
        cert = x509.Certificate.load(der_bytes)
        try:
            reason = getxattr(path, "user.revocation.reason").decode("ascii")
        except IOError:  # TODO: make sure it's not required
            reason = "key_compromise"
        return path, buf, cert, \
            cert["tbs_certificate"]["validity"]["not_before"].native.replace(tzinfo=None), \
            cert["tbs_certificate"]["validity"]["not_after"].native.replace(tzinfo=None), \
            datetime.utcfromtimestamp(os.stat(path).st_ctime), \
            reason
Exemple #33
0
 def test_unarmor_multiple(self):
     data = self.unarmor_armor_files()
     input_data = b''
     der_data = []
     for pem_file, der_file in ((data[0][0], data[0][1]), (data[1][0],
                                                           data[1][1])):
         with open(os.path.join(fixtures_dir, pem_file), 'rb') as f:
             input_data += f.read() + b'\n'
         with open(os.path.join(fixtures_dir, der_file), 'rb') as f:
             der_data.append(f.read())
     i = 0
     for name, headers, der_bytes in pem.unarmor(input_data, True):
         self.assertEqual('CERTIFICATE', name)
         self.assertEqual({}, headers)
         self.assertEqual(der_data[i], der_bytes)
         i += 1
     self.assertEqual(2, i)
Exemple #34
0
def extract_from_system():
    """
    Extracts trusted CA certs from the system CA cert bundle

    :return:
        A list of byte strings - each a DER-encoded certificate
    """

    ca_path = system_path()

    output = []
    with open(ca_path, 'rb') as f:
        for entry_info in unarmor(f.read(), multiple=True):
            if entry_info[0] == 'CERTIFICATE':
                output.append(entry_info[2])

    return output
Exemple #35
0
    def on_put(self, req, resp):
        # Consume token
        now = time()
        timestamp = req.get_param_as_int("t", required=True)
        username = req.get_param("u", required=True)
        user = User.objects.get(username)
        csum = hashlib.sha256()
        csum.update(config.TOKEN_SECRET)
        csum.update(username.encode("ascii"))
        csum.update(str(timestamp).encode("ascii"))

        margin = 300  # Tolerate 5 minute clock skew as Kerberos does
        if csum.hexdigest() != req.get_param("c", required=True):
            raise falcon.HTTPForbidden(
                "Forbidden",
                "Invalid token supplied, did you copy-paste link correctly?")
        if now < timestamp - margin:
            raise falcon.HTTPForbidden(
                "Forbidden",
                "Token not valid yet, are you sure server clock is correct?")
        if now > timestamp + margin + config.TOKEN_LIFETIME:
            raise falcon.HTTPForbidden("Forbidden", "Token expired")

        # At this point consider token to be legitimate
        body = req.stream.read(req.content_length)
        header, _, der_bytes = pem.unarmor(body)
        csr = CertificationRequest.load(der_bytes)
        common_name = csr["certification_request_info"]["subject"].native[
            "common_name"]
        assert common_name == username or common_name.startswith(
            username + "@"), "Invalid common name %s" % common_name
        try:
            _, resp.body = self.authority._sign(
                csr,
                body,
                profile="default",
                overwrite=config.TOKEN_OVERWRITE_PERMITTED)
            resp.set_header("Content-Type", "application/x-pem-file")
            logger.info("Autosigned %s as proven by token ownership",
                        common_name)
        except FileExistsError:
            logger.info("Won't autosign duplicate %s", common_name)
            raise falcon.HTTPConflict(
                "Certificate with such common name (CN) already exists",
                "Will not overwrite existing certificate signing request, explicitly delete existing one and try again"
            )
Exemple #36
0
def extract_from_system():
    """
    Extracts trusted CA certs from the system CA cert bundle

    :return:
        A list of byte strings - each a DER-encoded certificate
    """

    ca_path = system_path()

    output = []
    with open(ca_path, 'rb') as f:
        for entry_info in unarmor(f.read(), multiple=True):
            if entry_info[0] == 'CERTIFICATE':
                output.append(entry_info[2])

    return output
Exemple #37
0
    def add_other_cert(self, cert):
        """
        Allows adding an "other" cert that is obtained from doing revocation
        check via OCSP or CRL, or some other method

        :param cert:
            An asn1crypto.x509.Certificate object or a byte string of a DER or
            PEM-encoded certificate

        :return:
            A boolean indicating if the certificate was added - will return
            False if the certificate was already present
        """

        if not isinstance(cert, x509.Certificate):
            if not isinstance(cert, byte_cls):
                raise TypeError(pretty_message(
                    '''
                    cert must be a byte string or an instance of
                    asn1crypto.x509.Certificate, not %s
                    ''',
                    type_name(cert)
                ))
            if pem.detect(cert):
                _, _, cert = pem.unarmor(cert)
            cert = x509.Certificate.load(cert)

        hashable = cert.subject.hashable
        if hashable not in self._subject_map:
            self._subject_map[hashable] = []

        # Don't add the cert if we already have it
        else:
            serial_number = cert.serial_number
            for existing_cert in self._subject_map[hashable]:
                if existing_cert.serial_number == serial_number:
                    return False

        self._subject_map[hashable].append(cert)
        if cert.key_identifier:
            self._key_identifier_map[cert.key_identifier] = cert
        else:
            self._key_identifier_map[cert.public_key.sha1] = cert

        return True
Exemple #38
0
def parse_cert(byte_data):

    if not isinstance(byte_data, bytes):
        raise TypeError("byte_data must be a byte string")

    if byte_data[0] == 'M':
        byte_data = base64.b64decode(byte_data)

    if pem.detect(byte_data):
        file_type, headers, byte_data = pem.unarmor(byte_data)

        if file_type != 'CERTIFICATE':
            raise TypeError(
                "CERTIFICATE expected, but got {}".format(file_type))

    x509cert = x509.Certificate.load(byte_data)

    return x509cert
    def add_other_cert(self, cert):
        """
        Allows adding an "other" cert that is obtained from doing revocation
        check via OCSP or CRL, or some other method

        :param cert:
            An asn1crypto.x509.Certificate object or a byte string of a DER or
            PEM-encoded certificate

        :return:
            A boolean indicating if the certificate was added - will return
            False if the certificate was already present
        """

        if not isinstance(cert, x509.Certificate):
            if not isinstance(cert, byte_cls):
                raise TypeError(
                    pretty_message(
                        '''
                    cert must be a byte string or an instance of
                    asn1crypto.x509.Certificate, not %s
                    ''', type_name(cert)))
            if pem.detect(cert):
                _, _, cert = pem.unarmor(cert)
            cert = x509.Certificate.load(cert)

        hashable = cert.subject.hashable
        if hashable not in self._subject_map:
            self._subject_map[hashable] = []

        # Don't add the cert if we already have it
        else:
            serial_number = cert.serial_number
            for existing_cert in self._subject_map[hashable]:
                if existing_cert.serial_number == serial_number:
                    return False

        self._subject_map[hashable].append(cert)
        if cert.key_identifier:
            self._key_identifier_map[cert.key_identifier] = cert
        else:
            self._key_identifier_map[cert.public_key.sha1] = cert

        return True
    def decode(byte_string):
      try:
        if pem.detect(byte_string): 
            type_name, headers, decoded_bytes = pem.unarmor(byte_string)
            byte_string = decoded_bytes

        key = OneAsymmetricKey.load(byte_string)
        if key['privateKeyAlgorithm']['algorithm'].native != 'Curve25519' and key['privateKeyAlgorithm']['algorithm'].native != 'Ed25519':
            raise NotACurve25519Key
        
        key = PrivateKey.load(key['privateKey'].native)

        if len(key.native) != 32:
            raise NotA256BitCurve25519Key
      
      except Exception as e:
            raise FailedToParseCurve25519Key
      
      return key.native
Exemple #41
0
    def validate_vmc(self):
        try:
            end_entity_cert = None
            intermediates = []
            with open(self.vmc_file, 'rb') as f:
                readfile = f.read()
                # Create parsed data for expiry and embedded svg check
                self.parsed_vmc = self.parse_vmc_cert(readfile)
                for type_name, headers, der_bytes in pem.unarmor(
                        readfile, multiple=True):
                    if end_entity_cert is None:
                        end_entity_cert = der_bytes
                    else:
                        intermediates.append(der_bytes)

            validator = CertificateValidator(end_entity_cert, intermediates)
            validated = validator.validate_usage(
                set(['digital_signature'])
                # ,extended_key_usage=set(["server_auth", "client_auth"])
            )
            if validated:
                print("Certificate Validated")

        except errors.PathValidationError as PathValidationError:
            self.vmc_response["errors"].append("Warning: " +
                                               str(PathValidationError))
            print(PathValidationError)
        except errors.RevokedError as RevokedError:
            self.vmc_response["errors"].append(
                "Warning: Certificate Revoked.\n" + str(RevokedError))
            print(RevokedError)
        except errors.InvalidCertificateError as InvalidCertificateError:
            self.vmc_response["errors"].append(
                "Warning: Certificate Is Invalid.\n" +
                str(InvalidCertificateError))
            print(InvalidCertificateError)
        except errors.PathBuildingError as PathBuildingError:
            # self.vmc_response["errors"].append("Warning: Cannot Build Path.\n"+str(PathBuildingError))
            print(PathBuildingError)
        except Exception as e:
            self.vmc_response["errors"].append(
                "Warning: Validation Exception.\n" + str(e))
            print(e)
def unwrap_pkcs8(blob):
    if not pem.detect(blob):
        return

    _, _, der_bytes = pem.unarmor(blob)
    data = EncryptedPrivateKeyInfo.load(der_bytes).native

    if "encryption_algorithm" not in data:
        return
    if "encrypted_data" not in data:
        return
    if "algorithm" not in data["encryption_algorithm"]:
        return
    if data["encryption_algorithm"]["algorithm"] != "pbes2":
        sys.stderr.write("[%s] encryption_algorithm <%s> is not supported currently!\n" %
                         (sys.argv[0], data["encryption_algorithm"]["algorithm"]))
        return

    # encryption data
    encrypted_data = data["encrypted_data"]

    # KDF
    params = data["encryption_algorithm"]["parameters"]
    kdf = params["key_derivation_func"]
    if kdf["algorithm"] != "pbkdf2":
        sys.stderr.write("[%s] kdf algorithm <%s> is not supported currently!\n" %
                         (sys.argv[0], kdf["algorithm"]))
        return
    kdf_params = kdf["parameters"]
    salt = kdf_params["salt"]
    iterations = kdf_params["iteration_count"]

    # Cipher
    cipher_params = params["encryption_scheme"]
    cipher = cipher_params["algorithm"]
    iv = cipher_params["parameters"]

    if cipher != "tripledes_3key":
        sys.stderr.write("[%s] cipher <%s> is not supported currently!\n" % (sys.argv[0], cipher))
        return

    sys.stdout.write("$PEM$1$1$%s$%s$%s$%d$%s\n" % (salt.encode("hex"), iterations, iv.encode("hex"), len(encrypted_data), encrypted_data.encode("hex")))
Exemple #43
0
def _read_cert_bundle(ca_bundle_file):
    """
    Reads a certificate file including certificates in PEM format
    """
    from asn1crypto.x509 import Certificate
    from asn1crypto import pem
    certs = []

    logger = getLogger(__name__)
    logger.debug('reading certificate bundle: %s', ca_bundle_file)
    all_certs = open(ca_bundle_file, 'rb').read()

    pem_certs = pem.unarmor(all_certs, multiple=True)
    for type_name, _, der_bytes in pem_certs:
        if type_name == 'CERTIFICATE':
            crt = Certificate.load(der_bytes)
            logger.debug("Found part of the chain..")
            certs.append(crt)

    return certs
Exemple #44
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])
Exemple #45
0
def cert_from_crt(crt_id, req_session, src_address):
    """
    Get cert, pem and response code from crt id
    """
    if DEBUG_MODE:
        log(f'Getting cert for crt id {crt_id} with source IP ' + src_address)
    new_source = source.SourceAddressAdapter(src_address)
    url = CRT_URL + str(crt_id)
    req_session.mount('https://', new_source)
    response = req_session.get(url)
    txt = response.text # pem
    error = response.status_code
    try:
        der_bytes = pem.unarmor(txt.encode('utf-8'))[2]
        cert = x509.Certificate.load(der_bytes)
    except:
        if DEBUG_MODE:
            log(f'Could not get certificate for crt id {crt_id}: error {error}',
                mode='error')
        return None, None, None
    return cert, txt, response.status_code
Exemple #46
0
 def on_put(self, req, resp):
     try:
         username, mail, created, expires, profile = self.manager.consume(req.get_param("token", required=True))
     except RelationalMixin.DoesNotExist:
         raise falcon.HTTPForbidden("Forbidden", "No such token or token expired")
     body = req.stream.read(req.content_length)
     header, _, der_bytes = pem.unarmor(body)
     csr = CertificationRequest.load(der_bytes)
     common_name = csr["certification_request_info"]["subject"].native["common_name"]
     if not common_name.startswith(username + "@"):
         raise falcon.HTTPBadRequest("Bad requst", "Invalid common name %s" % common_name)
     try:
         _, resp.body = self.authority._sign(csr, body, profile=config.PROFILES.get(profile),
             overwrite=config.TOKEN_OVERWRITE_PERMITTED)
         resp.set_header("Content-Type", "application/x-pem-file")
         logger.info("Autosigned %s as proven by token ownership", common_name)
     except FileExistsError:
         logger.info("Won't autosign duplicate %s", common_name)
         raise falcon.HTTPConflict(
             "Certificate with such common name (CN) already exists",
             "Will not overwrite existing certificate signing request, explicitly delete existing one and try again")
Exemple #47
0
    def request_certificate(self, key_pem):
        # type: (str) -> bool
        """
        Requests a new certificate for this server.

        key_pem: the PEM-encoded private key (byte string).

        Returns True if the request was accepted, raises ServerApiError otherwise.

        """
        der = pem.unarmor(key_pem)[2]
        privkey = keys.PrivateKeyInfo.load(der)

        builder = CSRBuilder({'common_name': six.text_type(self.server_id)},
                             privkey.public_key_info)
        csr = builder.build(privkey)

        data = {'csr': b64encode(csr.dump())}

        http.post('server/csr/', data=data, auth=self._api_auth)

        return True
Exemple #48
0
def sign(common_name,
         skip_notify=False,
         skip_push=False,
         overwrite=False,
         profile="default",
         signer=None):
    """
    Sign certificate signing request by it's common name
    """

    req_path = os.path.join(config.REQUESTS_DIR, common_name + ".pem")
    with open(req_path, "rb") as fh:
        csr_buf = fh.read()
        header, _, der_bytes = pem.unarmor(csr_buf)
        csr = CertificationRequest.load(der_bytes)

    # Sign with function below
    cert, buf = _sign(csr, csr_buf, skip_notify, skip_push, overwrite, profile,
                      signer)

    os.unlink(req_path)
    return cert, buf
    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])
Exemple #50
0
    def wrapped(resource, req, resp, *args, **kwargs):
        buf = req.get_header("X-SSL-CERT")
        if not buf:
            logger.info(
                "No TLS certificate presented to access administrative API call"
            )
            raise falcon.HTTPForbidden(
                "Forbidden", "Machine not authorized to perform the operation")

        header, _, der_bytes = pem.unarmor(
            buf.replace("\t", "").encode("ascii"))
        cert = x509.Certificate.load(der_bytes)  # TODO: validate serial
        for extension in cert["tbs_certificate"]["extensions"]:
            if extension["extn_id"].native == "extended_key_usage":
                if "server_auth" in extension["extn_value"].native:
                    req.context["machine"] = cert.subject.native["common_name"]
                    return func(resource, req, resp, *args, **kwargs)
        logger.info(
            "TLS authenticated machine '%s' not authorized to access administrative API",
            cert.subject.native["common_name"])
        raise falcon.HTTPForbidden(
            "Forbidden", "Machine not authorized to perform the operation")
    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]
        )
def _grab_crl(user_agent, url, timeout):
    """
    Fetches a CRL and parses it

    :param user_agent:
        A unicode string of the user agent to use when fetching the URL

    :param url:
        A unicode string of the URL to fetch the CRL from

    :param timeout:
        The number of seconds after which an HTTP request should timeout

    :return:
        An asn1crypto.crl.CertificateList object
    """
    headers = {'Accept': 'application/pkix-crl', 'User-Agent': user_agent}
    response = requests.get(url=url, timeout=timeout, headers=headers)
    if response.status_code != 200:
        raise RequestException(f"status code {response.status_code}")
    data = response.content
    if pem.detect(data):
        _, _, data = pem.unarmor(data)
    return crl.CertificateList.load(data)
Exemple #53
0
    def testApksignAPKs(self):
        # These APKs are from the apksign testcases and cover
        # all different signature algorithms as well as some error cases
        from androguard.core.bytecodes.apk import APK
        import zipfile
        from asn1crypto import x509, pem
        import binascii
        root = "examples/signing/apksig"
        
        # Correct values generated with openssl:
        # In the apksig repo:src/test/resources/com/android/apksig
        # for f in *.pem; do openssl x509 -in $f -noout -sha256 -fingerprint; done
        certfp = {
            'dsa-1024.x509.pem': 'fee7c19ff9bfb4197b3727b9fd92d95406b1bd96db99ea642f5faac019a389d7',
            'dsa-2048.x509.pem': '97cce0bab292c2d5afb9de90e1810b41a5d25c006a10d10982896aa12ab35a9e',
            'dsa-3072.x509.pem': '966a4537058d24098ea213f12d4b24e37ff5a1d8f68deb8a753374881f23e474',
            'ec-p256.x509.pem': '6a8b96e278e58f62cfe3584022cec1d0527fcb85a9e5d2e1694eb0405be5b599',
            'ec-p384.x509.pem': '5e7777ada7ee7ce8f9c4d1b07094876e5604617b7988b4c5d5b764a23431afbe',
            'ec-p521.x509.pem': '69b50381d98bebcd27df6d7df8af8c8b38d0e51e9168a95ab992d1a9da6082da',
            'rsa-1024_2.x509.pem': 'eba3685e799f59804684abebf0363e14ccb1c213e2b954a22669714ed97f61e9',
            'rsa-1024.x509.pem': 'bc5e64eab1c4b5137c0fbc5ed05850b3a148d1c41775cffa4d96eea90bdd0eb8',
            'rsa-16384.x509.pem': 'f3c6b37909f6df310652fbd7c55ec27d3079dcf695dc6e75e22ba7c4e1c95601',
            'rsa-2048_2.x509.pem': '681b0e56a796350c08647352a4db800cc44b2adc8f4c72fa350bd05d4d50264d',
            'rsa-2048_3.x509.pem': 'bb77a72efc60e66501ab75953af735874f82cfe52a70d035186a01b3482180f3',
            'rsa-2048.x509.pem': 'fb5dbd3c669af9fc236c6991e6387b7f11ff0590997f22d0f5c74ff40e04fca8',
            'rsa-3072.x509.pem': '483934461229a780010bc07cd6eeb0b67025fc4fe255757abbf5c3f2ed249e89',
            'rsa-4096.x509.pem': '6a46158f87753395a807edcc7640ac99c9125f6b6e025bdbf461ff281e64e685',
            'rsa-8192.x509.pem': '060d0a24fea9b60d857225873f78838e081795f7ef2d1ea401262bbd75a58234',
        }

        will_not_validate_correctly = [
            "targetSandboxVersion-2.apk",
            "targetSandboxVersion-2.apk",
            "v1-only-with-cr-in-entry-name.apk",
            "v1-only-with-lf-in-entry-name.apk",
            "v1-only-with-nul-in-entry-name.apk",
            "v1-only-with-rsa-1024-cert-not-der2.apk",
            "v2-only-cert-and-public-key-mismatch.apk",
            "v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk",
            "debuggable-boolean.apk",
            "debuggable-resource.apk",
        ]

        # Collect possible hashes for certificates
        # Unfortunately, not all certificates are supplied...
        for apath in os.listdir(root):
            if apath in certfp:
                with open(os.path.join(root, apath), "rb") as fp:
                    cert = x509.Certificate.load(pem.unarmor(fp.read())[2])
                    h = cert.sha256_fingerprint.replace(" ","").lower()
                    self.assertEqual(h, certfp[apath])
                    self.assertIn(h, certfp.values())

        for apath in os.listdir(root):
            if apath.endswith(".apk"):
                if apath == "v2-only-garbage-between-cd-and-eocd.apk" or \
                   apath == "v2-only-truncated-cd.apk" or \
                   apath == "v1v2v3-with-rsa-2048-lineage-3-signers-invalid-zip.apk":
                    # Can not load as APK
                    with self.assertRaises(zipfile.BadZipFile):
                        APK(os.path.join(root, apath))
                    continue
                elif apath in will_not_validate_correctly:
                    # These APKs are faulty (by design) and will return a not correct fingerprint.
                    # TODO: we need to check if we can prevent such errors...
                    continue

                a = APK(os.path.join(root, apath))

                self.assertIsInstance(a, APK)

                # Test if the correct method returns True, while others return
                # False
                m_tests = {'1': a.is_signed_v1,
                           '2': a.is_signed_v2,
                           '3': a.is_signed_v3}

                # These APKs will raise an error
                excluded = [
                            "v1v2v3-with-rsa-2048-lineage-3-signers-no-sig-block.apk",
                            "v2-only-apk-sig-block-size-mismatch.apk",
                            "v2-only-empty.apk",
                            "v2-only-wrong-apk-sig-block-magic.apk",
                            "v2-stripped.apk",
                            "v2-stripped-with-ignorable-signing-schemes.apk",
                            "v2v3-signed-v3-block-stripped.apk",
                            "v3-only-empty.apk",
                            "v3-only-with-ecdsa-sha512-p384-wrong-apk-sig-block-magic.apk",
                            "v3-only-with-rsa-pkcs1-sha512-4096-apk-sig-block-size-mismatch.apk",
                            "v3-stripped.apk",
                           ]
                if apath[0] == "v" and apath not in excluded:
                    methods = apath.split("-", 1)[0].split("v")[1:]
                    for m, f in m_tests.items():
                        if m in methods:
                            self.assertTrue(f())
                        else:
                            self.assertFalse(f())

                # Special error cases
                if apath == "v2-only-apk-sig-block-size-mismatch.apk":
                    with self.assertRaises(apk.BrokenAPKError):
                        a.is_signed_v2()
                    continue
                elif apath == "v2-only-empty.apk":
                    with self.assertRaises(apk.BrokenAPKError):
                        a.is_signed_v2()
                    continue
                elif apath == "v3-only-with-rsa-pkcs1-sha512-4096-apk-sig-block-size-mismatch.apk":
                    with self.assertRaises(apk.BrokenAPKError):
                        a.is_signed_v3()
                    continue

                if a.is_signed_v1():
                    if apath == "weird-compression-method.apk":
                        with self.assertRaises(NotImplementedError):
                            for c in a.get_signature_names():
                                a.get_certificate(c)

                    elif apath == "v1-only-with-rsa-1024-cert-not-der.apk":
                        for sig in a.get_signature_names():
                            c = a.get_certificate(sig)
                            h = c.sha256_fingerprint.replace(" ","").lower()
                            self.assertNotIn(h, certfp.values())
                            # print([apath, h]) # I do not know, why put this file?
                            der = a.get_certificate_der(sig)
                            apk.show_Certificate(c, True)
                            apk.show_Certificate(c, False)
                            self.assertEqual(hashlib.sha256(der).hexdigest(), h)
                        pass
                    else:
                        for sig in a.get_signature_names():
                            c = a.get_certificate(sig)
                            h = c.sha256_fingerprint.replace(" ","").lower()
                            self.assertIn(h, certfp.values())

                            # Check that we get the same signature if we take the DER
                            der = a.get_certificate_der(sig)
                            self.assertEqual(hashlib.sha256(der).hexdigest(), h)

                if a.is_signed_v2():
                    if apath == "weird-compression-method.apk":
                        with self.assertRaises(NotImplementedError):
                            a.get_certificates_der_v2()
                    elif apath == "v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk":
                        # FIXME
                        # Not sure what this one should do... but the certificate fingerprint is weird
                        # as the hash over the DER is not the same when using the certificate
                        continue
                    else:
                        for c in a.get_certificates_der_v2():
                            cert = x509.Certificate.load(c)
                            h = cert.sha256_fingerprint.replace(" ","").lower()
                            self.assertIn(h, certfp.values())
                            # Check that we get the same signature if we take the DER
                            self.assertEqual(hashlib.sha256(c).hexdigest(), h)

                if a.is_signed_v3():
                    print(apath)
                    if apath == "weird-compression-method.apk":
                        with self.assertRaises(NotImplementedError):
                            a.get_certificates_der_v3()
                    elif apath == "v3-only-with-rsa-pkcs1-sha256-3072-sig-does-not-verify.apk" or \
                         apath == "v3-only-cert-and-public-key-mismatch.apk":
                        cert = x509.Certificate.load(a.get_certificates_der_v3()[0])
                        h = cert.sha256_fingerprint.replace(" ","").lower()
                        self.assertNotIn(h, certfp.values())
                    else:
                        for c in a.get_certificates_der_v3():
                            cert = x509.Certificate.load(c)
                            h = cert.sha256_fingerprint.replace(" ","").lower()
                            self.assertIn(h, certfp.values())
                            # Check that we get the same signature if we take the DER
                            self.assertEqual(hashlib.sha256(c).hexdigest(), h)
Exemple #54
0
    def testApksignAPKs(self):
        # These APKs are from the apksign testcases and cover
        # all different signature algorithms as well as some error cases
        from androguard.core.bytecodes.apk import APK
        import zipfile
        from asn1crypto import x509, pem
        import binascii
        root = "examples/signing/apksig"
        
        # Correct values generated with openssl:
        certfp = {
            "dsa-1024.x509.pem": "fee7c19ff9bfb4197b3727b9fd92d95406b1bd96db99ea642f5faac019a389d7",
            "dsa-2048.x509.pem": "97cce0bab292c2d5afb9de90e1810b41a5d25c006a10d10982896aa12ab35a9e",
            "dsa-3072.x509.pem": "966a4537058d24098ea213f12d4b24e37ff5a1d8f68deb8a753374881f23e474",
            "ec-p256.x509.pem": "6a8b96e278e58f62cfe3584022cec1d0527fcb85a9e5d2e1694eb0405be5b599",
            "ec-p384.x509.pem": "5e7777ada7ee7ce8f9c4d1b07094876e5604617b7988b4c5d5b764a23431afbe",
            "ec-p521.x509.pem": "69b50381d98bebcd27df6d7df8af8c8b38d0e51e9168a95ab992d1a9da6082da",
            "rsa-1024.x509.pem": "bc5e64eab1c4b5137c0fbc5ed05850b3a148d1c41775cffa4d96eea90bdd0eb8",
            "rsa-16384.x509.pem": "f3c6b37909f6df310652fbd7c55ec27d3079dcf695dc6e75e22ba7c4e1c95601",
            "rsa-2048.x509.pem": "fb5dbd3c669af9fc236c6991e6387b7f11ff0590997f22d0f5c74ff40e04fca8",
            "rsa-3072.x509.pem": "483934461229a780010bc07cd6eeb0b67025fc4fe255757abbf5c3f2ed249e89",
            "rsa-4096.x509.pem": "6a46158f87753395a807edcc7640ac99c9125f6b6e025bdbf461ff281e64e685",
            "rsa-8192.x509.pem": "060d0a24fea9b60d857225873f78838e081795f7ef2d1ea401262bbd75a58234",
        }

        will_not_validate_correctly = [
            "targetSandboxVersion-2.apk",
            "targetSandboxVersion-2.apk",
            "v1-only-with-cr-in-entry-name.apk",
            "v1-only-with-lf-in-entry-name.apk",
            "v1-only-with-nul-in-entry-name.apk",
            "v1-only-with-rsa-1024-cert-not-der2.apk",
            "v2-only-cert-and-public-key-mismatch.apk",
            "v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk",
        ]

        # Collect possible hashes for certificates
        # Unfortunately, not all certificates are supplied...
        for apath in os.listdir(root):
            if apath in certfp:
                with open(os.path.join(root, apath), "rb") as fp:
                    cert = x509.Certificate.load(pem.unarmor(fp.read())[2])
                    h = cert.sha256_fingerprint.replace(" ","").lower()
                    self.assertEqual(h, certfp[apath])
                    self.assertIn(h, certfp.values())

        for apath in os.listdir(root):
            if apath.endswith(".apk"):
                if apath == "v2-only-garbage-between-cd-and-eocd.apk" or \
                   apath == "v2-only-truncated-cd.apk":
                    # Can not load as APK
                    if sys.version_info.major == 2:
                        # Different name in python2...
                        with self.assertRaises(zipfile.BadZipfile):
                            APK(os.path.join(root, apath))
                    else:
                        with self.assertRaises(zipfile.BadZipFile):
                            APK(os.path.join(root, apath))
                    continue
                elif apath in will_not_validate_correctly:
                    # These APKs are faulty (by design) and will return a not correct fingerprint.
                    # TODO: we need to check if we can prevent such errors...
                    continue

                a = APK(os.path.join(root, apath))

                self.assertIsInstance(a, APK)

                # Special error cases
                if apath == "v2-only-apk-sig-block-size-mismatch.apk":
                    with self.assertRaises(AssertionError):
                        a.is_signed_v2()
                    continue
                elif apath == "v2-only-empty.apk":
                    with self.assertRaises(AssertionError):
                        a.is_signed_v2()
                    continue

                if a.is_signed_v1():
                    if apath == "weird-compression-method.apk":
                        with self.assertRaises(NotImplementedError):
                            for c in a.get_signature_names():
                                a.get_certificate(c)

                    elif apath == "v1-only-with-rsa-1024-cert-not-der.apk":
                        for sig in a.get_signature_names():
                            c = a.get_certificate(sig)
                            h = c.sha256_fingerprint.replace(" ","").lower()
                            self.assertNotIn(h, certfp.values())
                            # print([apath, h]) # I do not know, why put this file?
                            der = a.get_certificate_der(sig)
                            apk.show_Certificate(c, True)
                            apk.show_Certificate(c, False)
                            self.assertEqual(hashlib.sha256(der).hexdigest(), h)
                        pass
                    else:
                        for sig in a.get_signature_names():
                            c = a.get_certificate(sig)
                            h = c.sha256_fingerprint.replace(" ","").lower()
                            self.assertIn(h, certfp.values())

                            # Check that we get the same signature if we take the DER
                            der = a.get_certificate_der(sig)
                            self.assertEqual(hashlib.sha256(der).hexdigest(), h)

                if a.is_signed_v2():
                    if apath == "weird-compression-method.apk":
                        with self.assertRaises(NotImplementedError):
                            a.get_certificates_der_v2()
                    elif apath == "v2-only-with-rsa-pkcs1-sha256-1024-cert-not-der.apk":
                        # FIXME
                        # Not sure what this one should do... but the certificate fingerprint is weird
                        # as the hash over the DER is not the same when using the certificate
                        continue
                    else:
                        for c in a.get_certificates_der_v2():
                            cert = x509.Certificate.load(c)
                            h = cert.sha256_fingerprint.replace(" ","").lower()
                            self.assertIn(h, certfp.values())
                            # Check that we get the same signature if we take the DER
                            self.assertEqual(hashlib.sha256(c).hexdigest(), h)
Exemple #55
0
    def __init__(self, crl_pem: str):
        type_name, headers, der_bytes = asn1pem.unarmor(crl_pem.encode())
        if type_name != 'X509 CRL':
            raise ValueError('This does not seem like a Certificate Revocation List.')

        self._crl = asn1crl.CertificateList.load(der_bytes)