iPXE
Defines | Functions
asn1.c File Reference

ASN.1 encoding. More...

#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <ipxe/tables.h>
#include <ipxe/image.h>
#include <ipxe/asn1.h>

Go to the source code of this file.

Defines

#define EINVAL_ASN1_EMPTY   __einfo_error ( EINFO_EINVAL_ASN1_EMPTY )
#define EINFO_EINVAL_ASN1_EMPTY   __einfo_uniqify ( EINFO_EINVAL, 0x01, "Empty or underlength cursor" )
#define EINVAL_ASN1_LEN_LEN   __einfo_error ( EINFO_EINVAL_ASN1_LEN_LEN )
#define EINFO_EINVAL_ASN1_LEN_LEN   __einfo_uniqify ( EINFO_EINVAL, 0x02, "Length field overruns cursor" )
#define EINVAL_ASN1_LEN   __einfo_error ( EINFO_EINVAL_ASN1_LEN )
#define EINFO_EINVAL_ASN1_LEN   __einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
#define EINVAL_ASN1_BOOLEAN   __einfo_error ( EINFO_EINVAL_ASN1_BOOLEAN )
#define EINFO_EINVAL_ASN1_BOOLEAN   __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid boolean" )
#define EINVAL_ASN1_INTEGER   __einfo_error ( EINFO_EINVAL_ASN1_INTEGER )
#define EINFO_EINVAL_ASN1_INTEGER   __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid integer" )
#define EINVAL_ASN1_TIME   __einfo_error ( EINFO_EINVAL_ASN1_TIME )
#define EINFO_EINVAL_ASN1_TIME   __einfo_uniqify ( EINFO_EINVAL, 0x05, "Invalid time" )
#define EINVAL_ASN1_ALGORITHM   __einfo_error ( EINFO_EINVAL_ASN1_ALGORITHM )
#define EINFO_EINVAL_ASN1_ALGORITHM   __einfo_uniqify ( EINFO_EINVAL, 0x06, "Invalid algorithm" )
#define EINVAL_BIT_STRING   __einfo_error ( EINFO_EINVAL_BIT_STRING )
#define EINFO_EINVAL_BIT_STRING   __einfo_uniqify ( EINFO_EINVAL, 0x07, "Invalid bit string" )
#define ENOTSUP_ALGORITHM   __einfo_error ( EINFO_ENOTSUP_ALGORITHM )
#define EINFO_ENOTSUP_ALGORITHM   __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported algorithm" )
#define ENOTTY_ALGORITHM   __einfo_error ( EINFO_ENOTTY_ALGORITHM )
#define EINFO_ENOTTY_ALGORITHM   __einfo_uniqify ( EINFO_ENOTTY, 0x01, "Inappropriate algorithm" )

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
int asn1_start (struct asn1_cursor *cursor, unsigned int type, size_t extra)
 Start parsing ASN.1 object.
int asn1_enter (struct asn1_cursor *cursor, unsigned int type)
 Enter ASN.1 object.
int asn1_skip_if_exists (struct asn1_cursor *cursor, unsigned int type)
 Skip ASN.1 object if present.
int asn1_skip (struct asn1_cursor *cursor, unsigned int type)
 Skip ASN.1 object.
int asn1_shrink (struct asn1_cursor *cursor, unsigned int type)
 Shrink ASN.1 cursor to fit object.
int asn1_enter_any (struct asn1_cursor *cursor)
 Enter ASN.1 object of any type.
int asn1_skip_any (struct asn1_cursor *cursor)
 Skip ASN.1 object of any type.
int asn1_shrink_any (struct asn1_cursor *cursor)
 Shrink ASN.1 object of any type.
int asn1_boolean (const struct asn1_cursor *cursor)
 Parse value of ASN.1 boolean.
int asn1_integer (const struct asn1_cursor *cursor, int *value)
 Parse value of ASN.1 integer.
int asn1_bit_string (const struct asn1_cursor *cursor, struct asn1_bit_string *bits)
 Parse ASN.1 bit string.
int asn1_integral_bit_string (const struct asn1_cursor *cursor, struct asn1_bit_string *bits)
 Parse ASN.1 bit string that must be an integral number of bytes.
int asn1_compare (const struct asn1_cursor *cursor1, const struct asn1_cursor *cursor2)
 Compare two ASN.1 objects.
static struct asn1_algorithmasn1_find_algorithm (const struct asn1_cursor *cursor)
 Identify ASN.1 algorithm by OID.
int asn1_algorithm (const struct asn1_cursor *cursor, struct asn1_algorithm **algorithm)
 Parse ASN.1 OID-identified algorithm.
int asn1_pubkey_algorithm (const struct asn1_cursor *cursor, struct asn1_algorithm **algorithm)
 Parse ASN.1 OID-identified public-key algorithm.
