查看摘要算法列表
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)生成配置文件f
[ 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 -f
不使用配置文件的时候
openssl req -x509 -key private_key.pem -out certificate.pem -days 365 -config <(echo "[ req ]ndefault_bits = 256nprompt = nondefault_md = SM3ndistinguished_name = dnn[ dn ]nC = CNnST = SCnL = ChengdunO = zdxlznOU = zdxlznCN = 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、配置文件f
[ca]
default_ca = CA_default CA 的默认设置[CA_default]
dir = /path/to/CA/folder
crl_dir = $dir/crl 指定存放 CRL 文件的文件夹路径
database = $ 指定用于存储证书签发和撤销信息的数据库文件(索引文件)路径。该文件记录了已颁发的证书和被撤销的证书的相关信息。
serial = $dir/serial 指定一个用于跟踪证书序列号的文件路径。每当颁发一个新证书时,该文件中的序列号将递增。
private_key = /path/to/ca.key 指定 CA 的私钥文件路径。CRL 是由 CA 使用其私钥签名的
certificate = /path/ 指定 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 -f -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 %ldn", version);X509_NAME *issuer_name = X509_CRL_get_issuer(crl);char *issuer_str = X509_NAME_oneline(issuer_name, NULL, 0);debugPrintf("Issuer: %sn", issuer_str);X509_ALGOR *sig_alg = &crl->sig_alg;//将一个对象的数字标识符(NID)转换为对应的短名(SN)const char *alg_name = OBJ_nid2sn(sig_alg->algorithm->nid);debugPrintf("Signature Algorithm: %sn", 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] = '