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
43typedef 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
56typedef enum {
57    allDone,
58    encodeError,
59    keepGoing,
60    needBytes
61} sec_asn1e_parse_status;
62
63typedef 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 */
101struct 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
119static sec_asn1e_state *
120sec_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
154static void
155sec_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
166static void
167sec_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
178static void
179sec_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
190static sec_asn1e_state *
191sec_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__ */);
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
411static void
412sec_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 */
428static void
429sec_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
437int
438SEC_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
458static void
459sec_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
477static void
478sec_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
485static void
486sec_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
493static int
494sec_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
512static unsigned long
513sec_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__ */);
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__ */);
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
779static void
780sec_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__ */),
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__ */);
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
954static void
955sec_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
1119process_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 */
1138static void
1139sec_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 */
1185static void
1186sec_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
1229static void
1230sec_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 */
1256SECStatus
1257SEC_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
1325void
1326SEC_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
1336SEC_ASN1EncoderContext *
1337SEC_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
1378void
1379SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext *cx,
1380			      SEC_ASN1NotifyProc fn, void *arg)
1381{
1382    cx->notify_proc = fn;
1383    cx->notify_arg = arg;
1384}
1385
1386
1387void
1388SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext *cx)
1389{
1390    cx->notify_proc = NULL;
1391    cx->notify_arg = NULL;	/* not necessary; just being clean */
1392}
1393
1394
1395void
1396SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error)
1397{
1398    PORT_Assert(cx);
1399    PORT_SetError(error);
1400    cx->status = encodeError;
1401}
1402
1403
1404void
1405SEC_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
1413void
1414SEC_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
1422void
1423SEC_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
1436void
1437SEC_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
1453SECStatus
1454SEC_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 */
1475void
1476sec_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? */
1489void
1490sec_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 */
1510SecAsn1Item *
1511sec_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
1555SecAsn1Item *
1556SEC_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
1587static SecAsn1Item *
1588sec_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
1634SecAsn1Item *
1635SEC_ASN1EncodeInteger(PRArenaPool *poolp, SecAsn1Item *dest, long value)
1636{
1637    return sec_asn1e_integer (poolp, dest, (unsigned long) value, PR_FALSE);
1638}
1639
1640
1641extern SecAsn1Item *
1642SEC_ASN1EncodeUnsignedInteger(PRArenaPool *poolp,
1643			      SecAsn1Item *dest, unsigned long value)
1644{
1645    return sec_asn1e_integer (poolp, dest, value, PR_TRUE);
1646}
1647