import ctypes
from ctypes import wintypes

# Định nghĩa các hằng số từ Windows API
CRYPTUI_SELECT_LOCATION_COLUMN = 0x00000001
PKCS_7_ASN_ENCODING = 0x00010000
X509_ASN_ENCODING = 0x00000001
MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING

# Load các thư viện cần thiết
crypt32 = ctypes.WinDLL('crypt32.dll')
cryptui = ctypes.WinDLL('cryptui.dll')
user32 = ctypes.WinDLL('user32.dll')

def select_certificate_windows():
    """
    Gọi giao diện chọn chứng chỉ chuẩn của Windows.
    Trả về dữ liệu DER của chứng chỉ đã chọn hoặc None.
    """
    # 1. Mở "My" store (Chứng chỉ cá nhân)
    # 0x00000001 = CERT_SYSTEM_STORE_CURRENT_USER
    # "My" là tên store mặc định của người dùng
    h_store = crypt32.CertOpenSystemStoreW(None, "My")
    if not h_store:
        print("Không thể mở Windows Certificate Store.")
        return None

    try:
        # 2. Gọi hàm hiện dialog chọn chứng chỉ
        # HWND hwnd, LPCWSTR pwszTitle, LPCWSTR pwszDisplayString, DWORD dwFlags, ...
        p_cert_context = cryptui.CryptUIDlgSelectCertificateFromStore(
            h_store,
            None,
            "Chọn chứng chỉ ký số",
            "Vui lòng chọn chứng chỉ từ USB Token của bạn để thực hiện ký:",
            0,
            0,
            None
        )

        if p_cert_context:
            # 3. Trích xuất dữ liệu chứng chỉ (DER)
            # pCertContext là một pointer đến STRUCTURE CERT_CONTEXT
            # Chỗ này cần cẩn thận với mapping memory
            from ctypes import Structure, POINTER, c_void_p, c_char_p, c_uint32
            
            class CERT_CONTEXT(Structure):
                _fields_ = [
                    ("dwCertEncodingType", wintypes.DWORD),
                    ("pbCertEncoded", POINTER(ctypes.c_byte)),
                    ("cbCertEncoded", wintypes.DWORD),
                    ("pCertInfo", c_void_p),
                    ("hCertStore", c_void_p),
                ]

            cert_ctx = POINTER(CERT_CONTEXT).from_address(p_cert_context).contents
            cert_der = ctypes.string_at(cert_ctx.pbCertEncoded, cert_ctx.cbCertEncoded)
            
            # Giải phóng context sau khi lấy dữ liệu
            crypt32.CertFreeCertificateContext(p_cert_context)
            return cert_der
        else:
            print("Bạn đã hủy chọn chứng chỉ.")
            return None
    finally:
        crypt32.CertCloseStore(h_store, 0)

if __name__ == "__main__":
    der = select_certificate_windows()
    if der:
        print(f"Đã chọn chứng chỉ. Độ dài: {len(der)} bytes")
        # Lưu ra file test
        with open("selected_cert.der", "wb") as f:
            f.write(der)
        print("Đã lưu chứng chỉ đã chọn vào file selected_cert.der")
