OpenSSL之ASN1用法

ASN.1 – Abstract Syntax Notation dot one,抽象記法1,在大部分的書寫場合會簡寫為ASN1。它描述了一種對數據進行表示、編碼、傳輸和解碼的數據格式。它提供了一整套正規的格式用于描述對象的結構,而不管語言上如何執行及這些數據的具體指代,也不用去管到底是什么樣的應用程序。
ASN1有很多實現版本,OpenSSL主要采用DER格式。

本文假設你已經安裝好了OpenSSL,并且持有一份1.1.1的源碼。
ASN1相關的頭文件為asn1.h、asn1t.h、源文件在crypto/asn1目錄中。

主要結構:

struct asn1_string_st {
    int length;
    int type;
    unsigned char *data;
    long flags;
};

這個結構負責管理ANS1大多數數據類型的內存組織方式,字段含義:
length —— 管理的數據長度。
type —— 管理的數據類型。
data —— 數據指針。
flags —— 標志位,跟具體數據類型有關。

管理的數據類型:

typedef struct asn1_string_st ASN1_INTEGER;
typedef struct asn1_string_st ASN1_ENUMERATED;
typedef struct asn1_string_st ASN1_BIT_STRING;
typedef struct asn1_string_st ASN1_OCTET_STRING;
typedef struct asn1_string_st ASN1_PRINTABLESTRING;
typedef struct asn1_string_st ASN1_T61STRING;
typedef struct asn1_string_st ASN1_IA5STRING;
typedef struct asn1_string_st ASN1_GENERALSTRING;
typedef struct asn1_string_st ASN1_UNIVERSALSTRING;
typedef struct asn1_string_st ASN1_BMPSTRING;
typedef struct asn1_string_st ASN1_UTCTIME;
typedef struct asn1_string_st ASN1_TIME;
typedef struct asn1_string_st ASN1_GENERALIZEDTIME;
typedef struct asn1_string_st ASN1_VISIBLESTRING;
typedef struct asn1_string_st ASN1_UTF8STRING;
typedef struct asn1_string_st ASN1_STRING;

主要數據類型的取值:

# define V_ASN1_EOC                      0
# define V_ASN1_BOOLEAN                  1 /**/
# define V_ASN1_INTEGER                  2
# define V_ASN1_BIT_STRING               3
# define V_ASN1_OCTET_STRING             4
# define V_ASN1_NULL                     5
# define V_ASN1_OBJECT                   6
# define V_ASN1_OBJECT_DESCRIPTOR        7
# define V_ASN1_EXTERNAL                 8
# define V_ASN1_REAL                     9
# define V_ASN1_ENUMERATED               10
# define V_ASN1_UTF8STRING               12
# define V_ASN1_SEQUENCE                 16
# define V_ASN1_SET                      17
# define V_ASN1_NUMERICSTRING            18 /**/
# define V_ASN1_PRINTABLESTRING          19
# define V_ASN1_T61STRING                20
# define V_ASN1_TELETEXSTRING            20/* alias */
# define V_ASN1_VIDEOTEXSTRING           21 /**/
# define V_ASN1_IA5STRING                22
# define V_ASN1_UTCTIME                  23
# define V_ASN1_GENERALIZEDTIME          24 /**/
# define V_ASN1_GRAPHICSTRING            25 /**/
# define V_ASN1_ISO64STRING              26 /**/
# define V_ASN1_VISIBLESTRING            26/* alias */
# define V_ASN1_GENERALSTRING            27 /**/
# define V_ASN1_UNIVERSALSTRING          28 /**/
# define V_ASN1_BMPSTRING                30

其它一些類型的定義:

typedef int ASN1_BOOLEAN;
typedef int ASN1_NULL;
struct asn1_object_st {
    const char *sn, *ln;
    int nid;
    int length;
    const unsigned char *data;
    int flags;
};
typedef struct asn1_object_st ASN1_OBJECT;

數據類型轉換的ITEM定義:

在OpenSSL的實現中,每個數據類型都有一個ITEM結構,它負責定義這個數據類型的編解碼規則。

struct ASN1_ITEM_st {
    char itype;                 /* The item type, primitive, SEQUENCE, CHOICE
                                 * or extern */
    long utype;                 /* underlying type */
    const ASN1_TEMPLATE *templates; /* If SEQUENCE or CHOICE this contains
                                     * the contents */
    long tcount;                /* Number of templates if SEQUENCE or CHOICE */
    const void *funcs;          /* functions that handle this type */
    long size;                  /* Structure size (usually) */
    const char *sname;          /* Structure name */
};
typedef struct ASN1_ITEM_st ASN1_ITEM;
typedef const ASN1_ITEM ASN1_ITEM_EXP;

