iPXE
asn1.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdint.h>
00027 #include <stddef.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <ctype.h>
00031 #include <errno.h>
00032 #include <time.h>
00033 #include <ipxe/tables.h>
00034 #include <ipxe/image.h>
00035 #include <ipxe/asn1.h>
00036 
00037 /** @file
00038  *
00039  * ASN.1 encoding
00040  *
00041  */
00042 
00043 /* Disambiguate the various error causes */
00044 #define EINVAL_ASN1_EMPTY \
00045         __einfo_error ( EINFO_EINVAL_ASN1_EMPTY )
00046 #define EINFO_EINVAL_ASN1_EMPTY \
00047         __einfo_uniqify ( EINFO_EINVAL, 0x01, "Empty or underlength cursor" )
00048 #define EINVAL_ASN1_LEN_LEN \
00049         __einfo_error ( EINFO_EINVAL_ASN1_LEN_LEN )
00050 #define EINFO_EINVAL_ASN1_LEN_LEN \
00051         __einfo_uniqify ( EINFO_EINVAL, 0x02, "Length field overruns cursor" )
00052 #define EINVAL_ASN1_LEN \
00053         __einfo_error ( EINFO_EINVAL_ASN1_LEN )
00054 #define EINFO_EINVAL_ASN1_LEN \
00055         __einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
00056 #define EINVAL_ASN1_BOOLEAN \
00057         __einfo_error ( EINFO_EINVAL_ASN1_BOOLEAN )
00058 #define EINFO_EINVAL_ASN1_BOOLEAN \
00059         __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid boolean" )
00060 #define EINVAL_ASN1_INTEGER \
00061         __einfo_error ( EINFO_EINVAL_ASN1_INTEGER )
00062 #define EINFO_EINVAL_ASN1_INTEGER \
00063         __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid integer" )
00064 #define EINVAL_ASN1_TIME \
00065         __einfo_error ( EINFO_EINVAL_ASN1_TIME )
00066 #define EINFO_EINVAL_ASN1_TIME \
00067         __einfo_uniqify ( EINFO_EINVAL, 0x05, "Invalid time" )
00068 #define EINVAL_ASN1_ALGORITHM \
00069         __einfo_error ( EINFO_EINVAL_ASN1_ALGORITHM )
00070 #define EINFO_EINVAL_ASN1_ALGORITHM \
00071         __einfo_uniqify ( EINFO_EINVAL, 0x06, "Invalid algorithm" )
00072 #define EINVAL_BIT_STRING \
00073         __einfo_error ( EINFO_EINVAL_BIT_STRING )
00074 #define EINFO_EINVAL_BIT_STRING \
00075         __einfo_uniqify ( EINFO_EINVAL, 0x07, "Invalid bit string" )
00076 #define ENOTSUP_ALGORITHM \
00077         __einfo_error ( EINFO_ENOTSUP_ALGORITHM )
00078 #define EINFO_ENOTSUP_ALGORITHM \
00079         __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported algorithm" )
00080 #define ENOTTY_ALGORITHM \
00081         __einfo_error ( EINFO_ENOTTY_ALGORITHM )
00082 #define EINFO_ENOTTY_ALGORITHM \
00083         __einfo_uniqify ( EINFO_ENOTTY, 0x01, "Inappropriate algorithm" )
00084 
00085 /**
00086  * Start parsing ASN.1 object
00087  *
00088  * @v cursor            ASN.1 object cursor
00089  * @v type              Expected type, or ASN1_ANY
00090  * @v extra             Additional length not present within partial cursor
00091  * @ret len             Length of object body, or negative error
00092  *
00093  * The object cursor will be updated to point to the start of the
00094  * object body (i.e. the first byte following the length byte(s)), and
00095  * the length of the object body (i.e. the number of bytes until the
00096  * following object tag, if any) is returned.
00097  */
00098 int asn1_start ( struct asn1_cursor *cursor, unsigned int type, size_t extra ) {
00099         unsigned int len_len;
00100         unsigned int len;
00101 
00102         /* Sanity check */
00103         if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
00104                 if ( cursor->len )
00105                         DBGC ( cursor, "ASN1 %p too short\n", cursor );
00106                 return -EINVAL_ASN1_EMPTY;
00107         }
00108 
00109         /* Check the tag byte */
00110         if ( ( type != ASN1_ANY ) && ( type != asn1_type ( cursor ) ) ) {
00111                 DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
00112                        cursor, type, *( ( uint8_t * ) cursor->data ) );
00113                 return -ENXIO;
00114         }
00115         cursor->data++;
00116         cursor->len--;
00117 
00118         /* Extract length of the length field and sanity check */
00119         len_len = *( ( uint8_t * ) cursor->data );
00120         if ( len_len & 0x80 ) {
00121                 len_len = ( len_len & 0x7f );
00122                 cursor->data++;
00123                 cursor->len--;
00124         } else {
00125                 len_len = 1;
00126         }
00127         if ( cursor->len < len_len ) {
00128                 DBGC ( cursor, "ASN1 %p bad length field length %d (max "
00129                        "%zd)\n", cursor, len_len, cursor->len );
00130                 return -EINVAL_ASN1_LEN_LEN;
00131         }
00132 
00133         /* Extract the length and sanity check */
00134         for ( len = 0 ; len_len ; len_len-- ) {
00135                 len <<= 8;
00136                 len |= *( ( uint8_t * ) cursor->data );
00137                 cursor->data++;
00138                 cursor->len--;
00139         }
00140         if ( ( cursor->len + extra ) < len ) {
00141                 DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
00142                        cursor, len, ( cursor->len + extra ) );
00143                 return -EINVAL_ASN1_LEN;
00144         }
00145 
00146         return len;
00147 }
00148 
00149 /**
00150  * Enter ASN.1 object
00151  *
00152  * @v cursor            ASN.1 object cursor
00153  * @v type              Expected type, or ASN1_ANY
00154  * @ret rc              Return status code
00155  *
00156  * The object cursor will be updated to point to the body of the
00157  * current ASN.1 object.  If any error occurs, the object cursor will
00158  * be invalidated.
00159  */
00160 int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
00161         int len;
00162 
00163         len = asn1_start ( cursor, type, 0 );
00164         if ( len < 0 ) {
00165                 asn1_invalidate_cursor ( cursor );
00166                 return len;
00167         }
00168 
00169         cursor->len = len;
00170         DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
00171                cursor, type, len );
00172 
00173         return 0;
00174 }
00175 
00176 /**
00177  * Skip ASN.1 object if present
00178  *
00179  * @v cursor            ASN.1 object cursor
00180  * @v type              Expected type, or ASN1_ANY
00181  * @ret rc              Return status code
00182  *
00183  * The object cursor will be updated to point to the next ASN.1
00184  * object.  If any error occurs, the object cursor will not be
00185  * modified.
00186  */
00187 int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
00188         int len;
00189 
00190         len = asn1_start ( cursor, type, 0 );
00191         if ( len < 0 )
00192                 return len;
00193 
00194         cursor->data += len;
00195         cursor->len -= len;
00196         DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n",
00197                cursor, type, len );
00198 
00199         if ( ! cursor->len ) {
00200                 DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
00201                 return -ENOENT;
00202         }
00203 
00204         return 0;
00205 }
00206 
00207 /**
00208  * Skip ASN.1 object
00209  *
00210  * @v cursor            ASN.1 object cursor
00211  * @v type              Expected type, or ASN1_ANY
00212  * @ret rc              Return status code
00213  *
00214  * The object cursor will be updated to point to the next ASN.1
00215  * object.  If any error occurs, the object cursor will be
00216  * invalidated.
00217  */
00218 int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
00219         int rc;
00220 
00221         if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) != 0 ) {
00222                 asn1_invalidate_cursor ( cursor );
00223                 return rc;
00224         }
00225 
00226         return 0;
00227 }
00228 
00229 /**
00230  * Shrink ASN.1 cursor to fit object
00231  *
00232  * @v cursor            ASN.1 object cursor
00233  * @v type              Expected type, or ASN1_ANY
00234  * @ret rc              Return status code
00235  *
00236  * The object cursor will be shrunk to contain only the current ASN.1
00237  * object.  If any error occurs, the object cursor will be
00238  * invalidated.
00239  */
00240 int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ) {
00241         struct asn1_cursor temp;
00242         const void *end;
00243         int len;
00244 
00245         /* Find end of object */
00246         memcpy ( &temp, cursor, sizeof ( temp ) );
00247         len = asn1_start ( &temp, type, 0 );
00248         if ( len < 0 ) {
00249                 asn1_invalidate_cursor ( cursor );
00250                 return len;
00251         }
00252         end = ( temp.data + len );
00253 
00254         /* Shrink original cursor to contain only its first object */
00255         cursor->len = ( end - cursor->data );
00256 
00257         return 0;
00258 }
00259 
00260 /**
00261  * Enter ASN.1 object of any type
00262  *
00263  * @v cursor            ASN.1 object cursor
00264  * @ret rc              Return status code
00265  */
00266 int asn1_enter_any ( struct asn1_cursor *cursor ) {
00267         return asn1_enter ( cursor, ASN1_ANY );
00268 }
00269 
00270 /**
00271  * Skip ASN.1 object of any type
00272  *
00273  * @v cursor            ASN.1 object cursor
00274  * @ret rc              Return status code
00275  */
00276 int asn1_skip_any ( struct asn1_cursor *cursor ) {
00277         return asn1_skip ( cursor, ASN1_ANY );
00278 }
00279 
00280 /**
00281  * Shrink ASN.1 object of any type
00282  *
00283  * @v cursor            ASN.1 object cursor
00284  * @ret rc              Return status code
00285  */
00286 int asn1_shrink_any ( struct asn1_cursor *cursor ) {
00287         return asn1_shrink ( cursor, ASN1_ANY );
00288 }
00289 
00290 /**
00291  * Parse value of ASN.1 boolean
00292  *
00293  * @v cursor            ASN.1 object cursor
00294  * @ret value           Value, or negative error
00295  */
00296 int asn1_boolean ( const struct asn1_cursor *cursor ) {
00297         struct asn1_cursor contents;
00298         const struct {
00299                 uint8_t value;
00300         } __attribute__ (( packed )) *boolean;
00301 
00302         /* Enter boolean */
00303         memcpy ( &contents, cursor, sizeof ( contents ) );
00304         asn1_enter ( &contents, ASN1_BOOLEAN );
00305         if ( contents.len != sizeof ( *boolean ) )
00306                 return -EINVAL_ASN1_BOOLEAN;
00307 
00308         /* Extract value */
00309         boolean = contents.data;
00310         return boolean->value;
00311 }
00312 
00313 /**
00314  * Parse value of ASN.1 integer
00315  *
00316  * @v cursor            ASN.1 object cursor
00317  * @v value             Value to fill in
00318  * @ret rc              Return status code
00319  */
00320 int asn1_integer ( const struct asn1_cursor *cursor, int *value ) {
00321         struct asn1_cursor contents;
00322         uint8_t high_byte;
00323         int rc;
00324 
00325         /* Enter integer */
00326         memcpy ( &contents, cursor, sizeof ( contents ) );
00327         if ( ( rc = asn1_enter ( &contents, ASN1_INTEGER ) ) != 0 )
00328                 return rc;
00329         if ( contents.len < 1 )
00330                 return -EINVAL_ASN1_INTEGER;
00331 
00332         /* Initialise value according to sign byte */
00333         *value = *( ( int8_t * ) contents.data );
00334         contents.data++;
00335         contents.len--;
00336 
00337         /* Process value */
00338         while ( contents.len ) {
00339                 high_byte = ( (*value) >> ( 8 * ( sizeof ( *value ) - 1 ) ) );
00340                 if ( ( high_byte != 0x00 ) && ( high_byte != 0xff ) ) {
00341                         DBGC ( cursor, "ASN1 %p integer overflow\n", cursor );
00342                         return -EINVAL_ASN1_INTEGER;
00343                 }
00344                 *value = ( ( *value << 8 ) | *( ( uint8_t * ) contents.data ) );
00345                 contents.data++;
00346                 contents.len--;
00347         }
00348 
00349         return 0;
00350 }
00351 
00352 /**
00353  * Parse ASN.1 bit string
00354  *
00355  * @v cursor            ASN.1 cursor
00356  * @v bits              Bit string to fill in
00357  * @ret rc              Return status code
00358  */
00359 int asn1_bit_string ( const struct asn1_cursor *cursor,
00360                       struct asn1_bit_string *bits ) {
00361         struct asn1_cursor contents;
00362         const struct {
00363                 uint8_t unused;
00364                 uint8_t data[0];
00365         } __attribute__ (( packed )) *bit_string;
00366         size_t len;
00367         unsigned int unused;
00368         uint8_t unused_mask;
00369         const uint8_t *last;
00370         int rc;
00371 
00372         /* Enter bit string */
00373         memcpy ( &contents, cursor, sizeof ( contents ) );
00374         if ( ( rc = asn1_enter ( &contents, ASN1_BIT_STRING ) ) != 0 ) {
00375                 DBGC ( cursor, "ASN1 %p cannot locate bit string:\n", cursor );
00376                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00377                 return rc;
00378         }
00379 
00380         /* Validity checks */
00381         if ( contents.len < sizeof ( *bit_string ) ) {
00382                 DBGC ( cursor, "ASN1 %p invalid bit string:\n", cursor );
00383                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00384                 return -EINVAL_BIT_STRING;
00385         }
00386         bit_string = contents.data;
00387         len = ( contents.len - offsetof ( typeof ( *bit_string ), data ) );
00388         unused = bit_string->unused;
00389         unused_mask = ( 0xff >> ( 8 - unused ) );
00390         last = ( bit_string->data + len - 1 );
00391         if ( ( unused >= 8 ) ||
00392              ( ( unused > 0 ) && ( len == 0 ) ) ||
00393              ( ( *last & unused_mask ) != 0 ) ) {
00394                 DBGC ( cursor, "ASN1 %p invalid bit string:\n", cursor );
00395                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00396                 return -EINVAL_BIT_STRING;
00397         }
00398 
00399         /* Populate bit string */
00400         bits->data = &bit_string->data;
00401         bits->len = len;
00402         bits->unused = unused;
00403 
00404         return 0;
00405 }
00406 
00407 /**
00408  * Parse ASN.1 bit string that must be an integral number of bytes
00409  *
00410  * @v cursor            ASN.1 cursor
00411  * @v bits              Bit string to fill in
00412  * @ret rc              Return status code
00413  */
00414 int asn1_integral_bit_string ( const struct asn1_cursor *cursor,
00415                                struct asn1_bit_string *bits ) {
00416         int rc;
00417 
00418         /* Parse bit string */
00419         if ( ( rc = asn1_bit_string ( cursor, bits ) ) != 0 )
00420                 return rc;
00421 
00422         /* Check that there are no unused bits at end of string */
00423         if ( bits->unused ) {
00424                 DBGC ( cursor, "ASN1 %p invalid integral bit string:\n",
00425                        cursor );
00426                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00427                 return -EINVAL_BIT_STRING;
00428         }
00429 
00430         return 0;
00431 }
00432 
00433 /**
00434  * Compare two ASN.1 objects
00435  *
00436  * @v cursor1           ASN.1 object cursor
00437  * @v cursor2           ASN.1 object cursor
00438  * @ret difference      Difference as returned by memcmp()
00439  *
00440  * Note that invalid and empty cursors will compare as equal with each
00441  * other.
00442  */
00443 int asn1_compare ( const struct asn1_cursor *cursor1,
00444                    const struct asn1_cursor *cursor2 ) {
00445         int difference;
00446 
00447         difference = ( cursor2->len - cursor1->len );
00448         return ( difference ? difference :
00449                  memcmp ( cursor1->data, cursor2->data, cursor1->len ) );
00450 }
00451 
00452 /**
00453  * Identify ASN.1 algorithm by OID
00454  *
00455  * @v cursor            ASN.1 object cursor
00456 
00457  * @ret algorithm       Algorithm, or NULL
00458  */
00459 static struct asn1_algorithm *
00460 asn1_find_algorithm ( const struct asn1_cursor *cursor ) {
00461         struct asn1_algorithm *algorithm;
00462 
00463         for_each_table_entry ( algorithm, ASN1_ALGORITHMS ) {
00464                 if ( asn1_compare ( &algorithm->oid, cursor ) == 0 )
00465                         return algorithm;
00466         }
00467 
00468         return NULL;
00469 }
00470 
00471 /**
00472  * Parse ASN.1 OID-identified algorithm
00473  *
00474  * @v cursor            ASN.1 object cursor
00475  * @ret algorithm       Algorithm
00476  * @ret rc              Return status code
00477  */
00478 int asn1_algorithm ( const struct asn1_cursor *cursor,
00479                      struct asn1_algorithm **algorithm ) {
00480         struct asn1_cursor contents;
00481         int rc;
00482 
00483         /* Enter signatureAlgorithm */
00484         memcpy ( &contents, cursor, sizeof ( contents ) );
00485         asn1_enter ( &contents, ASN1_SEQUENCE );
00486 
00487         /* Enter algorithm */
00488         if ( ( rc = asn1_enter ( &contents, ASN1_OID ) ) != 0 ) {
00489                 DBGC ( cursor, "ASN1 %p cannot locate algorithm OID:\n",
00490                        cursor );
00491                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00492                 return -EINVAL_ASN1_ALGORITHM;
00493         }
00494 
00495         /* Identify algorithm */
00496         *algorithm = asn1_find_algorithm ( &contents );
00497         if ( ! *algorithm ) {
00498                 DBGC ( cursor, "ASN1 %p unrecognised algorithm:\n", cursor );
00499                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00500                 return -ENOTSUP_ALGORITHM;
00501         }
00502 
00503         return 0;
00504 }
00505 
00506 /**
00507  * Parse ASN.1 OID-identified public-key algorithm
00508  *
00509  * @v cursor            ASN.1 object cursor
00510  * @ret algorithm       Algorithm
00511  * @ret rc              Return status code
00512  */
00513 int asn1_pubkey_algorithm ( const struct asn1_cursor *cursor,
00514                             struct asn1_algorithm **algorithm ) {
00515         int rc;
00516 
00517         /* Parse algorithm */
00518         if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
00519                 return rc;
00520 
00521         /* Check algorithm has a public key */
00522         if ( ! (*algorithm)->pubkey ) {
00523                 DBGC ( cursor, "ASN1 %p algorithm %s is not a public-key "
00524                        "algorithm:\n", cursor, (*algorithm)->name );
00525                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00526                 return -ENOTTY_ALGORITHM;
00527         }
00528 
00529         return 0;
00530 }
00531 
00532 /**
00533  * Parse ASN.1 OID-identified digest algorithm
00534  *
00535  * @v cursor            ASN.1 object cursor
00536  * @ret algorithm       Algorithm
00537  * @ret rc              Return status code
00538  */
00539 int asn1_digest_algorithm ( const struct asn1_cursor *cursor,
00540                             struct asn1_algorithm **algorithm ) {
00541         int rc;
00542 
00543         /* Parse algorithm */
00544         if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
00545                 return rc;
00546 
00547         /* Check algorithm has a digest */
00548         if ( ! (*algorithm)->digest ) {
00549                 DBGC ( cursor, "ASN1 %p algorithm %s is not a digest "
00550                        "algorithm:\n", cursor, (*algorithm)->name );
00551                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00552                 return -ENOTTY_ALGORITHM;
00553         }
00554 
00555         return 0;
00556 }
00557 
00558 /**
00559  * Parse ASN.1 OID-identified signature algorithm
00560  *
00561  * @v cursor            ASN.1 object cursor
00562  * @ret algorithm       Algorithm
00563  * @ret rc              Return status code
00564  */
00565 int asn1_signature_algorithm ( const struct asn1_cursor *cursor,
00566                                struct asn1_algorithm **algorithm ) {
00567         int rc;
00568 
00569         /* Parse algorithm */
00570         if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
00571                 return rc;
00572 
00573         /* Check algorithm has a public key */
00574         if ( ! (*algorithm)->pubkey ) {
00575                 DBGC ( cursor, "ASN1 %p algorithm %s is not a signature "
00576                        "algorithm:\n", cursor, (*algorithm)->name );
00577                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00578                 return -ENOTTY_ALGORITHM;
00579         }
00580 
00581         /* Check algorithm has a digest */
00582         if ( ! (*algorithm)->digest ) {
00583                 DBGC ( cursor, "ASN1 %p algorithm %s is not a signature "
00584                        "algorithm:\n", cursor, (*algorithm)->name );
00585                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00586                 return -ENOTTY_ALGORITHM;
00587         }
00588 
00589         return 0;
00590 }
00591 
00592 /**
00593  * Parse ASN.1 GeneralizedTime
00594  *
00595  * @v cursor            ASN.1 cursor
00596  * @v time              Time to fill in
00597  * @ret rc              Return status code
00598  *
00599  * RFC 5280 section 4.1.2.5 places several restrictions on the allowed
00600  * formats for UTCTime and GeneralizedTime, and mandates the
00601  * interpretation of centuryless year values.
00602  */
00603 int asn1_generalized_time ( const struct asn1_cursor *cursor, time_t *time ) {
00604         struct asn1_cursor contents;
00605         unsigned int have_century;
00606         unsigned int type;
00607         union {
00608                 struct {
00609                         uint8_t century;
00610                         uint8_t year;
00611                         uint8_t month;
00612                         uint8_t day;
00613                         uint8_t hour;
00614                         uint8_t minute;
00615                         uint8_t second;
00616                 } __attribute__ (( packed )) named;
00617                 uint8_t raw[7];
00618         } pairs;
00619         struct tm tm;
00620         const uint8_t *data;
00621         size_t remaining;
00622         unsigned int tens;
00623         unsigned int units;
00624         unsigned int i;
00625         int rc;
00626 
00627         /* Determine time format utcTime/generalizedTime */
00628         memcpy ( &contents, cursor, sizeof ( contents ) );
00629         type = asn1_type ( &contents );
00630         switch ( type ) {
00631         case ASN1_UTC_TIME:
00632                 have_century = 0;
00633                 break;
00634         case ASN1_GENERALIZED_TIME:
00635                 have_century = 1;
00636                 break;
00637         default:
00638                 DBGC ( cursor, "ASN1 %p invalid time type %02x\n",
00639                        cursor, type );
00640                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00641                 return -EINVAL_ASN1_TIME;
00642         }
00643 
00644         /* Enter utcTime/generalizedTime */
00645         if ( ( rc = asn1_enter ( &contents, type ) ) != 0 ) {
00646                 DBGC ( cursor, "ASN1 %p cannot locate %s time:\n", cursor,
00647                        ( ( type == ASN1_UTC_TIME ) ? "UTC" : "generalized" ) );
00648                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00649                 return rc;
00650         }
00651 
00652         /* Parse digit string a pair at a time */
00653         memset ( &pairs, 0, sizeof ( pairs ) );
00654         data = contents.data;
00655         remaining = contents.len;
00656         for ( i = ( have_century ? 0 : 1 ) ; i < sizeof ( pairs.raw ) ; i++ ) {
00657                 if ( remaining < 2 ) {
00658                         /* Some certificates violate the X.509 RFC by
00659                          * omitting the "seconds" value.
00660                          */
00661                         if ( i == ( sizeof ( pairs.raw ) - 1 ) )
00662                                 break;
00663                         DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
00664                         DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00665                         return -EINVAL_ASN1_TIME;
00666                 }
00667                 tens = data[0];
00668                 units = data[1];
00669                 if ( ! ( isdigit ( tens ) && isdigit ( units ) ) ) {
00670                         DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
00671                         DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00672                         return -EINVAL_ASN1_TIME;
00673                 }
00674                 pairs.raw[i] = ( ( 10 * ( tens - '0' ) ) + ( units - '0' ) );
00675                 data += 2;
00676                 remaining -= 2;
00677         }
00678 
00679         /* Determine century if applicable */
00680         if ( ! have_century )
00681                 pairs.named.century = ( ( pairs.named.year >= 50 ) ? 19 : 20 );
00682 
00683         /* Check for trailing "Z" */
00684         if ( ( remaining != 1 ) || ( data[0] != 'Z' ) ) {
00685                 DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
00686                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
00687                 return -EINVAL_ASN1_TIME;
00688         }
00689 
00690         /* Fill in time */
00691         tm.tm_year = ( ( ( pairs.named.century - 19 ) * 100 ) +
00692                        pairs.named.year );
00693         tm.tm_mon = ( pairs.named.month - 1 );
00694         tm.tm_mday = pairs.named.day;
00695         tm.tm_hour = pairs.named.hour;
00696         tm.tm_min = pairs.named.minute;
00697         tm.tm_sec = pairs.named.second;
00698 
00699         /* Convert to seconds since the Epoch */
00700         *time = mktime ( &tm );
00701 
00702         return 0;
00703 }
00704 
00705 /**
00706  * Construct ASN.1 header
00707  *
00708  * @v header            ASN.1 builder header
00709  * @v type              Type
00710  * @v len               Content length
00711  * @ret header_len      Header length
00712  */
00713 static size_t asn1_header ( struct asn1_builder_header *header,
00714                             unsigned int type, size_t len ) {
00715         unsigned int header_len = 2;
00716         unsigned int len_len = 0;
00717         size_t temp;
00718 
00719         /* Construct header */
00720         header->type = type;
00721         if ( len < 0x80 ) {
00722                 header->length[0] = len;
00723         } else {
00724                 for ( temp = len ; temp ; temp >>= 8 )
00725                         len_len++;
00726                 header->length[0] = ( 0x80 | len_len );
00727                 header_len += len_len;
00728                 for ( temp = len ; temp ; temp >>= 8 )
00729                         header->length[len_len--] = ( temp & 0xff );
00730         }
00731 
00732         return header_len;
00733 }
00734 
00735 /**
00736  * Grow ASN.1 builder
00737  *
00738  * @v builder           ASN.1 builder
00739  * @v extra             Extra space to prepend
00740  * @ret rc              Return status code
00741  */
00742 int asn1_grow ( struct asn1_builder *builder, size_t extra ) {
00743         size_t new_len;
00744         void *new;
00745 
00746         /* As with the ASN1 parsing functions, make errors permanent */
00747         if ( builder->len && ! builder->data )
00748                 return -ENOMEM;
00749 
00750         /* Reallocate data buffer */
00751         new_len = ( builder->len + extra );
00752         new = realloc ( builder->data, new_len );
00753         if ( ! new ) {
00754                 free ( builder->data );
00755                 builder->data = NULL;
00756                 return -ENOMEM;
00757         }
00758         builder->data = new;
00759 
00760         /* Move existing data to end of buffer */
00761         memmove ( ( builder->data + extra ), builder->data, builder->len );
00762         builder->len = new_len;
00763 
00764         return 0;
00765 }
00766 
00767 /**
00768  * Prepend raw data to ASN.1 builder
00769  *
00770  * @v builder           ASN.1 builder
00771  * @v data              Data to prepend
00772  * @v len               Length of data to prepend
00773  * @ret rc              Return status code
00774  */
00775 int asn1_prepend_raw ( struct asn1_builder *builder, const void *data,
00776                        size_t len ) {
00777         int rc;
00778 
00779         /* Grow buffer */
00780         if ( ( rc = asn1_grow ( builder, len ) ) != 0 )
00781                 return rc;
00782 
00783         /* Populate data buffer */
00784         memcpy ( builder->data, data, len );
00785 
00786         return 0;
00787 }
00788 
00789 /**
00790  * Prepend data to ASN.1 builder
00791  *
00792  * @v builder           ASN.1 builder
00793  * @v type              Type
00794  * @v data              Data to prepend
00795  * @v len               Length of data to prepend
00796  * @ret rc              Return status code
00797  */
00798 int asn1_prepend ( struct asn1_builder *builder, unsigned int type,
00799                    const void *data, size_t len ) {
00800         struct asn1_builder_header header;
00801         size_t header_len;
00802         int rc;
00803 
00804         /* Construct header */
00805         header_len = asn1_header ( &header, type, len );
00806 
00807         /* Grow buffer */
00808         if ( ( rc = asn1_grow ( builder, header_len + len ) ) != 0 )
00809                 return rc;
00810 
00811         /* Populate data buffer */
00812         memcpy ( builder->data, &header, header_len );
00813         memcpy ( ( builder->data + header_len ), data, len );
00814 
00815         return 0;
00816 }
00817 
00818 /**
00819  * Wrap ASN.1 builder
00820  *
00821  * @v builder           ASN.1 builder
00822  * @v type              Type
00823  * @ret rc              Return status code
00824  */
00825 int asn1_wrap ( struct asn1_builder *builder, unsigned int type ) {
00826         struct asn1_builder_header header;
00827         size_t header_len;
00828         int rc;
00829 
00830         /* Construct header */
00831         header_len = asn1_header ( &header, type, builder->len );
00832 
00833         /* Grow buffer */
00834         if ( ( rc = asn1_grow ( builder, header_len ) ) != 0 )
00835                 return rc;
00836 
00837         /* Populate data buffer */
00838         memcpy ( builder->data, &header, header_len );
00839 
00840         return 0;
00841 }
00842 
00843 /**
00844  * Extract ASN.1 object from image
00845  *
00846  * @v image             Image
00847  * @v offset            Offset within image
00848  * @v cursor            ASN.1 cursor to fill in
00849  * @ret next            Offset to next image, or negative error
00850  *
00851  * The caller is responsible for eventually calling free() on the
00852  * allocated ASN.1 cursor.
00853  */
00854 int image_asn1 ( struct image *image, size_t offset,
00855                  struct asn1_cursor **cursor ) {
00856         int next;
00857         int rc;
00858 
00859         /* Sanity check */
00860         assert ( offset <= image->len );
00861 
00862         /* Check that this image can be used to extract an ASN.1 object */
00863         if ( ! ( image->type && image->type->asn1 ) )
00864                 return -ENOTSUP;
00865 
00866         /* Try creating ASN.1 cursor */
00867         next = image->type->asn1 ( image, offset, cursor );
00868         if ( next < 0 ) {
00869                 rc = next;
00870                 DBGC ( image, "IMAGE %s could not extract ASN.1 object: %s\n",
00871                        image->name, strerror ( rc ) );
00872                 return rc;
00873         }
00874 
00875         return next;
00876 }
00877 
00878 /* Drag in objects via image_asn1() */
00879 REQUIRING_SYMBOL ( image_asn1 );
00880 
00881 /* Drag in ASN.1 image formats */
00882 REQUIRE_OBJECT ( config_asn1 );