1 /*
2 * Copyright (C) 2007 Michael Brown <mbrown@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 */
asn1_start(struct asn1_cursor * cursor,unsigned int type)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 */
asn1_enter(struct asn1_cursor * cursor,unsigned int type)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 */
asn1_skip(struct asn1_cursor * cursor,unsigned int type)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