summaryrefslogtreecommitdiff
path: root/doc/ASN1.readme.txt
blob: 2529fd0851693be06ed7a148a6b841e01de7c152 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376

------------------------------------------------
--   Readme file for ASN1 parser              --
--                                            --
--   Originator:  Fabio Fiorina               --
--   e-mail:      Fabio.Fiorina@alcatel.it    --
--                fiorinaf@bgonline.it        --
------------------------------------------------



INTRODUCTION
------------
This file describes the forth version of ASN.1 parser I developed.
The main difference from the first version is the use of pointers and the
possibility to save/get ASN1 definitions in/from a C vector.
Other differences are:
- write_value function for type ANY
- the introduction of ENUMERATED type,
- negative integer are allowed in ASN.1 syntax files,
- PKIX1Implicit88.txt instead of Certificate.txt for the Certificate description
- functions naming 
- an easier way to set INTEGER and get OBJECT IDENTFIER  



FILE LIST
---------
ASN.readme.txt        this file
cert_ASN.y            bison input file
cert_ASN.tab.c        bison output file
CertificateExample.c  example based on Appendix D.1 of rfc2459
CrlExample.c          example based on Appendix D.4 of rfc2459
PkixTabExample.c      the program used to create pkix_asn1_tab.c
cert_asn1.c           functions for ASN1 parser and for reading and setting elements' value
cert_asn1.h           contains constants for the gnutls_asn1.c. Must be included in files 
                      that use ASN1 parser.
cert_der.c            functions for der encoding creation and analysis
cert_der.h            contains constants for the gnutls_der.c. Must be included in files 
                      that use ASN1 parser.
pkix.asn              certificate and CRL structures 
pkix_asn1_tab.c       C vector to use with 'asn1_create_tree' function. 
                      It was created from pkix.asn file.


ASN.1 SYNTAX
------------
The parser is case sensitive. The comments begin with "-- " and end at the end of line.
An example is in "Certificate.txt" file.
The ASN.1 declarations must have this form:
      
      object_name {<object definition>}

      DEFINITIONS <EXPLICIT or IMPLICIT> TAGS ::=

      BEGIN 

      <type and constants definitions>

      END

The token "::=" must be separate from others elements, so this is a wrong declaration:
      Version ::=INTEGER 
the correct one is :   Version ::= INTEGER
Here is the list of types that the parser can manage:
     INTEGER
     ENUMERATED
     BOOLEAN
     OBJECT IDENTIFIER
     NULL
     BIT STRING
     OCTET STRING
     UTCTime
     GeneralizedTime
     SEQUENCE
     SEQUENCE OF
     SET 
     SET OF
     CHOICE
     ANY
     ANY DEFINED BY
This version doesn't manage REAL type. It also not allow the use of 
"EXPORT" and "IMPORT" sections.

The SIZE constraints are allowed but no check is done on them.



NAMING
--------
If you have this definitions:

      Example { 1 2 3 4 }

      DEFINITIONS EXPLICIT TAGS ::=

      BEGIN 

      Group ::= SEQUENCE {
	 id   OBJECT IDENTIFIER,
	 value  Value
      }

      Value ::= SEQUENCE {
	    value1  INTEGER,
	    value2  BOOLEAN 
      }

      END

to identify the type 'Group' you have to use the null terminated string "Example.Group".
Others examples:
Field 'id' in 'Group' type :  "Example.Group.id"
Field 'value1' in filed 'value' in type 'Group':   "Example.Group.value.value1" 
These strings are used in functions that are described below.
Elements of structured types that don't have a name, receve the name "?1","?2", and so on. 
The name "?LAST" indicates the last element of a SET_OF or SEQUENCE_OF.



FUNCTIONS
---------

   int asn1_parser_asn1(char *file_name,node_asn **pointer);
   --------------------------------
Creates the structures needed to manage the definitions included in *FILE_NAME file.
Input Parameter: 
  char *file_name: specify the path and the name of file that contains ASN.1 declarations.
Output Parameter:
  node_asn **pointer : return the pointer to the structure created from 
                       "file_name" ASN.1 declarations.  
