Home | History | Annotate | Download | only in crypto
      1 /*
      2  * Copyright (C) 2007 Michael Brown <mbrown (at) fensystems.co.uk>.
      3  *
      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.
      8  *
      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.
     13  *
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
     17  */
     18 
     19 FILE_LICENCE ( GPL2_OR_LATER );
     20 
     21 #include <stdint.h>
     22 #include <stddef.h>
     23 #include <errno.h>
     24 #include <gpxe/asn1.h>
     25 
     26 /** @file
     27  *
     28  * ASN.1 encoding
     29  *
     30  */
     31 
     32 /**
     33  * Start parsing ASN.1 object
     34  *
     35  * @v cursor		ASN.1 object cursor
     36  * @v type		Expected type
     37  * @ret len		Length of object body, or negative error
     38  *
     39  * The object cursor will be updated to point to the start of the
     40  * object body (i.e. the first byte following the length byte(s)), and
     41  * the length of the object body (i.e. the number of bytes until the
     42  * following object tag, if any) is returned.
     43  *
     44  * If any error occurs (i.e. if the object is not of the expected
     45  * type, or if we overflow beyond the end of the ASN.1 object), then
     46  * the cursor will be invalidated and a negative value will be
     47  * returned.
     48  */
     49 static int asn1_start ( struct asn1_cursor *cursor,
     50 			       unsigned int type ) {
     51 	unsigned int len_len;
     52 	unsigned int len;
     53 	int rc;
     54 
     55 	/* Sanity check */
     56 	if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
     57 		if ( cursor->len )
     58 			DBGC ( cursor, "ASN1 %p too short\n", cursor );
     59 		rc = -EINVAL;
     60 		goto notfound;
     61 	}
     62 
     63 	/* Check the tag byte */
     64 	if ( *( ( uint8_t * ) cursor->data ) != type ) {
     65 		DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
     66 		       cursor, type, *( ( uint8_t * ) cursor->data ) );
     67 		rc = -ENXIO;
     68 		goto notfound;
     69 	}
     70 	cursor->data++;
     71 	cursor->len--;
     72 
     73 	/* Extract length of the length field and sanity check */
     74 	len_len = *( ( uint8_t * ) cursor->data );
     75 	if ( len_len & 0x80 ) {
     76 		len_len = ( len_len & 0x7f );
     77 		cursor->data++;
     78 		cursor->len--;
     79 	} else {
     80 		len_len = 1;
     81 	}
     82 	if ( cursor->len < len_len ) {
     83 		DBGC ( cursor, "ASN1 %p bad length field length %d (max "
     84 		       "%zd)\n", cursor, len_len, cursor->len );
     85 		rc = -EINVAL;
     86 		goto notfound;
     87 	}
     88 
     89 	/* Extract the length and sanity check */
     90 	for ( len = 0 ; len_len ; len_len-- ) {
     91 		len <<= 8;
     92 		len |= *( ( uint8_t * ) cursor->data );
     93 		cursor->data++;
     94 		cursor->len--;
     95 	}
     96 	if ( cursor->len < len ) {
     97 		DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
     98 		       cursor, len, cursor->len );
     99 		rc = -EINVAL;
    100 		goto notfound;
    101 	}
    102 
    103 	return len;
    104 
    105  notfound:
    106 	cursor->data = NULL;
    107 	cursor->len = 0;
    108 	return rc;
    109 }
    110 
    111 /**
    112  * Enter ASN.1 object
    113  *
    114  * @v cursor		ASN.1 object cursor
    115  * @v type		Expected type
    116  * @ret rc		Return status code
    117  *
    118  * The object cursor will be updated to point to the body of the
    119  * current ASN.1 object.  If any error occurs, the object cursor will
    120  * be invalidated.
    121  */
    122 int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
    123 	int len;
    124 
    125 	len = asn1_start ( cursor, type );
    126 	if ( len < 0 )
    127 		return len;
    128 
    129 	cursor->len = len;
    130 	DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
    131 	       cursor, type, len );
    132 
    133 	return 0;
    134 }
    135 
    136 /**
    137  * Skip ASN.1 object
    138  *
    139  * @v cursor		ASN.1 object cursor
    140  * @v type		Expected type
    141  * @ret rc		Return status code
    142  *
    143  * The object cursor will be updated to point to the next ASN.1
    144  * object.  If any error occurs, the object cursor will be
    145  * invalidated.
    146  */
    147 int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
    148 	int len;
    149 
    150 	len = asn1_start ( cursor, type );
    151 	if ( len < 0 )
    152 		return len;
    153 
    154 	cursor->data += len;
    155 	cursor->len -= len;
    156 	DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n",
    157 	       cursor, type, len );
    158 
    159 	if ( ! cursor->len ) {
    160 		DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
    161 		cursor->data = NULL;
    162 		return -ENOENT;
    163 	}
    164 
    165 	return 0;
    166 }
    167