int asn1_digest_algorithm (const struct asn1_cursor *cursor, struct asn1_algorithm **algorithm)
 Parse ASN.1 OID-identified digest algorithm.
int asn1_signature_algorithm (const struct asn1_cursor *cursor, struct asn1_algorithm **algorithm)
 Parse ASN.1 OID-identified signature algorithm.
int asn1_generalized_time (const struct asn1_cursor *cursor, time_t *time)
 Parse ASN.1 GeneralizedTime.
static size_t asn1_header (struct asn1_builder_header *header, unsigned int type, size_t len)
 Construct ASN.1 header.
int asn1_grow (struct asn1_builder *builder, size_t extra)
 Grow ASN.1 builder.
int asn1_prepend_raw (struct asn1_builder *builder, const void *data, size_t len)
 Prepend raw data to ASN.1 builder.
int asn1_prepend (struct asn1_builder *builder, unsigned int type, const void *data, size_t len)
 Prepend data to ASN.1 builder.
int asn1_wrap (struct asn1_builder *builder, unsigned int type)
 Wrap ASN.1 builder.
int image_asn1 (struct image *image, size_t offset, struct asn1_cursor **cursor)
 Extract ASN.1 object from image.
 REQUIRING_SYMBOL (image_asn1)
 REQUIRE_OBJECT (config_asn1)

Detailed Description

ASN.1 encoding.

Definition in file asn1.c.


Define Documentation

Definition at line 44 of file asn1.c.

Referenced by asn1_start().

#define EINFO_EINVAL_ASN1_EMPTY   __einfo_uniqify ( EINFO_EINVAL, 0x01, "Empty or underlength cursor" )

Definition at line 46 of file asn1.c.

Definition at line 48 of file asn1.c.

Referenced by asn1_start().

#define EINFO_EINVAL_ASN1_LEN_LEN   __einfo_uniqify ( EINFO_EINVAL, 0x02, "Length field overruns cursor" )

Definition at line 50 of file asn1.c.

Definition at line 52 of file asn1.c.

Referenced by asn1_start().

#define EINFO_EINVAL_ASN1_LEN   __einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )

Definition at line 54 of file asn1.c.

Definition at line 56 of file asn1.c.

Referenced by asn1_boolean().

#define EINFO_EINVAL_ASN1_BOOLEAN   __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid boolean" )

Definition at line 58 of file asn1.c.

Definition at line 60 of file asn1.c.

Referenced by asn1_integer().

#define EINFO_EINVAL_ASN1_INTEGER   __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid integer" )

Definition at line 62 of file asn1.c.

Definition at line 64 of file asn1.c.

Referenced by asn1_generalized_time().

#define EINFO_EINVAL_ASN1_TIME   __einfo_uniqify ( EINFO_EINVAL, 0x05, "Invalid time" )

Definition at line 66 of file asn1.c.

Definition at line 68 of file asn1.c.

Referenced by asn1_algorithm().

#define EINFO_EINVAL_ASN1_ALGORITHM   __einfo_uniqify ( EINFO_EINVAL, 0x06, "Invalid algorithm" )

Definition at line 70 of file asn1.c.

Definition at line 72 of file asn1.c.

Referenced by asn1_bit_string(), and asn1_integral_bit_string().

#define EINFO_EINVAL_BIT_STRING   __einfo_uniqify ( EINFO_EINVAL, 0x07, "Invalid bit string" )

Definition at line 74 of file asn1.c.

Definition at line 76 of file asn1.c.

Referenced by asn1_algorithm().

#define EINFO_ENOTSUP_ALGORITHM   __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported algorithm" )

Definition at line 78 of file asn1.c.

Definition at line 80 of file asn1.c.

Referenced by asn1_digest_algorithm(), asn1_pubkey_algorithm(), and asn1_signature_algorithm().

#define EINFO_ENOTTY_ALGORITHM   __einfo_uniqify ( EINFO_ENOTTY, 0x01, "Inappropriate algorithm" )

Definition at line 82 of file asn1.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
int asn1_start ( struct asn1_cursor cursor,
unsigned int  type,
size_t  extra 
)

Start parsing ASN.1 object.

Parameters:
cursorASN.1 object cursor
typeExpected type, or ASN1_ANY
extraAdditional length not present within partial cursor
Return values:
lenLength of object body, or negative error

The object cursor will be updated to point to the start of the object body (i.e. the first byte following the length byte(s)), and the length of the object body (i.e. the number of bytes until the following object tag, if any) is returned.

Definition at line 98 of file asn1.c.

References ASN1_ANY, asn1_type(), asn1_cursor::data, DBGC, EINVAL_ASN1_EMPTY, EINVAL_ASN1_LEN, EINVAL_ASN1_LEN_LEN, ENXIO, asn1_cursor::len, and len.

