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