0a69162a84c08785dd8a82ef009a4f0a81a2741d
[people/lynusvaz/gpxe.git] / src / crypto / asn1.c
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 #include <stdint.h>
20 #include <stddef.h>
21 #include <errno.h>
22 #include <gpxe/asn1.h>
23
24 /** @file
25  *
26  * ASN.1 encoding
27  *
28  */
29
30 /**
31  * Start parsing ASN.1 object
32  *
33  * @v cursor            ASN.1 object cursor
34  * @v type              Expected type
35  * @ret len             Length of object body, or -1 on error
36  *
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.
41  *
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.
46  */
47 static int asn1_start_object ( struct asn1_cursor *cursor,
48                                unsigned int type ) {
49         unsigned int len_len;
50         unsigned int len;
51
52         /* Sanity check */
53         if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
54                 if ( cursor->len )
55                         DBGC ( cursor, "ASN1 %p too short\n", cursor );
56                 goto notfound;
57         }
58
59         /* Check the tag byte */
60         if ( cursor->data[0] != type ) {
61                 DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
62                        cursor, type, cursor->data[0] );
63                 goto notfound;
64         }
65         cursor->data++;
66         cursor->len--;
67
68         /* Extract length of the length field and sanity check */
69         len_len = cursor->data[0];
70         if ( len_len & 0x80 ) {
71                 len_len = ( len_len & 0x7f );
72                 cursor->data++;
73                 cursor->len--;
74         } else {
75                 len_len = 1;
76         }
77         if ( cursor->len < len_len ) {
78                 DBGC ( cursor, "ASN1 %p bad length field length %d (max "
79                        "%zd)\n", cursor, len_len, cursor->len );
80                 goto notfound;
81         }
82
83         /* Extract the length and sanity check */
84         for ( len = 0 ; len_len ; len_len-- ) {
85                 len <<= 8;
86                 len |= cursor->data[0];
87                 cursor->data++;
88                 cursor->len--;
89         }
90         if ( cursor->len < len ) {
91                 DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
92                        cursor, len, cursor->len );
93                 goto notfound;
94         }
95
96         return len;
97
98  notfound:
99         cursor->data = NULL;
100         cursor->len = 0;
101         return -1;
102 }
103
104 /**
105  * Enter ASN.1 object
106  *
107  * @v cursor            ASN.1 object cursor
108  * @v type              Expected type
109  * @ret rc              Return status code
110  *
111  * The object cursor will be updated to point to the body of the
112  * current ASN.1 object.  If any error occurs, the object cursor will
113  * be invalidated.
114  */
115 int asn1_enter_object ( struct asn1_cursor *cursor, unsigned int type ) {
116         int len;
117
118         len = asn1_start_object ( cursor, type );
119         if ( len < 0 )
120                 return -ENOENT;
121
122         cursor->len = len;
123         DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
124                cursor, type, len );
125
126         return 0;
127 }
128
129 /**
130  * Skip ASN.1 object
131  *
132  * @v cursor            ASN.1 object cursor
133  * @v type              Expected type
134  * @ret rc              Return status code
135  *
136  * The object cursor will be updated to point to the next ASN.1
137  * object.  If any error occurs, the object cursor will be
138  * invalidated.
139  */
140 int asn1_skip_object ( struct asn1_cursor *cursor, unsigned int type ) {
141         int len;
142
143         len = asn1_start_object ( cursor, type );
144         if ( len < 0 )
145                 return -ENOENT;
146
147         cursor->data += len;
148         cursor->len -= len;
149         DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n",
150                cursor, type, len );
151
152         if ( ! cursor->len ) {
153                 DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
154                 cursor->data = NULL;
155                 return -ENOENT;
156         }
157
158         return 0;
159 }