Referenced by asn1_enter(), asn1_shrink(), asn1_skip_if_exists(), and der_probe().

                                                                               {
        unsigned int len_len;
        unsigned int len;

        /* Sanity check */
        if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
                if ( cursor->len )
                        DBGC ( cursor, "ASN1 %p too short\n", cursor );
                return -EINVAL_ASN1_EMPTY;
        }

        /* Check the tag byte */
        if ( ( type != ASN1_ANY ) && ( type != asn1_type ( cursor ) ) ) {
                DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
                       cursor, type, *( ( uint8_t * ) cursor->data ) );
                return -ENXIO;
        }
        cursor->data++;
        cursor->len--;

        /* Extract length of the length field and sanity check */
        len_len = *( ( uint8_t * ) cursor->data );
        if ( len_len & 0x80 ) {
                len_len = ( len_len & 0x7f );
                cursor->data++;
                cursor->len--;
        } else {
                len_len = 1;
        }
        if ( cursor->len < len_len ) {
                DBGC ( cursor, "ASN1 %p bad length field length %d (max "
                       "%zd)\n", cursor, len_len, cursor->len );
                return -EINVAL_ASN1_LEN_LEN;
        }

        /* Extract the length and sanity check */
        for ( len = 0 ; len_len ; len_len-- ) {
                len <<= 8;
                len |= *( ( uint8_t * ) cursor->data );
                cursor->data++;
                cursor->len--;
        }
        if ( ( cursor->len + extra ) < len ) {
                DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
                       cursor, len, ( cursor->len + extra ) );
                return -EINVAL_ASN1_LEN;
        }

        return len;
}
int asn1_enter ( struct asn1_cursor cursor,
unsigned int  type 
)

Enter ASN.1 object.

Parameters:
cursorASN.1 object cursor
typeExpected type, or ASN1_ANY
Return values:
rcReturn status code

The object cursor will be updated to point to the body of the current ASN.1 object. If any error occurs, the object cursor will be invalidated.

Definition at line 160 of file asn1.c.

References asn1_invalidate_cursor(), asn1_start(), DBGC, asn1_cursor::len, and len.

Referenced by asn1_algorithm(), asn1_bit_string(), asn1_boolean(), asn1_enter_any(), asn1_generalized_time(), asn1_integer(), cms_parse(), cms_parse_certificates(), cms_parse_content_type(), cms_parse_signature_value(), cms_parse_signer_identifier(), cms_parse_signer_info(), ocsp_compare_responder_key_hash(), ocsp_parse_basic_response(), ocsp_parse_certs(), ocsp_parse_response(), ocsp_parse_response_bytes(), ocsp_parse_response_status(), ocsp_parse_response_type(), ocsp_parse_responses(), ocsp_parse_tbs_response_data(), ocsp_request(), rsa_parse_integer(), rsa_parse_mod_exp(), validator_append(), x509_parse(), x509_parse_access_description(), x509_parse_authority_info_access(), x509_parse_basic_constraints(), x509_parse_common_name(), x509_parse_extended_key_usage(), x509_parse_extension(), x509_parse_extensions(), x509_parse_key_purpose(), x509_parse_ocsp(), x509_parse_public_key(), x509_parse_subject_alt_name(), x509_parse_tbscertificate(), x509_parse_validity(), and x509_parse_version().

                                                                 {
        int len;

        len = asn1_start ( cursor, type, 0 );
        if ( len < 0 ) {
                asn1_invalidate_cursor ( cursor );
                return len;
        }

        cursor->len = len;
        DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
               cursor, type, len );

        return 0;
}
int asn1_skip_if_exists ( struct asn1_cursor cursor,
unsigned int  type 
)

Skip ASN.1 object if present.

Parameters:
cursorASN.1 object cursor
typeExpected type, or ASN1_ANY
Return values:
rcReturn status code

The object cursor will be updated to point to the next ASN.1 object. If any error occurs, the object cursor will not be modified.

Definition at line 187 of file asn1.c.

References asn1_start(), asn1_cursor::data, DBGC, ENOENT, asn1_cursor::len, and len.

Referenced by asn1_skip(), cms_parse(), cms_parse_signer_info(), and ocsp_parse_tbs_response_data().

                                                                          {
        int len;

        len = asn1_start ( cursor, type, 0 );
        if ( len < 0 )
                return len;

        cursor->data += len;
        cursor->len -= len;
        DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n",
               cursor, type, len );

        if ( ! cursor->len ) {
                DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
                return -ENOENT;
        }

        return 0;
}
int asn1_skip ( struct asn1_cursor cursor,
unsigned int  type 
)

Skip ASN.1 object.

Parameters:
cursorASN.1 object cursor
typeExpected type, or ASN1_ANY
Return values:
rcReturn status code

The object cursor will be updated to point to the next ASN.1 object. If any error occurs, the object cursor will be invalidated.

Definition at line 218 of file asn1.c.

References asn1_invalidate_cursor(), asn1_skip_if_exists(), and rc.

