2 Unix SMB/CIFS implementation.
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.
24 /* free an asn1 structure */
25 void asn1_free(struct asn1_data *data)
27 talloc_free(data->data);
30 /* write to the ASN1 buffer, advancing the buffer pointer */
31 BOOL asn1_write(struct asn1_data *data, const void *p, int len)
33 if (data->has_error) return False;
34 if (data->length < data->ofs+len) {
36 newp = talloc_realloc(NULL, data->data, uint8_t, data->ofs+len);
39 data->has_error = True;
43 data->length = data->ofs+len;
45 memcpy(data->data + data->ofs, p, len);
50 /* useful fn for writing a uint8_t */
51 BOOL asn1_write_uint8(struct asn1_data *data, uint8_t 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(struct asn1_data *data, uint8_t tag)
59 struct nesting *nesting;
61 asn1_write_uint8(data, tag);
62 nesting = talloc(NULL, struct nesting);
64 data->has_error = True;
68 nesting->start = data->ofs;
69 nesting->next = data->nesting;
70 data->nesting = nesting;
71 return asn1_write_uint8(data, 0xff);
75 BOOL asn1_pop_tag(struct asn1_data *data)
77 struct nesting *nesting;
80 nesting = data->nesting;
83 data->has_error = True;
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 */
91 data->data[nesting->start] = 0x83;
92 if (!asn1_write_uint8(data, 0)) return False;
93 if (!asn1_write_uint8(data, 0)) return False;
94 if (!asn1_write_uint8(data, 0)) return False;
95 memmove(data->data+nesting->start+4, data->data+nesting->start+1, len);
96 data->data[nesting->start+1] = (len>>16) & 0xFF;
97 data->data[nesting->start+2] = (len>>8) & 0xFF;
98 data->data[nesting->start+3] = len&0xff;
99 } else if (len > 255) {
100 data->data[nesting->start] = 0x82;
101 if (!asn1_write_uint8(data, 0)) return False;
102 if (!asn1_write_uint8(data, 0)) return False;
103 memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
104 data->data[nesting->start+1] = len>>8;
105 data->data[nesting->start+2] = len&0xff;
106 } else if (len > 127) {
107 data->data[nesting->start] = 0x81;
108 if (!asn1_write_uint8(data, 0)) return False;
109 memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
110 data->data[nesting->start+1] = len;
112 data->data[nesting->start] = len;
115 data->nesting = nesting->next;
116 talloc_free(nesting);
120 /* "i" is the one's complement representation, as is the normal result of an
121 * implicit signed->unsigned conversion */
123 static BOOL push_int_bigendian(struct asn1_data *data, unsigned int i, BOOL negative)
125 uint8_t lowest = i & 0xFF;
129 if (!push_int_bigendian(data, i, negative))
132 if (data->nesting->start+1 == data->ofs) {
134 /* We did not write anything yet, looking at the highest
138 /* Don't write leading 0xff's */
142 if ((lowest & 0x80) == 0) {
143 /* The only exception for a leading 0xff is if
144 * the highest bit is 0, which would indicate
145 * a positive value */
146 if (!asn1_write_uint8(data, 0xff))
151 /* The highest bit of a positive integer is 1,
152 * this would indicate a negative number. Push
153 * a 0 to indicate a positive one */
154 if (!asn1_write_uint8(data, 0))
160 return asn1_write_uint8(data, lowest);
163 /* write an Integer without the tag framing. Needed for example for the LDAP
164 * Abandon Operation */
166 BOOL asn1_write_implicit_Integer(struct asn1_data *data, int i)
169 /* -1 is special as it consists of all-0xff bytes. In
170 push_int_bigendian this is the only case that is not
171 properly handled, as all 0xff bytes would be handled as
172 leading ones to be ignored. */
173 return asn1_write_uint8(data, 0xff);
175 return push_int_bigendian(data, i, i<0);
180 /* write an integer */
181 BOOL asn1_write_Integer(struct asn1_data *data, int i)
183 if (!asn1_push_tag(data, ASN1_INTEGER)) return False;
184 if (!asn1_write_implicit_Integer(data, i)) return False;
185 return asn1_pop_tag(data);
188 /* write an object ID to a ASN1 buffer */
189 BOOL asn1_write_OID(struct asn1_data *data, const char *OID)
192 const char *p = (const char *)OID;
195 if (!asn1_push_tag(data, ASN1_OID))
197 v = strtol(p, &newp, 10);
199 v2 = strtol(p, &newp, 10);
201 if (!asn1_write_uint8(data, 40*v + v2))
205 v = strtol(p, &newp, 10);
207 if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff));
208 if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
209 if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
210 if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
211 if (!asn1_write_uint8(data, v&0x7f))
214 return asn1_pop_tag(data);
217 /* write an octet string */
218 BOOL asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length)
220 asn1_push_tag(data, ASN1_OCTET_STRING);
221 asn1_write(data, p, length);
223 return !data->has_error;
226 /* write a LDAP string */
227 BOOL asn1_write_LDAPString(struct asn1_data *data, const char *s)
229 asn1_write(data, s, strlen(s));
230 return !data->has_error;
233 /* write a general string */
234 BOOL asn1_write_GeneralString(struct asn1_data *data, const char *s)
236 asn1_push_tag(data, ASN1_GENERAL_STRING);
237 asn1_write_LDAPString(data, s);
239 return !data->has_error;
242 BOOL asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
244 asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(num));
245 asn1_write(data, blob->data, blob->length);
247 return !data->has_error;
250 /* write a BOOLEAN */
251 BOOL asn1_write_BOOLEAN(struct asn1_data *data, BOOL v)
253 asn1_push_tag(data, ASN1_BOOLEAN);
254 asn1_write_uint8(data, v ? 0xFF : 0);
256 return !data->has_error;
259 BOOL asn1_read_BOOLEAN(struct asn1_data *data, BOOL *v)
262 asn1_start_tag(data, ASN1_BOOLEAN);
263 asn1_read_uint8(data, &tmp);
270 return !data->has_error;
273 /* check a BOOLEAN */
274 BOOL asn1_check_BOOLEAN(struct asn1_data *data, BOOL v)
278 asn1_read_uint8(data, &b);
279 if (b != ASN1_BOOLEAN) {
280 data->has_error = True;
283 asn1_read_uint8(data, &b);
285 data->has_error = True;
288 return !data->has_error;
292 /* load a struct asn1_data structure with a lump of data, ready to be parsed */
293 BOOL asn1_load(struct asn1_data *data, DATA_BLOB blob)
296 data->data = talloc_memdup(NULL, blob.data, blob.length);
298 data->has_error = True;
301 data->length = blob.length;
305 /* Peek into an ASN1 buffer, not advancing the pointer */
306 BOOL asn1_peek(struct asn1_data *data, void *p, int len)
308 if (len < 0 || data->ofs + len < data->ofs || data->ofs + len < len)
311 if (data->ofs + len > data->length) {
312 /* we need to mark the buffer as consumed, so the caller knows
313 this was an out of data error, and not a decode error */
314 data->ofs = data->length;
318 memcpy(p, data->data + data->ofs, len);
322 /* read from a ASN1 buffer, advancing the buffer pointer */
323 BOOL asn1_read(struct asn1_data *data, void *p, int len)
325 if (!asn1_peek(data, p, len)) {
326 data->has_error = True;
334 /* read a uint8_t from a ASN1 buffer */
335 BOOL asn1_read_uint8(struct asn1_data *data, uint8_t *v)
337 return asn1_read(data, v, 1);
340 BOOL asn1_peek_uint8(struct asn1_data *data, uint8_t *v)
342 return asn1_peek(data, v, 1);
345 BOOL asn1_peek_tag(struct asn1_data *data, uint8_t tag)
349 if (asn1_tag_remaining(data) <= 0) {
353 if (!asn1_peek(data, &b, sizeof(b)))
359 /* start reading a nested asn1 structure */
360 BOOL asn1_start_tag(struct asn1_data *data, uint8_t tag)
363 struct nesting *nesting;
365 if (!asn1_read_uint8(data, &b))
369 data->has_error = True;
372 nesting = talloc(NULL, struct nesting);
374 data->has_error = True;
378 if (!asn1_read_uint8(data, &b)) {
384 if (!asn1_read_uint8(data, &b))
388 if (!asn1_read_uint8(data, &b))
390 nesting->taglen = (nesting->taglen << 8) | b;
396 nesting->start = data->ofs;
397 nesting->next = data->nesting;
398 data->nesting = nesting;
399 return !data->has_error;
403 /* stop reading a tag */
404 BOOL asn1_end_tag(struct asn1_data *data)
406 struct nesting *nesting;
408 /* make sure we read it all */
409 if (asn1_tag_remaining(data) != 0) {
410 data->has_error = True;
414 nesting = data->nesting;
417 data->has_error = True;
421 data->nesting = nesting->next;
422 talloc_free(nesting);
426 /* work out how many bytes are left in this nested tag */
427 int asn1_tag_remaining(struct asn1_data *data)
429 if (!data->nesting) {
430 data->has_error = True;
433 return data->nesting->taglen - (data->ofs - data->nesting->start);
436 /* read an object ID from a ASN1 buffer */
437 BOOL asn1_read_OID(struct asn1_data *data, const char **OID)
440 char *tmp_oid = NULL;
442 if (!asn1_start_tag(data, ASN1_OID)) return False;
443 asn1_read_uint8(data, &b);
445 tmp_oid = talloc_asprintf(NULL, "%u", b/40);
446 tmp_oid = talloc_asprintf_append(tmp_oid, " %u", b%40);
448 while (!data->has_error && asn1_tag_remaining(data) > 0) {
451 asn1_read_uint8(data, &b);
452 v = (v<<7) | (b&0x7f);
453 } while (!data->has_error && (b & 0x80));
454 tmp_oid = talloc_asprintf_append(tmp_oid, " %u", v);
459 *OID = talloc_strdup(NULL, tmp_oid);
460 talloc_free(tmp_oid);
462 return (*OID && !data->has_error);
465 /* check that the next object ID is correct */
466 BOOL asn1_check_OID(struct asn1_data *data, const char *OID)
470 if (!asn1_read_OID(data, &id)) return False;
472 if (strcmp(id, OID) != 0) {
473 data->has_error = True;
476 talloc_free(discard_const(id));
480 /* read a LDAPString from a ASN1 buffer */
481 BOOL asn1_read_LDAPString(struct asn1_data *data, char **s)
484 len = asn1_tag_remaining(data);
486 data->has_error = True;
489 *s = talloc_size(NULL, len+1);
491 data->has_error = True;
494 asn1_read(data, *s, len);
496 return !data->has_error;
500 /* read a GeneralString from a ASN1 buffer */
501 BOOL asn1_read_GeneralString(struct asn1_data *data, char **s)
503 if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return False;
504 if (!asn1_read_LDAPString(data, s)) return False;
505 return asn1_end_tag(data);
509 /* read a octet string blob */
510 BOOL asn1_read_OctetString(struct asn1_data *data, DATA_BLOB *blob)
514 if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
515 len = asn1_tag_remaining(data);
517 data->has_error = True;
520 *blob = data_blob(NULL, len+1);
521 asn1_read(data, blob->data, len);
526 if (data->has_error) {
527 data_blob_free(blob);
528 *blob = data_blob(NULL, 0);
534 BOOL asn1_read_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
538 if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(num))) return False;
539 len = asn1_tag_remaining(data);
541 data->has_error = True;
544 *blob = data_blob(NULL, len);
545 asn1_read(data, blob->data, len);
547 return !data->has_error;
550 /* read an interger without tag*/
551 BOOL asn1_read_implicit_Integer(struct asn1_data *data, int *i)
556 while (!data->has_error && asn1_tag_remaining(data)>0) {
557 if (!asn1_read_uint8(data, &b)) return False;
560 return !data->has_error;
564 /* read an interger */
565 BOOL asn1_read_Integer(struct asn1_data *data, int *i)
569 if (!asn1_start_tag(data, ASN1_INTEGER)) return False;
570 if (!asn1_read_implicit_Integer(data, i)) return False;
571 return asn1_end_tag(data);
574 /* read an interger */
575 BOOL asn1_read_enumerated(struct asn1_data *data, int *v)
579 if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
580 while (!data->has_error && asn1_tag_remaining(data)>0) {
582 asn1_read_uint8(data, &b);
585 return asn1_end_tag(data);
588 /* check a enumarted value is correct */
589 BOOL asn1_check_enumerated(struct asn1_data *data, int v)
592 if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
593 asn1_read_uint8(data, &b);
597 data->has_error = False;
599 return !data->has_error;
602 /* write an enumarted value to the stream */
603 BOOL asn1_write_enumerated(struct asn1_data *data, uint8_t v)
605 if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
606 asn1_write_uint8(data, v);
608 return !data->has_error;