Return Value:
  ASN_OK: the file has a correct syntax and every identifier is known. 
  ASN_FILE_NOT_FOUND: an error occured while opening FILE_NAME.
  ASN_SYNTAX_ERROR: the syntax is not correct.
  ASN_IDENTIFIER_NOT_FOUND: in the file there is an identifier that is not defined.


   int asn1_parser_asn1_file_c(char *file_name);
   --------------------------------------------
Creates a file containing a C vector to use to manage the definitions included in
*FILE_NAME file. If *FILE_NAME is "/aa/bb/xx.yy" the file created is "/aa/bb/xx_asn1_tab.c",
and the vector is "xx_asn1_tab".
Input Parameter: 
  char *file_name: specify the path and the name of file that contains ASN.1 declarations.
Return Value:
  ASN_OK: the file has a correct syntax and every identifier is known. 
  ASN_FILE_NOT_FOUND: an error occured while opening FILE_NAME.
  ASN_SYNTAX_ERROR: the syntax is not correct.
  ASN_IDENTIFIER_NOT_FOUND: in the file there is an identifier that is not defined.


  int asn1_create_tree(static_asn *root,node_asn **pointer);
  ---------------------------------------------------------
Creates the structures needed to manage the ASN1 definitions. ROOT is a vector created by
'asn1_parser_asn1_file_c' function.
Input Parameter: 
  static_asn *root: specify vector that contains ASN.1 declarations.
Output Parameter:
  node_asn **pointer : return the pointer to the structure created by *ROOT ASN.1 declarations.  
Return Value:
  ASN_OK: structure created correctly. 
  ASN_GENERIC_ERROR: an error occured while structure creation.


   int asn1_create_structure(node_asn *p_structure,char *source_name,node_asn **pointer,
                        char *dest_name,);
   -------------------------------------------------------------------------------------
Creates a structure called DEST_NAME of type SOURCE_NAME.
Input Parameters:
  node_asn *p_structure: pointer to the structure returned by "parser_asn1" function 
  char *source_name: the name of the type of the new structure (must be inside p_structure).
  char *dest_name: the name of the new structure.
Output Parameter:
  node_asn **pointer : pointer to the structure created. 
Return Value:
  ASN_OK: creation OK
  ASN_ELEMENT_NOT_FOUND: SOURCE_NAME isn't known
Example: using "pkix.asn"
  result=asn1_create_structure(cert_def,"PKIX1Implicit88.Certificate",&cert,"certificate1");


   int asn1_write_value(node_asn *pointer,char *name,unsigned char *value,int len);
   --------------------------------------------------------
Set the value of one element inside a structure.
Input Parameters:
  node_asn *pointer: pointer to a structure
  char *name: the name of the element inside the structure that you want to set.
  unsigned char *value: vector used to specify the value to set. If len is >0, 
                        *VALUE must be a two's complement form integer.
                        if len=0 *VALUE must be a null terminated string with an integer value.
  int len: number of bytes of *value to use to set the value: value[0]..value[len-1]
           or 0 if value is a null terminated string
Return Value:
  ASN_OK: set value OK
  ASN_ELEMENT_NOT_FOUND: NAME is not a valid element.
  ASN_VALUE_NOT_VALID: VALUE has a wrong format.