Referenced by asn1_skip_any(), cms_parse(), cms_parse_signer_info(), and rsa_parse_mod_exp().

                                                                {
        int rc;

        if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) != 0 ) {
                asn1_invalidate_cursor ( cursor );
                return rc;
        }

        return 0;
}
int asn1_shrink ( struct asn1_cursor cursor,
unsigned int  type 
)

Shrink ASN.1 cursor to fit object.

Parameters:
cursorASN.1 object cursor
typeExpected type, or ASN1_ANY
Return values:
rcReturn status code

The object cursor will be shrunk to contain only the current ASN.1 object. If any error occurs, the object cursor will be invalidated.

Definition at line 240 of file asn1.c.

References asn1_invalidate_cursor(), asn1_start(), asn1_cursor::data, end, asn1_cursor::len, len, and memcpy().

Referenced by asn1_shrink_any(), cms_parse_signer_identifier(), x509_parse_issuer(), and x509_parse_serial().

                                                                  {
        struct asn1_cursor temp;
        const void *end;
        int len;

        /* Find end of object */
        memcpy ( &temp, cursor, sizeof ( temp ) );
        len = asn1_start ( &temp, type, 0 );
        if ( len < 0 ) {
                asn1_invalidate_cursor ( cursor );
                return len;
        }
        end = ( temp.data + len );

        /* Shrink original cursor to contain only its first object */
        cursor->len = ( end - cursor->data );

        return 0;
}
int asn1_enter_any ( struct asn1_cursor cursor)

Enter ASN.1 object of any type.

Parameters:
cursorASN.1 object cursor
Return values:
rcReturn status code

Definition at line 266 of file asn1.c.

References ASN1_ANY, and asn1_enter().

Referenced by ocsp_parse_responder_id(), x509_check_alt_name(), and x509_parse_common_name().

                                                  {
        return asn1_enter ( cursor, ASN1_ANY );
}
int asn1_skip_any ( struct asn1_cursor cursor)
int asn1_shrink_any ( struct asn1_cursor cursor)

Shrink ASN.1 object of any type.

Parameters:
cursorASN.1 object cursor
Return values:
rcReturn status code

Definition at line 286 of file asn1.c.

References ASN1_ANY, and asn1_shrink().

Referenced by cms_signature(), ocsp_parse_cert_id(), ocsp_parse_tbs_response_data(), x509_certificate(), x509_parse_public_key(), x509_parse_subject(), and x509_parse_tbscertificate().

                                                   {
        return asn1_shrink ( cursor, ASN1_ANY );
}
int asn1_boolean ( const struct asn1_cursor cursor)

Parse value of ASN.1 boolean.

Parameters:
cursorASN.1 object cursor
Return values:
valueValue, or negative error

Definition at line 296 of file asn1.c.

References __attribute__, ASN1_BOOLEAN, asn1_enter(), asn1_cursor::data, EINVAL_ASN1_BOOLEAN, asn1_cursor::len, memcpy(), and value.

Referenced by x509_parse_basic_constraints(), and x509_parse_extension().

                                                      {
        struct asn1_cursor contents;
        const struct {
                uint8_t value;
        } __attribute__ (( packed )) *boolean;

        /* Enter boolean */
        memcpy ( &contents, cursor, sizeof ( contents ) );
        asn1_enter ( &contents, ASN1_BOOLEAN );
        if ( contents.len != sizeof ( *boolean ) )
                return -EINVAL_ASN1_BOOLEAN;

        /* Extract value */
        boolean = contents.data;
        return boolean->value;
}
int asn1_integer ( const struct asn1_cursor cursor,
int *  value 
)

Parse value of ASN.1 integer.

Parameters:
cursorASN.1 object cursor
valueValue to fill in
Return values:
rcReturn status code

Definition at line 320 of file asn1.c.

References asn1_enter(), ASN1_INTEGER, asn1_cursor::data, DBGC, EINVAL_ASN1_INTEGER, asn1_cursor::len, memcpy(), and rc.

Referenced by x509_parse_basic_constraints(), and x509_parse_version().

                                                                  {
        struct asn1_cursor contents;
        uint8_t high_byte;
        int rc;

        /* Enter integer */
        memcpy ( &contents, cursor, sizeof ( contents ) );
        if ( ( rc = asn1_enter ( &contents, ASN1_INTEGER ) ) != 0 )
                return rc;
        if ( contents.len < 1 )
                return -EINVAL_ASN1_INTEGER;

        /* Initialise value according to sign byte */
        *value = *( ( int8_t * ) contents.data );
        contents.data++;
        contents.len--;

        /* Process value */
        while ( contents.len ) {
                high_byte = ( (*value) >> ( 8 * ( sizeof ( *value ) - 1 ) ) );
                if ( ( high_byte != 0x00 ) && ( high_byte != 0xff ) ) {
                        DBGC ( cursor, "ASN1 %p integer overflow\n", cursor );
                        return -EINVAL_ASN1_INTEGER;
                }
                *value = ( ( *value << 8 ) | *( ( uint8_t * ) contents.data ) );
                contents.data++;
                contents.len--;
        }

        return 0;
}
int asn1_bit_string ( const struct asn1_cursor cursor,
struct asn1_bit_string bits 
)

