|  | @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 | 
		
	
		
			
			| 20 | 20 |  
 | 
		
	
		
			
			| 21 | 21 |  #include <stdint.h>
 | 
		
	
		
			
			| 22 | 22 |  #include <stddef.h>
 | 
		
	
		
			
			|  | 23 | +#include <stdlib.h>
 | 
		
	
		
			
			| 23 | 24 |  #include <string.h>
 | 
		
	
		
			
			| 24 | 25 |  #include <ctype.h>
 | 
		
	
		
			
			| 25 | 26 |  #include <errno.h>
 | 
		
	
	
		
			
			|  | @@ -699,3 +700,141 @@ int asn1_generalized_time ( const struct asn1_cursor *cursor, time_t *time ) {
 | 
		
	
		
			
			| 699 | 700 |  
 | 
		
	
		
			
			| 700 | 701 |  	return 0;
 | 
		
	
		
			
			| 701 | 702 |  }
 | 
		
	
		
			
			|  | 703 | +
 | 
		
	
		
			
			|  | 704 | +/**
 | 
		
	
		
			
			|  | 705 | + * Construct ASN.1 header
 | 
		
	
		
			
			|  | 706 | + *
 | 
		
	
		
			
			|  | 707 | + * @v header		ASN.1 builder header
 | 
		
	
		
			
			|  | 708 | + * @v type		Type
 | 
		
	
		
			
			|  | 709 | + * @v len		Content length
 | 
		
	
		
			
			|  | 710 | + * @ret header_len	Header length
 | 
		
	
		
			
			|  | 711 | + */
 | 
		
	
		
			
			|  | 712 | +static size_t asn1_header ( struct asn1_builder_header *header,
 | 
		
	
		
			
			|  | 713 | +			    unsigned int type, size_t len ) {
 | 
		
	
		
			
			|  | 714 | +	unsigned int header_len = 2;
 | 
		
	
		
			
			|  | 715 | +	unsigned int len_len = 0;
 | 
		
	
		
			
			|  | 716 | +	size_t temp;
 | 
		
	
		
			
			|  | 717 | +
 | 
		
	
		
			
			|  | 718 | +	/* Construct header */
 | 
		
	
		
			
			|  | 719 | +	header->type = type;
 | 
		
	
		
			
			|  | 720 | +	if ( len < 0x80 ) {
 | 
		
	
		
			
			|  | 721 | +		header->length[0] = len;
 | 
		
	
		
			
			|  | 722 | +	} else {
 | 
		
	
		
			
			|  | 723 | +		for ( temp = len ; temp ; temp >>= 8 )
 | 
		
	
		
			
			|  | 724 | +			len_len++;
 | 
		
	
		
			
			|  | 725 | +		header->length[0] = ( 0x80 | len_len );
 | 
		
	
		
			
			|  | 726 | +		header_len += len_len;
 | 
		
	
		
			
			|  | 727 | +		for ( temp = len ; temp ; temp >>= 8 )
 | 
		
	
		
			
			|  | 728 | +			header->length[len_len--] = ( temp & 0xff );
 | 
		
	
		
			
			|  | 729 | +	}
 | 
		
	
		
			
			|  | 730 | +
 | 
		
	
		
			
			|  | 731 | +	return header_len;
 | 
		
	
		
			
			|  | 732 | +}
 | 
		
	
		
			
			|  | 733 | +
 | 
		
	
		
			
			|  | 734 | +/**
 | 
		
	
		
			
			|  | 735 | + * Grow ASN.1 builder
 | 
		
	
		
			
			|  | 736 | + *
 | 
		
	
		
			
			|  | 737 | + * @v builder		ASN.1 builder
 | 
		
	
		
			
			|  | 738 | + * @v extra		Extra space to prepend
 | 
		
	
		
			
			|  | 739 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 740 | + */
 | 
		
	
		
			
			|  | 741 | +static int asn1_grow ( struct asn1_builder *builder, size_t extra ) {
 | 
		
	
		
			
			|  | 742 | +	size_t new_len;
 | 
		
	
		
			
			|  | 743 | +	void *new;
 | 
		
	
		
			
			|  | 744 | +
 | 
		
	
		
			
			|  | 745 | +	/* As with the ASN1 parsing functions, make errors permanent */
 | 
		
	
		
			
			|  | 746 | +	if ( builder->len && ! builder->data )
 | 
		
	
		
			
			|  | 747 | +		return -ENOMEM;
 | 
		
	
		
			
			|  | 748 | +
 | 
		
	
		
			
			|  | 749 | +	/* Reallocate data buffer */
 | 
		
	
		
			
			|  | 750 | +	new_len = ( builder->len + extra );
 | 
		
	
		
			
			|  | 751 | +	new = realloc ( builder->data, new_len );
 | 
		
	
		
			
			|  | 752 | +	if ( ! new ) {
 | 
		
	
		
			
			|  | 753 | +		free ( builder->data );
 | 
		
	
		
			
			|  | 754 | +		builder->data = NULL;
 | 
		
	
		
			
			|  | 755 | +		return -ENOMEM;
 | 
		
	
		
			
			|  | 756 | +	}
 | 
		
	
		
			
			|  | 757 | +	builder->data = new;
 | 
		
	
		
			
			|  | 758 | +
 | 
		
	
		
			
			|  | 759 | +	/* Move existing data to end of buffer */
 | 
		
	
		
			
			|  | 760 | +	memmove ( ( builder->data + extra ), builder->data, builder->len );
 | 
		
	
		
			
			|  | 761 | +	builder->len = new_len;
 | 
		
	
		
			
			|  | 762 | +
 | 
		
	
		
			
			|  | 763 | +	return 0;
 | 
		
	
		
			
			|  | 764 | +}
 | 
		
	
		
			
			|  | 765 | +
 | 
		
	
		
			
			|  | 766 | +/**
 | 
		
	
		
			
			|  | 767 | + * Prepend raw data to ASN.1 builder
 | 
		
	
		
			
			|  | 768 | + *
 | 
		
	
		
			
			|  | 769 | + * @v builder		ASN.1 builder
 | 
		
	
		
			
			|  | 770 | + * @v data		Data to prepend
 | 
		
	
		
			
			|  | 771 | + * @v len		Length of data to prepend
 | 
		
	
		
			
			|  | 772 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 773 | + */
 | 
		
	
		
			
			|  | 774 | +int asn1_prepend_raw ( struct asn1_builder *builder, const void *data,
 | 
		
	
		
			
			|  | 775 | +		       size_t len ) {
 | 
		
	
		
			
			|  | 776 | +	int rc;
 | 
		
	
		
			
			|  | 777 | +
 | 
		
	
		
			
			|  | 778 | +	/* Grow buffer */
 | 
		
	
		
			
			|  | 779 | +	if ( ( rc = asn1_grow ( builder, len ) ) != 0 )
 | 
		
	
		
			
			|  | 780 | +		return rc;
 | 
		
	
		
			
			|  | 781 | +
 | 
		
	
		
			
			|  | 782 | +	/* Populate data buffer */
 | 
		
	
		
			
			|  | 783 | +	memcpy ( builder->data, data, len );
 | 
		
	
		
			
			|  | 784 | +
 | 
		
	
		
			
			|  | 785 | +	return 0;
 | 
		
	
		
			
			|  | 786 | +}
 | 
		
	
		
			
			|  | 787 | +
 | 
		
	
		
			
			|  | 788 | +/**
 | 
		
	
		
			
			|  | 789 | + * Prepend data to ASN.1 builder
 | 
		
	
		
			
			|  | 790 | + *
 | 
		
	
		
			
			|  | 791 | + * @v builder		ASN.1 builder
 | 
		
	
		
			
			|  | 792 | + * @v type		Type
 | 
		
	
		
			
			|  | 793 | + * @v data		Data to prepend
 | 
		
	
		
			
			|  | 794 | + * @v len		Length of data to prepend
 | 
		
	
		
			
			|  | 795 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 796 | + */
 | 
		
	
		
			
			|  | 797 | +int asn1_prepend ( struct asn1_builder *builder, unsigned int type,
 | 
		
	
		
			
			|  | 798 | +		   const void *data, size_t len ) {
 | 
		
	
		
			
			|  | 799 | +	struct asn1_builder_header header;
 | 
		
	
		
			
			|  | 800 | +	size_t header_len;
 | 
		
	
		
			
			|  | 801 | +	int rc;
 | 
		
	
		
			
			|  | 802 | +
 | 
		
	
		
			
			|  | 803 | +	/* Construct header */
 | 
		
	
		
			
			|  | 804 | +	header_len = asn1_header ( &header, type, len );
 | 
		
	
		
			
			|  | 805 | +
 | 
		
	
		
			
			|  | 806 | +	/* Grow buffer */
 | 
		
	
		
			
			|  | 807 | +	if ( ( rc = asn1_grow ( builder, header_len + len ) ) != 0 )
 | 
		
	
		
			
			|  | 808 | +		return rc;
 | 
		
	
		
			
			|  | 809 | +
 | 
		
	
		
			
			|  | 810 | +	/* Populate data buffer */
 | 
		
	
		
			
			|  | 811 | +	memcpy ( builder->data, &header, header_len );
 | 
		
	
		
			
			|  | 812 | +	memcpy ( ( builder->data + header_len ), data, len );
 | 
		
	
		
			
			|  | 813 | +
 | 
		
	
		
			
			|  | 814 | +	return 0;
 | 
		
	
		
			
			|  | 815 | +}
 | 
		
	
		
			
			|  | 816 | +
 | 
		
	
		
			
			|  | 817 | +/**
 | 
		
	
		
			
			|  | 818 | + * Wrap ASN.1 builder
 | 
		
	
		
			
			|  | 819 | + *
 | 
		
	
		
			
			|  | 820 | + * @v builder		ASN.1 builder
 | 
		
	
		
			
			|  | 821 | + * @v type		Type
 | 
		
	
		
			
			|  | 822 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 823 | + */
 | 
		
	
		
			
			|  | 824 | +int asn1_wrap ( struct asn1_builder *builder, unsigned int type ) {
 | 
		
	
		
			
			|  | 825 | +	struct asn1_builder_header header;
 | 
		
	
		
			
			|  | 826 | +	size_t header_len;
 | 
		
	
		
			
			|  | 827 | +	int rc;
 | 
		
	
		
			
			|  | 828 | +
 | 
		
	
		
			
			|  | 829 | +	/* Construct header */
 | 
		
	
		
			
			|  | 830 | +	header_len = asn1_header ( &header, type, builder->len );
 | 
		
	
		
			
			|  | 831 | +
 | 
		
	
		
			
			|  | 832 | +	/* Grow buffer */
 | 
		
	
		
			
			|  | 833 | +	if ( ( rc = asn1_grow ( builder, header_len ) ) != 0 )
 | 
		
	
		
			
			|  | 834 | +		return rc;
 | 
		
	
		
			
			|  | 835 | +
 | 
		
	
		
			
			|  | 836 | +	/* Populate data buffer */
 | 
		
	
		
			
			|  | 837 | +	memcpy ( builder->data, &header, header_len );
 | 
		
	
		
			
			|  | 838 | +
 | 
		
	
		
			
			|  | 839 | +	return 0;
 | 
		
	
		
			
			|  | 840 | +}
 |