java - CertGetCertificateChain - 无效的内存访问

标签 java jna cryptoapi

交叉发布以提高可见性:https://groups.google.com/forum/#!topic/jna-users/qfkoxPwA-r8

我正在为 Crypt32 库中的 CertGetCertificateChain 方法创建包装器,我希望获得帮助来解决导致崩溃的“无效内存访问”问题。

包装器的签名是:

boolean CertGetCertificateChain(Pointer hChainEngine, PCERT_CONTEXT pCertContext, Pointer pTime,
            Pointer hAdditionalStore, CERT_CHAIN_PARA.ByReference pChainPara, int dwFlags, Pointer pvReserved,
            PointerByReference ppChainContext);

我使用的结构是:

public static class CERT_CHAIN_PARA extends Structure {
    public int cbSize;
    public CERT_USAGE_MATCH RequestedUsage;

    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("cbSize", "RequestedUsage");
    }


    public static class ByReference extends CERT_CHAIN_PARA implements Structure.ByReference {}
}


public static class CERT_USAGE_MATCH extends Structure {
    public int dwType;
    public CERT_ENHKEY_USAGE Usage;


    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("dwType", "Usage");
    }


    public static class ByReference extends CERT_USAGE_MATCH implements Structure.ByReference {}
}


public static class CERT_ENHKEY_USAGE extends Structure {
    public int cUsageIdentifier;
    public LPSTR.ByReference rgpszUsageIdentifier;


    @Override
    protected List<String> getFieldOrder() {
        return Arrays.asList("cUsageIdentifier", "rgpszUsageIdentifier");
    }


    public static class ByReference extends CERT_ENHKEY_USAGE implements Structure.ByReference {}
}

Wincrypt.h header 中有这些副本。 CERT_CHAIN_PARA 有其他成员,仅当启用标志时才会激活,而我尚未在 native 代码中启用它。所以,我避免在这里添加它们。

调用代码为:

CERT_CHAIN_PARA.ByReference pChainPara = new CERT_CHAIN_PARA.ByReference();
PointerByReference p = new PointerByReference();


pChainPara.cbSize = pChainPara.size();
pChainPara.RequestedUsage.dwType = WinCrypt.USAGE_MATCH_TYPE_AND;
pChainPara.RequestedUsage.Usage.cUsageIdentifier = 0;
pChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = null;


CertGetCertificateChain(null, pCertContext, null, null, pChainPara, 0, null, p);

调用 CertGetCertificateChain 时发生崩溃。我注意到的一件事是将 pChainPara 设置为 null 可以阻止它抛出内存访问异常和崩溃。但我不确定这是否是因为 pChainPara 结构已损坏,或者设置 null 是否会强制其提前失败并掩盖其他地方的问题。我已经检查了传入的结构的大小,它们与 native 代码中的大小相匹配。

如果我需要提供更多信息,请告诉我。一旦实现和测试,我将清理它并将证书工作流的包装器和结构贡献给 JNA。

编辑: 我尝试在 CERT_CHAIN_PARA 中添加其他成员,如下所示:

    public static class CERT_CHAIN_PARA extends Structure {

        public int cbSize;
        public CERT_USAGE_MATCH RequestedUsage;

        public CERT_USAGE_MATCH RequestedIssuancePolicy;
        public int dwUrlRetrievalTimeout;
        public boolean fCheckRevocationFreshnessTime;
        public int dwRevocationFreshnessTime;
        public FILETIME pftCacheResync;
        public CERT_STRONG_SIGN_PARA.ByReference pStrongSignPara;
        public int dwStrongSignFlags;

        @Override
        protected List<String> getFieldOrder() {
            //          return Arrays.asList("cbSize", "RequestedUsage");
            return Arrays.asList("cbSize", "RequestedUsage","RequestedIssuancePolicy","dwUrlRetrievalTimeout","fCheckRevocationFreshnessTime",
                    "dwRevocationFreshnessTime","pftCacheResync","pStrongSignPara","dwStrongSignFlags");
        }

        public static class ByReference extends CERT_CHAIN_PARA implements Structure.ByReference {

        }
    }

    public static class CERT_STRONG_SIGN_SERIALIZED_INFO extends Structure {
        DWORD dwFlags;
        LPWSTR pwszCNGSignHashAlgids;
        LPWSTR pwszCNGPubKeyMinBitLengths;

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("dwFlags", "pwszCNGSignHashAlgids", "pwszCNGPubKeyMinBitLengths");
        }

        public static class ByReference extends CERT_STRONG_SIGN_SERIALIZED_INFO implements Structure.ByReference {
        }
    }

    public static class DUMMYUNIONNAME extends Union {
        Pointer pvInfo;
        CERT_STRONG_SIGN_SERIALIZED_INFO.ByReference pSerializedInfo;
        LPSTR pszOID;
    }

    public static class CERT_STRONG_SIGN_PARA extends Structure {
        public int cbSize;
        public int dwInfoChoice;

        public DUMMYUNIONNAME union;

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("cbSize", "dwInfoChoice", "union");
        }

        public static class ByReference extends CERT_STRONG_SIGN_PARA implements Structure.ByReference {
        }
    }

    public static class FILETIME extends Structure {

        public int dwLowDateTime;
        public int dwHighDateTime;

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("dwLowDateTime", "dwHighDateTime");
        }

        public static class ByReference extends FILETIME implements Structure.ByReference {
        }

        public static class ByValue extends FILETIME implements Structure.ByValue {
        }
    }
}