Parse ASN.1 bit string.

Parameters:
cursorASN.1 cursor
bitsBit string to fill in
Return values:
rcReturn status code

Definition at line 359 of file asn1.c.

References __attribute__, ASN1_BIT_STRING, asn1_enter(), asn1_cursor::data, data, asn1_bit_string::data, DBGC, DBGC_HDA, EINVAL_BIT_STRING, last, asn1_cursor::len, len, asn1_bit_string::len, memcpy(), offsetof, rc, unused, and asn1_bit_string::unused.

                                                     {
        struct asn1_cursor contents;
        const struct {
                uint8_t unused;
                uint8_t data[0];
        } __attribute__ (( packed )) *bit_string;
        size_t len;
        unsigned int unused;
        uint8_t unused_mask;
        const uint8_t *last;
        int rc;

        /* Enter bit string */
        memcpy ( &contents, cursor, sizeof ( contents ) );
        if ( ( rc = asn1_enter ( &contents, ASN1_BIT_STRING ) ) != 0 ) {
                DBGC ( cursor, "ASN1 %p cannot locate bit string:\n", cursor );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return rc;
        }

        /* Validity checks */
        if ( contents.len < sizeof ( *bit_string ) ) {
                DBGC ( cursor, "ASN1 %p invalid bit string:\n", cursor );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return -EINVAL_BIT_STRING;
        }
        bit_string = contents.data;
        len = ( contents.len - offsetof ( typeof ( *bit_string ), data ) );
        unused = bit_string->unused;
        unused_mask = ( 0xff >> ( 8 - unused ) );
        last = ( bit_string->data + len - 1 );
        if ( ( unused >= 8 ) ||
             ( ( unused > 0 ) && ( len == 0 ) ) ||
             ( ( *last & unused_mask ) != 0 ) ) {
                DBGC ( cursor, "ASN1 %p invalid bit string:\n", cursor );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return -EINVAL_BIT_STRING;
        }

        /* Populate bit string */
        bits->data = &bit_string->data;
        bits->len = len;
        bits->unused = unused;

        return 0;
}
int asn1_integral_bit_string ( const struct asn1_cursor cursor,
struct asn1_bit_string bits 
)

Parse ASN.1 bit string that must be an integral number of bytes.

Parameters:
cursorASN.1 cursor
bitsBit string to fill in
Return values:
rcReturn status code

Definition at line 414 of file asn1.c.

References asn1_cursor::data, DBGC, DBGC_HDA, EINVAL_BIT_STRING, asn1_cursor::len, rc, and asn1_bit_string::unused.

Referenced by ocsp_parse_basic_response(), rsa_parse_mod_exp(), and x509_parse().

                                                              {
        int rc;

        /* Parse bit string */
        if ( ( rc = asn1_bit_string ( cursor, bits ) ) != 0 )
                return rc;

        /* Check that there are no unused bits at end of string */
        if ( bits->unused ) {
                DBGC ( cursor, "ASN1 %p invalid integral bit string:\n",
                       cursor );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return -EINVAL_BIT_STRING;
        }

        return 0;
}
int asn1_compare ( const struct asn1_cursor cursor1,
const struct asn1_cursor cursor2 
)

Compare two ASN.1 objects.

Parameters:
cursor1ASN.1 object cursor
cursor2ASN.1 object cursor
Return values:
differenceDifference as returned by memcmp()

Note that invalid and empty cursors will compare as equal with each other.

Definition at line 443 of file asn1.c.

References asn1_cursor::data, asn1_cursor::len, and memcmp().

Referenced by asn1_find_algorithm(), certstore_find(), cms_find_issuer_serial(), cms_parse_content_type(), ocsp_compare_responder_name(), ocsp_parse_cert_id(), ocsp_parse_response_type(), rsa_match(), validator_step(), x509_check_issuer(), x509_find_access_method(), x509_find_extension(), x509_find_subject(), x509_parse_common_name(), and x509_parse_key_purpose().

                                                       {
        int difference;

        difference = ( cursor2->len - cursor1->len );
        return ( difference ? difference :
                 memcmp ( cursor1->data, cursor2->data, cursor1->len ) );
}
static struct asn1_algorithm* asn1_find_algorithm ( const struct asn1_cursor cursor) [static, read]

Identify ASN.1 algorithm by OID.

Parameters:
cursorASN.1 object cursor
Return values:
algorithmAlgorithm, or NULL

Definition at line 460 of file asn1.c.

References algorithm, ASN1_ALGORITHMS, asn1_compare(), for_each_table_entry, NULL, and asn1_algorithm::oid.

