root/lib/util/asn1.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. asn1_init
  2. asn1_free
  3. asn1_write
  4. asn1_write_uint8
  5. asn1_push_tag
  6. asn1_pop_tag
  7. push_int_bigendian
  8. asn1_write_implicit_Integer
  9. asn1_write_Integer
  10. ber_write_OID_String
  11. asn1_write_OID
  12. asn1_write_OctetString
  13. asn1_write_LDAPString
  14. asn1_write_DATA_BLOB_LDAPString
  15. asn1_write_GeneralString
  16. asn1_write_ContextSimple
  17. asn1_write_BOOLEAN
  18. asn1_read_BOOLEAN
  19. asn1_check_BOOLEAN
  20. asn1_load
  21. asn1_peek
  22. asn1_read
  23. asn1_read_uint8
  24. asn1_peek_uint8
  25. asn1_peek_tag
  26. asn1_start_tag
  27. asn1_end_tag
  28. asn1_tag_remaining
  29. ber_read_OID_String
  30. asn1_read_OID
  31. asn1_check_OID
  32. asn1_read_LDAPString
  33. asn1_read_GeneralString
  34. asn1_read_OctetString
  35. asn1_read_ContextSimple
  36. asn1_read_implicit_Integer
  37. asn1_read_Integer
  38. asn1_read_enumerated
  39. asn1_check_enumerated
  40. asn1_write_enumerated
  41. asn1_full_tag

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    simple ASN1 routines
   4    Copyright (C) Andrew Tridgell 2001
   5    
   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 3 of the License, or
   9    (at your option) any later version.
  10    
  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.
  15    
  16    You should have received a copy of the GNU General Public License
  17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19 
  20 #include "includes.h"
  21 #include "../lib/util/asn1.h"
  22 
  23 /* allocate an asn1 structure */
  24 struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
  25 {
  26         struct asn1_data *ret = talloc_zero(mem_ctx, struct asn1_data);
  27         if (ret == NULL) {
  28                 DEBUG(0,("asn1_init failed! out of memory\n"));
  29         }
  30         return ret;
  31 }
  32 
  33 /* free an asn1 structure */
  34 void asn1_free(struct asn1_data *data)
     /* [<][>][^][v][top][bottom][index][help] */
  35 {
  36         talloc_free(data);
  37 }
  38 
  39 /* write to the ASN1 buffer, advancing the buffer pointer */
  40 bool asn1_write(struct asn1_data *data, const void *p, int len)
     /* [<][>][^][v][top][bottom][index][help] */
  41 {
  42         if (data->has_error) return false;
  43         if (data->length < data->ofs+len) {
  44                 uint8_t *newp;
  45                 newp = talloc_realloc(data, data->data, uint8_t, data->ofs+len);
  46                 if (!newp) {
  47                         asn1_free(data);
  48                         data->has_error = true;
  49                         return false;
  50                 }
  51                 data->data = newp;
  52                 data->length = data->ofs+len;
  53         }
  54         memcpy(data->data + data->ofs, p, len);
  55         data->ofs += len;
  56         return true;
  57 }
  58 
  59 /* useful fn for writing a uint8_t */
  60 bool asn1_write_uint8(struct asn1_data *data, uint8_t v)
     /* [<][>][^][v][top][bottom][index][help] */
  61 {
  62         return asn1_write(data, &v, 1);
  63 }
  64 
  65 /* push a tag onto the asn1 data buffer. Used for nested structures */
  66 bool asn1_push_tag(struct asn1_data *data, uint8_t tag)
     /* [<][>][^][v][top][bottom][index][help] */
  67 {
  68         struct nesting *nesting;
  69 
  70         asn1_write_uint8(data, tag);
  71         nesting = talloc(data, struct nesting);
  72         if (!nesting) {
  73                 data->has_error = true;
  74                 return false;
  75         }
  76 
  77         nesting->start = data->ofs;
  78         nesting->next = data->nesting;
  79         data->nesting = nesting;
  80         return asn1_write_uint8(data, 0xff);
  81 }
  82 
  83 /* pop a tag */
  84 bool asn1_pop_tag(struct asn1_data *data)
     /* [<][>][^][v][top][bottom][index][help] */
  85 {
  86         struct nesting *nesting;
  87         size_t len;
  88 
  89         nesting = data->nesting;
  90 
  91         if (!nesting) {
  92                 data->has_error = true;
  93                 return false;
  94         }
  95         len = data->ofs - (nesting->start+1);
  96         /* yes, this is ugly. We don't know in advance how many bytes the length
  97            of a tag will take, so we assumed 1 byte. If we were wrong then we 
  98            need to correct our mistake */
  99         if (len > 0xFFFFFF) {
 100                 data->data[nesting->start] = 0x84;
 101                 if (!asn1_write_uint8(data, 0)) return false;
 102                 if (!asn1_write_uint8(data, 0)) return false;
 103                 if (!asn1_write_uint8(data, 0)) return false;
 104                 if (!asn1_write_uint8(data, 0)) return false;
 105                 memmove(data->data+nesting->start+5, data->data+nesting->start+1, len);
 106                 data->data[nesting->start+1] = (len>>24) & 0xFF;
 107                 data->data[nesting->start+2] = (len>>16) & 0xFF;
 108                 data->data[nesting->start+3] = (len>>8) & 0xFF;
 109                 data->data[nesting->start+4] = len&0xff;
 110         } else if (len > 0xFFFF) {
 111                 data->data[nesting->start] = 0x83;
 112                 if (!asn1_write_uint8(data, 0)) return false;
 113                 if (!asn1_write_uint8(data, 0)) return false;
 114                 if (!asn1_write_uint8(data, 0)) return false;
 115                 memmove(data->data+nesting->start+4, data->data+nesting->start+1, len);
 116                 data->data[nesting->start+1] = (len>>16) & 0xFF;
 117                 data->data[nesting->start+2] = (len>>8) & 0xFF;
 118                 data->data[nesting->start+3] = len&0xff;
 119         } else if (len > 255) {
 120                 data->data[nesting->start] = 0x82;
 121                 if (!asn1_write_uint8(data, 0)) return false;
 122                 if (!asn1_write_uint8(data, 0)) return false;
 123                 memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
 124                 data->data[nesting->start+1] = len>>8;
 125                 data->data[nesting->start+2] = len&0xff;
 126         } else if (len > 127) {
 127                 data->data[nesting->start] = 0x81;
 128                 if (!asn1_write_uint8(data, 0)) return false;
 129                 memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
 130                 data->data[nesting->start+1] = len;
 131         } else {
 132                 data->data[nesting->start] = len;
 133         }
 134 
 135         data->nesting = nesting->next;
 136         talloc_free(nesting);
 137         return true;
 138 }
 139 
 140 /* "i" is the one's complement representation, as is the normal result of an
 141  * implicit signed->unsigned conversion */
 142 
 143 static bool push_int_bigendian(struct asn1_data *data, unsigned int i, bool negative)
     /* [<][>][^][v][top][bottom][index][help] */
 144 {
 145         uint8_t lowest = i & 0xFF;
 146 
 147         i = i >> 8;
 148         if (i != 0)
 149                 if (!push_int_bigendian(data, i, negative))
 150                         return false;
 151 
 152         if (data->nesting->start+1 == data->ofs) {
 153 
 154                 /* We did not write anything yet, looking at the highest
 155                  * valued byte */
 156 
 157                 if (negative) {
 158                         /* Don't write leading 0xff's */
 159                         if (lowest == 0xFF)
 160                                 return true;
 161 
 162                         if ((lowest & 0x80) == 0) {
 163                                 /* The only exception for a leading 0xff is if
 164                                  * the highest bit is 0, which would indicate
 165                                  * a positive value */
 166                                 if (!asn1_write_uint8(data, 0xff))
 167                                         return false;
 168                         }
 169                 } else {
 170                         if (lowest & 0x80) {
 171                                 /* The highest bit of a positive integer is 1,
 172                                  * this would indicate a negative number. Push
 173                                  * a 0 to indicate a positive one */
 174                                 if (!asn1_write_uint8(data, 0))
 175                                         return false;
 176                         }
 177                 }
 178         }
 179 
 180         return asn1_write_uint8(data, lowest);
 181 }
 182 
 183 /* write an Integer without the tag framing. Needed for example for the LDAP
 184  * Abandon Operation */
 185 
 186 bool asn1_write_implicit_Integer(struct asn1_data *data, int i)
     /* [<][>][^][v][top][bottom][index][help] */
 187 {
 188         if (i == -1) {
 189                 /* -1 is special as it consists of all-0xff bytes. In
 190                     push_int_bigendian this is the only case that is not
 191                     properly handled, as all 0xff bytes would be handled as
 192                     leading ones to be ignored. */
 193                 return asn1_write_uint8(data, 0xff);
 194         } else {
 195                 return push_int_bigendian(data, i, i<0);
 196         }
 197 }
 198 
 199 
 200 /* write an integer */
 201 bool asn1_write_Integer(struct asn1_data *data, int i)
     /* [<][>][^][v][top][bottom][index][help] */
 202 {
 203         if (!asn1_push_tag(data, ASN1_INTEGER)) return false;
 204         if (!asn1_write_implicit_Integer(data, i)) return false;
 205         return asn1_pop_tag(data);
 206 }
 207 
 208 bool ber_write_OID_String(DATA_BLOB *blob, const char *OID)
     /* [<][>][^][v][top][bottom][index][help] */
 209 {
 210         uint_t v, v2;
 211         const char *p = (const char *)OID;
 212         char *newp;
 213         int i;
 214 
 215         v = strtoul(p, &newp, 10);
 216         if (newp[0] != '.') return false;
 217         p = newp + 1;
 218 
 219         v2 = strtoul(p, &newp, 10);
 220         if (newp[0] != '.') return false;
 221         p = newp + 1;
 222 
 223         /*the ber representation can't use more space then the string one */
 224         *blob = data_blob(NULL, strlen(OID));
 225         if (!blob->data) return false;
 226 
 227         blob->data[0] = 40*v + v2;
 228 
 229         i = 1;
 230         while (*p) {
 231                 v = strtoul(p, &newp, 10);
 232                 if (newp[0] == '.') {
 233                         p = newp + 1;
 234                 } else if (newp[0] == '\0') {
 235                         p = newp;
 236                 } else {
 237                         data_blob_free(blob);
 238                         return false;
 239                 }
 240                 if (v >= (1<<28)) blob->data[i++] = (0x80 | ((v>>28)&0x7f));
 241                 if (v >= (1<<21)) blob->data[i++] = (0x80 | ((v>>21)&0x7f));
 242                 if (v >= (1<<14)) blob->data[i++] = (0x80 | ((v>>14)&0x7f));
 243                 if (v >= (1<<7)) blob->data[i++] = (0x80 | ((v>>7)&0x7f));
 244                 blob->data[i++] = (v&0x7f);
 245         }
 246 
 247         blob->length = i;
 248 
 249         return true;
 250 }
 251 
 252 /* write an object ID to a ASN1 buffer */
 253 bool asn1_write_OID(struct asn1_data *data, const char *OID)
     /* [<][>][^][v][top][bottom][index][help] */
 254 {
 255         DATA_BLOB blob;
 256 
 257         if (!asn1_push_tag(data, ASN1_OID)) return false;
 258 
 259         if (!ber_write_OID_String(&blob, OID)) {
 260                 data->has_error = true;
 261                 return false;
 262         }
 263 
 264         if (!asn1_write(data, blob.data, blob.length)) {
 265                 data->has_error = true;
 266                 return false;
 267         }
 268         data_blob_free(&blob);
 269         return asn1_pop_tag(data);
 270 }
 271 
 272 /* write an octet string */
 273 bool asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length)
     /* [<][>][^][v][top][bottom][index][help] */
 274 {
 275         asn1_push_tag(data, ASN1_OCTET_STRING);
 276         asn1_write(data, p, length);
 277         asn1_pop_tag(data);
 278         return !data->has_error;
 279 }
 280 
 281 /* write a LDAP string */
 282 bool asn1_write_LDAPString(struct asn1_data *data, const char *s)
     /* [<][>][^][v][top][bottom][index][help] */
 283 {
 284         asn1_write(data, s, strlen(s));
 285         return !data->has_error;
 286 }
 287 
 288 /* write a LDAP string from a DATA_BLOB */
 289 bool asn1_write_DATA_BLOB_LDAPString(struct asn1_data *data, const DATA_BLOB *s)
     /* [<][>][^][v][top][bottom][index][help] */
 290 {
 291         asn1_write(data, s->data, s->length);
 292         return !data->has_error;
 293 }
 294 
 295 /* write a general string */
 296 bool asn1_write_GeneralString(struct asn1_data *data, const char *s)
     /* [<][>][^][v][top][bottom][index][help] */
 297 {
 298         asn1_push_tag(data, ASN1_GENERAL_STRING);
 299         asn1_write_LDAPString(data, s);
 300         asn1_pop_tag(data);
 301         return !data->has_error;
 302 }
 303 
 304 bool asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
     /* [<][>][^][v][top][bottom][index][help] */
 305 {
 306         asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(num));
 307         asn1_write(data, blob->data, blob->length);
 308         asn1_pop_tag(data);
 309         return !data->has_error;
 310 }
 311 
 312 /* write a BOOLEAN */
 313 bool asn1_write_BOOLEAN(struct asn1_data *data, bool v)
     /* [<][>][^][v][top][bottom][index][help] */
 314 {
 315         asn1_push_tag(data, ASN1_BOOLEAN);
 316         asn1_write_uint8(data, v ? 0xFF : 0);
 317         asn1_pop_tag(data);
 318         return !data->has_error;
 319 }
 320 
 321 bool asn1_read_BOOLEAN(struct asn1_data *data, bool *v)
     /* [<][>][^][v][top][bottom][index][help] */
 322 {
 323         uint8_t tmp = 0;
 324         asn1_start_tag(data, ASN1_BOOLEAN);
 325         asn1_read_uint8(data, &tmp);
 326         if (tmp == 0xFF) {
 327                 *v = true;
 328         } else {
 329                 *v = false;
 330         }
 331         asn1_end_tag(data);
 332         return !data->has_error;
 333 }
 334 
 335 /* check a BOOLEAN */
 336 bool asn1_check_BOOLEAN(struct asn1_data *data, bool v)
     /* [<][>][^][v][top][bottom][index][help] */
 337 {
 338         uint8_t b = 0;
 339 
 340         asn1_read_uint8(data, &b);
 341         if (b != ASN1_BOOLEAN) {
 342                 data->has_error = true;
 343                 return false;
 344         }
 345         asn1_read_uint8(data, &b);
 346         if (b != v) {
 347                 data->has_error = true;
 348                 return false;
 349         }
 350         return !data->has_error;
 351 }
 352 
 353 
 354 /* load a struct asn1_data structure with a lump of data, ready to be parsed */
 355 bool asn1_load(struct asn1_data *data, DATA_BLOB blob)
     /* [<][>][^][v][top][bottom][index][help] */
 356 {
 357         ZERO_STRUCTP(data);
 358         data->data = (uint8_t *)talloc_memdup(data, blob.data, blob.length);
 359         if (!data->data) {
 360                 data->has_error = true;
 361                 return false;
 362         }
 363         data->length = blob.length;
 364         return true;
 365 }
 366 
 367 /* Peek into an ASN1 buffer, not advancing the pointer */
 368 bool asn1_peek(struct asn1_data *data, void *p, int len)
     /* [<][>][^][v][top][bottom][index][help] */
 369 {
 370         if (data->has_error)
 371                 return false;
 372 
 373         if (len < 0 || data->ofs + len < data->ofs || data->ofs + len < len)
 374                 return false;
 375 
 376         if (data->ofs + len > data->length) {
 377                 /* we need to mark the buffer as consumed, so the caller knows
 378                    this was an out of data error, and not a decode error */
 379                 data->ofs = data->length;
 380                 return false;
 381         }
 382 
 383         memcpy(p, data->data + data->ofs, len);
 384         return true;
 385 }
 386 
 387 /* read from a ASN1 buffer, advancing the buffer pointer */
 388 bool asn1_read(struct asn1_data *data, void *p, int len)
     /* [<][>][^][v][top][bottom][index][help] */
 389 {
 390         if (!asn1_peek(data, p, len)) {
 391                 data->has_error = true;
 392                 return false;
 393         }
 394 
 395         data->ofs += len;
 396         return true;
 397 }
 398 
 399 /* read a uint8_t from a ASN1 buffer */
 400 bool asn1_read_uint8(struct asn1_data *data, uint8_t *v)
     /* [<][>][^][v][top][bottom][index][help] */
 401 {
 402         return asn1_read(data, v, 1);
 403 }
 404 
 405 bool asn1_peek_uint8(struct asn1_data *data, uint8_t *v)
     /* [<][>][^][v][top][bottom][index][help] */
 406 {
 407         return asn1_peek(data, v, 1);
 408 }
 409 
 410 bool asn1_peek_tag(struct asn1_data *data, uint8_t tag)
     /* [<][>][^][v][top][bottom][index][help] */
 411 {
 412         uint8_t b;
 413 
 414         if (asn1_tag_remaining(data) <= 0) {
 415                 return false;
 416         }
 417 
 418         if (!asn1_peek_uint8(data, &b))
 419                 return false;
 420 
 421         return (b == tag);
 422 }
 423 
 424 /* start reading a nested asn1 structure */
 425 bool asn1_start_tag(struct asn1_data *data, uint8_t tag)
     /* [<][>][^][v][top][bottom][index][help] */
 426 {
 427         uint8_t b;
 428         struct nesting *nesting;
 429         
 430         if (!asn1_read_uint8(data, &b))
 431                 return false;
 432 
 433         if (b != tag) {
 434                 data->has_error = true;
 435                 return false;
 436         }
 437         nesting = talloc(data, struct nesting);
 438         if (!nesting) {
 439                 data->has_error = true;
 440                 return false;
 441         }
 442 
 443         if (!asn1_read_uint8(data, &b)) {
 444                 return false;
 445         }
 446 
 447         if (b & 0x80) {
 448                 int n = b & 0x7f;
 449                 if (!asn1_read_uint8(data, &b))
 450                         return false;
 451                 nesting->taglen = b;
 452                 while (n > 1) {
 453                         if (!asn1_read_uint8(data, &b)) 
 454                                 return false;
 455                         nesting->taglen = (nesting->taglen << 8) | b;
 456                         n--;
 457                 }
 458         } else {
 459                 nesting->taglen = b;
 460         }
 461         nesting->start = data->ofs;
 462         nesting->next = data->nesting;
 463         data->nesting = nesting;
 464         if (asn1_tag_remaining(data) == -1) {
 465                 return false;
 466         }
 467         return !data->has_error;
 468 }
 469 
 470 /* stop reading a tag */
 471 bool asn1_end_tag(struct asn1_data *data)
     /* [<][>][^][v][top][bottom][index][help] */
 472 {
 473         struct nesting *nesting;
 474 
 475         /* make sure we read it all */
 476         if (asn1_tag_remaining(data) != 0) {
 477                 data->has_error = true;
 478                 return false;
 479         }
 480 
 481         nesting = data->nesting;
 482 
 483         if (!nesting) {
 484                 data->has_error = true;
 485                 return false;
 486         }
 487 
 488         data->nesting = nesting->next;
 489         talloc_free(nesting);
 490         return true;
 491 }
 492 
 493 /* work out how many bytes are left in this nested tag */
 494 int asn1_tag_remaining(struct asn1_data *data)
     /* [<][>][^][v][top][bottom][index][help] */
 495 {
 496         int remaining;
 497         if (data->has_error) {
 498                 return -1;
 499         }
 500 
 501         if (!data->nesting) {
 502                 data->has_error = true;
 503                 return -1;
 504         }
 505         remaining = data->nesting->taglen - (data->ofs - data->nesting->start);
 506         if (remaining > (data->length - data->ofs)) {
 507                 data->has_error = true;
 508                 return -1;
 509         }
 510         return remaining;
 511 }
 512 
 513 /* read an object ID from a data blob */
 514 bool ber_read_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB blob, const char **OID)
     /* [<][>][^][v][top][bottom][index][help] */
 515 {
 516         int i;
 517         uint8_t *b;
 518         uint_t v;
 519         char *tmp_oid = NULL;
 520 
 521         if (blob.length < 2) return false;
 522 
 523         b = blob.data;
 524 
 525         tmp_oid = talloc_asprintf(mem_ctx, "%u",  b[0]/40);
 526         if (!tmp_oid) goto nomem;
 527         tmp_oid = talloc_asprintf_append_buffer(tmp_oid, ".%u",  b[0]%40);
 528         if (!tmp_oid) goto nomem;
 529 
 530         for(i = 1, v = 0; i < blob.length; i++) {
 531                 v = (v<<7) | (b[i]&0x7f);
 532                 if ( ! (b[i] & 0x80)) {
 533                         tmp_oid = talloc_asprintf_append_buffer(tmp_oid, ".%u",  v);
 534                         v = 0;
 535                 }
 536                 if (!tmp_oid) goto nomem;
 537         }
 538 
 539         if (v != 0) {
 540                 talloc_free(tmp_oid);
 541                 return false;
 542         }
 543 
 544         *OID = tmp_oid;
 545         return true;
 546 
 547 nomem:  
 548         return false;
 549 }
 550 
 551 /* read an object ID from a ASN1 buffer */
 552 bool asn1_read_OID(struct asn1_data *data, TALLOC_CTX *mem_ctx, const char **OID)
     /* [<][>][^][v][top][bottom][index][help] */
 553 {
 554         DATA_BLOB blob;
 555         int len;
 556 
 557         if (!asn1_start_tag(data, ASN1_OID)) return false;
 558 
 559         len = asn1_tag_remaining(data);
 560         if (len < 0) {
 561                 data->has_error = true;
 562                 return false;
 563         }
 564 
 565         blob = data_blob(NULL, len);
 566         if (!blob.data) {
 567                 data->has_error = true;
 568                 return false;
 569         }
 570 
 571         asn1_read(data, blob.data, len);
 572         asn1_end_tag(data);
 573         if (data->has_error) {
 574                 data_blob_free(&blob);
 575                 return false;
 576         }
 577 
 578         if (!ber_read_OID_String(mem_ctx, blob, OID)) {
 579                 data->has_error = true;
 580                 data_blob_free(&blob);
 581                 return false;
 582         }
 583 
 584         data_blob_free(&blob);
 585         return true;
 586 }
 587 
 588 /* check that the next object ID is correct */
 589 bool asn1_check_OID(struct asn1_data *data, const char *OID)
     /* [<][>][^][v][top][bottom][index][help] */
 590 {
 591         const char *id;
 592 
 593         if (!asn1_read_OID(data, data, &id)) return false;
 594 
 595         if (strcmp(id, OID) != 0) {
 596                 talloc_free(discard_const(id));
 597                 data->has_error = true;
 598                 return false;
 599         }
 600         talloc_free(discard_const(id));
 601         return true;
 602 }
 603 
 604 /* read a LDAPString from a ASN1 buffer */
 605 bool asn1_read_LDAPString(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **s)
     /* [<][>][^][v][top][bottom][index][help] */
 606 {
 607         int len;
 608         len = asn1_tag_remaining(data);
 609         if (len < 0) {
 610                 data->has_error = true;
 611                 return false;
 612         }
 613         *s = talloc_array(mem_ctx, char, len+1);
 614         if (! *s) {
 615                 data->has_error = true;
 616                 return false;
 617         }
 618         asn1_read(data, *s, len);
 619         (*s)[len] = 0;
 620         return !data->has_error;
 621 }
 622 
 623 
 624 /* read a GeneralString from a ASN1 buffer */
 625 bool asn1_read_GeneralString(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **s)
     /* [<][>][^][v][top][bottom][index][help] */
 626 {
 627         if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return false;
 628         if (!asn1_read_LDAPString(data, mem_ctx, s)) return false;
 629         return asn1_end_tag(data);
 630 }
 631 
 632 
 633 /* read a octet string blob */
 634 bool asn1_read_OctetString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
     /* [<][>][^][v][top][bottom][index][help] */
 635 {
 636         int len;
 637         ZERO_STRUCTP(blob);
 638         if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return false;
 639         len = asn1_tag_remaining(data);
 640         if (len < 0) {
 641                 data->has_error = true;
 642                 return false;
 643         }
 644         *blob = data_blob_talloc(mem_ctx, NULL, len+1);
 645         if (!blob->data) {
 646                 data->has_error = true;
 647                 return false;
 648         }
 649         asn1_read(data, blob->data, len);
 650         asn1_end_tag(data);
 651         blob->length--;
 652         blob->data[len] = 0;
 653         
 654         if (data->has_error) {
 655                 data_blob_free(blob);
 656                 *blob = data_blob(NULL, 0);
 657                 return false;
 658         }
 659         return true;
 660 }
 661 
 662 bool asn1_read_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob)
     /* [<][>][^][v][top][bottom][index][help] */
 663 {
 664         int len;
 665         ZERO_STRUCTP(blob);
 666         if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(num))) return false;
 667         len = asn1_tag_remaining(data);
 668         if (len < 0) {
 669                 data->has_error = true;
 670                 return false;
 671         }
 672         *blob = data_blob(NULL, len);
 673         if ((len != 0) && (!blob->data)) {
 674                 data->has_error = true;
 675                 return false;
 676         }
 677         asn1_read(data, blob->data, len);
 678         asn1_end_tag(data);
 679         return !data->has_error;
 680 }
 681 
 682 /* read an integer without tag*/
 683 bool asn1_read_implicit_Integer(struct asn1_data *data, int *i)
     /* [<][>][^][v][top][bottom][index][help] */
 684 {
 685         uint8_t b;
 686         *i = 0;
 687 
 688         while (!data->has_error && asn1_tag_remaining(data)>0) {
 689                 if (!asn1_read_uint8(data, &b)) return false;
 690                 *i = (*i << 8) + b;
 691         }
 692         return !data->has_error;        
 693         
 694 }
 695 
 696 /* read an integer */
 697 bool asn1_read_Integer(struct asn1_data *data, int *i)
     /* [<][>][^][v][top][bottom][index][help] */
 698 {
 699         *i = 0;
 700 
 701         if (!asn1_start_tag(data, ASN1_INTEGER)) return false;
 702         if (!asn1_read_implicit_Integer(data, i)) return false;
 703         return asn1_end_tag(data);      
 704 }
 705 
 706 /* read an integer */
 707 bool asn1_read_enumerated(struct asn1_data *data, int *v)
     /* [<][>][^][v][top][bottom][index][help] */
 708 {
 709         *v = 0;
 710         
 711         if (!asn1_start_tag(data, ASN1_ENUMERATED)) return false;
 712         while (!data->has_error && asn1_tag_remaining(data)>0) {
 713                 uint8_t b;
 714                 asn1_read_uint8(data, &b);
 715                 *v = (*v << 8) + b;
 716         }
 717         return asn1_end_tag(data);      
 718 }
 719 
 720 /* check a enumerated value is correct */
 721 bool asn1_check_enumerated(struct asn1_data *data, int v)
     /* [<][>][^][v][top][bottom][index][help] */
 722 {
 723         uint8_t b;
 724         if (!asn1_start_tag(data, ASN1_ENUMERATED)) return false;
 725         asn1_read_uint8(data, &b);
 726         asn1_end_tag(data);
 727 
 728         if (v != b)
 729                 data->has_error = false;
 730 
 731         return !data->has_error;
 732 }
 733 
 734 /* write an enumerated value to the stream */
 735 bool asn1_write_enumerated(struct asn1_data *data, uint8_t v)
     /* [<][>][^][v][top][bottom][index][help] */
 736 {
 737         if (!asn1_push_tag(data, ASN1_ENUMERATED)) return false;
 738         asn1_write_uint8(data, v);
 739         asn1_pop_tag(data);
 740         return !data->has_error;
 741 }
 742 
 743 /*
 744   check if a ASN.1 blob is a full tag
 745 */
 746 NTSTATUS asn1_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
     /* [<][>][^][v][top][bottom][index][help] */
 747 {
 748         struct asn1_data *asn1 = asn1_init(NULL);
 749         int size;
 750 
 751         NT_STATUS_HAVE_NO_MEMORY(asn1);
 752 
 753         asn1->data = blob.data;
 754         asn1->length = blob.length;
 755         asn1_start_tag(asn1, tag);
 756         if (asn1->has_error) {
 757                 talloc_free(asn1);
 758                 return STATUS_MORE_ENTRIES;
 759         }
 760         size = asn1_tag_remaining(asn1) + asn1->ofs;
 761 
 762         talloc_free(asn1);
 763 
 764         if (size > blob.length) {
 765                 return STATUS_MORE_ENTRIES;
 766         }               
 767 
 768         *packet_size = size;
 769         return NT_STATUS_OK;
 770 }

/* [<][>][^][v][top][bottom][index][help] */