class CertificateContext(PCERT_CONTEXT) replaced by Certificate(CERT_CONTEXT) + multi-received encrypt/decrypt test

This commit is contained in:
hakril
2018-03-04 18:28:09 +01:00
parent c20d443c29
commit a057f8c130
10 changed files with 223 additions and 148 deletions
+2 -2
View File
@@ -33,7 +33,7 @@ l2ec6CyjDQc6HcQBNCsbJVq6qGtQbYNE+ih+KhIU4tO5jf25xthf2g==
raw_cert = ("".join(windowscert.split("\n")[1:-1])).decode('base64')
cert = windows.crypto.CertificateContext.from_buffer(raw_cert)
cert = windows.crypto.Certificate.from_buffer(raw_cert)
print("Analysing certificate: {0}".format(cert))
print(" * name: <{0}>".format(cert.name))
@@ -55,7 +55,7 @@ for i, chain in enumerate(chains):
print ""
cert_to_verif = ccert
print("Looking for <{0}> in trusted certificates".format(cert_to_verif.name))
root_store = windows.crypto.EHCERTSTORE.from_system_store("Root")
root_store = windows.crypto.CertificateStore.from_system_store("Root")
# This is not the correct way verify the validity of a certificate chain.
# I would say that if the goal is to verify the signature of the certificate: use wintrust.
# (or maybe CertVerifyCertificateChainPolicy : https://msdn.microsoft.com/en-us/library/windows/desktop/aa377163(v=vs.85).aspx)
+1 -1
View File
@@ -42,7 +42,7 @@ PFW_TMP_KEY_CONTAINER = "PythonForWindowsTMPContainer"
def genkeys(common_name, pfxpassword, outname, keysize=2048, **kwargs):
"""Generate a SHA256/RSA key pair. A self-signed certificate with 'common_name' is stored as 'outname'.cer.
The private key is stored in 'outname'.pfx protected with 'pfxpassword'"""
cert_store = crypto.EHCERTSTORE.new_in_memory()
cert_store = crypto.CertificateStore.new_in_memory()
# Create a TMP context that will hold our newly generated key-pair
with crypto.CryptContext(PFW_TMP_KEY_CONTAINER, None, PROV_RSA_FULL, 0, retrycreate=True) as ctx:
key = HCRYPTKEY()
+87 -5
View File
@@ -2,6 +2,7 @@ import pytest
import windows.crypto
import windows.generated_def as gdef
import windows.crypto.generation
from pfwtest import *
@@ -63,17 +64,71 @@ def rawcert():
def rawpfx():
return TEST_PFX.decode("base64")
PFW_TEST_TMP_KEY_CONTAINER = "PythonForWindowsTMPContainerTest"
RANDOM_CERTIF_NAME = "PythonForWindowsGeneratedRandomCertifTest"
RANDOM_PFX_PASSWORD = "PythonForWindowsGeneratedRandomPFXPassword"
@pytest.fixture()
def randomkeypair(keysize=1024):
"""Generate a cert / pfx. Based on samples\crypto\encryption_demo.py"""
cert_store = windows.crypto.CertificateStore.new_in_memory()
# Create a TMP context that will hold our newly generated key-pair
with windows.crypto.CryptContext(PFW_TEST_TMP_KEY_CONTAINER, None, gdef.PROV_RSA_FULL, 0, retrycreate=True) as ctx:
key = gdef.HCRYPTKEY()
keysize_flags = keysize << 16
# Generate a key-pair that is exportable
windows.winproxy.CryptGenKey(ctx, gdef.AT_KEYEXCHANGE, gdef.CRYPT_EXPORTABLE | keysize_flags, key)
# It does NOT destroy the key-pair from the container,
# It only release the key handle
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa379918(v=vs.85).aspx
windows.winproxy.CryptDestroyKey(key)
# Descrption of the key-container that will be used to generate the certificate
KeyProvInfo = gdef.CRYPT_KEY_PROV_INFO()
KeyProvInfo.pwszContainerName = PFW_TEST_TMP_KEY_CONTAINER
KeyProvInfo.pwszProvName = None
KeyProvInfo.dwProvType = gdef.PROV_RSA_FULL
KeyProvInfo.dwFlags = 0
KeyProvInfo.cProvParam = 0
KeyProvInfo.rgProvParam = None
#KeyProvInfo.dwKeySpec = AT_SIGNATURE
KeyProvInfo.dwKeySpec = gdef.AT_KEYEXCHANGE
crypt_algo = gdef.CRYPT_ALGORITHM_IDENTIFIER()
crypt_algo.pszObjId = gdef.szOID_RSA_SHA256RSA
certif_name = "CN={0}".format(RANDOM_CERTIF_NAME)
# Generate a self-signed certificate based on the given key-container and signature algorithme
certif = windows.crypto.generation.generate_selfsigned_certificate(certif_name, key_info=KeyProvInfo, signature_algo=crypt_algo)
# Add the newly created certificate to our TMP cert-store
cert_store.add_certificate(certif)
# Generate a pfx from the TMP cert-store
pfx = windows.crypto.generation.generate_pfx(cert_store, RANDOM_PFX_PASSWORD)
yield certif, pfx
# Destroy the TMP key container
prov = gdef.HCRYPTPROV()
windows.winproxy.CryptAcquireContextW(prov, PFW_TEST_TMP_KEY_CONTAINER, None, gdef.PROV_RSA_FULL, gdef.CRYPT_DELETEKEYSET)
def test_certificate(rawcert):
cert = windows.crypto.CertificateContext.from_buffer(rawcert)
cert = windows.crypto.Certificate.from_buffer(rawcert)
assert cert.serial == '1b 8e 94 cb 0b 3e eb b6 41 39 f3 c9 09 b1 6b 46'
assert cert.name == 'PythonForWindowsTest'
assert cert.issuer == 'PythonForWindowsTest'
assert cert.thumprint == 'EF 0C A8 C9 F9 E0 96 AF 74 18 56 8B C1 C9 57 27 A0 89 29 6A'
assert cert.encoded == rawcert
assert cert.version == 2
assert cert == cert
assert cert is cert.duplicate()
cert.chains # TODO: craft a certificate with a chain for test purpose
cert.store.certs
cert.properties
def test_pfx(rawcert, rawpfx):
pfx = windows.crypto.import_pfx(rawpfx, TEST_PFX_PASSWORD)
orig_cert = windows.crypto.CertificateContext.from_buffer(rawcert)
orig_cert = windows.crypto.Certificate.from_buffer(rawcert)
certs = pfx.certs
assert len(certs) == 1
# Test cert comparaison
@@ -87,10 +142,10 @@ def test_open_pfx_bad_password(rawpfx):
def test_encrypt_decrypt(rawcert, rawpfx):
message_to_encrypt = "Testing message \xff\x01"
cert = windows.crypto.CertificateContext.from_buffer(rawcert)
cert = windows.crypto.Certificate.from_buffer(rawcert)
# encrypt should accept a cert or iterable of cert
res = windows.crypto.encrypt(cert, message_to_encrypt)
res2 = windows.crypto.encrypt([cert], message_to_encrypt)
res2 = windows.crypto.encrypt([cert, cert], message_to_encrypt)
del cert
assert message_to_encrypt not in res
@@ -102,6 +157,33 @@ def test_encrypt_decrypt(rawcert, rawpfx):
assert message_to_encrypt == decrypt
assert decrypt == decrypt2
def test_randomkeypair(randomkeypair):
randcert, randrawpfx = randomkeypair
assert randcert.name == RANDOM_CERTIF_NAME
randpfx = windows.crypto.import_pfx(randrawpfx, RANDOM_PFX_PASSWORD) # Check password is good too
def test_encrypt_decrypt_multiple_receivers(rawcert, rawpfx, randomkeypair):
message_to_encrypt = "\xff\x00 Testing message \xff\x01"
# Receiver 1: random key pair
randcert, randrawpfx = randomkeypair
randpfx = windows.crypto.import_pfx(randrawpfx, RANDOM_PFX_PASSWORD)
# Receiver 1: PFW-test-keypair
pfx = windows.crypto.import_pfx(rawpfx, TEST_PFX_PASSWORD)
cert = windows.crypto.Certificate.from_buffer(rawcert)
assert cert.name != randcert.name
assert cert.encoded != randcert.encoded
# Encrypt the message with 2 differents certificates
encrypted = windows.crypto.encrypt([cert, randcert], message_to_encrypt)
# Decrypt with each PFX and check the result is valid/the same
decrypted = windows.crypto.decrypt(pfx, encrypted)
decrypted2 = windows.crypto.decrypt(randpfx, encrypted)
assert decrypted == decrypted2 == message_to_encrypt
def test_crypt_obj():
path = r"C:\windows\system32\kernel32.dll"
x = windows.crypto.CryptObject(path)
@@ -111,6 +193,6 @@ def test_crypt_obj():
# TODO: Need some better ideas
def test_certificate_from_store():
return windows.crypto.EHCERTSTORE.from_system_store("Root")
return windows.crypto.CertificateStore.from_system_store("Root")
+114 -50
View File
@@ -49,7 +49,7 @@ class CryptObject(object):
dwEncoding = gdef.DWORD()
dwContentType = gdef.DWORD()
dwFormatType = gdef.DWORD()
hStore = EHCERTSTORE()
hStore = CertificateStore()
hMsg = windows.crypto.cryptmsg.CryptMessage()
winproxy.CryptQueryObject(gdef.CERT_QUERY_OBJECT_FILE,
@@ -71,6 +71,8 @@ class CryptObject(object):
self.content_type = CRYPT_OBJECT_FORMAT_TYPE_DICT[dwContentType.value]
def _signers_and_certs_generator(self):
if self.crypt_msg is None:
return
for signer in self.crypt_msg.signers:
cert = self.cert_store.find(signer.Issuer, signer.SerialNumber)
yield signer, cert
@@ -84,13 +86,13 @@ class CryptObject(object):
# TODO: rename to CertificateStore ?
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa382037(v=vs.85).aspx
class EHCERTSTORE(gdef.HCERTSTORE):
class CertificateStore(gdef.HCERTSTORE):
"""A certificate store"""
@property
def certs(self):
"""The certificates in the store
:type: [:class:`CertificateContext`] -- A list of Certificate
:type: [:class:`Certificate`] -- A list of Certificate
"""
res = []
last = None
@@ -102,7 +104,7 @@ class EHCERTSTORE(gdef.HCERTSTORE):
return tuple(res)
raise
# Need to duplicate as CertEnumCertificatesInStore will free the context 'last'
ecert = windows.crypto.CertificateContext(cert[0])
ecert = windows.crypto.Certificate.from_pointer(cert)
res.append(ecert.duplicate())
last = ecert
raise RuntimeError("Out of infinit loop")
@@ -113,7 +115,7 @@ class EHCERTSTORE(gdef.HCERTSTORE):
@classmethod
def from_file(cls, filename):
"""Create a new :class:`EHCERTSTORE` from ``filename``"""
"""Create a new :class:`CertificateStore` from ``filename``"""
res = winproxy.CertOpenStore(gdef.CERT_STORE_PROV_FILENAME_A, DEFAULT_ENCODING, None, gdef.CERT_STORE_OPEN_EXISTING_FLAG, filename)
return ctypes.cast(res, cls)
@@ -128,7 +130,7 @@ class EHCERTSTORE(gdef.HCERTSTORE):
# See https://msdn.microsoft.com/en-us/library/windows/desktop/aa388136(v=vs.85).aspx
@classmethod
def from_system_store(cls, store_name):
"""Create a new :class:`EHCERTSTORE` from system store``store_name``
"""Create a new :class:`CertificateStore` from system store``store_name``
(see https://msdn.microsoft.com/en-us/library/windows/desktop/aa388136(v=vs.85).aspx)
"""
res = winproxy.CertOpenStore(gdef.CERT_STORE_PROV_SYSTEM_A, DEFAULT_ENCODING, None, gdef.CERT_SYSTEM_STORE_LOCAL_MACHINE | gdef.CERT_STORE_READONLY_FLAG, store_name)
@@ -136,7 +138,7 @@ class EHCERTSTORE(gdef.HCERTSTORE):
@classmethod
def new_in_memory(cls):
"""Create a new temporary :class:`EHCERTSTORE` in memory"""
"""Create a new temporary :class:`CertificateStore` in memory"""
res = winproxy.CertOpenStore(gdef.CERT_STORE_PROV_MEMORY, DEFAULT_ENCODING, None, 0, None)
return ctypes.cast(res, cls)
@@ -145,15 +147,14 @@ class EHCERTSTORE(gdef.HCERTSTORE):
def find(self, issuer, serialnumber):
"""Return the certificate that match `issuer` and `serialnumber`
:return: :class:`CertificateContext`
:return: :class:`Certificate`
"""
# data = self.get_signer_data(index)
cert_info = gdef.CERT_INFO()
cert_info.Issuer = issuer
cert_info.SerialNumber = serialnumber
rawcertcontext = winproxy.CertFindCertificateInStore(self, DEFAULT_ENCODING, 0, gdef.CERT_FIND_SUBJECT_CERT, ctypes.byref(cert_info), None)
# return rawcertcontext
return CertificateContext(rawcertcontext[0])
return Certificate.from_pointer(rawcertcontext)
# PKCS12_NO_PERSIST_KEY -> do not save it in a key container on disk
@@ -176,32 +177,23 @@ def import_pfx(pfx, password=None, flags=gdef.CRYPT_USER_KEYSET | gdef.PKCS12_NO
``PKCS12_NO_PERSIST_KEY`` tells ``CryptoAPI`` to NOT save the keys in a on-disk container.
:return: :class:`EHCERTSTORE`
:return: :class:`CertificateStore`
"""
if isinstance(pfx, basestring):
if isinstance(pfx, (basestring, bytearray)):
pfx = gdef.CRYPT_DATA_BLOB.from_string(pfx)
cert_store = winproxy.PFXImportCertStore(pfx, password, flags)
return EHCERTSTORE(cert_store)
return CertificateStore(cert_store)
# Why PCCERT_CONTEXT (pointer type) and not _CERT_CONTEXT ?
class CertificateContext(gdef.PCCERT_CONTEXT):
"""Represent a Certificate.
note: It is a pointer ctypes structure (``PCCERT_CONTEXT``)
"""
_type_ = gdef.PCCERT_CONTEXT._type_ # Not herited from PCCERT_CONTEXT
def __repr__(self):
return '<{0} "{1}" serial="{2}">'.format(type(self).__name__, self.name, self.serial)
class Certificate(gdef.CERT_CONTEXT):
"""Represent a Certificate """
@property
def raw_serial(self):
"""The raw serial number of the certificate.
:type: [:class:`int`]: A list of int ``0 <= x <= 255``"""
serial_number = self[0].pCertInfo[0].SerialNumber
serial_number = self.pCertInfo[0].SerialNumber
return [(c & 0xff) for c in serial_number.pbData[:serial_number.cbData][::-1]]
@property
@@ -210,7 +202,6 @@ class CertificateContext(gdef.PCCERT_CONTEXT):
:type: :class:`str`
"""
serial_number = self[0].pCertInfo[0].SerialNumber
serial_bytes = self.raw_serial
return " ".join("{:02x}".format(x) for x in serial_bytes)
@@ -230,6 +221,21 @@ class CertificateContext(gdef.PCCERT_CONTEXT):
:type: :class:`str`"""
def raw_hash(self):
size = gdef.DWORD(100)
buffer = ctypes.c_buffer(size.value)
winproxy.CryptHashCertificate(None, 0, 0, self.pbCertEncoded, self.cbCertEncoded, ctypes.cast(buffer, gdef.LPBYTE), size)
return buffer[:size.value]
@property
def thumprint(self):
"""The thumprint of the certificate (which is the sha1 of the encoded cert) with the format:
'XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX'
:type: :class:`str`
"""
return " ".join("{:02X}".format(x) for x in bytearray(self.raw_hash()))
@property
def issuer(self):
"""The name of the certificate's issuer.
@@ -241,9 +247,9 @@ class CertificateContext(gdef.PCCERT_CONTEXT):
def store(self):
"""The certificate store that contains the certificate
:type: :class:`EHCERTSTORE`
:type: :class:`CertificateStore`
"""
return EHCERTSTORE(self[0].hCertStore)
return CertificateStore(self.hCertStore)
def get_raw_certificate_chains(self): # Rename to all_chains ?
chain_context = EPCCERT_CHAIN_CONTEXT()
@@ -260,16 +266,18 @@ class CertificateContext(gdef.PCCERT_CONTEXT):
chain_para.cbSize = ctypes.sizeof(chain_para)
chain_para.RequestedUsage = cert_usage
winproxy.CertGetCertificateChain(None, self, None, self[0].hCertStore, ctypes.byref(chain_para), 0, None, ctypes.byref(chain_context))
winproxy.CertGetCertificateChain(None, self, None, self.hCertStore, ctypes.byref(chain_para), 0, None, ctypes.byref(chain_context))
# Lower chains ?
# winproxy.CertGetCertificateChain(None, self, None, self[0].hCertStore, ctypes.byref(chain_para), 0x80, None, ctypes.byref(chain_context))
#return CertficateChain(chain_context)
return chain_context
@property # fixedproperty ?
def chains(self):
"""The list of chain context available for this certificate. Each elements of this list is a list of ``CertificateContext`` that should
"""The list of chain context available for this certificate. Each elements of this list is a list of ``Certificate`` that should
go from the ``self`` certificate to a trusted certificate.
:type: [[:class:`CertificateContext`]] -- A list of chain (list) of :class:`CertificateContext`
:type: [[:class:`Certificate`]] -- A list of chain (list) of :class:`Certificate`
"""
chain_context = self.get_raw_certificate_chains()
res = []
@@ -286,19 +294,62 @@ class CertificateContext(gdef.PCCERT_CONTEXT):
note: The object returned is ``self``
:return: :class:`CertificateContext`
:return: :class:`Certificate`
"""
res = winproxy.CertDuplicateCertificateContext(self)
# Check what the doc says: the pointer returned is actually the PCERT in parameter
# Only the refcount is incremented
# This postulate allow us to return 'self' directly
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa376045(v=vs.85).aspx
if not ctypes.cast(res, gdef.PVOID).value == ctypes.cast(self, gdef.PVOID).value:
if not ctypes.addressof(res[0]) == ctypes.addressof(self):
raise ValueError("CertDuplicateCertificateContext did not returned the argument (check doc)")
return self
def view(self, title=None):
return windows.winproxy.CryptUIDlgViewContext(gdef.CERT_STORE_CERTIFICATE_CONTEXT, self, None, title, 0, None)
return windows.winproxy.CryptUIDlgViewContext(gdef.CERT_STORE_CERTIFICATE_CONTEXT, ctypes.byref(self), None, title, 0, None)
KNOWN_PROPERTIES_VALUES = gdef.FlagMapper(
gdef.CERT_KEY_PROV_HANDLE_PROP_ID,
gdef.CERT_KEY_PROV_INFO_PROP_ID,
gdef.CERT_SHA1_HASH_PROP_ID,
gdef.CERT_MD5_HASH_PROP_ID,
gdef.CERT_HASH_PROP_ID,
gdef.CERT_KEY_CONTEXT_PROP_ID,
gdef.CERT_KEY_SPEC_PROP_ID,
gdef.CERT_IE30_RESERVED_PROP_ID,
gdef.CERT_PUBKEY_HASH_RESERVED_PROP_ID,
gdef.CERT_ENHKEY_USAGE_PROP_ID,
gdef.CERT_CTL_USAGE_PROP_ID,
gdef.CERT_NEXT_UPDATE_LOCATION_PROP_ID,
gdef.CERT_FRIENDLY_NAME_PROP_ID,
gdef.CERT_PVK_FILE_PROP_ID,
gdef.CERT_DESCRIPTION_PROP_ID,
gdef.CERT_ACCESS_STATE_PROP_ID,
gdef.CERT_SIGNATURE_HASH_PROP_ID,
gdef.CERT_SMART_CARD_DATA_PROP_ID,
gdef.CERT_EFS_PROP_ID,
gdef.CERT_FORTEZZA_DATA_PROP_ID,
gdef.CERT_ARCHIVED_PROP_ID,
gdef.CERT_KEY_IDENTIFIER_PROP_ID,
gdef.CERT_AUTO_ENROLL_PROP_ID,
gdef.CERT_PUBKEY_ALG_PARA_PROP_ID,
gdef.CERT_CROSS_CERT_DIST_POINTS_PROP_ID,
gdef.CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID,
gdef.CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID,
gdef.CERT_ENROLLMENT_PROP_ID,
gdef.CERT_DATE_STAMP_PROP_ID,
gdef.CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID,
gdef.CERT_SUBJECT_NAME_MD5_HASH_PROP_ID,
gdef.CERT_EXTENDED_ERROR_INFO_PROP_ID,
gdef.CERT_RENEWAL_PROP_ID,
gdef.CERT_ARCHIVED_KEY_HASH_PROP_ID,
gdef.CERT_AUTO_ENROLL_RETRY_PROP_ID,
gdef.CERT_AIA_URL_RETRIEVED_PROP_ID,
gdef.CERT_AUTHORITY_INFO_ACCESS_PROP_ID,
gdef.CERT_BACKED_UP_PROP_ID,
gdef.CERT_OCSP_RESPONSE_PROP_ID,
gdef.CERT_REQUEST_ORIGINATOR_PROP_ID,
gdef.CERT_SOURCE_LOCATION_PROP_ID)
def enum_properties(self):
prop = 0
@@ -307,7 +358,7 @@ class CertificateContext(gdef.PCCERT_CONTEXT):
prop = winproxy.CertEnumCertificateContextProperties(self, prop)
if not prop:
return res
res.append(prop)
res.append(self.KNOWN_PROPERTIES_VALUES[prop])
raise RuntimeError("Unreachable code")
properties = property(enum_properties)
@@ -323,43 +374,49 @@ class CertificateContext(gdef.PCCERT_CONTEXT):
"""The encoded certificate.
:type: :class:`bytearray`"""
return bytearray(self[0].pbCertEncoded[:self[0].cbCertEncoded])
return bytearray(self.pbCertEncoded[:self.cbCertEncoded])
@property
def version(self):
"TODO: doc"
return self[0].pbCertInfo.dwVersion
return self.pCertInfo[0].dwVersion
@classmethod
def from_file(cls, filename):
"""Create a :class:`CertificateContext` from the file ``filename``
"""Create a :class:`Certificate` from the file ``filename``
:return: :class:`CertificateContext`
:return: :class:`Certificate`
"""
with open(filename, "rb") as f:
data = f.read()
buf = (ctypes.c_ubyte * len(data))(*bytearray(data))
res = windows.winproxy.CertCreateCertificateContext(windows.crypto.DEFAULT_ENCODING, buf, len(data))
return ctypes.cast(res, cls)
pcert = windows.winproxy.CertCreateCertificateContext(windows.crypto.DEFAULT_ENCODING, buf, len(data))
return cls.from_pointer(pcert)
@classmethod
def from_buffer(cls, data):
"""Create a :class:`CertificateContext` from the buffer ``data``
"""Create a :class:`Certificate` from the buffer ``data``
:return: :class:`CertificateContext`
:return: :class:`Certificate`
"""
buf = (ctypes.c_ubyte * len(data))(*bytearray(data))
res = windows.winproxy.CertCreateCertificateContext(windows.crypto.DEFAULT_ENCODING, buf, len(data))
return ctypes.cast(res, cls)
pcert = windows.winproxy.CertCreateCertificateContext(windows.crypto.DEFAULT_ENCODING, buf, len(data))
return cls.from_pointer(pcert)
@classmethod
def from_pointer(self, ptr):
return ctypes.cast(ptr, ctypes.POINTER(Certificate))[0]
def __eq__(self, other):
if not isinstance(other, CertificateContext):
if not isinstance(other, Certificate):
return NotImplemented
return windows.winproxy.CertCompareCertificate(DEFAULT_ENCODING, self[0].pCertInfo, other[0].pCertInfo)
return windows.winproxy.CertCompareCertificate(DEFAULT_ENCODING, self.pCertInfo, other.pCertInfo)
def __repr__(self):
return '<{0} "{1}" serial="{2}">'.format(type(self).__name__, self.name, self.serial)
# CertCompareCertificate ?
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa376027(v=vs.85).aspx
# class CertficateChain(object):
@@ -374,12 +431,19 @@ class CertificateContext(gdef.PCCERT_CONTEXT):
# Those classes are more of a POC than anything else
# Should be the struct itself (like Certificate ?)
class EPCCERT_CHAIN_CONTEXT(gdef.PCCERT_CHAIN_CONTEXT):
_type_ = gdef.PCCERT_CHAIN_CONTEXT._type_
@property
def chains(self):
res = []
# if (self[0].cLowerQualityChainContext):
# print("LOL")
# import pdb;pdb.set_trace()
# if self[0].cChain > 1:
# print("HAAAAA")
# import pdb;pdb.set_trace()
for i in range(self[0].cChain):
simple_chain = ctypes.cast(self[0].rgpChain[i], EPCCERT_SIMPLE_CHAIN)
res.append(simple_chain)
@@ -411,7 +475,7 @@ class EPCERT_CHAIN_ELEMENT(gdef.PCERT_CHAIN_ELEMENT):
@property
def cert(self):
return ctypes.cast(self[0].pCertContext, CertificateContext)
return Certificate.from_pointer(self[0].pCertContext)
# Move this in another .py ?
+5 -4
View File
@@ -10,12 +10,14 @@ class CryptMessage(gdef.HCRYPTMSG):
gdef.CMSG_CERT_COUNT_PARAM: gdef.DWORD}
def get_param(self, param_type, index=0):
def get_param(self, param_type, index=0, raw=False):
data_size = gdef.DWORD()
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa380227(v=vs.85).aspx
winproxy.CryptMsgGetParam(self, param_type, index, None, data_size)
buffer = ctypes.c_buffer(data_size.value)
winproxy.CryptMsgGetParam(self, param_type, index, buffer, data_size)
if raw:
return (buffer, data_size)
if param_type in self.MSG_PARAM_KNOW_TYPES:
buffer = self.MSG_PARAM_KNOW_TYPES[param_type].from_buffer(buffer)
@@ -23,7 +25,6 @@ class CryptMessage(gdef.HCRYPTMSG):
return buffer.value
return buffer
# Certificate accessors
@property
@@ -42,9 +43,9 @@ class CryptMessage(gdef.HCRYPTMSG):
note: not all embded certificate are directly used to sign the :class:`CryptObject`.
:return: :class:`CertificateContext`
:return: :class:`Certificate`
"""
return windows.crypto.CertificateContext.from_buffer(self.get_raw_cert(index))
return windows.crypto.Certificate.from_buffer(self.get_raw_cert(index))
@property
def certs(self):
+9 -3
View File
@@ -4,6 +4,7 @@ from windows import winproxy
from windows.crypto import DEFAULT_ENCODING
from windows.crypto.helper import ECRYPT_DATA_BLOB
from windows.generated_def import *
from windows.crypto import Certificate
def encode_init_vector(data):
blob = ECRYPT_DATA_BLOB.from_string(data)
@@ -46,10 +47,14 @@ def encrypt(cert_or_certlist, msg, algo=szOID_NIST_AES256_CBC, initvector=genini
"""
alg_ident = CRYPT_ALGORITHM_IDENTIFIER()
alg_ident.pszObjId = algo
if isinstance(cert_or_certlist, PCERT_CONTEXT):
certlist = (cert_or_certlist,)
# We want to have automatique translation of Certificate -> PCERT_CONTEXT
# In order to simple create the 'PCERT_CONTEXT[] certs'
# For that we need a tuple of X * 1-item-tuple
# as a (cert,) will be automaticly translatable to a PCERT_CONTEXT
if isinstance(cert_or_certlist, CERT_CONTEXT):
certlist = ((cert_or_certlist,),)
else:
certlist = tuple(cert_or_certlist)
certlist = tuple((c,) for c in cert_or_certlist)
# Set (compute if needed) the IV
if initvector is None:
@@ -74,6 +79,7 @@ def encrypt(cert_or_certlist, msg, algo=szOID_NIST_AES256_CBC, initvector=genini
param.dwFlags = 0
param.dwInnerContentType = 0
certs = (PCERT_CONTEXT * len(certlist))(*certlist)
#Ask the output buffer size
size = DWORD()
+3 -3
View File
@@ -3,7 +3,7 @@ from windows import winproxy
from windows.generated_def import *
from windows.crypto.helper import ECRYPT_DATA_BLOB
from windows.crypto import DEFAULT_ENCODING, EHCERTSTORE
from windows.crypto import DEFAULT_ENCODING, CertificateStore
def generate_selfsigned_certificate(name="CN=DEFAULT", prov=None, key_info=None, flags=0, signature_algo=None):
@@ -11,14 +11,14 @@ def generate_selfsigned_certificate(name="CN=DEFAULT", prov=None, key_info=None,
See https://msdn.microsoft.com/en-us/library/windows/desktop/aa376039(v=vs.85).aspx
:return: :class:`windows.crypto.CertificateContext`
:return: :class:`windows.crypto.Certificate`
"""
size = ULONG(len(name) + 0x100)
buffer = (ctypes.c_ubyte * size.value)()
winproxy.CertStrToNameA(X509_ASN_ENCODING, name, CERT_OID_NAME_STR, None, buffer, size, None)
blobname = ECRYPT_DATA_BLOB(size.value, buffer)
cert = winproxy.CertCreateSelfSignCertificate(prov, blobname, flags, key_info, signature_algo, None, None, None)
return windows.crypto.CertificateContext(cert[0])
return windows.crypto.Certificate.from_pointer(cert)
def generate_key(prov, keytype=AT_KEYEXCHANGE, flags=CRYPT_EXPORTABLE):
+2 -2
View File
@@ -4,8 +4,6 @@ import _ctypes
from windows.generated_def import Flag, LPCSTR, LPWSTR
def buffer(size): # Test
buf = ctypes.create_string_buffer(size)
buf.size = size
@@ -25,6 +23,7 @@ def buffer(size): # Test
return ImprovedCtypesBufferImpl()
def fixedpropety(f):
cache_name = "_" + f.__name__
@@ -73,5 +72,6 @@ def print_ctypes_struct(struct, name="", ident=0, hexa=False):
continue
print_ctypes_struct(value, "{0}.{1}".format(name, fname), hexa=hexa)
def sprint(struct, name="struct", hexa=True):
return print_ctypes_struct(struct, name=name, hexa=hexa)
-2
View File
@@ -104,8 +104,6 @@ class Handle(SYSTEM_HANDLE):
del thread._handle
return res
def __repr__(self):
return "<{0} value=<0x{1:x}> in process pid={2}>".format(type(self).__name__, self.wValue, self.dwProcessId)
-76
View File
@@ -1,76 +0,0 @@
import ctypes
import windows
from windows import winproxy
from windows.generated_def import *
callback_type = ctypes.WINFUNCTYPE(UINT, HWND, LPARAM)
class Point(POINT):
def __repr__(self):
return "<{0} x={1} y={2}>".format(type(self).__name__, self.x, self.y)
#return "<{0} x={1:#x} y={2:#x}>".format(type(self).__name__, self.x, self.y)
class Rect(RECT):
def __repr__(self):
return "<{0} left={1} top={2} right={3} bottom={4}>".format(type(self).__name__, self.left, self.top, self.right, self.bottom)
#return "<{0} x={1:#x} y={2:#x}>".format(type(self).__name__, self.x, self.y)
def get_cursor_pos():
res = Point()
winproxy.GetCursorPos(res)
return res
class Window(object):
def __init__(self, handle):
self.handle = handle
def name(self):
size = 0x1024
buffer = ctypes.c_buffer(size)
res = windows.winproxy.GetWindowTextA(self.handle, buffer, size)
return buffer[:res]
def rect(self):
res = Rect()
winproxy.GetWindowRect(self.handle, res)
return res
def size(self):
rect = self.rect()
width = rect.right - rect.left
heigth = rect.bottom - rect.top
return width, heigth
@classmethod
def at_point(cls, point):
handle = winproxy.WindowFromPoint(point)
return cls(handle)
# I don't understand the interest:
# Either return "" or C:\Python27\python.exe
#def module(self):
# size = 0x1024
# buffer = ctypes.c_buffer(size)
# res = windows.winproxy.GetWindowModuleFileNameA(self.handle, buffer, size)
# return buffer[:res]
def enumwindows():
result = []
def callback(handle, param):
result.append(handle)
return True
try:
x = windows.winproxy.EnumWindows(callback_type(callback), 0)
except WindowsError:
if not result:
raise
return result