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