Referenced by asn1_algorithm().

                                                         {
        struct asn1_algorithm *algorithm;

        for_each_table_entry ( algorithm, ASN1_ALGORITHMS ) {
                if ( asn1_compare ( &algorithm->oid, cursor ) == 0 )
                        return algorithm;
        }

        return NULL;
}
int asn1_algorithm ( const struct asn1_cursor cursor,
struct asn1_algorithm **  algorithm 
)

Parse ASN.1 OID-identified algorithm.

Parameters:
cursorASN.1 object cursor
Return values:
algorithmAlgorithm
rcReturn status code

Definition at line 478 of file asn1.c.

References asn1_enter(), asn1_find_algorithm(), ASN1_OID, ASN1_SEQUENCE, asn1_cursor::data, DBGC, DBGC_HDA, EINVAL_ASN1_ALGORITHM, ENOTSUP_ALGORITHM, asn1_cursor::len, memcpy(), and rc.

                                                         {
        struct asn1_cursor contents;
        int rc;

        /* Enter signatureAlgorithm */
        memcpy ( &contents, cursor, sizeof ( contents ) );
        asn1_enter ( &contents, ASN1_SEQUENCE );

        /* Enter algorithm */
        if ( ( rc = asn1_enter ( &contents, ASN1_OID ) ) != 0 ) {
                DBGC ( cursor, "ASN1 %p cannot locate algorithm OID:\n",
                       cursor );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return -EINVAL_ASN1_ALGORITHM;
        }

        /* Identify algorithm */
        *algorithm = asn1_find_algorithm ( &contents );
        if ( ! *algorithm ) {
                DBGC ( cursor, "ASN1 %p unrecognised algorithm:\n", cursor );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return -ENOTSUP_ALGORITHM;
        }

        return 0;
}
int asn1_pubkey_algorithm ( const struct asn1_cursor cursor,
struct asn1_algorithm **  algorithm 
)

Parse ASN.1 OID-identified public-key algorithm.

Parameters:
cursorASN.1 object cursor
Return values:
algorithmAlgorithm
rcReturn status code

Definition at line 513 of file asn1.c.

References asn1_cursor::data, DBGC, DBGC_HDA, ENOTTY_ALGORITHM, asn1_cursor::len, and rc.

Referenced by cms_parse_signature_algorithm(), and x509_parse_public_key().

                                                                {
        int rc;

        /* Parse algorithm */
        if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
                return rc;

        /* Check algorithm has a public key */
        if ( ! (*algorithm)->pubkey ) {
                DBGC ( cursor, "ASN1 %p algorithm %s is not a public-key "
                       "algorithm:\n", cursor, (*algorithm)->name );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return -ENOTTY_ALGORITHM;
        }

        return 0;
}
int asn1_digest_algorithm ( const struct asn1_cursor cursor,
struct asn1_algorithm **  algorithm 
)

Parse ASN.1 OID-identified digest algorithm.

Parameters:
cursorASN.1 object cursor
Return values:
algorithmAlgorithm
rcReturn status code

Definition at line 539 of file asn1.c.

References asn1_cursor::data, DBGC, DBGC_HDA, ENOTTY_ALGORITHM, asn1_cursor::len, and rc.

Referenced by cms_parse_digest_algorithm().

                                                                {
        int rc;

        /* Parse algorithm */
        if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
                return rc;

        /* Check algorithm has a digest */
        if ( ! (*algorithm)->digest ) {
                DBGC ( cursor, "ASN1 %p algorithm %s is not a digest "
                       "algorithm:\n", cursor, (*algorithm)->name );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return -ENOTTY_ALGORITHM;
        }

        return 0;
}
int asn1_signature_algorithm ( const struct asn1_cursor cursor,
struct asn1_algorithm **  algorithm 
)

Parse ASN.1 OID-identified signature algorithm.

Parameters:
cursorASN.1 object cursor
Return values:
algorithmAlgorithm
rcReturn status code

Definition at line 565 of file asn1.c.

References asn1_cursor::data, DBGC, DBGC_HDA, ENOTTY_ALGORITHM, asn1_cursor::len, and rc.

Referenced by ocsp_parse_basic_response(), x509_parse(), and x509_parse_tbscertificate().

                                                                   {
        int rc;

        /* Parse algorithm */
        if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
                return rc;

        /* Check algorithm has a public key */
        if ( ! (*algorithm)->pubkey ) {
                DBGC ( cursor, "ASN1 %p algorithm %s is not a signature "
                       "algorithm:\n", cursor, (*algorithm)->name );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return -ENOTTY_ALGORITHM;
        }

        /* Check algorithm has a digest */
        if ( ! (*algorithm)->digest ) {
                DBGC ( cursor, "ASN1 %p algorithm %s is not a signature "
                       "algorithm:\n", cursor, (*algorithm)->name );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return -ENOTTY_ALGORITHM;
        }

        return 0;
}
int asn1_generalized_time ( const struct asn1_cursor cursor,
time_t time 
)

