[sundance] Add reset completion check
[gpxe.git] / src / crypto / asn1.c
blob25e7495bd18942990f06a298b64c5eea5e4af45f
1 /*
2 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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.
19 #include <stdint.h>
20 #include <stddef.h>
21 #include <errno.h>
22 #include <gpxe/asn1.h>
24 /** @file
26 * ASN.1 encoding
30 /**
31 * Start parsing ASN.1 object
33 * @v cursor ASN.1 object cursor
34 * @v type Expected type
35 * @ret len Length of object body, or negative error
37 * The object cursor will be updated to point to the start of the
38 * object body (i.e. the first byte following the length byte(s)), and
39 * the length of the object body (i.e. the number of bytes until the
40 * following object tag, if any) is returned.
42 * If any error occurs (i.e. if the object is not of the expected
43 * type, or if we overflow beyond the end of the ASN.1 object), then
44 * the cursor will be invalidated and a negative value will be
45 * returned.
47 static int asn1_start ( struct asn1_cursor *cursor,
48 unsigned int type ) {
49 unsigned int len_len;
50 unsigned int len;
51 int rc;
53 /* Sanity check */
54 if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
55 if ( cursor->len )
56 DBGC ( cursor, "ASN1 %p too short\n", cursor );
57 rc = -EINVAL;
58 goto notfound;
61 /* Check the tag byte */
62 if ( *( ( uint8_t * ) cursor->data ) != type ) {
63 DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
64 cursor, type, *( ( uint8_t * ) cursor->data ) );
65 rc = -ENXIO;
66 goto notfound;
68 cursor->data++;
69 cursor->len--;
71 /* Extract length of the length field and sanity check */
72 len_len = *( ( uint8_t * ) cursor->data );
73 if ( len_len & 0x80 ) {
74 len_len = ( len_len & 0x7f );
75 cursor->data++;
76 cursor->len--;
77 } else {
78 len_len = 1;
80 if ( cursor->len < len_len ) {
81 DBGC ( cursor, "ASN1 %p bad length field length %d (max "
82 "%zd)\n", cursor, len_len, cursor->len );
83 rc = -EINVAL;
84 goto notfound;
87 /* Extract the length and sanity check */
88 for ( len = 0 ; len_len ; len_len-- ) {
89 len <<= 8;
90 len |= *( ( uint8_t * ) cursor->data );
91 cursor->data++;
92 cursor->len--;
94 if ( cursor->len < len ) {
95 DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
96 cursor, len, cursor->len );
97 rc = -EINVAL;
98 goto notfound;
101 return len;
103 notfound:
104 cursor->data = NULL;
105 cursor->len = 0;
106 return rc;
110 * Enter ASN.1 object
112 * @v cursor ASN.1 object cursor
113 * @v type Expected type
114 * @ret rc Return status code
116 * The object cursor will be updated to point to the body of the
117 * current ASN.1 object. If any error occurs, the object cursor will
118 * be invalidated.
120 int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
121 int len;
123 len = asn1_start ( cursor, type );
124 if ( len < 0 )
125 return len;
127 cursor->len = len;
128 DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
129 cursor, type, len );
131 return 0;
135 * Skip ASN.1 object
137 * @v cursor ASN.1 object cursor
138 * @v type Expected type
139 * @ret rc Return status code
141 * The object cursor will be updated to point to the next ASN.1
142 * object. If any error occurs, the object cursor will be
143 * invalidated.
145 int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
146 int len;
148 len = asn1_start ( cursor, type );
149 if ( len < 0 )
150 return len;
152 cursor->data += len;
153 cursor->len -= len;
154 DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n",
155 cursor, type, len );
157 if ( ! cursor->len ) {
158 DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
159 cursor->data = NULL;
160 return -ENOENT;
163 return 0;