2 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
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.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
33 #include <ipxe/tables.h>
34 #include <ipxe/image.h>
35 #include <ipxe/asn1.h>
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" )
86 * Start parsing ASN.1 object
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
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.
98 int asn1_start ( struct asn1_cursor
*cursor
, unsigned int type
, size_t extra
) {
103 if ( cursor
->len
< 2 /* Tag byte and first length byte */ ) {
105 DBGC ( cursor
, "ASN1 %p too short\n", cursor
);
106 return -EINVAL_ASN1_EMPTY
;
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
) );
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 );
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
;
133 /* Extract the length and sanity check */
134 for ( len
= 0 ; len_len
; len_len
-- ) {
136 len
|= *( ( uint8_t * ) cursor
->data
);
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
;
152 * @v cursor ASN.1 object cursor
153 * @v type Expected type, or ASN1_ANY
154 * @ret rc Return status code
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
160 int asn1_enter ( struct asn1_cursor
*cursor
, unsigned int type
) {
163 len
= asn1_start ( cursor
, type
, 0 );
165 asn1_invalidate_cursor ( cursor
);
170 DBGC ( cursor
, "ASN1 %p entered object type %02x (len %x)\n",
177 * Skip ASN.1 object if present
179 * @v cursor ASN.1 object cursor
180 * @v type Expected type, or ASN1_ANY
181 * @ret rc Return status code
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
187 int asn1_skip_if_exists ( struct asn1_cursor
*cursor
, unsigned int type
) {
190 len
= asn1_start ( cursor
, type
, 0 );
196 DBGC ( cursor
, "ASN1 %p skipped object type %02x (len %x)\n",
199 if ( ! cursor
->len
) {
200 DBGC ( cursor
, "ASN1 %p reached end of object\n", cursor
);
210 * @v cursor ASN.1 object cursor
211 * @v type Expected type, or ASN1_ANY
212 * @ret rc Return status code
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
218 int asn1_skip ( struct asn1_cursor
*cursor
, unsigned int type
) {
221 if ( ( rc
= asn1_skip_if_exists ( cursor
, type
) ) != 0 ) {
222 asn1_invalidate_cursor ( cursor
);
230 * Shrink ASN.1 cursor to fit object
232 * @v cursor ASN.1 object cursor
233 * @v type Expected type, or ASN1_ANY
234 * @ret rc Return status code
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
240 int asn1_shrink ( struct asn1_cursor
*cursor
, unsigned int type
) {
241 struct asn1_cursor temp
;
245 /* Find end of object */
246 memcpy ( &temp
, cursor
, sizeof ( temp
) );
247 len
= asn1_start ( &temp
, type
, 0 );
249 asn1_invalidate_cursor ( cursor
);
252 end
= ( temp
.data
+ len
);
254 /* Shrink original cursor to contain only its first object */
255 cursor
->len
= ( end
- cursor
->data
);
261 * Enter ASN.1 object of any type
263 * @v cursor ASN.1 object cursor
264 * @ret rc Return status code
266 int asn1_enter_any ( struct asn1_cursor
*cursor
) {
267 return asn1_enter ( cursor
, ASN1_ANY
);
271 * Skip ASN.1 object of any type
273 * @v cursor ASN.1 object cursor
274 * @ret rc Return status code
276 int asn1_skip_any ( struct asn1_cursor
*cursor
) {
277 return asn1_skip ( cursor
, ASN1_ANY
);
281 * Shrink ASN.1 object of any type
283 * @v cursor ASN.1 object cursor
284 * @ret rc Return status code
286 int asn1_shrink_any ( struct asn1_cursor
*cursor
) {
287 return asn1_shrink ( cursor
, ASN1_ANY
);
291 * Parse value of ASN.1 boolean
293 * @v cursor ASN.1 object cursor
294 * @ret value Value, or negative error
296 int asn1_boolean ( const struct asn1_cursor
*cursor
) {
297 struct asn1_cursor contents
;
300 } __attribute__ (( packed
)) *boolean
;
303 memcpy ( &contents
, cursor
, sizeof ( contents
) );
304 asn1_enter ( &contents
, ASN1_BOOLEAN
);
305 if ( contents
.len
!= sizeof ( *boolean
) )
306 return -EINVAL_ASN1_BOOLEAN
;
309 boolean
= contents
.data
;
310 return boolean
->value
;
314 * Parse value of ASN.1 integer
316 * @v cursor ASN.1 object cursor
317 * @v value Value to fill in
318 * @ret rc Return status code
320 int asn1_integer ( const struct asn1_cursor
*cursor
, int *value
) {
321 struct asn1_cursor contents
;
326 memcpy ( &contents
, cursor
, sizeof ( contents
) );
327 if ( ( rc
= asn1_enter ( &contents
, ASN1_INTEGER
) ) != 0 )
329 if ( contents
.len
< 1 )
330 return -EINVAL_ASN1_INTEGER
;
332 /* Initialise value according to sign byte */
333 *value
= *( ( int8_t * ) contents
.data
);
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
;
344 *value
= ( ( *value
<< 8 ) | *( ( uint8_t * ) contents
.data
) );
353 * Parse ASN.1 bit string
355 * @v cursor ASN.1 cursor
356 * @v bits Bit string to fill in
357 * @ret rc Return status code
359 int asn1_bit_string ( const struct asn1_cursor
*cursor
,
360 struct asn1_bit_string
*bits
) {
361 struct asn1_cursor contents
;
365 } __attribute__ (( packed
)) *bit_string
;
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
);
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
;
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
;
399 /* Populate bit string */
400 bits
->data
= &bit_string
->data
;
402 bits
->unused
= unused
;
408 * Parse ASN.1 bit string that must be an integral number of bytes
410 * @v cursor ASN.1 cursor
411 * @v bits Bit string to fill in
412 * @ret rc Return status code
414 int asn1_integral_bit_string ( const struct asn1_cursor
*cursor
,
415 struct asn1_bit_string
*bits
) {
418 /* Parse bit string */
419 if ( ( rc
= asn1_bit_string ( cursor
, bits
) ) != 0 )
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",
426 DBGC_HDA ( cursor
, 0, cursor
->data
, cursor
->len
);
427 return -EINVAL_BIT_STRING
;
434 * Compare two ASN.1 objects
436 * @v cursor1 ASN.1 object cursor
437 * @v cursor2 ASN.1 object cursor
438 * @ret difference Difference as returned by memcmp()
440 * Note that invalid and empty cursors will compare as equal with each
443 int asn1_compare ( const struct asn1_cursor
*cursor1
,
444 const struct asn1_cursor
*cursor2
) {
447 difference
= ( cursor2
->len
- cursor1
->len
);
448 return ( difference ? difference
:
449 memcmp ( cursor1
->data
, cursor2
->data
, cursor1
->len
) );
453 * Identify ASN.1 algorithm by OID
455 * @v cursor ASN.1 object cursor
457 * @ret algorithm Algorithm, or NULL
459 static struct asn1_algorithm
*
460 asn1_find_algorithm ( const struct asn1_cursor
*cursor
) {
461 struct asn1_algorithm
*algorithm
;
463 for_each_table_entry ( algorithm
, ASN1_ALGORITHMS
) {
464 if ( asn1_compare ( &algorithm
->oid
, cursor
) == 0 )
472 * Parse ASN.1 OID-identified algorithm
474 * @v cursor ASN.1 object cursor
475 * @ret algorithm Algorithm
476 * @ret rc Return status code
478 int asn1_algorithm ( const struct asn1_cursor
*cursor
,
479 struct asn1_algorithm
**algorithm
) {
480 struct asn1_cursor contents
;
483 /* Enter signatureAlgorithm */
484 memcpy ( &contents
, cursor
, sizeof ( contents
) );
485 asn1_enter ( &contents
, ASN1_SEQUENCE
);
487 /* Enter algorithm */
488 if ( ( rc
= asn1_enter ( &contents
, ASN1_OID
) ) != 0 ) {
489 DBGC ( cursor
, "ASN1 %p cannot locate algorithm OID:\n",
491 DBGC_HDA ( cursor
, 0, cursor
->data
, cursor
->len
);
492 return -EINVAL_ASN1_ALGORITHM
;
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
;
507 * Parse ASN.1 OID-identified public-key algorithm
509 * @v cursor ASN.1 object cursor
510 * @ret algorithm Algorithm
511 * @ret rc Return status code
513 int asn1_pubkey_algorithm ( const struct asn1_cursor
*cursor
,
514 struct asn1_algorithm
**algorithm
) {
517 /* Parse algorithm */
518 if ( ( rc
= asn1_algorithm ( cursor
, algorithm
) ) != 0 )
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
;
533 * Parse ASN.1 OID-identified digest algorithm
535 * @v cursor ASN.1 object cursor
536 * @ret algorithm Algorithm
537 * @ret rc Return status code
539 int asn1_digest_algorithm ( const struct asn1_cursor
*cursor
,
540 struct asn1_algorithm
**algorithm
) {
543 /* Parse algorithm */
544 if ( ( rc
= asn1_algorithm ( cursor
, algorithm
) ) != 0 )
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
;
559 * Parse ASN.1 OID-identified signature algorithm
561 * @v cursor ASN.1 object cursor
562 * @ret algorithm Algorithm
563 * @ret rc Return status code
565 int asn1_signature_algorithm ( const struct asn1_cursor
*cursor
,
566 struct asn1_algorithm
**algorithm
) {
569 /* Parse algorithm */
570 if ( ( rc
= asn1_algorithm ( cursor
, algorithm
) ) != 0 )
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
;
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
;
593 * Parse ASN.1 GeneralizedTime
595 * @v cursor ASN.1 cursor
596 * @v time Time to fill in
597 * @ret rc Return status code
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.
603 int asn1_generalized_time ( const struct asn1_cursor
*cursor
, time_t *time
) {
604 struct asn1_cursor contents
;
605 unsigned int have_century
;
616 } __attribute__ (( packed
)) named
;
627 /* Determine time format utcTime/generalizedTime */
628 memcpy ( &contents
, cursor
, sizeof ( contents
) );
629 type
= asn1_type ( &contents
);
634 case ASN1_GENERALIZED_TIME
:
638 DBGC ( cursor
, "ASN1 %p invalid time type %02x\n",
640 DBGC_HDA ( cursor
, 0, cursor
->data
, cursor
->len
);
641 return -EINVAL_ASN1_TIME
;
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
);
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.
661 if ( i
== ( sizeof ( pairs
.raw
) - 1 ) )
663 DBGC ( cursor
, "ASN1 %p invalid time:\n", cursor
);
664 DBGC_HDA ( cursor
, 0, cursor
->data
, cursor
->len
);
665 return -EINVAL_ASN1_TIME
;
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
;
674 pairs
.raw
[i
] = ( ( 10 * ( tens
- '0' ) ) + ( units
- '0' ) );
679 /* Determine century if applicable */
680 if ( ! have_century
)
681 pairs
.named
.century
= ( ( pairs
.named
.year
>= 50 ) ?
19 : 20 );
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
;
691 tm
.tm_year
= ( ( ( pairs
.named
.century
- 19 ) * 100 ) +
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
;
699 /* Convert to seconds since the Epoch */
700 *time
= mktime ( &tm
);
706 * Construct ASN.1 header
708 * @v header ASN.1 builder header
710 * @v len Content length
711 * @ret header_len Header length
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;
719 /* Construct header */
722 header
->length
[0] = len
;
724 for ( temp
= len
; temp
; temp
>>= 8 )
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 );
738 * @v builder ASN.1 builder
739 * @v extra Extra space to prepend
740 * @ret rc Return status code
742 int asn1_grow ( struct asn1_builder
*builder
, size_t extra
) {
746 /* As with the ASN1 parsing functions, make errors permanent */
747 if ( builder
->len
&& ! builder
->data
)
750 /* Reallocate data buffer */
751 new_len
= ( builder
->len
+ extra
);
752 new = realloc ( builder
->data
, new_len
);
754 free ( builder
->data
);
755 builder
->data
= NULL
;
760 /* Move existing data to end of buffer */
761 memmove ( ( builder
->data
+ extra
), builder
->data
, builder
->len
);
762 builder
->len
= new_len
;
768 * Prepend raw data to ASN.1 builder
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
775 int asn1_prepend_raw ( struct asn1_builder
*builder
, const void *data
,
780 if ( ( rc
= asn1_grow ( builder
, len
) ) != 0 )
783 /* Populate data buffer */
784 memcpy ( builder
->data
, data
, len
);
790 * Prepend data to ASN.1 builder
792 * @v builder ASN.1 builder
794 * @v data Data to prepend
795 * @v len Length of data to prepend
796 * @ret rc Return status code
798 int asn1_prepend ( struct asn1_builder
*builder
, unsigned int type
,
799 const void *data
, size_t len
) {
800 struct asn1_builder_header header
;
804 /* Construct header */
805 header_len
= asn1_header ( &header
, type
, len
);
808 if ( ( rc
= asn1_grow ( builder
, header_len
+ len
) ) != 0 )
811 /* Populate data buffer */
812 memcpy ( builder
->data
, &header
, header_len
);
813 memcpy ( ( builder
->data
+ header_len
), data
, len
);
821 * @v builder ASN.1 builder
823 * @ret rc Return status code
825 int asn1_wrap ( struct asn1_builder
*builder
, unsigned int type
) {
826 struct asn1_builder_header header
;
830 /* Construct header */
831 header_len
= asn1_header ( &header
, type
, builder
->len
);
834 if ( ( rc
= asn1_grow ( builder
, header_len
) ) != 0 )
837 /* Populate data buffer */
838 memcpy ( builder
->data
, &header
, header_len
);
844 * Extract ASN.1 object from 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
851 * The caller is responsible for eventually calling free() on the
852 * allocated ASN.1 cursor.
854 int image_asn1 ( struct image
*image
, size_t offset
,
855 struct asn1_cursor
**cursor
) {
860 assert ( offset
<= image
->len
);
862 /* Check that this image can be used to extract an ASN.1 object */
863 if ( ! ( image
->type
&& image
->type
->asn1
) )
866 /* Try creating ASN.1 cursor */
867 next
= image
->type
->asn1 ( image
, offset
, cursor
);
870 DBGC ( image
, "IMAGE %s could not extract ASN.1 object: %s\n",
871 image
->name
, strerror ( rc
) );
878 /* Drag in objects via image_asn1() */
879 REQUIRING_SYMBOL ( image_asn1
);
881 /* Drag in ASN.1 image formats */
882 REQUIRE_OBJECT ( config_asn1
);