代码之家  ›  专栏  ›  技术社区  ›  Zohar81

了解pkcs7块在使用openssl进行验证期间失败的原因

  •  3
  • Zohar81  · 技术社区  · 7 年前

    我有一个PKCS#7 Der格式的文件名为 p7 mroot.der.cer 它与p7链的根证书匹配。

    First - convert my mroot trusted cert file to pem format. 
    openssl x509 -in mroot.der.cer -inform der -outform PEM -out mroot.pem.cer
    
    Second - verify the root chain using mroot.pem.cer
    openssl  smime -verify -CAfile mroot.pem.cer -in p7 -inform DER -out blabla
    

    然而,我得到了以下错误:

    验证失败 140735569544136:错误:21075075:PKCS7例程:PKCS7_验证:证书验证错误:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/PKCS7/pk7_smime.c:343:验证错误:无法获取本地颁发者证书

    -noverify 但是得到了一个不同的错误。

    验证失败 140735569544136:错误:21071065:PKCS7例程:PKCS7_签名验证:摘要失败:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/PKCS7/pk7_doit.c:1084: 140735569544136:错误:21075069:PKCS7例程:PKCS7_验证:签名失败:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/PKCS7/pk7_smime.c:412:

    pkcs7结构应该很好,因为我已经从PE文件中提取了它 iexlorer.exe 我从它的链中提取了根证书,并将其称为可信证书。

    附笔。 为了观察相同的故障,我已将文件上载到以下链接:

    https://ufile.io/vrqpt

    https://ufile.io/ajgex

    1 回复  |  直到 7 年前
        1
  •  2
  •   Reinier Torenbeek    7 年前

    上载的示例文件有一些属性,这些属性会阻止对其进行验证。

    p7 文件已于过期 Apr 24 22:33:39 2014 GMT . 如果要验证链,则必须禁用过期日期检查。这是通过使用verify标志以编程方式完成的 X509_V_FLAG_NO_CHECK_TIME -no_check_time 对于OpenSSL smime -verify

    然后,你的“信任之根”,在 mroot.pem.cer Microsoft Time-Stamp PCA 证书的签署人 p7 文件链到 Microsoft Code Signing PCA 证明书

    trust.pem.cer . 该证书不是自签名的:其颁发者是 Microsoft Root Certificate Authority . 如果您希望这样的证书位于链的末尾,则必须指出您正在使用所谓的部分链。这是通过使用verify标志以编程方式完成的 X509_V_FLAG_PARTIAL_CHAIN ,或选择 -partial_chain smime-验证 工具。

    此外,PKCS7验证的OpenSSL实现似乎要求您的证书包含S/MIME签名的扩展密钥用法,而您的证书不包含该用法。看起来可以通过为OpenSSL设置代码签名目的来解决这个问题 X509_STORE . OpenSSL 工具不公开此类设置,因此您必须通过设置 XKU_CODE_SIGN XKU

    下面的代码段(省略返回代码检查)成功验证了您数据库中的证书链 p7 文件,但不是签名:

    BIO *bio_p7 = BIO_new_file("p7", "r");
    PKCS7 *p7 = d2i_PKCS7_bio(bio_p7, NULL);
    X509_STORE *store = X509_STORE_new();
    X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
    X509_LOOKUP_load_file(lookup, "trust.pem.cer", X509_FILETYPE_PEM);
    X509_STORE_set_purpose(store, XKU_CODE_SIGN); /* see caveat above */
    X509_VERIFY_PARAM_set_flags(
        X509_STORE_get0_param(store),
        X509_V_FLAG_NO_CHECK_TIME | X509_V_FLAG_PARTIAL_CHAIN);
    int retcode = PKCS7_verify(p7, NULL, store, NULL, NULL, PKCS7_NOSIGS);
    

    verify_pe_pkcs7() in osslsigncode.c 给出了执行此操作的示例代码。它的 PKCS7_verify() 调用不会验证证书链,但会检查签名。这需要提取散列,散列存储在p7中的Microsoft特定元素中,类型为 SpcIndirectDataContent ,正如下面的@dave_thompson_085所指出的。可以验证接管该散列的签名。为了完成验证,您还需要重新计算PE文件本身的哈希值,并将其与p7中的哈希值进行比较。

    这个答案基于OpenSSL 1.1.1。刚才,我意识到您正在使用libressl,它基于(更)旧的OpenSSL版本。这在你的情况下可能不起作用。例如,对于我的libressl版本 工具不支持 partial_chain no_time_check 选项,因为它们是在OpenSSL 1.1.0分支中引入的。