当前位置: 首页 > 知识库问答 >
问题:

PKCS#7签名验证

童冠玉
2023-03-14

我试图实现PDFS的签名验证。这是一个很大的主题,所以我一步一步地进行,首先,我试图在我自己签名的PDF中实际返回一个正值,使用当前Acrobat的所有默认值--对于摘要,应该是SHA256和PKCS7分离签名。因此,我破解了openssl,通过读取PDF中给出的字节范围并调用SHA256_*函数,我得到了一个哈希值来进行比较。因此,现在我需要读取证书数据等,并使用PKCS7_*函数。这个看起来就是我想要的:

int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, BIO *indata, BIO *out, int flags);

如文档中所示。除了上述文档没有告诉我如何构造这些东西。好的,所以我认为bio*indata可以用这里的一些函数和使用这些函数的证书数组来创建(尽管还没有计算出精确的细节),但是pkcs7*p7或者调用的stack_of(x)呢。我找不到任何文件化的方法来初始化这些结构。pkcs7.h头中有一些pkcs7_ctrl函数:-

long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg);

int PKCS7_set_type(PKCS7 *p7, int type);
int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other);
int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data);
int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey, const EVP_MD *dgst);
int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si);
int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *p7i);
int PKCS7_add_certificate(PKCS7 *p7, X509 *x509);
int PKCS7_add_crl(PKCS7 *p7, X509_CRL *x509);
int PKCS7_content_new(PKCS7 *p7, int nid);
int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx,
    BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si); 
int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, X509 *x509);

BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio);
int PKCS7_dataFinal(PKCS7 *p7, BIO *bio);
BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert);

但是如果没有一些指导方针,这看起来就不像是一个森林,开始盲目地在里面闲逛是有效的。

我是不是漏掉了一些明显的东西?如何使用从PDF中解析的数据值调用此函数?

共有1个答案

张承颜
2023-03-14

好吧,这一切都是(非常)艰难地找到的。你就是这样做的,这样别人就可以学得更容易。

假设我们有签名char*sig,其长度int sig_length,以及验证数据char*dataint data_length。(这里有一些PDF签名的细微之处,但这些在PDF规范中有很好的记录。)

OpenSSL_add_all_algorithms();
OpenSSL_add_all_digests();
EVP_add_digest(EVP_md5());
EVP_add_digest(EVP_sha1());
EVP_add_digest(EVP_sha256());

BIO* sig_BIO = BIO_new_mem_buf(sig, sig_length)
PKCS7* sig_pkcs7 = d2i_PKCS7_bio(sig_BIO, NULL);

BIO* data_BIO = BIO_new_mem_buf(data, data_length)
BIO* data_pkcs7_BIO = PKCS7_dataInit(sig_pkcs7, data_BIO);

// Goto this place in the BIO. Why? No idea!
char unneeded[1024*4];
while (BIO_read(dataPKCS7_BIO, unneeded, sizeof(buffer)) > 0);

int result;
X509_STORE *certificateStore = X509_STORE_new();
X509_STORE_CTX certificateContext;
STACK_OF(PKCS7_SIGNER_INFO) *signerStack = PKCS7_get_signer_info(sig_pkcs7);
int numSignerInfo = sk_PKCS7_SIGNER_INFO_num(signerStack);
for (int i=0; i<numSignerInfo; ++i) {
    PKCS7_SIGNER_INFO *signerInfo = sk_PKCS7_SIGNER_INFO_value(signerStack, i);
    result = PKCS7_dataVerify(certificateStore, &certificateContext, data_pkcs7_BIO, sig_pkcs7, signerInfo);
}

X509_STORE_CTX_cleanup(&certificateContext);
BIO_free(sig_BIO);
BIO_free(data_BIO);
BIO_free(data_pkcs7_BIO);
PKCS7_free(sig_pkcs7);
X509_STORE_free(certificateStore);

完成这项工作的函数实际上是PKCS7_dataVerify,您不需要自己运行任何摘要。

X509_VERIFY_PARAM_set_flags(certificateStore->param, X509_V_FLAG_CB_ISSUER_CHECK);
X509_STORE_set_verify_cb_func(certificateStore, verificationCallback);
static int verificationCallback(int ok, X509_STORE_CTX *ctx) {
    switch (ctx->error)
    {
        case X509_V_ERR_INVALID_PURPOSE: //...
        case X509_V_ERR_CERT_HAS_EXPIRED: //...
        case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: //... 
        case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: //...
        // ... etc
        default: break;
    }
    return ok;
}

您可以将错误设置为ok,并告诉它进行验证,例如,如果要忽略过期证书:

static int verificationCallback(int ok, X509_STORE_CTX *ctx) {
    switch (ctx->error)
    {
        case X509_V_ERR_CERT_HAS_EXPIRED: 
            X509_STORE_CTX_set_error(ctx, X509_V_OK);
            ok = 1;
            break;
    }
    return ok;
}
 类似资料:
  • 我能够成功提取PKCS#7容器数据,并使用以下代码验证数据类型代码值是否为: 然而,我现在已经到了一个我被卡住的地步。如何从PKCS#7有效载荷获取X.509证书数据?我可以看到数据结构应该包含证书链数据。它的数据类型是,我想一旦我在内存中获得X.509证书数据,我就可以找到使用OpenSSL的方法的代码。我只是不知道怎么做那部分。 我找到了这个关于在OSX/IOS上验证收据的资源,它涉及到许多相

  • 我想做的是: 使用证书使用openssl对zip文件进行签名,并创建签名文件(PKCS#7) 我安装了openssl并打开了控制台 我创建了一个rsa密钥(openssl genrsa-out key.pem 2048) 我创建了一个请求(openssl req-batch-sha256-new-key key.pem-out request.pem-subj'/c=../st=../l=../o

  • 我想用pdf摘要签署pdf文件。我使用下面的代码创建了散列, 最后,我需要把这个签名附在我的PDF上。我找到了一个解决方案,从文件摘要创建pkcs7签名,但在链接中使用的算法是SHA256with RSA。我的privatekey是使用EC算法生成的,我需要使用SHA256withECDSA。是否可以使用SHA256withECDSA对哈希进行签名,并使用PDFBox ExternalSignin

  • 问题内容: 在Java中需要有关加密例程的帮助。 给定PKCS#7签名,我想针对受信任的存储验证它包含的所有证书。我假设签名中包含的所有证书均以正确的顺序形成有效的证书路径(或链,无论如何),因此 最上面的(#0)是签名证书; 下一个(#1)是中间证书,用于签署#0; 下一个(#2)是另一个中间证书,用于签署#1; 等等。 最后一个证书(#N)由CA签名。 到目前为止,这是我设法破解的: 所以问题

  • 为了在OpenSSL中签名证书,我使用函数,向它提供一个请求(作为)、一个签名密钥和一个摘要。 现在我有我的签名密钥存储在HSM中,所以我无法提取它来签名证书。不幸的是,PKCS#11没有提供的等价物。它只有系列函数,这些函数对原始数据进行操作,而不是对证书进行操作。 有人能帮助我使用示例C/C++代码如何使用PKCS#11签署一个用OpenSSL创建的证书吗?