相關字段含義如下:
itype —— 定義ITEM自身的類型,取值:

#define ASN1_ITYPE_PRIMITIVE            0x0
#define ASN1_ITYPE_SEQUENCE             0x1
#define ASN1_ITYPE_CHOICE               0x2
#define ASN1_ITYPE_EXTERN               0x4
#define ASN1_ITYPE_MSTRING              0x5
#define ASN1_ITYPE_NDEF_SEQUENCE        0x6

utype —— 定義管理的數據類型,取值前面有說明,例如V_ASN1_INTEGER。
templates —— 數據處理方法模板數組指針。
tcount —— 模板數組的個數。
funcs —— 回調方法指針。
size —— 負責數據結構的大小。
sname —— 指向數據結構的名稱。

數據類型的函數聲明和實現:

前面講到,對每個數據類型來說,OpenSSL需要一個對應的ITEM結構,下面這幾個宏為每個數據類型聲明ITEM結構,同時也聲明了相應的助記函數。如下:

# define DECLARE_ASN1_FUNCTIONS(type) DECLARE_ASN1_FUNCTIONS_name(type, type)

# define DECLARE_ASN1_FUNCTIONS_name(type, name) \
        DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
        DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name)

# define DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
        type *name##_new(void); \
        void name##_free(type *a);

# define DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) \
        type *d2i_##name(type **a, const unsigned char **in, long len); \
        int i2d_##name(type *a, unsigned char **out); \
        DECLARE_ASN1_ITEM(itname)

#  define DECLARE_ASN1_ITEM(name) \
        OPENSSL_EXTERN const ASN1_ITEM name##_it;

#  define ASN1_ITEM_ref(iptr) (&(iptr##_it))
#  define ASN1_ITEM_rptr(ref) (&(ref##_it))

拿 DECLARE_ASN1_FUNCTIONS(ASN1_INTEGER) 來說,宏定義展開形式為:

ASN1_INTEGER *ASN1_INTEGER_new(void); 
void ASN1_INTEGER_free(ASN1_INTEGER *a);
type *d2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **in, long len); 
int i2d_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **out); 
const ASN1_ITEM ASN1_INTEGER_it;

還有幾個宏負責為數據類型實現相應的助記函數。如下:

# define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname)

# define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname)

# define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname) \
        IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \
        IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname)

# define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \
        stname *fname##_new(void) \
        { \
                return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \
        } \
        void fname##_free(stname *a) \
        { \
                ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \
        }

# define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \
        stname *d2i_##fname(stname **a, const unsigned char **in, long len) \
        { \
                return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\
        } \
        int i2d_##fname(stname *a, unsigned char **out) \
        { \
                return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\
        }

拿 IMPLEMENT_ASN1_ITEM(ASN1_INTEGER) 來說,其展開形式為:

ASN1_INTEGER *ASN1_INTEGER_new(void)
{
    return (ASN1_INTEGER*)ASN1_item_new(ASN1_ITEM_rptr(ASN1_INTEGER));
}
void ASN1_INTEGER_free(ASN1_INTEGER *a)
{
    ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(ASN1_INTEGER));
}
ASN1_INTEGER *d2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **in, long len)
{
    return (ASN1_INTEGER*)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(ASN1_INTEGER));
}
int i2d_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **out)
{
    return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(ASN1_INTEGER));
}

可以看到,展開形式所實現的助記函數實際上是對ASN1內部幾個函數的封裝調用,對提供上層數據類型與內部類型的轉換,其中ASN1_VALUE是類型上下轉換的紐帶,它是個萬能指針:
typedef struct ASN1_VALUE_st ASN1_VALUE;

在asn1.h中,對基本數據類型聲明了助記函數:

DECLARE_ASN1_FUNCTIONS(ASN1_INTEGER)
DECLARE_ASN1_FUNCTIONS(ASN1_ENUMERATED)
DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING)
DECLARE_ASN1_FUNCTIONS(ASN1_OCTET_STRING)
DECLARE_ASN1_FUNCTIONS(ASN1_NULL)
DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME)
DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME)
DECLARE_ASN1_FUNCTIONS(ASN1_TIME)
DECLARE_ASN1_FUNCTIONS(ASN1_UTF8STRING)

