1. Trang chủ
  2. » Công Nghệ Thông Tin

cryptography for developers 2006 phần 3 potx

44 301 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 44
Dung lượng 239 KB

Nội dung

025 { 'e', 101 }, { 'f', 102 }, { 'g', 103 }, { 'h', 104 }, 026 { 'i', 105 }, { 'j', 106 }, { 'k', 107 }, { 'l', 108 }, 027 { 'm', 109 }, { 'n', 110 }, { 'o', 111 }, { 'p', 112 }, 028 { 'q', 113 }, { 'r', 114 }, { 's', 115 }, { 't', 116 }, 029 { 'u', 117 }, { 'v', 118 }, { 'w', 119 }, { 'x', 120 }, 030 { 'y', 121 }, { 'z', 122 }, { '{', 123 }, { '|', 124 }, 031 { '}', 125 }, { '~', 126 } }; For the interested reader it is possible to save space both in the table and in the code space. If a third parameter were added to the table to say which code type the symbol belonged to (e.g., IA5 or PRINTABLE), a single encode/decoder could be written with an additional input argument specifying which target code we are trying to use. For the sake of simplicity, the routines demonstrated were implemented individually. They are fairly small and in the grand scheme of things are not significant code size contributors. UTCTIME Encodings UTCTIME encoding has been simplified in the 2002 specifications to only include one format.The time is encoded as a string in the format “YYMMDDHHMMSSZ” using two digits per component. The year is encoded by examining the last two digits. Nothing beyond the year 2069 can be encoded with this format as it will be interpreted as 1970 (of course, by that time we can just reprogram the software to treat it as 2070). Despite the Y2K debacle, they still used two digits for the date. The actual byte encoding of the string is using the ASCII code, and fortunately, we have to look no further than our PRINTABLE STRING routines for help. To efficiently handle dates we require some structure to hold the parameters. We could just pass all six of them as arguments to the function. However, a more useful way (as we shall see when dealing with SEQUENCE types) is to have a structure.This structure is stored in our ASN.1 header file. asn1.h: 119 /* UTCTIME */ 120 typedef struct { 121 int year, 122 month, 123 day, 124 hour, 125 min, 126 sec; 127 } UTCTIME; We have made this a type so that we can simply pass UTCTIME instead of “struct UTCTIME.” www.syngress.com ASN.1 Encoding • Chapter 2 67 404_CRYPTO_02.qxd 10/27/06 3:40 PM Page 67 der_utctime_length.c: 001 #include “asn1.h" 002 unsigned long der_utctime_length(void) 003 { 004 return 15; 005 } My thanks go to the revised ASN.1 specifications! ☺ der_utctime_encode.c: 001 #include “asn1.h" 002 003 static int putnum(int val, unsigned char **out) 004 { 005 unsigned char *ptr; 006 int h, l; 007 008 if (val < 0) return -1; 009 010 ptr = *out; 011 h = val / 10; 012 l = val % 10; 013 014 if(h>9||l>9){ 015 return -1; 016 } 017 018 *ptr++ = der_printable_char_encode(“0123456789"[h]); 019 *ptr++ = der_printable_char_encode(“0123456789"[l]); 020 *out = ptr; 021 022 return 0; 023 } This function stores an integer in a two-digit ASCII representation.The number must be in the range 0–99 for this function to succeed. It updates the output pointer, which as we shall see in the next function is immediately useful. We are re-using the der_printable_char_encode() to convert our integers to the ASCII code required. 025 int der_utctime_encode( UTCTIME *in, 026 unsigned char *out, 027 unsigned long *outlen) 028 { 029 /* check output size */ 030 if (der_utctime_length() > *outlen) { 031 return -1; 032 } 033 034 /* store header and length */ 035 der_put_header_length(&out, ASN1_DER_UTCTIME, 13, outlen); 036 037 /* store data */ www.syngress.com 68 Chapter 2 • ASN.1 Encoding 404_CRYPTO_02.qxd 10/27/06 3:40 PM Page 68 038 if (putnum(in->year % 100, &out) || 039 putnum(in->month, &out) || 040 putnum(in->day, &out) || 041 putnum(in->hour, &out) || 042 putnum(in->min, &out) || 043 putnum(in->sec, &out)) { 044 return -1; 045 } 046 047 *out++ = der_printable_char_encode('Z'); 048 049 return 0; 050 } After the standard issue header encoding we then proceed to store the fields of the date and time in order as expected. We make extensive use of the way the C language handles the double-OR bars (||). Specifically, that is always implemented from left to right and will abort on the first nonzero return value without proceeding to the next case. This means, for example, that if after encoding the month the routine fails, it will not encode the rest and will proceed inside to the braced statements directly. der_utctime_decode.c: 001 #include “asn1.h" 002 003 static int readnum(unsigned char **in, int *dest) 004 { 005 int x, y, z, num; 006 unsigned char *ptr; 007 008 num = 0; 009 ptr = *in; 010 for (x = 0; x < 2; x++) { 011 num *= 10; 012 z = der_printable_value_decode(*ptr++); 013 if (z < 0) { 014 return -1; 015 } 016 for (y = 0; y < 10; y++) { 017 if (“0123456789"[y] == z) { 018 num += y; 019 break; 020 } 021 } 022 if (y == 10) { 023 return -1; 024 } 025 } 026 027 *dest = num; 028 *in = ptr; 029 030 return 0; 031 } www.syngress.com ASN.1 Encoding • Chapter 2 69 404_CRYPTO_02.qxd 10/27/06 3:40 PM Page 69 This function decodes two bytes into the numerical value they represent. It borrows the PRINTABLE STRING routines again to decode the bytes to characters. It returns the number in the “dest” field and signals errors by the return code. We will use the same trick in the decoder to cascade a series of reads, which is why storing the result to a pointer pro- vided by the caller is important. 033 int der_utctime_decode(unsigned char *in, 034 unsigned long inlen, 035 UTCTIME *out) 036 { 037 unsigned type; 038 unsigned long payload_length; 039 int ret; 040 041 /* decode header */ 042 ret = der_get_header_length(&in, inlen, 043 &type, &payload_length); 044 if (ret < 0) { 045 return ret; 046 } 047 if (type != ASN1_DER_UTCTIME || payload_length != 13) { 048 return -2; 049 } 050 051 if (readnum(&in, &out->year) || 052 readnum(&in, &out->month) || 053 readnum(&in, &out->day) || 054 readnum(&in, &out->hour) || 055 readnum(&in, &out->min) || 056 readnum(&in, &out->sec)) { 057 return -1; 058 } 059 060 /* must be a Z here */ 061 if (der_printable_value_decode(in[0]) != 'Z') { 062 return -2; 063 } 064 065 /* fix up year */ 066 if (out->year < 70) { 067 out->year += 2000; 068 } else { 069 out->year += 1900; 070 } 071 072 return 0; 073 } Here we use the cascade trick (lines 51 to 56) to parse the input and store the decoded fields one at a time to the output structure. After we have decoded the fields, we check for the required ‘Z’ (line 61) and then fix the year field to the appropriate century (lines 66 to 70). www.syngress.com 70 Chapter 2 • ASN.1 Encoding 404_CRYPTO_02.qxd 10/27/06 3:40 PM Page 70 SEQUENCE Encodings The SEQUENCE type along with the SET and SET OF types are by far the most encom- passing types to develop.They require all of the ASN.1 functions including them as well! We will demonstrate relatively simple SEQUENCE encodings and omit SET types for brevity.The complete listing includes routines to handle SET types and the reader is encour- aged to seek them out. The first thing we need before we can encode a SEQUENCE is some way of repre- senting it in the C programming language. In this case, we are going to use an array of a structure to represent the elements of the SEQUENCE. asn1.h: 138 typedef struct { 139 int type; 140 unsigned long length; 141 void *data; 142 } asn1_list; This is the structure for a SEQUENCE element type (it will also be used for SET types).The type indicates the ASN.1 type of the element, length the length or size of the value, and data is a pointer to the native representation of the given data type. An array of this type describes the elements of a SEQUENCE. The length and data fields have different meanings depending on what the ASN.1 type is.Table 2.8 describes their use. Table 2.8 Definitions for the ASN.1_List Type ASN.1 Type Meaning of “Data” Meaning of “Length” BOOLEAN Pointer to an int Ignored INTEGER Pointer to a long Ignored BIT STRING Pointer to array of unsigned char Number of bits OCTET STRING Pointer to array of unsigned char Number of octets NULL Ignored Ignored OBJECT IDENTIFIER Pointer to array of unsigned long Number of words in the OID IA5 STRING Pointer to array of unsigned char Number of characters PRINTABLE STRING Pointer to array of unsigned char Number of characters UTCTIME Pointer to a UTCTIME structure Ignored SEQUENCE Pointer to an array of asn1_list Number of elements in the list The use of the length field takes on a dual role depending on whether we are encoding for decoding. For all but the SEQUENCE type where the length is not ignored, the length www.syngress.com ASN.1 Encoding • Chapter 2 71 404_CRYPTO_02.qxd 10/27/06 3:40 PM Page 71 specifies the maximum output size when decoding. It will be updated by the decoder to the actual length of the object decoded (in terms of what you would pass to the encoder). For example, if you specify a length of 16 for a BIT STRING element and the decoder places a 7 in its place, that means that the decoder read a BIT STRING of seven bits. We will also define a macro that is handy for creating lists at runtime, but first let us proceed through the SEQUENCE functions. der_sequence_length.c: 001 #include “asn1.h" 002 unsigned long der_sequence_paylen(asn1_list *list, 003 unsigned long length) 004 { 005 unsigned long i, paylen, x; 006 007 for (i = paylen = 0; i < length; i++) { 008 switch (list[i].type) { The crux of the SEQUENCE and SET routines is a huge switch statement for all the types. Here, we are using the ASN1_DER_* values, which fortunately do map to the ASN.1 types. It is best, though, that you use ASN1_DER_* symbols instead of literals. 009 case ASN1_DER_BOOLEAN: 010 paylen += der_boolean_length(); 011 break; 012 case ASN1_DER_INTEGER: 013 paylen += 014 der_integer_length(*((long *)list[i].data)); 015 break; Here we see the use of the .data member of the structure to get access to what will eventually be encoded. We make use of the fact that in C, the void pointer can be cast to and from any other pointer type without violating the standard. What the data pointer actu- ally points to changes based on what we are encoding. In this case, it is a long. 016 case ASN1_DER_BITSTRING: 017 paylen += der_bitstring_length(list[i].length); 018 break; Here we see the use of the .length member of the structure.The length means the number of units of a given type. In the case of BIT STRING, it means the number of bits to be encoded, whereas, for example, in the case of OID, length means the number of words in the OID encoding. 019 case ASN1_DER_OCTETSTRING: 020 paylen += der_octetstring_length(list[i].length); 021 break; 022 case ASN1_DER_NULL: 023 paylen += der_null_length(); 024 break; 025 case ASN1_DER_OID: 026 x = der_oid_length(list[i].data, list[i].length); www.syngress.com 72 Chapter 2 • ASN.1 Encoding 404_CRYPTO_02.qxd 10/27/06 3:40 PM Page 72 027 if (x == 0) return 0; 028 paylen += x; 029 break; 030 case ASN1_DER_PRINTABLESTRING: 031 x = der_printablestring_length(list[i].data, 032 list[i].length); 033 if (x == 0) return 0; 034 paylen += x; 035 break; 036 case ASN1_DER_IA5STRING: 037 x = der_ia5string_length(list[i].data, 038 list[i].length); 039 if (x == 0) return 0; 040 paylen += x; 041 break; 042 case ASN1_DER_UTCTIME: 043 paylen += der_utctime_length(); 044 break; 045 case ASN1_DER_SEQUENCE: 046 x = der_sequence_length(list[i].data, 047 list[i].length); 048 if (x == 0) return 0; 049 paylen += x; 050 break; 051 default: 052 return 0; 053 } 054 } 055 return paylen; 056 } 057 058 unsigned long der_sequence_length(asn1_list *list, 059 unsigned long length) 060 { 061 return der_length(der_sequence_paylen(list, length)); 062 } der_sequence_encode.c: 001 #include “asn1.h" 002 int der_sequence_encode(asn1_list *list, 003 unsigned long length, 004 unsigned char *out, 005 unsigned long *outlen) 006 { 007 unsigned long i, x; 008 int err; 009 010 /* check output size */ 011 if (der_sequence_length(list, length) > *outlen) { 012 return -1; 013 } 014 015 /* store header and length */ 016 der_put_header_length(&out, ASN1_DER_SEQUENCE, www.syngress.com ASN.1 Encoding • Chapter 2 73 404_CRYPTO_02.qxd 10/27/06 3:40 PM Page 73 017 der_sequence_paylen(list, length), 018 outlen); 019 020 /* now encode each element */ 021 for (i = 0; i < length; i++) { 022 switch (list[i].type) { 023 case ASN1_DER_BOOLEAN: 024 x = *outlen; 025 err = der_boolean_encode(*((int *)list[i].data), 026 out, &x); 027 if (err < 0) return err; 028 out += x; 029 break; 030 case ASN1_DER_INTEGER: 031 x = *outlen; 032 err = der_integer_encode(*((long *)list[i].data), 033 out, &x); 034 if (err < 0) return err; 035 out += x; 036 break; 037 case ASN1_DER_BITSTRING: 038 x = *outlen; 039 err = der_bitstring_encode(list[i].data, 040 list[i].length, 041 out, &x); 042 if (err < 0) return err; 043 out += x; 044 break; 045 case ASN1_DER_OCTETSTRING: 046 x = *outlen; 047 err = der_octetstring_encode(list[i].data, 048 list[i].length, 049 out, &x); 050 if (err < 0) return err; 051 out += x; 052 break; 053 case ASN1_DER_NULL: 054 x = *outlen; 055 err = der_null_encode(out, &x); 056 if (err < 0) return err; 057 out += x; 058 break; 059 case ASN1_DER_OID: 060 x = *outlen; 061 err = der_oid_encode(list[i].data, 062 list[i].length, out, &x); 063 if (err < 0) return err; 064 out += x; 065 break; 066 case ASN1_DER_PRINTABLESTRING: 067 x = *outlen; 068 err = der_printablestring_encode(list[i].data, 069 list[i].length, 070 out, &x); www.syngress.com 74 Chapter 2 • ASN.1 Encoding 404_CRYPTO_02.qxd 10/27/06 3:40 PM Page 74 071 if (err < 0) return err; 072 out += x; 073 break; 074 case ASN1_DER_IA5STRING: 075 x = *outlen; 076 err = der_ia5string_encode(list[i].data, 077 list[i].length, 078 out, &x); 079 if (err < 0) return err; 080 out += x; 081 break; 082 case ASN1_DER_UTCTIME: 083 x = *outlen; 084 err = der_utctime_encode(list[i].data, out, &x); 085 if (err < 0) return err; 086 out += x; 087 break; 088 case ASN1_DER_SEQUENCE: 089 x = *outlen; 090 err = der_sequence_encode(list[i].data, 091 list[i].length, 092 out, &x); 093 if (err < 0) return err; 094 out += x; 095 break; 096 default: 097 return -1; 098 } 099 } 100 return 0; 101 } der_sequence_decode.c: 001 #include “asn1.h" 002 int der_sequence_decode(unsigned char *in, 003 unsigned long inlen, 004 asn1_list *list, 005 unsigned long length) 006 { 007 unsigned type; 008 unsigned long payload_length, i, z; 009 int ret; 010 011 /* decode header */ 012 ret = der_get_header_length(&in, inlen, 013 &type, &payload_length); 014 if (ret < 0) { 015 return ret; 016 } 017 018 if (type != ASN1_DER_SEQUENCE) { 019 return -2; 020 } 021 www.syngress.com ASN.1 Encoding • Chapter 2 75 404_CRYPTO_02.qxd 10/27/06 3:40 PM Page 75 022 for (i = 0; i < length; i++) { 023 switch (list[i].type) { 024 case ASN1_DER_BOOLEAN: 025 ret = der_boolean_decode(in, payload_length, 026 ((int *)list[i].data)); 027 if (ret < 0) return ret; 028 z = der_boolean_length(); 029 break; 030 case ASN1_DER_INTEGER: 031 ret = der_integer_decode(in, payload_length, 032 ((long *)list[i].data)); 033 if (ret < 0) return ret; 034 z = der_integer_length(*((long *)list[i].data)); 035 break; 036 case ASN1_DER_BITSTRING: 037 ret = der_bitstring_decode(in, payload_length, 038 list[i].data, 039 &list[i].length); 040 if (ret < 0) return ret; 041 z = list[i].length; 042 break; 043 case ASN1_DER_OCTETSTRING: 044 ret = der_octetstring_decode(in, payload_length, 045 list[i].data, 046 &list[i].length); 047 if (ret < 0) return ret; 048 z = der_octetstring_length(list[i].length); 049 break; 050 case ASN1_DER_NULL: 051 ret = der_null_decode(in, payload_length); 052 if (ret < 0) return ret; 053 z = der_null_length(); 054 break; 055 case ASN1_DER_OID: 056 ret = 057 der_oid_decode(in, payload_length, 058 ((unsigned long *)list[i].data), 059 &list[i].length); 060 if (ret < 0) return ret; 061 z = 062 der_oid_length(((unsigned long *)list[i].data), 063 list[i].length); 064 break; 065 case ASN1_DER_PRINTABLESTRING: 066 ret = der_printablestring_decode(in, 067 payload_length, 068 list[i].data, 069 &list[i].length); 070 if (ret < 0) return ret; 071 z = der_printablestring_length(list[i].data, 072 list[i].length); 073 break; 074 case ASN1_DER_IA5STRING: 075 ret = der_ia5string_decode(in, payload_length, www.syngress.com 76 Chapter 2 • ASN.1 Encoding 404_CRYPTO_02.qxd 10/27/06 3:40 PM Page 76 [...]... 029 030 031 032 033 034 035 036 037 038 039 040 041 042 0 43 044 045 /* decode the payload length */ if (in[1] < 128) { /* short form */ len = in[1]; } else { /* get length of length */ x = in[1] & 0x7F; /* can we actually read this many bytes? */ if (inlen < 2 + x) { return -2; } /* load it */ len = 0; y = 2; while (x ) { len = (len . size */ 030 if (der_utctime_length() > *outlen) { 031 return -1; 032 } 033 034 /* store header and length */ 035 der_put_header_length(&out, ASN1_DER_UTCTIME, 13, outlen); 036 037 /* store. (in[1] < 128) { 030 /* short form */ 031 len = in[1]; 032 } else { 033 /* get length of length */ 034 x = in[1] & 0x7F; 035 036 /* can we actually read this many bytes? */ 037 if (inlen <2+x){return. x; 029 break; 030 case ASN1_DER_INTEGER: 031 x = *outlen; 032 err = der_integer_encode(*((long *)list[i].data), 033 out, &x); 034 if (err < 0) return err; 035 out += x; 036 break; 037 case ASN1_DER_BITSTRING: 038

Ngày đăng: 12/08/2014, 20:22

TỪ KHÓA LIÊN QUAN