Examples:  description for each type
  INTEGER: VALUE must contain a two's complement form integer.
           value[0]=0xFF ,               len=1 -> integer=-1
           value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1
           value[0]=0x01 ,               len=1 -> integer= 1
           value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1
           value="123"                 , len=0 -> integer= 123
  ENUMERATED: as INTEGER (but only with not negative numbers)
  BOOLEAN: VALUE must be the null terminated string "TRUE" or "FALSE" and LEN != 0
           value="TRUE" , len=1 -> boolean=TRUE
           value="FALSE" , len=1 -> boolean=FALSE
  OBJECT IDENTIFIER: VALUE must be a null terminated string with each number separated by
                     a blank (e.g. "1 2 3 543 1"). 
                     LEN != 0
           value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha
  UTCTime: VALUE must be a null terminated string in one of these formats:
           "YYMMDDhhmmssZ" "YYMMDDhhmmssZ" "YYMMDDhhmmss+hh'mm'" "YYMMDDhhmmss-hh'mm'"
           "YYMMDDhhmm+hh'mm'" "YYMMDDhhmm-hh'mm'".  
           LEN != 0
           value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998 at 12h 00m  Greenwich Mean Time
  GeneralizedTime: VALUE must be in one of this format:
                   "YYYYMMDDhhmmss.sZ" "YYYYMMDDhhmmss.sZ" "YYYYMMDDhhmmss.s+hh'mm'" 
                   "YYYYMMDDhhmmss.s-hh'mm'" "YYYYMMDDhhmm+hh'mm'" "YYYYMMDDhhmm-hh'mm'" 
                   where ss.s indicates the seconds with any precision like "10.1" or "01.02".
                   LEN != 0
           value="2001010112001.12-0700" , len=1 -> time=Jannuary 1st, 2001 at 12h 00m 01.12s 
                                                    Pacific Daylight Time
  OCTET STRING: VALUE contains the octet string and LEN is the number of octet.
           value="\x01\x02\x03" , len=3  -> three bytes octet string
  BIT STRING: VALUE contains the bit string organized by bytes and LEN is the number of bits.
           value="\xCF" , len=6 -> bit string="110011" (six bits)
  CHOICE: if NAME indicates a choice type, VALUE must specify one of the alternatives with a
          null terminated string. LEN != 0
          Using "pkix.asn":
          result=asn1_write_value(cert,"certificate1.tbsCertificate.subject","rdnSequence",1);
  ANY: VALUE indicates the der encoding of a structure.
       LEN != 0 
  SEQUENCE OF: VALUE must be the null terminated string "NEW" and LEN != 0. With this 
               instruction another element is appended in the sequence. The name of this
               element will be "?1" if it's the first one, "?2" for the second and so on.
          Using "pkix.asn":   
          result=asn1_write_value(cert,"certificate1.tbsCertificate.subject.rdnSequence","NEW",1);
  SET OF: the same as SEQUENCE OF. 
          Using "pkix.asn":
          result=asn1_write_value(cert,"certificate1.tbsCertificate.subject.rdnSequence.?LAST","NEW",1);

If an element is OPTIONAL and you want to delete it, you must use the value=NULL and len=0.
          Using "pkix.asn":
          result=asn1_write_value(cert,"certificate1.tbsCertificate.issuerUniqueID",NULL,0);


   int asn1_read_value(node_asn *pointer,char *name,unsigned char *value,int *len);
   --------------------------------------------------------
Returns the value of one element inside a structure.
Input Parameters:
  node_asn *pointer: pointer to a structure
  char *name: the name of the element inside a structure that you want to read.
Output Parameters:
  unsigned char *value: vector that will contain the element's content. 
                        VALUE must be a pointer to memory cells already allocated.
  int *len: number of bytes of *value: value[0]..value[len-1]
Return Value:
  ASN_OK: set value OK
  ASN_ELEMENT_NOT_FOUND: NAME is not a valid element.
  ASN_VALUE_NOT_FOUND: there isn't any value for the element selected.
Examples: a description for each type
  INTEGER: VALUE will contain a two's complement form integer.
           integer=-1  -> value[0]=0xFF , len=1
           integer=1   -> value[0]=0x01 , len=1
  ENUMERATED: as INTEGER (but only with not negative numbers)
  BOOLEAN: VALUE will be the null terminated string "TRUE" or "FALSE" and LEN=5 or LEN=6
  OBJECT IDENTIFIER: VALUE will be a null terminated string with each number separated by
                     a blank (i.e. "1 2 3 543 1"). 
                     LEN = strlen(VALUE)+1
  UTCTime: VALUE will be a null terminated string in one of these formats: 
           "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'"
           LEN=strlen(VALUE)+1
  GeneralizedTime: VALUE will be a null terminated string in the same format used to set
                   the value
  OCTET STRING: VALUE will contain the octet string and LEN will be the number of octet.
  BIT STRING: VALUE will contain the bit string organized by bytes and LEN will be the 
              number of bits.
  CHOICE: if NAME indicates a choice type, VALUE will specify the alternative selected
  ANY: if NAME indicates an any type, VALUE will indicate the DER encoding of the structure 
       actually used.

