summaryrefslogtreecommitdiff
path: root/doc/rst/legacy/nss_tech_notes/nss_tech_note1/index.rst
blob: 3b8313fd3a7c9b93a4327f03126cd51f25720415 (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
.. _mozilla_projects_nss_nss_tech_notes_nss_tech_note1:

nss tech note1
==============

.. _how_to_use_the_nss_asn.1_and_quickder_decoders:

`How to use the NSS ASN.1 and QuickDER decoders <#how_to_use_the_nss_asn.1_and_quickder_decoders>`__
----------------------------------------------------------------------------------------------------

.. container::

.. _nss_technical_note_1:

`NSS Technical Note: 1 <#nss_technical_note_1>`__
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. container::

   NSS 3.6 contains several decoders for ASN.1 and DER.Two of them are extensively used and are part
   of the public NSS API :

   #. The "classic" ASN.1 decoder, written by Lisa Repka . This was written to be a generic decoder,
      that includes both DER (Distinguished Encoding Rules) and BER (Basic Encoding Rules).† It
      handles both streaming and non-streaming input.
   #. The "QuickDER" decoder, written by Julien Pierre for NSS 3.6 . This decoder was written when
      performance issues were discovered with the classic decoder. It can only decode DER .† It does
      not handle streaming input, and requires that all input be present before beginning to decode.

   Despite their differences, the two decoders have a lot in common. QuickDER was written to be as
   compatible as possible with the classic decoder, in order to ease migration to it in areas of
   critical performance bottlenecks. For this reason, I will first describe all the common
   functionality of the two decoders, before outlining their differences.
   The main non-streaming APIs for these two decoders have an identical prototype :

   -  SECStatus SEC_ASN1DecodeItem(PRArenaPool \*pool, void \*dest, const SEC_ASN1Template \*t,
      SECItem \*item);
   -  SECStatus SEC_QuickDERDecodeItem(PRArenaPool\* arena, void\* dest, const SEC_ASN1Template\*
      templateEntry, SECItem\* src);

   Here is a description of the arguments :

   -  *SECItem\* src*\ † is a structure containing a pointer to the binary data to be decoded, as
      well as its size.
   -  *const SEC_ASN1Template\* templateEntry* is a pointer to one or more `decoder
      templates <#templates>`__. The number of required templates is determined by the type of the
      first template.When multiple templates are required, the pointer must point to a
      NULL-terminated array of templates. The syntax of these templates is identical for both
      decoders, except where noted. A "NULL Template" is a template that is all zeros, having a zero
      kind.† The term "NULL-terminated array", as used throughout this document, means an array of
      templates, the last of which is a NULL template.
   -  *void\* dest* is a pointer to the target area. This is where the decoder stores its output.
      The type is undefined as it is completely dependent on the content of the decoder templates.†
      This typically points to a struct that is described (or partially described) by the templates.
   -  *PRArenaPool\* arena* is a pointer to an NSPR arena pool. This is the arena pool from which
      the decoder will allocate memory as needed.

   Decoder templates :
   The SEC_ASN1Template structure tells the decoder what to do with the input data. This structure
   contains four fields :

   -  *kind* . This 32-bit field tells the decoder what to do with a particular component within the
      input data. It is made of two parts : the lower byte, which can contain `ASN.1
      tags <#asn.1_tags>`__, and the upper 3 bytes, which can contain `decoder
      modifiers <#decoder_modifiers>`__. If only an ASN.1 tag is specified without a modifier, then
      the decoder will enforce the presence of a component of that type, and fail if it does not
      match. If kind is an ASN.1 SEQUENCE tag (SEC_ASN1_SEQUENCE), then you must specify additional
      templates in a NULL-terminated array to define the content of the of the ASN.1 SEQUENCE. If
      kind is the SEC_ASN1_CHOICE modifier, you must also specify additional templates in a NULL
      terminated array to list the various possible types that this component can have. In all other
      cases, only the first template structure passed to the decoder will be considered, even if
      additonal templates are passed in an array. When only one template is needed, you do not need
      a NULL template to terminate the array.
   -  *offset*\ † . This field does not apply to all template types. It is only needed if the
      template instructs the decoder to save some data, such as for primitive component types, or
      for some modifiers where noted.When needed, it tells the decoder where in the target data to
      save the current component. It is normally relative to the dest argument passed to the
      decoder. If templates are nested, the offset applies to the location of the current component
      within the target component, typically the decoded SEQUENCE.
   -  *sub*\ † . This field does not apply to all template types. If kind contains the
      SEC_ASN1_INLINE or SEC_ASN1_POINTER modifiers, then it must point to the required subtemplate.
      If kind contains the SEC_ASN1_XTRN or SEC_ASN1_DYNAMIC modifiers, this is a pointer to a
      callback function that will dynamically return the required subtemplate.
   -  *size*\ † . This field does not apply to all template types. It is only required for
      dynamically allocating memory for the structure if the template is being included from an
      ASN.1 SEQUENCE or SEQUENCE OF, or if dynamic allocation was requested from the parent template
      using the SEC_ASN1_POINTER modifier

   Here is a description of the various tags and modifiers that apply to the kind field.
   *ASN.1 tags*

   | ASN.1 tags are specified in the lower byte of the kind field of the template, as noted above.
   | The following is not an attempt to explain ASN.1 tags or their purposes. Rather, the goal here
     is to explain what type of tags the decoder supports and which macros should be used when
     defining tags in decoder templates. It should be noted that we only support an older
     specification of ASN.1; multibyte tags are not currently supported.

   The 8-bit ASN.1 tags that we support are made of three parts :

   #. The ASN.1 component class type. It is specified in the upper 2 tag bits (number 6 and 7).
      There are four classes of ASN.1 tags : universal, application-specific, context-specific, and
      private. You can specify the class of the tag using the macros SEC_ASN1_UNIVERSAL,
      SEC_ASN1_APPLICATION, SEC_ASN1_CONTEXT_SPECIFIC and SEC_ASN1_PRIVATE. Universal is the default
      tag class and does not have to be specified, as the value of the class type is zero.

   #. The method type : whether the component type is constructed or primitive. This information is
      stored in the next lowest tag bit (number 5). You can use the macro SEC_ASN1_CONSTRUCTED for a
      constructed component type. A SEC_ASN1_PRIMITIVE macro is also provided, but does not need to
      be included as it is zero.

   #. | The tag number. It is stored in the lower 5 tag bits (number 0 through 4). The ASN.1
        standard only defines tag numbers in the universal class. If you are using a tag of a
        different classes, you can define your own tag number macros or specify the tag value within
        the template definition. The following macros are provided for tag numbers within the
        universal class :
      | SEC_ASN1_BOOLEAN, SEC_ASN1_INTEGER, SEC_ASN1_BIT_STRING, SEC_ASN1_OCTET_STRING,
        SEC_ASN1_NULL, SEC_ASN1_OBJECT_ID, SEC_ASN1_OBJECT_DESCRIPTOR,† SEC_ASN1_REAL,
        SEC_ASN1_ENUMERATED, SEC_ASN1_EMBEDDED_PDV, SEC_ASN1_UTF8_STRING, SEC_ASN1_SEQUENCE,
        SEC_ASN1_SET, SEC_ASN1_NUMERIC_STRING, SEC_ASN1_PRINTABLE_STRING, SEC_ASN1_T61_STRING,
        SEC_ASN1_TELETEX_STRING, SEC_ASN1_T61_STRING, SEC_ASN1_VIDEOTEX_STRING, SEC_ASN1_IA5_STRING,
        SEC_ASN1_UTC_TIME, SEC_ASN1_GENERALIZED_TIME, SEC_ASN1_GRAPHIC_STRING,
        SEC_ASN1_VISIBLE_STRING, SEC_ASN1_GENERAL_STRING, SEC_ASN1_UNIVERSAL_STRING,
        SEC_ASN1_BMP_STRING

      Note that for SEC_ASN1_SET and SEC_ASN1_SEQUENCE types, you must also include the method type
      macro SEC_ASN1_CONSTRUCTED to construct a fully valid tag, as defined by the ASN.1 standard .

   *Decoder modifiers :*
   These modifiers are also specified in the kind field of the template structure. All the values
   are in the 9 - 31 bit range.

   -  *SEC_ASN1_OPTIONAL*: tells the decoder that this component is optional. If the component in
      the input data does not match this template, the decoder will continue processing the input
      data using the next available template.
   -  *SEC_ASN1_EXPLICIT*: tells the decoder that explicit tagging is being used. This is always a
      constructed type. It requires a subtemplate defining the types of the data within.
   -  *SEC_ASN1_ANY*: allows the decoder to match this template with any component type, regardless
      of the tag in the input data. If used in conjunction with SEC_ASN1_OPTIONAL as part of a
      sequence, this must be the last template in the template array.
   -  *SEC_ASN1_INLINE*: recurse into the specified subtemplate to continue processing. This is
      typically used for SEC_ASN1_SEQUENCE or SEC_ASN1_CHOICE definitions, which always need to be
      the first template in a template array of their own.
   -  *SEC_ASN1_POINTER*: similar to SEC_ASN1_INLINE, except that the memory in the target will be
      allocated dynamically and a pointer to the dynamically allocated memory will be stored in the
      *dest* struct at the *offset*. This requires that the subtemplate contains a non-zero size
      field.
   -  *SEC_ASN1_GROUP*: can only be used in conjunction with a SEC_ASN1_SET or SEC_ASN1_SEQUENCE. It
      tells the decoder that the component is an ASN.1 SET OF or SEQUENCE OF respectively. You can
      also use the macros SEC_ASN1_SET_OF and SEC_ASN1_SEQUENCE_OF which define both the tag number
      and this modifier (but still need the method type, this may be a bug).
   -  *SEC_ASN1_DYNAMIC* or *SEC_ASN1_XTRN* : specifies that the component format is defined in a
      dynamic subtemplate. There is no difference between the two macros. The sub field of the
      template points to a callback function of type SEC_ASN1TemplateChooser that returns the
      subtemplate depending on the component data.
   -  *SEC_ASN1_SKIP*: specifies that the decoder should skip decoding of the component.
      SEC_ASN1DecodeItem can only skip required components and will assert if you try to skip an
      OPTIONAL component. SEC_QuickDERDecodeItem supports skipping the decoding of OPTIONAL
      components if you define the tag of the component in the template
   -  *SEC_ASN1_INNER*: recurse into the component and saves its content, without the surrounding
      ASN.1 tag and length
   -  *SEC_ASN1_SAVE*: saves the component data, but does not proceed to the next component if
      within a SEQUENCE template array. This means the next template will reprocess the same
      component.
   -  *SEC_ASN1_SKIP_REST*: abort the decoding. This is used in a template array within a SEQUENCE,
      if you don't care about the fields at the end of it. SEC_ASN1DecodeItem only supports this
      modifier in the top-level template. SEC_QuickDERDecodeItem allows it at any nested sublevel.
   -  *SEC_ASN1_CHOICE*: allows decoding of components that are of variable type. This must be the
      first template in a NULL-terminated array. The offset parameter specifies where to store the
      type identifier in the target data . Subsequent templates specify a custom identifier for each
      possible component type in the size parameter .
   -  *SEC_ASN1_DEBUG_BREAK*: makes the decoder assert when processing the template. This option is
      only supported with SEC_QuickDERDecodeItem . It is useful to debug your templates or when
      writing new templates if they don't work.

   |
   | *Differences between SEC_ASN1DecodeItem and SEC_QuickDERDecodeItem*

   #. The arena argument is required to be non-NULL for SEC_QuickDERDecodeItem . With
      SEC_ASN1DecodeItem, it can be NULL, and if so, the decoder will allocate from the heap using
      PR_Malloc . However, this usage is strongly discouraged and we recommend that you always use
      an arena pool even with SEC_ASN1DecodeItem. See `bug
      175163 <http://bugzilla.mozilla.org/show_bug.cgi?id=175163>`__ for more information about the
      reason for this recommendation.
   #. SEC_ASN1DecodeItem will make a copy of the input data into the decoded target as needed, while
      SEC_QuickDERDecodeItem will generate output with pointers into the input. This means that if
      you use SEC_QuickDERDecodeItem, you must always be careful not to free the input as long as
      you intend to use the decoded structure. Ideally, you should allocate the input data out of
      the same arena that you are passing to the decoder. This will allow you to free both the input
      data and the decoded data at once when freeing the arena.
   #. SEC_ASN1DecodeItem can decode both BER and DER data, while SEC_QuickDERDecodeItem can only
      decode DER data.
   #. SEC_QuickDERDecodeItem does not support streaming data. This feature will most likely never be
      added, as this decoder gets most of its extra speed from not making a copy of the input data,
      which would be required when streaming.
   #. SEC_QuickDERDecodeItem supports SEC_ASN1_OPTIONAL together with SEC_ASN1_SKIP
   #. SEC_ASN1_DEBUG_BREAK is not supported by SEC_ASN1DecodeItem