evolution-3.6.4/smime/lib/e-asn1-object.c

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 }