26.openssl编程——X509数字证书
26.1 X509数字证书
数字证书是将用户(或其他实体)身份与公钥绑定的信息载体。一个合法的数字证书不仅要符合X509格式规范,还必须有CA的签名。用户不仅有自己的数字证书,还必须有对应的私钥。
X509V3数字证书主要包含的内容有:
a.证书版本
b.证书序列号
c.签名算法
d.颁发者信息
e.有效时间
f.持有者信息
g.公钥信息
h.颁发者信息
i.公钥信息
j.颁发者ID
k.扩展项
26.2 openssl实现
openssl实现了标准x509v3数字证书,其源码在x509v3中。其中x509目录实现了数字证书以及证书申请相关的各种函数,包括X509和X509_REQ结构的设置、读取打印和比较。数字证书的验证、摘要;各种公钥导入导出等功能。x509v3目录主要实现了数字证书扩展项相关的函数。
26.3 X509数据结构
struct x509_cinf_st {
ASN1_INTEGER *version; 版本
ASN1_INTEGER serialNumber; 序列号
X509_ALGOR signature; 签名算法
X509_NAME *issuer; 颁发者
X509_VAL validity; 有效时间
X509_NAME *subject; 持有者
X509_PUBKEY *key; 公钥
ASN1_BIT_STRING *issuerUID; 颁发者唯一标识
ASN1_BIT_STRING *subjectUID; 持有者唯一标识
STACK_OF(X509_EXTENSION) *extensions; 扩展项
ASN1_ENCODING enc;
}
struct x509_st {
X509_CINF cert_info; 证书主体信息
X509_ALGOR sig_alg; 签名算法
ASN1_BIT_STRING signature; 签名值
X509_SIG_INFO siginf;
CRYPTO_REF_COUNT references; 引用次数,被引用一次则加一
CRYPTO_EX_DATA ex_data; 扩展数据结构,用于存放用户自定义的信息
long ex_pathlen; 证书路径长度,对应扩展项为NID_basic_constraints
long ex_pcpathlen;
uint32_t ex_flags; 通过与计算存放各种标志
uint32_t ex_kusage; 密钥用法
uint32_t ex_xkusage; 扩展密钥用法
uint32_t ex_nscert; 证书类型
ASN1_OCTET_STRING *skid; 主体密钥标识
AUTHORITY_KEYID *akid; 颁发者密钥标识
X509_POLICY_CACHE *policy_cache; 各种策略缓存
STACK_OF(DIST_POINT) *ctldp;
STACK_OF(GENERAL_NAME) *altname;
NAME_CONSTRAINTS *nc;
#ifndef OPENSSL_NO_RFC377G
STACK_OF(IPAddressFamily) *rfc3779_addr;
struct ASIdentifiers_st *rfc3779_asid;
#endif
unsigned cahr sha1_hash[SHA_DIGEST_LENGTH]; 存放证书的sha1摘要值
X509_CERT_AUX *aux;辅助信息
CRYPTO_RWLOCK *lock;
}
26.4 X509_TRUST与X509_CERT_AUX
a. typedef struct x509_trust_st {
int trust;
int flags;
int (*check_trust) (struct x509_trust_st *, X509 *, int);
char *name;
int arg1;
void *arg2;
} X509_TRUST;
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}
}
X509_CERT_AUX
typedef struct X509_cert_aux_st
{
STACK_OF(ASN1_OBJECT) *trust;
STACK_OF(ASN1_OBJECT) *reject;
ASN1_UTF8STRING *alias;
ASN1_OCTET_STRING *keyid;
STACK_OF(X509_ALGOR) *other;
}
验证证书时,如果要验证某个ASN1_OBJCT是否受信任,查找到相应的check_trust,进行计算。如果对应项在标准表trstandard中,除了X509_TRUST_COMPAT(检查证书用途)都会调用obj_trus函数
26.5 X509_PURPOSE
typedef struct x509_purpose_st {
int purpose;
int trust;
int flags;
int (*check_purpose) (const struct x509_purpose_st *, const X509*, int);
char *name;
char *sname;
void *usr_data;
}
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},
};
26.6 主要函数
26.7 证书验证项
a. 数字证书验证中,主要考察的项有
*有效期,看证书是否已经失效
*签名,用颁发者的公钥来验证签名
*证书用途
*名字比较,证书中的颁发者信息应与颁发者证书的持有者信息一致;扩展项约束。
b.Openssl中的证书验证
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