CertGetCertificateChain - 无效的内存访问

时间:2018-01-19 19:51:09

标签: java jna cryptoapi

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

我正在为Crypt32 lib中的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;

但我仍然如上所述得到了失败。

EDIT2:

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 {
        }
    }

1 个答案:

答案 0 :(得分:1)

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

  

注意只有在CERT_CHAIN_PARA_HAS_EXTRA_FIELDS时才能使用此成员   在包含Wincrypt.h之前使用#define指令定义。   如果定义了此值,则应用程序必须将所有未使用的字段归零。

<强>更新

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

通常,您应该省略<Structure>.ByReference符号,除非您要定义的结构字段需要struct *类型。