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 */
asn1_start(struct asn1_cursor * cursor,unsigned int type,size_t extra)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 */
asn1_enter(struct asn1_cursor * cursor,unsigned int type)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 */
asn1_skip_if_exists(struct asn1_cursor * cursor,unsigned int type)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 */
asn1_skip(struct asn1_cursor * cursor,unsigned int type)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 */
asn1_shrink(struct asn1_cursor * cursor,unsigned int type)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 */
asn1_enter_any(struct asn1_cursor * cursor)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 */
asn1_skip_any(struct asn1_cursor * cursor)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 */
asn1_shrink_any(struct asn1_cursor * cursor)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 */
asn1_boolean(const struct asn1_cursor * cursor)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 */
asn1_integer(const struct asn1_cursor * cursor,int * value)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 */
asn1_bit_string(const struct asn1_cursor * cursor,struct asn1_bit_string * bits)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 */
asn1_integral_bit_string(const struct asn1_cursor * cursor,struct asn1_bit_string * bits)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 */
asn1_compare(const struct asn1_cursor * cursor1,const struct asn1_cursor * cursor2)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 *
asn1_find_algorithm(const struct asn1_cursor * cursor)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 */
asn1_algorithm(const struct asn1_cursor * cursor,struct asn1_algorithm ** algorithm)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 */
asn1_pubkey_algorithm(const struct asn1_cursor * cursor,struct asn1_algorithm ** algorithm)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 */
asn1_digest_algorithm(const struct asn1_cursor * cursor,struct asn1_algorithm ** algorithm)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 */
asn1_signature_algorithm(const struct asn1_cursor * cursor,struct asn1_algorithm ** algorithm)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 */
asn1_generalized_time(const struct asn1_cursor * cursor,time_t * time)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 */
asn1_header(struct asn1_builder_header * header,unsigned int type,size_t len)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 */
asn1_grow(struct asn1_builder * builder,size_t extra)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 */
asn1_prepend_raw(struct asn1_builder * builder,const void * data,size_t len)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 */
asn1_prepend(struct asn1_builder * builder,unsigned int type,const void * data,size_t len)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 */
asn1_wrap(struct asn1_builder * builder,unsigned int type)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 */
image_asn1(struct image * image,size_t offset,struct asn1_cursor ** cursor)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 );
883