CertGetCertificateChain - 无效的内存访问

CertGetCertificateChain - Invalid memory access

Cross-posting 可见度:https://groups.google.com/forum/#!topic/jna-users/qfkoxPwA-r8

我正在为 Crypt32 库中的 CertGetCertificateChain 方法创建一个包装器,我想获得解决导致崩溃的 'Invalid Memory Access' 问题的帮助。

包装器的签名是:

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.hheader中有副本。 CERT_CHAIN_PARA 有其他成员只有在启用标志时才会激活,而我没有在本机代码中启用它。所以,我避免在这里添加它们。

调用代码为:

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 会强制它提前失败并掩盖其他地方的问题。我检查了传入的结构的大小,它们与本机代码中的大小匹配。

如果我需要提供更多信息,请告诉我。一旦实施和测试,我将清理它并将证书工作流的包装器和结构贡献给 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 * 的类型定义。您的 Java 定义实际上将使其成为 CERT_CONTEXT **,至少 w/r/t 将其作为参数传递。如果需要原生CERT_CONTEXT *,参数类型就用JavaCERT_CONTEXT。在结构中嵌入指针字段可以有效地为被调用方提供您希望传递的值的 地址,而不是您真正想要传递的指针值。

一般来说,你应该省略 <Structure>.ByReference 符号 除非你正在定义一个需要 struct *.[=20= 类型的结构字段 ]