可是我暫時還沒有找到對基本數據類型助記函數的宏實現。

自定義結構體支持:

OpenSSL的ASN1編碼處理依賴ASN1_ITEM對象,對基本類型來說,OpenSSL本身已經做了聲明和初使化,所以可以直接以相關函數中使用。然而對于自定義結構體,需要開發者來定義ASN1_ITEM對象和規則,有一些宏可以提供幫助,摘錄部分如下:

# define ASN1_SEQUENCE(tname) \
        static const ASN1_TEMPLATE tname##_seq_tt[]

# define ASN1_SEQUENCE_END(stname) ASN1_SEQUENCE_END_name(stname, stname)

# define ASN1_SEQUENCE_END_name(stname, tname) \
        ;\
        ASN1_ITEM_start(tname) \
                ASN1_ITYPE_SEQUENCE,\
                V_ASN1_SEQUENCE,\
                tname##_seq_tt,\
                sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
                NULL,\
                sizeof(stname),\
                #tname \
        ASN1_ITEM_end(tname)

#  define ASN1_ITEM_start(itname) \
        const ASN1_ITEM itname##_it = {
#  define ASN1_ITEM_end(itname)                 \
                };

# define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0,0, stname, field, type)

# define ASN1_EX_TYPE(flags, tag, stname, field, type) { \
        (flags), (tag), offsetof(stname, field),\
        #field, ASN1_ITEM_ref(type) }

在ASN1_ITEM結構中,ASN1_TEMPLATE的結構定義如下:

struct ASN1_TEMPLATE_st {
    unsigned long flags;        /* Various flags */
    long tag;                   /* tag, not used if no tagging */
    unsigned long offset;       /* Offset of this field in structure */
    const char *field_name;     /* Field name */
    ASN1_ITEM_EXP *item;        /* Relevant ASN1_ITEM or ASN1_ADB */
};
typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE;

主要字段含義:
offset —— 字段在父結構中的偏移。
field_name —— 字段名稱。
item —— 指向字段對應結構類型的ASN1_ITEM對象。

舉例定義如下的自定義結構:

typedef  struct X509V4_VALID_st
{
    ASN1_GENERALIZEDTIME *notBefore;
    ASN1_GENERALIZEDTIME *notAfter;
} X509V4_VALID;
DECLARE_ASN1_FUNCTIONS(X509V4_VALID)

ASN1_SEQUENCE(X509V4_VALID) =
{
    ASN1_SIMPLE(X509V4_VALID, notBefore, ASN1_GENERALIZEDTIME),
    ASN1_SIMPLE(X509V4_VALID, notAfter, ASN1_GENERALIZEDTIME)
} 
ASN1_SEQUENCE_END(X509V4_VALID)
IMPLEMENT_ASN1_FUNCTIONS(X509V4_VALID)

將宏展開,為:

static const ASN1_TEMPLATE X509V4_VALID_seq_tt[] = 
{
    { 0, 0, offsetof(X509V4_VALID, notBefore), notBefore, ASN1_ITEM_ref(ASN1_GENERALIZEDTIME) },
    { 0, 0, offsetof(X509V4_VALID, notAfter), notAfter, ASN1_ITEM_ref(ASN1_GENERALIZEDTIME) }
};
const ASN1_ITEM X509V4_VALID_it = {
    ASN1_ITYPE_SEQUENCE,\
    V_ASN1_SEQUENCE,\
    X509V4_VALID_seq_tt,\
    sizeof(X509V4_VALID_seq_tt) / sizeof(ASN1_TEMPLATE),\
    NULL,\
    sizeof(X509V4_VALID,),\
    X509V4_VALID \
};

常用函數:

ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it);
void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it);
根據ITEM對象創建和釋放對應的數據類型。

ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_ITEM *it);
根據ITEM對象將DER編碼轉換為二進制結構。
成功返回有效指針,成功返回NULL。
如果val為NULL,將內部分配內存,但必須由外部使用者釋放。
其內部實現為:

{
    ASN1_TLC c;
    ASN1_VALUE *ptmpval = NULL;
    if (!pval)
        pval = &ptmpval;
    asn1_tlc_clear_nc(&c);
    if (ASN1_item_ex_d2i(pval, in, len, it, -1, 0, 0, &c) > 0)
        return *pval;
    return NULL;
}

可以看到內部做了為val傳入NULL的兼容性處理。

int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it);
根據ITEM對象將二進制結構轉換為DER編碼。
成功返回DER編碼長度,失敗返回負數。
如果*out為NULL,將內部分配內存,但內存必須由外部使用者釋放。若**out為NULL,將僅返回長度,這用于試探長度的場景。
其內部實現為:

{
    if (out && !*out) {
        unsigned char *p, *buf;
        int len;

        len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags);
        if (len <= 0)
            return len;
        if ((buf = OPENSSL_malloc(len)) == NULL) {
            ASN1err(ASN1_F_ASN1_ITEM_FLAGS_I2D, ERR_R_MALLOC_FAILURE);
            return -1;
        }
        p = buf;
        ASN1_item_ex_i2d(&val, &p, it, -1, flags);
        *out = buf;
        return len;
    }

    return ASN1_item_ex_i2d(&val, out, it, -1, flags);
}

可以看到內部做了為out和*out傳入NULL的兼容性處理。在out傳入NULL的情況下,無法接收緩沖區,只能返回長度。

void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x);
根據ITEM對象將DER編碼轉換為二進制結構,輸入的DER編碼來源于BIO對象。
成功返回有效指針,成功返回NULL。
事實上,本函數是對ASN1_item_d2i()的封裝調用。
其內部實現為:

{
    const unsigned char *p;
    void *ret = NULL;
    int len;

    BUF_MEM *b = NULL;
    len = asn1_d2i_read_bio(in, &b);
    if (len < 0)
        goto err;

    p = (const unsigned char *)b->data;
    ret = ASN1_item_d2i(x, &p, len, it);
 err:
    BUF_MEM_free(b);
    return ret;
}

void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x);
ASN1_item_d2i_bio()的FILE版本。

ASN1_item_d2i_bio()和ASN1_item_d2i_fp() 這兩個函數關于輸出參數x的類型定義是不恰當的,后面講的 ASN1_d2i_bio()和ASN1_d2i_bio() 有修復這個問題。

int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x);
根據ITEM對象將二進制結構轉換為DER編碼,輸出到BIO對象中。
成功返回DER編碼長度,失敗返回負數。
如果*out為NULL,將內部分配內存,但內存必須由外部使用者釋放。事實上,本函數是對ASN1_item_i2d()的封裝調用。
其內部實現為:

{
    int i, j = 0, n, ret = 1;

    unsigned char *b = NULL;
    n = ASN1_item_i2d(x, &b, it);
    if (b == NULL) {
        ASN1err(ASN1_F_ASN1_ITEM_I2D_BIO, ERR_R_MALLOC_FAILURE);
        return 0;
    }

    for (;;) {
        i = BIO_write(out, &(b[j]), n);
        if (i == n)
            break;
        if (i <= 0) {
            ret = 0;
            break;
        }
        j += i;
        n -= i;
    }
    OPENSSL_free(b);
    return ret;
}

int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x);
ASN1_item_i2d_bio()的FILE版本。

其實上,以上函數由于直接需要ASN1_ITEM做為參數,很少在程序中直接使用,而是由DECLARE_ASN1_FUNCTIONS宏聲明的變體,或者下面介紹的函數代替。

void *ASN1_d2i_bio(void *(*xnew) (void), d2i_of_void *d2i, BIO *in, void **x);
從BIO對象讀取DER編碼數據,轉換為對應的二進制結構,具體的轉換依賴d2i函數指針。
成功返回有效指針,失改返回NULL。
其內部實現為:

{
    BUF_MEM *b = NULL;
    int len = asn1_d2i_read_bio(in, &b);
    if (len < 0)
        goto err;
    const unsigned char *p = (unsigned char *)b->data;
    void *ret = d2i(x, &p, len);
 err:
    BUF_MEM_free(b);
    return ret;
}

void *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x);
ASN1_d2i_bio()的FILE版本。

int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, unsigned char *x);
將二進制結構轉換為DER編碼,輸出到BIO中,具體的轉換依賴i2d函數指針。
成功返回1,失敗返回0。
其內部實現為:

{
    int ret = 1;

    int n = i2d(x, NULL);
    if (n <= 0)
        return 0;

    char* b = OPENSSL_malloc(n);
    unsigned char *p = (unsigned char *)b;
    i2d(x, &p);

    int i, j = 0;
    for (;;) {
        i = BIO_write(out, &(b[j]), n);
        if (i == n)
            break;
        if (i <= 0) {
            ret = 0;
            break;
        }
        j += i;
        n -= i;
    }
    OPENSSL_free(b);
    return ret;
}

int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, void *x);
ASN1_i2d_bio() 的FILE版本。