If an element is OPTIONAL and the function "read_value" returns ASN_ELEMENT_NOT_FOUND, it 
means that this element wasn't present in the der encoding that created the structure.
The first element of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and so on.


   int asn1_create_der(node_asn *pointer,char *name,unsigned char *der,int *len);
   ------------------------------------------------------
Creates the DER encoding for the NAME structure (inside *POINTER structure).
Input Parameters:
  node_asn *pointer: pointer to a structure
  char *name: the name of the structure you want to encode (it must be inside *POINTER).
Output Parameters:
  unsigned char *der: vector that will contain the DER encoding. 
                      DER must be a pointer to memory cells already allocated.
  int *len: number of bytes of *der: der[0]..der[len-1]
Return Value:
  ASN_OK: DER encoding OK
  ASN_ELEMENT_NOT_FOUND: NAME is not a valid element.
  ASN_VALUE_NOT_FOUND: there is an element without a value.


   int asn1_get_der(node_asn *pointer,char *name,unsigned char *der,int len);
   --------------------------------------------------
Fill the structure *POINTER with values of a DER encoding string. The sructure must just be
created with function 'create_stucture'.
Input Parameters:
  node_asn *pointer: pointer to the structure that you want to fill.
  unsigned char *der: vector that contains the DER encoding. 
  int len: number of bytes of *der: der[0]..der[len-1]
Return Value:
  ASN_OK: DER encoding OK
  ASN_ELEMENT_NOT_FOUND: NAME is not a valid element.
  ASN_TAG_ERROR, ASN_DER_ERROR: the der encoding doesn't match the structure NAME.


   int asn1_get_start_end_der(node_asn *pointer,unsigned char *der,int len,char *name_element,int *start, int *end);
   ----------------------------------------------------------------------------------------------------
Find the start and end point of an element in a DER encoding string. I mean that if you
have a der encoding and you have already used the function "get_der" to fill a structure, it may
happen that you want to find the piece of string concerning an element of the structure.
Example: the sequence "tbsCertificate" inside an X509 certificate.
Input Parameters:
  node_asn *pointer: the pointer to the structure that is already setted with DER string.
  unsigned char *der: vector that contains the DER encoding. 
  int len: number of bytes of *der: der[0]..der[len-1]
  char *name_element: an element of NAME structure.
Output Parameters:
  int *start: the position of the first byte of NAME_ELEMENT decoding (der[*start]) 
  int *end: the position of the last byte of NAME_ELEMENT decoding (der[*end])
Return Value:
  ASN_OK: DER encoding OK
  ASN_ELEMENT_NOT_FOUND: NAME or NAME_ELEMENT is not a valid element.
  ASN_TAG_ERROR, ASN_DER_ERROR: the der encoding doesn't match the structure NAME.
  

   int asn1_delete_structure(node_asn *pointer);
   ---------------------------------
Deletes the structure *POINTER. 
Input Parameters:
  node_asn *pointer: pointer to the structure that you want to delete.
Return Value:
  ASN_OK: everything OK
  ASN_ELEMENT_NOT_FOUND: pointer==NULL.


   void asn1_visit_tree(node_asn *pointer,char *name);
   ---------------------------
Prints on the standard output the structure's tree starting from the NAME element inside
the structure *POINTER.



FUTURE DEVELOPMENTS
-------------------
1. type REAL 
2. improve the error signaling with strings that give you more details. 
   Examples: in case of ASN1 syntax error you will have the line number where the error is,  
             if creating a der encoding the result is ASN_VALUE_NOT_FOUND you will have the
             name of the element without the value.
3. improve the 'visit_tree' function and change the output from stdout to a null terminated 
   string.