本文共 6818 字,大约阅读时间需要 22 分钟。
数字证书是将用户(或其他实体)身份与公钥绑定的信息载体。一个合法的数字证书不仅要符合X509格式规范,还必须有CA的签名。用户不仅有自己的数字证书,还必须有对应的私钥。
openssl实现了标准x509v3数字证书,其源码在x509v3中。其中x509目录实现了数字证书以及证书申请相关的各种函数,包括X509和X509_REQ结构的设置、读取打印和比较。数字证书的验证、摘要;各种公钥导入导出等功能。x509v3目录主要实现了数字证书扩展项相关的函数。
ASN1_INTEGER *version; 版本
ASN1_INTEGER serialNumber; 序列号
X509_ALGOR signature; 签名算法
ASN1_BIT_STRING *issuerUID; 颁发者唯一标识
ASN1_BIT_STRING *subjectUID; 持有者唯一标识
STACK_OF(X509_EXTENSION) *extensions; 扩展项
X509_CINF cert_info; 证书主体信息
ASN1_BIT_STRING signature; 签名值
CRYPTO_REF_COUNT references; 引用次数,被引用一次则加一
CRYPTO_EX_DATA ex_data; 扩展数据结构,用于存放用户自定义的信息
long ex_pathlen; 证书路径长度,对应扩展项为NID_basic_constraints
uint32_t ex_flags; 通过与计算存放各种标志
uint32_t ex_xkusage; 扩展密钥用法
ASN1_OCTET_STRING *skid; 主体密钥标识
AUTHORITY_KEYID *akid; 颁发者密钥标识
X509_POLICY_CACHE *policy_cache; 各种策略缓存
STACK_OF(DIST_POINT) *ctldp;
STACK_OF(GENERAL_NAME) *altname;
#ifndef OPENSSL_NO_RFC377G
STACK_OF(IPAddressFamily) *rfc3779_addr;
struct ASIdentifiers_st *rfc3779_asid;
unsigned cahr sha1_hash[SHA_DIGEST_LENGTH]; 存放证书的sha1摘要值
26.4 X509_TRUST与X509_CERT_AUX a. typedef struct x509_trust_st {
int (*check_trust) (struct x509_trust_st *, X509 *, int);
static X509_TRUST trstandard[] = {
{X509_TRUST_COMPAT, 0, trust_compat, "compatible", 0, NULL},
{X509_TRUST_SSL_CLIENT, 0, trust_loidany, "SSL CLient", NID_client_aut, NULL},
{X509_TRUST_SSL_SERVER, 0, trust_loidany, "SSL Server", NID_server_auth, NULL},
{X509_TRUST_EMAIL, 0, trust_loidany, "S/MIME email", NID_email_protect, NULL},
{X509_TRUST_OBJECT_SIGN, 0, trust_loidany, "Object Signer", NID_code_sign, NULL},
{X509_TRUST_OCSP_SIGN, 0, trust_loid, "OCSP responder", NID_OCSP_sign, NULL},
{X509_TRUST_OCSP_REQUEST, 0, trust_loid, "OCSP request", NID_ad_OCSP, NULL},
{X509_TRUST_TSA, 0, trust_loidany, "TSA server", NID_time_stamp, NULL}
typedef struct X509_cert_aux_st
STACK_OF(ASN1_OBJECT) *trust;
STACK_OF(ASN1_OBJECT) *reject;
ASN1_OCTET_STRING *keyid;
STACK_OF(X509_ALGOR) *other;
验证证书时,如果要验证某个ASN1_OBJCT是否受信任,查找到相应的check_trust,进行计算。如果对应项在标准表trstandard中,除了X509_TRUST_COMPAT(检查证书用途)都会调用obj_trus函数
typedef struct x509_purpose_st {
int (*check_purpose) (const struct x509_purpose_st *, const X509*, int);
purpsoe为证书用途ID,check_purpose为检查证书用途函数
#define X509_PURPOSE_SSL_CLIENT 1
#define X509_PURPOSE_SSL_SERVER 2
#define X509_PURPOSE_SSL_NS_SSL_SERVER 3
#define X509_PURPOSE_SMIME_SIGN 4
#define X509_PURPOSE_SMIME_ENCRYPT 5
#define X509_PURPOSE_CRL_SIGN 6
#define X509_PURPOSE_ANY 7
#define X509_PURPOSE_OCASP_HELPER 8
#define X509_PURPOSE_TIMESTAMP_SIGN 9
static X509_PURPOSE xstandard[] = {
{X509_PURPSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0
check_purpose_ssl_client, ""SSL client}, "sslclient", NULL},
{X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0,
check_purpose_ssl_server, "SSL server", "sslserver", NULL},
{X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0,
check_purpose_ns_ssl_server, "Netscape SSL server", "nesslever", NULL},
{X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign,"S/MIME sgning", "smimesign", NULL},
{X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0,
check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL},
{X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign,
"CRL signing", "crlsign", NULL},
{X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any PUrpose", "any", NULL},
{X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helpoer, "OCSP helper", "ocsphelper", NULL},
{X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0, check_purpose_timestamp_sign, "TIme Stamp signing", "timestampsign", NULL},
| |
| |
| |
| 将flags赋值给ctx里面的flags,表明验证证书时需要验证哪些项 |
| |
| |
| |
X509_verify_cert_error_string | |
| |
| X509_EXTENSION堆栈中,在制定位置添加一项 |
| |
| |
| 获取X509的ASN1_METHOD,包括new\free\i2d和d2i函数 |
| |
| |
| |
| 将s与当前时间进行比较,返回值小于0则s遭遇当前时间, |
| 如果ctm时间在cmp_time之后,则返回值大于0. |
| |
| |
| |
X509_find_by_issuer_and_serial | |
| |
| |
| |
| 根据X509_PURPOSE的位置获取对应的X509_PURPOSE |
| |
| |
| 根据证书用途ID获取X509_PURPOSE在当前数组(xstandard) |
X509_PURPOSE_get_by_sname | 根据别名获取对应的X509_PURPOSE的数组或堆栈中的位置 |
| 获取所有的X509_PURPOSE个数,包括标准和用户动态添加的 |
| |
| 检查是否有purpose标识X509_purpose,并将purpose值写入p |
| 将ex表示的扩展项根据loc指定的位置插入到X509_EXTENSION堆栈中 |
| |
| 本函数用于打印单个扩展项,out为BIO类型的输出对象 ext为扩展项,flag表明不支持扩展项的处理方式,indent表明输出时第一列的位置 |
| |
X509v3_get_ext_by_critical | 获取扩展项在堆栈中的位置,crit表明扩展项是否关键 |
| 此函数根据扩展项标识nid以及堆栈搜索的其实进行搜索 |
| 获取扩展项在堆栈中的位置,crit表面扩展项是否关键 |
| 获取扩展项,loc为扩展项在堆栈x中的位置,如果不成功,返回NULL |
| |
| 获取配置信息,section为配置信息中的段信息。 |
| |
| 判断配置信息的布尔值,如果value表示的值为true,TRUE |
| 将value中的值转换为ASN1_INTEGER类型, 结果存放在**aint中,函数调用成功返回1,否则返回0 |
| |
*名字比较,证书中的颁发者信息应与颁发者证书的持有者信息一致;扩展项约束。
Openssl中的证书验证比较复杂,实现源码X509/X509_vfy.c中,主要有两个函数:X509_verify_cert和internal_verify.X509_verify_cert主要讲所有的证书信息进行排序,构造出一个有序的证书链,然后interanl_verify函数来验证证书。internal_verify是openssl提供的一个内置的验证证书链的函数。如果用户通过X509_STRORE_set_verify_func函数设置了X509_STORE_CTX的verify函数,将调用用户是实现的verify函数而不会调用internal_veriify。如何用openssl函数验证证书,用户可以参考apps/verify.c
转载地址:http://cqwdb.baihongyu.com/