使用 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;
}
我有可用的命令行:
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;
}