r17760: The DNS SRV lookup already sorts by priority and weight so don't
[Samba/gebeck_regimport.git] / source / libsmb / asn1.c
blobdd22051ae7c212507678e94d9970ec8ace7b07ff
1 /*
2 Unix SMB/CIFS implementation.
3 simple SPNEGO routines
4 Copyright (C) Andrew Tridgell 2001
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
23 /* free an asn1 structure */
24 void asn1_free(ASN1_DATA *data)
26 SAFE_FREE(data->data);
29 /* write to the ASN1 buffer, advancing the buffer pointer */
30 BOOL asn1_write(ASN1_DATA *data, const void *p, int len)
32 if (data->has_error) return False;
33 if (data->length < data->ofs+len) {
34 data->data = SMB_REALLOC_ARRAY(data->data, unsigned char,
35 data->ofs+len);
36 if (!data->data) {
37 data->has_error = True;
38 return False;
40 data->length = data->ofs+len;
42 memcpy(data->data + data->ofs, p, len);
43 data->ofs += len;
44 return True;
47 /* useful fn for writing a uint8 */
48 BOOL asn1_write_uint8(ASN1_DATA *data, uint8 v)
50 return asn1_write(data, &v, 1);
53 /* push a tag onto the asn1 data buffer. Used for nested structures */
54 BOOL asn1_push_tag(ASN1_DATA *data, uint8 tag)
56 struct nesting *nesting;
58 asn1_write_uint8(data, tag);
59 nesting = SMB_MALLOC_P(struct nesting);
60 if (!nesting) {
61 data->has_error = True;
62 return False;
65 nesting->start = data->ofs;
66 nesting->next = data->nesting;
67 data->nesting = nesting;
68 return asn1_write_uint8(data, 0xff);
71 /* pop a tag */
72 BOOL asn1_pop_tag(ASN1_DATA *data)
74 struct nesting *nesting;
75 size_t len;
77 nesting = data->nesting;
79 if (!nesting) {
80 data->has_error = True;
81 return False;
83 len = data->ofs - (nesting->start+1);
84 /* yes, this is ugly. We don't know in advance how many bytes the length
85 of a tag will take, so we assumed 1 byte. If we were wrong then we
86 need to correct our mistake */
87 if (len > 0xFFFF) {
88 data->data[nesting->start] = 0x83;
89 if (!asn1_write_uint8(data, 0)) return False;
90 if (!asn1_write_uint8(data, 0)) return False;
91 if (!asn1_write_uint8(data, 0)) return False;
92 memmove(data->data+nesting->start+4, data->data+nesting->start+1, len);
93 data->data[nesting->start+1] = (len>>16) & 0xFF;
94 data->data[nesting->start+2] = (len>>8) & 0xFF;
95 data->data[nesting->start+3] = len&0xff;
96 } else if (len > 255) {
97 data->data[nesting->start] = 0x82;
98 if (!asn1_write_uint8(data, 0)) return False;
99 if (!asn1_write_uint8(data, 0)) return False;
100 memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
101 data->data[nesting->start+1] = len>>8;
102 data->data[nesting->start+2] = len&0xff;
103 } else if (len > 127) {
104 data->data[nesting->start] = 0x81;
105 if (!asn1_write_uint8(data, 0)) return False;
106 memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
107 data->data[nesting->start+1] = len;
108 } else {
109 data->data[nesting->start] = len;
112 data->nesting = nesting->next;
113 free(nesting);
114 return True;
118 /* write an integer */
119 BOOL asn1_write_Integer(ASN1_DATA *data, int i)
121 if (!asn1_push_tag(data, ASN1_INTEGER)) return False;
122 do {
123 asn1_write_uint8(data, i);
124 i = i >> 8;
125 } while (i);
126 return asn1_pop_tag(data);
129 /* write an object ID to a ASN1 buffer */
130 BOOL asn1_write_OID(ASN1_DATA *data, const char *OID)
132 unsigned v, v2;
133 const char *p = (const char *)OID;
134 char *newp;
136 if (!asn1_push_tag(data, ASN1_OID))
137 return False;
138 v = strtol(p, &newp, 10);
139 p = newp;
140 v2 = strtol(p, &newp, 10);
141 p = newp;
142 if (!asn1_write_uint8(data, 40*v + v2))
143 return False;
145 while (*p) {
146 v = strtol(p, &newp, 10);
147 p = newp;
148 if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff));
149 if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
150 if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
151 if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
152 if (!asn1_write_uint8(data, v&0x7f))
153 return False;
155 return asn1_pop_tag(data);
158 /* write an octet string */
159 BOOL asn1_write_OctetString(ASN1_DATA *data, const void *p, size_t length)
161 asn1_push_tag(data, ASN1_OCTET_STRING);
162 asn1_write(data, p, length);
163 asn1_pop_tag(data);
164 return !data->has_error;
167 /* write a general string */
168 BOOL asn1_write_GeneralString(ASN1_DATA *data, const char *s)
170 asn1_push_tag(data, ASN1_GENERAL_STRING);
171 asn1_write(data, s, strlen(s));
172 asn1_pop_tag(data);
173 return !data->has_error;
176 /* write a BOOLEAN */
177 BOOL asn1_write_BOOLEAN(ASN1_DATA *data, BOOL v)
179 asn1_write_uint8(data, ASN1_BOOLEAN);
180 asn1_write_uint8(data, v);
181 return !data->has_error;
184 /* write a BOOLEAN - hmm, I suspect this one is the correct one, and the
185 above boolean is bogus. Need to check */
186 BOOL asn1_write_BOOLEAN2(ASN1_DATA *data, BOOL v)
188 asn1_push_tag(data, ASN1_BOOLEAN);
189 asn1_write_uint8(data, v);
190 asn1_pop_tag(data);
191 return !data->has_error;
194 /* check a BOOLEAN */
195 BOOL asn1_check_BOOLEAN(ASN1_DATA *data, BOOL v)
197 uint8 b = 0;
199 asn1_read_uint8(data, &b);
200 if (b != ASN1_BOOLEAN) {
201 data->has_error = True;
202 return False;
204 asn1_read_uint8(data, &b);
205 if (b != v) {
206 data->has_error = True;
207 return False;
209 return !data->has_error;
213 /* load a ASN1_DATA structure with a lump of data, ready to be parsed */
214 BOOL asn1_load(ASN1_DATA *data, DATA_BLOB blob)
216 ZERO_STRUCTP(data);
217 data->data = (unsigned char *)memdup(blob.data, blob.length);
218 if (!data->data) {
219 data->has_error = True;
220 return False;
222 data->length = blob.length;
223 return True;
226 /* read from a ASN1 buffer, advancing the buffer pointer */
227 BOOL asn1_read(ASN1_DATA *data, void *p, int len)
229 if (data->has_error)
230 return False;
232 if (len < 0 || data->ofs + len < data->ofs || data->ofs + len < len) {
233 data->has_error = True;
234 return False;
237 if (data->ofs + len > data->length) {
238 data->has_error = True;
239 return False;
241 memcpy(p, data->data + data->ofs, len);
242 data->ofs += len;
243 return True;
246 /* read a uint8 from a ASN1 buffer */
247 BOOL asn1_read_uint8(ASN1_DATA *data, uint8 *v)
249 return asn1_read(data, v, 1);
252 /* start reading a nested asn1 structure */
253 BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
255 uint8 b;
256 struct nesting *nesting;
258 if (!asn1_read_uint8(data, &b))
259 return False;
261 if (b != tag) {
262 data->has_error = True;
263 return False;
265 nesting = SMB_MALLOC_P(struct nesting);
266 if (!nesting) {
267 data->has_error = True;
268 return False;
271 if (!asn1_read_uint8(data, &b)) {
272 SAFE_FREE(nesting);
273 return False;
276 if (b & 0x80) {
277 int n = b & 0x7f;
278 if (!asn1_read_uint8(data, &b)) {
279 SAFE_FREE(nesting);
280 return False;
282 nesting->taglen = b;
283 while (n > 1) {
284 if (!asn1_read_uint8(data, &b)) {
285 SAFE_FREE(nesting);
286 return False;
288 nesting->taglen = (nesting->taglen << 8) | b;
289 n--;
291 } else {
292 nesting->taglen = b;
294 nesting->start = data->ofs;
295 nesting->next = data->nesting;
296 data->nesting = nesting;
297 return !data->has_error;
301 /* stop reading a tag */
302 BOOL asn1_end_tag(ASN1_DATA *data)
304 struct nesting *nesting;
306 /* make sure we read it all */
307 if (asn1_tag_remaining(data) != 0) {
308 data->has_error = True;
309 return False;
312 nesting = data->nesting;
314 if (!nesting) {
315 data->has_error = True;
316 return False;
319 data->nesting = nesting->next;
320 free(nesting);
321 return True;
324 /* work out how many bytes are left in this nested tag */
325 int asn1_tag_remaining(ASN1_DATA *data)
327 if (data->has_error)
328 return 0;
330 if (!data->nesting) {
331 data->has_error = True;
332 return -1;
334 return data->nesting->taglen - (data->ofs - data->nesting->start);
337 /* read an object ID from a ASN1 buffer */
338 BOOL asn1_read_OID(ASN1_DATA *data, char **OID)
340 uint8 b;
341 pstring oid_str;
342 fstring el;
344 *OID = NULL;
346 if (!asn1_start_tag(data, ASN1_OID)) {
347 return False;
349 asn1_read_uint8(data, &b);
351 oid_str[0] = 0;
352 fstr_sprintf(el, "%u", b/40);
353 pstrcat(oid_str, el);
354 fstr_sprintf(el, " %u", b%40);
355 pstrcat(oid_str, el);
357 while (asn1_tag_remaining(data) > 0) {
358 unsigned v = 0;
359 do {
360 asn1_read_uint8(data, &b);
361 v = (v<<7) | (b&0x7f);
362 } while (!data->has_error && b & 0x80);
363 fstr_sprintf(el, " %u", v);
364 pstrcat(oid_str, el);
367 asn1_end_tag(data);
369 if (!data->has_error) {
370 *OID = SMB_STRDUP(oid_str);
373 return !data->has_error;
376 /* check that the next object ID is correct */
377 BOOL asn1_check_OID(ASN1_DATA *data, const char *OID)
379 char *id;
381 if (!asn1_read_OID(data, &id)) {
382 return False;
385 if (strcmp(id, OID) != 0) {
386 data->has_error = True;
387 return False;
389 free(id);
390 return True;
393 /* read a GeneralString from a ASN1 buffer */
394 BOOL asn1_read_GeneralString(ASN1_DATA *data, char **s)
396 int len;
397 char *str;
399 *s = NULL;
401 if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) {
402 return False;
404 len = asn1_tag_remaining(data);
405 if (len < 0) {
406 data->has_error = True;
407 return False;
409 str = SMB_MALLOC_ARRAY(char, len+1);
410 if (!str) {
411 data->has_error = True;
412 return False;
414 asn1_read(data, str, len);
415 str[len] = 0;
416 asn1_end_tag(data);
418 if (!data->has_error) {
419 *s = str;
421 return !data->has_error;
424 /* read a octet string blob */
425 BOOL asn1_read_OctetString(ASN1_DATA *data, DATA_BLOB *blob)
427 int len;
428 ZERO_STRUCTP(blob);
429 if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
430 len = asn1_tag_remaining(data);
431 if (len < 0) {
432 data->has_error = True;
433 return False;
435 *blob = data_blob(NULL, len);
436 asn1_read(data, blob->data, len);
437 asn1_end_tag(data);
438 return !data->has_error;
441 /* read an interger */
442 BOOL asn1_read_Integer(ASN1_DATA *data, int *i)
444 uint8 b;
445 *i = 0;
447 if (!asn1_start_tag(data, ASN1_INTEGER)) return False;
448 while (asn1_tag_remaining(data)>0) {
449 asn1_read_uint8(data, &b);
450 *i = (*i << 8) + b;
452 return asn1_end_tag(data);
456 /* check a enumarted value is correct */
457 BOOL asn1_check_enumerated(ASN1_DATA *data, int v)
459 uint8 b;
460 if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
461 asn1_read_uint8(data, &b);
462 asn1_end_tag(data);
464 if (v != b)
465 data->has_error = False;
467 return !data->has_error;
470 /* write an enumarted value to the stream */
471 BOOL asn1_write_enumerated(ASN1_DATA *data, uint8 v)
473 if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
474 asn1_write_uint8(data, v);
475 asn1_pop_tag(data);
476 return !data->has_error;