secasn1e.c (51533B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /* 6 * Support for ENcoding ASN.1 data based on BER/DER (Basic/Distinguished 7 * Encoding Rules). 8 */ 9 10 #include "secasn1.h" 11 12 typedef enum { 13 beforeHeader, 14 duringContents, 15 duringGroup, 16 duringSequence, 17 afterContents, 18 afterImplicit, 19 afterInline, 20 afterPointer, 21 afterChoice, 22 notInUse 23 } sec_asn1e_parse_place; 24 25 typedef enum { 26 allDone, 27 encodeError, 28 keepGoing, 29 needBytes 30 } sec_asn1e_parse_status; 31 32 typedef enum { 33 hdr_normal = 0, /* encode header normally */ 34 hdr_any = 1, /* header already encoded in content */ 35 hdr_decoder = 2, /* template only used by decoder. skip it. */ 36 hdr_optional = 3, /* optional component, to be omitted */ 37 hdr_placeholder = 4 /* place holder for from_buf content */ 38 } sec_asn1e_hdr_encoding; 39 40 typedef struct sec_asn1e_state_struct { 41 SEC_ASN1EncoderContext *top; 42 const SEC_ASN1Template *theTemplate; 43 void *src; 44 45 struct sec_asn1e_state_struct *parent; /* aka prev */ 46 struct sec_asn1e_state_struct *child; /* aka next */ 47 48 sec_asn1e_parse_place place; /* where we are in encoding process */ 49 50 /* 51 * XXX explain the next fields as clearly as possible... 52 */ 53 unsigned char tag_modifiers; 54 unsigned char tag_number; 55 unsigned long underlying_kind; 56 57 int depth; 58 59 PRBool isExplicit, /* we are handling an isExplicit header */ 60 indefinite, /* need end-of-contents */ 61 is_string, /* encoding a simple string or an ANY */ 62 may_stream, /* when streaming, do indefinite encoding */ 63 optional, /* omit field if it has no contents */ 64 disallowStreaming; /* disallow streaming in all sub-templates */ 65 } sec_asn1e_state; 66 67 /* 68 * An "outsider" will have an opaque pointer to this, created by calling 69 * SEC_ASN1EncoderStart(). It will be passed back in to all subsequent 70 * calls to SEC_ASN1EncoderUpdate() and related routines, and when done 71 * it is passed to SEC_ASN1EncoderFinish(). 72 */ 73 struct sec_EncoderContext_struct { 74 PLArenaPool *our_pool; /* for our internal allocs */ 75 76 sec_asn1e_state *current; 77 sec_asn1e_parse_status status; 78 79 PRBool streaming; 80 PRBool from_buf; 81 82 SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */ 83 void *notify_arg; /* argument to notify_proc */ 84 PRBool during_notify; /* true during call to notify_proc */ 85 86 SEC_ASN1WriteProc output_proc; /* pass encoded bytes to this */ 87 void *output_arg; /* argument to that function */ 88 }; 89 90 static sec_asn1e_state * 91 sec_asn1e_push_state(SEC_ASN1EncoderContext *cx, 92 const SEC_ASN1Template *theTemplate, 93 const void *src, PRBool new_depth) 94 { 95 sec_asn1e_state *state, *new_state; 96 97 if (theTemplate == NULL) { 98 cx->status = encodeError; 99 return NULL; 100 } 101 102 state = cx->current; 103 new_state = (sec_asn1e_state *)PORT_ArenaZAlloc(cx->our_pool, 104 sizeof(*new_state)); 105 if (new_state == NULL) { 106 cx->status = encodeError; 107 return NULL; 108 } 109 110 new_state->top = cx; 111 new_state->parent = state; 112 new_state->theTemplate = theTemplate; 113 new_state->place = notInUse; 114 if (src != NULL) 115 new_state->src = (char *)src + theTemplate->offset; 116 117 if (state != NULL) { 118 new_state->depth = state->depth; 119 if (new_depth) 120 new_state->depth++; 121 state->child = new_state; 122 } 123 124 cx->current = new_state; 125 return new_state; 126 } 127 128 static void 129 sec_asn1e_scrub_state(sec_asn1e_state *state) 130 { 131 /* 132 * Some default "scrubbing". 133 * XXX right set of initializations? 134 */ 135 state->place = beforeHeader; 136 state->indefinite = PR_FALSE; 137 } 138 139 static void 140 sec_asn1e_notify_before(SEC_ASN1EncoderContext *cx, void *src, int depth) 141 { 142 if (cx->notify_proc == NULL) 143 return; 144 145 cx->during_notify = PR_TRUE; 146 (*cx->notify_proc)(cx->notify_arg, PR_TRUE, src, depth); 147 cx->during_notify = PR_FALSE; 148 } 149 150 static void 151 sec_asn1e_notify_after(SEC_ASN1EncoderContext *cx, void *src, int depth) 152 { 153 if (cx->notify_proc == NULL) 154 return; 155 156 cx->during_notify = PR_TRUE; 157 (*cx->notify_proc)(cx->notify_arg, PR_FALSE, src, depth); 158 cx->during_notify = PR_FALSE; 159 } 160 161 static sec_asn1e_state * 162 sec_asn1e_init_state_based_on_template(sec_asn1e_state *state) 163 { 164 PRBool isExplicit, is_string, may_stream, optional, universal; 165 PRBool disallowStreaming; 166 unsigned char tag_modifiers; 167 unsigned long encode_kind, under_kind; 168 unsigned long tag_number; 169 PRBool isInline = PR_FALSE; 170 171 encode_kind = state->theTemplate->kind; 172 173 universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL) 174 ? PR_TRUE 175 : PR_FALSE; 176 177 isExplicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE; 178 encode_kind &= ~SEC_ASN1_EXPLICIT; 179 180 optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE; 181 encode_kind &= ~SEC_ASN1_OPTIONAL; 182 183 PORT_Assert(!(isExplicit && universal)); /* bad templates */ 184 185 may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE; 186 encode_kind &= ~SEC_ASN1_MAY_STREAM; 187 188 disallowStreaming = (encode_kind & SEC_ASN1_NO_STREAM) ? PR_TRUE : PR_FALSE; 189 encode_kind &= ~SEC_ASN1_NO_STREAM; 190 191 /* Just clear this to get it out of the way; we do not need it here */ 192 encode_kind &= ~SEC_ASN1_DYNAMIC; 193 194 if (encode_kind & SEC_ASN1_CHOICE) { 195 under_kind = SEC_ASN1_CHOICE; 196 } else if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || 197 (!universal && !isExplicit)) { 198 const SEC_ASN1Template *subt; 199 void *src = NULL; 200 201 PORT_Assert((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0); 202 203 sec_asn1e_scrub_state(state); 204 205 if (encode_kind & SEC_ASN1_POINTER) { 206 src = *(void **)state->src; 207 state->place = afterPointer; 208 209 if (src == NULL) { 210 /* 211 * If this is optional, but NULL, then the field does 212 * not need to be encoded. In this case we are done; 213 * we do not want to push a subtemplate. 214 */ 215 if (optional) 216 return state; 217 218 /* 219 * XXX this is an error; need to figure out 220 * how to handle this 221 */ 222 } 223 } else { 224 src = state->src; 225 if (encode_kind & SEC_ASN1_INLINE) { 226 /* check that there are no extraneous bits */ 227 /* PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional); */ 228 state->place = afterInline; 229 isInline = PR_TRUE; 230 } else { 231 /* 232 * Save the tag modifiers and tag number here before moving 233 * on to the next state in case this is a member of a 234 * SEQUENCE OF 235 */ 236 state->tag_modifiers = (unsigned char)(encode_kind & (SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK)); 237 state->tag_number = (unsigned char)(encode_kind & SEC_ASN1_TAGNUM_MASK); 238 239 state->place = afterImplicit; 240 state->optional = optional; 241 } 242 } 243 244 subt = SEC_ASN1GetSubtemplate(state->theTemplate, state->src, PR_TRUE); 245 if (isInline && optional) { 246 /* we only handle a very limited set of optional inline cases at 247 this time */ 248 if (PR_FALSE != SEC_ASN1IsTemplateSimple(subt)) { 249 /* we now know that the target is a SECItem*, so we can check 250 if the source contains one */ 251 SECItem *target = (SECItem *)state->src; 252 if (!target || !target->data || !target->len) { 253 /* no valid data to encode subtemplate */ 254 return state; 255 } 256 } else { 257 PORT_Assert(0); /* complex templates are not handled as 258 inline optional */ 259 } 260 } 261 state = sec_asn1e_push_state(state->top, subt, src, PR_FALSE); 262 if (state == NULL) 263 return state; 264 265 if (universal) { 266 /* 267 * This is a POINTER or INLINE; just init based on that 268 * and we are done. 269 */ 270 return sec_asn1e_init_state_based_on_template(state); 271 } 272 273 /* 274 * This is an implicit, non-universal (meaning, application-private 275 * or context-specific) field. This results in a "magic" tag but 276 * encoding based on the underlying type. We pushed a new state 277 * that is based on the subtemplate (the underlying type), but 278 * now we will sort of alias it to give it some of our properties 279 * (tag, optional status, etc.). 280 * 281 * NB: ALL the following flags in the subtemplate are disallowed 282 * and/or ignored: EXPLICIT, OPTIONAL, INNER, INLINE, POINTER. 283 */ 284 285 under_kind = state->theTemplate->kind; 286 if ((under_kind & SEC_ASN1_MAY_STREAM) && !disallowStreaming) { 287 may_stream = PR_TRUE; 288 } 289 under_kind &= ~(SEC_ASN1_MAY_STREAM | SEC_ASN1_DYNAMIC); 290 } else { 291 under_kind = encode_kind; 292 } 293 294 /* 295 * Sanity check that there are no unwanted bits marked in under_kind. 296 * These bits were either removed above (after we recorded them) or 297 * they simply should not be found (signalling a bad/broken template). 298 * XXX is this the right set of bits to test here? (i.e. need to add 299 * or remove any?) 300 */ 301 #define UNEXPECTED_FLAGS \ 302 (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_SKIP | SEC_ASN1_INNER | \ 303 SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_INLINE | SEC_ASN1_POINTER) 304 305 PORT_Assert((under_kind & UNEXPECTED_FLAGS) == 0); 306 under_kind &= ~UNEXPECTED_FLAGS; 307 #undef UNEXPECTED_FLAGS 308 309 if (encode_kind & SEC_ASN1_ANY) { 310 PORT_Assert(encode_kind == under_kind); 311 tag_modifiers = 0; 312 tag_number = 0; 313 is_string = PR_TRUE; 314 } else { 315 tag_modifiers = (unsigned char)(encode_kind & (SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK)); 316 /* 317 * XXX This assumes only single-octet identifiers. To handle 318 * the HIGH TAG form we would need to do some more work, especially 319 * in how to specify them in the template, because right now we 320 * do not provide a way to specify more *tag* bits in encode_kind. 321 */ 322 tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK; 323 324 is_string = PR_FALSE; 325 switch (under_kind & SEC_ASN1_TAGNUM_MASK) { 326 case SEC_ASN1_SET: 327 /* 328 * XXX A plain old SET (as opposed to a SET OF) is not implemented. 329 * If it ever is, remove this assert... 330 */ 331 PORT_Assert((under_kind & SEC_ASN1_GROUP) != 0); 332 /* fallthru */ 333 case SEC_ASN1_SEQUENCE: 334 tag_modifiers |= SEC_ASN1_CONSTRUCTED; 335 break; 336 case SEC_ASN1_BIT_STRING: 337 case SEC_ASN1_BMP_STRING: 338 case SEC_ASN1_GENERALIZED_TIME: 339 case SEC_ASN1_IA5_STRING: 340 case SEC_ASN1_OCTET_STRING: 341 case SEC_ASN1_PRINTABLE_STRING: 342 case SEC_ASN1_T61_STRING: 343 case SEC_ASN1_UNIVERSAL_STRING: 344 case SEC_ASN1_UTC_TIME: 345 case SEC_ASN1_UTF8_STRING: 346 case SEC_ASN1_VISIBLE_STRING: 347 /* 348 * We do not yet know if we will be constructing the string, 349 * so we have to wait to do this final tag modification. 350 */ 351 is_string = PR_TRUE; 352 break; 353 } 354 } 355 356 state->tag_modifiers = tag_modifiers; 357 state->tag_number = (unsigned char)tag_number; 358 state->underlying_kind = under_kind; 359 state->isExplicit = isExplicit; 360 state->may_stream = may_stream; 361 state->is_string = is_string; 362 state->optional = optional; 363 state->disallowStreaming = disallowStreaming; 364 365 sec_asn1e_scrub_state(state); 366 367 return state; 368 } 369 370 static void 371 sec_asn1e_write_part(sec_asn1e_state *state, 372 const char *buf, unsigned long len, 373 SEC_ASN1EncodingPart part) 374 { 375 SEC_ASN1EncoderContext *cx; 376 377 cx = state->top; 378 (*cx->output_proc)(cx->output_arg, buf, len, state->depth, part); 379 } 380 381 /* 382 * XXX This assumes only single-octet identifiers. To handle 383 * the HIGH TAG form we would need to modify this interface and 384 * teach it to properly encode the special form. 385 */ 386 static void 387 sec_asn1e_write_identifier_bytes(sec_asn1e_state *state, unsigned char value) 388 { 389 char byte; 390 391 byte = (char)value; 392 sec_asn1e_write_part(state, &byte, 1, SEC_ASN1_Identifier); 393 } 394 395 int 396 SEC_ASN1EncodeLength(unsigned char *buf, int value) 397 { 398 int lenlen; 399 400 lenlen = SEC_ASN1LengthLength(value); 401 if (lenlen == 1) { 402 buf[0] = value; 403 } else { 404 int i; 405 406 i = lenlen - 1; 407 buf[0] = 0x80 | i; 408 while (i) { 409 buf[i--] = value; 410 value >>= 8; 411 } 412 PORT_Assert(value == 0); 413 } 414 return lenlen; 415 } 416 417 static void 418 sec_asn1e_write_length_bytes(sec_asn1e_state *state, unsigned long value, 419 PRBool indefinite) 420 { 421 int lenlen; 422 unsigned char buf[sizeof(unsigned long) + 1]; 423 424 if (indefinite) { 425 PORT_Assert(value == 0); 426 buf[0] = 0x80; 427 lenlen = 1; 428 } else { 429 lenlen = SEC_ASN1EncodeLength(buf, value); 430 } 431 432 sec_asn1e_write_part(state, (char *)buf, lenlen, SEC_ASN1_Length); 433 } 434 435 static void 436 sec_asn1e_write_contents_bytes(sec_asn1e_state *state, 437 const char *buf, unsigned long len) 438 { 439 sec_asn1e_write_part(state, buf, len, SEC_ASN1_Contents); 440 } 441 442 static void 443 sec_asn1e_write_end_of_contents_bytes(sec_asn1e_state *state) 444 { 445 const char eoc[2] = { 0, 0 }; 446 447 sec_asn1e_write_part(state, eoc, 2, SEC_ASN1_EndOfContents); 448 } 449 450 static int 451 sec_asn1e_which_choice( 452 void *src, 453 const SEC_ASN1Template *theTemplate) 454 { 455 int rv; 456 unsigned int which = *(unsigned int *)src; 457 458 for (rv = 1, theTemplate++; theTemplate->kind != 0; rv++, theTemplate++) { 459 if (which == theTemplate->size) { 460 return rv; 461 } 462 } 463 464 return 0; 465 } 466 467 static unsigned long 468 sec_asn1e_contents_length(const SEC_ASN1Template *theTemplate, void *src, 469 PRBool disallowStreaming, PRBool insideIndefinite, 470 sec_asn1e_hdr_encoding *pHdrException) 471 { 472 unsigned long encode_kind, underlying_kind; 473 PRBool isExplicit, optional, universal, may_stream; 474 unsigned long len; 475 476 /* 477 * This function currently calculates the length in all cases 478 * except the following: when writing out the contents of a 479 * template that belongs to a state where it was a sub-template 480 * with the SEC_ASN1_MAY_STREAM bit set and it's parent had the 481 * optional bit set. The information that the parent is optional 482 * and that we should return the length of 0 when that length is 483 * present since that means the optional field is no longer present. 484 * So we add the disallowStreaming flag which is passed in when 485 * writing the contents, but for all recursive calls to 486 * sec_asn1e_contents_length, we pass PR_FALSE, because this 487 * function correctly calculates the length for children templates 488 * from that point on. Confused yet? At least you didn't have 489 * to figure it out. ;) -javi 490 */ 491 encode_kind = theTemplate->kind; 492 493 universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL) 494 ? PR_TRUE 495 : PR_FALSE; 496 497 isExplicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE; 498 encode_kind &= ~SEC_ASN1_EXPLICIT; 499 500 optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE; 501 encode_kind &= ~SEC_ASN1_OPTIONAL; 502 503 PORT_Assert(!(isExplicit && universal)); /* bad templates */ 504 505 may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE; 506 encode_kind &= ~SEC_ASN1_MAY_STREAM; 507 508 /* Just clear this to get it out of the way; we do not need it here */ 509 encode_kind &= ~SEC_ASN1_DYNAMIC; 510 511 if (encode_kind & SEC_ASN1_NO_STREAM) { 512 disallowStreaming = PR_TRUE; 513 } 514 encode_kind &= ~SEC_ASN1_NO_STREAM; 515 516 if (encode_kind & SEC_ASN1_CHOICE) { 517 void *src2; 518 int indx = sec_asn1e_which_choice(src, theTemplate); 519 if (0 == indx) { 520 /* XXX set an error? "choice not found" */ 521 /* state->top->status = encodeError; */ 522 return 0; 523 } 524 525 src2 = (void *)((char *)src - theTemplate->offset + theTemplate[indx].offset); 526 527 return sec_asn1e_contents_length(&theTemplate[indx], src2, 528 disallowStreaming, insideIndefinite, 529 pHdrException); 530 } 531 532 if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || !universal) { 533 /* XXX any bits we want to disallow (PORT_Assert against) here? */ 534 theTemplate = SEC_ASN1GetSubtemplate(theTemplate, src, PR_TRUE); 535 if (encode_kind & SEC_ASN1_POINTER) { 536 src = *(void **)src; 537 if (src == NULL) { 538 *pHdrException = optional ? hdr_optional : hdr_normal; 539 return 0; 540 } 541 } else if (encode_kind & SEC_ASN1_INLINE) { 542 /* check that there are no extraneous bits */ 543 if (optional) { 544 if (PR_FALSE != SEC_ASN1IsTemplateSimple(theTemplate)) { 545 /* we now know that the target is a SECItem*, so we can check 546 if the source contains one */ 547 SECItem *target = (SECItem *)src; 548 if (!target || !target->data || !target->len) { 549 /* no valid data to encode subtemplate */ 550 *pHdrException = hdr_optional; 551 return 0; 552 } 553 } else { 554 PORT_Assert(0); /* complex templates not handled as inline 555 optional */ 556 } 557 } 558 } 559 560 src = (char *)src + theTemplate->offset; 561 562 /* recurse to find the length of the subtemplate */ 563 len = sec_asn1e_contents_length(theTemplate, src, disallowStreaming, 564 insideIndefinite, pHdrException); 565 if (len == 0 && optional) { 566 *pHdrException = hdr_optional; 567 } else if (isExplicit) { 568 if (*pHdrException == hdr_any) { 569 /* *we* do not want to add in a header, 570 ** but our caller still does. 571 */ 572 *pHdrException = hdr_normal; 573 } else if (*pHdrException == hdr_normal) { 574 /* if the inner content exists, our length is 575 * len(identifier) + len(length) + len(innercontent) 576 * XXX we currently assume len(identifier) == 1; 577 * to support a high-tag-number this would need to be smarter. 578 */ 579 len += 1 + SEC_ASN1LengthLength(len); 580 } 581 } 582 return len; 583 } 584 underlying_kind = encode_kind; 585 586 /* This is only used in decoding; it plays no part in encoding. */ 587 if (underlying_kind & SEC_ASN1_SAVE) { 588 /* check that there are no extraneous bits */ 589 PORT_Assert(underlying_kind == SEC_ASN1_SAVE); 590 *pHdrException = hdr_decoder; 591 return 0; 592 } 593 594 #define UNEXPECTED_FLAGS \ 595 (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_INLINE | SEC_ASN1_POINTER | \ 596 SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_SAVE | SEC_ASN1_SKIP) 597 598 /* Having any of these bits is not expected here... */ 599 PORT_Assert((underlying_kind & UNEXPECTED_FLAGS) == 0); 600 underlying_kind &= ~UNEXPECTED_FLAGS; 601 #undef UNEXPECTED_FLAGS 602 603 if (underlying_kind & SEC_ASN1_CHOICE) { 604 void *src2; 605 int indx = sec_asn1e_which_choice(src, theTemplate); 606 if (0 == indx) { 607 /* XXX set an error? "choice not found" */ 608 /* state->top->status = encodeError; */ 609 return 0; 610 } 611 612 src2 = (void *)((char *)src - theTemplate->offset + theTemplate[indx].offset); 613 len = sec_asn1e_contents_length(&theTemplate[indx], src2, 614 disallowStreaming, insideIndefinite, 615 pHdrException); 616 } else { 617 switch (underlying_kind) { 618 case SEC_ASN1_SEQUENCE_OF: 619 case SEC_ASN1_SET_OF: { 620 const SEC_ASN1Template *tmpt; 621 void *sub_src; 622 unsigned long sub_len; 623 void **group; 624 625 len = 0; 626 627 group = *(void ***)src; 628 if (group == NULL) 629 break; 630 631 tmpt = SEC_ASN1GetSubtemplate(theTemplate, src, PR_TRUE); 632 633 for (; *group != NULL; group++) { 634 sub_src = (char *)(*group) + tmpt->offset; 635 sub_len = sec_asn1e_contents_length(tmpt, sub_src, 636 disallowStreaming, 637 insideIndefinite, 638 pHdrException); 639 len += sub_len; 640 /* 641 * XXX The 1 below is the presumed length of the identifier; 642 * to support a high-tag-number this would need to be smarter. 643 */ 644 if (*pHdrException == hdr_normal) 645 len += 1 + SEC_ASN1LengthLength(sub_len); 646 } 647 } break; 648 649 case SEC_ASN1_SEQUENCE: 650 case SEC_ASN1_SET: { 651 const SEC_ASN1Template *tmpt; 652 void *sub_src; 653 unsigned long sub_len; 654 655 len = 0; 656 for (tmpt = theTemplate + 1; tmpt->kind; tmpt++) { 657 sub_src = (char *)src + tmpt->offset; 658 sub_len = sec_asn1e_contents_length(tmpt, sub_src, 659 disallowStreaming, 660 insideIndefinite, 661 pHdrException); 662 len += sub_len; 663 /* 664 * XXX The 1 below is the presumed length of the identifier; 665 * to support a high-tag-number this would need to be smarter. 666 */ 667 if (*pHdrException == hdr_normal) 668 len += 1 + SEC_ASN1LengthLength(sub_len); 669 } 670 } break; 671 672 case SEC_ASN1_BIT_STRING: 673 /* convert bit length to byte */ 674 len = (((SECItem *)src)->len + 7) >> 3; 675 /* bit string contents involve an extra octet */ 676 if (len) 677 len++; 678 break; 679 680 case SEC_ASN1_INTEGER: 681 /* ASN.1 INTEGERs are signed. 682 * If the source is an unsigned integer, the encoder will need 683 * to handle the conversion here. 684 */ 685 { 686 unsigned char *buf = ((SECItem *)src)->data; 687 SECItemType integerType = ((SECItem *)src)->type; 688 len = ((SECItem *)src)->len; 689 while (len > 0) { 690 if (*buf != 0) { 691 if (*buf & 0x80 && integerType == siUnsignedInteger) { 692 len++; /* leading zero needed to make number signed */ 693 } 694 break; /* reached beginning of number */ 695 } 696 if (len == 1) { 697 break; /* the number 0 */ 698 } 699 if (buf[1] & 0x80) { 700 break; /* leading zero already present */ 701 } 702 /* extraneous leading zero, keep going */ 703 buf++; 704 len--; 705 } 706 } 707 break; 708 709 default: 710 len = ((SECItem *)src)->len; 711 break; 712 } /* end switch */ 713 714 #ifndef WHAT_PROBLEM_DOES_THIS_SOLVE 715 /* if we're streaming, we may have a secitem w/len 0 as placeholder */ 716 if (!len && insideIndefinite && may_stream && !disallowStreaming) { 717 len = 1; 718 } 719 #endif 720 } /* end else */ 721 722 if (len == 0 && optional) 723 *pHdrException = hdr_optional; 724 else if (underlying_kind == SEC_ASN1_ANY) 725 *pHdrException = hdr_any; 726 else 727 *pHdrException = hdr_normal; 728 729 return len; 730 } 731 732 static void 733 sec_asn1e_write_header(sec_asn1e_state *state) 734 { 735 unsigned long contents_length; 736 unsigned char tag_number, tag_modifiers; 737 sec_asn1e_hdr_encoding hdrException = hdr_normal; 738 PRBool indefinite = PR_FALSE; 739 740 PORT_Assert(state->place == beforeHeader); 741 742 tag_number = state->tag_number; 743 tag_modifiers = state->tag_modifiers; 744 745 if (state->underlying_kind == SEC_ASN1_ANY) { 746 state->place = duringContents; 747 return; 748 } 749 750 if (state->underlying_kind & SEC_ASN1_CHOICE) { 751 int indx = sec_asn1e_which_choice(state->src, state->theTemplate); 752 if (0 == indx) { 753 /* XXX set an error? "choice not found" */ 754 state->top->status = encodeError; 755 return; 756 } 757 state->place = afterChoice; 758 state = sec_asn1e_push_state(state->top, &state->theTemplate[indx], 759 (char *)state->src - state->theTemplate->offset, 760 PR_TRUE); 761 if (state) { 762 /* 763 * Do the "before" field notification. 764 */ 765 sec_asn1e_notify_before(state->top, state->src, state->depth); 766 (void)sec_asn1e_init_state_based_on_template(state); 767 } 768 return; 769 } 770 771 /* The !isString test below is apparently intended to ensure that all 772 ** constructed types receive indefinite length encoding. 773 */ 774 indefinite = (PRBool)(state->top->streaming && state->may_stream && 775 (state->top->from_buf || !state->is_string)); 776 777 /* 778 * If we are doing a definite-length encoding, first we have to 779 * walk the data structure to calculate the entire contents length. 780 * If we are doing an indefinite-length encoding, we still need to 781 * know if the contents is: 782 * optional and to be omitted, or 783 * an ANY (header is pre-encoded), or 784 * a SAVE or some other kind of template used only by the decoder. 785 * So, we call this function either way. 786 */ 787 contents_length = sec_asn1e_contents_length(state->theTemplate, 788 state->src, 789 state->disallowStreaming, 790 indefinite, 791 &hdrException); 792 /* 793 * We might be told explicitly not to put out a header. 794 * But it can also be the case, via a pushed subtemplate, that 795 * sec_asn1e_contents_length could not know that this field is 796 * really optional. So check for that explicitly, too. 797 */ 798 if (hdrException != hdr_normal || 799 (contents_length == 0 && state->optional)) { 800 state->place = afterContents; 801 if (state->top->streaming && 802 state->may_stream && 803 state->top->from_buf) { 804 /* we did not find an optional indefinite string, so we 805 * don't encode it. However, if TakeFromBuf is on, we stop 806 * here anyway to give our caller a chance to intercept at the 807 * same point where we would stop if the field were present. 808 */ 809 state->top->status = needBytes; 810 } 811 return; 812 } 813 814 if (indefinite) { 815 /* 816 * We need to put out an indefinite-length encoding. 817 * The only universal types that can be constructed are SETs, 818 * SEQUENCEs, and strings; so check that it is one of those, 819 * or that it is not universal (e.g. context-specific). 820 */ 821 state->indefinite = PR_TRUE; 822 PORT_Assert((tag_number == SEC_ASN1_SET) || (tag_number == SEC_ASN1_SEQUENCE) || ((tag_modifiers & SEC_ASN1_CLASS_MASK) != 0) || state->is_string); 823 tag_modifiers |= SEC_ASN1_CONSTRUCTED; 824 contents_length = 0; 825 } 826 827 sec_asn1e_write_identifier_bytes(state, 828 (unsigned char)(tag_number | tag_modifiers)); 829 sec_asn1e_write_length_bytes(state, contents_length, state->indefinite); 830 831 if (contents_length == 0 && !state->indefinite) { 832 /* 833 * If no real contents to encode, then we are done with this field. 834 */ 835 state->place = afterContents; 836 return; 837 } 838 839 /* 840 * An EXPLICIT is nothing but an outer header, which we have already 841 * written. Now we need to do the inner header and contents. 842 */ 843 if (state->isExplicit) { 844 const SEC_ASN1Template *subt = 845 SEC_ASN1GetSubtemplate(state->theTemplate, state->src, PR_TRUE); 846 state->place = afterContents; 847 state = sec_asn1e_push_state(state->top, subt, state->src, PR_TRUE); 848 if (state != NULL) { 849 (void)sec_asn1e_init_state_based_on_template(state); 850 } 851 return; 852 } 853 854 switch (state->underlying_kind) { 855 case SEC_ASN1_SET_OF: 856 case SEC_ASN1_SEQUENCE_OF: 857 /* 858 * We need to push a child to handle each member. 859 */ 860 { 861 void **group; 862 const SEC_ASN1Template *subt; 863 864 group = *(void ***)state->src; 865 if (group == NULL || *group == NULL) { 866 /* 867 * Group is empty; we are done. 868 */ 869 state->place = afterContents; 870 return; 871 } 872 state->place = duringGroup; 873 subt = SEC_ASN1GetSubtemplate(state->theTemplate, state->src, 874 PR_TRUE); 875 state = sec_asn1e_push_state(state->top, subt, *group, PR_TRUE); 876 if (state != NULL) { 877 (void)sec_asn1e_init_state_based_on_template(state); 878 } 879 } 880 break; 881 882 case SEC_ASN1_SEQUENCE: 883 case SEC_ASN1_SET: 884 /* 885 * We need to push a child to handle the individual fields. 886 */ 887 state->place = duringSequence; 888 state = sec_asn1e_push_state(state->top, state->theTemplate + 1, 889 state->src, PR_TRUE); 890 if (state != NULL) { 891 /* 892 * Do the "before" field notification. 893 */ 894 sec_asn1e_notify_before(state->top, state->src, state->depth); 895 (void)sec_asn1e_init_state_based_on_template(state); 896 } 897 break; 898 899 default: 900 /* 901 * I think we do not need to do anything else. 902 * XXX Correct? 903 */ 904 state->place = duringContents; 905 break; 906 } 907 } 908 909 static void 910 sec_asn1e_write_contents_from_buf(sec_asn1e_state *state, 911 const char *buf, unsigned long len) 912 { 913 PORT_Assert(state->place == duringContents); 914 PORT_Assert(state->top->from_buf); 915 PORT_Assert(state->may_stream && !state->disallowStreaming); 916 917 /* 918 * Probably they just turned on "take from buf", but have not 919 * yet given us any bytes. If there is nothing in the buffer 920 * then we have nothing to do but return and wait. 921 */ 922 if (buf == NULL || len == 0) { 923 state->top->status = needBytes; 924 return; 925 } 926 /* 927 * We are streaming, reading from a passed-in buffer. 928 * This means we are encoding a simple string or an ANY. 929 * For the former, we need to put out a substring, with its 930 * own identifier and length. For an ANY, we just write it 931 * out as is (our caller is required to ensure that it 932 * is a properly encoded entity). 933 */ 934 PORT_Assert(state->is_string); /* includes ANY */ 935 if (state->underlying_kind != SEC_ASN1_ANY) { 936 unsigned char identifier; 937 938 /* 939 * Create the identifier based on underlying_kind. We cannot 940 * use tag_number and tag_modifiers because this can be an 941 * implicitly encoded field. In that case, the underlying 942 * substrings *are* encoded with their real tag. 943 */ 944 identifier = (unsigned char)(state->underlying_kind & SEC_ASN1_TAG_MASK); 945 /* 946 * The underlying kind should just be a simple string; there 947 * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set. 948 */ 949 PORT_Assert((identifier & SEC_ASN1_TAGNUM_MASK) == identifier); 950 /* 951 * Write out the tag and length for the substring. 952 */ 953 sec_asn1e_write_identifier_bytes(state, identifier); 954 if (state->underlying_kind == SEC_ASN1_BIT_STRING) { 955 char byte; 956 /* 957 * Assume we have a length in bytes but we need to output 958 * a proper bit string. This interface only works for bit 959 * strings that are full multiples of 8. If support for 960 * real, variable length bit strings is needed then the 961 * caller will have to know to pass in a bit length instead 962 * of a byte length and then this code will have to 963 * perform the encoding necessary (length written is length 964 * in bytes plus 1, and the first octet of string is the 965 * number of bits remaining between the end of the bit 966 * string and the next byte boundary). 967 */ 968 sec_asn1e_write_length_bytes(state, len + 1, PR_FALSE); 969 byte = 0; 970 sec_asn1e_write_contents_bytes(state, &byte, 1); 971 } else { 972 sec_asn1e_write_length_bytes(state, len, PR_FALSE); 973 } 974 } 975 sec_asn1e_write_contents_bytes(state, buf, len); 976 state->top->status = needBytes; 977 } 978 979 static void 980 sec_asn1e_write_contents(sec_asn1e_state *state) 981 { 982 unsigned long len = 0; 983 984 PORT_Assert(state->place == duringContents); 985 986 switch (state->underlying_kind) { 987 case SEC_ASN1_SET: 988 case SEC_ASN1_SEQUENCE: 989 PORT_Assert(0); 990 break; 991 992 case SEC_ASN1_BIT_STRING: { 993 SECItem *item; 994 char rem; 995 996 item = (SECItem *)state->src; 997 len = (item->len + 7) >> 3; 998 rem = (unsigned char)((len << 3) - item->len); /* remaining bits */ 999 sec_asn1e_write_contents_bytes(state, &rem, 1); 1000 sec_asn1e_write_contents_bytes(state, (char *)item->data, len); 1001 } break; 1002 1003 case SEC_ASN1_BMP_STRING: 1004 /* The number of bytes must be divisable by 2 */ 1005 if ((((SECItem *)state->src)->len) % 2) { 1006 SEC_ASN1EncoderContext *cx; 1007 1008 cx = state->top; 1009 cx->status = encodeError; 1010 break; 1011 } 1012 /* otherwise, fall through to write the content */ 1013 goto process_string; 1014 1015 case SEC_ASN1_UNIVERSAL_STRING: 1016 /* The number of bytes must be divisable by 4 */ 1017 if ((((SECItem *)state->src)->len) % 4) { 1018 SEC_ASN1EncoderContext *cx; 1019 1020 cx = state->top; 1021 cx->status = encodeError; 1022 break; 1023 } 1024 /* otherwise, fall through to write the content */ 1025 goto process_string; 1026 1027 case SEC_ASN1_INTEGER: 1028 /* ASN.1 INTEGERs are signed. If the source is an unsigned 1029 * integer, the encoder will need to handle the conversion here. 1030 */ 1031 { 1032 unsigned int blen; 1033 unsigned char *buf; 1034 SECItemType integerType; 1035 blen = ((SECItem *)state->src)->len; 1036 buf = ((SECItem *)state->src)->data; 1037 integerType = ((SECItem *)state->src)->type; 1038 while (blen > 0) { 1039 if (*buf & 0x80 && integerType == siUnsignedInteger) { 1040 char zero = 0; /* write a leading 0 */ 1041 sec_asn1e_write_contents_bytes(state, &zero, 1); 1042 /* and then the remaining buffer */ 1043 sec_asn1e_write_contents_bytes(state, 1044 (char *)buf, blen); 1045 break; 1046 } 1047 /* Check three possibilities: 1048 * 1. No leading zeros, msb of MSB is not 1; 1049 * 2. The number is zero itself; 1050 * 3. Encoding a signed integer with a leading zero, 1051 * keep the zero so that the number is positive. 1052 */ 1053 if (*buf != 0 || 1054 blen == 1 || 1055 (buf[1] & 0x80 && integerType != siUnsignedInteger)) { 1056 sec_asn1e_write_contents_bytes(state, 1057 (char *)buf, blen); 1058 break; 1059 } 1060 /* byte is 0, continue */ 1061 buf++; 1062 blen--; 1063 } 1064 } 1065 /* done with this content */ 1066 break; 1067 1068 process_string: 1069 default: { 1070 SECItem *item; 1071 1072 item = (SECItem *)state->src; 1073 sec_asn1e_write_contents_bytes(state, (char *)item->data, 1074 item->len); 1075 } break; 1076 } 1077 state->place = afterContents; 1078 } 1079 1080 /* 1081 * We are doing a SET OF or SEQUENCE OF, and have just finished an item. 1082 */ 1083 static void 1084 sec_asn1e_next_in_group(sec_asn1e_state *state) 1085 { 1086 sec_asn1e_state *child; 1087 void **group; 1088 void *member; 1089 1090 PORT_Assert(state->place == duringGroup); 1091 PORT_Assert(state->child != NULL); 1092 1093 child = state->child; 1094 1095 group = *(void ***)state->src; 1096 1097 /* 1098 * Find placement of current item. 1099 */ 1100 member = (char *)(state->child->src) - child->theTemplate->offset; 1101 while (*group != member) 1102 group++; 1103 1104 /* 1105 * Move forward to next item. 1106 */ 1107 group++; 1108 if (*group == NULL) { 1109 /* 1110 * That was our last one; we are done now. 1111 */ 1112 child->place = notInUse; 1113 state->place = afterContents; 1114 return; 1115 } 1116 child->src = (char *)(*group) + child->theTemplate->offset; 1117 1118 /* 1119 * Re-"push" child. 1120 */ 1121 sec_asn1e_scrub_state(child); 1122 state->top->current = child; 1123 } 1124 1125 /* 1126 * We are moving along through a sequence; move forward by one, 1127 * (detecting end-of-sequence when it happens). 1128 */ 1129 static void 1130 sec_asn1e_next_in_sequence(sec_asn1e_state *state) 1131 { 1132 sec_asn1e_state *child; 1133 1134 PORT_Assert(state->place == duringSequence); 1135 PORT_Assert(state->child != NULL); 1136 1137 child = state->child; 1138 1139 /* 1140 * Do the "after" field notification. 1141 */ 1142 sec_asn1e_notify_after(state->top, child->src, child->depth); 1143 1144 /* 1145 * Move forward. 1146 */ 1147 child->theTemplate++; 1148 if (child->theTemplate->kind == 0) { 1149 /* 1150 * We are done with this sequence. 1151 */ 1152 child->place = notInUse; 1153 state->place = afterContents; 1154 return; 1155 } 1156 1157 /* 1158 * Reset state and push. 1159 */ 1160 1161 child->src = (char *)state->src + child->theTemplate->offset; 1162 1163 /* 1164 * Do the "before" field notification. 1165 */ 1166 sec_asn1e_notify_before(state->top, child->src, child->depth); 1167 1168 state->top->current = child; 1169 (void)sec_asn1e_init_state_based_on_template(child); 1170 } 1171 1172 static void 1173 sec_asn1e_after_contents(sec_asn1e_state *state) 1174 { 1175 PORT_Assert(state->place == afterContents); 1176 1177 if (state->indefinite) 1178 sec_asn1e_write_end_of_contents_bytes(state); 1179 1180 /* 1181 * Just make my parent be the current state. It will then clean 1182 * up after me and free me (or reuse me). 1183 */ 1184 state->top->current = state->parent; 1185 } 1186 1187 /* 1188 * This function is called whether or not we are streaming; if we 1189 * *are* streaming, our caller can also instruct us to take bytes 1190 * from the passed-in buffer (at buf, for length len, which is likely 1191 * bytes but could even mean bits if the current field is a bit string). 1192 * If we have been so instructed, we will gobble up bytes from there 1193 * (rather than from our src structure) and output them, and then 1194 * we will just return, expecting to be called again -- either with 1195 * more bytes or after our caller has instructed us that we are done 1196 * (for now) with the buffer. 1197 */ 1198 SECStatus 1199 SEC_ASN1EncoderUpdate(SEC_ASN1EncoderContext *cx, 1200 const char *buf, unsigned long len) 1201 { 1202 sec_asn1e_state *state; 1203 1204 if (cx->status == needBytes) { 1205 cx->status = keepGoing; 1206 } 1207 1208 while (cx->status == keepGoing) { 1209 state = cx->current; 1210 switch (state->place) { 1211 case beforeHeader: 1212 sec_asn1e_write_header(state); 1213 break; 1214 case duringContents: 1215 if (cx->from_buf) 1216 sec_asn1e_write_contents_from_buf(state, buf, len); 1217 else 1218 sec_asn1e_write_contents(state); 1219 break; 1220 case duringGroup: 1221 sec_asn1e_next_in_group(state); 1222 break; 1223 case duringSequence: 1224 sec_asn1e_next_in_sequence(state); 1225 break; 1226 case afterContents: 1227 sec_asn1e_after_contents(state); 1228 break; 1229 case afterImplicit: 1230 case afterInline: 1231 case afterPointer: 1232 case afterChoice: 1233 /* 1234 * These states are more documentation than anything. 1235 * They just need to force a pop. 1236 */ 1237 PORT_Assert(!state->indefinite); 1238 state->place = afterContents; 1239 break; 1240 case notInUse: 1241 default: 1242 /* This is not an error, but rather a plain old BUG! */ 1243 PORT_Assert(0); 1244 cx->status = encodeError; 1245 break; 1246 } 1247 1248 if (cx->status == encodeError) 1249 break; 1250 1251 /* It might have changed, so we have to update our local copy. */ 1252 state = cx->current; 1253 1254 /* If it is NULL, we have popped all the way to the top. */ 1255 if (state == NULL) { 1256 cx->status = allDone; 1257 break; 1258 } 1259 } 1260 1261 if (cx->status == encodeError) { 1262 return SECFailure; 1263 } 1264 1265 return SECSuccess; 1266 } 1267 1268 void 1269 SEC_ASN1EncoderFinish(SEC_ASN1EncoderContext *cx) 1270 { 1271 /* 1272 * XXX anything else that needs to be finished? 1273 */ 1274 1275 PORT_FreeArena(cx->our_pool, PR_FALSE); 1276 } 1277 1278 SEC_ASN1EncoderContext * 1279 SEC_ASN1EncoderStart(const void *src, const SEC_ASN1Template *theTemplate, 1280 SEC_ASN1WriteProc output_proc, void *output_arg) 1281 { 1282 PLArenaPool *our_pool; 1283 SEC_ASN1EncoderContext *cx; 1284 1285 our_pool = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); 1286 if (our_pool == NULL) 1287 return NULL; 1288 1289 cx = (SEC_ASN1EncoderContext *)PORT_ArenaZAlloc(our_pool, sizeof(*cx)); 1290 if (cx == NULL) { 1291 PORT_FreeArena(our_pool, PR_FALSE); 1292 return NULL; 1293 } 1294 1295 cx->our_pool = our_pool; 1296 cx->output_proc = output_proc; 1297 cx->output_arg = output_arg; 1298 1299 cx->status = keepGoing; 1300 1301 if (sec_asn1e_push_state(cx, theTemplate, src, PR_FALSE) == NULL || 1302 sec_asn1e_init_state_based_on_template(cx->current) == NULL) { 1303 /* 1304 * Trouble initializing (probably due to failed allocations) 1305 * requires that we just give up. 1306 */ 1307 PORT_FreeArena(our_pool, PR_FALSE); 1308 return NULL; 1309 } 1310 1311 return cx; 1312 } 1313 1314 /* 1315 * XXX Do we need a FilterProc, too? 1316 */ 1317 1318 void 1319 SEC_ASN1EncoderSetNotifyProc(SEC_ASN1EncoderContext *cx, 1320 SEC_ASN1NotifyProc fn, void *arg) 1321 { 1322 cx->notify_proc = fn; 1323 cx->notify_arg = arg; 1324 } 1325 1326 void 1327 SEC_ASN1EncoderClearNotifyProc(SEC_ASN1EncoderContext *cx) 1328 { 1329 cx->notify_proc = NULL; 1330 cx->notify_arg = NULL; /* not necessary; just being clean */ 1331 } 1332 1333 void 1334 SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error) 1335 { 1336 PORT_Assert(cx); 1337 PORT_SetError(error); 1338 cx->status = encodeError; 1339 } 1340 1341 void 1342 SEC_ASN1EncoderSetStreaming(SEC_ASN1EncoderContext *cx) 1343 { 1344 /* XXX is there a way to check that we are "between" fields here? */ 1345 1346 cx->streaming = PR_TRUE; 1347 } 1348 1349 void 1350 SEC_ASN1EncoderClearStreaming(SEC_ASN1EncoderContext *cx) 1351 { 1352 /* XXX is there a way to check that we are "between" fields here? */ 1353 1354 cx->streaming = PR_FALSE; 1355 } 1356 1357 void 1358 SEC_ASN1EncoderSetTakeFromBuf(SEC_ASN1EncoderContext *cx) 1359 { 1360 /* 1361 * XXX is there a way to check that we are "between" fields here? this 1362 * needs to include a check for being in between groups of items in 1363 * a SET_OF or SEQUENCE_OF. 1364 */ 1365 PORT_Assert(cx->streaming); 1366 1367 cx->from_buf = PR_TRUE; 1368 } 1369 1370 void 1371 SEC_ASN1EncoderClearTakeFromBuf(SEC_ASN1EncoderContext *cx) 1372 { 1373 /* we should actually be taking from buf *now* */ 1374 PORT_Assert(cx->from_buf); 1375 if (!cx->from_buf) /* if not, just do nothing */ 1376 return; 1377 1378 cx->from_buf = PR_FALSE; 1379 1380 if (cx->status == needBytes) { 1381 cx->status = keepGoing; 1382 cx->current->place = afterContents; 1383 } 1384 } 1385 1386 SECStatus 1387 SEC_ASN1Encode(const void *src, const SEC_ASN1Template *theTemplate, 1388 SEC_ASN1WriteProc output_proc, void *output_arg) 1389 { 1390 SEC_ASN1EncoderContext *ecx; 1391 SECStatus rv; 1392 1393 ecx = SEC_ASN1EncoderStart(src, theTemplate, output_proc, output_arg); 1394 if (ecx == NULL) 1395 return SECFailure; 1396 1397 rv = SEC_ASN1EncoderUpdate(ecx, NULL, 0); 1398 1399 SEC_ASN1EncoderFinish(ecx); 1400 return rv; 1401 } 1402 1403 /* 1404 * XXX depth and data_kind are unused; is there a PC way to silence warnings? 1405 * (I mean "politically correct", not anything to do with intel/win platform) 1406 */ 1407 static void 1408 sec_asn1e_encode_item_count(void *arg, const char *buf, unsigned long len, 1409 int depth, SEC_ASN1EncodingPart data_kind) 1410 { 1411 unsigned long *count; 1412 1413 count = (unsigned long *)arg; 1414 PORT_Assert(count != NULL); 1415 1416 *count += len; 1417 } 1418 1419 /* XXX depth and data_kind are unused; is there a PC way to silence warnings? */ 1420 static void 1421 sec_asn1e_encode_item_store(void *arg, const char *buf, unsigned long len, 1422 int depth, SEC_ASN1EncodingPart data_kind) 1423 { 1424 SECItem *dest; 1425 1426 dest = (SECItem *)arg; 1427 PORT_Assert(dest != NULL); 1428 1429 if (len > 0) { 1430 PORT_Memcpy(dest->data + dest->len, buf, len); 1431 dest->len += len; 1432 } 1433 } 1434 1435 /* 1436 * Allocate an entire SECItem, or just the data part of it, to hold 1437 * "len" bytes of stuff. Allocate from the given pool, if specified, 1438 * otherwise just do a vanilla PORT_Alloc. 1439 * 1440 * XXX This seems like a reasonable general-purpose function (for SECITEM_)? 1441 */ 1442 static SECItem * 1443 sec_asn1e_allocate_item(PLArenaPool *poolp, SECItem *dest, unsigned long len) 1444 { 1445 if (poolp != NULL) { 1446 void *release; 1447 1448 release = PORT_ArenaMark(poolp); 1449 if (dest == NULL) 1450 dest = (SECItem *)PORT_ArenaAlloc(poolp, sizeof(SECItem)); 1451 if (dest != NULL) { 1452 dest->data = (unsigned char *)PORT_ArenaAlloc(poolp, len); 1453 if (dest->data == NULL) { 1454 dest = NULL; 1455 } 1456 } 1457 if (dest == NULL) { 1458 /* one or both allocations failed; release everything */ 1459 PORT_ArenaRelease(poolp, release); 1460 } else { 1461 /* everything okay; unmark the arena */ 1462 PORT_ArenaUnmark(poolp, release); 1463 } 1464 } else { 1465 SECItem *indest; 1466 1467 indest = dest; 1468 if (dest == NULL) 1469 dest = (SECItem *)PORT_Alloc(sizeof(SECItem)); 1470 if (dest != NULL) { 1471 dest->type = siBuffer; 1472 dest->data = (unsigned char *)PORT_Alloc(len); 1473 if (dest->data == NULL) { 1474 if (indest == NULL) 1475 PORT_Free(dest); 1476 dest = NULL; 1477 } 1478 } 1479 } 1480 1481 return dest; 1482 } 1483 1484 SECItem * 1485 SEC_ASN1EncodeItem(PLArenaPool *poolp, SECItem *dest, const void *src, 1486 const SEC_ASN1Template *theTemplate) 1487 { 1488 unsigned long encoding_length; 1489 SECStatus rv; 1490 1491 PORT_Assert(dest == NULL || dest->data == NULL); 1492 1493 encoding_length = 0; 1494 rv = SEC_ASN1Encode(src, theTemplate, 1495 sec_asn1e_encode_item_count, &encoding_length); 1496 if (rv != SECSuccess) 1497 return NULL; 1498 1499 dest = sec_asn1e_allocate_item(poolp, dest, encoding_length); 1500 if (dest == NULL) 1501 return NULL; 1502 1503 /* XXX necessary? This really just checks for a bug in the allocate fn */ 1504 PORT_Assert(dest->data != NULL); 1505 if (dest->data == NULL) 1506 return NULL; 1507 1508 dest->len = 0; 1509 (void)SEC_ASN1Encode(src, theTemplate, sec_asn1e_encode_item_store, dest); 1510 1511 PORT_Assert(encoding_length == dest->len); 1512 return dest; 1513 } 1514 1515 static SECItem * 1516 sec_asn1e_integer(PLArenaPool *poolp, SECItem *dest, unsigned long value, 1517 PRBool is_unsigned) 1518 { 1519 unsigned long copy; 1520 unsigned char sign; 1521 int len = 0; 1522 1523 /* 1524 * Determine the length of the encoded value (minimum of 1). 1525 */ 1526 copy = value; 1527 do { 1528 len++; 1529 sign = (unsigned char)(copy & 0x80); 1530 copy >>= 8; 1531 } while (copy); 1532 1533 /* 1534 * If 'value' is non-negative, and the high bit of the last 1535 * byte we counted was set, we need to add one to the length so 1536 * we put a high-order zero byte in the encoding. 1537 */ 1538 if (sign && (is_unsigned || (long)value >= 0)) 1539 len++; 1540 1541 /* 1542 * Allocate the item (if necessary) and the data pointer within. 1543 */ 1544 dest = sec_asn1e_allocate_item(poolp, dest, len); 1545 if (dest == NULL) 1546 return NULL; 1547 1548 /* 1549 * Store the value, byte by byte, in the item. 1550 */ 1551 dest->len = len; 1552 while (len) { 1553 dest->data[--len] = (unsigned char)value; 1554 value >>= 8; 1555 } 1556 PORT_Assert(value == 0); 1557 1558 return dest; 1559 } 1560 1561 SECItem * 1562 SEC_ASN1EncodeInteger(PLArenaPool *poolp, SECItem *dest, long value) 1563 { 1564 return sec_asn1e_integer(poolp, dest, (unsigned long)value, PR_FALSE); 1565 } 1566 1567 SECItem * 1568 SEC_ASN1EncodeUnsignedInteger(PLArenaPool *poolp, 1569 SECItem *dest, unsigned long value) 1570 { 1571 return sec_asn1e_integer(poolp, dest, value, PR_TRUE); 1572 }