mirror of https://github.com/ipxe/ipxe.git
[crypto] Add more ASN.1 functions for X.509 certificate parsing
Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/6/head
parent
da76a489d6
commit
e20550fddf
|
@ -43,6 +43,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
__einfo_error ( EINFO_EINVAL_ASN1_LEN )
|
__einfo_error ( EINFO_EINVAL_ASN1_LEN )
|
||||||
#define EINFO_EINVAL_ASN1_LEN \
|
#define EINFO_EINVAL_ASN1_LEN \
|
||||||
__einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
|
__einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
|
||||||
|
#define EINVAL_ASN1_BOOLEAN \
|
||||||
|
__einfo_error ( EINFO_EINVAL_ASN1_BOOLEAN )
|
||||||
|
#define EINFO_EINVAL_ASN1_BOOLEAN \
|
||||||
|
__einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid boolean" )
|
||||||
|
#define EINVAL_ASN1_INTEGER \
|
||||||
|
__einfo_error ( EINFO_EINVAL_ASN1_INTEGER )
|
||||||
|
#define EINFO_EINVAL_ASN1_INTEGER \
|
||||||
|
__einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid integer" )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidate ASN.1 object cursor
|
* Invalidate ASN.1 object cursor
|
||||||
|
@ -191,7 +199,7 @@ int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||||
int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
|
int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) < 0 ) {
|
if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) != 0 ) {
|
||||||
asn1_invalidate_cursor ( cursor );
|
asn1_invalidate_cursor ( cursor );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -199,6 +207,32 @@ int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shrink ASN.1 cursor to fit object
|
||||||
|
*
|
||||||
|
* @v cursor ASN.1 object cursor
|
||||||
|
* @v type Expected type, or ASN1_ANY
|
||||||
|
* @ret rc Return status code
|
||||||
|
*
|
||||||
|
* The object cursor will be shrunk to contain only the current ASN.1
|
||||||
|
* object. If any error occurs, the object cursor will be
|
||||||
|
* invalidated.
|
||||||
|
*/
|
||||||
|
int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||||
|
struct asn1_cursor next;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Skip to next object */
|
||||||
|
memcpy ( &next, cursor, sizeof ( next ) );
|
||||||
|
if ( ( rc = asn1_skip ( &next, type ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Shrink original cursor to contain only its first object */
|
||||||
|
cursor->len = ( next.data - cursor->data );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enter ASN.1 object of any type
|
* Enter ASN.1 object of any type
|
||||||
*
|
*
|
||||||
|
@ -219,6 +253,76 @@ int asn1_skip_any ( struct asn1_cursor *cursor ) {
|
||||||
return asn1_skip ( cursor, ASN1_ANY );
|
return asn1_skip ( cursor, ASN1_ANY );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shrink ASN.1 object of any type
|
||||||
|
*
|
||||||
|
* @v cursor ASN.1 object cursor
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
int asn1_shrink_any ( struct asn1_cursor *cursor ) {
|
||||||
|
return asn1_shrink ( cursor, ASN1_ANY );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse value of ASN.1 boolean
|
||||||
|
*
|
||||||
|
* @v cursor ASN.1 object cursor
|
||||||
|
* @ret value Value, or negative error
|
||||||
|
*/
|
||||||
|
int asn1_boolean ( const struct asn1_cursor *cursor ) {
|
||||||
|
struct asn1_cursor contents;
|
||||||
|
const struct asn1_boolean *boolean;
|
||||||
|
|
||||||
|
/* Enter boolean */
|
||||||
|
memcpy ( &contents, cursor, sizeof ( contents ) );
|
||||||
|
asn1_enter ( &contents, ASN1_BOOLEAN );
|
||||||
|
if ( contents.len != sizeof ( *boolean ) )
|
||||||
|
return -EINVAL_ASN1_BOOLEAN;
|
||||||
|
|
||||||
|
/* Extract value */
|
||||||
|
boolean = contents.data;
|
||||||
|
return boolean->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse value of ASN.1 integer
|
||||||
|
*
|
||||||
|
* @v cursor ASN.1 object cursor
|
||||||
|
* @v value Value to fill in
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
int asn1_integer ( const struct asn1_cursor *cursor, int *value ) {
|
||||||
|
struct asn1_cursor contents;
|
||||||
|
uint8_t high_byte;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Enter integer */
|
||||||
|
memcpy ( &contents, cursor, sizeof ( contents ) );
|
||||||
|
if ( ( rc = asn1_enter ( &contents, ASN1_INTEGER ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
if ( contents.len < 1 )
|
||||||
|
return -EINVAL_ASN1_INTEGER;
|
||||||
|
|
||||||
|
/* Initialise value according to sign byte */
|
||||||
|
*value = *( ( int8_t * ) contents.data );
|
||||||
|
contents.data++;
|
||||||
|
contents.len--;
|
||||||
|
|
||||||
|
/* Process value */
|
||||||
|
while ( contents.len ) {
|
||||||
|
high_byte = ( (*value) >> ( 8 * ( sizeof ( *value ) - 1 ) ) );
|
||||||
|
if ( ( high_byte != 0x00 ) && ( high_byte != 0xff ) ) {
|
||||||
|
DBGC ( cursor, "ASN1 %p integer overflow\n", cursor );
|
||||||
|
return -EINVAL_ASN1_INTEGER;
|
||||||
|
}
|
||||||
|
*value = ( ( *value << 8 ) | *( ( uint8_t * ) contents.data ) );
|
||||||
|
contents.data++;
|
||||||
|
contents.len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare two ASN.1 objects
|
* Compare two ASN.1 objects
|
||||||
*
|
*
|
||||||
|
|
|
@ -55,7 +55,7 @@ static int x509_public_key ( const struct asn1_cursor *certificate,
|
||||||
memcpy ( &cursor, certificate, sizeof ( cursor ) );
|
memcpy ( &cursor, certificate, sizeof ( cursor ) );
|
||||||
rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
|
rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
|
||||||
asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */
|
asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */
|
||||||
asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ), /* version */
|
asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG(0) ),/*version*/
|
||||||
asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
|
asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
|
||||||
asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
|
asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
|
||||||
asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */
|
asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */
|
||||||
|
|
|
@ -20,6 +20,9 @@ struct asn1_cursor {
|
||||||
/** ASN.1 end */
|
/** ASN.1 end */
|
||||||
#define ASN1_END 0x00
|
#define ASN1_END 0x00
|
||||||
|
|
||||||
|
/** ASN.1 boolean */
|
||||||
|
#define ASN1_BOOLEAN 0x01
|
||||||
|
|
||||||
/** ASN.1 integer */
|
/** ASN.1 integer */
|
||||||
#define ASN1_INTEGER 0x02
|
#define ASN1_INTEGER 0x02
|
||||||
|
|
||||||
|
@ -48,7 +51,7 @@ struct asn1_cursor {
|
||||||
#define ASN1_SET 0x31
|
#define ASN1_SET 0x31
|
||||||
|
|
||||||
/** ASN.1 explicit tag */
|
/** ASN.1 explicit tag */
|
||||||
#define ASN1_EXPLICIT_TAG 0xa0
|
#define ASN1_EXPLICIT_TAG( number) ( 0xa0 | (number) )
|
||||||
|
|
||||||
/** ASN.1 "any tag" magic value */
|
/** ASN.1 "any tag" magic value */
|
||||||
#define ASN1_ANY -1U
|
#define ASN1_ANY -1U
|
||||||
|
@ -79,15 +82,14 @@ struct asn1_cursor {
|
||||||
/** ASN.1 OID for iso(1) member-body(2) */
|
/** ASN.1 OID for iso(1) member-body(2) */
|
||||||
#define ASN1_OID_ISO_MEMBERBODY ASN1_OID_INITIAL ( 1, 2 )
|
#define ASN1_OID_ISO_MEMBERBODY ASN1_OID_INITIAL ( 1, 2 )
|
||||||
|
|
||||||
|
/** ASN.1 OID for iso(1) identified-organization(3) */
|
||||||
|
#define ASN1_OID_IDENTIFIED_ORGANIZATION ASN1_OID_INITIAL ( 1, 3 )
|
||||||
|
|
||||||
/** ASN.1 OID for joint-iso-itu-t(2) ds(5) */
|
/** ASN.1 OID for joint-iso-itu-t(2) ds(5) */
|
||||||
#define ASN1_OID_DIRECTORY_SERVICES ASN1_OID_INITIAL ( 2, 5 )
|
#define ASN1_OID_DIRECTORY_SERVICES ASN1_OID_INITIAL ( 2, 5 )
|
||||||
|
|
||||||
/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) */
|
/** ASN.1 OID for joint-iso-itu-t(2) country(16) */
|
||||||
#define ASN1_OID_ATTRIBUTE_TYPE \
|
#define ASN1_OID_COUNTRY ASN1_OID_INITIAL ( 2, 16 )
|
||||||
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 an ASN.1 cursor containing an OID */
|
||||||
#define ASN1_OID_CURSOR( oid_value ) { \
|
#define ASN1_OID_CURSOR( oid_value ) { \
|
||||||
|
@ -95,6 +97,12 @@ struct asn1_cursor {
|
||||||
.len = sizeof ( oid_value ), \
|
.len = sizeof ( oid_value ), \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** An ASN.1 boolean */
|
||||||
|
struct asn1_boolean {
|
||||||
|
/** Value */
|
||||||
|
uint8_t value;
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
/** An ASN.1 bit string */
|
/** An ASN.1 bit string */
|
||||||
struct asn1_bit_string {
|
struct asn1_bit_string {
|
||||||
/** Number of unused bits */
|
/** Number of unused bits */
|
||||||
|
@ -119,8 +127,12 @@ extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type );
|
||||||
extern int asn1_skip_if_exists ( struct asn1_cursor *cursor,
|
extern int asn1_skip_if_exists ( struct asn1_cursor *cursor,
|
||||||
unsigned int type );
|
unsigned int type );
|
||||||
extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type );
|
extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type );
|
||||||
|
extern int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type );
|
||||||
extern int asn1_enter_any ( struct asn1_cursor *cursor );
|
extern int asn1_enter_any ( struct asn1_cursor *cursor );
|
||||||
extern int asn1_skip_any ( struct asn1_cursor *cursor );
|
extern int asn1_skip_any ( struct asn1_cursor *cursor );
|
||||||
|
extern int asn1_shrink_any ( struct asn1_cursor *cursor );
|
||||||
|
extern int asn1_boolean ( const struct asn1_cursor *cursor );
|
||||||
|
extern int asn1_integer ( const struct asn1_cursor *cursor, int *value );
|
||||||
extern int asn1_compare ( const struct asn1_cursor *cursor1,
|
extern int asn1_compare ( const struct asn1_cursor *cursor1,
|
||||||
const struct asn1_cursor *cursor2 );
|
const struct asn1_cursor *cursor2 );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue