1. 程式人生 > >13.openssl程式設計——ASN1庫

13.openssl程式設計——ASN1庫

13.1  ASN1簡介 ANS.1(Abstract Syntax Notation One, X.208),是一套靈活的標記語言,他允許定義多種資料型別,從integer、bit string、一類的簡單型別到結構化型別,如set和sequence,並且可以使用這些型別構建複雜型別。 DER編碼是ANS.1定義的將物件描述資料編碼成8位串值的編碼規則,他給出了對ANS.1值(物件的型別和值)的唯一編碼規則。 a  簡單型別                      BIT STRING  任意0、1位串;                      IA5String      任意IA5(ASCII)字串;                      INTEGER   任意一個整數;                      NULL      空值;                      OBJECT IDENTIFIER 一個物件標識號(一串整數),標識演算法或屬性型別等物件;                      OCTET STRING 8位串;                      PrintableString       任意可列印字串;                      T61String       任意T.61(8位)字串;                      UTCTime       一個“協同世界時”或“格林威治標準時(G.M.T)”。 b    結構型別                      結構型別由元件組成,ANS.1定義了四種結構型別:                      SEQUENCE                  一個或多個型別的有序排列;                      SEQUENCE OF            一個給定型別的0個或多個有序排列;                      SET                             一個或多個型別的無序集合;                      SET OF                     一個給定型別的0個或多個無序集合。        c    帶標記型別 在一個應用內部區分型別的有效方法是使用標記,標記也同樣用於區分一個結構型別內部不同的元件。例如SET或SEQUENCE型別可選項通常使用上下文標記以避免混淆。有兩種標記型別的方法:隱式和顯式。隱式標記型別是將其它型別的標記改變,得到新的型別。隱式標記的關鍵字是IMPLICIT。顯式標記型別是將其它型別加上一個外部標記,得到新的型別。顯式標記的關鍵字是EXPLICIT。 為了進行編碼,隱式標記型別除了標記不同以外,可以視為與其基礎型別相同。顯式標記型別可以視為只有一個元件的結構型別。       d    其它型別 型別和值用符號::=表示,符號左邊的是名字,右邊是型別和值。名字又可以用於定義其它的型別和值。 除了CHOICE型別、ANY型別以外,所有ANS.1型別都有一個標記,標記由一個類和一個非負的標記碼組成,當且僅當標記碼相同時,ANS.1型別是相同的。也就是說,影響其抽象意義的不是ANS.1型別的名字,而是其標記。 13.2 DER編碼
DER給出了一種將ASN.1值為8位串的方法。DER編碼包含三個部分: 標識(一個或多個8位串):定義值的類和標記碼,指出是原始編碼還是結構化編碼 長度(一個或多個8位串):對於定長編碼,指出內容中8位串的個數;對於不定長編碼 內容(一個或多個8位串):對於原始定長編碼,給出真實值,對於結構化編碼,給出個串聯結果 內容結束(一個或多個8位串):對於結構化不定長編碼,標識內容結束,對於其他編碼,無此項。 13.3 ANS1基本型別示例 a.ANS1_BOOLEAN 表明ASN1語法中的true和flase。 其中0x01 (表示為BOOLEAN) 0x01(表示後面值的長度) 0x00(值)為本例BOOLEAN
DER編碼。 b.ANS1_OBJECT ANS1中OBJECT表明一個物件,每個物件有一個OID(object id) 其中0x06(表示為OBJECT型別) 0x03(值的長度) 0x55 0x04 0x0A c.ASN1_INTEGER ANS1中的INTEGER型別用於表示整數。 其內容為:0x30 0x03 0x02(整數) 0x01 (整數值長度)0x55 (整數值) d.ASN1_ENUMERATED e. ASN1_BIT_STRING 0x01 0x02的DER編碼:0x03(BIT STRING 型別) 0x02(長度) 0x01 0x02(位元值) f.ANS1_OCTET_STRING 0x04(OCTET STRING) 0x02(長度) 0x01 0x02(值) g.ASN1_PRINGTABLESTRING
可列印字元 0x13(PRINTABLESTRING) 0x04(長度) 0x61 0x73 0x6E 0X31(即"asn1") ASN1_UTCTIME:表示時間 ASN1_GENERALIZEDTIME:表示時間 ASN1_VISIBLESTRING:存放可見字元 ASN1_UTF8STRING:用於存放utf8字串,存放漢子需要將漢子轉換utf8字串 ASN1_TYPE:用於存放任意型別 13.4 openssl的ASN.1庫 typedef struct asn1_string_st ASN1_INTGER; ASN1_INTEGER ASN1_ENUMERATED ASN1_BIT_STRING ASN1_OCTET_STRING ASN1_PRINTABLESTRING ASN1_T61STRING ASN1_IAS5STRING ASN1_UTCTIME ASN1_GENERALIZEDTIME ASN1_TIME ASN1_GENERALSTRING ASN1_TIME ASN1_GENERALSTRING ASN1_UNIVERSALSTRING ASN1_BMPSTRING ASN1_VISIBLESTRING ASN1_UTF8STRING ASN1_BOOLEAN ASN1_NULL 四種基本的函式 new:用於生成一個新的資料結構 free:用於釋放該結構 i2d:用於將該內部資料結構轉換成DER編碼 d2i:用於將DER編碼轉換成內部資料結構 ASN1_INTEGER_ASN1_INTEGER_new(void); void *ASN1_INTEGER_free(ASN1_INTEGER *a) ASN1_INTEGER *d2i_ASN1_INTEGER(ASN1_INTEGER **a, unsigned char **in, long ,len) int i2d_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **out); long ASN1_INTEGER_get(ASN1_INTEGER *a) int ASN1_INTEGER_set(ASN1_INTEGER *a, long v) 13.5 用openssl的ASN.1庫DER編解碼 當採用openssl的ASN.1庫編碼一個asn.1定義結構的時候,需要採用如下步驟 a.用ASN.1語法定義內部資料結構,並宣告函式 所謂內部資料結構,指的是openssl中用基本的資料型別按照ASN.1語法資料結構 以x509v4中正數有效期為例,正數有效期定義如下: AttCertValidityPeriod::= SEQUENCE { notBeforeTime GeneralizedTime, notAfterTime GenerailizedTime, } 我們定義相應內部資料結構 typedef struct X509V4_VALID_st { ASN1_GENERALIZEDTIME *notBefore; ASN1_GENERALIZEDTIME *notAfter; } X509V4_VALID; DECLARE_ASN1_FUNCTIONS(X509V4_VALID) 其中最後一行用於定義四個函式 X509V4_VALID *X509V4_VALID_new(void); void *X509V4_VALID_free(X509V4_VALID *a); X509V4_VALID *d2i_ASN1_INTEGER(X509V4_VALID **a, unsgined char **in, long len); b. 實現內部資料結構的四個基本函式 實現內部資料結構的基本函式,是通過一系列的紅來實現的。定義的模式如下,定義的模式如下,以屬性證書有效期為例, /*X509V4_VALID*/ ASN1_SEQUENCE(X509V4_VALID) = { ASN1_SIMPLE(X509V4_VALID, notBefore, ASN1_GENERALIZEDTIME), ASN1_SIMPLE(X509V4_VALID, notAfter, ASN1_GENERALIZEDTIME) } ASN1_SEQUNCE_END(X509V4_VALID) IMPLEMENT_ASN1_FUNCTIONS(X509V4_VALID) 這樣通過巨集實現了一個asn.1定義結構的最基本的四個函式 13.6 Openssl的ASN.1巨集 openssl中ASN.1巨集用來定義某種內部資料結構以及這種結構如何編碼,部分巨集定義說明如下 a.DECLARE_ASN1_FUNCTIONS 用於宣告一個內部資料結構的四個基本函式,一般可以在標頭檔案中定義。 b.IMPLEMENT_ASN1_FUNCTIONS 用於實現一個數據結構的四個基本函式 c.ASN1_SEQUENCE 用於SEQUENCE,表明下面的編碼是一個SEQUENCE. d.ASN1_CHOICE 表明下面的編碼是選擇其中一項,為CHOICE型別 e.ASN1_SIMPLE 用於簡單型別或結構型別,並且是必須項。 f.ANS1_OPT 用於可選項,表明asn.1語法中,本項可選的。 g.ANS1_EXP_OPT 用於顯示標記,表明asn.1語法中,本項是顯示型別,並且是可選的。 h.ASN1_EXP 用於顯示標記,表明asn.1語法中,本項是顯示標記 i.ASN1_IMP_SEQUENCE_OF_OPT 用於隱示標記,表明asn.1語法中,本項是一個SEQUENCE序列,為隱的。 j.ASN1_IMP_OPT 用於隱示標記,表明asn.1語法中,本想是隱示型別,並且是可選的。 k.ASN1_SEQUENCE_END 用於SEQUENCE結束 l.ASN1_CHOICE_END 用於結束CHOICE型別。 13.7 ASN1常用函式 ANS1的基本資料型別如下函式:new, free, i2d, d2i, i2a a2i print set get cmp和dup。 new函式用於分配空間,生成ASN1資料結構 free用於釋放空間 i2d函式用於ASN1資料結構轉換為DER編碼 d2i將DER編碼轉換為ASN1資料結構 i2a將內部結構轉換為ASCII碼 a2i將ASCII碼轉換為內部資料結構 set函式用於設定ASN1型別的值 get函式用於獲取ASN1型別值 print將ASN1型別列印 cmp用於比較ASN1資料結構 dup函式進行資料結構的拷貝。 常用的函式有: a.int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num) 功能:計算OID的DER編碼 b.int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size) 功能:將bp中ASC碼轉換為ASN1_INTEGER,buf存放BIO中ASC碼 c.int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size) 功能:將ASCII碼轉換為ASN1_STRING d.unsigned char *asc2uni(const char *asc, int asclen, usngined char **uni, int *unilen) 功能:將ASCII碼轉換為unicode e.int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n) 功能:本函式根據n獲取位元位上的值 f.ASN1_BIT_STRING_set 設定ASN1_BIT_STRING的值,他呼叫ASN1_STRING_set函式 g.void *ASN1_d2i_bio(void *(xnew)(void), d2i_of_void *d2i, BIO *in, void **x) 對bio的資料DER解碼,xnew無意義,d2i為DER解碼函式,in為bio資料,x為資料型別,返回值為解碼後的結果。 h.void *ANS1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x) 將in只想的檔案進行DER解碼,器內部呼叫了ASN1_d2i_b函式,用法與ASN1_d2i_b類似。 i.int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, unsigned char *x) 將ASN1資料結構DER編碼,並將結果寫入bio j.int ASN1_i2d_fp(i2d_of_void *i2d, d2i_of_void *d2i, char *x) ASN1資料複製。x為ASN1內部資料結構,本函式先將x通過i2d將他變成DER編碼,然後用d2i在DERb編碼結果 k.ASN1_ENUMERATED_set 設定ASN1_ENUMERATED的值 l.ASN1_ENUMERATED_get 獲取ASN1_ENUMERTED的值。 m.BIGNUM * ANS1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai, BIGNUM *bn) 將ASN1_ENUMERATED型別轉換為BN大數型別。此函式呼叫BN_bin2bn函式獲取bn,如果ai->type表明他在呼叫BN_set_negative設定bn成負數。 n.int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len; int indent, int dump) 本函式用於將pp和len指明的DER編碼值寫在BIO中,其中indent和dump用於設定列印的格式。 o.int ASN1_sign(i2d_of_void *i2d, X509_ALGOR *algor1, X509_LAGOR *algor2, ANS1_BIT_STRING *data, EVP_PKEY *pkey, const EVP_MD *type) 對ASN1資料型別簽名。i2d為ASN1資料的DER方法,signature用於存放簽名結果,data為ASN1資料指標,pkey指明簽名金鑰,type為摘要演算法,algor1和algor2無用,可全為NULL.簽名時,先將ASN1資料DER編碼,然後摘要,最後簽名運算 p.ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *str) ASN1_STRING型別拷貝。內部申請空間,需要使用者呼叫ASN1_STRING_free釋放該空間 q.int ASN1_STRING_cmp(ASN1_STRING *a, ASN1_STRING *b) ASN1_STRING比較.ossl_typ.h中絕大多數ASN1基本型別都定義 ASN1_STRING,所以,此函式比較通用。 r.unsigned char *ASN1_STRING_data(ASN1_STRING *x) 獲取ASN1_STRING資料存放地址,即ASN1_STRING資料結構中data地址。 s.int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len) 設定ASN1字串型別的值。str為ASN1_STRING地址,_data為設定值的首地址,len為被設定值的長度。 t.ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid) 根據nid來查詢ASN1_STRING_TABLE表。此函式先查詢標準表tbl_standard,再查詢擴充套件表stable。 u.ASN1_STRING *ASN1-STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in , int inlen, int inform, int nid) 根據nid和輸入值獲取對應的ASN1_STIRNG型別 static const ASN1_STRING_TABLE tbl_standard[] = { {NID_commonName, 1, ub_common_name, DIRSTRING_TYPE, 0}, {NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, {NID_localityName, 1, ub_locality_name, DIRSTRING_TYPE, 0}, {NID_stateOrProvinceName, 1, ub_state_name, DIRSTRING_TYPE, 0}, {NID_organizationName, 1, ub_organization_name, DIRSTRING_TYPE, 0}, {NID_organizationalUnitName, 1, ub_organization_unit_name, DIRSTRING_TYPE, 0}, {NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING, STABLE_NO_MASK}, {NID_pkcs9_unstructuredName, 1, -1, PKCS9STRING_TYPE, 0}, {NID_pkcs9_challengePassword, 1, -1, PKCS9STRING_TYPE, 0}, {NID_pkcs9_unstructuredAddress, 1, -1, DIRSTRING_TYPE, 0}, {NID_givenName, 1, ub_name, DIRSTRING_TYPE, 0}, {NID_surname, 1, ub_name, DIRSTRING_TYPE, 0}, {NID_initials, 1, ub_name, DIRSTRING_TYPE, 0}, {NID_serialNumber, 1, ub_serial_number, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, {NID_friendlyName, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK}, {NID_name, 1, ub_name, DIRSTRING_TYPE, 0}, {NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, {NID_domainComponent, 1, -1, B_ASN1_IA5STRING, STABLE_NO_MASK}, {NID_ms_csp_name, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK}, {NID_rfc822Mailbox, 1, ub_rfc822_mailbox, B_ASN1_IA5STRING, STABLE_NO_MASK}, {NID_jurisdictionCountryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, {NID_INN, 1, 12, B_ASN1_NUMERICSTRING, STABLE_NO_MASK}, {NID_OGRN, 1, 13, B_ASN1_NUMERICSTRING, STABLE_NO_MASK}, {NID_SNILS, 1, 11, B_ASN1_NUMERICSTRING, STABLE_NO_MASK}, {NID_countryCode3c, 3, 3, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, {NID_countryCode3n, 3, 3, B_ASN1_NUMERICSTRING, STABLE_NO_MASK}, {NID_dnsName, 0, -1, B_ASN1_UTF8STRING, STABLE_NO_MASK} }; v.void ASN1_STRING_set_default_mask(unsigned long mask) 設定ASN1_STRING_set_by_NID函式返回的ASN1_STRING型別。 w.int ASN1_STRING_set_defualt_mask_asc(char *p) 設定ASN1_STRING_set_by_NID函式返回ASN1_STRING型別。字串p可以的值由:nombstr, pkix\utf8only和defualt x.int ASN1_STRING_TABLE_add(int nid, long minsize, long maxsize, usngiend long mask, unsigned long flags) 新增擴充套件ASN1_STRING_TABLE項 y.void ASN1_STRING_TABLE_cleanup(void) 清除使用者自建的擴充套件ASN1_STRING_TBALE表 z.int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a) 將整數轉換為ASCII碼,放在BIO中。 a1.int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type) type不起作用,將ASN1_STRING轉換為ASCII碼 b1.OBJ_bsearch 用於從排序好的資料結構地址陣列中用二分法查詢資料。 c1.OBJ_create 根據oid以及名稱資訊生成一個你不的object d1.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函式用於根據名字獲取對稱演算法或者摘要演算法。 e1. int OBJ_new_nid(int num) 此函式將內部的new_nid加num,返回原nid f1.const char *OBJ_nid2ln(int n) 根據nide得到物件的描述 g1.OBJ_nid2obj 根據nid得到物件 h1.const char *OBJ_nid2sn(int n) 根據nid得到的物件的sn(簡稱) i1.OBJ_nid2obj 根據nid得到物件 j1.const char *OBJ_nid2sn(int n) 根據nid得到物件 k1.int OBJ_obj2nid(const ASN1_OBJECT *a) 根據物件獲取其nid; l1 int OBJ_obj2nid(const ASN1_OBJECT *a) 根據物件獲取器nid; m1 OBJ_obj2txt 根據物件獲取物件說明或者nid n1.OBJ_txt2obj 根據sn或者ln得到的物件 13.8 屬性證書編碼 對屬性證書(x509v4)編碼 typedef struct X509V4_VALID_st { ASN1_GENERALIZEDTIME *notBefor; ASN1_GENERALIZEDTIME *notAfer; }X509V4_VALID; DECLARE_ASN1_FUNCTIONS(X509V4_VALID) typedef struct ISSUERSERIAL_st { GENERAL_NBAMES *issuer; ASN1_INTEGER *subjectSN; ASN1_BIT_STRING *issuerUID; } ISSUERSERIAL; DECLARE_ASN1_FUNCTIONS(ISSUERSERIAL) typedef struct OBJDIGEST_st { ASN1_ENUMERATE *digestType; ASN1_OBJECT *otherType; X509_ALGOR *digestAlg; ASN1_BIT_STRING *digestBit; } OBJDIGEST; DECLARE_ASN1_FUNCTIONS(OBJDIGEST) typedef struct ACHOLDER_st { ISSUERSERIAL *baseCertificateID; GENERAL_NAMES *entiyName OBJDIGEST *objDigest; }ACHOLDER; DECLARE_ASN1_FUNCTIONS(ACHOLDER) typedef struct V2FORM_st { GENERAL_NAMES *entiyName; issuerserial *baseCertificateID; OBJDIGEST *objDigest; }V2FORM; DECLARE_ASN1_FUNCTIONS(V2FORM) typedef struct ACISSUER_st { int type; union { V2FORM *v2Form; }form; } ACISSUER; DECLARE_ASN1_FUNCTIONS(ACISSUER) ASN1_SEQUENCE(ISSUERSERIAL) = { asn1_simple(issuerserial, ISSUER, GENERAL_NAMES), ASN1_SIMPLE(ISSUERSERIAL, subjectSN, ASN1_INTEGER) ASN1_OPT(ISSUERSERIAL, isserUID, ASN1_BIT_STIRNG) }ASN1_SEQUENCE_END(ISSUERSERIAL) IMPLEMENT_ASN1_FUNCTIONS(ISSUERSERIAL) ASN1_SEQUENCE(OBJDIGEST) = { ASN1_SIMPLE(OBJDIGEST, digestType, ASN1_ENUMERATED), ASN1_OPT(OBJDIGEST, otherType, ASN1_OBJECT), ASN1_SIMPLE(OBJDIGEST, digestAlg, X509_ALGOR) ASN1_SIMPLE(OBJDIGEST, digestBit, ASN1_BIT_STRING) } ASN1_SEQUENEC_END(OBJDIGEST) IMPLEMENT_ASN1_FUNCTIONS(OBJDIGEST) ASN1_SEQUENCE(X509V4_ALID) = { ASN1_SIMPLE(X509V4_VALID, notBefore, ASN1_GENERALIZEDTIME) ASN1_SIMPLE(X509V4_VALID, notAfer, ASN1_GENERALIZEDTIME) }IMPLEMENT_ASN1_FUNCTIONS(X509V4_VALID)\ ASN1_SEQUENCE(X5409V4_CINF) = { ASN1_SIMPLE(X509V4_CINF, version, ASN1_INTEGER) ASN1_SIMPLE(X509V4_CINF, holder, ACHOLDER) ASN1_SIMPLE(X509V4_CINF, issuer, ACISSUER) ASN1_SIMPLE(X509V4_CINF, signature, ACISSUER) ASN1_SIMPLE(X509V4_CINF, serialNumber, ASN1_INTEGER) ASN1_SIMPLE(X509V4_CINF, X509V4_VALID) ASN1_SIMPLE(X509V4_CINF,attributes, X509_ATTRIBUTE) ASN1_SIMPLE(X509V4_CINF, issuerUID, ASN1_BIT_STRING) ASN1_SIMPLE(X509V4_CINF, EXTENSIONS, x509_extension }ASN1_SEQUENCE_END(X509V4_CINF) IMPLEMENT_ASN1_FUNCTIONS(X509V4_CINF) ASN1_SEQUENCE(X509V4) = { ASN1_SIMPLE(X509V4, cert_info, X509V4_CINF) ASN1_SIMPLE(X509V4, sig_alg, X509_ALGOR) ASN1_SIMPLE(X509V4, signature, ASN1_BIT_STRING) }ASN1_SEQUENCE_END(X5509V4)