def extract_from_system(cert_callback=None, callback_only_on_failure=False):
    """
    Extracts trusted CA certificates from the Windows certificate store

    :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.

    :param callback_only_on_failure:
        A boolean - if the callback should only be called when a certificate is
        not exported.

    :raises:
        OSError - when an error is returned by the OS crypto library

    :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
    """

    certificates = {}
    processed = {}

    now = datetime.datetime.utcnow()

    for store in ["ROOT", "CA"]:
        store_handle = crypt32.CertOpenSystemStoreW(null(), store)
        handle_error(store_handle)

        context_pointer = null()
        while True:
            context_pointer = crypt32.CertEnumCertificatesInStore(store_handle, context_pointer)
            if is_null(context_pointer):
                break
            context = unwrap(context_pointer)

            trust_all = False
            data = None
            digest = None

            if context.dwCertEncodingType != Crypt32Const.X509_ASN_ENCODING:
                continue

            data = bytes_from_buffer(context.pbCertEncoded, int(context.cbCertEncoded))
            digest = hashlib.sha1(data).digest()
            if digest in processed:
                continue

            processed[digest] = True
            cert_info = unwrap(context.pCertInfo)

            not_before_seconds = _convert_filetime_to_timestamp(cert_info.NotBefore)
            try:
                not_before = datetime.datetime.fromtimestamp(not_before_seconds)
                if not_before > now:
                    if cert_callback:
                        cert_callback(Certificate.load(data), 'not yet valid')
                    continue
            except (ValueError, OSError):
                # If there is an error converting the not before timestamp,
                # it is almost certainly because it is from too long ago,
                # which means the cert is definitely valid by now.
                pass

            not_after_seconds = _convert_filetime_to_timestamp(cert_info.NotAfter)
            try:
                not_after = datetime.datetime.fromtimestamp(not_after_seconds)
                if not_after < now:
                    if cert_callback:
                        cert_callback(Certificate.load(data), 'no longer valid')
                    continue
            except (ValueError, OSError) as e:
                # The only reason we would get an exception here is if the
                # expiration time is so far in the future that it can't be
                # used as a timestamp, or it is before 0. If it is very far
                # in the future, the cert is still valid, so we only raise
                # an exception if the timestamp is less than zero.
                if not_after_seconds < 0:
                    message = e.args[0] + ' - ' + str_cls(not_after_seconds)
                    e.args = (message,) + e.args[1:]
                    raise e

            trust_oids = set()
            reject_oids = set()

            # Here we grab the extended key usage properties that Windows
            # layers on top of the extended key usage extension that is
            # part of the certificate itself. For highest security, users
            # should only use certificates for the intersection of the two
            # lists of purposes. However, many seen to treat the OS trust
            # list as an override.
            to_read = new(crypt32, 'DWORD *', 0)
            res = crypt32.CertGetEnhancedKeyUsage(
                context_pointer,
                Crypt32Const.CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
                null(),
                to_read
            )

            # Per the Microsoft documentation, if CRYPT_E_NOT_FOUND is returned
            # from get_error(), it means the certificate is valid for all purposes
            error_code, _ = get_error()
            if not res and error_code != Crypt32Const.CRYPT_E_NOT_FOUND:
                handle_error(res)

            if error_code == Crypt32Const.CRYPT_E_NOT_FOUND:
                trust_all = True
            else:
                usage_buffer = buffer_from_bytes(deref(to_read))
                res = crypt32.CertGetEnhancedKeyUsage(
                    context_pointer,
                    Crypt32Const.CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
                    cast(crypt32, 'CERT_ENHKEY_USAGE *', usage_buffer),
                    to_read
                )
                handle_error(res)

                key_usage_pointer = struct_from_buffer(crypt32, 'CERT_ENHKEY_USAGE', usage_buffer)
                key_usage = unwrap(key_usage_pointer)

                # Having no enhanced usage properties means a cert is distrusted
                if key_usage.cUsageIdentifier == 0:
                    if cert_callback:
                        cert_callback(Certificate.load(data), 'explicitly distrusted')
                    continue

                oids = array_from_pointer(
                    crypt32,
                    'LPCSTR',
                    key_usage.rgpszUsageIdentifier,
                    key_usage.cUsageIdentifier
                )
                for oid in oids:
                    trust_oids.add(oid.decode('ascii'))

            cert = None

            # If the certificate is not under blanket trust, we have to
            # determine what purposes it is rejected for by diffing the
            # set of OIDs from the certificate with the OIDs that are
            # trusted.
            if not trust_all:
                cert = Certificate.load(data)
                if cert.extended_key_usage_value:
                    for cert_oid in cert.extended_key_usage_value:
                        oid = cert_oid.dotted
                        if oid not in trust_oids:
                            reject_oids.add(oid)

            if cert_callback and not callback_only_on_failure:
                if cert is None:
                    cert = Certificate.load(data)
                cert_callback(cert, None)

            certificates[digest] = (data, trust_oids, reject_oids)

        result = crypt32.CertCloseStore(store_handle, 0)
        handle_error(result)
        store_handle = None

    return certificates.values()
