CryptVerifyMessageSignature 返回带有附加标头的原始消息,为什么?

问题描述

我使用 signtool 生成一个 PKCS#7 包,其中包含:

  • 留言
  • 数字签名
  • 签署者证书。

构建此 PKCS#7 文件的命令如下:

$signtool sign /f signer_certificate.pfx /p ∙∙∙ /fd sha512 /p7 . /p7ce Embedded /p7co 0 my_file

这会以 DER 格式 (ASN.1) 输出名为 my_file.p7文件

现在我编写了一个 C++ 程序来验证我们可以从包中提取证书和消息。为此,我调用 CryptVerifyMessageSignature

#include <windows.h>
#include <wincrypt.h>
#include <vector>

std::vector<BYTE> InputPkcs7Data;
// read input file into InputPkcs7Data (CreateFile,GetFileSizeEx,ReadFile).
// out of scope.

CRYPT_VERIFY_MESSAGE_Para Parameters = {};
Parameters.cbSize = sizeof(Parameters);
Parameters.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
Parameters.hCryptProv = NULL;
Parameters.pfnGetSignerCertificate = NULL;
Parameters.pvGetArg = NULL;

DWORD DecodedMessageLength = 0;
PCCERT_CONTEXT SignerCertificate = NULL;
BOOL Result = CryptVerifyMessageSignature(&Parameters,InputPkcs7Data.data(),InputPkcs7Data.size(),NULL,&DecodedMessageLength,&SignerCertificate);

std::vector<BYTE> DecodedMessage;
DecodedMessage.assign(DecodedMessageLength,0);

Result = CryptVerifyMessageSignature(&Parameters,DecodedMessage.data(),&SignerCertificate);

if (Result == FALSE) {
    wprintf(L"Error: %lx\n",GetLastError());
}
else
{
    // inspect Memory
    CertFreeCertificateContext(SignerCertificate);
}

我的问题是,即使 CryptVerifyMessageSignature 成功,我进入 DecodedMessage内容也不是原始消息。总是有几个前导字节起初看起来像垃圾,但包含有关消息长度的信息。我设法理解 DecodedMessage 的顺序如下,具体取决于原始消息的长度:

  • OriginalMessageLength ⩽ 127 字节:
    • 0x04
    • 表示消息长度的一个字节
    • 消息
  • 128 字节 ⩽ OriginalMessageLength ⩽ 255 字节:
    • 0x04
    • 0x81
    • 表示消息长度的一个字节
    • 消息
  • 256 字节 ⩽ OriginalMessageLength ⩽ 65535 字节:
    • 0x04
    • 0x82
    • 两个字节表示消息的长度,以 Big Endian 表示
    • 消息
  • 65536 字节 ⩽ OriginalMessageLength ⩽ 16777215 字节:
    • 0x04
    • 0x83
    • 三个字节表示消息的长度,以 Big Endian 表示
    • 消息
  • OriginalMessageLength ⩾ 16777216 字节:
    • 0x04
    • 0x84
    • 四个字节,以 Big Endian 表示消息的长度
    • 消息。 (我没有尝试处理大于 4GiB 的消息。

这真的出乎我的意料。这个“头信息”从何而来,有什么方法可以避免在调用 CryptVerifyCertificate 时得到它?

是否可能 signtool 不是生成签名消息的正确工具?

解决方法

解码后的消息似乎是一个 OCTET STRING,根据 https://en.wikipedia.org/wiki/X.690#DER_encoding 使用可分辨编码规则进行编码。 04 是 OCTET STRING 的标签号。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...