]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Add ASN.1 functions for X.509 certificate parsing
authorMichael Brown <mcb30@ipxe.org>
Tue, 13 Mar 2012 16:30:17 +0000 (16:30 +0000)
committerMichael Brown <mcb30@ipxe.org>
Tue, 13 Mar 2012 16:30:17 +0000 (16:30 +0000)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/crypto/asn1.c
src/include/ipxe/asn1.h

index 40b87533dda4f6a9ed5beb32abd4346517973457..d988aab4b0b0fdec9ec5f842e0caa27f027f93a2 100644 (file)
@@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
 #include <stddef.h>
+#include <string.h>
 #include <errno.h>
 #include <ipxe/asn1.h>
 
@@ -43,11 +44,23 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define EINFO_EINVAL_ASN1_LEN \
        __einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
 
+/**
+ * Invalidate ASN.1 object cursor
+ *
+ * @v cursor           ASN.1 object cursor
+ */
+void asn1_invalidate_cursor ( struct asn1_cursor *cursor ) {
+       static uint8_t asn1_invalid_object[] = { ASN1_END, 0 };
+
+       cursor->data = asn1_invalid_object;
+       cursor->len = 0;
+}
+
 /**
  * Start parsing ASN.1 object
  *
  * @v cursor           ASN.1 object cursor
- * @v type             Expected type
+ * @v type             Expected type, or ASN1_ANY
  * @ret len            Length of object body, or negative error
  *
  * The object cursor will be updated to point to the start of the
@@ -67,7 +80,7 @@ static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) {
        }
 
        /* Check the tag byte */
-       if ( *( ( uint8_t * ) cursor->data ) != type ) {
+       if ( ( type != ASN1_ANY ) && ( type != asn1_type ( cursor ) ) ) {
                DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
                       cursor, type, *( ( uint8_t * ) cursor->data ) );
                return -ENXIO;
@@ -110,7 +123,7 @@ static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) {
  * Enter ASN.1 object
  *
  * @v cursor           ASN.1 object cursor
- * @v type             Expected type
+ * @v type             Expected type, or ASN1_ANY
  * @ret rc             Return status code
  *
  * The object cursor will be updated to point to the body of the
@@ -137,7 +150,7 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
  * Skip ASN.1 object if present
  *
  * @v cursor           ASN.1 object cursor
- * @v type             Expected type
+ * @v type             Expected type, or ASN1_ANY
  * @ret rc             Return status code
  *
  * The object cursor will be updated to point to the next ASN.1
@@ -168,7 +181,7 @@ int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
  * Skip ASN.1 object
  *
  * @v cursor           ASN.1 object cursor
- * @v type             Expected type
+ * @v type             Expected type, or ASN1_ANY
  * @ret rc             Return status code
  *
  * The object cursor will be updated to point to the next ASN.1
@@ -185,3 +198,42 @@ int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
 
        return 0;
 }
+
+/**
+ * Enter ASN.1 object of any type
+ *
+ * @v cursor           ASN.1 object cursor
+ * @ret rc             Return status code
+ */
+int asn1_enter_any ( struct asn1_cursor *cursor ) {
+       return asn1_enter ( cursor, ASN1_ANY );
+}
+
+/**
+ * Skip ASN.1 object of any type
+ *
+ * @v cursor           ASN.1 object cursor
+ * @ret rc             Return status code
+ */
+int asn1_skip_any ( struct asn1_cursor *cursor ) {
+       return asn1_skip ( cursor, ASN1_ANY );
+}
+
+/**
+ * Compare two ASN.1 objects
+ *
+ * @v cursor1          ASN.1 object cursor
+ * @v cursor2          ASN.1 object cursor
+ * @ret difference     Difference as returned by memcmp()
+ *
+ * Note that invalid and empty cursors will compare as equal with each
+ * other.
+ */
+int asn1_compare ( const struct asn1_cursor *cursor1,
+                  const struct asn1_cursor *cursor2 ) {
+       int difference;
+
+       difference = ( cursor2->len - cursor1->len );
+       return ( difference ? difference :
+                memcmp ( cursor1->data, cursor2->data, cursor1->len ) );
+}
index b51267ba3b231fbca02131193b33c9774b7af235..7d8f667046ad6196532e65287df58ac1033d5a6a 100644 (file)
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+/** An ASN.1 object cursor */
+struct asn1_cursor {
+       /** Start of data */
+       const void *data;
+       /** Length of data */
+       size_t len;
+};
+
+/** ASN.1 end */
+#define ASN1_END 0x00
+
+/** ASN.1 integer */
 #define ASN1_INTEGER 0x02
