使用 openssl 在 C 中使用 PEM 证书以 DER 格式验证 PKCS7

Verify PKCS7 in DER format using PEM certificate in C using openssl

我有可用的命令行:

openssl cms -inform DER -cmsout -in sod.pkcs7 -verify -CAfile cert.pem

但我正在努力用 C(在 iOS 下)来完成这项工作。

我找到了使用 PKCS7_verify 但带有 SMIME 信息的示例。所以我想我应该使用 CMS_verify 但不确定...

我的测试:

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>              /* open() */

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/pkcs7.h>
#include <openssl/safestack.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>     /* X509_PURPOSE_ANY */
#include <openssl/x509_vfy.h>

#include <openssl/cms.h>
#include <openssl/pem.h>

int testssl(const char* cert_path, const char* sod_path)
{
    X509_STORE *trusted_store;
    X509_STORE_CTX *ctx;
    STACK_OF(X509) *cert_chain;
    X509 *root, *intermediate, *signing;
    BIO *in;
    int purpose, ret;
    X509_VERIFY_PARAM *verify_params;
    PKCS7 *p7;
    FILE *fp;
    int fd;

    SSL_library_init();
    SSL_load_error_strings();

    fd = open(sod_path, O_RDONLY);
    in = BIO_new_fd(fd, BIO_NOCLOSE);
    p7 = SMIME_read_PKCS7(in, NULL);

    cert_chain = sk_X509_new_null();

    fp = fopen(cert_path, "r");
    root = PEM_read_X509(fp, NULL, NULL, NULL);
    sk_X509_push(cert_chain, root);

    // <C> not sure what this is good for...
    //    fp = fopen("intermediate.pem", "r");
    fp = fopen(cert_path, "r");
    intermediate = PEM_read_X509(fp, NULL, NULL, NULL);
    sk_X509_push(cert_chain, intermediate);

    trusted_store = X509_STORE_new();
    X509_STORE_add_cert(trusted_store, root);

//    fp = fopen("signing-ext-no-smimesign.pem", "r");
//    signing = PEM_read_X509(fp, NULL, NULL, NULL);


    BIO *cont = NULL;
    CMS_ContentInfo *cms = NULL;
    //    cms = d2i_CMS_bio(in, NULL);
    //    cms = PEM_read_bio_CMS(in, NULL, NULL, NULL);
    cms = SMIME_read_CMS(in, &cont);
    // <C> all of above return NULL thus CMS_verify() fails

    // 1st attempt
    //
    ret = CMS_verify(cms, cert_chain,trusted_store, NULL, NULL, 0);
    printf("CMS_verify: %s\n", ret ? "OK" : "failure");


    // 2nd attempt
    //
    ret = PKCS7_verify(p7, cert_chain, trusted_store, NULL, NULL, 0);
    printf("Verification without specifying params: %s\n", ret ? "OK" : "failure");

    /* Now set a suitable OpenSSL's "purpose", or disable its checking.
    * Note: since OpenSSL 1.1.0, we'd not need `ctx`, but could just use:
    * verify_params = X509_STORE_get0_param(trusted_store); */

    ctx = X509_STORE_CTX_new();
    X509_STORE_CTX_init(ctx, trusted_store, signing, cert_chain);
    verify_params = X509_STORE_CTX_get0_param(ctx);
    purpose = X509_PURPOSE_get_by_sname("crlsign"); /* Or: purpose = X509_PURPOSE_ANY */
    X509_VERIFY_PARAM_set_purpose(verify_params, purpose);
    X509_STORE_set1_param(trusted_store, verify_params);

    // 3rd attempt
    //
    ret = PKCS7_verify(p7, cert_chain, trusted_store, NULL, NULL, 0);
    printf("Verification with 'crlsign' purpose: %s\n", ret ? "OK" : "failure");
    return 0;
}

想通了。

int testcms (const char* cert_path, const char* sod_path)
{
    BIO *in = NULL, *out = NULL, *tbio = NULL, *cont = NULL;
    X509_STORE *st = NULL;
    X509 *cacert = NULL;
    CMS_ContentInfo *cms = NULL;

    int ret = 1;

    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();

    st = X509_STORE_new();

    tbio = BIO_new_file(cert_path, "r");

    if (!tbio) {
        fprintf(stderr, "Cert file not opened: path=%s;\n", cert_path);
        goto err;
    }

    cacert = PEM_read_bio_X509(tbio, NULL, 0, NULL);

    if (!cacert) {
        fprintf(stderr, "PEM_read_bio_X509 FAILED: cert.path=%s;\n", cert_path);
        goto err;
    }

    if (!X509_STORE_add_cert(st, cacert)) {
        fprintf(stderr, "X509_STORE_add_cert FAILED: cert.path=%s;\n", cert_path);
        goto err;
    }

    in = BIO_new_file(sod_path, "r");

    if (!in) {
        fprintf(stderr, "PKCS7 file not opened: path=%s;\n", sod_path);
        goto err;
    }

    //cms = SMIME_read_CMS(in, &cont);
    cms = d2i_CMS_bio(in, NULL);

    if (!cms) {
        fprintf(stderr, "SMIME_read_CMS FAILED: pkcs7.path=%s;\n", sod_path);
        goto err;
    }

    if (!CMS_verify(cms, NULL, st, cont, NULL, 0)) {
        fprintf(stderr, "Verification Failure\n");
        goto err;
    }

    fprintf(stderr, "Verification Successful\n");

    ret = 0;

err:

    if (ret) {
        fprintf(stderr, "Error Verifying Data\n");
        ERR_print_errors_fp(stderr);
    }

    CMS_ContentInfo_free(cms);
    X509_free(cacert);
    BIO_free(in);
    BIO_free(out);
    BIO_free(tbio);
    return ret;
}