security/nss/lib/util/secasn1d.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * Support for DEcoding ASN.1 data based on BER/DER (Basic/Distinguished
michael@0 7 * Encoding Rules).
michael@0 8 */
michael@0 9
michael@0 10 /* #define DEBUG_ASN1D_STATES 1 */
michael@0 11
michael@0 12 #ifdef DEBUG_ASN1D_STATES
michael@0 13 #include <stdio.h>
michael@0 14 #define PR_Assert sec_asn1d_Assert
michael@0 15 #endif
michael@0 16
michael@0 17 #include "secasn1.h"
michael@0 18 #include "secerr.h"
michael@0 19
michael@0 20 typedef enum {
michael@0 21 beforeIdentifier,
michael@0 22 duringIdentifier,
michael@0 23 afterIdentifier,
michael@0 24 beforeLength,
michael@0 25 duringLength,
michael@0 26 afterLength,
michael@0 27 beforeBitString,
michael@0 28 duringBitString,
michael@0 29 duringConstructedString,
michael@0 30 duringGroup,
michael@0 31 duringLeaf,
michael@0 32 duringSaveEncoding,
michael@0 33 duringSequence,
michael@0 34 afterConstructedString,
michael@0 35 afterGroup,
michael@0 36 afterExplicit,
michael@0 37 afterImplicit,
michael@0 38 afterInline,
michael@0 39 afterPointer,
michael@0 40 afterSaveEncoding,
michael@0 41 beforeEndOfContents,
michael@0 42 duringEndOfContents,
michael@0 43 afterEndOfContents,
michael@0 44 beforeChoice,
michael@0 45 duringChoice,
michael@0 46 afterChoice,
michael@0 47 notInUse
michael@0 48 } sec_asn1d_parse_place;
michael@0 49
michael@0 50 #ifdef DEBUG_ASN1D_STATES
michael@0 51 static const char * const place_names[] = {
michael@0 52 "beforeIdentifier",
michael@0 53 "duringIdentifier",
michael@0 54 "afterIdentifier",
michael@0 55 "beforeLength",
michael@0 56 "duringLength",
michael@0 57 "afterLength",
michael@0 58 "beforeBitString",
michael@0 59 "duringBitString",
michael@0 60 "duringConstructedString",
michael@0 61 "duringGroup",
michael@0 62 "duringLeaf",
michael@0 63 "duringSaveEncoding",
michael@0 64 "duringSequence",
michael@0 65 "afterConstructedString",
michael@0 66 "afterGroup",
michael@0 67 "afterExplicit",
michael@0 68 "afterImplicit",
michael@0 69 "afterInline",
michael@0 70 "afterPointer",
michael@0 71 "afterSaveEncoding",
michael@0 72 "beforeEndOfContents",
michael@0 73 "duringEndOfContents",
michael@0 74 "afterEndOfContents",
michael@0 75 "beforeChoice",
michael@0 76 "duringChoice",
michael@0 77 "afterChoice",
michael@0 78 "notInUse"
michael@0 79 };
michael@0 80
michael@0 81 static const char * const class_names[] = {
michael@0 82 "UNIVERSAL",
michael@0 83 "APPLICATION",
michael@0 84 "CONTEXT_SPECIFIC",
michael@0 85 "PRIVATE"
michael@0 86 };
michael@0 87
michael@0 88 static const char * const method_names[] = { "PRIMITIVE", "CONSTRUCTED" };
michael@0 89
michael@0 90 static const char * const type_names[] = {
michael@0 91 "END_OF_CONTENTS",
michael@0 92 "BOOLEAN",
michael@0 93 "INTEGER",
michael@0 94 "BIT_STRING",
michael@0 95 "OCTET_STRING",
michael@0 96 "NULL",
michael@0 97 "OBJECT_ID",
michael@0 98 "OBJECT_DESCRIPTOR",
michael@0 99 "(type 08)",
michael@0 100 "REAL",
michael@0 101 "ENUMERATED",
michael@0 102 "EMBEDDED",
michael@0 103 "UTF8_STRING",
michael@0 104 "(type 0d)",
michael@0 105 "(type 0e)",
michael@0 106 "(type 0f)",
michael@0 107 "SEQUENCE",
michael@0 108 "SET",
michael@0 109 "NUMERIC_STRING",
michael@0 110 "PRINTABLE_STRING",
michael@0 111 "T61_STRING",
michael@0 112 "VIDEOTEXT_STRING",
michael@0 113 "IA5_STRING",
michael@0 114 "UTC_TIME",
michael@0 115 "GENERALIZED_TIME",
michael@0 116 "GRAPHIC_STRING",
michael@0 117 "VISIBLE_STRING",
michael@0 118 "GENERAL_STRING",
michael@0 119 "UNIVERSAL_STRING",
michael@0 120 "(type 1d)",
michael@0 121 "BMP_STRING",
michael@0 122 "HIGH_TAG_VALUE"
michael@0 123 };
michael@0 124
michael@0 125 static const char * const flag_names[] = { /* flags, right to left */
michael@0 126 "OPTIONAL",
michael@0 127 "EXPLICIT",
michael@0 128 "ANY",
michael@0 129 "INLINE",
michael@0 130 "POINTER",
michael@0 131 "GROUP",
michael@0 132 "DYNAMIC",
michael@0 133 "SKIP",
michael@0 134 "INNER",
michael@0 135 "SAVE",
michael@0 136 "", /* decoder ignores "MAY_STREAM", */
michael@0 137 "SKIP_REST",
michael@0 138 "CHOICE",
michael@0 139 "NO_STREAM",
michael@0 140 "DEBUG_BREAK",
michael@0 141 "unknown 08",
michael@0 142 "unknown 10",
michael@0 143 "unknown 20",
michael@0 144 "unknown 40",
michael@0 145 "unknown 80"
michael@0 146 };
michael@0 147
michael@0 148 static int /* bool */
michael@0 149 formatKind(unsigned long kind, char * buf)
michael@0 150 {
michael@0 151 int i;
michael@0 152 unsigned long k = kind & SEC_ASN1_TAGNUM_MASK;
michael@0 153 unsigned long notag = kind & (SEC_ASN1_CHOICE | SEC_ASN1_POINTER |
michael@0 154 SEC_ASN1_INLINE | SEC_ASN1_ANY | SEC_ASN1_SAVE);
michael@0 155
michael@0 156 buf[0] = 0;
michael@0 157 if ((kind & SEC_ASN1_CLASS_MASK) != SEC_ASN1_UNIVERSAL) {
michael@0 158 sprintf(buf, " %s", class_names[(kind & SEC_ASN1_CLASS_MASK) >> 6] );
michael@0 159 buf += strlen(buf);
michael@0 160 }
michael@0 161 if (kind & SEC_ASN1_METHOD_MASK) {
michael@0 162 sprintf(buf, " %s", method_names[1]);
michael@0 163 buf += strlen(buf);
michael@0 164 }
michael@0 165 if ((kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL) {
michael@0 166 if (k || !notag) {
michael@0 167 sprintf(buf, " %s", type_names[k] );
michael@0 168 if ((k == SEC_ASN1_SET || k == SEC_ASN1_SEQUENCE) &&
michael@0 169 (kind & SEC_ASN1_GROUP)) {
michael@0 170 buf += strlen(buf);
michael@0 171 sprintf(buf, "_OF");
michael@0 172 }
michael@0 173 }
michael@0 174 } else {
michael@0 175 sprintf(buf, " [%d]", k);
michael@0 176 }
michael@0 177 buf += strlen(buf);
michael@0 178
michael@0 179 for (k = kind >> 8, i = 0; k; k >>= 1, ++i) {
michael@0 180 if (k & 1) {
michael@0 181 sprintf(buf, " %s", flag_names[i]);
michael@0 182 buf += strlen(buf);
michael@0 183 }
michael@0 184 }
michael@0 185 return notag != 0;
michael@0 186 }
michael@0 187
michael@0 188 #endif /* DEBUG_ASN1D_STATES */
michael@0 189
michael@0 190 typedef enum {
michael@0 191 allDone,
michael@0 192 decodeError,
michael@0 193 keepGoing,
michael@0 194 needBytes
michael@0 195 } sec_asn1d_parse_status;
michael@0 196
michael@0 197 struct subitem {
michael@0 198 const void *data;
michael@0 199 unsigned long len; /* only used for substrings */
michael@0 200 struct subitem *next;
michael@0 201 };
michael@0 202
michael@0 203 typedef struct sec_asn1d_state_struct {
michael@0 204 SEC_ASN1DecoderContext *top;
michael@0 205 const SEC_ASN1Template *theTemplate;
michael@0 206 void *dest;
michael@0 207
michael@0 208 void *our_mark; /* free on completion */
michael@0 209
michael@0 210 struct sec_asn1d_state_struct *parent; /* aka prev */
michael@0 211 struct sec_asn1d_state_struct *child; /* aka next */
michael@0 212
michael@0 213 sec_asn1d_parse_place place;
michael@0 214
michael@0 215 /*
michael@0 216 * XXX explain the next fields as clearly as possible...
michael@0 217 */
michael@0 218 unsigned char found_tag_modifiers;
michael@0 219 unsigned char expect_tag_modifiers;
michael@0 220 unsigned long check_tag_mask;
michael@0 221 unsigned long found_tag_number;
michael@0 222 unsigned long expect_tag_number;
michael@0 223 unsigned long underlying_kind;
michael@0 224
michael@0 225 unsigned long contents_length;
michael@0 226 unsigned long pending;
michael@0 227 unsigned long consumed;
michael@0 228
michael@0 229 int depth;
michael@0 230
michael@0 231 /*
michael@0 232 * Bit strings have their length adjusted -- the first octet of the
michael@0 233 * contents contains a value between 0 and 7 which says how many bits
michael@0 234 * at the end of the octets are not actually part of the bit string;
michael@0 235 * when parsing bit strings we put that value here because we need it
michael@0 236 * later, for adjustment of the length (when the whole string is done).
michael@0 237 */
michael@0 238 unsigned int bit_string_unused_bits;
michael@0 239
michael@0 240 /*
michael@0 241 * The following are used for indefinite-length constructed strings.
michael@0 242 */
michael@0 243 struct subitem *subitems_head;
michael@0 244 struct subitem *subitems_tail;
michael@0 245
michael@0 246 PRPackedBool
michael@0 247 allocate, /* when true, need to allocate the destination */
michael@0 248 endofcontents, /* this state ended up parsing end-of-contents octets */
michael@0 249 explicit, /* we are handling an explicit header */
michael@0 250 indefinite, /* the current item has indefinite-length encoding */
michael@0 251 missing, /* an optional field that was not present */
michael@0 252 optional, /* the template says this field may be omitted */
michael@0 253 substring; /* this is a substring of a constructed string */
michael@0 254
michael@0 255 } sec_asn1d_state;
michael@0 256
michael@0 257 #define IS_HIGH_TAG_NUMBER(n) ((n) == SEC_ASN1_HIGH_TAG_NUMBER)
michael@0 258 #define LAST_TAG_NUMBER_BYTE(b) (((b) & 0x80) == 0)
michael@0 259 #define TAG_NUMBER_BITS 7
michael@0 260 #define TAG_NUMBER_MASK 0x7f
michael@0 261
michael@0 262 #define LENGTH_IS_SHORT_FORM(b) (((b) & 0x80) == 0)
michael@0 263 #define LONG_FORM_LENGTH(b) ((b) & 0x7f)
michael@0 264
michael@0 265 #define HIGH_BITS(field,cnt) ((field) >> ((sizeof(field) * 8) - (cnt)))
michael@0 266
michael@0 267
michael@0 268 /*
michael@0 269 * An "outsider" will have an opaque pointer to this, created by calling
michael@0 270 * SEC_ASN1DecoderStart(). It will be passed back in to all subsequent
michael@0 271 * calls to SEC_ASN1DecoderUpdate(), and when done it is passed to
michael@0 272 * SEC_ASN1DecoderFinish().
michael@0 273 */
michael@0 274 struct sec_DecoderContext_struct {
michael@0 275 PLArenaPool *our_pool; /* for our internal allocs */
michael@0 276 PLArenaPool *their_pool; /* for destination structure allocs */
michael@0 277 #ifdef SEC_ASN1D_FREE_ON_ERROR /*
michael@0 278 * XXX see comment below (by same
michael@0 279 * ifdef) that explains why this
michael@0 280 * does not work (need more smarts
michael@0 281 * in order to free back to mark)
michael@0 282 */
michael@0 283 /*
michael@0 284 * XXX how to make their_mark work in the case where they do NOT
michael@0 285 * give us a pool pointer?
michael@0 286 */
michael@0 287 void *their_mark; /* free on error */
michael@0 288 #endif
michael@0 289
michael@0 290 sec_asn1d_state *current;
michael@0 291 sec_asn1d_parse_status status;
michael@0 292
michael@0 293 SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */
michael@0 294 void *notify_arg; /* argument to notify_proc */
michael@0 295 PRBool during_notify; /* true during call to notify_proc */
michael@0 296
michael@0 297 SEC_ASN1WriteProc filter_proc; /* pass field bytes to this */
michael@0 298 void *filter_arg; /* argument to that function */
michael@0 299 PRBool filter_only; /* do not allocate/store fields */
michael@0 300 };
michael@0 301
michael@0 302
michael@0 303 /*
michael@0 304 * XXX this is a fairly generic function that may belong elsewhere
michael@0 305 */
michael@0 306 static void *
michael@0 307 sec_asn1d_alloc (PLArenaPool *poolp, unsigned long len)
michael@0 308 {
michael@0 309 void *thing;
michael@0 310
michael@0 311 if (poolp != NULL) {
michael@0 312 /*
michael@0 313 * Allocate from the pool.
michael@0 314 */
michael@0 315 thing = PORT_ArenaAlloc (poolp, len);
michael@0 316 } else {
michael@0 317 /*
michael@0 318 * Allocate generically.
michael@0 319 */
michael@0 320 thing = PORT_Alloc (len);
michael@0 321 }
michael@0 322
michael@0 323 return thing;
michael@0 324 }
michael@0 325
michael@0 326
michael@0 327 /*
michael@0 328 * XXX this is a fairly generic function that may belong elsewhere
michael@0 329 */
michael@0 330 static void *
michael@0 331 sec_asn1d_zalloc (PLArenaPool *poolp, unsigned long len)
michael@0 332 {
michael@0 333 void *thing;
michael@0 334
michael@0 335 thing = sec_asn1d_alloc (poolp, len);
michael@0 336 if (thing != NULL)
michael@0 337 PORT_Memset (thing, 0, len);
michael@0 338 return thing;
michael@0 339 }
michael@0 340
michael@0 341
michael@0 342 static sec_asn1d_state *
michael@0 343 sec_asn1d_push_state (SEC_ASN1DecoderContext *cx,
michael@0 344 const SEC_ASN1Template *theTemplate,
michael@0 345 void *dest, PRBool new_depth)
michael@0 346 {
michael@0 347 sec_asn1d_state *state, *new_state;
michael@0 348
michael@0 349 state = cx->current;
michael@0 350
michael@0 351 PORT_Assert (state == NULL || state->child == NULL);
michael@0 352
michael@0 353 if (state != NULL) {
michael@0 354 PORT_Assert (state->our_mark == NULL);
michael@0 355 state->our_mark = PORT_ArenaMark (cx->our_pool);
michael@0 356 }
michael@0 357
michael@0 358 new_state = (sec_asn1d_state*)sec_asn1d_zalloc (cx->our_pool,
michael@0 359 sizeof(*new_state));
michael@0 360 if (new_state == NULL) {
michael@0 361 goto loser;
michael@0 362 }
michael@0 363
michael@0 364 new_state->top = cx;
michael@0 365 new_state->parent = state;
michael@0 366 new_state->theTemplate = theTemplate;
michael@0 367 new_state->place = notInUse;
michael@0 368 if (dest != NULL)
michael@0 369 new_state->dest = (char *)dest + theTemplate->offset;
michael@0 370
michael@0 371 if (state != NULL) {
michael@0 372 new_state->depth = state->depth;
michael@0 373 if (new_depth) {
michael@0 374 if (++new_state->depth > SEC_ASN1D_MAX_DEPTH) {
michael@0 375 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 376 goto loser;
michael@0 377 }
michael@0 378 }
michael@0 379 state->child = new_state;
michael@0 380 }
michael@0 381
michael@0 382 cx->current = new_state;
michael@0 383 return new_state;
michael@0 384
michael@0 385 loser:
michael@0 386 cx->status = decodeError;
michael@0 387 if (state != NULL) {
michael@0 388 PORT_ArenaRelease(cx->our_pool, state->our_mark);
michael@0 389 state->our_mark = NULL;
michael@0 390 }
michael@0 391 return NULL;
michael@0 392 }
michael@0 393
michael@0 394
michael@0 395 static void
michael@0 396 sec_asn1d_scrub_state (sec_asn1d_state *state)
michael@0 397 {
michael@0 398 /*
michael@0 399 * Some default "scrubbing".
michael@0 400 * XXX right set of initializations?
michael@0 401 */
michael@0 402 state->place = beforeIdentifier;
michael@0 403 state->endofcontents = PR_FALSE;
michael@0 404 state->indefinite = PR_FALSE;
michael@0 405 state->missing = PR_FALSE;
michael@0 406 PORT_Assert (state->consumed == 0);
michael@0 407 }
michael@0 408
michael@0 409
michael@0 410 static void
michael@0 411 sec_asn1d_notify_before (SEC_ASN1DecoderContext *cx, void *dest, int depth)
michael@0 412 {
michael@0 413 if (cx->notify_proc == NULL)
michael@0 414 return;
michael@0 415
michael@0 416 cx->during_notify = PR_TRUE;
michael@0 417 (* cx->notify_proc) (cx->notify_arg, PR_TRUE, dest, depth);
michael@0 418 cx->during_notify = PR_FALSE;
michael@0 419 }
michael@0 420
michael@0 421
michael@0 422 static void
michael@0 423 sec_asn1d_notify_after (SEC_ASN1DecoderContext *cx, void *dest, int depth)
michael@0 424 {
michael@0 425 if (cx->notify_proc == NULL)
michael@0 426 return;
michael@0 427
michael@0 428 cx->during_notify = PR_TRUE;
michael@0 429 (* cx->notify_proc) (cx->notify_arg, PR_FALSE, dest, depth);
michael@0 430 cx->during_notify = PR_FALSE;
michael@0 431 }
michael@0 432
michael@0 433
michael@0 434 static sec_asn1d_state *
michael@0 435 sec_asn1d_init_state_based_on_template (sec_asn1d_state *state)
michael@0 436 {
michael@0 437 PRBool explicit, optional, universal;
michael@0 438 unsigned char expect_tag_modifiers;
michael@0 439 unsigned long encode_kind, under_kind;
michael@0 440 unsigned long check_tag_mask, expect_tag_number;
michael@0 441
michael@0 442
michael@0 443 /* XXX Check that both of these tests are really needed/appropriate. */
michael@0 444 if (state == NULL || state->top->status == decodeError)
michael@0 445 return state;
michael@0 446
michael@0 447 encode_kind = state->theTemplate->kind;
michael@0 448
michael@0 449 if (encode_kind & SEC_ASN1_SAVE) {
michael@0 450 /*
michael@0 451 * This is a "magic" field that saves away all bytes, allowing
michael@0 452 * the immediately following field to still be decoded from this
michael@0 453 * same spot -- sort of a fork.
michael@0 454 */
michael@0 455 /* check that there are no extraneous bits */
michael@0 456 PORT_Assert (encode_kind == SEC_ASN1_SAVE);
michael@0 457 if (state->top->filter_only) {
michael@0 458 /*
michael@0 459 * If we are not storing, then we do not do the SAVE field
michael@0 460 * at all. Just move ahead to the "real" field instead,
michael@0 461 * doing the appropriate notify calls before and after.
michael@0 462 */
michael@0 463 sec_asn1d_notify_after (state->top, state->dest, state->depth);
michael@0 464 /*
michael@0 465 * Since we are not storing, allow for our current dest value
michael@0 466 * to be NULL. (This might not actually occur, but right now I
michael@0 467 * cannot convince myself one way or the other.) If it is NULL,
michael@0 468 * assume that our parent dest can help us out.
michael@0 469 */
michael@0 470 if (state->dest == NULL)
michael@0 471 state->dest = state->parent->dest;
michael@0 472 else
michael@0 473 state->dest = (char *)state->dest - state->theTemplate->offset;
michael@0 474 state->theTemplate++;
michael@0 475 if (state->dest != NULL)
michael@0 476 state->dest = (char *)state->dest + state->theTemplate->offset;
michael@0 477 sec_asn1d_notify_before (state->top, state->dest, state->depth);
michael@0 478 encode_kind = state->theTemplate->kind;
michael@0 479 PORT_Assert ((encode_kind & SEC_ASN1_SAVE) == 0);
michael@0 480 } else {
michael@0 481 sec_asn1d_scrub_state (state);
michael@0 482 state->place = duringSaveEncoding;
michael@0 483 state = sec_asn1d_push_state (state->top, SEC_AnyTemplate,
michael@0 484 state->dest, PR_FALSE);
michael@0 485 if (state != NULL)
michael@0 486 state = sec_asn1d_init_state_based_on_template (state);
michael@0 487 return state;
michael@0 488 }
michael@0 489 }
michael@0 490
michael@0 491
michael@0 492 universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
michael@0 493 ? PR_TRUE : PR_FALSE;
michael@0 494
michael@0 495 explicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
michael@0 496 encode_kind &= ~SEC_ASN1_EXPLICIT;
michael@0 497
michael@0 498 optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
michael@0 499 encode_kind &= ~SEC_ASN1_OPTIONAL;
michael@0 500
michael@0 501 PORT_Assert (!(explicit && universal)); /* bad templates */
michael@0 502
michael@0 503 encode_kind &= ~SEC_ASN1_DYNAMIC;
michael@0 504 encode_kind &= ~SEC_ASN1_MAY_STREAM;
michael@0 505
michael@0 506 if (encode_kind & SEC_ASN1_CHOICE) {
michael@0 507 #if 0 /* XXX remove? */
michael@0 508 sec_asn1d_state *child = sec_asn1d_push_state(state->top, state->theTemplate, state->dest, PR_FALSE);
michael@0 509 if ((sec_asn1d_state *)NULL == child) {
michael@0 510 return (sec_asn1d_state *)NULL;
michael@0 511 }
michael@0 512
michael@0 513 child->allocate = state->allocate;
michael@0 514 child->place = beforeChoice;
michael@0 515 return child;
michael@0 516 #else
michael@0 517 state->place = beforeChoice;
michael@0 518 return state;
michael@0 519 #endif
michael@0 520 }
michael@0 521
michael@0 522 if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || (!universal
michael@0 523 && !explicit)) {
michael@0 524 const SEC_ASN1Template *subt;
michael@0 525 void *dest;
michael@0 526 PRBool child_allocate;
michael@0 527
michael@0 528 PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);
michael@0 529
michael@0 530 sec_asn1d_scrub_state (state);
michael@0 531 child_allocate = PR_FALSE;
michael@0 532
michael@0 533 if (encode_kind & SEC_ASN1_POINTER) {
michael@0 534 /*
michael@0 535 * A POINTER means we need to allocate the destination for
michael@0 536 * this field. But, since it may also be an optional field,
michael@0 537 * we defer the allocation until later; we just record that
michael@0 538 * it needs to be done.
michael@0 539 *
michael@0 540 * There are two possible scenarios here -- one is just a
michael@0 541 * plain POINTER (kind of like INLINE, except with allocation)
michael@0 542 * and the other is an implicitly-tagged POINTER. We don't
michael@0 543 * need to do anything special here for the two cases, but
michael@0 544 * since the template definition can be tricky, we do check
michael@0 545 * that there are no extraneous bits set in encode_kind.
michael@0 546 *
michael@0 547 * XXX The same conditions which assert should set an error.
michael@0 548 */
michael@0 549 if (universal) {
michael@0 550 /*
michael@0 551 * "universal" means this entry is a standalone POINTER;
michael@0 552 * there should be no other bits set in encode_kind.
michael@0 553 */
michael@0 554 PORT_Assert (encode_kind == SEC_ASN1_POINTER);
michael@0 555 } else {
michael@0 556 /*
michael@0 557 * If we get here we have an implicitly-tagged field
michael@0 558 * that needs to be put into a POINTER. The subtemplate
michael@0 559 * will determine how to decode the field, but encode_kind
michael@0 560 * describes the (implicit) tag we are looking for.
michael@0 561 * The non-tag bits of encode_kind will be ignored by
michael@0 562 * the code below; none of them should be set, however,
michael@0 563 * except for the POINTER bit itself -- so check that.
michael@0 564 */
michael@0 565 PORT_Assert ((encode_kind & ~SEC_ASN1_TAG_MASK)
michael@0 566 == SEC_ASN1_POINTER);
michael@0 567 }
michael@0 568 if (!state->top->filter_only)
michael@0 569 child_allocate = PR_TRUE;
michael@0 570 dest = NULL;
michael@0 571 state->place = afterPointer;
michael@0 572 } else {
michael@0 573 dest = state->dest;
michael@0 574 if (encode_kind & SEC_ASN1_INLINE) {
michael@0 575 /* check that there are no extraneous bits */
michael@0 576 PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional);
michael@0 577 state->place = afterInline;
michael@0 578 } else {
michael@0 579 state->place = afterImplicit;
michael@0 580 }
michael@0 581 }
michael@0 582
michael@0 583 state->optional = optional;
michael@0 584 subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest, PR_FALSE);
michael@0 585 state = sec_asn1d_push_state (state->top, subt, dest, PR_FALSE);
michael@0 586 if (state == NULL)
michael@0 587 return NULL;
michael@0 588
michael@0 589 state->allocate = child_allocate;
michael@0 590
michael@0 591 if (universal) {
michael@0 592 state = sec_asn1d_init_state_based_on_template (state);
michael@0 593 if (state != NULL) {
michael@0 594 /*
michael@0 595 * If this field is optional, we need to record that on
michael@0 596 * the pushed child so it won't fail if the field isn't
michael@0 597 * found. I can't think of a way that this new state
michael@0 598 * could already have optional set (which we would wipe
michael@0 599 * out below if our local optional is not set) -- but
michael@0 600 * just to be sure, assert that it isn't set.
michael@0 601 */
michael@0 602 PORT_Assert (!state->optional);
michael@0 603 state->optional = optional;
michael@0 604 }
michael@0 605 return state;
michael@0 606 }
michael@0 607
michael@0 608 under_kind = state->theTemplate->kind;
michael@0 609 under_kind &= ~SEC_ASN1_MAY_STREAM;
michael@0 610 } else if (explicit) {
michael@0 611 /*
michael@0 612 * For explicit, we only need to match the encoding tag next,
michael@0 613 * then we will push another state to handle the entire inner
michael@0 614 * part. In this case, there is no underlying kind which plays
michael@0 615 * any part in the determination of the outer, explicit tag.
michael@0 616 * So we just set under_kind to 0, which is not a valid tag,
michael@0 617 * and the rest of the tag matching stuff should be okay.
michael@0 618 */
michael@0 619 under_kind = 0;
michael@0 620 } else {
michael@0 621 /*
michael@0 622 * Nothing special; the underlying kind and the given encoding
michael@0 623 * information are the same.
michael@0 624 */
michael@0 625 under_kind = encode_kind;
michael@0 626 }
michael@0 627
michael@0 628 /* XXX is this the right set of bits to test here? */
michael@0 629 PORT_Assert ((under_kind & (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL
michael@0 630 | SEC_ASN1_MAY_STREAM
michael@0 631 | SEC_ASN1_INLINE | SEC_ASN1_POINTER)) == 0);
michael@0 632
michael@0 633 if (encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) {
michael@0 634 PORT_Assert (encode_kind == under_kind);
michael@0 635 if (encode_kind & SEC_ASN1_SKIP) {
michael@0 636 PORT_Assert (!optional);
michael@0 637 PORT_Assert (encode_kind == SEC_ASN1_SKIP);
michael@0 638 state->dest = NULL;
michael@0 639 }
michael@0 640 check_tag_mask = 0;
michael@0 641 expect_tag_modifiers = 0;
michael@0 642 expect_tag_number = 0;
michael@0 643 } else {
michael@0 644 check_tag_mask = SEC_ASN1_TAG_MASK;
michael@0 645 expect_tag_modifiers = (unsigned char)encode_kind & SEC_ASN1_TAG_MASK
michael@0 646 & ~SEC_ASN1_TAGNUM_MASK;
michael@0 647 /*
michael@0 648 * XXX This assumes only single-octet identifiers. To handle
michael@0 649 * the HIGH TAG form we would need to do some more work, especially
michael@0 650 * in how to specify them in the template, because right now we
michael@0 651 * do not provide a way to specify more *tag* bits in encode_kind.
michael@0 652 */
michael@0 653 expect_tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
michael@0 654
michael@0 655 switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
michael@0 656 case SEC_ASN1_SET:
michael@0 657 /*
michael@0 658 * XXX A plain old SET (as opposed to a SET OF) is not implemented.
michael@0 659 * If it ever is, remove this assert...
michael@0 660 */
michael@0 661 PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
michael@0 662 /* fallthru */
michael@0 663 case SEC_ASN1_SEQUENCE:
michael@0 664 expect_tag_modifiers |= SEC_ASN1_CONSTRUCTED;
michael@0 665 break;
michael@0 666 case SEC_ASN1_BIT_STRING:
michael@0 667 case SEC_ASN1_BMP_STRING:
michael@0 668 case SEC_ASN1_GENERALIZED_TIME:
michael@0 669 case SEC_ASN1_IA5_STRING:
michael@0 670 case SEC_ASN1_OCTET_STRING:
michael@0 671 case SEC_ASN1_PRINTABLE_STRING:
michael@0 672 case SEC_ASN1_T61_STRING:
michael@0 673 case SEC_ASN1_UNIVERSAL_STRING:
michael@0 674 case SEC_ASN1_UTC_TIME:
michael@0 675 case SEC_ASN1_UTF8_STRING:
michael@0 676 case SEC_ASN1_VISIBLE_STRING:
michael@0 677 check_tag_mask &= ~SEC_ASN1_CONSTRUCTED;
michael@0 678 break;
michael@0 679 }
michael@0 680 }
michael@0 681
michael@0 682 state->check_tag_mask = check_tag_mask;
michael@0 683 state->expect_tag_modifiers = expect_tag_modifiers;
michael@0 684 state->expect_tag_number = expect_tag_number;
michael@0 685 state->underlying_kind = under_kind;
michael@0 686 state->explicit = explicit;
michael@0 687 state->optional = optional;
michael@0 688
michael@0 689 sec_asn1d_scrub_state (state);
michael@0 690
michael@0 691 return state;
michael@0 692 }
michael@0 693
michael@0 694 static sec_asn1d_state *
michael@0 695 sec_asn1d_get_enclosing_construct(sec_asn1d_state *state)
michael@0 696 {
michael@0 697 for (state = state->parent; state; state = state->parent) {
michael@0 698 sec_asn1d_parse_place place = state->place;
michael@0 699 if (place != afterImplicit &&
michael@0 700 place != afterPointer &&
michael@0 701 place != afterInline &&
michael@0 702 place != afterSaveEncoding &&
michael@0 703 place != duringSaveEncoding &&
michael@0 704 place != duringChoice) {
michael@0 705
michael@0 706 /* we've walked up the stack to a state that represents
michael@0 707 ** the enclosing construct.
michael@0 708 */
michael@0 709 break;
michael@0 710 }
michael@0 711 }
michael@0 712 return state;
michael@0 713 }
michael@0 714
michael@0 715 static PRBool
michael@0 716 sec_asn1d_parent_allows_EOC(sec_asn1d_state *state)
michael@0 717 {
michael@0 718 /* get state of enclosing construct. */
michael@0 719 state = sec_asn1d_get_enclosing_construct(state);
michael@0 720 if (state) {
michael@0 721 sec_asn1d_parse_place place = state->place;
michael@0 722 /* Is it one of the types that permits an unexpected EOC? */
michael@0 723 int eoc_permitted =
michael@0 724 (place == duringGroup ||
michael@0 725 place == duringConstructedString ||
michael@0 726 state->child->optional);
michael@0 727 return (state->indefinite && eoc_permitted) ? PR_TRUE : PR_FALSE;
michael@0 728 }
michael@0 729 return PR_FALSE;
michael@0 730 }
michael@0 731
michael@0 732 static unsigned long
michael@0 733 sec_asn1d_parse_identifier (sec_asn1d_state *state,
michael@0 734 const char *buf, unsigned long len)
michael@0 735 {
michael@0 736 unsigned char byte;
michael@0 737 unsigned char tag_number;
michael@0 738
michael@0 739 PORT_Assert (state->place == beforeIdentifier);
michael@0 740
michael@0 741 if (len == 0) {
michael@0 742 state->top->status = needBytes;
michael@0 743 return 0;
michael@0 744 }
michael@0 745
michael@0 746 byte = (unsigned char) *buf;
michael@0 747 #ifdef DEBUG_ASN1D_STATES
michael@0 748 {
michael@0 749 char kindBuf[256];
michael@0 750 formatKind(byte, kindBuf);
michael@0 751 printf("Found tag %02x %s\n", byte, kindBuf);
michael@0 752 }
michael@0 753 #endif
michael@0 754 tag_number = byte & SEC_ASN1_TAGNUM_MASK;
michael@0 755
michael@0 756 if (IS_HIGH_TAG_NUMBER (tag_number)) {
michael@0 757 state->place = duringIdentifier;
michael@0 758 state->found_tag_number = 0;
michael@0 759 /*
michael@0 760 * Actually, we have no idea how many bytes are pending, but we
michael@0 761 * do know that it is at least 1. That is all we know; we have
michael@0 762 * to look at each byte to know if there is another, etc.
michael@0 763 */
michael@0 764 state->pending = 1;
michael@0 765 } else {
michael@0 766 if (byte == 0 && sec_asn1d_parent_allows_EOC(state)) {
michael@0 767 /*
michael@0 768 * Our parent has indefinite-length encoding, and the
michael@0 769 * entire tag found is 0, so it seems that we have hit the
michael@0 770 * end-of-contents octets. To handle this, we just change
michael@0 771 * our state to that which expects to get the bytes of the
michael@0 772 * end-of-contents octets and let that code re-read this byte
michael@0 773 * so that our categorization of field types is correct.
michael@0 774 * After that, our parent will then deal with everything else.
michael@0 775 */
michael@0 776 state->place = duringEndOfContents;
michael@0 777 state->pending = 2;
michael@0 778 state->found_tag_number = 0;
michael@0 779 state->found_tag_modifiers = 0;
michael@0 780 /*
michael@0 781 * We might be an optional field that is, as we now find out,
michael@0 782 * missing. Give our parent a clue that this happened.
michael@0 783 */
michael@0 784 if (state->optional)
michael@0 785 state->missing = PR_TRUE;
michael@0 786 return 0;
michael@0 787 }
michael@0 788 state->place = afterIdentifier;
michael@0 789 state->found_tag_number = tag_number;
michael@0 790 }
michael@0 791 state->found_tag_modifiers = byte & ~SEC_ASN1_TAGNUM_MASK;
michael@0 792
michael@0 793 return 1;
michael@0 794 }
michael@0 795
michael@0 796
michael@0 797 static unsigned long
michael@0 798 sec_asn1d_parse_more_identifier (sec_asn1d_state *state,
michael@0 799 const char *buf, unsigned long len)
michael@0 800 {
michael@0 801 unsigned char byte;
michael@0 802 int count;
michael@0 803
michael@0 804 PORT_Assert (state->pending == 1);
michael@0 805 PORT_Assert (state->place == duringIdentifier);
michael@0 806
michael@0 807 if (len == 0) {
michael@0 808 state->top->status = needBytes;
michael@0 809 return 0;
michael@0 810 }
michael@0 811
michael@0 812 count = 0;
michael@0 813
michael@0 814 while (len && state->pending) {
michael@0 815 if (HIGH_BITS (state->found_tag_number, TAG_NUMBER_BITS) != 0) {
michael@0 816 /*
michael@0 817 * The given high tag number overflows our container;
michael@0 818 * just give up. This is not likely to *ever* happen.
michael@0 819 */
michael@0 820 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 821 state->top->status = decodeError;
michael@0 822 return 0;
michael@0 823 }
michael@0 824
michael@0 825 state->found_tag_number <<= TAG_NUMBER_BITS;
michael@0 826
michael@0 827 byte = (unsigned char) buf[count++];
michael@0 828 state->found_tag_number |= (byte & TAG_NUMBER_MASK);
michael@0 829
michael@0 830 len--;
michael@0 831 if (LAST_TAG_NUMBER_BYTE (byte))
michael@0 832 state->pending = 0;
michael@0 833 }
michael@0 834
michael@0 835 if (state->pending == 0)
michael@0 836 state->place = afterIdentifier;
michael@0 837
michael@0 838 return count;
michael@0 839 }
michael@0 840
michael@0 841
michael@0 842 static void
michael@0 843 sec_asn1d_confirm_identifier (sec_asn1d_state *state)
michael@0 844 {
michael@0 845 PRBool match;
michael@0 846
michael@0 847 PORT_Assert (state->place == afterIdentifier);
michael@0 848
michael@0 849 match = (PRBool)(((state->found_tag_modifiers & state->check_tag_mask)
michael@0 850 == state->expect_tag_modifiers)
michael@0 851 && ((state->found_tag_number & state->check_tag_mask)
michael@0 852 == state->expect_tag_number));
michael@0 853 if (match) {
michael@0 854 state->place = beforeLength;
michael@0 855 } else {
michael@0 856 if (state->optional) {
michael@0 857 state->missing = PR_TRUE;
michael@0 858 state->place = afterEndOfContents;
michael@0 859 } else {
michael@0 860 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 861 state->top->status = decodeError;
michael@0 862 }
michael@0 863 }
michael@0 864 }
michael@0 865
michael@0 866
michael@0 867 static unsigned long
michael@0 868 sec_asn1d_parse_length (sec_asn1d_state *state,
michael@0 869 const char *buf, unsigned long len)
michael@0 870 {
michael@0 871 unsigned char byte;
michael@0 872
michael@0 873 PORT_Assert (state->place == beforeLength);
michael@0 874
michael@0 875 if (len == 0) {
michael@0 876 state->top->status = needBytes;
michael@0 877 return 0;
michael@0 878 }
michael@0 879
michael@0 880 /*
michael@0 881 * The default/likely outcome. It may get adjusted below.
michael@0 882 */
michael@0 883 state->place = afterLength;
michael@0 884
michael@0 885 byte = (unsigned char) *buf;
michael@0 886
michael@0 887 if (LENGTH_IS_SHORT_FORM (byte)) {
michael@0 888 state->contents_length = byte;
michael@0 889 } else {
michael@0 890 state->contents_length = 0;
michael@0 891 state->pending = LONG_FORM_LENGTH (byte);
michael@0 892 if (state->pending == 0) {
michael@0 893 state->indefinite = PR_TRUE;
michael@0 894 } else {
michael@0 895 state->place = duringLength;
michael@0 896 }
michael@0 897 }
michael@0 898
michael@0 899 /* If we're parsing an ANY, SKIP, or SAVE template, and
michael@0 900 ** the object being saved is definite length encoded and constructed,
michael@0 901 ** there's no point in decoding that construct's members.
michael@0 902 ** So, just forget it's constructed and treat it as primitive.
michael@0 903 ** (SAVE appears as an ANY at this point)
michael@0 904 */
michael@0 905 if (!state->indefinite &&
michael@0 906 (state->underlying_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP))) {
michael@0 907 state->found_tag_modifiers &= ~SEC_ASN1_CONSTRUCTED;
michael@0 908 }
michael@0 909
michael@0 910 return 1;
michael@0 911 }
michael@0 912
michael@0 913
michael@0 914 static unsigned long
michael@0 915 sec_asn1d_parse_more_length (sec_asn1d_state *state,
michael@0 916 const char *buf, unsigned long len)
michael@0 917 {
michael@0 918 int count;
michael@0 919
michael@0 920 PORT_Assert (state->pending > 0);
michael@0 921 PORT_Assert (state->place == duringLength);
michael@0 922
michael@0 923 if (len == 0) {
michael@0 924 state->top->status = needBytes;
michael@0 925 return 0;
michael@0 926 }
michael@0 927
michael@0 928 count = 0;
michael@0 929
michael@0 930 while (len && state->pending) {
michael@0 931 if (HIGH_BITS (state->contents_length, 9) != 0) {
michael@0 932 /*
michael@0 933 * The given full content length overflows our container;
michael@0 934 * just give up.
michael@0 935 */
michael@0 936 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 937 state->top->status = decodeError;
michael@0 938 return 0;
michael@0 939 }
michael@0 940
michael@0 941 state->contents_length <<= 8;
michael@0 942 state->contents_length |= (unsigned char) buf[count++];
michael@0 943
michael@0 944 len--;
michael@0 945 state->pending--;
michael@0 946 }
michael@0 947
michael@0 948 if (state->pending == 0)
michael@0 949 state->place = afterLength;
michael@0 950
michael@0 951 return count;
michael@0 952 }
michael@0 953
michael@0 954
michael@0 955 static void
michael@0 956 sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
michael@0 957 {
michael@0 958 SECItem *item;
michael@0 959 PLArenaPool *poolp;
michael@0 960 unsigned long alloc_len;
michael@0 961
michael@0 962 #ifdef DEBUG_ASN1D_STATES
michael@0 963 {
michael@0 964 printf("Found Length %d %s\n", state->contents_length,
michael@0 965 state->indefinite ? "indefinite" : "");
michael@0 966 }
michael@0 967 #endif
michael@0 968
michael@0 969 /*
michael@0 970 * XXX I cannot decide if this allocation should exclude the case
michael@0 971 * where state->endofcontents is true -- figure it out!
michael@0 972 */
michael@0 973 if (state->allocate) {
michael@0 974 void *dest;
michael@0 975
michael@0 976 PORT_Assert (state->dest == NULL);
michael@0 977 /*
michael@0 978 * We are handling a POINTER or a member of a GROUP, and need to
michael@0 979 * allocate for the data structure.
michael@0 980 */
michael@0 981 dest = sec_asn1d_zalloc (state->top->their_pool,
michael@0 982 state->theTemplate->size);
michael@0 983 if (dest == NULL) {
michael@0 984 state->top->status = decodeError;
michael@0 985 return;
michael@0 986 }
michael@0 987 state->dest = (char *)dest + state->theTemplate->offset;
michael@0 988
michael@0 989 /*
michael@0 990 * For a member of a GROUP, our parent will later put the
michael@0 991 * pointer wherever it belongs. But for a POINTER, we need
michael@0 992 * to record the destination now, in case notify or filter
michael@0 993 * procs need access to it -- they cannot find it otherwise,
michael@0 994 * until it is too late (for one-pass processing).
michael@0 995 */
michael@0 996 if (state->parent->place == afterPointer) {
michael@0 997 void **placep;
michael@0 998
michael@0 999 placep = state->parent->dest;
michael@0 1000 *placep = dest;
michael@0 1001 }
michael@0 1002 }
michael@0 1003
michael@0 1004 /*
michael@0 1005 * Remember, length may be indefinite here! In that case,
michael@0 1006 * both contents_length and pending will be zero.
michael@0 1007 */
michael@0 1008 state->pending = state->contents_length;
michael@0 1009
michael@0 1010 /* If this item has definite length encoding, and
michael@0 1011 ** is enclosed by a definite length constructed type,
michael@0 1012 ** make sure it isn't longer than the remaining space in that
michael@0 1013 ** constructed type.
michael@0 1014 */
michael@0 1015 if (state->contents_length > 0) {
michael@0 1016 sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(state);
michael@0 1017 if (parent && !parent->indefinite &&
michael@0 1018 state->consumed + state->contents_length > parent->pending) {
michael@0 1019 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1020 state->top->status = decodeError;
michael@0 1021 return;
michael@0 1022 }
michael@0 1023 }
michael@0 1024
michael@0 1025 /*
michael@0 1026 * An EXPLICIT is nothing but an outer header, which we have
michael@0 1027 * already parsed and accepted. Now we need to do the inner
michael@0 1028 * header and its contents.
michael@0 1029 */
michael@0 1030 if (state->explicit) {
michael@0 1031 state->place = afterExplicit;
michael@0 1032 state = sec_asn1d_push_state (state->top,
michael@0 1033 SEC_ASN1GetSubtemplate(state->theTemplate,
michael@0 1034 state->dest,
michael@0 1035 PR_FALSE),
michael@0 1036 state->dest, PR_TRUE);
michael@0 1037 if (state != NULL)
michael@0 1038 state = sec_asn1d_init_state_based_on_template (state);
michael@0 1039 return;
michael@0 1040 }
michael@0 1041
michael@0 1042 /*
michael@0 1043 * For GROUP (SET OF, SEQUENCE OF), even if we know the length here
michael@0 1044 * we cannot tell how many items we will end up with ... so push a
michael@0 1045 * state that can keep track of "children" (the individual members
michael@0 1046 * of the group; we will allocate as we go and put them all together
michael@0 1047 * at the end.
michael@0 1048 */
michael@0 1049 if (state->underlying_kind & SEC_ASN1_GROUP) {
michael@0 1050 /* XXX If this assertion holds (should be able to confirm it via
michael@0 1051 * inspection, too) then move this code into the switch statement
michael@0 1052 * below under cases SET_OF and SEQUENCE_OF; it will be cleaner.
michael@0 1053 */
michael@0 1054 PORT_Assert (state->underlying_kind == SEC_ASN1_SET_OF
michael@0 1055 || state->underlying_kind == SEC_ASN1_SEQUENCE_OF
michael@0 1056 || state->underlying_kind == (SEC_ASN1_SEQUENCE_OF|SEC_ASN1_DYNAMIC)
michael@0 1057 || state->underlying_kind == (SEC_ASN1_SEQUENCE_OF|SEC_ASN1_DYNAMIC)
michael@0 1058 );
michael@0 1059 if (state->contents_length != 0 || state->indefinite) {
michael@0 1060 const SEC_ASN1Template *subt;
michael@0 1061
michael@0 1062 state->place = duringGroup;
michael@0 1063 subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest,
michael@0 1064 PR_FALSE);
michael@0 1065 state = sec_asn1d_push_state (state->top, subt, NULL, PR_TRUE);
michael@0 1066 if (state != NULL) {
michael@0 1067 if (!state->top->filter_only)
michael@0 1068 state->allocate = PR_TRUE; /* XXX propogate this? */
michael@0 1069 /*
michael@0 1070 * Do the "before" field notification for next in group.
michael@0 1071 */
michael@0 1072 sec_asn1d_notify_before (state->top, state->dest, state->depth);
michael@0 1073 state = sec_asn1d_init_state_based_on_template (state);
michael@0 1074 }
michael@0 1075 } else {
michael@0 1076 /*
michael@0 1077 * A group of zero; we are done.
michael@0 1078 * Set state to afterGroup and let that code plant the NULL.
michael@0 1079 */
michael@0 1080 state->place = afterGroup;
michael@0 1081 }
michael@0 1082 return;
michael@0 1083 }
michael@0 1084
michael@0 1085 switch (state->underlying_kind) {
michael@0 1086 case SEC_ASN1_SEQUENCE:
michael@0 1087 /*
michael@0 1088 * We need to push a child to handle the individual fields.
michael@0 1089 */
michael@0 1090 state->place = duringSequence;
michael@0 1091 state = sec_asn1d_push_state (state->top, state->theTemplate + 1,
michael@0 1092 state->dest, PR_TRUE);
michael@0 1093 if (state != NULL) {
michael@0 1094 /*
michael@0 1095 * Do the "before" field notification.
michael@0 1096 */
michael@0 1097 sec_asn1d_notify_before (state->top, state->dest, state->depth);
michael@0 1098 state = sec_asn1d_init_state_based_on_template (state);
michael@0 1099 }
michael@0 1100 break;
michael@0 1101
michael@0 1102 case SEC_ASN1_SET: /* XXX SET is not really implemented */
michael@0 1103 /*
michael@0 1104 * XXX A plain SET requires special handling; scanning of a
michael@0 1105 * template to see where a field should go (because by definition,
michael@0 1106 * they are not in any particular order, and you have to look at
michael@0 1107 * each tag to disambiguate what the field is). We may never
michael@0 1108 * implement this because in practice, it seems to be unused.
michael@0 1109 */
michael@0 1110 PORT_Assert(0);
michael@0 1111 PORT_SetError (SEC_ERROR_BAD_DER); /* XXX */
michael@0 1112 state->top->status = decodeError;
michael@0 1113 break;
michael@0 1114
michael@0 1115 case SEC_ASN1_NULL:
michael@0 1116 /*
michael@0 1117 * The NULL type, by definition, is "nothing", content length of zero.
michael@0 1118 * An indefinite-length encoding is not alloweed.
michael@0 1119 */
michael@0 1120 if (state->contents_length || state->indefinite) {
michael@0 1121 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1122 state->top->status = decodeError;
michael@0 1123 break;
michael@0 1124 }
michael@0 1125 if (state->dest != NULL) {
michael@0 1126 item = (SECItem *)(state->dest);
michael@0 1127 item->data = NULL;
michael@0 1128 item->len = 0;
michael@0 1129 }
michael@0 1130 state->place = afterEndOfContents;
michael@0 1131 break;
michael@0 1132
michael@0 1133 case SEC_ASN1_BMP_STRING:
michael@0 1134 /* Error if length is not divisable by 2 */
michael@0 1135 if (state->contents_length % 2) {
michael@0 1136 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1137 state->top->status = decodeError;
michael@0 1138 break;
michael@0 1139 }
michael@0 1140 /* otherwise, handle as other string types */
michael@0 1141 goto regular_string_type;
michael@0 1142
michael@0 1143 case SEC_ASN1_UNIVERSAL_STRING:
michael@0 1144 /* Error if length is not divisable by 4 */
michael@0 1145 if (state->contents_length % 4) {
michael@0 1146 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1147 state->top->status = decodeError;
michael@0 1148 break;
michael@0 1149 }
michael@0 1150 /* otherwise, handle as other string types */
michael@0 1151 goto regular_string_type;
michael@0 1152
michael@0 1153 case SEC_ASN1_SKIP:
michael@0 1154 case SEC_ASN1_ANY:
michael@0 1155 case SEC_ASN1_ANY_CONTENTS:
michael@0 1156 /*
michael@0 1157 * These are not (necessarily) strings, but they need nearly
michael@0 1158 * identical handling (especially when we need to deal with
michael@0 1159 * constructed sub-pieces), so we pretend they are.
michael@0 1160 */
michael@0 1161 /* fallthru */
michael@0 1162 regular_string_type:
michael@0 1163 case SEC_ASN1_BIT_STRING:
michael@0 1164 case SEC_ASN1_IA5_STRING:
michael@0 1165 case SEC_ASN1_OCTET_STRING:
michael@0 1166 case SEC_ASN1_PRINTABLE_STRING:
michael@0 1167 case SEC_ASN1_T61_STRING:
michael@0 1168 case SEC_ASN1_UTC_TIME:
michael@0 1169 case SEC_ASN1_UTF8_STRING:
michael@0 1170 case SEC_ASN1_VISIBLE_STRING:
michael@0 1171 /*
michael@0 1172 * We are allocating for a primitive or a constructed string.
michael@0 1173 * If it is a constructed string, it may also be indefinite-length.
michael@0 1174 * If it is primitive, the length can (legally) be zero.
michael@0 1175 * Our first order of business is to allocate the memory for
michael@0 1176 * the string, if we can (if we know the length).
michael@0 1177 */
michael@0 1178 item = (SECItem *)(state->dest);
michael@0 1179
michael@0 1180 /*
michael@0 1181 * If the item is a definite-length constructed string, then
michael@0 1182 * the contents_length is actually larger than what we need
michael@0 1183 * (because it also counts each intermediate header which we
michael@0 1184 * will be throwing away as we go), but it is a perfectly good
michael@0 1185 * upper bound that we just allocate anyway, and then concat
michael@0 1186 * as we go; we end up wasting a few extra bytes but save a
michael@0 1187 * whole other copy.
michael@0 1188 */
michael@0 1189 alloc_len = state->contents_length;
michael@0 1190 poolp = NULL; /* quiet compiler warnings about unused... */
michael@0 1191
michael@0 1192 if (item == NULL || state->top->filter_only) {
michael@0 1193 if (item != NULL) {
michael@0 1194 item->data = NULL;
michael@0 1195 item->len = 0;
michael@0 1196 }
michael@0 1197 alloc_len = 0;
michael@0 1198 } else if (state->substring) {
michael@0 1199 /*
michael@0 1200 * If we are a substring of a constructed string, then we may
michael@0 1201 * not have to allocate anything (because our parent, the
michael@0 1202 * actual constructed string, did it for us). If we are a
michael@0 1203 * substring and we *do* have to allocate, that means our
michael@0 1204 * parent is an indefinite-length, so we allocate from our pool;
michael@0 1205 * later our parent will copy our string into the aggregated
michael@0 1206 * whole and free our pool allocation.
michael@0 1207 */
michael@0 1208 if (item->data == NULL) {
michael@0 1209 PORT_Assert (item->len == 0);
michael@0 1210 poolp = state->top->our_pool;
michael@0 1211 } else {
michael@0 1212 alloc_len = 0;
michael@0 1213 }
michael@0 1214 } else {
michael@0 1215 item->len = 0;
michael@0 1216 item->data = NULL;
michael@0 1217 poolp = state->top->their_pool;
michael@0 1218 }
michael@0 1219
michael@0 1220 if (alloc_len || ((! state->indefinite)
michael@0 1221 && (state->subitems_head != NULL))) {
michael@0 1222 struct subitem *subitem;
michael@0 1223 int len;
michael@0 1224
michael@0 1225 PORT_Assert (item);
michael@0 1226 if (!item) {
michael@0 1227 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1228 state->top->status = decodeError;
michael@0 1229 return;
michael@0 1230 }
michael@0 1231 PORT_Assert (item->len == 0 && item->data == NULL);
michael@0 1232 /*
michael@0 1233 * Check for and handle an ANY which has stashed aside the
michael@0 1234 * header (identifier and length) bytes for us to include
michael@0 1235 * in the saved contents.
michael@0 1236 */
michael@0 1237 if (state->subitems_head != NULL) {
michael@0 1238 PORT_Assert (state->underlying_kind == SEC_ASN1_ANY);
michael@0 1239 for (subitem = state->subitems_head;
michael@0 1240 subitem != NULL; subitem = subitem->next)
michael@0 1241 alloc_len += subitem->len;
michael@0 1242 }
michael@0 1243
michael@0 1244 item->data = (unsigned char*)sec_asn1d_zalloc (poolp, alloc_len);
michael@0 1245 if (item->data == NULL) {
michael@0 1246 state->top->status = decodeError;
michael@0 1247 break;
michael@0 1248 }
michael@0 1249
michael@0 1250 len = 0;
michael@0 1251 for (subitem = state->subitems_head;
michael@0 1252 subitem != NULL; subitem = subitem->next) {
michael@0 1253 PORT_Memcpy (item->data + len, subitem->data, subitem->len);
michael@0 1254 len += subitem->len;
michael@0 1255 }
michael@0 1256 item->len = len;
michael@0 1257
michael@0 1258 /*
michael@0 1259 * Because we use arenas and have a mark set, we later free
michael@0 1260 * everything we have allocated, so this does *not* present
michael@0 1261 * a memory leak (it is just temporarily left dangling).
michael@0 1262 */
michael@0 1263 state->subitems_head = state->subitems_tail = NULL;
michael@0 1264 }
michael@0 1265
michael@0 1266 if (state->contents_length == 0 && (! state->indefinite)) {
michael@0 1267 /*
michael@0 1268 * A zero-length simple or constructed string; we are done.
michael@0 1269 */
michael@0 1270 state->place = afterEndOfContents;
michael@0 1271 } else if (state->found_tag_modifiers & SEC_ASN1_CONSTRUCTED) {
michael@0 1272 const SEC_ASN1Template *sub;
michael@0 1273
michael@0 1274 switch (state->underlying_kind) {
michael@0 1275 case SEC_ASN1_ANY:
michael@0 1276 case SEC_ASN1_ANY_CONTENTS:
michael@0 1277 sub = SEC_AnyTemplate;
michael@0 1278 break;
michael@0 1279 case SEC_ASN1_BIT_STRING:
michael@0 1280 sub = SEC_BitStringTemplate;
michael@0 1281 break;
michael@0 1282 case SEC_ASN1_BMP_STRING:
michael@0 1283 sub = SEC_BMPStringTemplate;
michael@0 1284 break;
michael@0 1285 case SEC_ASN1_GENERALIZED_TIME:
michael@0 1286 sub = SEC_GeneralizedTimeTemplate;
michael@0 1287 break;
michael@0 1288 case SEC_ASN1_IA5_STRING:
michael@0 1289 sub = SEC_IA5StringTemplate;
michael@0 1290 break;
michael@0 1291 case SEC_ASN1_OCTET_STRING:
michael@0 1292 sub = SEC_OctetStringTemplate;
michael@0 1293 break;
michael@0 1294 case SEC_ASN1_PRINTABLE_STRING:
michael@0 1295 sub = SEC_PrintableStringTemplate;
michael@0 1296 break;
michael@0 1297 case SEC_ASN1_T61_STRING:
michael@0 1298 sub = SEC_T61StringTemplate;
michael@0 1299 break;
michael@0 1300 case SEC_ASN1_UNIVERSAL_STRING:
michael@0 1301 sub = SEC_UniversalStringTemplate;
michael@0 1302 break;
michael@0 1303 case SEC_ASN1_UTC_TIME:
michael@0 1304 sub = SEC_UTCTimeTemplate;
michael@0 1305 break;
michael@0 1306 case SEC_ASN1_UTF8_STRING:
michael@0 1307 sub = SEC_UTF8StringTemplate;
michael@0 1308 break;
michael@0 1309 case SEC_ASN1_VISIBLE_STRING:
michael@0 1310 sub = SEC_VisibleStringTemplate;
michael@0 1311 break;
michael@0 1312 case SEC_ASN1_SKIP:
michael@0 1313 sub = SEC_SkipTemplate;
michael@0 1314 break;
michael@0 1315 default: /* redundant given outer switch cases, but */
michael@0 1316 PORT_Assert(0); /* the compiler does not seem to know that, */
michael@0 1317 sub = NULL; /* so just do enough to quiet it. */
michael@0 1318 break;
michael@0 1319 }
michael@0 1320
michael@0 1321 state->place = duringConstructedString;
michael@0 1322 state = sec_asn1d_push_state (state->top, sub, item, PR_TRUE);
michael@0 1323 if (state != NULL) {
michael@0 1324 state->substring = PR_TRUE; /* XXX propogate? */
michael@0 1325 state = sec_asn1d_init_state_based_on_template (state);
michael@0 1326 }
michael@0 1327 } else if (state->indefinite) {
michael@0 1328 /*
michael@0 1329 * An indefinite-length string *must* be constructed!
michael@0 1330 */
michael@0 1331 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1332 state->top->status = decodeError;
michael@0 1333 } else {
michael@0 1334 /*
michael@0 1335 * A non-zero-length simple string.
michael@0 1336 */
michael@0 1337 if (state->underlying_kind == SEC_ASN1_BIT_STRING)
michael@0 1338 state->place = beforeBitString;
michael@0 1339 else
michael@0 1340 state->place = duringLeaf;
michael@0 1341 }
michael@0 1342 break;
michael@0 1343
michael@0 1344 default:
michael@0 1345 /*
michael@0 1346 * We are allocating for a simple leaf item.
michael@0 1347 */
michael@0 1348 if (state->contents_length) {
michael@0 1349 if (state->dest != NULL) {
michael@0 1350 item = (SECItem *)(state->dest);
michael@0 1351 item->len = 0;
michael@0 1352 if (state->top->filter_only) {
michael@0 1353 item->data = NULL;
michael@0 1354 } else {
michael@0 1355 item->data = (unsigned char*)
michael@0 1356 sec_asn1d_zalloc (state->top->their_pool,
michael@0 1357 state->contents_length);
michael@0 1358 if (item->data == NULL) {
michael@0 1359 state->top->status = decodeError;
michael@0 1360 return;
michael@0 1361 }
michael@0 1362 }
michael@0 1363 }
michael@0 1364 state->place = duringLeaf;
michael@0 1365 } else {
michael@0 1366 /*
michael@0 1367 * An indefinite-length or zero-length item is not allowed.
michael@0 1368 * (All legal cases of such were handled above.)
michael@0 1369 */
michael@0 1370 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1371 state->top->status = decodeError;
michael@0 1372 }
michael@0 1373 }
michael@0 1374 }
michael@0 1375
michael@0 1376
michael@0 1377 static void
michael@0 1378 sec_asn1d_free_child (sec_asn1d_state *state, PRBool error)
michael@0 1379 {
michael@0 1380 if (state->child != NULL) {
michael@0 1381 PORT_Assert (error || state->child->consumed == 0);
michael@0 1382 PORT_Assert (state->our_mark != NULL);
michael@0 1383 PORT_ArenaZRelease (state->top->our_pool, state->our_mark);
michael@0 1384 if (error && state->top->their_pool == NULL) {
michael@0 1385 /*
michael@0 1386 * XXX We need to free anything allocated.
michael@0 1387 * At this point, we failed in the middle of decoding. But we
michael@0 1388 * can't free the data we previously allocated with PR_Malloc
michael@0 1389 * unless we keep track of every pointer. So instead we have a
michael@0 1390 * memory leak when decoding fails half-way, unless an arena is
michael@0 1391 * used. See bug 95311 .
michael@0 1392 */
michael@0 1393 }
michael@0 1394 state->child = NULL;
michael@0 1395 state->our_mark = NULL;
michael@0 1396 } else {
michael@0 1397 /*
michael@0 1398 * It is important that we do not leave a mark unreleased/unmarked.
michael@0 1399 * But I do not think we should ever have one set in this case, only
michael@0 1400 * if we had a child (handled above). So check for that. If this
michael@0 1401 * assertion should ever get hit, then we probably need to add code
michael@0 1402 * here to release back to our_mark (and then set our_mark to NULL).
michael@0 1403 */
michael@0 1404 PORT_Assert (state->our_mark == NULL);
michael@0 1405 }
michael@0 1406 state->place = beforeEndOfContents;
michael@0 1407 }
michael@0 1408
michael@0 1409 /* We have just saved an entire encoded ASN.1 object (type) for a SAVE
michael@0 1410 ** template, and now in the next template, we are going to decode that
michael@0 1411 ** saved data by calling SEC_ASN1DecoderUpdate recursively.
michael@0 1412 ** If that recursive call fails with needBytes, it is a fatal error,
michael@0 1413 ** because the encoded object should have been complete.
michael@0 1414 ** If that recursive call fails with decodeError, it will have already
michael@0 1415 ** cleaned up the state stack, so we must bail out quickly.
michael@0 1416 **
michael@0 1417 ** These checks of the status returned by the recursive call are now
michael@0 1418 ** done in the caller of this function, immediately after it returns.
michael@0 1419 */
michael@0 1420 static void
michael@0 1421 sec_asn1d_reuse_encoding (sec_asn1d_state *state)
michael@0 1422 {
michael@0 1423 sec_asn1d_state *child;
michael@0 1424 unsigned long consumed;
michael@0 1425 SECItem *item;
michael@0 1426 void *dest;
michael@0 1427
michael@0 1428
michael@0 1429 child = state->child;
michael@0 1430 PORT_Assert (child != NULL);
michael@0 1431
michael@0 1432 consumed = child->consumed;
michael@0 1433 child->consumed = 0;
michael@0 1434
michael@0 1435 item = (SECItem *)(state->dest);
michael@0 1436 PORT_Assert (item != NULL);
michael@0 1437
michael@0 1438 PORT_Assert (item->len == consumed);
michael@0 1439
michael@0 1440 /*
michael@0 1441 * Free any grandchild.
michael@0 1442 */
michael@0 1443 sec_asn1d_free_child (child, PR_FALSE);
michael@0 1444
michael@0 1445 /*
michael@0 1446 * Notify after the SAVE field.
michael@0 1447 */
michael@0 1448 sec_asn1d_notify_after (state->top, state->dest, state->depth);
michael@0 1449
michael@0 1450 /*
michael@0 1451 * Adjust to get new dest and move forward.
michael@0 1452 */
michael@0 1453 dest = (char *)state->dest - state->theTemplate->offset;
michael@0 1454 state->theTemplate++;
michael@0 1455 child->dest = (char *)dest + state->theTemplate->offset;
michael@0 1456 child->theTemplate = state->theTemplate;
michael@0 1457
michael@0 1458 /*
michael@0 1459 * Notify before the "real" field.
michael@0 1460 */
michael@0 1461 PORT_Assert (state->depth == child->depth);
michael@0 1462 sec_asn1d_notify_before (state->top, child->dest, child->depth);
michael@0 1463
michael@0 1464 /*
michael@0 1465 * This will tell DecoderUpdate to return when it is done.
michael@0 1466 */
michael@0 1467 state->place = afterSaveEncoding;
michael@0 1468
michael@0 1469 /*
michael@0 1470 * We already have a child; "push" it by making it current.
michael@0 1471 */
michael@0 1472 state->top->current = child;
michael@0 1473
michael@0 1474 /*
michael@0 1475 * And initialize it so it is ready to parse.
michael@0 1476 */
michael@0 1477 (void) sec_asn1d_init_state_based_on_template(child);
michael@0 1478
michael@0 1479 /*
michael@0 1480 * Now parse that out of our data.
michael@0 1481 */
michael@0 1482 if (SEC_ASN1DecoderUpdate (state->top,
michael@0 1483 (char *) item->data, item->len) != SECSuccess)
michael@0 1484 return;
michael@0 1485 if (state->top->status == needBytes) {
michael@0 1486 return;
michael@0 1487 }
michael@0 1488
michael@0 1489 PORT_Assert (state->top->current == state);
michael@0 1490 PORT_Assert (state->child == child);
michael@0 1491
michael@0 1492 /*
michael@0 1493 * That should have consumed what we consumed before.
michael@0 1494 */
michael@0 1495 PORT_Assert (consumed == child->consumed);
michael@0 1496 child->consumed = 0;
michael@0 1497
michael@0 1498 /*
michael@0 1499 * Done.
michael@0 1500 */
michael@0 1501 state->consumed += consumed;
michael@0 1502 child->place = notInUse;
michael@0 1503 state->place = afterEndOfContents;
michael@0 1504 }
michael@0 1505
michael@0 1506
michael@0 1507 static unsigned long
michael@0 1508 sec_asn1d_parse_leaf (sec_asn1d_state *state,
michael@0 1509 const char *buf, unsigned long len)
michael@0 1510 {
michael@0 1511 SECItem *item;
michael@0 1512 unsigned long bufLen;
michael@0 1513
michael@0 1514 if (len == 0) {
michael@0 1515 state->top->status = needBytes;
michael@0 1516 return 0;
michael@0 1517 }
michael@0 1518
michael@0 1519 if (state->pending < len)
michael@0 1520 len = state->pending;
michael@0 1521
michael@0 1522 bufLen = len;
michael@0 1523
michael@0 1524 item = (SECItem *)(state->dest);
michael@0 1525 if (item != NULL && item->data != NULL) {
michael@0 1526 /* Strip leading zeroes when target is unsigned integer */
michael@0 1527 if (state->underlying_kind == SEC_ASN1_INTEGER && /* INTEGER */
michael@0 1528 item->len == 0 && /* MSB */
michael@0 1529 item->type == siUnsignedInteger) /* unsigned */
michael@0 1530 {
michael@0 1531 while (len > 1 && buf[0] == 0) { /* leading 0 */
michael@0 1532 buf++;
michael@0 1533 len--;
michael@0 1534 }
michael@0 1535 }
michael@0 1536 PORT_Memcpy (item->data + item->len, buf, len);
michael@0 1537 item->len += len;
michael@0 1538 }
michael@0 1539 state->pending -= bufLen;
michael@0 1540 if (state->pending == 0)
michael@0 1541 state->place = beforeEndOfContents;
michael@0 1542
michael@0 1543 return bufLen;
michael@0 1544 }
michael@0 1545
michael@0 1546
michael@0 1547 static unsigned long
michael@0 1548 sec_asn1d_parse_bit_string (sec_asn1d_state *state,
michael@0 1549 const char *buf, unsigned long len)
michael@0 1550 {
michael@0 1551 unsigned char byte;
michael@0 1552
michael@0 1553 /*PORT_Assert (state->pending > 0); */
michael@0 1554 PORT_Assert (state->place == beforeBitString);
michael@0 1555
michael@0 1556 if (state->pending == 0) {
michael@0 1557 if (state->dest != NULL) {
michael@0 1558 SECItem *item = (SECItem *)(state->dest);
michael@0 1559 item->data = NULL;
michael@0 1560 item->len = 0;
michael@0 1561 state->place = beforeEndOfContents;
michael@0 1562 return 0;
michael@0 1563 }
michael@0 1564 }
michael@0 1565
michael@0 1566 if (len == 0) {
michael@0 1567 state->top->status = needBytes;
michael@0 1568 return 0;
michael@0 1569 }
michael@0 1570
michael@0 1571 byte = (unsigned char) *buf;
michael@0 1572 if (byte > 7) {
michael@0 1573 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1574 state->top->status = decodeError;
michael@0 1575 return 0;
michael@0 1576 }
michael@0 1577
michael@0 1578 state->bit_string_unused_bits = byte;
michael@0 1579 state->place = duringBitString;
michael@0 1580 state->pending -= 1;
michael@0 1581
michael@0 1582 return 1;
michael@0 1583 }
michael@0 1584
michael@0 1585
michael@0 1586 static unsigned long
michael@0 1587 sec_asn1d_parse_more_bit_string (sec_asn1d_state *state,
michael@0 1588 const char *buf, unsigned long len)
michael@0 1589 {
michael@0 1590 PORT_Assert (state->place == duringBitString);
michael@0 1591 if (state->pending == 0) {
michael@0 1592 /* An empty bit string with some unused bits is invalid. */
michael@0 1593 if (state->bit_string_unused_bits) {
michael@0 1594 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1595 state->top->status = decodeError;
michael@0 1596 } else {
michael@0 1597 /* An empty bit string with no unused bits is OK. */
michael@0 1598 state->place = beforeEndOfContents;
michael@0 1599 }
michael@0 1600 return 0;
michael@0 1601 }
michael@0 1602
michael@0 1603 len = sec_asn1d_parse_leaf (state, buf, len);
michael@0 1604 if (state->place == beforeEndOfContents && state->dest != NULL) {
michael@0 1605 SECItem *item;
michael@0 1606
michael@0 1607 item = (SECItem *)(state->dest);
michael@0 1608 if (item->len)
michael@0 1609 item->len = (item->len << 3) - state->bit_string_unused_bits;
michael@0 1610 }
michael@0 1611
michael@0 1612 return len;
michael@0 1613 }
michael@0 1614
michael@0 1615
michael@0 1616 /*
michael@0 1617 * XXX All callers should be looking at return value to detect
michael@0 1618 * out-of-memory errors (and stop!).
michael@0 1619 */
michael@0 1620 static struct subitem *
michael@0 1621 sec_asn1d_add_to_subitems (sec_asn1d_state *state,
michael@0 1622 const void *data, unsigned long len,
michael@0 1623 PRBool copy_data)
michael@0 1624 {
michael@0 1625 struct subitem *thing;
michael@0 1626
michael@0 1627 thing = (struct subitem*)sec_asn1d_zalloc (state->top->our_pool,
michael@0 1628 sizeof (struct subitem));
michael@0 1629 if (thing == NULL) {
michael@0 1630 state->top->status = decodeError;
michael@0 1631 return NULL;
michael@0 1632 }
michael@0 1633
michael@0 1634 if (copy_data) {
michael@0 1635 void *copy;
michael@0 1636 copy = sec_asn1d_alloc (state->top->our_pool, len);
michael@0 1637 if (copy == NULL) {
michael@0 1638 state->top->status = decodeError;
michael@0 1639 if (!state->top->our_pool)
michael@0 1640 PORT_Free(thing);
michael@0 1641 return NULL;
michael@0 1642 }
michael@0 1643 PORT_Memcpy (copy, data, len);
michael@0 1644 thing->data = copy;
michael@0 1645 } else {
michael@0 1646 thing->data = data;
michael@0 1647 }
michael@0 1648 thing->len = len;
michael@0 1649 thing->next = NULL;
michael@0 1650
michael@0 1651 if (state->subitems_head == NULL) {
michael@0 1652 PORT_Assert (state->subitems_tail == NULL);
michael@0 1653 state->subitems_head = state->subitems_tail = thing;
michael@0 1654 } else {
michael@0 1655 state->subitems_tail->next = thing;
michael@0 1656 state->subitems_tail = thing;
michael@0 1657 }
michael@0 1658
michael@0 1659 return thing;
michael@0 1660 }
michael@0 1661
michael@0 1662
michael@0 1663 static void
michael@0 1664 sec_asn1d_record_any_header (sec_asn1d_state *state,
michael@0 1665 const char *buf,
michael@0 1666 unsigned long len)
michael@0 1667 {
michael@0 1668 SECItem *item;
michael@0 1669
michael@0 1670 item = (SECItem *)(state->dest);
michael@0 1671 if (item != NULL && item->data != NULL) {
michael@0 1672 PORT_Assert (state->substring);
michael@0 1673 PORT_Memcpy (item->data + item->len, buf, len);
michael@0 1674 item->len += len;
michael@0 1675 } else {
michael@0 1676 sec_asn1d_add_to_subitems (state, buf, len, PR_TRUE);
michael@0 1677 }
michael@0 1678 }
michael@0 1679
michael@0 1680
michael@0 1681 /*
michael@0 1682 * We are moving along through the substrings of a constructed string,
michael@0 1683 * and have just finished parsing one -- we need to save our child data
michael@0 1684 * (if the child was not already writing directly into the destination)
michael@0 1685 * and then move forward by one.
michael@0 1686 *
michael@0 1687 * We also have to detect when we are done:
michael@0 1688 * - a definite-length encoding stops when our pending value hits 0
michael@0 1689 * - an indefinite-length encoding stops when our child is empty
michael@0 1690 * (which means it was the end-of-contents octets)
michael@0 1691 */
michael@0 1692 static void
michael@0 1693 sec_asn1d_next_substring (sec_asn1d_state *state)
michael@0 1694 {
michael@0 1695 sec_asn1d_state *child;
michael@0 1696 SECItem *item;
michael@0 1697 unsigned long child_consumed;
michael@0 1698 PRBool done;
michael@0 1699
michael@0 1700 PORT_Assert (state->place == duringConstructedString);
michael@0 1701 PORT_Assert (state->child != NULL);
michael@0 1702
michael@0 1703 child = state->child;
michael@0 1704
michael@0 1705 child_consumed = child->consumed;
michael@0 1706 child->consumed = 0;
michael@0 1707 state->consumed += child_consumed;
michael@0 1708
michael@0 1709 done = PR_FALSE;
michael@0 1710
michael@0 1711 if (state->pending) {
michael@0 1712 PORT_Assert (!state->indefinite);
michael@0 1713 if (child_consumed > state->pending) {
michael@0 1714 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1715 state->top->status = decodeError;
michael@0 1716 return;
michael@0 1717 }
michael@0 1718
michael@0 1719 state->pending -= child_consumed;
michael@0 1720 if (state->pending == 0)
michael@0 1721 done = PR_TRUE;
michael@0 1722 } else {
michael@0 1723 PORT_Assert (state->indefinite);
michael@0 1724
michael@0 1725 item = (SECItem *)(child->dest);
michael@0 1726 if (item != NULL && item->data != NULL) {
michael@0 1727 /*
michael@0 1728 * Save the string away for later concatenation.
michael@0 1729 */
michael@0 1730 PORT_Assert (item->data != NULL);
michael@0 1731 sec_asn1d_add_to_subitems (state, item->data, item->len, PR_FALSE);
michael@0 1732 /*
michael@0 1733 * Clear the child item for the next round.
michael@0 1734 */
michael@0 1735 item->data = NULL;
michael@0 1736 item->len = 0;
michael@0 1737 }
michael@0 1738
michael@0 1739 /*
michael@0 1740 * If our child was just our end-of-contents octets, we are done.
michael@0 1741 */
michael@0 1742 if (child->endofcontents)
michael@0 1743 done = PR_TRUE;
michael@0 1744 }
michael@0 1745
michael@0 1746 /*
michael@0 1747 * Stop or do the next one.
michael@0 1748 */
michael@0 1749 if (done) {
michael@0 1750 child->place = notInUse;
michael@0 1751 state->place = afterConstructedString;
michael@0 1752 } else {
michael@0 1753 sec_asn1d_scrub_state (child);
michael@0 1754 state->top->current = child;
michael@0 1755 }
michael@0 1756 }
michael@0 1757
michael@0 1758
michael@0 1759 /*
michael@0 1760 * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
michael@0 1761 */
michael@0 1762 static void
michael@0 1763 sec_asn1d_next_in_group (sec_asn1d_state *state)
michael@0 1764 {
michael@0 1765 sec_asn1d_state *child;
michael@0 1766 unsigned long child_consumed;
michael@0 1767
michael@0 1768 PORT_Assert (state->place == duringGroup);
michael@0 1769 PORT_Assert (state->child != NULL);
michael@0 1770
michael@0 1771 child = state->child;
michael@0 1772
michael@0 1773 child_consumed = child->consumed;
michael@0 1774 child->consumed = 0;
michael@0 1775 state->consumed += child_consumed;
michael@0 1776
michael@0 1777 /*
michael@0 1778 * If our child was just our end-of-contents octets, we are done.
michael@0 1779 */
michael@0 1780 if (child->endofcontents) {
michael@0 1781 /* XXX I removed the PORT_Assert (child->dest == NULL) because there
michael@0 1782 * was a bug in that a template that was a sequence of which also had
michael@0 1783 * a child of a sequence of, in an indefinite group was not working
michael@0 1784 * properly. This fix seems to work, (added the if statement below),
michael@0 1785 * and nothing appears broken, but I am putting this note here just
michael@0 1786 * in case. */
michael@0 1787 /*
michael@0 1788 * XXX No matter how many times I read that comment,
michael@0 1789 * I cannot figure out what case he was fixing. I believe what he
michael@0 1790 * did was deliberate, so I am loathe to touch it. I need to
michael@0 1791 * understand how it could ever be that child->dest != NULL but
michael@0 1792 * child->endofcontents is true, and why it is important to check
michael@0 1793 * that state->subitems_head is NULL. This really needs to be
michael@0 1794 * figured out, as I am not sure if the following code should be
michael@0 1795 * compensating for "offset", as is done a little farther below
michael@0 1796 * in the more normal case.
michael@0 1797 */
michael@0 1798 PORT_Assert (state->indefinite);
michael@0 1799 PORT_Assert (state->pending == 0);
michael@0 1800 if(child->dest && !state->subitems_head) {
michael@0 1801 sec_asn1d_add_to_subitems (state, child->dest, 0, PR_FALSE);
michael@0 1802 child->dest = NULL;
michael@0 1803 }
michael@0 1804
michael@0 1805 child->place = notInUse;
michael@0 1806 state->place = afterGroup;
michael@0 1807 return;
michael@0 1808 }
michael@0 1809
michael@0 1810 /*
michael@0 1811 * Do the "after" field notification for next in group.
michael@0 1812 */
michael@0 1813 sec_asn1d_notify_after (state->top, child->dest, child->depth);
michael@0 1814
michael@0 1815 /*
michael@0 1816 * Save it away (unless we are not storing).
michael@0 1817 */
michael@0 1818 if (child->dest != NULL) {
michael@0 1819 void *dest;
michael@0 1820
michael@0 1821 dest = child->dest;
michael@0 1822 dest = (char *)dest - child->theTemplate->offset;
michael@0 1823 sec_asn1d_add_to_subitems (state, dest, 0, PR_FALSE);
michael@0 1824 child->dest = NULL;
michael@0 1825 }
michael@0 1826
michael@0 1827 /*
michael@0 1828 * Account for those bytes; see if we are done.
michael@0 1829 */
michael@0 1830 if (state->pending) {
michael@0 1831 PORT_Assert (!state->indefinite);
michael@0 1832 if (child_consumed > state->pending) {
michael@0 1833 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1834 state->top->status = decodeError;
michael@0 1835 return;
michael@0 1836 }
michael@0 1837
michael@0 1838 state->pending -= child_consumed;
michael@0 1839 if (state->pending == 0) {
michael@0 1840 child->place = notInUse;
michael@0 1841 state->place = afterGroup;
michael@0 1842 return;
michael@0 1843 }
michael@0 1844 }
michael@0 1845
michael@0 1846 /*
michael@0 1847 * Do the "before" field notification for next item in group.
michael@0 1848 */
michael@0 1849 sec_asn1d_notify_before (state->top, child->dest, child->depth);
michael@0 1850
michael@0 1851 /*
michael@0 1852 * Now we do the next one.
michael@0 1853 */
michael@0 1854 sec_asn1d_scrub_state (child);
michael@0 1855
michael@0 1856 /* Initialize child state from the template */
michael@0 1857 sec_asn1d_init_state_based_on_template(child);
michael@0 1858
michael@0 1859 state->top->current = child;
michael@0 1860 }
michael@0 1861
michael@0 1862
michael@0 1863 /*
michael@0 1864 * We are moving along through a sequence; move forward by one,
michael@0 1865 * (detecting end-of-sequence when it happens).
michael@0 1866 * XXX The handling of "missing" is ugly. Fix it.
michael@0 1867 */
michael@0 1868 static void
michael@0 1869 sec_asn1d_next_in_sequence (sec_asn1d_state *state)
michael@0 1870 {
michael@0 1871 sec_asn1d_state *child;
michael@0 1872 unsigned long child_consumed;
michael@0 1873 PRBool child_missing;
michael@0 1874
michael@0 1875 PORT_Assert (state->place == duringSequence);
michael@0 1876 PORT_Assert (state->child != NULL);
michael@0 1877
michael@0 1878 child = state->child;
michael@0 1879
michael@0 1880 /*
michael@0 1881 * Do the "after" field notification.
michael@0 1882 */
michael@0 1883 sec_asn1d_notify_after (state->top, child->dest, child->depth);
michael@0 1884
michael@0 1885 child_missing = (PRBool) child->missing;
michael@0 1886 child_consumed = child->consumed;
michael@0 1887 child->consumed = 0;
michael@0 1888
michael@0 1889 /*
michael@0 1890 * Take care of accounting.
michael@0 1891 */
michael@0 1892 if (child_missing) {
michael@0 1893 PORT_Assert (child->optional);
michael@0 1894 } else {
michael@0 1895 state->consumed += child_consumed;
michael@0 1896 /*
michael@0 1897 * Free any grandchild.
michael@0 1898 */
michael@0 1899 sec_asn1d_free_child (child, PR_FALSE);
michael@0 1900 if (state->pending) {
michael@0 1901 PORT_Assert (!state->indefinite);
michael@0 1902 if (child_consumed > state->pending) {
michael@0 1903 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1904 state->top->status = decodeError;
michael@0 1905 return;
michael@0 1906 }
michael@0 1907 state->pending -= child_consumed;
michael@0 1908 if (state->pending == 0) {
michael@0 1909 child->theTemplate++;
michael@0 1910 while (child->theTemplate->kind != 0) {
michael@0 1911 if ((child->theTemplate->kind & SEC_ASN1_OPTIONAL) == 0) {
michael@0 1912 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1913 state->top->status = decodeError;
michael@0 1914 return;
michael@0 1915 }
michael@0 1916 child->theTemplate++;
michael@0 1917 }
michael@0 1918 child->place = notInUse;
michael@0 1919 state->place = afterEndOfContents;
michael@0 1920 return;
michael@0 1921 }
michael@0 1922 }
michael@0 1923 }
michael@0 1924
michael@0 1925 /*
michael@0 1926 * Move forward.
michael@0 1927 */
michael@0 1928 child->theTemplate++;
michael@0 1929 if (child->theTemplate->kind == 0) {
michael@0 1930 /*
michael@0 1931 * We are done with this sequence.
michael@0 1932 */
michael@0 1933 child->place = notInUse;
michael@0 1934 if (state->pending) {
michael@0 1935 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1936 state->top->status = decodeError;
michael@0 1937 } else if (child_missing) {
michael@0 1938 /*
michael@0 1939 * We got to the end, but have a child that started parsing
michael@0 1940 * and ended up "missing". The only legitimate reason for
michael@0 1941 * this is that we had one or more optional fields at the
michael@0 1942 * end of our sequence, and we were encoded indefinite-length,
michael@0 1943 * so when we went looking for those optional fields we
michael@0 1944 * found our end-of-contents octets instead.
michael@0 1945 * (Yes, this is ugly; dunno a better way to handle it.)
michael@0 1946 * So, first confirm the situation, and then mark that we
michael@0 1947 * are done.
michael@0 1948 */
michael@0 1949 if (state->indefinite && child->endofcontents) {
michael@0 1950 PORT_Assert (child_consumed == 2);
michael@0 1951 if (child_consumed != 2) {
michael@0 1952 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1953 state->top->status = decodeError;
michael@0 1954 } else {
michael@0 1955 state->consumed += child_consumed;
michael@0 1956 state->place = afterEndOfContents;
michael@0 1957 }
michael@0 1958 } else {
michael@0 1959 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 1960 state->top->status = decodeError;
michael@0 1961 }
michael@0 1962 } else {
michael@0 1963 /*
michael@0 1964 * We have to finish out, maybe reading end-of-contents octets;
michael@0 1965 * let the normal logic do the right thing.
michael@0 1966 */
michael@0 1967 state->place = beforeEndOfContents;
michael@0 1968 }
michael@0 1969 } else {
michael@0 1970 unsigned char child_found_tag_modifiers = 0;
michael@0 1971 unsigned long child_found_tag_number = 0;
michael@0 1972
michael@0 1973 /*
michael@0 1974 * Reset state and push.
michael@0 1975 */
michael@0 1976 if (state->dest != NULL)
michael@0 1977 child->dest = (char *)state->dest + child->theTemplate->offset;
michael@0 1978
michael@0 1979 /*
michael@0 1980 * Do the "before" field notification.
michael@0 1981 */
michael@0 1982 sec_asn1d_notify_before (state->top, child->dest, child->depth);
michael@0 1983
michael@0 1984 if (child_missing) { /* if previous child was missing, copy the tag data we already have */
michael@0 1985 child_found_tag_modifiers = child->found_tag_modifiers;
michael@0 1986 child_found_tag_number = child->found_tag_number;
michael@0 1987 }
michael@0 1988 state->top->current = child;
michael@0 1989 child = sec_asn1d_init_state_based_on_template (child);
michael@0 1990 if (child_missing && child) {
michael@0 1991 child->place = afterIdentifier;
michael@0 1992 child->found_tag_modifiers = child_found_tag_modifiers;
michael@0 1993 child->found_tag_number = child_found_tag_number;
michael@0 1994 child->consumed = child_consumed;
michael@0 1995 if (child->underlying_kind == SEC_ASN1_ANY
michael@0 1996 && !child->top->filter_only) {
michael@0 1997 /*
michael@0 1998 * If the new field is an ANY, and we are storing, then
michael@0 1999 * we need to save the tag out. We would have done this
michael@0 2000 * already in the normal case, but since we were looking
michael@0 2001 * for an optional field, and we did not find it, we only
michael@0 2002 * now realize we need to save the tag.
michael@0 2003 */
michael@0 2004 unsigned char identifier;
michael@0 2005
michael@0 2006 /*
michael@0 2007 * Check that we did not end up with a high tag; for that
michael@0 2008 * we need to re-encode the tag into multiple bytes in order
michael@0 2009 * to store it back to look like what we parsed originally.
michael@0 2010 * In practice this does not happen, but for completeness
michael@0 2011 * sake it should probably be made to work at some point.
michael@0 2012 */
michael@0 2013 PORT_Assert (child_found_tag_number < SEC_ASN1_HIGH_TAG_NUMBER);
michael@0 2014 identifier = (unsigned char)(child_found_tag_modifiers | child_found_tag_number);
michael@0 2015 sec_asn1d_record_any_header (child, (char *) &identifier, 1);
michael@0 2016 }
michael@0 2017 }
michael@0 2018 }
michael@0 2019 }
michael@0 2020
michael@0 2021
michael@0 2022 static void
michael@0 2023 sec_asn1d_concat_substrings (sec_asn1d_state *state)
michael@0 2024 {
michael@0 2025 PORT_Assert (state->place == afterConstructedString);
michael@0 2026
michael@0 2027 if (state->subitems_head != NULL) {
michael@0 2028 struct subitem *substring;
michael@0 2029 unsigned long alloc_len, item_len;
michael@0 2030 unsigned char *where;
michael@0 2031 SECItem *item;
michael@0 2032 PRBool is_bit_string;
michael@0 2033
michael@0 2034 item_len = 0;
michael@0 2035 is_bit_string = (state->underlying_kind == SEC_ASN1_BIT_STRING)
michael@0 2036 ? PR_TRUE : PR_FALSE;
michael@0 2037
michael@0 2038 substring = state->subitems_head;
michael@0 2039 while (substring != NULL) {
michael@0 2040 /*
michael@0 2041 * All bit-string substrings except the last one should be
michael@0 2042 * a clean multiple of 8 bits.
michael@0 2043 */
michael@0 2044 if (is_bit_string && (substring->next == NULL)
michael@0 2045 && (substring->len & 0x7)) {
michael@0 2046 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 2047 state->top->status = decodeError;
michael@0 2048 return;
michael@0 2049 }
michael@0 2050 item_len += substring->len;
michael@0 2051 substring = substring->next;
michael@0 2052 }
michael@0 2053
michael@0 2054 if (is_bit_string) {
michael@0 2055 alloc_len = ((item_len + 7) >> 3);
michael@0 2056 } else {
michael@0 2057 /*
michael@0 2058 * Add 2 for the end-of-contents octets of an indefinite-length
michael@0 2059 * ANY that is *not* also an INNER. Because we zero-allocate
michael@0 2060 * below, all we need to do is increase the length here.
michael@0 2061 */
michael@0 2062 if (state->underlying_kind == SEC_ASN1_ANY && state->indefinite)
michael@0 2063 item_len += 2;
michael@0 2064 alloc_len = item_len;
michael@0 2065 }
michael@0 2066
michael@0 2067 item = (SECItem *)(state->dest);
michael@0 2068 PORT_Assert (item != NULL);
michael@0 2069 PORT_Assert (item->data == NULL);
michael@0 2070 item->data = (unsigned char*)sec_asn1d_zalloc (state->top->their_pool,
michael@0 2071 alloc_len);
michael@0 2072 if (item->data == NULL) {
michael@0 2073 state->top->status = decodeError;
michael@0 2074 return;
michael@0 2075 }
michael@0 2076 item->len = item_len;
michael@0 2077
michael@0 2078 where = item->data;
michael@0 2079 substring = state->subitems_head;
michael@0 2080 while (substring != NULL) {
michael@0 2081 if (is_bit_string)
michael@0 2082 item_len = (substring->len + 7) >> 3;
michael@0 2083 else
michael@0 2084 item_len = substring->len;
michael@0 2085 PORT_Memcpy (where, substring->data, item_len);
michael@0 2086 where += item_len;
michael@0 2087 substring = substring->next;
michael@0 2088 }
michael@0 2089
michael@0 2090 /*
michael@0 2091 * Because we use arenas and have a mark set, we later free
michael@0 2092 * everything we have allocated, so this does *not* present
michael@0 2093 * a memory leak (it is just temporarily left dangling).
michael@0 2094 */
michael@0 2095 state->subitems_head = state->subitems_tail = NULL;
michael@0 2096 }
michael@0 2097
michael@0 2098 state->place = afterEndOfContents;
michael@0 2099 }
michael@0 2100
michael@0 2101
michael@0 2102 static void
michael@0 2103 sec_asn1d_concat_group (sec_asn1d_state *state)
michael@0 2104 {
michael@0 2105 const void ***placep;
michael@0 2106
michael@0 2107 PORT_Assert (state->place == afterGroup);
michael@0 2108
michael@0 2109 placep = (const void***)state->dest;
michael@0 2110 PORT_Assert(state->subitems_head == NULL || placep != NULL);
michael@0 2111 if (placep != NULL) {
michael@0 2112 struct subitem *item;
michael@0 2113 const void **group;
michael@0 2114 int count;
michael@0 2115
michael@0 2116 count = 0;
michael@0 2117 item = state->subitems_head;
michael@0 2118 while (item != NULL) {
michael@0 2119 PORT_Assert (item->next != NULL || item == state->subitems_tail);
michael@0 2120 count++;
michael@0 2121 item = item->next;
michael@0 2122 }
michael@0 2123
michael@0 2124 group = (const void**)sec_asn1d_zalloc (state->top->their_pool,
michael@0 2125 (count + 1) * (sizeof(void *)));
michael@0 2126 if (group == NULL) {
michael@0 2127 state->top->status = decodeError;
michael@0 2128 return;
michael@0 2129 }
michael@0 2130
michael@0 2131 *placep = group;
michael@0 2132
michael@0 2133 item = state->subitems_head;
michael@0 2134 while (item != NULL) {
michael@0 2135 *group++ = item->data;
michael@0 2136 item = item->next;
michael@0 2137 }
michael@0 2138 *group = NULL;
michael@0 2139
michael@0 2140 /*
michael@0 2141 * Because we use arenas and have a mark set, we later free
michael@0 2142 * everything we have allocated, so this does *not* present
michael@0 2143 * a memory leak (it is just temporarily left dangling).
michael@0 2144 */
michael@0 2145 state->subitems_head = state->subitems_tail = NULL;
michael@0 2146 }
michael@0 2147
michael@0 2148 state->place = afterEndOfContents;
michael@0 2149 }
michael@0 2150
michael@0 2151
michael@0 2152 /*
michael@0 2153 * For those states that push a child to handle a subtemplate,
michael@0 2154 * "absorb" that child (transfer necessary information).
michael@0 2155 */
michael@0 2156 static void
michael@0 2157 sec_asn1d_absorb_child (sec_asn1d_state *state)
michael@0 2158 {
michael@0 2159 /*
michael@0 2160 * There is absolutely supposed to be a child there.
michael@0 2161 */
michael@0 2162 PORT_Assert (state->child != NULL);
michael@0 2163
michael@0 2164 /*
michael@0 2165 * Inherit the missing status of our child, and do the ugly
michael@0 2166 * backing-up if necessary.
michael@0 2167 */
michael@0 2168 state->missing = state->child->missing;
michael@0 2169 if (state->missing) {
michael@0 2170 state->found_tag_number = state->child->found_tag_number;
michael@0 2171 state->found_tag_modifiers = state->child->found_tag_modifiers;
michael@0 2172 state->endofcontents = state->child->endofcontents;
michael@0 2173 }
michael@0 2174
michael@0 2175 /*
michael@0 2176 * Add in number of bytes consumed by child.
michael@0 2177 * (Only EXPLICIT should have already consumed bytes itself.)
michael@0 2178 */
michael@0 2179 PORT_Assert (state->place == afterExplicit || state->consumed == 0);
michael@0 2180 state->consumed += state->child->consumed;
michael@0 2181
michael@0 2182 /*
michael@0 2183 * Subtract from bytes pending; this only applies to a definite-length
michael@0 2184 * EXPLICIT field.
michael@0 2185 */
michael@0 2186 if (state->pending) {
michael@0 2187 PORT_Assert (!state->indefinite);
michael@0 2188 PORT_Assert (state->place == afterExplicit);
michael@0 2189
michael@0 2190 /*
michael@0 2191 * If we had a definite-length explicit, then what the child
michael@0 2192 * consumed should be what was left pending.
michael@0 2193 */
michael@0 2194 if (state->pending != state->child->consumed) {
michael@0 2195 if (state->pending < state->child->consumed) {
michael@0 2196 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 2197 state->top->status = decodeError;
michael@0 2198 return;
michael@0 2199 }
michael@0 2200 /*
michael@0 2201 * Okay, this is a hack. It *should* be an error whether
michael@0 2202 * pending is too big or too small, but it turns out that
michael@0 2203 * we had a bug in our *old* DER encoder that ended up
michael@0 2204 * counting an explicit header twice in the case where
michael@0 2205 * the underlying type was an ANY. So, because we cannot
michael@0 2206 * prevent receiving these (our own certificate server can
michael@0 2207 * send them to us), we need to be lenient and accept them.
michael@0 2208 * To do so, we need to pretend as if we read all of the
michael@0 2209 * bytes that the header said we would find, even though
michael@0 2210 * we actually came up short.
michael@0 2211 */
michael@0 2212 state->consumed += (state->pending - state->child->consumed);
michael@0 2213 }
michael@0 2214 state->pending = 0;
michael@0 2215 }
michael@0 2216
michael@0 2217 /*
michael@0 2218 * Indicate that we are done with child.
michael@0 2219 */
michael@0 2220 state->child->consumed = 0;
michael@0 2221
michael@0 2222 /*
michael@0 2223 * And move on to final state.
michael@0 2224 * (Technically everybody could move to afterEndOfContents except
michael@0 2225 * for an indefinite-length EXPLICIT; for simplicity though we assert
michael@0 2226 * that but let the end-of-contents code do the real determination.)
michael@0 2227 */
michael@0 2228 PORT_Assert (state->place == afterExplicit || (! state->indefinite));
michael@0 2229 state->place = beforeEndOfContents;
michael@0 2230 }
michael@0 2231
michael@0 2232
michael@0 2233 static void
michael@0 2234 sec_asn1d_prepare_for_end_of_contents (sec_asn1d_state *state)
michael@0 2235 {
michael@0 2236 PORT_Assert (state->place == beforeEndOfContents);
michael@0 2237
michael@0 2238 if (state->indefinite) {
michael@0 2239 state->place = duringEndOfContents;
michael@0 2240 state->pending = 2;
michael@0 2241 } else {
michael@0 2242 state->place = afterEndOfContents;
michael@0 2243 }
michael@0 2244 }
michael@0 2245
michael@0 2246
michael@0 2247 static unsigned long
michael@0 2248 sec_asn1d_parse_end_of_contents (sec_asn1d_state *state,
michael@0 2249 const char *buf, unsigned long len)
michael@0 2250 {
michael@0 2251 unsigned int i;
michael@0 2252
michael@0 2253 PORT_Assert (state->pending <= 2);
michael@0 2254 PORT_Assert (state->place == duringEndOfContents);
michael@0 2255
michael@0 2256 if (len == 0) {
michael@0 2257 state->top->status = needBytes;
michael@0 2258 return 0;
michael@0 2259 }
michael@0 2260
michael@0 2261 if (state->pending < len)
michael@0 2262 len = state->pending;
michael@0 2263
michael@0 2264 for (i = 0; i < len; i++) {
michael@0 2265 if (buf[i] != 0) {
michael@0 2266 /*
michael@0 2267 * We expect to find only zeros; if not, just give up.
michael@0 2268 */
michael@0 2269 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 2270 state->top->status = decodeError;
michael@0 2271 return 0;
michael@0 2272 }
michael@0 2273 }
michael@0 2274
michael@0 2275 state->pending -= len;
michael@0 2276
michael@0 2277 if (state->pending == 0) {
michael@0 2278 state->place = afterEndOfContents;
michael@0 2279 state->endofcontents = PR_TRUE;
michael@0 2280 }
michael@0 2281
michael@0 2282 return len;
michael@0 2283 }
michael@0 2284
michael@0 2285
michael@0 2286 static void
michael@0 2287 sec_asn1d_pop_state (sec_asn1d_state *state)
michael@0 2288 {
michael@0 2289 #if 0 /* XXX I think this should always be handled explicitly by parent? */
michael@0 2290 /*
michael@0 2291 * Account for our child.
michael@0 2292 */
michael@0 2293 if (state->child != NULL) {
michael@0 2294 state->consumed += state->child->consumed;
michael@0 2295 if (state->pending) {
michael@0 2296 PORT_Assert (!state->indefinite);
michael@0 2297 if (state->child->consumed > state->pending) {
michael@0 2298 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 2299 state->top->status = decodeError;
michael@0 2300 } else {
michael@0 2301 state->pending -= state->child->consumed;
michael@0 2302 }
michael@0 2303 }
michael@0 2304 state->child->consumed = 0;
michael@0 2305 }
michael@0 2306 #endif /* XXX */
michael@0 2307
michael@0 2308 /*
michael@0 2309 * Free our child.
michael@0 2310 */
michael@0 2311 sec_asn1d_free_child (state, PR_FALSE);
michael@0 2312
michael@0 2313 /*
michael@0 2314 * Just make my parent be the current state. It will then clean
michael@0 2315 * up after me and free me (or reuse me).
michael@0 2316 */
michael@0 2317 state->top->current = state->parent;
michael@0 2318 }
michael@0 2319
michael@0 2320 static sec_asn1d_state *
michael@0 2321 sec_asn1d_before_choice (sec_asn1d_state *state)
michael@0 2322 {
michael@0 2323 sec_asn1d_state *child;
michael@0 2324
michael@0 2325 if (state->allocate) {
michael@0 2326 void *dest;
michael@0 2327
michael@0 2328 dest = sec_asn1d_zalloc(state->top->their_pool, state->theTemplate->size);
michael@0 2329 if ((void *)NULL == dest) {
michael@0 2330 state->top->status = decodeError;
michael@0 2331 return (sec_asn1d_state *)NULL;
michael@0 2332 }
michael@0 2333
michael@0 2334 state->dest = (char *)dest + state->theTemplate->offset;
michael@0 2335 }
michael@0 2336
michael@0 2337 child = sec_asn1d_push_state(state->top, state->theTemplate + 1,
michael@0 2338 (char *)state->dest - state->theTemplate->offset,
michael@0 2339 PR_FALSE);
michael@0 2340 if ((sec_asn1d_state *)NULL == child) {
michael@0 2341 return (sec_asn1d_state *)NULL;
michael@0 2342 }
michael@0 2343
michael@0 2344 sec_asn1d_scrub_state(child);
michael@0 2345 child = sec_asn1d_init_state_based_on_template(child);
michael@0 2346 if ((sec_asn1d_state *)NULL == child) {
michael@0 2347 return (sec_asn1d_state *)NULL;
michael@0 2348 }
michael@0 2349
michael@0 2350 child->optional = PR_TRUE;
michael@0 2351
michael@0 2352 state->place = duringChoice;
michael@0 2353
michael@0 2354 return child;
michael@0 2355 }
michael@0 2356
michael@0 2357 static sec_asn1d_state *
michael@0 2358 sec_asn1d_during_choice (sec_asn1d_state *state)
michael@0 2359 {
michael@0 2360 sec_asn1d_state *child = state->child;
michael@0 2361
michael@0 2362 PORT_Assert((sec_asn1d_state *)NULL != child);
michael@0 2363
michael@0 2364 if (child->missing) {
michael@0 2365 unsigned char child_found_tag_modifiers = 0;
michael@0 2366 unsigned long child_found_tag_number = 0;
michael@0 2367 void * dest;
michael@0 2368
michael@0 2369 state->consumed += child->consumed;
michael@0 2370
michael@0 2371 if (child->endofcontents) {
michael@0 2372 /* This choice is probably the first item in a GROUP
michael@0 2373 ** (e.g. SET_OF) that was indefinite-length encoded.
michael@0 2374 ** We're actually at the end of that GROUP.
michael@0 2375 ** We look up the stack to be sure that we find
michael@0 2376 ** a state with indefinite length encoding before we
michael@0 2377 ** find a state (like a SEQUENCE) that is definite.
michael@0 2378 */
michael@0 2379 child->place = notInUse;
michael@0 2380 state->place = afterChoice;
michael@0 2381 state->endofcontents = PR_TRUE; /* propagate this up */
michael@0 2382 if (sec_asn1d_parent_allows_EOC(state))
michael@0 2383 return state;
michael@0 2384 PORT_SetError(SEC_ERROR_BAD_DER);
michael@0 2385 state->top->status = decodeError;
michael@0 2386 return NULL;
michael@0 2387 }
michael@0 2388
michael@0 2389 dest = (char *)child->dest - child->theTemplate->offset;
michael@0 2390 child->theTemplate++;
michael@0 2391
michael@0 2392 if (0 == child->theTemplate->kind) {
michael@0 2393 /* Ran out of choices */
michael@0 2394 PORT_SetError(SEC_ERROR_BAD_DER);
michael@0 2395 state->top->status = decodeError;
michael@0 2396 return (sec_asn1d_state *)NULL;
michael@0 2397 }
michael@0 2398 child->dest = (char *)dest + child->theTemplate->offset;
michael@0 2399
michael@0 2400 /* cargo'd from next_in_sequence innards */
michael@0 2401 if (state->pending) {
michael@0 2402 PORT_Assert(!state->indefinite);
michael@0 2403 if (child->consumed > state->pending) {
michael@0 2404 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 2405 state->top->status = decodeError;
michael@0 2406 return NULL;
michael@0 2407 }
michael@0 2408 state->pending -= child->consumed;
michael@0 2409 if (0 == state->pending) {
michael@0 2410 /* XXX uh.. not sure if I should have stopped this
michael@0 2411 * from happening before. */
michael@0 2412 PORT_Assert(0);
michael@0 2413 PORT_SetError(SEC_ERROR_BAD_DER);
michael@0 2414 state->top->status = decodeError;
michael@0 2415 return (sec_asn1d_state *)NULL;
michael@0 2416 }
michael@0 2417 }
michael@0 2418
michael@0 2419 child->consumed = 0;
michael@0 2420 sec_asn1d_scrub_state(child);
michael@0 2421
michael@0 2422 /* move it on top again */
michael@0 2423 state->top->current = child;
michael@0 2424
michael@0 2425 child_found_tag_modifiers = child->found_tag_modifiers;
michael@0 2426 child_found_tag_number = child->found_tag_number;
michael@0 2427
michael@0 2428 child = sec_asn1d_init_state_based_on_template(child);
michael@0 2429 if ((sec_asn1d_state *)NULL == child) {
michael@0 2430 return (sec_asn1d_state *)NULL;
michael@0 2431 }
michael@0 2432
michael@0 2433 /* copy our findings to the new top */
michael@0 2434 child->found_tag_modifiers = child_found_tag_modifiers;
michael@0 2435 child->found_tag_number = child_found_tag_number;
michael@0 2436
michael@0 2437 child->optional = PR_TRUE;
michael@0 2438 child->place = afterIdentifier;
michael@0 2439
michael@0 2440 return child;
michael@0 2441 }
michael@0 2442 if ((void *)NULL != state->dest) {
michael@0 2443 /* Store the enum */
michael@0 2444 int *which = (int *)state->dest;
michael@0 2445 *which = (int)child->theTemplate->size;
michael@0 2446 }
michael@0 2447
michael@0 2448 child->place = notInUse;
michael@0 2449
michael@0 2450 state->place = afterChoice;
michael@0 2451 return state;
michael@0 2452 }
michael@0 2453
michael@0 2454 static void
michael@0 2455 sec_asn1d_after_choice (sec_asn1d_state *state)
michael@0 2456 {
michael@0 2457 state->consumed += state->child->consumed;
michael@0 2458 state->child->consumed = 0;
michael@0 2459 state->place = afterEndOfContents;
michael@0 2460 sec_asn1d_pop_state(state);
michael@0 2461 }
michael@0 2462
michael@0 2463 unsigned long
michael@0 2464 sec_asn1d_uinteger(SECItem *src)
michael@0 2465 {
michael@0 2466 unsigned long value;
michael@0 2467 int len;
michael@0 2468
michael@0 2469 if (src->len > 5 || (src->len > 4 && src->data[0] == 0))
michael@0 2470 return 0;
michael@0 2471
michael@0 2472 value = 0;
michael@0 2473 len = src->len;
michael@0 2474 while (len) {
michael@0 2475 value <<= 8;
michael@0 2476 value |= src->data[--len];
michael@0 2477 }
michael@0 2478 return value;
michael@0 2479 }
michael@0 2480
michael@0 2481 SECStatus
michael@0 2482 SEC_ASN1DecodeInteger(SECItem *src, unsigned long *value)
michael@0 2483 {
michael@0 2484 unsigned long v;
michael@0 2485 unsigned int i;
michael@0 2486
michael@0 2487 if (src == NULL) {
michael@0 2488 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 2489 return SECFailure;
michael@0 2490 }
michael@0 2491
michael@0 2492 if (src->len > sizeof(unsigned long)) {
michael@0 2493 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 2494 return SECFailure;
michael@0 2495 }
michael@0 2496
michael@0 2497 if (src->data == NULL) {
michael@0 2498 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 2499 return SECFailure;
michael@0 2500 }
michael@0 2501
michael@0 2502 if (src->data[0] & 0x80)
michael@0 2503 v = -1; /* signed and negative - start with all 1's */
michael@0 2504 else
michael@0 2505 v = 0;
michael@0 2506
michael@0 2507 for (i= 0; i < src->len; i++) {
michael@0 2508 /* shift in next byte */
michael@0 2509 v <<= 8;
michael@0 2510 v |= src->data[i];
michael@0 2511 }
michael@0 2512 *value = v;
michael@0 2513 return SECSuccess;
michael@0 2514 }
michael@0 2515
michael@0 2516 #ifdef DEBUG_ASN1D_STATES
michael@0 2517 static void
michael@0 2518 dump_states(SEC_ASN1DecoderContext *cx)
michael@0 2519 {
michael@0 2520 sec_asn1d_state *state;
michael@0 2521 char kindBuf[256];
michael@0 2522
michael@0 2523 for (state = cx->current; state->parent; state = state->parent) {
michael@0 2524 ;
michael@0 2525 }
michael@0 2526
michael@0 2527 for (; state; state = state->child) {
michael@0 2528 int i;
michael@0 2529 for (i = 0; i < state->depth; i++) {
michael@0 2530 printf(" ");
michael@0 2531 }
michael@0 2532
michael@0 2533 i = formatKind(state->theTemplate->kind, kindBuf);
michael@0 2534 printf("%s: tmpl %08x, kind%s",
michael@0 2535 (state == cx->current) ? "STATE" : "State",
michael@0 2536 state->theTemplate,
michael@0 2537 kindBuf);
michael@0 2538 printf(" %s", (state->place >= 0 && state->place <= notInUse)
michael@0 2539 ? place_names[ state->place ]
michael@0 2540 : "(undefined)");
michael@0 2541 if (!i)
michael@0 2542 printf(", expect 0x%02x",
michael@0 2543 state->expect_tag_number | state->expect_tag_modifiers);
michael@0 2544
michael@0 2545 printf("%s%s%s %d\n",
michael@0 2546 state->indefinite ? ", indef" : "",
michael@0 2547 state->missing ? ", miss" : "",
michael@0 2548 state->endofcontents ? ", EOC" : "",
michael@0 2549 state->pending
michael@0 2550 );
michael@0 2551 }
michael@0 2552
michael@0 2553 return;
michael@0 2554 }
michael@0 2555 #endif /* DEBUG_ASN1D_STATES */
michael@0 2556
michael@0 2557 SECStatus
michael@0 2558 SEC_ASN1DecoderUpdate (SEC_ASN1DecoderContext *cx,
michael@0 2559 const char *buf, unsigned long len)
michael@0 2560 {
michael@0 2561 sec_asn1d_state *state = NULL;
michael@0 2562 unsigned long consumed;
michael@0 2563 SEC_ASN1EncodingPart what;
michael@0 2564 sec_asn1d_state *stateEnd = cx->current;
michael@0 2565
michael@0 2566 if (cx->status == needBytes)
michael@0 2567 cx->status = keepGoing;
michael@0 2568
michael@0 2569 while (cx->status == keepGoing) {
michael@0 2570 state = cx->current;
michael@0 2571 what = SEC_ASN1_Contents;
michael@0 2572 consumed = 0;
michael@0 2573 #ifdef DEBUG_ASN1D_STATES
michael@0 2574 printf("\nPLACE = %s, next byte = 0x%02x, %08x[%d]\n",
michael@0 2575 (state->place >= 0 && state->place <= notInUse) ?
michael@0 2576 place_names[ state->place ] : "(undefined)",
michael@0 2577 (unsigned int)((unsigned char *)buf)[ consumed ],
michael@0 2578 buf, consumed);
michael@0 2579 dump_states(cx);
michael@0 2580 #endif /* DEBUG_ASN1D_STATES */
michael@0 2581 switch (state->place) {
michael@0 2582 case beforeIdentifier:
michael@0 2583 consumed = sec_asn1d_parse_identifier (state, buf, len);
michael@0 2584 what = SEC_ASN1_Identifier;
michael@0 2585 break;
michael@0 2586 case duringIdentifier:
michael@0 2587 consumed = sec_asn1d_parse_more_identifier (state, buf, len);
michael@0 2588 what = SEC_ASN1_Identifier;
michael@0 2589 break;
michael@0 2590 case afterIdentifier:
michael@0 2591 sec_asn1d_confirm_identifier (state);
michael@0 2592 break;
michael@0 2593 case beforeLength:
michael@0 2594 consumed = sec_asn1d_parse_length (state, buf, len);
michael@0 2595 what = SEC_ASN1_Length;
michael@0 2596 break;
michael@0 2597 case duringLength:
michael@0 2598 consumed = sec_asn1d_parse_more_length (state, buf, len);
michael@0 2599 what = SEC_ASN1_Length;
michael@0 2600 break;
michael@0 2601 case afterLength:
michael@0 2602 sec_asn1d_prepare_for_contents (state);
michael@0 2603 break;
michael@0 2604 case beforeBitString:
michael@0 2605 consumed = sec_asn1d_parse_bit_string (state, buf, len);
michael@0 2606 break;
michael@0 2607 case duringBitString:
michael@0 2608 consumed = sec_asn1d_parse_more_bit_string (state, buf, len);
michael@0 2609 break;
michael@0 2610 case duringConstructedString:
michael@0 2611 sec_asn1d_next_substring (state);
michael@0 2612 break;
michael@0 2613 case duringGroup:
michael@0 2614 sec_asn1d_next_in_group (state);
michael@0 2615 break;
michael@0 2616 case duringLeaf:
michael@0 2617 consumed = sec_asn1d_parse_leaf (state, buf, len);
michael@0 2618 break;
michael@0 2619 case duringSaveEncoding:
michael@0 2620 sec_asn1d_reuse_encoding (state);
michael@0 2621 if (cx->status == decodeError) {
michael@0 2622 /* recursive call has already popped all states from stack.
michael@0 2623 ** Bail out quickly.
michael@0 2624 */
michael@0 2625 return SECFailure;
michael@0 2626 }
michael@0 2627 if (cx->status == needBytes) {
michael@0 2628 /* recursive call wanted more data. Fatal. Clean up below. */
michael@0 2629 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 2630 cx->status = decodeError;
michael@0 2631 }
michael@0 2632 break;
michael@0 2633 case duringSequence:
michael@0 2634 sec_asn1d_next_in_sequence (state);
michael@0 2635 break;
michael@0 2636 case afterConstructedString:
michael@0 2637 sec_asn1d_concat_substrings (state);
michael@0 2638 break;
michael@0 2639 case afterExplicit:
michael@0 2640 case afterImplicit:
michael@0 2641 case afterInline:
michael@0 2642 case afterPointer:
michael@0 2643 sec_asn1d_absorb_child (state);
michael@0 2644 break;
michael@0 2645 case afterGroup:
michael@0 2646 sec_asn1d_concat_group (state);
michael@0 2647 break;
michael@0 2648 case afterSaveEncoding:
michael@0 2649 /* SEC_ASN1DecoderUpdate has called itself recursively to
michael@0 2650 ** decode SAVEd encoded data, and now is done decoding that.
michael@0 2651 ** Return to the calling copy of SEC_ASN1DecoderUpdate.
michael@0 2652 */
michael@0 2653 return SECSuccess;
michael@0 2654 case beforeEndOfContents:
michael@0 2655 sec_asn1d_prepare_for_end_of_contents (state);
michael@0 2656 break;
michael@0 2657 case duringEndOfContents:
michael@0 2658 consumed = sec_asn1d_parse_end_of_contents (state, buf, len);
michael@0 2659 what = SEC_ASN1_EndOfContents;
michael@0 2660 break;
michael@0 2661 case afterEndOfContents:
michael@0 2662 sec_asn1d_pop_state (state);
michael@0 2663 break;
michael@0 2664 case beforeChoice:
michael@0 2665 state = sec_asn1d_before_choice(state);
michael@0 2666 break;
michael@0 2667 case duringChoice:
michael@0 2668 state = sec_asn1d_during_choice(state);
michael@0 2669 break;
michael@0 2670 case afterChoice:
michael@0 2671 sec_asn1d_after_choice(state);
michael@0 2672 break;
michael@0 2673 case notInUse:
michael@0 2674 default:
michael@0 2675 /* This is not an error, but rather a plain old BUG! */
michael@0 2676 PORT_Assert (0);
michael@0 2677 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 2678 cx->status = decodeError;
michael@0 2679 break;
michael@0 2680 }
michael@0 2681
michael@0 2682 if (cx->status == decodeError)
michael@0 2683 break;
michael@0 2684
michael@0 2685 /* We should not consume more than we have. */
michael@0 2686 PORT_Assert (consumed <= len);
michael@0 2687 if (consumed > len) {
michael@0 2688 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 2689 cx->status = decodeError;
michael@0 2690 break;
michael@0 2691 }
michael@0 2692
michael@0 2693 /* It might have changed, so we have to update our local copy. */
michael@0 2694 state = cx->current;
michael@0 2695
michael@0 2696 /* If it is NULL, we have popped all the way to the top. */
michael@0 2697 if (state == NULL) {
michael@0 2698 PORT_Assert (consumed == 0);
michael@0 2699 #if 0 /* XXX I want this here, but it seems that we have situations (like
michael@0 2700 * downloading a pkcs7 cert chain from some issuers) that give us a
michael@0 2701 * length which is greater than the entire encoding. So, we cannot
michael@0 2702 * have this be an error.
michael@0 2703 */
michael@0 2704 if (len > 0) {
michael@0 2705 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 2706 cx->status = decodeError;
michael@0 2707 } else
michael@0 2708 #endif
michael@0 2709 cx->status = allDone;
michael@0 2710 break;
michael@0 2711 }
michael@0 2712 else if (state->theTemplate->kind == SEC_ASN1_SKIP_REST) {
michael@0 2713 cx->status = allDone;
michael@0 2714 break;
michael@0 2715 }
michael@0 2716
michael@0 2717 if (consumed == 0)
michael@0 2718 continue;
michael@0 2719
michael@0 2720 /*
michael@0 2721 * The following check is specifically looking for an ANY
michael@0 2722 * that is *not* also an INNER, because we need to save aside
michael@0 2723 * all bytes in that case -- the contents parts will get
michael@0 2724 * handled like all other contents, and the end-of-contents
michael@0 2725 * bytes are added by the concat code, but the outer header
michael@0 2726 * bytes need to get saved too, so we do them explicitly here.
michael@0 2727 */
michael@0 2728 if (state->underlying_kind == SEC_ASN1_ANY
michael@0 2729 && !cx->filter_only && (what == SEC_ASN1_Identifier
michael@0 2730 || what == SEC_ASN1_Length)) {
michael@0 2731 sec_asn1d_record_any_header (state, buf, consumed);
michael@0 2732 }
michael@0 2733
michael@0 2734 /*
michael@0 2735 * We had some number of good, accepted bytes. If the caller
michael@0 2736 * has registered to see them, pass them along.
michael@0 2737 */
michael@0 2738 if (state->top->filter_proc != NULL) {
michael@0 2739 int depth;
michael@0 2740
michael@0 2741 depth = state->depth;
michael@0 2742 if (what == SEC_ASN1_EndOfContents && !state->indefinite) {
michael@0 2743 PORT_Assert (state->parent != NULL
michael@0 2744 && state->parent->indefinite);
michael@0 2745 depth--;
michael@0 2746 PORT_Assert (depth == state->parent->depth);
michael@0 2747 }
michael@0 2748 (* state->top->filter_proc) (state->top->filter_arg,
michael@0 2749 buf, consumed, depth, what);
michael@0 2750 }
michael@0 2751
michael@0 2752 state->consumed += consumed;
michael@0 2753 buf += consumed;
michael@0 2754 len -= consumed;
michael@0 2755 }
michael@0 2756
michael@0 2757 if (cx->status == decodeError) {
michael@0 2758 while (state != NULL && stateEnd->parent!=state) {
michael@0 2759 sec_asn1d_free_child (state, PR_TRUE);
michael@0 2760 state = state->parent;
michael@0 2761 }
michael@0 2762 #ifdef SEC_ASN1D_FREE_ON_ERROR /*
michael@0 2763 * XXX This does not work because we can
michael@0 2764 * end up leaving behind dangling pointers
michael@0 2765 * to stuff that was allocated. In order
michael@0 2766 * to make this really work (which would
michael@0 2767 * be a good thing, I think), we need to
michael@0 2768 * keep track of every place/pointer that
michael@0 2769 * was allocated and make sure to NULL it
michael@0 2770 * out before we then free back to the mark.
michael@0 2771 */
michael@0 2772 if (cx->their_pool != NULL) {
michael@0 2773 PORT_Assert (cx->their_mark != NULL);
michael@0 2774 PORT_ArenaRelease (cx->their_pool, cx->their_mark);
michael@0 2775 cx->their_mark = NULL;
michael@0 2776 }
michael@0 2777 #endif
michael@0 2778 return SECFailure;
michael@0 2779 }
michael@0 2780
michael@0 2781 #if 0 /* XXX This is what I want, but cannot have because it seems we
michael@0 2782 * have situations (like when downloading a pkcs7 cert chain from
michael@0 2783 * some issuers) that give us a total length which is greater than
michael@0 2784 * the entire encoding. So, we have to allow allDone to have a
michael@0 2785 * remaining length greater than zero. I wanted to catch internal
michael@0 2786 * bugs with this, noticing when we do not have the right length.
michael@0 2787 * Oh well.
michael@0 2788 */
michael@0 2789 PORT_Assert (len == 0
michael@0 2790 && (cx->status == needBytes || cx->status == allDone));
michael@0 2791 #else
michael@0 2792 PORT_Assert ((len == 0 && cx->status == needBytes)
michael@0 2793 || cx->status == allDone);
michael@0 2794 #endif
michael@0 2795 return SECSuccess;
michael@0 2796 }
michael@0 2797
michael@0 2798
michael@0 2799 SECStatus
michael@0 2800 SEC_ASN1DecoderFinish (SEC_ASN1DecoderContext *cx)
michael@0 2801 {
michael@0 2802 SECStatus rv;
michael@0 2803
michael@0 2804 if (cx->status == needBytes) {
michael@0 2805 PORT_SetError (SEC_ERROR_BAD_DER);
michael@0 2806 rv = SECFailure;
michael@0 2807 } else {
michael@0 2808 rv = SECSuccess;
michael@0 2809 }
michael@0 2810
michael@0 2811 /*
michael@0 2812 * XXX anything else that needs to be finished?
michael@0 2813 */
michael@0 2814
michael@0 2815 PORT_FreeArena (cx->our_pool, PR_TRUE);
michael@0 2816
michael@0 2817 return rv;
michael@0 2818 }
michael@0 2819
michael@0 2820
michael@0 2821 SEC_ASN1DecoderContext *
michael@0 2822 SEC_ASN1DecoderStart (PLArenaPool *their_pool, void *dest,
michael@0 2823 const SEC_ASN1Template *theTemplate)
michael@0 2824 {
michael@0 2825 PLArenaPool *our_pool;
michael@0 2826 SEC_ASN1DecoderContext *cx;
michael@0 2827
michael@0 2828 our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
michael@0 2829 if (our_pool == NULL)
michael@0 2830 return NULL;
michael@0 2831
michael@0 2832 cx = (SEC_ASN1DecoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
michael@0 2833 if (cx == NULL) {
michael@0 2834 PORT_FreeArena (our_pool, PR_FALSE);
michael@0 2835 return NULL;
michael@0 2836 }
michael@0 2837
michael@0 2838 cx->our_pool = our_pool;
michael@0 2839 if (their_pool != NULL) {
michael@0 2840 cx->their_pool = their_pool;
michael@0 2841 #ifdef SEC_ASN1D_FREE_ON_ERROR
michael@0 2842 cx->their_mark = PORT_ArenaMark (their_pool);
michael@0 2843 #endif
michael@0 2844 }
michael@0 2845
michael@0 2846 cx->status = needBytes;
michael@0 2847
michael@0 2848 if (sec_asn1d_push_state(cx, theTemplate, dest, PR_FALSE) == NULL
michael@0 2849 || sec_asn1d_init_state_based_on_template (cx->current) == NULL) {
michael@0 2850 /*
michael@0 2851 * Trouble initializing (probably due to failed allocations)
michael@0 2852 * requires that we just give up.
michael@0 2853 */
michael@0 2854 PORT_FreeArena (our_pool, PR_FALSE);
michael@0 2855 return NULL;
michael@0 2856 }
michael@0 2857
michael@0 2858 return cx;
michael@0 2859 }
michael@0 2860
michael@0 2861
michael@0 2862 void
michael@0 2863 SEC_ASN1DecoderSetFilterProc (SEC_ASN1DecoderContext *cx,
michael@0 2864 SEC_ASN1WriteProc fn, void *arg,
michael@0 2865 PRBool only)
michael@0 2866 {
michael@0 2867 /* check that we are "between" fields here */
michael@0 2868 PORT_Assert (cx->during_notify);
michael@0 2869
michael@0 2870 cx->filter_proc = fn;
michael@0 2871 cx->filter_arg = arg;
michael@0 2872 cx->filter_only = only;
michael@0 2873 }
michael@0 2874
michael@0 2875
michael@0 2876 void
michael@0 2877 SEC_ASN1DecoderClearFilterProc (SEC_ASN1DecoderContext *cx)
michael@0 2878 {
michael@0 2879 /* check that we are "between" fields here */
michael@0 2880 PORT_Assert (cx->during_notify);
michael@0 2881
michael@0 2882 cx->filter_proc = NULL;
michael@0 2883 cx->filter_arg = NULL;
michael@0 2884 cx->filter_only = PR_FALSE;
michael@0 2885 }
michael@0 2886
michael@0 2887
michael@0 2888 void
michael@0 2889 SEC_ASN1DecoderSetNotifyProc (SEC_ASN1DecoderContext *cx,
michael@0 2890 SEC_ASN1NotifyProc fn, void *arg)
michael@0 2891 {
michael@0 2892 cx->notify_proc = fn;
michael@0 2893 cx->notify_arg = arg;
michael@0 2894 }
michael@0 2895
michael@0 2896
michael@0 2897 void
michael@0 2898 SEC_ASN1DecoderClearNotifyProc (SEC_ASN1DecoderContext *cx)
michael@0 2899 {
michael@0 2900 cx->notify_proc = NULL;
michael@0 2901 cx->notify_arg = NULL; /* not necessary; just being clean */
michael@0 2902 }
michael@0 2903
michael@0 2904 void
michael@0 2905 SEC_ASN1DecoderAbort(SEC_ASN1DecoderContext *cx, int error)
michael@0 2906 {
michael@0 2907 PORT_Assert(cx);
michael@0 2908 PORT_SetError(error);
michael@0 2909 cx->status = decodeError;
michael@0 2910 }
michael@0 2911
michael@0 2912
michael@0 2913 SECStatus
michael@0 2914 SEC_ASN1Decode (PLArenaPool *poolp, void *dest,
michael@0 2915 const SEC_ASN1Template *theTemplate,
michael@0 2916 const char *buf, long len)
michael@0 2917 {
michael@0 2918 SEC_ASN1DecoderContext *dcx;
michael@0 2919 SECStatus urv, frv;
michael@0 2920
michael@0 2921 dcx = SEC_ASN1DecoderStart (poolp, dest, theTemplate);
michael@0 2922 if (dcx == NULL)
michael@0 2923 return SECFailure;
michael@0 2924
michael@0 2925 urv = SEC_ASN1DecoderUpdate (dcx, buf, len);
michael@0 2926 frv = SEC_ASN1DecoderFinish (dcx);
michael@0 2927
michael@0 2928 if (urv != SECSuccess)
michael@0 2929 return urv;
michael@0 2930
michael@0 2931 return frv;
michael@0 2932 }
michael@0 2933
michael@0 2934
michael@0 2935 SECStatus
michael@0 2936 SEC_ASN1DecodeItem (PLArenaPool *poolp, void *dest,
michael@0 2937 const SEC_ASN1Template *theTemplate,
michael@0 2938 const SECItem *src)
michael@0 2939 {
michael@0 2940 return SEC_ASN1Decode (poolp, dest, theTemplate,
michael@0 2941 (const char *)src->data, src->len);
michael@0 2942 }
michael@0 2943
michael@0 2944 #ifdef DEBUG_ASN1D_STATES
michael@0 2945 void sec_asn1d_Assert(const char *s, const char *file, PRIntn ln)
michael@0 2946 {
michael@0 2947 printf("Assertion failed, \"%s\", file %s, line %d\n", s, file, ln);
michael@0 2948 fflush(stdout);
michael@0 2949 }
michael@0 2950 #endif
michael@0 2951
michael@0 2952 /*
michael@0 2953 * Generic templates for individual/simple items and pointers to
michael@0 2954 * and sets of same.
michael@0 2955 *
michael@0 2956 * If you need to add a new one, please note the following:
michael@0 2957 * - For each new basic type you should add *four* templates:
michael@0 2958 * one plain, one PointerTo, one SequenceOf and one SetOf.
michael@0 2959 * - If the new type can be constructed (meaning, it is a
michael@0 2960 * *string* type according to BER/DER rules), then you should
michael@0 2961 * or-in SEC_ASN1_MAY_STREAM to the type in the basic template.
michael@0 2962 * See the definition of the OctetString template for an example.
michael@0 2963 * - It may not be obvious, but these are in *alphabetical*
michael@0 2964 * order based on the SEC_ASN1_XXX name; so put new ones in
michael@0 2965 * the appropriate place.
michael@0 2966 */
michael@0 2967
michael@0 2968 const SEC_ASN1Template SEC_SequenceOfAnyTemplate[] = {
michael@0 2969 { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
michael@0 2970 };
michael@0 2971
michael@0 2972 #if 0
michael@0 2973
michael@0 2974 const SEC_ASN1Template SEC_PointerToBitStringTemplate[] = {
michael@0 2975 { SEC_ASN1_POINTER, 0, SEC_BitStringTemplate }
michael@0 2976 };
michael@0 2977
michael@0 2978 const SEC_ASN1Template SEC_SequenceOfBitStringTemplate[] = {
michael@0 2979 { SEC_ASN1_SEQUENCE_OF, 0, SEC_BitStringTemplate }
michael@0 2980 };
michael@0 2981
michael@0 2982 const SEC_ASN1Template SEC_SetOfBitStringTemplate[] = {
michael@0 2983 { SEC_ASN1_SET_OF, 0, SEC_BitStringTemplate }
michael@0 2984 };
michael@0 2985
michael@0 2986 const SEC_ASN1Template SEC_PointerToBMPStringTemplate[] = {
michael@0 2987 { SEC_ASN1_POINTER, 0, SEC_BMPStringTemplate }
michael@0 2988 };
michael@0 2989
michael@0 2990 const SEC_ASN1Template SEC_SequenceOfBMPStringTemplate[] = {
michael@0 2991 { SEC_ASN1_SEQUENCE_OF, 0, SEC_BMPStringTemplate }
michael@0 2992 };
michael@0 2993
michael@0 2994 const SEC_ASN1Template SEC_SetOfBMPStringTemplate[] = {
michael@0 2995 { SEC_ASN1_SET_OF, 0, SEC_BMPStringTemplate }
michael@0 2996 };
michael@0 2997
michael@0 2998 const SEC_ASN1Template SEC_PointerToBooleanTemplate[] = {
michael@0 2999 { SEC_ASN1_POINTER, 0, SEC_BooleanTemplate }
michael@0 3000 };
michael@0 3001
michael@0 3002 const SEC_ASN1Template SEC_SequenceOfBooleanTemplate[] = {
michael@0 3003 { SEC_ASN1_SEQUENCE_OF, 0, SEC_BooleanTemplate }
michael@0 3004 };
michael@0 3005
michael@0 3006 const SEC_ASN1Template SEC_SetOfBooleanTemplate[] = {
michael@0 3007 { SEC_ASN1_SET_OF, 0, SEC_BooleanTemplate }
michael@0 3008 };
michael@0 3009
michael@0 3010 #endif
michael@0 3011
michael@0 3012 const SEC_ASN1Template SEC_EnumeratedTemplate[] = {
michael@0 3013 { SEC_ASN1_ENUMERATED, 0, NULL, sizeof(SECItem) }
michael@0 3014 };
michael@0 3015
michael@0 3016 const SEC_ASN1Template SEC_PointerToEnumeratedTemplate[] = {
michael@0 3017 { SEC_ASN1_POINTER, 0, SEC_EnumeratedTemplate }
michael@0 3018 };
michael@0 3019
michael@0 3020 #if 0
michael@0 3021
michael@0 3022 const SEC_ASN1Template SEC_SequenceOfEnumeratedTemplate[] = {
michael@0 3023 { SEC_ASN1_SEQUENCE_OF, 0, SEC_EnumeratedTemplate }
michael@0 3024 };
michael@0 3025
michael@0 3026 #endif
michael@0 3027
michael@0 3028 const SEC_ASN1Template SEC_SetOfEnumeratedTemplate[] = {
michael@0 3029 { SEC_ASN1_SET_OF, 0, SEC_EnumeratedTemplate }
michael@0 3030 };
michael@0 3031
michael@0 3032 const SEC_ASN1Template SEC_PointerToGeneralizedTimeTemplate[] = {
michael@0 3033 { SEC_ASN1_POINTER, 0, SEC_GeneralizedTimeTemplate }
michael@0 3034 };
michael@0 3035
michael@0 3036 #if 0
michael@0 3037
michael@0 3038 const SEC_ASN1Template SEC_SequenceOfGeneralizedTimeTemplate[] = {
michael@0 3039 { SEC_ASN1_SEQUENCE_OF, 0, SEC_GeneralizedTimeTemplate }
michael@0 3040 };
michael@0 3041
michael@0 3042 const SEC_ASN1Template SEC_SetOfGeneralizedTimeTemplate[] = {
michael@0 3043 { SEC_ASN1_SET_OF, 0, SEC_GeneralizedTimeTemplate }
michael@0 3044 };
michael@0 3045
michael@0 3046 const SEC_ASN1Template SEC_PointerToIA5StringTemplate[] = {
michael@0 3047 { SEC_ASN1_POINTER, 0, SEC_IA5StringTemplate }
michael@0 3048 };
michael@0 3049
michael@0 3050 const SEC_ASN1Template SEC_SequenceOfIA5StringTemplate[] = {
michael@0 3051 { SEC_ASN1_SEQUENCE_OF, 0, SEC_IA5StringTemplate }
michael@0 3052 };
michael@0 3053
michael@0 3054 const SEC_ASN1Template SEC_SetOfIA5StringTemplate[] = {
michael@0 3055 { SEC_ASN1_SET_OF, 0, SEC_IA5StringTemplate }
michael@0 3056 };
michael@0 3057
michael@0 3058 const SEC_ASN1Template SEC_PointerToIntegerTemplate[] = {
michael@0 3059 { SEC_ASN1_POINTER, 0, SEC_IntegerTemplate }
michael@0 3060 };
michael@0 3061
michael@0 3062 const SEC_ASN1Template SEC_SequenceOfIntegerTemplate[] = {
michael@0 3063 { SEC_ASN1_SEQUENCE_OF, 0, SEC_IntegerTemplate }
michael@0 3064 };
michael@0 3065
michael@0 3066 const SEC_ASN1Template SEC_SetOfIntegerTemplate[] = {
michael@0 3067 { SEC_ASN1_SET_OF, 0, SEC_IntegerTemplate }
michael@0 3068 };
michael@0 3069
michael@0 3070 const SEC_ASN1Template SEC_PointerToNullTemplate[] = {
michael@0 3071 { SEC_ASN1_POINTER, 0, SEC_NullTemplate }
michael@0 3072 };
michael@0 3073
michael@0 3074 const SEC_ASN1Template SEC_SequenceOfNullTemplate[] = {
michael@0 3075 { SEC_ASN1_SEQUENCE_OF, 0, SEC_NullTemplate }
michael@0 3076 };
michael@0 3077
michael@0 3078 const SEC_ASN1Template SEC_SetOfNullTemplate[] = {
michael@0 3079 { SEC_ASN1_SET_OF, 0, SEC_NullTemplate }
michael@0 3080 };
michael@0 3081
michael@0 3082 const SEC_ASN1Template SEC_PointerToObjectIDTemplate[] = {
michael@0 3083 { SEC_ASN1_POINTER, 0, SEC_ObjectIDTemplate }
michael@0 3084 };
michael@0 3085
michael@0 3086 #endif
michael@0 3087
michael@0 3088 const SEC_ASN1Template SEC_SequenceOfObjectIDTemplate[] = {
michael@0 3089 { SEC_ASN1_SEQUENCE_OF, 0, SEC_ObjectIDTemplate }
michael@0 3090 };
michael@0 3091
michael@0 3092 #if 0
michael@0 3093
michael@0 3094 const SEC_ASN1Template SEC_SetOfObjectIDTemplate[] = {
michael@0 3095 { SEC_ASN1_SET_OF, 0, SEC_ObjectIDTemplate }
michael@0 3096 };
michael@0 3097
michael@0 3098 const SEC_ASN1Template SEC_SequenceOfOctetStringTemplate[] = {
michael@0 3099 { SEC_ASN1_SEQUENCE_OF, 0, SEC_OctetStringTemplate }
michael@0 3100 };
michael@0 3101
michael@0 3102 const SEC_ASN1Template SEC_SetOfOctetStringTemplate[] = {
michael@0 3103 { SEC_ASN1_SET_OF, 0, SEC_OctetStringTemplate }
michael@0 3104 };
michael@0 3105
michael@0 3106 #endif
michael@0 3107
michael@0 3108 const SEC_ASN1Template SEC_PrintableStringTemplate[] = {
michael@0 3109 { SEC_ASN1_PRINTABLE_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
michael@0 3110 };
michael@0 3111
michael@0 3112 #if 0
michael@0 3113
michael@0 3114 const SEC_ASN1Template SEC_PointerToPrintableStringTemplate[] = {
michael@0 3115 { SEC_ASN1_POINTER, 0, SEC_PrintableStringTemplate }
michael@0 3116 };
michael@0 3117
michael@0 3118 const SEC_ASN1Template SEC_SequenceOfPrintableStringTemplate[] = {
michael@0 3119 { SEC_ASN1_SEQUENCE_OF, 0, SEC_PrintableStringTemplate }
michael@0 3120 };
michael@0 3121
michael@0 3122 const SEC_ASN1Template SEC_SetOfPrintableStringTemplate[] = {
michael@0 3123 { SEC_ASN1_SET_OF, 0, SEC_PrintableStringTemplate }
michael@0 3124 };
michael@0 3125
michael@0 3126 #endif
michael@0 3127
michael@0 3128 const SEC_ASN1Template SEC_T61StringTemplate[] = {
michael@0 3129 { SEC_ASN1_T61_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
michael@0 3130 };
michael@0 3131
michael@0 3132 #if 0
michael@0 3133
michael@0 3134 const SEC_ASN1Template SEC_PointerToT61StringTemplate[] = {
michael@0 3135 { SEC_ASN1_POINTER, 0, SEC_T61StringTemplate }
michael@0 3136 };
michael@0 3137
michael@0 3138 const SEC_ASN1Template SEC_SequenceOfT61StringTemplate[] = {
michael@0 3139 { SEC_ASN1_SEQUENCE_OF, 0, SEC_T61StringTemplate }
michael@0 3140 };
michael@0 3141
michael@0 3142 const SEC_ASN1Template SEC_SetOfT61StringTemplate[] = {
michael@0 3143 { SEC_ASN1_SET_OF, 0, SEC_T61StringTemplate }
michael@0 3144 };
michael@0 3145
michael@0 3146 #endif
michael@0 3147
michael@0 3148 const SEC_ASN1Template SEC_UniversalStringTemplate[] = {
michael@0 3149 { SEC_ASN1_UNIVERSAL_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
michael@0 3150 };
michael@0 3151
michael@0 3152 #if 0
michael@0 3153
michael@0 3154 const SEC_ASN1Template SEC_PointerToUniversalStringTemplate[] = {
michael@0 3155 { SEC_ASN1_POINTER, 0, SEC_UniversalStringTemplate }
michael@0 3156 };
michael@0 3157
michael@0 3158 const SEC_ASN1Template SEC_SequenceOfUniversalStringTemplate[] = {
michael@0 3159 { SEC_ASN1_SEQUENCE_OF, 0, SEC_UniversalStringTemplate }
michael@0 3160 };
michael@0 3161
michael@0 3162 const SEC_ASN1Template SEC_SetOfUniversalStringTemplate[] = {
michael@0 3163 { SEC_ASN1_SET_OF, 0, SEC_UniversalStringTemplate }
michael@0 3164 };
michael@0 3165
michael@0 3166 const SEC_ASN1Template SEC_PointerToUTCTimeTemplate[] = {
michael@0 3167 { SEC_ASN1_POINTER, 0, SEC_UTCTimeTemplate }
michael@0 3168 };
michael@0 3169
michael@0 3170 const SEC_ASN1Template SEC_SequenceOfUTCTimeTemplate[] = {
michael@0 3171 { SEC_ASN1_SEQUENCE_OF, 0, SEC_UTCTimeTemplate }
michael@0 3172 };
michael@0 3173
michael@0 3174 const SEC_ASN1Template SEC_SetOfUTCTimeTemplate[] = {
michael@0 3175 { SEC_ASN1_SET_OF, 0, SEC_UTCTimeTemplate }
michael@0 3176 };
michael@0 3177
michael@0 3178 const SEC_ASN1Template SEC_PointerToUTF8StringTemplate[] = {
michael@0 3179 { SEC_ASN1_POINTER, 0, SEC_UTF8StringTemplate }
michael@0 3180 };
michael@0 3181
michael@0 3182 const SEC_ASN1Template SEC_SequenceOfUTF8StringTemplate[] = {
michael@0 3183 { SEC_ASN1_SEQUENCE_OF, 0, SEC_UTF8StringTemplate }
michael@0 3184 };
michael@0 3185
michael@0 3186 const SEC_ASN1Template SEC_SetOfUTF8StringTemplate[] = {
michael@0 3187 { SEC_ASN1_SET_OF, 0, SEC_UTF8StringTemplate }
michael@0 3188 };
michael@0 3189
michael@0 3190 #endif
michael@0 3191
michael@0 3192 const SEC_ASN1Template SEC_VisibleStringTemplate[] = {
michael@0 3193 { SEC_ASN1_VISIBLE_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
michael@0 3194 };
michael@0 3195
michael@0 3196 #if 0
michael@0 3197
michael@0 3198 const SEC_ASN1Template SEC_PointerToVisibleStringTemplate[] = {
michael@0 3199 { SEC_ASN1_POINTER, 0, SEC_VisibleStringTemplate }
michael@0 3200 };
michael@0 3201
michael@0 3202 const SEC_ASN1Template SEC_SequenceOfVisibleStringTemplate[] = {
michael@0 3203 { SEC_ASN1_SEQUENCE_OF, 0, SEC_VisibleStringTemplate }
michael@0 3204 };
michael@0 3205
michael@0 3206 const SEC_ASN1Template SEC_SetOfVisibleStringTemplate[] = {
michael@0 3207 { SEC_ASN1_SET_OF, 0, SEC_VisibleStringTemplate }
michael@0 3208 };
michael@0 3209
michael@0 3210 #endif
michael@0 3211
michael@0 3212 /*
michael@0 3213 * Template for skipping a subitem.
michael@0 3214 *
michael@0 3215 * Note that it only makes sense to use this for decoding (when you want
michael@0 3216 * to decode something where you are only interested in one or two of
michael@0 3217 * the fields); you cannot encode a SKIP!
michael@0 3218 */
michael@0 3219 const SEC_ASN1Template SEC_SkipTemplate[] = {
michael@0 3220 { SEC_ASN1_SKIP }
michael@0 3221 };
michael@0 3222
michael@0 3223
michael@0 3224 /* These functions simply return the address of the above-declared templates.
michael@0 3225 ** This is necessary for Windows DLLs. Sigh.
michael@0 3226 */
michael@0 3227 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_EnumeratedTemplate)
michael@0 3228 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToEnumeratedTemplate)
michael@0 3229 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SequenceOfAnyTemplate)
michael@0 3230 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SequenceOfObjectIDTemplate)
michael@0 3231 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SkipTemplate)
michael@0 3232 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_UniversalStringTemplate)
michael@0 3233 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PrintableStringTemplate)
michael@0 3234 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_T61StringTemplate)
michael@0 3235 SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToGeneralizedTimeTemplate)
michael@0 3236

mercurial