+
+/** ASN.1 bit string */
 #define ASN1_BIT_STRING 0x03
+
+/** ASN.1 octet string */
 #define ASN1_OCTET_STRING 0x04
+
+/** ASN.1 null */
 #define ASN1_NULL 0x05
+
+/** ASN.1 object identifier */
 #define ASN1_OID 0x06
+
+/** ASN.1 UTC time */
+#define ASN1_UTC_TIME 0x17
+
+/** ASN.1 generalized time */
+#define ASN1_GENERALIZED_TIME 0x18
+
+/** ASN.1 sequence */
 #define ASN1_SEQUENCE 0x30
-#define ASN1_IP_ADDRESS 0x40
+
+/** ASN.1 set */
+#define ASN1_SET 0x31
+
+/** ASN.1 explicit tag */
 #define ASN1_EXPLICIT_TAG 0xa0
 
-/**
- * A DER-encoded ASN.1 object cursor
+/** ASN.1 "any tag" magic value */
+#define ASN1_ANY -1U
+
+/** Initial OID byte */
+#define ASN1_OID_INITIAL( first, second ) ( ( (first) * 40 ) + (second) )
+
+/** Single-byte OID value
+ *
+ * Valid for values up to 127
  */
-struct asn1_cursor {
-       /** Start of data */
-       const void *data;
-       /** Length of data */
-       size_t len;
-};
+#define ASN1_OID_SINGLE( value ) ( (value) & 0x7f )
+
+/** Double-byte OID value
+ *
+ * Valid for values up to 16383
+ */
+#define ASN1_OID_DOUBLE( value ) \
+       ( 0x80 | ( ( (value) >> 7 ) & 0x7f ) ), ASN1_OID_SINGLE ( (value) )
+
+/** Double-byte OID value
+ *
+ * Valid for values up to 2097151
+ */
+#define ASN1_OID_TRIPLE( value ) \
+       ( 0x80 | ( ( (value) >> 14 ) & 0x7f ) ), ASN1_OID_DOUBLE ( (value) )
+
+/** ASN.1 OID for iso(1) member-body(2) */
+#define ASN1_OID_ISO_MEMBERBODY ASN1_OID_INITIAL ( 1, 2 )
+
+/** ASN.1 OID for joint-iso-itu-t(2) ds(5) */
+#define ASN1_OID_DIRECTORY_SERVICES ASN1_OID_INITIAL ( 2, 5 )
+
+/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) */
+#define ASN1_OID_ATTRIBUTE_TYPE \
+       ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 4 )
+
+/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) commonName(3) */
+#define ASN1_OID_COMMON_NAME ASN1_OID_ATTRIBUTE_TYPE, ASN1_OID_SINGLE ( 3 )
+
+/** Define an ASN.1 cursor containing an OID */
+#define ASN1_OID_CURSOR( oid_value ) {                 \
+               .data = oid_value,                      \
+               .len = sizeof ( oid_value ),            \
+       }
+
+/** An ASN.1 bit string */
+struct asn1_bit_string {
+       /** Number of unused bits */
+       uint8_t unused;
+       /** Data */
+       uint8_t data[0];
+} __attribute__ (( packed ));
 
 /**
- * Invalidate ASN.1 object cursor
+ * Extract ASN.1 type
  *
  * @v cursor           ASN.1 object cursor
+ * @ret type           Type
  */
-static inline __attribute__ (( always_inline )) void
-asn1_invalidate_cursor ( struct asn1_cursor *cursor ) {
-       cursor->len = 0;
+static inline __attribute__ (( always_inline )) unsigned int
+asn1_type ( const struct asn1_cursor *cursor ) {
+       return ( *( ( const uint8_t * ) cursor->data ) );
 }
 
+extern void asn1_invalidate_cursor ( struct asn1_cursor *cursor );
 extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type );
 extern int asn1_skip_if_exists ( struct asn1_cursor *cursor,
                                 unsigned int type );
 extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type );
+extern int asn1_enter_any ( struct asn1_cursor *cursor );
+extern int asn1_skip_any ( struct asn1_cursor *cursor );
+extern int asn1_compare ( const struct asn1_cursor *cursor1,
+                         const struct asn1_cursor *cursor2 );
 
 #endif /* _IPXE_ASN1_H */