并且修改了调用代码以设置其余成员:

pChainPara.RequestedIssuancePolicy.Usage.cUsageIdentifier = 0;
pChainPara.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = null;

pChainPara.dwUrlRetrievalTimeout = 0;
pChainPara.fCheckRevocationFreshnessTime = false;
pChainPara.dwRevocationFreshnessTime = 0;
pChainPara.pftCacheResync.dwHighDateTime = 0;
pChainPara.pftCacheResync.dwLowDateTime = 0;

pChainPara.pStrongSignPara = null;

但是我仍然遇到上面提到的失败。

编辑2:

PCERT_CONTEXT context = CryptUIDlgSelectCertificateFromStore(store, hwnd,
                "", "", 2, 0, null);

    public static class CERT_CONTEXT extends Structure {

        public int dwCertEncodingType;
        public Pointer pbCertEncoded;
        public int cbCertEncoded;
        public Pointer pCertInfo;
        public Pointer hCertStore;

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("dwCertEncodingType", "pbCertEncoded", "cbCertEncoded", "pCertInfo", "hCertStore");
        }

        public static class ByReference extends CERT_CONTEXT implements Structure.ByReference {
        }
    }

    public static class PCERT_CONTEXT extends Structure {

        public CERT_CONTEXT.ByReference certContext;

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("certContext");
        }

        public static class ByReference extends PCERT_CONTEXT implements Structure.ByReference {
        }

        public static class ByValue extends PCERT_CONTEXT implements Structure.ByValue {
        }
    }

最佳答案

您很可能需要定义 CERT_CHAIN_PARA 的其余部分结构,因为它的预期大小取决于编译时变量(与您在 cbSize 中提供的内容无关)。

Note This member can be used only if CERT_CHAIN_PARA_HAS_EXTRA_FIELDS is defined by using the #define directive before including Wincrypt.h. If this value is defined, the application must zero all unused fields.

更新

PCERT_CONTEXTCERT_CONTEXT * 的 typedef 。您的 Java 定义实际上将使其成为 CERT_CONTEXT ** ,至少 w/r/t 将其作为参数传递。如果您需要原生CERT_CONTEXT * ,使用Java CERT_CONTEXT作为参数类型。在结构中嵌入指针字段可以有效地为被调用者提供您希望传递的值的地址,而不是您真正想要传递的指针值。

一般来说,您应该省略 <Structure>.ByReference符号除非您定义的结构字段需要为 struct * 类型.

关于java - CertGetCertificateChain - 无效的内存访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48348550/

相关文章:

Java & Tomcat : Severe Error starting obfuscated app w/hibernate inside

java - DLL 导出查看器显示函数的完整签名 - 无法从 Java 调用它们

java - 在 Java 中将 HCURSOR 保存到 BufferedImage

c++ - 使用 Openssl 和 C++ 从公钥中提取模数和指数

c# - Ubuntu 16.04 上的 System.Security.Cryptography.Csp

java - 创建接受多种参数类型的通用函数

java.lang.NoClassDefFoundError : Could not initialize class weblogic. wsee.jaxws.spi.WLSProvider

c - HMAC-MD5 与 CryptoApi

java - 无法使用 JavaFX 获取标签来更新其文本

java - bundle -NativeCode : header in MANIFEST file give "Error: An unexpected error occurred while trying to open file pr.jar"