[contrib] Allow Network Protocol header to display in rom-o-matic
[gpxe.git] / src / crypto / asn1.c
blob154a8a840e9942dd7cd127d947560d31cfcb4faf
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 FILE_LICENCE ( GPL2_OR_LATER );
21 #include <stdint.h>
22 #include <stddef.h>
23 #include <errno.h>
24 #include <gpxe/asn1.h>
26 /** @file
28 * ASN.1 encoding
32 /**
33 * Start parsing ASN.1 object
35 * @v cursor ASN.1 object cursor
36 * @v type Expected type
37 * @ret len Length of object body, or negative error
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.
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.
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;
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;
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;
70 cursor->data++;
71 cursor->len--;
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;
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;
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--;
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;
103 return len;
105 notfound:
106 cursor->data = NULL;
107 cursor->len = 0;
108 return rc;
112 * Enter ASN.1 object
114 * @v cursor ASN.1 object cursor
115 * @v type Expected type
116 * @ret rc Return status code
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.
122 int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
123 int len;
125 len = asn1_start ( cursor, type );
126 if ( len < 0 )
127 return len;
129 cursor->len = len;
130 DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
131 cursor, type, len );
133 return 0;
137 * Skip ASN.1 object
139 * @v cursor ASN.1 object cursor
140 * @v type Expected type
141 * @ret rc Return status code
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.
147 int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
148 int len;
150 len = asn1_start ( cursor, type );
151 if ( len < 0 )
152 return len;
154 cursor->data += len;
155 cursor->len -= len;
156 DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n",
157 cursor, type, len );
159 if ( ! cursor->len ) {
160 DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
161 cursor->data = NULL;
162 return -ENOENT;
165 return 0;