preparing for release of 3.0-alpha11
[Samba/ekacnet.git] / source / libsmb / asn1.c
blob93e95b52bbb5064784ee58742945fd4649ff59bd
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 simple SPNEGO routines
5 Copyright (C) Andrew Tridgell 2001
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
24 /* free an asn1 structure */
25 void asn1_free(ASN1_DATA *data)
27 SAFE_FREE(data->data);
30 /* write to the ASN1 buffer, advancing the buffer pointer */
31 BOOL asn1_write(ASN1_DATA *data, const void *p, int len)
33 if (data->has_error) return False;
34 if (data->length < data->ofs+len) {
35 uint8 *newp;
36 newp = Realloc(data->data, data->ofs+len);
37 if (!newp) {
38 SAFE_FREE(data->data);
39 data->has_error = True;
40 return False;
42 data->data = newp;
43 data->length = data->ofs+len;
45 memcpy(data->data + data->ofs, p, len);
46 data->ofs += len;
47 return True;
50 /* useful fn for writing a uint8 */
51 BOOL asn1_write_uint8(ASN1_DATA *data, uint8 v)
53 return asn1_write(data, &v, 1);
56 /* push a tag onto the asn1 data buffer. Used for nested structures */
57 BOOL asn1_push_tag(ASN1_DATA *data, uint8 tag)
59 struct nesting *nesting;
61 asn1_write_uint8(data, tag);
62 nesting = (struct nesting *)malloc(sizeof(struct nesting));
63 if (!nesting) {
64 data->has_error = True;
65 return False;
68 nesting->start = data->ofs;
69 nesting->next = data->nesting;
70 data->nesting = nesting;
71 return asn1_write_uint8(data, 0xff);
74 /* pop a tag */
75 BOOL asn1_pop_tag(ASN1_DATA *data)
77 struct nesting *nesting;
78 size_t len;
80 nesting = data->nesting;
82 if (!nesting) {
83 data->has_error = True;
84 return False;
86 len = data->ofs - (nesting->start+1);
87 /* yes, this is ugly. We don't know in advance how many bytes the length
88 of a tag will take, so we assumed 1 byte. If we were wrong then we
89 need to correct our mistake */
90 if (len > 255) {
91 data->data[nesting->start] = 0x82;
92 if (!asn1_write_uint8(data, 0)) return False;
93 if (!asn1_write_uint8(data, 0)) return False;
94 memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
95 data->data[nesting->start+1] = len>>8;
96 data->data[nesting->start+2] = len&0xff;
97 } else if (len > 127) {
98 data->data[nesting->start] = 0x81;
99 if (!asn1_write_uint8(data, 0)) return False;
100 memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
101 data->data[nesting->start+1] = len;
102 } else {
103 data->data[nesting->start] = len;
106 data->nesting = nesting->next;
107 free(nesting);
108 return True;
112 /* write an integer */
113 BOOL asn1_write_Integer(ASN1_DATA *data, int i)
115 if (!asn1_push_tag(data, ASN1_INTEGER)) return False;
116 do {
117 asn1_write_uint8(data, i);
118 i = i >> 8;
119 } while (i);
120 return asn1_pop_tag(data);
123 /* write an object ID to a ASN1 buffer */
124 BOOL asn1_write_OID(ASN1_DATA *data, const char *OID)
126 unsigned v, v2;
127 const char *p = (const char *)OID;
128 char *newp;
130 if (!asn1_push_tag(data, ASN1_OID))
131 return False;
132 v = strtol(p, &newp, 10);
133 p = newp;
134 v2 = strtol(p, &newp, 10);
135 p = newp;
136 if (!asn1_write_uint8(data, 40*v + v2))
137 return False;
139 while (*p) {
140 v = strtol(p, &newp, 10);
141 p = newp;
142 if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff));
143 if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
144 if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
145 if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
146 if (!asn1_write_uint8(data, v&0x7f))
147 return False;
149 return asn1_pop_tag(data);
152 /* write an octet string */
153 BOOL asn1_write_OctetString(ASN1_DATA *data, const void *p, size_t length)
155 asn1_push_tag(data, ASN1_OCTET_STRING);
156 asn1_write(data, p, length);
157 asn1_pop_tag(data);
158 return !data->has_error;
161 /* write a general string */
162 BOOL asn1_write_GeneralString(ASN1_DATA *data, const char *s)
164 asn1_push_tag(data, ASN1_GENERAL_STRING);
165 asn1_write(data, s, strlen(s));
166 asn1_pop_tag(data);
167 return !data->has_error;
170 /* write a BOOLEAN */
171 BOOL asn1_write_BOOLEAN(ASN1_DATA *data, BOOL v)
173 asn1_write_uint8(data, ASN1_BOOLEAN);
174 asn1_write_uint8(data, v);
175 return !data->has_error;
178 /* check a BOOLEAN */
179 BOOL asn1_check_BOOLEAN(ASN1_DATA *data, BOOL v)
181 uint8 b = 0;
183 asn1_read_uint8(data, &b);
184 if (b != ASN1_BOOLEAN) {
185 data->has_error = True;
186 return False;
188 asn1_read_uint8(data, &b);
189 if (b != v) {
190 data->has_error = True;
191 return False;
193 return !data->has_error;
197 /* load a ASN1_DATA structure with a lump of data, ready to be parsed */
198 BOOL asn1_load(ASN1_DATA *data, DATA_BLOB blob)
200 ZERO_STRUCTP(data);
201 data->data = memdup(blob.data, blob.length);
202 if (!data->data) {
203 data->has_error = True;
204 return False;
206 data->length = blob.length;
207 return True;
210 /* read from a ASN1 buffer, advancing the buffer pointer */
211 BOOL asn1_read(ASN1_DATA *data, void *p, int len)
213 if (data->ofs + len > data->length) {
214 data->has_error = True;
215 return False;
217 memcpy(p, data->data + data->ofs, len);
218 data->ofs += len;
219 return True;
222 /* read a uint8 from a ASN1 buffer */
223 BOOL asn1_read_uint8(ASN1_DATA *data, uint8 *v)
225 return asn1_read(data, v, 1);
228 /* start reading a nested asn1 structure */
229 BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
231 uint8 b;
232 struct nesting *nesting;
234 asn1_read_uint8(data, &b);
235 if (b != tag) {
236 data->has_error = True;
237 return False;
239 nesting = (struct nesting *)malloc(sizeof(struct nesting));
240 if (!nesting) {
241 data->has_error = True;
242 return False;
245 asn1_read_uint8(data, &b);
246 if (b & 0x80) {
247 int n = b & 0x7f;
248 if (n > 2) {
249 data->has_error = True;
250 return False;
252 asn1_read_uint8(data, &b);
253 nesting->taglen = b;
254 if (n == 2) {
255 asn1_read_uint8(data, &b);
256 nesting->taglen = (nesting->taglen << 8) | b;
258 } else {
259 nesting->taglen = b;
261 nesting->start = data->ofs;
262 nesting->next = data->nesting;
263 data->nesting = nesting;
264 return !data->has_error;
268 /* stop reading a tag */
269 BOOL asn1_end_tag(ASN1_DATA *data)
271 struct nesting *nesting;
273 /* make sure we read it all */
274 if (asn1_tag_remaining(data) != 0) {
275 data->has_error = True;
276 return False;
279 nesting = data->nesting;
281 if (!nesting) {
282 data->has_error = True;
283 return False;
286 data->nesting = nesting->next;
287 free(nesting);
288 return True;
291 /* work out how many bytes are left in this nested tag */
292 int asn1_tag_remaining(ASN1_DATA *data)
294 if (!data->nesting) {
295 data->has_error = True;
296 return -1;
298 return data->nesting->taglen - (data->ofs - data->nesting->start);
301 /* read an object ID from a ASN1 buffer */
302 BOOL asn1_read_OID(ASN1_DATA *data, char **OID)
304 uint8 b;
305 pstring oid;
306 fstring el;
308 if (!asn1_start_tag(data, ASN1_OID)) return False;
309 asn1_read_uint8(data, &b);
311 oid[0] = 0;
312 snprintf(el, sizeof(el), "%u", b/40);
313 pstrcat(oid, el);
314 snprintf(el, sizeof(el), " %u", b%40);
315 pstrcat(oid, el);
317 while (asn1_tag_remaining(data) > 0) {
318 unsigned v = 0;
319 do {
320 asn1_read_uint8(data, &b);
321 v = (v<<7) | (b&0x7f);
322 } while (!data->has_error && b & 0x80);
323 snprintf(el, sizeof(el), " %u", v);
324 pstrcat(oid, el);
327 asn1_end_tag(data);
329 *OID = strdup(oid);
331 return !data->has_error;
334 /* check that the next object ID is correct */
335 BOOL asn1_check_OID(ASN1_DATA *data, char *OID)
337 char *id;
339 if (!asn1_read_OID(data, &id)) return False;
341 if (strcmp(id, OID) != 0) {
342 data->has_error = True;
343 return False;
345 free(id);
346 return True;
349 /* read a GeneralString from a ASN1 buffer */
350 BOOL asn1_read_GeneralString(ASN1_DATA *data, char **s)
352 int len;
353 if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return False;
354 len = asn1_tag_remaining(data);
355 *s = malloc(len+1);
356 if (! *s) {
357 data->has_error = True;
358 return False;
360 asn1_read(data, *s, len);
361 (*s)[len] = 0;
362 asn1_end_tag(data);
363 return !data->has_error;
366 /* read a octet string blob */
367 BOOL asn1_read_OctetString(ASN1_DATA *data, DATA_BLOB *blob)
369 int len;
370 if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
371 len = asn1_tag_remaining(data);
372 blob->data = malloc(len);
373 if (!blob->data) {
374 data->has_error = True;
375 return False;
377 asn1_read(data, blob->data, len);
378 blob->length = len;
379 asn1_end_tag(data);
380 return !data->has_error;
383 /* read an interger */
384 BOOL asn1_read_Integer(ASN1_DATA *data, int *i)
386 uint8 b;
387 *i = 0;
389 if (!asn1_start_tag(data, ASN1_INTEGER)) return False;
390 while (asn1_tag_remaining(data)>0) {
391 *i = (*i << 8) + asn1_read_uint8(data, &b);
393 return asn1_end_tag(data);
397 /* check a enumarted value is correct */
398 BOOL asn1_check_enumerated(ASN1_DATA *data, int v)
400 uint8 b;
401 if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
402 asn1_read_uint8(data, &b);
403 asn1_end_tag(data);
404 return !data->has_error && (v == b);
407 /* check a enumarted value is correct */
408 BOOL asn1_write_enumerated(ASN1_DATA *data, uint8 v)
410 if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
411 asn1_write_uint8(data, v);
412 asn1_pop_tag(data);
413 return !data->has_error;