• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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