Parse ASN.1 GeneralizedTime.

Parameters:
cursorASN.1 cursor
timeTime to fill in
Return values:
rcReturn status code

RFC 5280 section 4.1.2.5 places several restrictions on the allowed formats for UTCTime and GeneralizedTime, and mandates the interpretation of centuryless year values.

Definition at line 603 of file asn1.c.

References __attribute__, asn1_enter(), ASN1_GENERALIZED_TIME, asn1_type(), ASN1_UTC_TIME, asn1_cursor::data, data, DBGC, DBGC_HDA, EINVAL_ASN1_TIME, isdigit(), asn1_cursor::len, memcpy(), memset(), mktime(), raw, rc, tm::tm_hour, tm::tm_mday, tm::tm_min, tm::tm_mon, tm::tm_sec, tm::tm_year, and type.

Referenced by ocsp_parse_responses(), and x509_parse_validity().

                                                                             {
        struct asn1_cursor contents;
        unsigned int have_century;
        unsigned int type;
        union {
                struct {
                        uint8_t century;
                        uint8_t year;
                        uint8_t month;
                        uint8_t day;
                        uint8_t hour;
                        uint8_t minute;
                        uint8_t second;
                } __attribute__ (( packed )) named;
                uint8_t raw[7];
        } pairs;
        struct tm tm;
        const uint8_t *data;
        size_t remaining;
        unsigned int tens;
        unsigned int units;
        unsigned int i;
        int rc;

        /* Determine time format utcTime/generalizedTime */
        memcpy ( &contents, cursor, sizeof ( contents ) );
        type = asn1_type ( &contents );
        switch ( type ) {
        case ASN1_UTC_TIME:
                have_century = 0;
                break;
        case ASN1_GENERALIZED_TIME:
                have_century = 1;
                break;
        default:
                DBGC ( cursor, "ASN1 %p invalid time type %02x\n",
                       cursor, type );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return -EINVAL_ASN1_TIME;
        }

        /* Enter utcTime/generalizedTime */
        if ( ( rc = asn1_enter ( &contents, type ) ) != 0 ) {
                DBGC ( cursor, "ASN1 %p cannot locate %s time:\n", cursor,
                       ( ( type == ASN1_UTC_TIME ) ? "UTC" : "generalized" ) );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return rc;
        }

        /* Parse digit string a pair at a time */
        memset ( &pairs, 0, sizeof ( pairs ) );
        data = contents.data;
        remaining = contents.len;
        for ( i = ( have_century ? 0 : 1 ) ; i < sizeof ( pairs.raw ) ; i++ ) {
                if ( remaining < 2 ) {
                        /* Some certificates violate the X.509 RFC by
                         * omitting the "seconds" value.
                         */
                        if ( i == ( sizeof ( pairs.raw ) - 1 ) )
                                break;
                        DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
                        DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                        return -EINVAL_ASN1_TIME;
                }
                tens = data[0];
                units = data[1];
                if ( ! ( isdigit ( tens ) && isdigit ( units ) ) ) {
                        DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
                        DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                        return -EINVAL_ASN1_TIME;
                }
                pairs.raw[i] = ( ( 10 * ( tens - '0' ) ) + ( units - '0' ) );
                data += 2;
                remaining -= 2;
        }

        /* Determine century if applicable */
        if ( ! have_century )
                pairs.named.century = ( ( pairs.named.year >= 50 ) ? 19 : 20 );

        /* Check for trailing "Z" */
        if ( ( remaining != 1 ) || ( data[0] != 'Z' ) ) {
                DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
                DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
                return -EINVAL_ASN1_TIME;
        }

        /* Fill in time */
        tm.tm_year = ( ( ( pairs.named.century - 19 ) * 100 ) +
                       pairs.named.year );
        tm.tm_mon = ( pairs.named.month - 1 );
        tm.tm_mday = pairs.named.day;
        tm.tm_hour = pairs.named.hour;
        tm.tm_min = pairs.named.minute;
        tm.tm_sec = pairs.named.second;

        /* Convert to seconds since the Epoch */
        *time = mktime ( &tm );

        return 0;
}
static size_t asn1_header ( struct asn1_builder_header header,
unsigned int  type,
size_t  len 
) [static]

Construct ASN.1 header.

Parameters:
headerASN.1 builder header
typeType
lenContent length
Return values:
header_lenHeader length

Definition at line 713 of file asn1.c.

References len, asn1_builder_header::length, asn1_builder_header::type, and type.

