diff --git a/windows/crypto/__init__.py b/windows/crypto/__init__.py index 220e17f..880a02d 100644 --- a/windows/crypto/__init__.py +++ b/windows/crypto/__init__.py @@ -1 +1,4 @@ -from windows.crypto.certificate import * \ No newline at end of file +from windows.generated_def import X509_ASN_ENCODING, PKCS_7_ASN_ENCODING +from windows.crypto.certificate import * + +DEFAULT_ENCODING = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING \ No newline at end of file diff --git a/windows/crypto/certificate.py b/windows/crypto/certificate.py index 4b68ec8..1fffc90 100644 --- a/windows/crypto/certificate.py +++ b/windows/crypto/certificate.py @@ -1,29 +1,67 @@ +import itertools + import windows from windows import winproxy from windows.generated_def import * +class EHCERTSTORE(HCERTSTORE): + # def __str__(self): + # return "CertStore()" + + @property + def certs(self): + res = [] + last = None + while True: + try: + cert = winproxy.CertEnumCertificatesInStore(self, last) + except winproxy.Kernel32Error as e: + if (e.winerror & 0xffffffff) in (CRYPT_E_NOT_FOUND,): + return tuple(res) + raise + # Need to duplicate as CertEnumCertificatesInStore will free the context 'last' + ecert = windows.crypto.CertificatContext(cert[0]) + res.append(ecert.duplicate()) + last = ecert + raise RuntimeError("Out of infinit loop") + +# Why PCCERT_CONTEXT (pointer type) and not _CERT_CONTEXT ? class CertificatContext(PCCERT_CONTEXT): _type_ = PCCERT_CONTEXT._type_ # Not herited from PCCERT_CONTEXT + + def __repr__(self): + return '<{0} "{1}" serial="{2}">'.format(type(self).__name__, self.name, self.serial) + + @property def raw_serial(self): serial_number = self[0].pCertInfo[0].SerialNumber return [(c & 0xff) for c in serial_number.pbData[:serial_number.cbData][::-1]] - def serial_string(self): + @property + def serial(self): serial_number = self[0].pCertInfo[0].SerialNumber - serial_bytes = [(c & 0xff) for c in serial_number.pbData[:serial_number.cbData][::-1]] + serial_bytes = self.raw_serial return " ".join("{:02x}".format(x) for x in serial_bytes) + def get_name(self, flags=0): size = winproxy.CertGetNameStringA(self, CERT_NAME_SIMPLE_DISPLAY_TYPE, flags, None, None, 0) namebuff = ctypes.c_buffer(size) size = winproxy.CertGetNameStringA(self, CERT_NAME_SIMPLE_DISPLAY_TYPE, flags, None, namebuff, size) return namebuff[:-1] - def get_issuer_name(self): + name = property(get_name) + + @property + def issuer_name(self): return self.get_name(flags=CERT_NAME_ISSUER_FLAG) + @property + def store(self): + return EHCERTSTORE(self[0].hCertStore) + def get_raw_chain(self): chain_context = PCCERT_CHAIN_CONTEXT() @@ -39,9 +77,9 @@ class CertificatContext(PCCERT_CONTEXT): chain_para.cbSize = sizeof(chain_para) chain_para.RequestedUsage = cert_usage - winproxy.CertGetCertificateChain(None, self.cert, None, self.cert.hCertStore, byref(chain_para), 0, None, byref(chain_context)) + winproxy.CertGetCertificateChain(None, self, None, self[0].hCertStore, byref(chain_para), 0, None, byref(chain_context)) return CertficateChain(chain_context) - + def duplicate(self): res = winproxy.CertDuplicateCertificateContext(self) # Check what the doc says: the pointer returned is actually the PCERT in parameter @@ -51,7 +89,17 @@ class CertificatContext(PCCERT_CONTEXT): if not ctypes.cast(res, PVOID).value == ctypes.cast(self, PVOID).value: raise ValueError("CertDuplicateCertificateContext did not returned the argument (check doc)") return self - + + def enum_properties(self): + prop = 0 + res = [] + while True: + prop = winproxy.CertEnumCertificateContextProperties(self, prop) + if not prop: + return res + res.append(prop) + raise RuntimeError("Unreachable code") + class CertficateChain(object):