ASN1的基本的数据类型一般都有如下函数:new、free、i2d、d2i、i
常用的函数有:
1) int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
计算OID的DER编码,比如将2.99999.3形式转换为内存形式。示例:
#include <openssl/asn1.h>
void main()
{
const char oid[]={"2.99999.3"};
int i;
unsigned char *buf;
i=a2d_ASN1_OBJECT(NULL,0,oid,-1);
if (i <= 0)
return;
buf=(unsigned char *)malloc(sizeof(unsigned char)*i);
i=a2d_ASN1_OBJECT(buf,i,oid,-1);
free(buf);
return;
}
输出结果:buf内存值为:86 8D
2) int a2i_ASN1_INTEGER(BIO *bp,ASN1_INTEGER *bs,char *buf,int size)
将bp中的ASC码转换为ASN1_INTEGER,buf存放BIO中的ASC码。示例如下:
#include <openssl/asn1.h>
int main()
{
BIO *bp;
ASN1_INTEGER *i;
unsigned charbuf[50];
int size,len;
bp=BIO_new(BIO_s_mem());
len=BIO_write(bp,"0FAB08BBDDEECC",14);
size=50;
i=ASN1_INTEGER_new();
a2i_ASN1_INTEGER(bp,i,buf,size);
BIO_free(bp);
ASN1_INTEGER_free(i);
return 0;
}
3)int a2i_ASN1_STRING(BIO *bp,ASN1_STRING *bs,char *buf,int size)
将ASCII码转换为ASN1_STRING,示例:
#include <openssl/asn1.h>
int main()
{
BIO *bp;
ASN1_STRING *str;
unsigned charbuf[50];
int size,len;
bp=BIO_new(BIO_s_mem());
len=BIO_write(bp,"B2E2CAD4",8);
size=50;
str=ASN1_STRING_new();
a2i_ASN1_STRING(bp,str,buf,size);
BIO_free(bp);
ASN1_STRING_free(str);
return 0;
}
转换后str->data的前四个字节即变成"测试"。
4)unsigned char *asc2uni(const char *asc, int asclen, unsigned char **uni, int *unilen)
将ASCII码转换为unicode,示例:
#include <stdio.h>
#include <openssl/crypto.h>
int main()
{
unsigned charasc[50]={"B2E2CAD4"};
unsigned charuni[50],*p,*q;
int ascLen,unlen;
ascLen=strlen(asc);
q=asc2uni(asc,ascLen,NULL,&unlen);
OPENSSL_free(q);
return 0;
}
5)int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n)
本函数根据n获取其比特位上的值,示例:
#include <openssl/asn1.h>
int main()
{
int ret,i,n;
ASN1_BIT_STRING *a;
a=ASN1_BIT_STRING_new();
ASN1_BIT_STRING_set(a,"ab",2);
for(i=0;i<2*8;i++)
{
ret=ASN1_BIT_STRING_get_bit(a,i);
printf("%d",ret);
}
ASN1_BIT_STRING_free(a);
return 0;
}
程序输出:0110000101100010
说明:a中”ab”的二进制既是0110000101100010。
6)ASN1_BIT_STRING_set
设置ASN1_BIT_STRING的值,它调用了ASN1_STRING_set函数;
7)void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x)
对bio的数据DER解码,xnew无意义,d2i为DER解码函数,in为bio数据,x为数据类型,返回值为解码后的结果。如果x分配了内存,x所指向的地址与返回值一致。示例如下:
#include <stdio.h>
#include <openssl/asn1.h>
#include <openssl/x509v3.h>
#include <openssl/bio.h>
int main()
{
BIO *in;
X509 **out=NULL,*x;
in=BIO_new_file("a.cer","r");
out=(X509 **)malloc(sizeof(X509 *));
*out=NULL;
x=ASN1_d2i_bio(NULL,(d2i_of_void *)d2i_X509,in,out);
X509_free(x);
free(out);
return 0;
}
8)void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x)
将in指向的文件进行DER解码,其内部调用了ASN1_d2i_bi函数,用法与ASN1_d2i_bi类似。
9)int ASN1_digest(i2d_of_void *i2d, const EVP_MD *type,
char *data,unsigned char *md, unsigned int *len)
ASN1数据类型签名。将data指针指向的ASN1数据类型用i2d函数进行DER编码,然后用type指定的摘要方法进行计算,结果存放在md中,结果的长度由len表示。
10)int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, unsigned char *x)
将ASN1数据结构DER编码,并将结果写入bio。示例如下:
#include <openssl/asn1.h>
#include <openssl/bio.h>
int main()
{
int ret;
BIO *out;
ASN1_INTEGER *a;
out=BIO_new_file("int.cer","w");
a=ASN1_INTEGER_new();
ASN1_INTEGER_set(a,(long)100);
ret=ASN1_i2d_bio(i2d_ASN1_INTEGER,out,a);
BIO_free(out);
return 0;
}
本程序将ASN1_INTEGER类型装换为DER编码并写入文件。int.cer的内容如下:
02 01 64 (十六进制)。
11) int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, void *x)
将ASN1数据结构DER编码并写入FILE,此函数调用了ASN1_i2d_bio。
12)void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, char *x)
ASN1数据复制。x为ASN1内部数据结构,本函数先将x通过i2d将它变成DER编码,然后用d2i再DER解码,并返回解码结果。
13) ASN1_ENUMERATED_set
设置ASN1_ENUMERATED的值。
14) ASN1_ENUMERATED_get
获取ASN1_ENUMERATED的值;示例如下:
clude <openssl/asn1.h>
int main()
{
long ret;
ASN1_ENUMERATED *a;
a=ASN1_ENUMERATED_new();
ASN1_ENUMERATED_set(a,(long)155);
ret=ASN1_ENUMERATED_get(a);
printf("%ld\n",ret);
return 0;
}
15)BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai, BIGNUM *bn)
将ASN1_ENUMERATED类型转换为BN大数类型。此函数调用BN_bin2bn函数获取bn,如果ai->type表明它是负数,再调用BN_set_negative设置bn成负数。示例如下:
#include <openssl/asn1.h>
int main()
{
long ret;
ASN1_ENUMERATED *a;
BIGNUM *bn;
a=ASN1_ENUMERATED_new();
ASN1_ENUMERATED_set(a,(long)155);
ret=ASN1_ENUMERATED_get(a);
bn=BN_new();
bn=ASN1_ENUMERATED_to_BN(a,bn);
BN_free(bn);
ASN1_ENUMERATED_free(a);
return 0;
}
如果ASN1_ENUMERATED_to_BN的第二个参数为NULL,bn将在内部分配空间。
16)int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *a)
检查输入参数是不是合法的ASN1_GENERALIZEDTIME类型。
17)int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent, int dump)
本函数用于将pp和len指明的DER编码值写在BIO中,其中indent和dump用于设置打印的格式。indent用来设置打印出来当列之间空格个数,ident越小,打印内容越紧凑。dump表明当asn1单元为BIT STRING或OCTET STRING时,打印内容的字节数。示例如下:
#include <openssl/bio.h>
#include <openssl/asn1.h>
int main()
{
int ret,len,indent,dump;
BIO *bp;
char*pp,buf[5000];
FILE *fp;
bp=BIO_new(BIO_s_file());
BIO_set_fp(bp,stdout,BIO_NOCLOSE);
fp=fopen("der.cer","rb");
len=fread(buf,1,5000,fp);
fclose(fp);
pp=buf;
indent=7;
dump=11;
ret=ASN1_parse_dump(bp,pp,len,indent,dump);
BIO_free(bp);
return 0;
}
其中der.cer为一个DER编码的文件,比如一个数字证书。
18)int ASN1_sign(i2d_of_void *i2d, X509_ALGOR *algor1, X509_ALGOR *algor2, ASN1_BIT_STRING *signature, char *data, EVP_PKEY *pkey, const EVP_MD *type)
对ASN1数据类型签名。i2d为ASN1数据的DER方法,signature用于存放签名结果,data为ASN1数据指针,pkey指明签名密钥,type为摘要算法,algor1和algor2无用,可全为NULL。签名时,先将ASN1数据DER编码,然后摘要,最后签名运算。
在x509.h中有很多ASN1数据类型的签名都通过此函数来定义,有X509_sign、X509_REQ_sign、X509_CRL_sign、NETSCAPE_SPKI_sign等。示例如下:
#include <openssl/asn1.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
int main()
{
int ret;
ASN1_INTEGER *a;
EVP_MD *md;
EVP_PKEY *pkey;
char *data;
ASN1_BIT_STRING *signature=NULL;
RSA *r;
int i,bits=1024;
unsigned long e=RSA_3;
BIGNUM *bne;
bne=BN_new();
ret=BN_set_word(bne,e);
r=RSA_new();
ret=RSA_generate_key_ex(r,bits,bne,NULL);
if(ret!=1)
{
printf("RSA_generate_key_ex err!\n");
return -1;
}
pkey=EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey,r);
a=ASN1_INTEGER_new();
ASN1_INTEGER_set(a,100);
md=EVP_md5();
data=(char *)a;
signature=ASN1_BIT_STRING_new();
ret=ASN1_sign(i2d_ASN1_INTEGER,NULL,NULL,signature,data,pkey,md);
printf("signature len : %d\n",ret);
EVP_PKEY_free(pkey);
ASN1_INTEGER_free(a);
free(signature);
return 0;
}本例将ASN1_INTEGER整数签名。
19)ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *str)
ASN1_STRING类型拷贝。内部申请空间,需要用户调用ASN1_STRING_free释放该空间。
20)int ASN1_STRING_cmp(ASN1_STRING *a, ASN1_STRING *b)
ASN1_STRING比较。ossl_typ.h中绝大多数ASN1基本类型都定义为ASN1_STRING,所以,此函数比较通用。示例如下:
#include <openssl/asn1.h>
int main()
{
int ret;
ASN1_STRING *a,*b,*c;
a=ASN1_STRING_new();
b=ASN1_STRING_new();
ASN1_STRING_set(a,"abc",3);
ASN1_STRING_set(b,"def",3);
ret=ASN1_STRING_cmp(a,b);
printf("%d\n",ret);
c=ASN1_STRING_dup(a);
ret=ASN1_STRING_cmp(a,c);
printf("%d\n",ret);
ASN1_STRING_free(a);
ASN1_STRING_free(b);
ASN1_STRING_free(c);
return 0;
}
21)unsigned char * ASN1_STRING_data(ASN1_STRING *x)
获取ASN1_STRING数据存放地址,即ASN1_STRING数据结构中data地址。本函数由宏实现。
22)int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len)
设置ASN1字符串类型的值。str为ASN1_STRING地址,_data为设置值的首地址,len为被设置值的长度。示例如下:
ASN1_STRING *str=NULL;
str=ASN1_STRING_new();
ASN1_STRING_set(str,”abc”,3);
此示例生成的ASN1_STRING类型为OCTET_STRING。其他的ASN1_STRING类型也能用此函数设置,如下:
ASN1_PRINTABLESTRING*str=NULL;
str=ASN1_PRINTABLESTRING_new();
ASN1_STRING_set(str,”abc”,3);
23)ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid)
根据nid来查找ASN1_STRING_TABLE表。此函数先查找标准表tbl_standard,再查找扩展表stable。ASN1_STRING_TABLE数据结构在asn1.h中定义,它用于约束ASN1_STRING_set_by_NID函数生成的ASN1_STRING类型。
typedef struct asn1_string_table_st {
int nid;
long minsize;
long maxsize;
unsigned long mask;
unsigned long flags;
} ASN1_STRING_TABLE;
其中nid表示对象id,minsize表示此nid值的最小长度,maxsize表示此nid值的最大长度,mask为此nid可以采用的ASN1_STRING类型:B_ASN1_BMPSTRING、B_ASN1_UTF8STRING、B_ASN1_T61STRING和B_ASN1_UTF8STRING,flags用于标记是否为扩展或是否已有mask。
24)ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in, int inlen, int inform, int nid)
根据nid和输入值获取对应的ASN1_STIRNG类型。out为输出,in为输入数据,inlen为其长度,inform为输入数据的类型,可以的值有:MBSTRING_BMP、MBSTRING_UNIV、MBSTRING_UTF8、MBSTRING_ASC,nid为数字证书中常用的nid,在a_strnid.c中由全局变量tbl_standard定义,可以的值有:NID_commonName、NID_countryName、NID_localityName、NID_stateOrProvinceName、NID_organizationName、NID_organizationalUnitName、NID_pkcs9_emailAddress、NID_pkcs9_unstructuredName、NID_pkcs9_challengePassword、NID_pkcs9_unstructuredAddress、NID_givenName、NID_surname、NID_initials、NID_serialNumber、NID_friendlyName、NID_name、NID_dnQualifier、NID_domainComponent和NID_ms_csp_name。生成的ASN1_STRING类型可以为:ASN1_T61STRING、ASN1_IA5STRING、ASN1_PRINTABLESTRING、ASN1_BMPSTRING、ASN1_UNIVERSALSTRING和ASN1_UTF8STRING。
示例1:
#include <stdio.h>
#include <openssl/asn1.h>
#include <openssl/obj_mac.h>
int main()
{
int inlen,nid,inform,len;
charin[100],out[100],*p;
ASN1_STRING *a;
FILE *fp;
/* 汉字“赵”的UTF8值,可以用UltraEdit获取*/
memset(&in[0],0xEF,1);
memset(&in[1],0xBB,1);
memset(&in[2],0xBF,1);
memset(&in[3],0xE8,1);
memset(&in[4],0xB5,1);
memset(&in[5],0xB5,1);
inlen=6;
inform=MBSTRING_UTF8;
nid=NID_commonName;
/* 如果调用下面两个函数,生成的ASN1_STRING类型将是ASN1_UTF8而不是ASN1_BMPSTRING */
ASN1_STRING_set_default_mask(B_ASN1_UTF8STRING);
ret=ASN1_STRING_set_default_mask_asc("utf8only");
if(ret!=1)
{
printf("ASN1_STRING_set_default_mask_asc err.\n");
return 0;
}
a=ASN1_STRING_set_by_NID(NULL,in,inlen,inform,nid);
p=out;
len=i2d_ASN1_BMPSTRING(a,&p);
fp=fopen("a.cer","w");
fwrite(out,1,len,fp);
fclose(fp);
ASN1_STRING_free(a);
return 0;
}
本例根据UTF8编码的汉字获取nid为NID_commonName的ASN1_STRING类型,其结果是一个ASN1_BMPSTRING类型。
示例2:
#include <stdio.h>
#include <openssl/asn1.h>
#include <openssl/obj_mac.h>
int main()
{
int inlen,nid,inform,len;
charin[100],out[100],*p;
ASN1_STRING *a;
FILE *fp;
strcpy(in,"ab");
inlen=2;
inform=MBSTRING_ASC;
nid=NID_commonName;
/* 设置生成的ASN1_STRING类型 */
ASN1_STRING_set_default_mask(B_ASN1_UTF8STRING);
a=ASN1_STRING_set_by_NID(NULL,in,inlen,inform,nid);
switch(a->type)
{
caseV_ASN1_T61STRING:
printf("V_ASN1_T61STRING\n");
break;
caseV_ASN1_IA5STRING:
printf("V_ASN1_IA5STRING\n");
break;
caseV_ASN1_PRINTABLESTRING:
printf("V_ASN1_PRINTABLESTRING\n");
break;
caseV_ASN1_BMPSTRING:
printf("V_ASN1_BMPSTRING\n");
break;
caseV_ASN1_UNIVERSALSTRING:
printf("V_ASN1_UNIVERSALSTRING\n");
break;
caseV_ASN1_UTF8STRING:
printf("V_ASN1_UTF8STRING\n");
break;
default:
printf("err");
break;
}
p=out;
len=i2d_ASN1_bytes(a,&p,a->type,V_ASN1_UNIVERSAL);
fp=fopen("a.cer","w");
fwrite(out,1,len,fp);
fclose(fp);
ASN1_STRING_free(a);
getchar();
return 0;
}
25)void ASN1_STRING_set_default_mask(unsigned long mask)
设置ASN1_STRING_set_by_NID函数返回的ASN1_STRING类型。mask可以取如下值:B_ASN1_BMPSTRING、B_ASN1_UTF8STRING、B_ASN1_T61STRING和B_ASN1_UTF8STRING。
26)int ASN1_STRING_set_default_mask_asc(char *p)
设置ASN1_STRING_set_by_NID函数返回的ASN1_STRING类型。字符串p可以的值有:nombstr、pkix、utf8only和default,如果设置为default,则相当于没有调用本函数。
27)int ASN1_STRING_TABLE_add(int nid, long minsize, long maxsize, unsigned long mask, unsigned long flags)
添加扩展的ASN1_STRING_TABLE项。说明:a_strnid.c中定义了基本的ASN1_STRING_TABLE项,如果用户要添加新的ASN1_STRING_TABLE项,需要调此次函数。Openssl源代码中有好几处都有这种用法,Openssl定义标准的某种表,并且提供扩展函数供用户去扩充。
示例:ASN1_STRING_TABLE_add(NID_yourNID,1,100, DIRSTRING_TYPE,0)。
28)void ASN1_STRING_TABLE_cleanup(void)
清除用户自建的扩展ASN1_STRING_TABLE表。
29)int i
将整数转换成为ASCII码,放在BIO中。示例如下:
#include <openssl/asn1.h>
int main()
{
ASN1_INTEGER *i;
long v;
BIO *bp;
printf("输入v的值:\n");
scanf("%ld",&v);
i=ASN1_INTEGER_new();
ASN1_INTEGER_set(i,v);
bp=BIO_new(BIO_s_file());
BIO_set_fp(bp,stdout,BIO_NOCLOSE);
i
BIO_free(bp);
ASN1_INTEGER_free(i);
printf("\n");
return 0;
}
输出:
输入v的值:
15
30)int i
type不起作用,将ASN1_STRING转换为ASCII码.。示例如下:
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
int main()
{
ASN1_STRING *a;
BIO *bp;
a=ASN1_STRING_new();
ASN1_STRING_set(a,"测试",4);
bp=BIO_new(BIO_s_file());
BIO_set_fp(bp,stdout,BIO_NOCLOSE);
i
BIO_free(bp);
ASN1_STRING_free(a);
printf("\n");
return 0;
}
输出结果:
B2E2CAD4
31)OBJ_bsearch
用于从排序好的数据结构地址数组中用二分法查找数据。示例如下:
#include <openssl/objects.h>
typedef struct Student_st
{
int age;
}Student;
int cmp_func(const void *a,const void *b)
{
Student *x,*y;
x=*(Student **)a;
y=*(Student **)b;
return x->age-y->age;
}
int main()
{
int ret,num,size;
ASN1_OBJECT *obj=NULL;
char **addr,*p;
Student a[6],**sort,**x;
a[0].age=3;
a[1].age=56;
a[2].age=5;
a[3].age=1;
a[4].age=3;
a[5].age=6;
sort=(Student **)malloc(6*sizeof(Student *));
sort[0]=&a[0];
sort[1]=&a[1];
sort[2]=&a[2];
sort[3]=&a[3];
sort[4]=&a[4];
sort[5]=&a[5];
qsort(sort,6,sizeof(Student *),cmp_func);
obj=OBJ_nid2obj(NID_rsa);
ret=OBJ_add_object(obj);
if(ret==NID_undef)
{
printf("err");
}
else
{
printf("ok\n");
}
p=&a[4];
addr=OBJ_bsearch(&p,(char *)sort,6,sizeof(Student *),cmp_func);
x=(Student **)addr;
printf("%d == %d\n",a[4].age,(*x)->age);
return 0;
}
32)OBJ_create
根据oid以及名称信息生成一个内部的object,示例:
nid=OBJ_create("
33)OBJ_NAME_add
OBJ_NAME_cleanup
OBJ_NAME_get
OBJ_NAME_init
OBJ_NAME_remove
OBJ_NAME_new_index
OBJ_NAME_do_all
OBJ_NAME_do_all_sorted
OBJ_NAME函数用于根据名字获取对称算法或者摘要算法,主要涉及到函数有:
int EVP_add_cipher(const EVP_CIPHER *c);
int EVP_add_digest(const EVP_MD *md);
const EVP_CIPHER *EVP_get_cipherbyname(const char *name);
const EVP_MD *EVP_get_digestbyname(const char *name);
void EVP_cleanup(void);
这些函数在evp/names.c中实现,他们调用了OBJ_NAME函数。
EVP_add_cipher和EVP_add_digest函数调用OBJ_NAME_init和OBJ_NAME_add函数,将EVP_CIPHER