def extract_from_system(cert_callback=None, callback_only_on_failure=False):
    """
    Extracts trusted CA certificates from the Windows certificate store

    :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.

    :param callback_only_on_failure:
        A boolean - if the callback should only be called when a certificate is
        not exported.

    :raises:
        OSError - when an error is returned by the OS crypto library

    :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
    """

    certificates = {}
    processed = {}

    now = datetime.datetime.utcnow()

    for store in ["ROOT", "CA"]:
        store_handle = crypt32.CertOpenSystemStoreW(null(), store)
        handle_error(store_handle)

        context_pointer = null()
        while True:
            context_pointer = crypt32.CertEnumCertificatesInStore(store_handle, context_pointer)
            if is_null(context_pointer):
                break
            context = unwrap(context_pointer)

            trust_all = False
            data = None
            digest = None

            if context.dwCertEncodingType != Crypt32Const.X509_ASN_ENCODING:
                continue

            data = bytes_from_buffer(context.pbCertEncoded, int(context.cbCertEncoded))
            digest = hashlib.sha1(data).digest()
            if digest in processed:
                continue

            processed[digest] = True
            cert_info = unwrap(context.pCertInfo)

            not_before_seconds = _convert_filetime_to_timestamp(cert_info.NotBefore)
            try:
                not_before = datetime.datetime.fromtimestamp(not_before_seconds)
                if not_before > now:
                    if cert_callback:
                        cert_callback(Certificate.load(data), 'not yet valid')
                    continue
            except (ValueError, OSError):
                # If there is an error converting the not before timestamp,
                # it is almost certainly because it is from too long ago,
                # which means the cert is definitely valid by now.
                pass

            not_after_seconds = _convert_filetime_to_timestamp(cert_info.NotAfter)
            try:
                not_after = datetime.datetime.fromtimestamp(not_after_seconds)
                if not_after < now:
                    if cert_callback:
                        cert_callback(Certificate.load(data), 'no longer valid')
                    continue
            except (ValueError, OSError) as e:
                # The only reason we would get an exception here is if the
                # expiration time is so far in the future that it can't be
                # used as a timestamp, or it is before 0. If it is very far
                # in the future, the cert is still valid, so we only raise
                # an exception if the timestamp is less than zero.
                if not_after_seconds < 0:
                    message = e.args[0] + ' - ' + str_cls(not_after_seconds)
                    e.args = (message,) + e.args[1:]
                    raise e

            trust_oids = set()
            reject_oids = set()

            # Here we grab the extended key usage properties that Windows
            # layers on top of the extended key usage extension that is
            # part of the certificate itself. For highest security, users
            # should only use certificates for the intersection of the two
            # lists of purposes. However, many seen to treat the OS trust
            # list as an override.
            to_read = new(crypt32, 'DWORD *', 0)
            res = crypt32.CertGetEnhancedKeyUsage(
                context_pointer,
                Crypt32Const.CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
                null(),
                to_read
            )

            # Per the Microsoft documentation, if CRYPT_E_NOT_FOUND is returned
            # from get_error(), it means the certificate is valid for all purposes
            error_code, _ = get_error()
            if not res and error_code != Crypt32Const.CRYPT_E_NOT_FOUND:
                handle_error(res)

            if error_code == Crypt32Const.CRYPT_E_NOT_FOUND:
                trust_all = True
            else:
                usage_buffer = buffer_from_bytes(deref(to_read))
                res = crypt32.CertGetEnhancedKeyUsage(
                    context_pointer,
                    Crypt32Const.CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG,
                    cast(crypt32, 'CERT_ENHKEY_USAGE *', usage_buffer),
                    to_read
                )
                handle_error(res)

                key_usage_pointer = struct_from_buffer(crypt32, 'CERT_ENHKEY_USAGE', usage_buffer)
                key_usage = unwrap(key_usage_pointer)

                # Having no enhanced usage properties means a cert is distrusted
                if key_usage.cUsageIdentifier == 0:
                    if cert_callback:
                        cert_callback(Certificate.load(data), 'explicitly distrusted')
                    continue

                oids = array_from_pointer(
                    crypt32,
                    'LPCSTR',
                    key_usage.rgpszUsageIdentifier,
                    key_usage.cUsageIdentifier
                )
                for oid in oids:
                    trust_oids.add(oid.decode('ascii'))

            cert = None

            # If the certificate is not under blanket trust, we have to
            # determine what purposes it is rejected for by diffing the
            # set of OIDs from the certificate with the OIDs that are
            # trusted.
            if not trust_all:
                cert = Certificate.load(data)
                if cert.extended_key_usage_value:
                    for cert_oid in cert.extended_key_usage_value:
                        oid = cert_oid.dotted
                        if oid not in trust_oids:
                            reject_oids.add(oid)

            if cert_callback and not callback_only_on_failure:
                if cert is None:
                    cert = Certificate.load(data)
                cert_callback(cert, None)

            certificates[digest] = (data, trust_oids, reject_oids)

        result = crypt32.CertCloseStore(store_handle, 0)
        handle_error(result)
        store_handle = None

    return certificates.values()
