赞
踩
查看摘要算法列表
openssl list -digest-algorithms
openssl crl -in crl.pem -text 查看信息
openssl x509 -in cert.pem -text
生成私钥
openssl ecparam -genkey -name SM2 -out private_key.pem
(RSA 公钥的字节结构可以使用标准的SubjectPublicKeyInfo(SPKI)格式来表示。这个格式由一系列的 DER 编码的 ASN.1 结构组成)
用私钥生成公钥
openssl ec -in private_key.pem -pubout -out sm2PubKey.pem
生成证书
1)生成配置文件cert.conf
[ req ]
default_bits = 256
prompt = no
default_md = sm3
distinguished_name = dn
[ dn ]
C = CN
ST = Beijing
L = Beijing
O = Your Organization
OU = Your Unit
CN = Your Common Name
default_bits:指定生成的密钥长度,默认为 256 位。在 SM2 中,通常使用 256 位曲线。
prompt:设置是否显示提示信息。在此示例中,设置为 no,即不显示提示信息。
default_md:指定摘要算法类型,默认为 SM3。SM3 是中国国家标准的密码杂凑算法,用于计算数字签名和生成证书请求。
distinguished_name:指定证书主题的字段。
C:国家名(Country),两个字母的国家代码。例如,CN 表示中国。
ST:省/自治区/直辖市名(State/Province/Region)。
L:地区/城市名(Locality/City)。
O:组织名(Organization)。
OU:组织单位名(Organizational Unit)。
CN:通用名称(Common Name),即证书的主题。
2)用私钥和配置文件生成证书
openssl req -new -key private_key.pem -out cert_req.csr -config cert.conf
不使用配置文件的时候
openssl req -x509 -key private_key.pem -out certificate.pem -days 365 -config <(echo "[ req ]\ndefault_bits = 256\nprompt = no\ndefault_md = SM3\ndistinguished_name = dn\n[ dn ]\nC = CN\nST = SC\nL = Chengdu\nO = zdxlz\nOU = zdxlz\nCN = Test")
易错点
140345702581568:error:100C508A:elliptic curve routines:pkey_ec_ctrl:invalid digest type:../crypto/ec/ec_pmeth.c:331
openssl 1.1.1版本后支持国密算法(去掉default_md = sm3)
介绍
包含撤销的证书列表的签名数据结构,类似于信用卡的黑名单,公布某些数字证书无效。
CRL可以分为完全CRL和增量CRL。在完全CRL中包含了所有的被撤销证书信息,增量CRL由一系列的CRL来表明被撤销的证书信息,它每次发布的CRL是对前面发布CRL的增量扩充。
基本的CRL信息有:被撤销证书序列号、撤销时间、撤销原因、签名者以及CRL签名等信息。
基于CRL的验证是一种不严格的证书认证。CRL能证明在CRL中被撤销的证书是无效的。但是,它不能给出不在CRL中的证书的状态。如果执行严格的认证,需要采用在线方式进行认证,即OCSP认证。
结构体
typedef struct X509_revoked_st//一个被撤销证书的信息 { ASN1_INTEGER *serialNumber;//被撤销证书的序列号; ASN1_TIME *revocationDate;//撤销时间 STACK_OF(X509_EXTENSION) *extensions;//扩展项,可选 int sequence;//顺序号,用于排序,表示当前被撤销证书信息在crl中的顺序 } X509_REVOKED; //主体信息 typedef struct X509_crl_info_st { ASN1_INTEGER *version;//crl版本 X509_ALGOR *sig_alg;//crl签名法 X509_NAME *issuer;//签发者信息 ASN1_TIME *lastUpdate;//上次更新时间 ASN1_TIME *nextUpdate;//下次更新时间 STACK_OF(X509_REVOKED) *revoked;//被撤销证书信息 STACK_OF(X509_EXTENSION) *extensions;// ASN1_ENCODING enc;// } X509_CRL_INFO; // 完整crl数据结构 struct X509_crl_st { X509_CRL_INFO *crl;//crl信息主体 X509_ALGOR *sig_alg;//签名算法,与X509_CRL_INFO中的一致 ASN1_BIT_STRING *signature;//签名值 int references;//引用 } ;
函数
int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev)//添加一个被撤销证书的信息 int X509_CRL_print(BIO *bp,X509_CRL *x)//打印crl内容到BIO中 int X509_CRL_print_fp(FILE *fp, X509_CRL *x)//将crl的内容输出到fp中,此函数调用了X509_CRL_print int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name)//设置crl的颁发者 int X509_CRL_set_lastUpdate(X509_CRL *x, ASN1_TIME *tm)//设置crl上次发布时间 int X509_CRL_set_nextUpdate(X509_CRL *x, ASN1_TIME *tm)//设置crl下次发布时间 int X509_CRL_set_version(X509_CRL *x, long version)//设置crl版本 int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md)//对crl进行签名,pkey为私钥,md为摘要算法,结果存放在x-> signature中 int X509_CRL_sort(X509_CRL *c)//根据证书序列号对crl排序,此函数实现采用了堆栈排序,堆栈的比较函数为X509_REVOKED_cmp(crypto/asn1/x_crl.c) //添加CRL扩展,nid为要添加的扩展标识,value为被添加的具体扩展项的内部数据结构地址,crit表明是否为关键扩展,flags表明何种操作。此函数调用X509V3_add1_i2d函数 int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit, unsigned long flags) int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc)//添加扩展项到指定堆栈位置,此函数调用X509v3_add_ext,进行堆栈插入操作。 int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b)//CRL比较,此函数调用X509_NAME_cmp,只比较颁发者的名字是否相同。 X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc)//删除CRL扩展项堆栈中的某一项,loc指定被删除项在堆栈中的位置 int X509_CRL_digest(const X509_CRL *data, const EVP_MD *type,unsigned char *md, unsigned int *len)//CRL摘要,本函数对X509_CRL进行摘要,type指定摘要算法,摘要结果存放在md中,len表明摘要结果长度 X509_CRL *X509_CRL_dup(X509_CRL *crl); void *X509_CRL_get_ext_d2i(X509_CRL *x, int nid, int *crit, int *idx)//CRL中的获取扩展项,此函数用于获取crl中指定扩展项的内部数据结构,返回值为具体的扩展项数据结构地址,nid为扩展项标识,它调用了X509V3_get_d2i函数。 int X509_CRL_get_ext_by_critical(X509_CRL *x, int crit, int lastpos) int X509_CRL_get_ext_by_NID(X509_CRL *x, int nid, int lastpos) int X509_CRL_get_ext_by_OBJ(X509_CRL *x, ASN1_OBJECT *obj, int lastpos) int X509_CRL_get_ext_count(X509_CRL *x)//获取crl中扩展项的个数 int X509_CRL_verify(X509_CRL *a, EVP_PKEY *r)//验证CRL。EVP_PKEY结构r中需要给出公钥(与签名相对应的)验证内容:签名,签发者证书,验证crl完整性 long X509_CRL_get_version(const X509_CRL *crl);//获取版本号 X509_NAME *X509_CRL_get_issuer(const X509_CRL *crl);//获取颁发者名称 char *X509_NAME_oneline(const X509_NAME *a, char *buf, int size);//将 X.509 证书的主题或颁发者(发行者)的名称转换为可打印的字符串形式 ASN1_TIME *X509_CRL_get_lastUpdate(X509_CRL *crl) ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *crl) STACK_OF(X509_REVOKED) *X509_CRL_get_REVOKED(X509_CRL *crl);//用于获取撤销证书列表,该函数返回一个 STACK_OF(X509_REVOKED) 结构的指针,即撤销证书的列表。STACK_OF(X509_REVOKED) 是 OpenSSL 提供的一种堆栈数据结构,用于存储多个 X509_REVOKED(被撤销的证书)对象 static inline int sk_X509_REVOKED_num(const stack_st_X509_REVOKED *sk)//获取 STACK_OF(X509_REVOKED) 结构中元素数量的函数 static inline x509_revoked_st *sk_X509_REVOKED_value(const stack_st_X509_REVOKED *sk, int idx)//获取指定索引位置的元素的函数,返回撤销证书列表中指定索引位置的被撤销证书对象 const ASN1_INTEGER *X509_REVOKED_get0_serialNumber(const X509_REVOKED *x);// 获取被撤销证书的序列号 unsigned char *ASN1_STRING_data(ASN1_STRING *x)//获取 ASN1_STRING 结构中数据的指针 int ASN1_STRING_length(const ASN1_STRING *x);//用于获取 ASN1_STRING 结构中数据的长度 ASN1_INTEGER *X509_get_serialNumber(X509 *x);//获取证书序列号
1、配置文件crl.conf
[ca] default_ca = CA_default CA 的默认设置 [CA_default] dir = /path/to/CA/folder crl_dir = $dir/crl 指定存放 CRL 文件的文件夹路径 database = $dir/index.txt 指定用于存储证书签发和撤销信息的数据库文件(索引文件)路径。该文件记录了已颁发的证书和被撤销的证书的相关信息。 serial = $dir/serial 指定一个用于跟踪证书序列号的文件路径。每当颁发一个新证书时,该文件中的序列号将递增。 private_key = /path/to/ca.key 指定 CA 的私钥文件路径。CRL 是由 CA 使用其私钥签名的 certificate = /path/to/ca.crt 指定 CA 的证书文件路径。该证书将包含在生成的 CRL 中。 crlnumber = $dir/crlnumber 指定存储 CRL 号码的文件路径。每次生成 CRL 时,该号码将递增。 default_crl_days = 30 指定生成的 CRL 的默认有效期(以天为单位)。在生成 CRL 时可以覆盖此值. [crl_ext] CRL 扩展字段的部分 issuerAltName=issuer:copy 指定 CRL 的颁发者别名,以及将从 CA 证书中拷贝的颁发者信息。 authorityKeyIdentifier=keyid:always 声明 CRL 中的颁发者密钥标识符(AKI)字段始终包含在 CRL 中 [req] default_bits = 2048 prompt = no 控制是否在生成证书请求时提示用户输入信息。将其设置为 "no" 可以禁用提示,使用默认值填充 default_md = sha256 指定证书签名所使用的消息摘要算法,默认为 SHA256 distinguished_name = dn 定义证书主题(Subject)的字段信息 [dn] CN = Your CA Name 部分参数可忽略
openssl ca -config crl.conf -gencrl -out crl.pem
测试程序
#include "x509.h" #include "pem.h" #include "ossl_typ.h" #include "../third-Part/openssl/include/crypto/x509.h" #include "../third-Part/openssl/include/crypto/asn1.h" #include "Debug.h" #include "parseCRL.h" #include "parseCertTest.h" void parseCRL(char *fileStr, X509 *cert) { FILE *crlFile = fopen(fileStr, "r"); if(crlFile == NULL){ debugPrintf("crlFile fopen err \n"); return; } X509_CRL *crl = NULL; //PEM 文件的指针, 指向 X509_CRL 结构体指针的指针(读取到才有), 指向密码回调函数的指针,用户数据指针 crl = PEM_read_X509_CRL(crlFile, &crl, NULL, NULL); if(crl == NULL){ debugPrintf("PEM_read_X509_CRL err \n"); return; } //DER格式读取 // BIO *crl_bio = BIO_new_file(fileStr, "r"); // crl = d2i_X509_CRL_bio(crl_bio, NULL); // BIO_free(crl_bio); //获取版本号 long version = X509_CRL_get_version(crl); debugPrintf("version %ld\n", version); X509_NAME *issuer_name = X509_CRL_get_issuer(crl); char *issuer_str = X509_NAME_oneline(issuer_name, NULL, 0); debugPrintf("Issuer: %s\n", issuer_str); X509_ALGOR *sig_alg = &crl->sig_alg; //将一个对象的数字标识符(NID)转换为对应的短名(SN) const char *alg_name = OBJ_nid2sn(sig_alg->algorithm->nid); debugPrintf("Signature Algorithm: %s\n", alg_name); // 获取上次更新时间和下次更新时间 ASN1_TIME *last_update = X509_CRL_get_lastUpdate(crl); ASN1_TIME *next_update = X509_CRL_get_nextUpdate(crl); printASN1Time(last_update); printASN1Time(next_update); // 获取撤销列表,栈 STACK_OF(X509_REVOKED) *revoked_list = X509_CRL_get_REVOKED(crl); int num_revoked = 0; if (revoked_list != NULL) { //获取revoked_list中的数量 num_revoked = sk_X509_REVOKED_num(revoked_list); // 遍历撤销的证书列表 } X509_REVOKED *revoked_cert; ASN1_INTEGER *serial_number; for (int i = 0; i < num_revoked; i++) { //获取指定索引位置的元素的函数,返回撤销证书列表中指定索引位置的被撤销证书对象 revoked_cert = sk_X509_REVOKED_value(revoked_list, i); // 获取被撤销证书的序列号 serial_number = X509_REVOKED_get0_serialNumber(revoked_cert); // 打印序列号,获取 ASN1_STRING 结构中数据的指针 char *hex_serial = (char *)ASN1_STRING_data(serial_number); int hex_serial_len = ASN1_STRING_length(serial_number); for (int j = 0; j < hex_serial_len; j++) { printf("%02X", hex_serial[j]); } printf("\n"); } //获取证书序列号,验证吊销列表 int isRevoked = 0; ASN1_INTEGER *cert_serial = X509_get_serialNumber(cert); for (int i = 0; i < num_revoked; ++i) { revoked_cert = sk_X509_REVOKED_value(revoked_list, i); serial_number = X509_REVOKED_get0_serialNumber(revoked_cert); // 比较证书的序列号 if (ASN1_INTEGER_cmp(cert_serial, serial_number) == 0) { isRevoked = 1; break; } } debugPrintf("check serialNumber \n"); }
说明
结合证书校验代码,测试用该证书生成的crl(如果获取的吊销列表为空,注意crl配置文件里面的证书吊销的序列号是否有)。
DER格式和PEM格式略有不同
static void _getASN1Time(ASN1_TIME* Time, char *rcvTime) { //BIO是一种用于进行输入/输出操作的抽象类型。它提供了一种统一的接口,可用于在不同的数据源和目标之间进行读写操作。 BIO* bio = BIO_new(BIO_s_mem()); if (bio == NULL) { return; } if (ASN1_TIME_print(bio, Time) <= 0) { BIO_free(bio); return; } char buf[1024]; //从bio对象中读取结果 int len = BIO_read(bio, buf, sizeof(buf) - 1); if (len <= 0) { BIO_free(bio); return; } buf[len] = '\0'; memcpy(rcvTime, buf, len); BIO_free(bio); } /** * 从字节流或字节数组读取证书结构存储X509 * @param buffer 证书数据 * @param size 大小 * @param crl 返回的证书 * @return 0成功 */ int crlInit(unsigned char* buffer, int size, X509_CRL **crl) { TRACE_INFO("crlInit"); TRACE_HEX_DUMP("buffer", buffer, size); //der格式 X509_CRL* _crl = d2i_X509_CRL(NULL, &buffer, size); if (_crl != NULL) { TRACE_INFO("d2i_X509_CRL err"); } else{ BIO *bio = BIO_new_mem_buf(buffer, -1); //pem格式 _crl = PEM_read_bio_X509_CRL(bio, NULL,NULL,NULL); if(_crl ==NULL){ TRACE_INFO("read crl err"); return -1; } } *crl = _crl;//值传递 return 0; } /** * 获取基本crl基本信息 * @param crl 输入crl * @param x509_CRL_INFO 返回的结构体信息 * @return */ int crlGetInfo(X509_CRL *crl, _X509_CRL_INFO *x509_CRL_INFO) { if(x509_CRL_INFO == NULL) { TRACE_INFO("x509_CRL_INFO NULL"); return -1; } x509_CRL_INFO->version = X509_CRL_get_version(crl) + 1; if(X509_CRL_get_issuer(crl) != NULL){ X509_NAME *issuer_name = X509_CRL_get_issuer(crl); char *issuer_str = X509_NAME_oneline(issuer_name, NULL, 0); x509_CRL_INFO->issuer_name_len = (int)strlen(issuer_str); x509_CRL_INFO->issuer_name = issuer_str; } X509_ALGOR *sig_alg = &crl->sig_alg; //将一个对象的数字标识符(NID)转换为对应的短名(SN) const char *alg_name = OBJ_nid2sn(sig_alg->algorithm->nid); memcpy(x509_CRL_INFO->alg_name, alg_name, strlen(alg_name)); ASN1_TIME *thisUpdate = X509_CRL_get_lastUpdate(crl); ASN1_TIME *nextUpdate = X509_CRL_get_nextUpdate(crl); _getASN1Time(thisUpdate,x509_CRL_INFO->thisUpdate); _getASN1Time(nextUpdate,x509_CRL_INFO->nextUpdate); if(crl->signature.data != NULL) { x509_CRL_INFO->signLen = crl->signature.length; x509_CRL_INFO->signDate = crl->signature.data; } if(crl->crl_number != NULL) { x509_CRL_INFO->crlNumber_len = crl->crl_number->length; x509_CRL_INFO->crlNumber = crl->crl_number->data; } if(crl->crl_number != NULL) { x509_CRL_INFO->base_crl_number_len = crl->base_crl_number->length; x509_CRL_INFO->base_crl_number = crl->base_crl_number->data; } return 0; } /** * * @param crl 输入 x509 crl * @param cert_serial 输入需要校验证书的序列号 * @return 1 证书合法不在吊销列表,0校验失败,证书不合法 */ int crlCheckRevokedList(X509_CRL *crl, ASN1_INTEGER *cert_serial) { STACK_OF(X509_REVOKED) *revoked_list = X509_CRL_get_REVOKED(crl); int num_revoked = 0; if (revoked_list != NULL){ num_revoked = sk_X509_REVOKED_num(revoked_list); } else{ TRACE_INFO("X509_CRL_get_REVOKED NULL"); return 1; } X509_REVOKED *revoked_cert; ASN1_INTEGER *serial_number; for (int i = 0; i < num_revoked; i++) { //获取指定索引位置的元素的函数,返回撤销证书列表中指定索引位置的被撤销证书对象 revoked_cert = sk_X509_REVOKED_value(revoked_list, i); // 获取被撤销证书的序列号 serial_number = X509_REVOKED_get0_serialNumber(revoked_cert); char *hex_serial = (char *)ASN1_STRING_data(serial_number); int hex_serial_len = ASN1_STRING_length(serial_number); TRACE_HEX_DUMP("hex_serial", hex_serial, hex_serial_len); //对比序列号是否是吊销列表 if (ASN1_INTEGER_cmp(cert_serial, serial_number) == 0) { return 0;//查出吊销列表 } } return 1; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。