交叉发布以提高可见性: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标头中有这些副本。 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
中提供的内容无关)。
注意仅在CERT_CHAIN_PARA_HAS_EXTRA_FIELDS时可以使用此成员
是在包含Wincrypt.h之前使用#define指令定义的。
如果定义了此值,则应用程序必须将所有未使用的字段清零。
更新PCERT_CONTEXT
是CERT_CONTEXT *
的typedef。您的Java定义实际上会使其成为CERT_CONTEXT **
,至少w / r / t将其作为参数传递。如果需要本机CERT_CONTEXT *
,请使用Java CERT_CONTEXT
作为参数类型。将指针字段嵌入结构中可以有效地为被调用方提供您希望传递的值的地址,而不是您真正想要传递的指针值。
通常,除非定义的结构字段必须为<Structure>.ByReference
类型,否则应省略struct *
表示法。