aboutsummaryrefslogblamecommitdiffstats
path: root/smime/lib/e-asn1-object.c
blob: 4dd519e2d4de2ad6f82fef743532cfa8889dc2fa (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                                                                           
                                                                    
                                                           
  
                                    
  



                                                                              
  



                                                                             
  
                                                        
  



                                                                        
  










                                                                             

   




                                                        



                    










                                 

                            
 
                    








                                       








                                                         
                                                                                   




                                                  






                                                  
                                              









                                                      

                                           



















                                                                  

                                                                          




                                
                                                     




                                                         
  
           

                              
 
                 





















                                                                                   







                                                                    
              



                                          
 
                               
                            
 


                                      
                                                  



                                  
 
                                                











                                                            
                               




                      


                                    
 
                         


                            
                            
                                       




                            






                                                                    











                                                                                  


                                                        
                                  
                                                      
























                                                                                   
 


                                                                         









                                                                    
                                                                       








                                                                                            


                                        










                                                                   
             




                                                                       
    

                                                    



                                          

















                                                   
       



                                                            
                                                              



                        
    

                                                
 

                                                              


    

                                                  




                                                  
             




                                                 
    

                                                    




                                            
             





                                                  


                                         



                                   
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* The following is the mozilla license blurb, as the bodies some of
 * these functions were derived from the mozilla source. */
/*
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the Netscape security libraries.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1994-2000
 * the Initial Developer. All Rights Reserved.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 */

/*
 * Author: Chris Toshok (toshok@ximian.com)
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "e-asn1-object.h"

#include "secasn1.h"

struct _EASN1ObjectPrivate {
    PRUint32 tag;
    PRUint32 type;
    gboolean valid_container;

    GList *children;

    gchar *display_name;
    gchar *value;

    gchar *data;
    guint data_len;
};

#define PARENT_TYPE G_TYPE_OBJECT
static GObjectClass *parent_class;

static void
e_asn1_object_dispose (GObject *object)
{
    EASN1Object *obj = E_ASN1_OBJECT (object);
    if (obj->priv) {

        if (obj->priv->display_name)
            g_free (obj->priv->display_name);

        if (obj->priv->value)
            g_free (obj->priv->value);

        g_list_foreach (obj->priv->children, (GFunc) g_object_unref, NULL);
        g_list_free (obj->priv->children);

        g_free (obj->priv);
        obj->priv = NULL;
    }
}

static void
e_asn1_object_class_init (EASN1ObjectClass *klass)
{
    GObjectClass *object_class;

    object_class = G_OBJECT_CLASS (klass);

    parent_class = g_type_class_ref (PARENT_TYPE);

    object_class->dispose = e_asn1_object_dispose;
}

static void
e_asn1_object_init (EASN1Object *asn1)
{
    asn1->priv = g_new0 (EASN1ObjectPrivate, 1);

    asn1->priv->valid_container = TRUE;
}

GType
e_asn1_object_get_type (void)
{
    static GType asn1_object_type = 0;

    if (!asn1_object_type) {
        static const GTypeInfo asn1_object_info =  {
            sizeof (EASN1ObjectClass),
            NULL,           /* base_init */
            NULL,           /* base_finalize */
            (GClassInitFunc) e_asn1_object_class_init,
            NULL,           /* class_finalize */
            NULL,           /* class_data */
            sizeof (EASN1Object),
            0,             /* n_preallocs */
            (GInstanceInitFunc) e_asn1_object_init,
        };

        asn1_object_type = g_type_register_static (
            PARENT_TYPE, "EASN1Object", &asn1_object_info, 0);
    }

    return asn1_object_type;
}

/* This function is used to interpret an integer that
 * was encoded in a DER buffer. This function is used
 * when converting a DER buffer into a nsIASN1Object
 * structure.  This interprets the buffer in data
 * as defined by the DER (Distinguised Encoding Rules) of
 * ASN1.
*/
static gint
get_integer_256 (guchar *data,
                 guint nb)
{
    gint val;

    switch (nb) {
    case 1:
        val = data[0];
        break;
    case 2:
        val = (data[0] << 8) | data[1];
        break;
    case 3:
        val = (data[0] << 16) | (data[1] << 8) | data[2];
        break;
    case 4:
        val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
        break;
    default:
        return -1;
    }

    return val;
}

/* This function is used to retrieve the lenght of a DER encoded
 * item.  It looks to see if this a multibyte length and then
 * interprets the buffer accordingly to get the actual length value.
 * This funciton is used mostly while parsing the DER headers.
 *
 * A DER encoded item has the following structure:
 *
 * <tag><length<data consisting of lenght bytes>
 */
static guint32
get_der_item_length (guchar *data,
                     guchar *end,
                     gulong *bytesUsed,
                     gboolean *indefinite)
{
    guchar lbyte = *data++;
    PRInt32 length = -1;

    *indefinite = FALSE;
    if (lbyte >= 0x80) {
        /* Multibyte length */
        guint nb = (guint) (lbyte & 0x7f);
        if (nb > 4) {
            return -1;
        }
        if (nb > 0) {

            if ((data + nb) > end) {
                return -1;
            }
            length = get_integer_256 (data, nb);
            if (length < 0)
                return -1;
        } else {
            *indefinite = TRUE;
            length = 0;
        }
        *bytesUsed = nb+1;
    } else {
        length = lbyte;
        *bytesUsed = 1;
    }
    return length;
}

