获取 Java 代码以触发 Windows 的 CTL 查找/CTL 到受信任的根 CA 迁移

问题描述 投票:0回答:1

我有一个调用

System.setProperty("javax.net.ssl.trustStoreType", "WINDOWS-ROOT");
的 Java 应用程序,从而触发 JRE 最终调用 Windows
CertOpenSystemStore
方法,然后枚举并加载来自 HKLM 支持的受信任根证书颁发机构证书存储区的证书以用于其内部验证。

这很棒,除了处理非常干净/最近安装的 Windows 计算机时,其中受信任的根证书颁发机构仅包含约 16 个条目。我最近才了解到 Windows 的证书信任列表 (CTL) 功能,这是一种隐藏机制,可以根据 Windows 从 Windows 更新(或其他地方,如果被覆盖,例如通过 GPO)下载的受信任根列表来透明地检查证书链。这使得网络浏览器能够毫无怨言地与多个网站一起工作,并且数字签名的二进制文件能够在没有警告的情况下执行。某些操作(例如访问 Internet Explorer(但不是 Edge)中的站点)还会导致 CA 从 CTL 迁移到受信任的根证书颁发机构存储。

但是,我推断 CTL 机制不会在 Java 工作流程中触发,因为 Java 不会要求 Windows 验证 TLS 证书链,它只是根据从受信任的根证书颁发机构枚举的证书来验证该链(

 CertOpenSystemStore
)。调用
sun.security.validator.ValidatorException: PKIX path building failed: : sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
后最终结果是
HttpURLConnection::getOutputStream().write(postDataBytes);

有谁知道触发 Windows 的 CTL 到受信任的根证书颁发机构迁移机制的方法吗?显然,如果有一种本机 Java 方法可以做到这一点,那将是理想的,但即使有人知道什么 Windows C API 会触发此操作,所以我可以编写一些 JNI,这也比告诉用户的替代方案更好在 Internet Explorer 中访问站点,以确保其根 CA 受到 Java 应用程序的信任。

谢谢!

java ssl winapi
1个回答
0
投票

没有“java”方式可以完成您所要求的操作,您需要使用 C++ 或 C 代码来调用以下内容,并具有巴拿马附带的功能 项目。

import java.lang.invoke.MethodHandle;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

public class WindowsCertValidator {
    // Define the library path for Advapi32.dll and crypt32.dll (the libraries needed for Cert APIs)
    private static final String ADVAPI32 = "Advapi32";
    private static final String CRYPT32 = "Crypt32";

    // Foreign linker to access native functions
    private static final Linker linker = Linker.nativeLinker();

    // Define function signatures for CertOpenSystemStore and CertGetCertificateChain
    static final MethodHandle CertOpenSystemStore;
    static final MethodHandle CertGetCertificateChain;
    static final MethodHandle CertCloseStore;

    static {
        // Load the native methods using Panama Foreign API
        var lookup = SymbolLookup.loaderLookup();
        
        // CertOpenSystemStore (from crypt32.dll)
        CertOpenSystemStore = linker.downcallHandle(
                lookup.find("CertOpenSystemStoreA").orElseThrow(),
                FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS)
        );

        // CertGetCertificateChain (from crypt32.dll)
        CertGetCertificateChain = linker.downcallHandle(
                lookup.find("CertGetCertificateChain").orElseThrow(),
                FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS,
                                      ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.ADDRESS)
        );

        // CertCloseStore (from crypt32.dll)
        CertCloseStore = linker.downcallHandle(
                lookup.find("CertCloseStore").orElseThrow(),
                FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.JAVA_INT)
        );
    }

    public static MemorySegment openCertStore(String storeName) throws Throwable {
        MemorySegment storeNameSegment = SegmentAllocator.implicitAllocator()
                .allocateUtf8String(storeName);

        MemorySegment certStore = (MemorySegment) CertOpenSystemStore.invokeExact(MemoryAddress.NULL, storeNameSegment);
        if (certStore.address().toRawLongValue() == 0) {
            throw new IllegalStateException("Failed to open cert store");
        }
        return certStore;
    }

    public static void closeCertStore(MemorySegment certStore) throws Throwable {
        int success = (int) CertCloseStore.invokeExact(certStore, 0);
        if (success == 0) {
            throw new IllegalStateException("Failed to close cert store");
        }
    }

    public static void main(String[] args) {
        try {
            // Open the Trusted Root Certification Authorities store
            MemorySegment certStore = openCertStore("ROOT");
            System.out.println("Successfully opened Trusted Root Certification Authorities store.");

            // Normally, you would invoke CertGetCertificateChain here to trigger validation
            // and interact with the cert chain, using similar downcalls as CertOpenSystemStore.

            // Close the cert store when done
            closeCertStore(certStore);
            System.out.println("Successfully closed the cert store.");
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.