该结构用于检查证书用途,它定义在x509v3.h中,如下:
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;
} X509_PURPOSE;
purpose为证书用途ID,check_purpose为检查证书用途函数。基本的用途ID在x509v3.h中定义,如下:
#define X509_PURPOSE_SSL_CLIENT 1
#define X509_PURPOSE_SSL_SERVER 2
#define X509_PURPOSE_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_OCSP_HELPER 8
Openssl在x509v3/v3_purp.c中维护了两个表,用来检查各种证书用途。如下:
标准表:
static X509_PURPOSE xstandard[] = {
{X509_PURPOSE_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", "nssslserver", NULL},
{X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign, "S/MIME signing", "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_helper, "OCSP helper", "ocsphelper", NULL},
};
扩展表:
static STACK_OF(X509_PURPOSE) *xptable = NULL;
扩展表由用户通过X509_PURPOSE_add函数来添加。
当用户需要检查某个证书用途时,先查表,找到对应的X509_PURPOSE,然后调用其check_purpose函数来判断证书用途是否合法。
检查证书用途的函数为int X509_check_purpose(X509 *x, int id, int ca),该函数用于检查证书的用途。x为待检查待证书,id为证书用途NID,ca表明x是否是ca证书。
基本用法如下:
#include <openssl/x509.h>
#include <openssl/x509v3.h>
int main()
{
X509 *x=0;
int id,len,ret;
FILE *fp;
unsigned charbuf[5000],*p;
fp=fopen("root.cer","rb");
len=fread(buf,1,5000,fp);
fclose(fp);
p=buf;
d2i_X509(&x,&p,len);
id=X509_PURPOSE_OCSP_HELPER;
ret=X509_check_purpose(x,id,0);
if(ret==1)
{
printf("purpose check ok!\n");
}
else
{
printf("purpose check failed!\n");
}
X509_free(x);
return 0;
}
如果输入的id小于0,不做任何检查,只是证书的各个扩展项信息写入到将X509数据结构中。
另外本函数支持其他用途的验证,示例如下:
#include <openssl/x509v3.h>
int cb_check_tsa(X509_PURPOSE *purpose,const X509 *x,int isCA)
{
int flag;
printf("------------my check!-----------------\n");
/* 针对x添加判断函数 */
flag=*((int *)(purpose->usr_data));
if(flag)
return 1; /* 由此功能 */
else
return 0; /* 无此功能 */
}
int main()
{
X509 *x=0;
int id,len,ret;
FILE *fp;
unsigned charbuf[5000],*p;
int tsaFlag;
tsaFlag=1;
ret=X509_PURPOSE_add(1000,1000,0,cb_check_tsa,"tsa","checkTsa",&tsaFlag);
fp=fopen("root.cer","rb");
len=fread(buf,1,5000,fp);
fclose(fp);
p=buf;
d2i_X509(&x,&p,len);
id=1000;
ret=X509_check_purpose(x,id,0);
if(ret==1)
{
printf("purpose check ok!\n");
}
else
{
printf("purpose check failed!\n");
}
X509_free(x);
return 0;
}
本程序通过调用函数X509_PURPOSE_add添加一个X509_PURPOSE内部数据结构,然后再验证证书是否有此用途。用户所要实现的为X509_PURPOSE中的回调函数,在此回调函数中,用户根据证书信息来判断证书是否有此用途。如果用户还需要其他的信息才能作出判断,可以另外获取X509_PURPOSE数据结构中的usr_data。usr_data为一个void指针类型。用户可在调用X509_PURPOSE_add函数时将它写入对应的X509_PURPOSE数据结构(上例中的tsaFlag)。