]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Add functions for constructing ASN.1 objects
authorMichael Brown <mcb30@ipxe.org>
Fri, 11 May 2012 15:40:28 +0000 (16:40 +0100)
committerMichael Brown <mcb30@ipxe.org>
Mon, 14 May 2012 17:09:43 +0000 (18:09 +0100)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/crypto/asn1.c
src/include/ipxe/asn1.h

index 9b3864ed27106cf006716ac60f8f4c91295f65ac..5fc37849b3b87cc234e9b0bb45dcf4dd91c6ceb8 100644 (file)
@@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
 #include <stddef.h>
+#include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
 #include <errno.h>
@@ -699,3 +700,141 @@ int asn1_generalized_time ( const struct asn1_cursor *cursor, time_t *time ) {
 
        return 0;
 }
+
+/**
+ * Construct ASN.1 header
+ *
+ * @v header           ASN.1 builder header
+ * @v type             Type
+ * @v len              Content length
+ * @ret header_len     Header length
+ */
+static size_t asn1_header ( struct asn1_builder_header *header,
+                           unsigned int type, size_t len ) {
+       unsigned int header_len = 2;
+       unsigned int len_len = 0;
+       size_t temp;
+
+       /* Construct header */
+       header->type = type;
+       if ( len < 0x80 ) {
+               header->length[0] = len;
+       } else {
+               for ( temp = len ; temp ; temp >>= 8 )
+                       len_len++;
+               header->length[0] = ( 0x80 | len_len );
+               header_len += len_len;
+               for ( temp = len ; temp ; temp >>= 8 )
+                       header->length[len_len--] = ( temp & 0xff );
+       }
+
+       return header_len;
+}
+
+/**
+ * Grow ASN.1 builder
+ *
+ * @v builder          ASN.1 builder
+ * @v extra            Extra space to prepend
+ * @ret rc             Return status code
+ */
+static int asn1_grow ( struct asn1_builder *builder, size_t extra ) {
+       size_t new_len;
+       void *new;
+
+       /* As with the ASN1 parsing functions, make errors permanent */
+       if ( builder->len && ! builder->data )
+               return -ENOMEM;
+
+       /* Reallocate data buffer */
+       new_len = ( builder->len + extra );
+       new = realloc ( builder->data, new_len );
+       if ( ! new ) {
+               free ( builder->data );
+               builder->data = NULL;
+               return -ENOMEM;
+       }
+       builder->data = new;
+
+       /* Move existing data to end of buffer */
+       memmove ( ( builder->data + extra ), builder->data, builder->len );
+       builder->len = new_len;
+
+       return 0;
+}
+
+/**
+ * Prepend raw data to ASN.1 builder
+ *
+ * @v builder          ASN.1 builder
+ * @v data             Data to prepend
+ * @v len              Length of data to prepend
+ * @ret rc             Return status code
+ */
+int asn1_prepend_raw ( struct asn1_builder *builder, const void *data,
+                      size_t len ) {
+       int rc;
+
+       /* Grow buffer */
+       if ( ( rc = asn1_grow ( builder, len ) ) != 0 )
+               return rc;
+
+       /* Populate data buffer */
+       memcpy ( builder->data, data, len );
+
+       return 0;
+}
+
+/**
+ * Prepend data to ASN.1 builder
+ *
+ * @v builder          ASN.1 builder
+ * @v type             Type
+ * @v data             Data to prepend
+ * @v len              Length of data to prepend
+ * @ret rc             Return status code
+ */
+int asn1_prepend ( struct asn1_builder *builder, unsigned int type,
+                  const void *data, size_t len ) {
+       struct asn1_builder_header header;
+       size_t header_len;
+       int rc;
+
+       /* Construct header */
+       header_len = asn1_header ( &header, type, len );
+
+       /* Grow buffer */
+       if ( ( rc = asn1_grow ( builder, header_len + len ) ) != 0 )
+               return rc;
+
+       /* Populate data buffer */
+       memcpy ( builder->data, &header, header_len );
+       memcpy ( ( builder->data + header_len ), data, len );
+
+       return 0;
+}
+
+/**
+ * Wrap ASN.1 builder
+ *
+ * @v builder          ASN.1 builder
+ * @v type             Type
+ * @ret rc             Return status code
+ */
+int asn1_wrap ( struct asn1_builder *builder, unsigned int type ) {
+       struct asn1_builder_header header;
+       size_t header_len;
+       int rc;
+
+       /* Construct header */
+       header_len = asn1_header ( &header, type, builder->len );
+
+       /* Grow buffer */
+       if ( ( rc = asn1_grow ( builder, header_len ) ) != 0 )
+               return rc;
+
+       /* Populate data buffer */
+       memcpy ( builder->data, &header, header_len );
+
+       return 0;
+}
index cd5c3306d2808fa8a9c8f726519d8740db97c89a..3fbd09f48121e5246d1dacbb608ecfe4e973c092 100644 (file)
@@ -21,6 +21,34 @@ struct asn1_cursor {
        size_t len;
 };
 
+/** An ASN.1 object builder */
+struct asn1_builder {
+       /** Data
+        *
+        * This is always dynamically allocated.  If @c data is NULL
+        * while @len is non-zero, this indicates that a memory
+        * allocation error has occurred during the building process.
+        */
+       void *data;
+       /** Length of data */
+       size_t len;
+};
+
+/** Maximum (viable) length of ASN.1 length
+ *
+ * While in theory unlimited, this length is sufficient to contain a
+ * size_t.
+ */
+#define ASN1_MAX_LEN_LEN ( 1 + sizeof ( size_t ) )
+
+/** An ASN.1 header */
+struct asn1_builder_header {
+       /** Type */
+       uint8_t type;
+       /** Length (encoded) */
+       uint8_t length[ASN1_MAX_LEN_LEN];
+} __attribute__ (( packed ));
+
 /** ASN.1 end */
 #define ASN1_END 0x00
 
@@ -255,5 +283,10 @@ extern int asn1_signature_algorithm ( const struct asn1_cursor *cursor,
                                      struct asn1_algorithm **algorithm );
 extern int asn1_generalized_time ( const struct asn1_cursor *cursor,
                                   time_t *time );
+extern int asn1_prepend_raw ( struct asn1_builder *builder, const void *data,
+                             size_t len );
+extern int asn1_prepend ( struct asn1_builder *builder, unsigned int type,
+                         const void *data, size_t len );
+extern int asn1_wrap ( struct asn1_builder *builder, unsigned int type );
 
 #endif /* _IPXE_ASN1_H */