上面d2i_of_void 和 i2d_of_void 函數的簽名為:

# define D2I_OF(type) type *(*)(type **,const unsigned char **,long)
# define I2D_OF(type) int (*)(type *,unsigned char **)

通常為數據類型的轉換助記函數。

int ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
將v值設置到a中。成功返回1,失敗返回0。
long ASN1_INTEGER_get(const ASN1_INTEGER *a);
獲取a中存儲的整數值。失敗返回-1。
int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v);
將v值設置到a中。成功返回1,失敗返回0。
long ASN1_ENUMERATED_get(const ASN1_ENUMERATED *a);
獲取a中存儲的枚舉值。失敗返回-1。
int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len);
將data和len指向的串值設置到str中。成功返回1,失敗返回0。
unsigned char *ASN1_STRING_data(ASN1_STRING *x);
獲取x的字符串首指針。成功返回有效指針,失敗返回NULL。
int ASN1_STRING_length(const ASN1_STRING *x);
獲取x的字符串長度。

int i2a_ASN1_INTEGER(BIO *bp, const ASN1_INTEGER *a);
將ASN1_INTEGER轉換為ASC碼,輸出到bp中。成功返回1,失敗返回0。
int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size);
將bp中的ASC碼轉換為ASN1_INTEGER,buf存放BIO的ASC碼。成功返回1,失敗返回0。
int i2a_ASN1_ENUMERATED(BIO *bp, const ASN1_ENUMERATED *a);
將ASN1_ENUMERATED轉換為ASC碼,輸出到bp中。成功返回1,失敗返回0。
int a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size);
將bp中的ASC碼轉換為ASN1_ENUMERATED,buf存放BIO的ASC碼。成功返回1,失敗返回0。
int i2a_ASN1_STRING(BIO *bp, const ASN1_STRING *a, int type);
將a中的字符串轉換為ASC碼輸出到bp中,type不起作用。返回轉換的ASC字符串長度。
int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size);
將bp中的ASC碼轉換為ASN1_STRING,buf存放BIO的ASC碼。成功返回1,失敗返回0。

ASN1_OBJECT *ASN1_OBJECT_new(void);
分配OID對象。
void ASN1_OBJECT_free(ASN1_OBJECT *a);
釋放OID對象。

OID的編碼規為:第一個八位組采用公式:first_arc* 40+second_arc。如果一個數大于127,就采用多個8位表示,最高位用1表示后續還有octet,用0表示后續沒有。成功返回OID編碼的字節數。

int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num);
計算由ASC字符串指定的OID的DER編碼。返回編碼的字節數。所果事先需要知道編碼的長度來分配內存,可以設置out為NULL,olen為0,獲取編碼字節長度,根據該長度再去分配內存。

ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp, long length);
將DER編碼轉換為OID對象。成功返回有效指針。
int i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp);
將OID對象換轉為DER編碼。返回DER編碼的長度。
int i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *a);
將DER編碼轉換為ASC字符串,結果輸出到bp中。返回ASC字符串長度。

使用舉例:

下面這個例子測試了很多函數的用法,請自行放開注釋并測試。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <openssl/asn1.h>
#include <openssl/asn1t.h>

namespace dakuang {}

void printHex(const char* pBuf, int nLen)
{
    for (int i = 0; i < nLen; ++i)
    {
        printf("%02x", (unsigned char)pBuf[i]);
    }
    printf("\n");
}

