No issues found
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* The following is the mozilla license blurb, as the bodies some of
3 * these functions were derived from the mozilla source. */
4 /*
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * The Original Code is the Netscape security libraries.
18 *
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1994-2000
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
35 */
36
37 /*
38 * Author: Chris Toshok (toshok@ximian.com)
39 *
40 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
41 */
42 #ifdef HAVE_CONFIG_H
43 #include <config.h>
44 #endif
45
46 #include "e-asn1-object.h"
47
48 #include "secasn1.h"
49
50 #define E_ASN1_OBJECT_GET_PRIVATE(obj) \
51 (G_TYPE_INSTANCE_GET_PRIVATE \
52 ((obj), E_TYPE_ASN1_OBJECT, EASN1ObjectPrivate))
53
54 struct _EASN1ObjectPrivate {
55 PRUint32 tag;
56 PRUint32 type;
57 gboolean valid_container;
58
59 GList *children;
60
61 gchar *display_name;
62 gchar *value;
63
64 gchar *data;
65 guint data_len;
66 };
67
68 G_DEFINE_TYPE (EASN1Object, e_asn1_object, G_TYPE_OBJECT)
69
70 static void
71 e_asn1_object_finalize (GObject *object)
72 {
73 EASN1ObjectPrivate *priv;
74
75 priv = E_ASN1_OBJECT_GET_PRIVATE (object);
76
77 g_free (priv->display_name);
78 g_free (priv->value);
79
80 g_list_free_full (priv->children, (GDestroyNotify) g_object_unref);
81
82 /* Chain up to parent's finalize() method. */
83 G_OBJECT_CLASS (e_asn1_object_parent_class)->finalize (object);
84 }
85
86 static void
87 e_asn1_object_class_init (EASN1ObjectClass *class)
88 {
89 GObjectClass *object_class;
90
91 g_type_class_add_private (class, sizeof (EASN1ObjectPrivate));
92
93 object_class = G_OBJECT_CLASS (class);
94 object_class->finalize = e_asn1_object_finalize;
95 }
96
97 static void
98 e_asn1_object_init (EASN1Object *asn1)
99 {
100 asn1->priv = E_ASN1_OBJECT_GET_PRIVATE (asn1);
101
102 asn1->priv->valid_container = TRUE;
103 }
104
105 /* This function is used to interpret an integer that
106 * was encoded in a DER buffer. This function is used
107 * when converting a DER buffer into a nsIASN1Object
108 * structure. This interprets the buffer in data
109 * as defined by the DER (Distinguised Encoding Rules) of
110 * ASN1.
111 */
112 static gint
113 get_integer_256 (guchar *data,
114 guint nb)
115 {
116 gint val;
117
118 switch (nb) {
119 case 1:
120 val = data[0];
121 break;
122 case 2:
123 val = (data[0] << 8) | data[1];
124 break;
125 case 3:
126 val = (data[0] << 16) | (data[1] << 8) | data[2];
127 break;
128 case 4:
129 val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
130 break;
131 default:
132 return -1;
133 }
134
135 return val;
136 }
137
138 /* This function is used to retrieve the lenght of a DER encoded
139 * item. It looks to see if this a multibyte length and then
140 * interprets the buffer accordingly to get the actual length value.
141 * This funciton is used mostly while parsing the DER headers.
142 *
143 * A DER encoded item has the following structure:
144 *
145 * <tag><length<data consisting of lenght bytes>
146 */
147 static guint32
148 get_der_item_length (guchar *data,
149 guchar *end,
150 gulong *bytesUsed,
151 gboolean *indefinite)
152 {
153 guchar lbyte = *data++;
154 PRInt32 length = -1;
155
156 *indefinite = FALSE;
157 if (lbyte >= 0x80) {
158 /* Multibyte length */
159 guint nb = (guint) (lbyte & 0x7f);
160 if (nb > 4) {
161 return -1;
162 }
163 if (nb > 0) {
164
165 if ((data + nb) > end) {
166 return -1;
167 }
168 length = get_integer_256 (data, nb);
169 if (length < 0)
170 return -1;
171 } else {
172 *indefinite = TRUE;
173 length = 0;
174 }
175 *bytesUsed = nb+1;
176 } else {
177 length = lbyte;
178 *bytesUsed = 1;
179 }
180 return length;
181 }
182
183 static gboolean
184 build_from_der (EASN1Object *parent,
185 gchar *data,
186 gchar *end)
187 {
188 gulong bytesUsed;
189 gboolean indefinite;
190 PRInt32 len;
191 PRUint32 type;
192 guchar code, tagnum;
193 EASN1Object *asn1object = NULL;
194
195 if (data >= end)
196 return TRUE;
197
198 /*
199 * A DER item has the form of |tag|len|data
200 * tag is one byte and describes the type of elment
201 * we are dealing with.
202 * len is a DER encoded gint telling us how long the data is
203 * data is a buffer that is len bytes long and has to be
204 * interpreted according to its type.
205 */
206
207 while (data < end) {
208 code = *data;
209 tagnum = code & SEC_ASN1_TAGNUM_MASK;
210
211 /*
212 * NOTE: This code does not (yet) handle the high-tag-number form!
213 */
214 if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) {
215 return FALSE;
216 }
217 data++;
218 len = get_der_item_length (
219 (guchar *) data, (guchar *) end,
220 &bytesUsed, &indefinite);
221 data += bytesUsed;
222 if ((len < 0) || ((data + len) > end))
223 return FALSE;
224
225 if (code & SEC_ASN1_CONSTRUCTED) {
226 if (len > 0 || indefinite) {
227 switch (code & SEC_ASN1_CLASS_MASK) {
228 case SEC_ASN1_UNIVERSAL:
229 type = tagnum;
230 break;
231 case SEC_ASN1_APPLICATION:
232 type = E_ASN1_OBJECT_TYPE_APPLICATION;
233 break;
234 case SEC_ASN1_CONTEXT_SPECIFIC:
235 type = E_ASN1_OBJECT_TYPE_CONTEXT_SPECIFIC;
236 break;
237 case SEC_ASN1_PRIVATE:
238 type = E_ASN1_OBJECT_TYPE_PRIVATE;
239 break;
240 default:
241 g_warning ("bad DER");
242 return FALSE;
243 }
244
245 asn1object = e_asn1_object_new ();
246 asn1object->priv->tag = tagnum;
247 asn1object->priv->type = type;
248
249 if (!build_from_der (
250 asn1object, data,
251 (len == 0) ? end : data + len)) {
252 g_object_unref (asn1object);
253 return FALSE;
254 }
255 }
256 } else {
257 asn1object = e_asn1_object_new ();
258
259 asn1object->priv->type = tagnum;
260 asn1object->priv->tag = tagnum;
261
262 /*printableItem->SetData((gchar *)data, len);*/
263 }
264 data += len;
265
266 parent->priv->children = g_list_append (parent->priv->children, asn1object);
267 }
268
269 return TRUE;
270 }
271
272 EASN1Object *
273 e_asn1_object_new_from_der (gchar *data,
274 guint32 len)
275 {
276 EASN1Object *obj = g_object_new (E_TYPE_ASN1_OBJECT, NULL);
277
278 if (!build_from_der (obj, data, data + len)) {
279 g_object_unref (obj);
280 return NULL;
281 }
282
283 return obj;
284 }
285
286 EASN1Object *
287 e_asn1_object_new (void)
288 {
289 return E_ASN1_OBJECT (g_object_new (E_TYPE_ASN1_OBJECT, NULL));
290 }
291
292 void
293 e_asn1_object_set_valid_container (EASN1Object *obj,
294 gboolean flag)
295 {
296 obj->priv->valid_container = flag;
297 }
298
299 gboolean
300 e_asn1_object_is_valid_container (EASN1Object *obj)
301 {
302 return obj->priv->valid_container;
303 }
304
305 PRUint32
306 e_asn1_object_get_asn1_type (EASN1Object *obj)
307 {
308 return obj->priv->type;
309 }
310
311 PRUint32
312 e_asn1_object_get_asn1_tag (EASN1Object *obj)
313 {
314 return obj->priv->tag;
315 }
316
317 GList *
318 e_asn1_object_get_children (EASN1Object *obj)
319 {
320 GList *children = g_list_copy (obj->priv->children);
321
322 g_list_foreach (children, (GFunc) g_object_ref, NULL);
323
324 return children;
325 }
326
327 void
328 e_asn1_object_append_child (EASN1Object *parent,
329 EASN1Object *child)
330 {
331 parent->priv->children = g_list_append (
332 parent->priv->children, g_object_ref (child));
333 }
334
335 void
336 e_asn1_object_set_display_name (EASN1Object *obj,
337 const gchar *name)
338 {
339 g_free (obj->priv->display_name);
340 obj->priv->display_name = g_strdup (name);
341 }
342
343 const gchar *
344 e_asn1_object_get_display_name (EASN1Object *obj)
345 {
346 return obj->priv->display_name;
347 }
348
349 void
350 e_asn1_object_set_display_value (EASN1Object *obj,
351 const gchar *value)
352 {
353 g_free (obj->priv->value);
354 obj->priv->value = g_strdup (value);
355 }
356
357 const gchar *
358 e_asn1_object_get_display_value (EASN1Object *obj)
359 {
360 return obj->priv->value;
361 }
362
363 void
364 e_asn1_object_get_data (EASN1Object *obj,
365 gchar **data,
366 guint32 *len)
367 {
368 *data = obj->priv->data;
369 *len = obj->priv->data_len;
370 }