def extract_from_system ( cert_callback = None , callback_only_on_failure = False ) : certificates = { } processed = { } now = datetime . datetime . utcnow ( ) for store in [ "ROOT" , "CA" ] : store_handle = crypt32 . CertOpenSystemStoreW ( null ( ) , store ) handle_error ( store_handle ) context_pointer = null ( ) while True : context_pointer = crypt32 . CertEnumCertificatesInStore ( store_handle , context_pointer ) if is_null ( context_pointer ) : break context = unwrap ( context_pointer ) trust_all = False data = None digest = None if context . dwCertEncodingType != Crypt32Const . X509_ASN_ENCODING : continue data = bytes_from_buffer ( context . pbCertEncoded , int ( context . cbCertEncoded ) ) digest = hashlib . sha1 ( data ) . digest ( ) if digest in processed : continue processed [ digest ] = True cert_info = unwrap ( context . pCertInfo ) not_before_seconds = _convert_filetime_to_timestamp ( cert_info . NotBefore ) try : not_before = datetime . datetime . fromtimestamp ( not_before_seconds ) if not_before > now : if cert_callback : cert_callback ( Certificate . load ( data ) , 'not yet valid' ) continue except ( ValueError , OSError ) : # If there is an error converting the not before timestamp, # it is almost certainly because it is from too long ago, # which means the cert is definitely valid by now. pass not_after_seconds = _convert_filetime_to_timestamp ( cert_info . NotAfter ) try : not_after = datetime . datetime . fromtimestamp ( not_after_seconds ) if not_after < now : if cert_callback : cert_callback ( Certificate . load ( data ) , 'no longer valid' ) continue except ( ValueError , OSError ) as e : # The only reason we would get an exception here is if the # expiration time is so far in the future that it can't be # used as a timestamp, or it is before 0. If it is very far # in the future, the cert is still valid, so we only raise # an exception if the timestamp is less than zero. if not_after_seconds < 0 : message = e . args [ 0 ] + ' - ' + str_cls ( not_after_seconds ) e . args = ( message , ) + e . args [ 1 : ] raise e trust_oids = set ( ) reject_oids = set ( ) # Here we grab the extended key usage properties that Windows # layers on top of the extended key usage extension that is # part of the certificate itself. For highest security, users # should only use certificates for the intersection of the two # lists of purposes. However, many seen to treat the OS trust # list as an override. to_read = new ( crypt32 , 'DWORD *' , 0 ) res = crypt32 . CertGetEnhancedKeyUsage ( context_pointer , Crypt32Const . CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG , null ( ) , to_read ) # Per the Microsoft documentation, if CRYPT_E_NOT_FOUND is returned # from get_error(), it means the certificate is valid for all purposes error_code , _ = get_error ( ) if not res and error_code != Crypt32Const . CRYPT_E_NOT_FOUND : handle_error ( res ) if error_code == Crypt32Const . CRYPT_E_NOT_FOUND : trust_all = True else : usage_buffer = buffer_from_bytes ( deref ( to_read ) ) res = crypt32 . CertGetEnhancedKeyUsage ( context_pointer , Crypt32Const . CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG , cast ( crypt32 , 'CERT_ENHKEY_USAGE *' , usage_buffer ) , to_read ) handle_error ( res ) key_usage_pointer = struct_from_buffer ( crypt32 , 'CERT_ENHKEY_USAGE' , usage_buffer ) key_usage = unwrap ( key_usage_pointer ) # Having no enhanced usage properties means a cert is distrusted if key_usage . cUsageIdentifier == 0 : if cert_callback : cert_callback ( Certificate . load ( data ) , 'explicitly distrusted' ) continue oids = array_from_pointer ( crypt32 , 'LPCSTR' , key_usage . rgpszUsageIdentifier , key_usage . cUsageIdentifier ) for oid in oids : trust_oids . add ( oid . decode ( 'ascii' ) ) cert = None # If the certificate is not under blanket trust, we have to # determine what purposes it is rejected for by diffing the # set of OIDs from the certificate with the OIDs that are # trusted. if not trust_all : cert = Certificate . load ( data ) if cert . extended_key_usage_value : for cert_oid in cert . extended_key_usage_value : oid = cert_oid . dotted if oid not in trust_oids : reject_oids . add ( oid ) if cert_callback and not callback_only_on_failure : if cert is None : cert = Certificate . load ( data ) cert_callback ( cert , None ) certificates [ digest ] = ( data , trust_oids , reject_oids ) result = crypt32 . CertCloseStore ( store_handle , 0 ) handle_error ( result ) store_handle = None return certificates . values ( )
Extracts trusted CA certificates from the Windows certificate store

    :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.

    :param callback_only_on_failure:
        A boolean - if the callback should only be called when a certificate is
        not exported.

    :raises:
        OSError - when an error is returned by the OS crypto library

    :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
Extracts trusted CA certificates from the Windows certificate store