使用OpenSSL创建包含CRL的CMS signedData
前提:
已安装vscode、openssl
撤销rsacert-plus-revoke.crt
配置CRL服务器:在准备放crl.pem的位置终端
python3 -m http.server
编辑openssl.cnf配置crl分发点
[ v3_ca ]
# ... other settings ...
crlDistributionPoints = URI:http://localhost:8000/crl.pem
生成证书,openssl x509和openssl ca都可以颁发证书,但是需要在证书的扩展字段添加crl的颁发点,就需要使用openssl ca
生成csr
注:commonName不可为空,输入的是CN
openssl req -new -key rsakey2048.pem -out rsacert-plus.csr
openssl ca -extensions v3_ca -in rsacert-plus.csr -out rsacert-plus.crt
再生成一个被撤销的证书,一样的命令,但是commonName输入CN2
openssl req -new -key rsakey2048.pem -out rsacert-plus-revoke.csr
openssl ca -extensions v3_ca -in rsacert-plus-revoke.csr -out rsacert-plus-revoke.crt
由于配置文件里写死了cakey.pem的文件名
所以自己生成目录和目录下的文件,会在撤销时找./demoCA/private/cakey.pem
./demoCA/cacert.pem
创建目录和文件
mkdir demoCA
mkdir demoCA/newcerts
mkdir demoCA/private
touch demoCA/index.txt
echo 01 > demoCA/serial
echo 01 > demoCA/crlnumber
生成CA密钥和证书
cd ./demoCA/private
openssl req -newkey isa:2048 -nodes -keyout cakey.pem -x509 -days 365 -out cacert.pem
mv cacert.pem ../
撤销证书
cd ../..
openssl ca -revoke ./rsacert—plus-revoke.crt
生成crl
openssl ca -gencrl -out ./crl.pem
创建CMS
生成不含crl的cms
openssl cms -sign -in temp.txt -outform DER -signer rsacert-plus.crt -inkey rsakey2048.pem -out cms-plus.der
openssl不支持使用命令行创建包含crl的cms,需要自己编写代码来调用openssl的API来创建
查看openssl的安装路径:
which openssl
在vscode里编写代码,
#include <openssl/cms.h>
#include <openssl/bio.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/pem.h>
#include <openssl/err.h>
int add_crl_to_cms(const char *cms_in_path, const char *crl_path, const char *cms_out_path) {
BIO *cms_bio = NULL;
BIO *crl_bio = NULL;
BIO *out_bio = NULL;
X509_CRL *crl = NULL;
CMS_ContentInfo *cms = NULL;
int ret = 1; // 失败为1,成功为0
// 读取CMS文件
cms_bio = BIO_new_file(cms_in_path, "rb");
if(!cms_bio){
fprintf(stderr, "读取cms失败\n");
goto err;
}
cms = d2i_CMS_bio(cms_bio, NULL);
if(!cms){
fprintf(stderr, "解析cms失败\n");
goto err;
}
// 读取CRL文件
crl_bio = BIO_new_file(crl_path, "rb");
if(!crl_bio){
fprintf(stderr, "读取crl失败\n");
goto err;
}
crl = PEM_read_bio_X509_CRL(crl_bio, NULL, 0, NULL);
if(!crl){
fprintf(stderr, "解析crl失败\n");
goto err;
}
// 添加CRL到CMS
if(!CMS_add0_crl(cms, crl)){
fprintf(stderr, "添加CRL到CMS失败\n");
goto err;
}
// 写CMS到文件
out_bio = BIO_new_file(cms_out_path, "wb");
if(!out_bio){
fprintf(stderr, "创建输出文件失败\n");
goto err;
}
if(!i2d_CMS_bio(out_bio, cms)){
fprintf(stderr, "写入CMS到文件失败\n");
goto err;
}
ret = 0; // 成功
err:
if(ret != 0) ERR_print_errors_fp(stderr);
if(cms_bio) BIO_free(cms_bio);
if(crl_bio) BIO_free(crl_bio);
if(out_bio) BIO_free(out_bio);
if(cms) CMS_ContentInfo_free(cms);
if(crl) X509_CRL_free(crl);
return ret;
}
int main(int argc, char *argv[]) {
// 检查命令行参数
if(argc != 4) {
fprintf(stderr, "用法: %s <cms输入路径> <crl路径> <cms输出路径>\n", argv[0]);
return 1;
}
// 调用函数添加CRL到CMS
if(add_crl_to_cms(argv[1], argv[2], argv[3]) != 0) {
fprintf(stderr, "添加CRL到CMS失败\n");
return 1;
}
printf("CRL已成功添加到CMS\n");
return 0;
}
编译:在vscode的终端使用gcc编译
注:-lssl -lcrypto是必须的,-L后面和-I后面换成自己之前which openssl的路径
gcc cms.c -o cms -L/opt/homebrew/opt/openssl/lib -I/opt/homebrew/opt/openssl/include -lssl -lcrypto
然后再运行cms
sudo ./cms ./cms-plus.der ./crl.pem ./cms-plus-full.der
验证CMS
openssl cms -verify -inform DER -in cms-plus.der -content temp.txt -signer rsacert-plus.crt -CAfile ./demoCA/cacert.pem
结果:
CMS Verification successful