int main(int argc, char* argv[])
{
/*
    int len = a2d_ASN1_OBJECT(NULL, 0, "1.2.840.10040.4.1", -1);
    printf("len:%d \n", len);
    char* pBuf = (char*)malloc(len);
    int ret = a2d_ASN1_OBJECT((unsigned char *)pBuf, len, "1.2.840.10040.4.1", -1);
    printf("ret:%d \n", ret);
    printf("buf => ");
    printHex(pBuf, len);
    free(pBuf);
*/

/*
    BIO* bp = BIO_new(BIO_s_mem());
    BIO_write(bp, "0FAB08BBDDEECC", 14);
    ASN1_INTEGER* i = ASN1_INTEGER_new();
    char sBuf[50] = {0};
    int ret = a2i_ASN1_INTEGER(bp, i, sBuf, 50);
    printf("ret:%d \n", ret);
    long l = ASN1_INTEGER_get(i);
    printf("l:[%ld] \n", l);
    ASN1_INTEGER_free(i);
    BIO_free(bp);
*/

/*
    BIO* bp = BIO_new(BIO_s_mem());
    BIO_write(bp, "B2E2CAD4", 8);
    ASN1_STRING* str = ASN1_STRING_new();
    char sBuf[50] = {0};
    int ret = a2i_ASN1_STRING(bp, str, sBuf, 50);
    printf("ret:%d \n", ret);
    int len = ASN1_STRING_length(str);
    printf("len:%d \n", len);
    printf("buf => ");
    printHex(sBuf, len);
    unsigned char* p = ASN1_STRING_data(str);
    printf("str:[%s] \n", p);
    ASN1_STRING_free(str);
    BIO_free(bp);
*/

/*
    ASN1_INTEGER* i = ASN1_INTEGER_new();
    int ret = ASN1_INTEGER_set(i, 123);
    printf("ret:%d \n", ret);
    long l = ASN1_INTEGER_get(i);
    printf("l:[%ld] \n", l);
    ASN1_INTEGER_free(i);
*/

/*
    ASN1_STRING* str = ASN1_STRING_new();
    int ret = ASN1_STRING_set(str, "abc", 3);
    printf("ret:%d \n", ret);
    unsigned char* p = ASN1_STRING_data(str);
    printf("str:[%s] \n", p);
    ASN1_STRING_free(str);
*/

/*
    ASN1_STRING* str = ASN1_STRING_new();
    int ret = ASN1_STRING_set(str, "abc", 3);
    printf("ret:%d \n", ret);
    BIO* bp = BIO_new(BIO_s_file());
    BIO_set_fp(bp, stdout, BIO_NOCLOSE);
    ret = i2a_ASN1_STRING(bp, str, 0);
    printf("ret:%d \n", ret);
    BIO_free(bp);
    ASN1_STRING_free(str);
*/

/*
    BIO* out = BIO_new_file("int.cer","w");
    ASN1_INTEGER* a = ASN1_INTEGER_new();
    ASN1_INTEGER_set(a, 100);
    int ret = ASN1_i2d_bio((i2d_of_void*)i2d_ASN1_INTEGER, out, (unsigned char*)a);
    printf("ret:%d \n", ret);
    BIO_free(out);
*/

/*
    BIO* in = BIO_new_file("int.cer","r");
    ASN1_INTEGER* a = ASN1_INTEGER_new();
    ASN1_d2i_bio(NULL, (d2i_of_void *)d2i_ASN1_INTEGER, in, (void**)&a);
    long l = ASN1_INTEGER_get(a);
    printf("l:[%ld] \n", l);
    ASN1_INTEGER_free(a);
    BIO_free(in);
*/

/*
    char buf[50] = {0};
    int ret = a2d_ASN1_OBJECT((unsigned char*)buf, 50, "1.2.3.4", -1);
    printf("ret:%d \n", ret);
    printf("buf => ");
    printHex(buf, ret);
    ASN1_OBJECT* o = ASN1_OBJECT_new();
    printf("o:[%p] \n", o);
    d2i_ASN1_OBJECT(&o, (const unsigned char**)&buf, ret);
    ret = i2d_ASN1_OBJECT(o, (unsigned char**)&buf);
    printf("ret:%d \n", ret);
    BIO* bp = BIO_new(BIO_s_file());
    BIO_set_fp(bp, stdout, BIO_NOCLOSE);
    ret = i2a_ASN1_OBJECT(bp, o);
    printf("ret:%d \n", ret);
    BIO_free(bp);
    ASN1_OBJECT_free(o);
*/
    return 0;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • hash表 數據結構:使用鏈表數組實現 相關接口 內存分配 內存相關數據結構 內存操作相關接口 CRYPTO_me...
    鏡中無我閱讀 594評論 0 0
  • 轉:http://caisenchen.blog.163.com/blog/static/552865502008...
    right_33cb閱讀 4,455評論 0 4
  • 大數一般指的是位數很多的數。計算機表示的數的大小是有限的,精度也是有限的,它不能支持大數運算。密碼學中采用了很多大...
    大匡先生閱讀 3,920評論 0 1
  • 隨機數是一種無規律的數,但是真正做到完全無規律也較困難,所以一般將它稱之為偽隨機數。隨機數在密碼學用的很多,比如S...
    大匡先生閱讀 8,125評論 0 2
  • 16宿命:用概率思維提高你的勝算 以前的我是風險厭惡者,不喜歡去冒險,但是人生放棄了冒險,也就放棄了無數的可能。 ...
    yichen大刀閱讀 6,098評論 0 4