Referenced by asn1_prepend(), and asn1_wrap().

                                                            {
        unsigned int header_len = 2;
        unsigned int len_len = 0;
        size_t temp;

        /* Construct header */
        header->type = type;
        if ( len < 0x80 ) {
                header->length[0] = len;
        } else {
                for ( temp = len ; temp ; temp >>= 8 )
                        len_len++;
                header->length[0] = ( 0x80 | len_len );
                header_len += len_len;
                for ( temp = len ; temp ; temp >>= 8 )
                        header->length[len_len--] = ( temp & 0xff );
        }

        return header_len;
}
int asn1_grow ( struct asn1_builder builder,
size_t  extra 
)

Grow ASN.1 builder.

Parameters:
builderASN.1 builder
extraExtra space to prepend
Return values:
rcReturn status code

Definition at line 742 of file asn1.c.

References asn1_builder::data, ENOMEM, free, asn1_builder::len, memmove(), NULL, and realloc().

Referenced by asn1_prepend(), asn1_prepend_raw(), and asn1_wrap().

                                                             {
        size_t new_len;
        void *new;

        /* As with the ASN1 parsing functions, make errors permanent */
        if ( builder->len && ! builder->data )
                return -ENOMEM;

        /* Reallocate data buffer */
        new_len = ( builder->len + extra );
        new = realloc ( builder->data, new_len );
        if ( ! new ) {
                free ( builder->data );
                builder->data = NULL;
                return -ENOMEM;
        }
        builder->data = new;

        /* Move existing data to end of buffer */
        memmove ( ( builder->data + extra ), builder->data, builder->len );
        builder->len = new_len;

        return 0;
}
int asn1_prepend_raw ( struct asn1_builder builder,
const void *  data,
size_t  len 
)

Prepend raw data to ASN.1 builder.

Parameters:
builderASN.1 builder
dataData to prepend
lenLength of data to prepend
Return values:
rcReturn status code

Definition at line 775 of file asn1.c.

References asn1_grow(), asn1_builder::data, memcpy(), and rc.

Referenced by ocsp_request().

                                    {
        int rc;

        /* Grow buffer */
        if ( ( rc = asn1_grow ( builder, len ) ) != 0 )
                return rc;

        /* Populate data buffer */
        memcpy ( builder->data, data, len );

        return 0;
}
int asn1_prepend ( struct asn1_builder builder,
unsigned int  type,
const void *  data,
size_t  len 
)

Prepend data to ASN.1 builder.

Parameters:
builderASN.1 builder
typeType
dataData to prepend
lenLength of data to prepend
Return values:
rcReturn status code

Definition at line 798 of file asn1.c.

References asn1_grow(), asn1_header(), asn1_builder::data, memcpy(), and rc.

Referenced by ocsp_request().

                                                  {
        struct asn1_builder_header header;
        size_t header_len;
        int rc;

        /* Construct header */
        header_len = asn1_header ( &header, type, len );

        /* Grow buffer */
        if ( ( rc = asn1_grow ( builder, header_len + len ) ) != 0 )
                return rc;

        /* Populate data buffer */
        memcpy ( builder->data, &header, header_len );
        memcpy ( ( builder->data + header_len ), data, len );

        return 0;
}
int asn1_wrap ( struct asn1_builder builder,
unsigned int  type 
)

Wrap ASN.1 builder.

Parameters:
builderASN.1 builder
typeType
Return values:
rcReturn status code

Definition at line 825 of file asn1.c.

References asn1_grow(), asn1_header(), asn1_builder::data, asn1_builder::len, memcpy(), and rc.

Referenced by ocsp_request().

                                                                  {
        struct asn1_builder_header header;
        size_t header_len;
        int rc;

        /* Construct header */
        header_len = asn1_header ( &header, type, builder->len );

        /* Grow buffer */
        if ( ( rc = asn1_grow ( builder, header_len ) ) != 0 )
                return rc;

        /* Populate data buffer */
        memcpy ( builder->data, &header, header_len );

        return 0;
}
int image_asn1 ( struct image image,
size_t  offset,
struct asn1_cursor **  cursor 
)

Extract ASN.1 object from image.

Parameters:
imageImage
offsetOffset within image
cursorASN.1 cursor to fill in
Return values:
nextOffset to next image, or negative error

The caller is responsible for eventually calling free() on the allocated ASN.1 cursor.

Definition at line 854 of file asn1.c.

References image_type::asn1, assert, DBGC, ENOTSUP, len, image::name, next, rc, strerror(), and image::type.

Referenced by asn1_okx(), image_x509(), and imgverify().

                                               {
        int next;
        int rc;

        /* Sanity check */
        assert ( offset <= image->len );

        /* Check that this image can be used to extract an ASN.1 object */
        if ( ! ( image->type && image->type->asn1 ) )
                return -ENOTSUP;

        /* Try creating ASN.1 cursor */
        next = image->type->asn1 ( image, offset, cursor );
        if ( next < 0 ) {
                rc = next;
                DBGC ( image, "IMAGE %s could not extract ASN.1 object: %s\n",
                       image->name, strerror ( rc ) );
                return rc;
        }

        return next;
}
REQUIRE_OBJECT ( config_asn1  )