static gboolean
build_from_der (EASN1Object *parent,
                gchar *data,
                gchar *end)
{
    gulong bytesUsed;
    gboolean indefinite;
    PRInt32 len;
    PRUint32 type;
    guchar code, tagnum;
    EASN1Object *asn1object = NULL;

    if (data >= end)
        return TRUE;

    /*
     * A DER item has the form of |tag|len|data
     * tag is one byte and describes the type of elment
     * we are dealing with.
     * len is a DER encoded gint telling us how long the data is
     * data is a buffer that is len bytes long and has to be
     * interpreted according to its type.
     */

    while (data < end) {
        code = *data;
        tagnum = code & SEC_ASN1_TAGNUM_MASK;

        /*
         * NOTE: This code does not (yet) handle the high-tag-number form!
         */
        if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) {
            return FALSE;
        }
        data++;
        len = get_der_item_length (
            (guchar *) data, (guchar *) end,
            &bytesUsed, &indefinite);
        data += bytesUsed;
        if ((len < 0) || ((data + len) > end))
            return FALSE;

        if (code & SEC_ASN1_CONSTRUCTED) {
            if (len > 0 || indefinite) {
                switch (code & SEC_ASN1_CLASS_MASK) {
                case SEC_ASN1_UNIVERSAL:
                    type = tagnum;
                    break;
                case SEC_ASN1_APPLICATION:
                    type = E_ASN1_OBJECT_TYPE_APPLICATION;
                    break;
                case SEC_ASN1_CONTEXT_SPECIFIC:
                    type = E_ASN1_OBJECT_TYPE_CONTEXT_SPECIFIC;
                    break;
                case SEC_ASN1_PRIVATE:
                    type = E_ASN1_OBJECT_TYPE_PRIVATE;
                    break;
                default:
                    g_warning ("bad DER");
                    return FALSE;
                }

                asn1object = e_asn1_object_new ();
                asn1object->priv->tag = tagnum;
                asn1object->priv->type = type;

                if (!build_from_der (
                    asn1object, data,
                    (len == 0) ? end : data + len)) {
                    g_object_unref (asn1object);
                    return FALSE;
                }
            }
        } else {
            asn1object = e_asn1_object_new ();

            asn1object->priv->type = tagnum;
            asn1object->priv->tag = tagnum;

            /*printableItem->SetData((gchar *)data, len);*/
        }
        data += len;

        parent->priv->children = g_list_append (parent->priv->children, asn1object);
    }

    return TRUE;
}

EASN1Object *
e_asn1_object_new_from_der (gchar *data,
                            guint32 len)
{
    EASN1Object *obj = g_object_new (E_TYPE_ASN1_OBJECT, NULL);

    if (!build_from_der (obj, data, data + len)) {
        g_object_unref (obj);
        return NULL;
    }

    return obj;
}

EASN1Object *
e_asn1_object_new (void)
{
    return E_ASN1_OBJECT (g_object_new (E_TYPE_ASN1_OBJECT, NULL));
}

void
e_asn1_object_set_valid_container (EASN1Object *obj,
                                   gboolean flag)
{
    obj->priv->valid_container = flag;
}

gboolean
e_asn1_object_is_valid_container (EASN1Object *obj)
{
    return obj->priv->valid_container;
}

PRUint32
e_asn1_object_get_asn1_type (EASN1Object *obj)
{
    return obj->priv->type;
}

PRUint32
e_asn1_object_get_asn1_tag (EASN1Object *obj)
{
    return obj->priv->tag;
}

GList *
e_asn1_object_get_children (EASN1Object *obj)
{
    GList *children = g_list_copy (obj->priv->children);

    g_list_foreach (children, (GFunc) g_object_ref, NULL);

    return children;
}

void
e_asn1_object_append_child (EASN1Object *parent,
                            EASN1Object *child)
{
    parent->priv->children = g_list_append (
        parent->priv->children, g_object_ref (child));
}

void
e_asn1_object_set_display_name (EASN1Object *obj,
                                const gchar *name)
{
    g_free (obj->priv->display_name);
    obj->priv->display_name = g_strdup (name);
}

const gchar *
e_asn1_object_get_display_name (EASN1Object *obj)
{
    return obj->priv->display_name;
}

void
e_asn1_object_set_display_value (EASN1Object *obj,
                                 const gchar *value)
{
    g_free (obj->priv->value);
    obj->priv->value = g_strdup (value);
}

const gchar *
e_asn1_object_get_display_value (EASN1Object *obj)
{
    return obj->priv->value;
}

void
e_asn1_object_get_data (EASN1Object *obj,
                        gchar **data,
                        guint32 *len)
{
    *data = obj->priv->data;
    *len = obj->priv->data_len;
}