首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PKCS#7签名验证

PKCS#7签名验证
EN

Stack Overflow用户
提问于 2013-10-16 18:11:02
回答 1查看 4.8K关注 0票数 10

我正在尝试为PDF实现签名验证。这是一个很大的话题,所以我一步一步地去做,首先我尝试在我自己签名的PDF文件中返回一个正数,使用当前Acrobat的所有默认值--这应该是摘要的SHA256,以及一个PKCS7分离的签名。因此,我研究了openssl,通过读取PDF中给出的字节范围并调用SHA256_*函数,我有一个可以比较的散列。因此,现在我需要读取证书数据等,并使用PKCS7_*函数。这个看起来是我想要的:

代码语言:javascript
复制
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_ctrl头中有一些pkcs7.h函数:-

代码语言:javascript
复制
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中解析的数据值调用此函数?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-10-25 11:16:01

好吧,发现这一切都是很难的。你就是这样做的,这样别人才能更容易地学习。

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

代码语言:javascript
复制
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,您不需要自己运行任何摘要。

但是等等,如果你尝试这个,它是行不通的!为什么?因为验证同时具有信任和完整性。此外,您还需要通过向商店添加证书来建立信任,这也是复杂和无文档的。如果您想要细粒度的结果,您需要通过证书存储设置一个回调,如下所示:

代码语言:javascript
复制
X509_VERIFY_PARAM_set_flags(certificateStore->param, X509_V_FLAG_CB_ISSUER_CHECK);
X509_STORE_set_verify_cb_func(certificateStore, verificationCallback);

哪里

代码语言:javascript
复制
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;
}

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

代码语言:javascript
复制
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;
}
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19410688

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档