iPXE - Open Source Boot Firmware

[peerdist] Allow PeerDist to be globally enabled or disabled
[ipxe.git] / src / crypto / asn1.c
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #include <stdint.h>
27 #include <stddef.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <time.h>
33 #include <ipxe/tables.h>
34 #include <ipxe/image.h>
35 #include <ipxe/asn1.h>
36
37 /** @file
38  *
39  * ASN.1 encoding
40  *
41  */
42
43 /* Disambiguate the various error causes */
44 #define EINVAL_ASN1_EMPTY \
45         __einfo_error ( EINFO_EINVAL_ASN1_EMPTY )
46 #define EINFO_EINVAL_ASN1_EMPTY \
47         __einfo_uniqify ( EINFO_EINVAL, 0x01, "Empty or underlength cursor" )
48 #define EINVAL_ASN1_LEN_LEN \
49         __einfo_error ( EINFO_EINVAL_ASN1_LEN_LEN )
50 #define EINFO_EINVAL_ASN1_LEN_LEN \
51         __einfo_uniqify ( EINFO_EINVAL, 0x02, "Length field overruns cursor" )
52 #define EINVAL_ASN1_LEN \
53         __einfo_error ( EINFO_EINVAL_ASN1_LEN )
54 #define EINFO_EINVAL_ASN1_LEN \
55         __einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
56 #define EINVAL_ASN1_BOOLEAN \
57         __einfo_error ( EINFO_EINVAL_ASN1_BOOLEAN )
58 #define EINFO_EINVAL_ASN1_BOOLEAN \
59         __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid boolean" )
60 #define EINVAL_ASN1_INTEGER \
61         __einfo_error ( EINFO_EINVAL_ASN1_INTEGER )
62 #define EINFO_EINVAL_ASN1_INTEGER \
63         __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid integer" )
64 #define EINVAL_ASN1_TIME \
65         __einfo_error ( EINFO_EINVAL_ASN1_TIME )
66 #define EINFO_EINVAL_ASN1_TIME \
67         __einfo_uniqify ( EINFO_EINVAL, 0x05, "Invalid time" )
68 #define EINVAL_ASN1_ALGORITHM \
69         __einfo_error ( EINFO_EINVAL_ASN1_ALGORITHM )
70 #define EINFO_EINVAL_ASN1_ALGORITHM \
71         __einfo_uniqify ( EINFO_EINVAL, 0x06, "Invalid algorithm" )
72 #define EINVAL_BIT_STRING \
73         __einfo_error ( EINFO_EINVAL_BIT_STRING )
74 #define EINFO_EINVAL_BIT_STRING \
75         __einfo_uniqify ( EINFO_EINVAL, 0x07, "Invalid bit string" )
76 #define ENOTSUP_ALGORITHM \
77         __einfo_error ( EINFO_ENOTSUP_ALGORITHM )
78 #define EINFO_ENOTSUP_ALGORITHM \
79         __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported algorithm" )
80 #define ENOTTY_ALGORITHM \
81         __einfo_error ( EINFO_ENOTTY_ALGORITHM )
82 #define EINFO_ENOTTY_ALGORITHM \
83         __einfo_uniqify ( EINFO_ENOTTY, 0x01, "Inappropriate algorithm" )
84
85 /**
86  * Start parsing ASN.1 object
87  *
88  * @v cursor            ASN.1 object cursor
89  * @v type              Expected type, or ASN1_ANY
90  * @v extra             Additional length not present within partial cursor
91  * @ret len             Length of object body, or negative error
92  *
93  * The object cursor will be updated to point to the start of the
94  * object body (i.e. the first byte following the length byte(s)), and
95  * the length of the object body (i.e. the number of bytes until the
96  * following object tag, if any) is returned.
97  */
98 int asn1_start ( struct asn1_cursor *cursor, unsigned int type, size_t extra ) {
99         unsigned int len_len;
100         unsigned int len;
101
102         /* Sanity check */
103         if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
104                 if ( cursor->len )
105                         DBGC ( cursor, "ASN1 %p too short\n", cursor );
106                 return -EINVAL_ASN1_EMPTY;
107         }
108
109         /* Check the tag byte */
110         if ( ( type != ASN1_ANY ) && ( type != asn1_type ( cursor ) ) ) {
111                 DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
112                        cursor, type, *( ( uint8_t * ) cursor->data ) );
113                 return -ENXIO;
114         }
115         cursor->data++;
116         cursor->len--;
117
118         /* Extract length of the length field and sanity check */
119         len_len = *( ( uint8_t * ) cursor->data );
120         if ( len_len & 0x80 ) {
121                 len_len = ( len_len & 0x7f );
122                 cursor->data++;
123                 cursor->len--;
124         } else {
125                 len_len = 1;
126         }
127         if ( cursor->len < len_len ) {
128                 DBGC ( cursor, "ASN1 %p bad length field length %d (max "
129                        "%zd)\n", cursor, len_len, cursor->len );
130                 return -EINVAL_ASN1_LEN_LEN;
131         }
132
133         /* Extract the length and sanity check */
134         for ( len = 0 ; len_len ; len_len-- ) {
135                 len <<= 8;
136                 len |= *( ( uint8_t * ) cursor->data );
137                 cursor->data++;
138                 cursor->len--;
139         }
140         if ( ( cursor->len + extra ) < len ) {
141                 DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
142                        cursor, len, ( cursor->len + extra ) );
143                 return -EINVAL_ASN1_LEN;
144         }
145
146         return len;
147 }
148
149 /**
150  * Enter ASN.1 object
151  *
152  * @v cursor            ASN.1 object cursor
153  * @v type              Expected type, or ASN1_ANY
154  * @ret rc              Return status code
155  *
156  * The object cursor will be updated to point to the body of the
157  * current ASN.1 object.  If any error occurs, the object cursor will
158  * be invalidated.
159  */
160 int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
161         int len;
162
163         len = asn1_start ( cursor, type, 0 );
164         if ( len < 0 ) {
165                 asn1_invalidate_cursor ( cursor );
166                 return len;
167         }
168
169         cursor->len = len;
170         DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
171                cursor, type, len );
172
173         return 0;
174 }
175
176 /**
177  * Skip ASN.1 object if present
178  *
179  * @v cursor            ASN.1 object cursor
180  * @v type              Expected type, or ASN1_ANY
181  * @ret rc              Return status code
182  *
183  * The object cursor will be updated to point to the next ASN.1
184  * object.  If any error occurs, the object cursor will not be
185  * modified.
186  */
187 int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
188         int len;
189
190         len = asn1_start ( cursor, type, 0 );
191         if ( len < 0 )
192                 return len;
193
194         cursor->data += len;
195         cursor->len -= len;
196         DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n",
197                cursor, type, len );
198
199         if ( ! cursor->len ) {
200                 DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
201                 return -ENOENT;
202         }
203
204         return 0;
205 }
206
207 /**
208  * Skip ASN.1 object
209  *
210  * @v cursor            ASN.1 object cursor
211  * @v type              Expected type, or ASN1_ANY
212  * @ret rc              Return status code
213  *
214  * The object cursor will be updated to point to the next ASN.1
215  * object.  If any error occurs, the object cursor will be
216  * invalidated.
217  */
218 int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
219         int rc;
220
221         if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) != 0 ) {
222                 asn1_invalidate_cursor ( cursor );
223                 return rc;
224         }
225
226         return 0;
227 }
228
229 /**
230  * Shrink ASN.1 cursor to fit object
231  *
232  * @v cursor            ASN.1 object cursor
233  * @v type              Expected type, or ASN1_ANY
234  * @ret rc              Return status code
235  *
236  * The object cursor will be shrunk to contain only the current ASN.1
237  * object.  If any error occurs, the object cursor will be
238  * invalidated.
239  */
240 int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ) {
241         struct asn1_cursor temp;
242         const void *end;
243         int len;
244
245         /* Find end of object */
246         memcpy ( &temp, cursor, sizeof ( temp ) );
247         len = asn1_start ( &temp, type, 0 );
248         if ( len < 0 ) {
249                 asn1_invalidate_cursor ( cursor );
250                 return len;
251         }
252         end = ( temp.data + len );
253
254         /* Shrink original cursor to contain only its first object */
255         cursor->len = ( end - cursor->data );
256
257         return 0;
258 }
259
260 /**
261  * Enter ASN.1 object of any type
262  *
263  * @v cursor            ASN.1 object cursor
264  * @ret rc              Return status code
265  */
266 int asn1_enter_any ( struct asn1_cursor *cursor ) {
267         return asn1_enter ( cursor, ASN1_ANY );
268 }
269
270 /**
271  * Skip ASN.1 object of any type
272  *
273  * @v cursor            ASN.1 object cursor
274  * @ret rc              Return status code
275  */
276 int asn1_skip_any ( struct asn1_cursor *cursor ) {
277         return asn1_skip ( cursor, ASN1_ANY );
278 }
279
280 /**
281  * Shrink ASN.1 object of any type
282  *
283  * @v cursor            ASN.1 object cursor
284  * @ret rc              Return status code
285  */
286 int asn1_shrink_any ( struct asn1_cursor *cursor ) {
287         return asn1_shrink ( cursor, ASN1_ANY );
288 }
289
290 /**
291  * Parse value of ASN.1 boolean
292  *
293  * @v cursor            ASN.1 object cursor
294  * @ret value           Value, or negative error
295  */
296 int asn1_boolean ( const struct asn1_cursor *cursor ) {
297         struct asn1_cursor contents;
298         const struct {
299                 uint8_t value;
300         } __attribute__ (( packed )) *boolean;
301
302         /* Enter boolean */
303         memcpy ( &contents, cursor, sizeof ( contents ) );
304         asn1_enter ( &contents, ASN1_BOOLEAN );
305         if ( contents.len != sizeof ( *boolean ) )
306                 return -EINVAL_ASN1_BOOLEAN;
307
308         /* Extract value */
309         boolean = contents.data;
310         return boolean->value;
311 }
312
313 /**
314  * Parse value of ASN.1 integer
315  *
316  * @v cursor            ASN.1 object cursor
317  * @v value             Value to fill in
318  * @ret rc              Return status code
319  */
320 int asn1_integer ( const struct asn1_cursor *cursor, int *value ) {
321         struct asn1_cursor contents;
322         uint8_t high_byte;
323         int rc;
324
325         /* Enter integer */
326         memcpy ( &contents, cursor, sizeof ( contents ) );
327         if ( ( rc = asn1_enter ( &contents, ASN1_INTEGER ) ) != 0 )
328                 return rc;
329         if ( contents.len < 1 )
330                 return -EINVAL_ASN1_INTEGER;
331
332         /* Initialise value according to sign byte */
333         *value = *( ( int8_t * ) contents.data );
334         contents.data++;
335         contents.len--;
336
337         /* Process value */
338         while ( contents.len ) {
339                 high_byte = ( (*value) >> ( 8 * ( sizeof ( *value ) - 1 ) ) );
340                 if ( ( high_byte != 0x00 ) && ( high_byte != 0xff ) ) {
341                         DBGC ( cursor, "ASN1 %p integer overflow\n", cursor );
342                         return -EINVAL_ASN1_INTEGER;
343                 }
344                 *value = ( ( *value << 8 ) | *( ( uint8_t * ) contents.data ) );
345                 contents.data++;
346                 contents.len--;
347         }
348
349         return 0;
350 }
351
352 /**
353  * Parse ASN.1 bit string
354  *
355  * @v cursor            ASN.1 cursor
356  * @v bits              Bit string to fill in
357  * @ret rc              Return status code
358  */
359 int asn1_bit_string ( const struct asn1_cursor *cursor,
360                       struct asn1_bit_string *bits ) {
361         struct asn1_cursor contents;
362         const struct {
363                 uint8_t unused;
364                 uint8_t data[0];
365         } __attribute__ (( packed )) *bit_string;
366         size_t len;
367         unsigned int unused;
368         uint8_t unused_mask;
369         const uint8_t *last;
370         int rc;
371
372         /* Enter bit string */
373         memcpy ( &contents, cursor, sizeof ( contents ) );
374         if ( ( rc = asn1_enter ( &contents, ASN1_BIT_STRING ) ) != 0 ) {
375                 DBGC ( cursor, "ASN1 %p cannot locate bit string:\n", cursor );
376                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
377                 return rc;
378         }
379
380         /* Validity checks */
381         if ( contents.len < sizeof ( *bit_string ) ) {
382                 DBGC ( cursor, "ASN1 %p invalid bit string:\n", cursor );
383                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
384                 return -EINVAL_BIT_STRING;
385         }
386         bit_string = contents.data;
387         len = ( contents.len - offsetof ( typeof ( *bit_string ), data ) );
388         unused = bit_string->unused;
389         unused_mask = ( 0xff >> ( 8 - unused ) );
390         last = ( bit_string->data + len - 1 );
391         if ( ( unused >= 8 ) ||
392              ( ( unused > 0 ) && ( len == 0 ) ) ||
393              ( ( *last & unused_mask ) != 0 ) ) {
394                 DBGC ( cursor, "ASN1 %p invalid bit string:\n", cursor );
395                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
396                 return -EINVAL_BIT_STRING;
397         }
398
399         /* Populate bit string */
400         bits->data = &bit_string->data;
401         bits->len = len;
402         bits->unused = unused;
403
404         return 0;
405 }
406
407 /**
408  * Parse ASN.1 bit string that must be an integral number of bytes
409  *
410  * @v cursor            ASN.1 cursor
411  * @v bits              Bit string to fill in
412  * @ret rc              Return status code
413  */
414 int asn1_integral_bit_string ( const struct asn1_cursor *cursor,
415                                struct asn1_bit_string *bits ) {
416         int rc;
417
418         /* Parse bit string */
419         if ( ( rc = asn1_bit_string ( cursor, bits ) ) != 0 )
420                 return rc;
421
422         /* Check that there are no unused bits at end of string */
423         if ( bits->unused ) {
424                 DBGC ( cursor, "ASN1 %p invalid integral bit string:\n",
425                        cursor );
426                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
427                 return -EINVAL_BIT_STRING;
428         }
429
430         return 0;
431 }
432
433 /**
434  * Compare two ASN.1 objects
435  *
436  * @v cursor1           ASN.1 object cursor
437  * @v cursor2           ASN.1 object cursor
438  * @ret difference      Difference as returned by memcmp()
439  *
440  * Note that invalid and empty cursors will compare as equal with each
441  * other.
442  */
443 int asn1_compare ( const struct asn1_cursor *cursor1,
444                    const struct asn1_cursor *cursor2 ) {
445         int difference;
446
447         difference = ( cursor2->len - cursor1->len );
448         return ( difference ? difference :
449                  memcmp ( cursor1->data, cursor2->data, cursor1->len ) );
450 }
451
452 /**
453  * Identify ASN.1 algorithm by OID
454  *
455  * @v cursor            ASN.1 object cursor
456
457  * @ret algorithm       Algorithm, or NULL
458  */
459 static struct asn1_algorithm *
460 asn1_find_algorithm ( const struct asn1_cursor *cursor ) {
461         struct asn1_algorithm *algorithm;
462
463         for_each_table_entry ( algorithm, ASN1_ALGORITHMS ) {
464                 if ( asn1_compare ( &algorithm->oid, cursor ) == 0 )
465                         return algorithm;
466         }
467
468         return NULL;
469 }
470
471 /**
472  * Parse ASN.1 OID-identified algorithm
473  *
474  * @v cursor            ASN.1 object cursor
475  * @ret algorithm       Algorithm
476  * @ret rc              Return status code
477  */
478 int asn1_algorithm ( const struct asn1_cursor *cursor,
479                      struct asn1_algorithm **algorithm ) {
480         struct asn1_cursor contents;
481         int rc;
482
483         /* Enter signatureAlgorithm */
484         memcpy ( &contents, cursor, sizeof ( contents ) );
485         asn1_enter ( &contents, ASN1_SEQUENCE );
486
487         /* Enter algorithm */
488         if ( ( rc = asn1_enter ( &contents, ASN1_OID ) ) != 0 ) {
489                 DBGC ( cursor, "ASN1 %p cannot locate algorithm OID:\n",
490                        cursor );
491                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
492                 return -EINVAL_ASN1_ALGORITHM;
493         }
494
495         /* Identify algorithm */
496         *algorithm = asn1_find_algorithm ( &contents );
497         if ( ! *algorithm ) {
498                 DBGC ( cursor, "ASN1 %p unrecognised algorithm:\n", cursor );
499                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
500                 return -ENOTSUP_ALGORITHM;
501         }
502
503         return 0;
504 }
505
506 /**
507  * Parse ASN.1 OID-identified public-key algorithm
508  *
509  * @v cursor            ASN.1 object cursor
510  * @ret algorithm       Algorithm
511  * @ret rc              Return status code
512  */
513 int asn1_pubkey_algorithm ( const struct asn1_cursor *cursor,
514                             struct asn1_algorithm **algorithm ) {
515         int rc;
516
517         /* Parse algorithm */
518         if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
519                 return rc;
520
521         /* Check algorithm has a public key */
522         if ( ! (*algorithm)->pubkey ) {
523                 DBGC ( cursor, "ASN1 %p algorithm %s is not a public-key "
524                        "algorithm:\n", cursor, (*algorithm)->name );
525                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
526                 return -ENOTTY_ALGORITHM;
527         }
528
529         return 0;
530 }
531
532 /**
533  * Parse ASN.1 OID-identified digest algorithm
534  *
535  * @v cursor            ASN.1 object cursor
536  * @ret algorithm       Algorithm
537  * @ret rc              Return status code
538  */
539 int asn1_digest_algorithm ( const struct asn1_cursor *cursor,
540                             struct asn1_algorithm **algorithm ) {
541         int rc;
542
543         /* Parse algorithm */
544         if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
545                 return rc;
546
547         /* Check algorithm has a digest */
548         if ( ! (*algorithm)->digest ) {
549                 DBGC ( cursor, "ASN1 %p algorithm %s is not a digest "
550                        "algorithm:\n", cursor, (*algorithm)->name );
551                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
552                 return -ENOTTY_ALGORITHM;
553         }
554
555         return 0;
556 }
557
558 /**
559  * Parse ASN.1 OID-identified signature algorithm
560  *
561  * @v cursor            ASN.1 object cursor
562  * @ret algorithm       Algorithm
563  * @ret rc              Return status code
564  */
565 int asn1_signature_algorithm ( const struct asn1_cursor *cursor,
566                                struct asn1_algorithm **algorithm ) {
567         int rc;
568
569         /* Parse algorithm */
570         if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
571                 return rc;
572
573         /* Check algorithm has a public key */
574         if ( ! (*algorithm)->pubkey ) {
575                 DBGC ( cursor, "ASN1 %p algorithm %s is not a signature "
576                        "algorithm:\n", cursor, (*algorithm)->name );
577                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
578                 return -ENOTTY_ALGORITHM;
579         }
580
581         /* Check algorithm has a digest */
582         if ( ! (*algorithm)->digest ) {
583                 DBGC ( cursor, "ASN1 %p algorithm %s is not a signature "
584                        "algorithm:\n", cursor, (*algorithm)->name );
585                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
586                 return -ENOTTY_ALGORITHM;
587         }
588
589         return 0;
590 }
591
592 /**
593  * Parse ASN.1 GeneralizedTime
594  *
595  * @v cursor            ASN.1 cursor
596  * @v time              Time to fill in
597  * @ret rc              Return status code
598  *
599  * RFC 5280 section 4.1.2.5 places several restrictions on the allowed
600  * formats for UTCTime and GeneralizedTime, and mandates the
601  * interpretation of centuryless year values.
602  */
603 int asn1_generalized_time ( const struct asn1_cursor *cursor, time_t *time ) {
604         struct asn1_cursor contents;
605         unsigned int have_century;
606         unsigned int type;
607         union {
608                 struct {
609                         uint8_t century;
610                         uint8_t year;
611                         uint8_t month;
612                         uint8_t day;
613                         uint8_t hour;
614                         uint8_t minute;
615                         uint8_t second;
616                 } __attribute__ (( packed )) named;
617                 uint8_t raw[7];
618         } pairs;
619         struct tm tm;
620         const uint8_t *data;
621         size_t remaining;
622         unsigned int tens;
623         unsigned int units;
624         unsigned int i;
625         int rc;
626
627         /* Determine time format utcTime/generalizedTime */
628         memcpy ( &contents, cursor, sizeof ( contents ) );
629         type = asn1_type ( &contents );
630         switch ( type ) {
631         case ASN1_UTC_TIME:
632                 have_century = 0;
633                 break;
634         case ASN1_GENERALIZED_TIME:
635                 have_century = 1;
636                 break;
637         default:
638                 DBGC ( cursor, "ASN1 %p invalid time type %02x\n",
639                        cursor, type );
640                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
641                 return -EINVAL_ASN1_TIME;
642         }
643
644         /* Enter utcTime/generalizedTime */
645         if ( ( rc = asn1_enter ( &contents, type ) ) != 0 ) {
646                 DBGC ( cursor, "ASN1 %p cannot locate %s time:\n", cursor,
647                        ( ( type == ASN1_UTC_TIME ) ? "UTC" : "generalized" ) );
648                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
649                 return rc;
650         }
651
652         /* Parse digit string a pair at a time */
653         memset ( &pairs, 0, sizeof ( pairs ) );
654         data = contents.data;
655         remaining = contents.len;
656         for ( i = ( have_century ? 0 : 1 ) ; i < sizeof ( pairs.raw ) ; i++ ) {
657                 if ( remaining < 2 ) {
658                         /* Some certificates violate the X.509 RFC by
659                          * omitting the "seconds" value.
660                          */
661                         if ( i == ( sizeof ( pairs.raw ) - 1 ) )
662                                 break;
663                         DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
664                         DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
665                         return -EINVAL_ASN1_TIME;
666                 }
667                 tens = data[0];
668                 units = data[1];
669                 if ( ! ( isdigit ( tens ) && isdigit ( units ) ) ) {
670                         DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
671                         DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
672                         return -EINVAL_ASN1_TIME;
673                 }
674                 pairs.raw[i] = ( ( 10 * ( tens - '0' ) ) + ( units - '0' ) );
675                 data += 2;
676                 remaining -= 2;
677         }
678
679         /* Determine century if applicable */
680         if ( ! have_century )
681                 pairs.named.century = ( ( pairs.named.year >= 50 ) ? 19 : 20 );
682
683         /* Check for trailing "Z" */
684         if ( ( remaining != 1 ) || ( data[0] != 'Z' ) ) {
685                 DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
686                 DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
687                 return -EINVAL_ASN1_TIME;
688         }
689
690         /* Fill in time */
691         tm.tm_year = ( ( ( pairs.named.century - 19 ) * 100 ) +
692                        pairs.named.year );
693         tm.tm_mon = ( pairs.named.month - 1 );
694         tm.tm_mday = pairs.named.day;
695         tm.tm_hour = pairs.named.hour;
696         tm.tm_min = pairs.named.minute;
697         tm.tm_sec = pairs.named.second;
698
699         /* Convert to seconds since the Epoch */
700         *time = mktime ( &tm );
701
702         return 0;
703 }
704
705 /**
706  * Construct ASN.1 header
707  *
708  * @v header            ASN.1 builder header
709  * @v type              Type
710  * @v len               Content length
711  * @ret header_len      Header length
712  */
713 static size_t asn1_header ( struct asn1_builder_header *header,
714                             unsigned int type, size_t len ) {
715         unsigned int header_len = 2;
716         unsigned int len_len = 0;
717         size_t temp;
718
719         /* Construct header */
720         header->type = type;
721         if ( len < 0x80 ) {
722                 header->length[0] = len;
723         } else {
724                 for ( temp = len ; temp ; temp >>= 8 )
725                         len_len++;
726                 header->length[0] = ( 0x80 | len_len );
727                 header_len += len_len;
728                 for ( temp = len ; temp ; temp >>= 8 )
729                         header->length[len_len--] = ( temp & 0xff );
730         }
731
732         return header_len;
733 }
734
735 /**
736  * Grow ASN.1 builder
737  *
738  * @v builder           ASN.1 builder
739  * @v extra             Extra space to prepend
740  * @ret rc              Return status code
741  */
742 int asn1_grow ( struct asn1_builder *builder, size_t extra ) {
743         size_t new_len;
744         void *new;
745
746         /* As with the ASN1 parsing functions, make errors permanent */
747         if ( builder->len && ! builder->data )
748                 return -ENOMEM;
749
750         /* Reallocate data buffer */
751         new_len = ( builder->len + extra );
752         new = realloc ( builder->data, new_len );
753         if ( ! new ) {
754                 free ( builder->data );
755                 builder->data = NULL;
756                 return -ENOMEM;
757         }
758         builder->data = new;
759
760         /* Move existing data to end of buffer */
761         memmove ( ( builder->data + extra ), builder->data, builder->len );
762         builder->len = new_len;
763
764         return 0;
765 }
766
767 /**
768  * Prepend raw data to ASN.1 builder
769  *
770  * @v builder           ASN.1 builder
771  * @v data              Data to prepend
772  * @v len               Length of data to prepend
773  * @ret rc              Return status code
774  */
775 int asn1_prepend_raw ( struct asn1_builder *builder, const void *data,
776                        size_t len ) {
777         int rc;
778
779         /* Grow buffer */
780         if ( ( rc = asn1_grow ( builder, len ) ) != 0 )
781                 return rc;
782
783         /* Populate data buffer */
784         memcpy ( builder->data, data, len );
785
786         return 0;
787 }
788
789 /**
790  * Prepend data to ASN.1 builder
791  *
792  * @v builder           ASN.1 builder
793  * @v type              Type
794  * @v data              Data to prepend
795  * @v len               Length of data to prepend
796  * @ret rc              Return status code
797  */
798 int asn1_prepend ( struct asn1_builder *builder, unsigned int type,
799                    const void *data, size_t len ) {
800         struct asn1_builder_header header;
801         size_t header_len;
802         int rc;
803
804         /* Construct header */
805         header_len = asn1_header ( &header, type, len );
806
807         /* Grow buffer */
808         if ( ( rc = asn1_grow ( builder, header_len + len ) ) != 0 )
809                 return rc;
810
811         /* Populate data buffer */
812         memcpy ( builder->data, &header, header_len );
813         memcpy ( ( builder->data + header_len ), data, len );
814
815         return 0;
816 }
817
818 /**
819  * Wrap ASN.1 builder
820  *
821  * @v builder           ASN.1 builder
822  * @v type              Type
823  * @ret rc              Return status code
824  */
825 int asn1_wrap ( struct asn1_builder *builder, unsigned int type ) {
826         struct asn1_builder_header header;
827         size_t header_len;
828         int rc;
829
830         /* Construct header */
831         header_len = asn1_header ( &header, type, builder->len );
832
833         /* Grow buffer */
834         if ( ( rc = asn1_grow ( builder, header_len ) ) != 0 )
835                 return rc;
836
837         /* Populate data buffer */
838         memcpy ( builder->data, &header, header_len );
839
840         return 0;
841 }
842
843 /**
844  * Extract ASN.1 object from image
845  *
846  * @v image             Image
847  * @v offset            Offset within image
848  * @v cursor            ASN.1 cursor to fill in
849  * @ret next            Offset to next image, or negative error
850  *
851  * The caller is responsible for eventually calling free() on the
852  * allocated ASN.1 cursor.
853  */
854 int image_asn1 ( struct image *image, size_t offset,
855                  struct asn1_cursor **cursor ) {
856         int next;
857         int rc;
858
859         /* Sanity check */
860         assert ( offset <= image->len );
861
862         /* Check that this image can be used to extract an ASN.1 object */
863         if ( ! ( image->type && image->type->asn1 ) )
864                 return -ENOTSUP;
865
866         /* Try creating ASN.1 cursor */
867         next = image->type->asn1 ( image, offset, cursor );
868         if ( next < 0 ) {
869                 rc = next;
870                 DBGC ( image, "IMAGE %s could not extract ASN.1 object: %s\n",
871                        image->name, strerror ( rc ) );
872                 return rc;
873         }
874
875         return next;
876 }
877
878 /* Drag in objects via image_asn1() */
879 REQUIRING_SYMBOL ( image_asn1 );
880
881 /* Drag in ASN.1 image formats */
882 REQUIRE_OBJECT ( config_asn1 );