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      return;
818    }
819
820    /*
821     * We are doing a definite-length encoding.  First we have to
822     * walk the data structure to calculate the entire contents length.
823     */
824    contents_length = sec_asn1e_contents_length (state->theTemplate,
825						 state->src,
826                                                 state->ignore_stream,
827                                                 &noheader);
828    /*
829     * We might be told explicitly not to put out a header.
830     * But it can also be the case, via a pushed subtemplate, that
831     * sec_asn1e_contents_length could not know that this field is
832     * really optional.  So check for that explicitly, too.
833     */
834    if (noheader || (contents_length == 0 && state->optional)) {
835	state->place = afterContents;
836	if (state->top->streaming && state->may_stream && state->top->from_buf)
837	    /* we did not find an optional indefinite string, so we don't encode it.
838	     * However, if TakeFromBuf is on, we stop here anyway to give our caller
839	     * a chance to intercept at the same point where we would stop if the
840	     * field were present. */
841	    state->top->status = needBytes;
842	return;
843    }
844
845    if (state->top->streaming && state->may_stream
846			      && (state->top->from_buf || !state->is_string)) {
847	/*
848	 * We need to put out an indefinite-length encoding.
849	 */
850	state->indefinite = PR_TRUE;
851	/*
852	 * The only universal types that can be constructed are SETs,
853	 * SEQUENCEs, and strings; so check that it is one of those,
854	 * or that it is not universal (e.g. context-specific).
855	 */
856	PORT_Assert ((tag_number == SEC_ASN1_SET)
857		     || (tag_number == SEC_ASN1_SEQUENCE)
858		     || ((tag_modifiers & SEC_ASN1_CLASS_MASK) != 0)
859		     || state->is_string);
860	tag_modifiers |= SEC_ASN1_CONSTRUCTED;
861	contents_length = 0;
862    }
863
864    sec_asn1e_write_identifier_bytes (state, (unsigned char)(tag_number | tag_modifiers));
865    sec_asn1e_write_length_bytes (state, contents_length, state->indefinite);
866
867    if (contents_length == 0 && !state->indefinite) {
868	/*
869	 * If no real contents to encode, then we are done with this field.
870	 */
871	state->place = afterContents;
872	return;
873    }
874
875    /*
876     * An EXPLICIT is nothing but an outer header, which we have already
877     * written.  Now we need to do the inner header and contents.
878     */
879    if (state->explicit) {
880	state->place = afterContents;
881	state = sec_asn1e_push_state (state->top,
882				      SEC_ASN1GetSubtemplate(state->theTemplate,
883							     state->src,
884							     PR_TRUE,
885								 NULL /* __APPLE__ */),
886				      state->src, PR_TRUE);
887	if (state != NULL)
888	    state = sec_asn1e_init_state_based_on_template (state);
889	return;
890    }
891
892    switch (state->underlying_kind) {
893      case SEC_ASN1_SET_OF:
894      case SEC_ASN1_SEQUENCE_OF:
895	/*
896	 * We need to push a child to handle each member.
897	 */
898	{
899	    void **group;
900	    const SecAsn1Template *subt;
901
902	    group = *(void ***)state->src;
903	    if (group == NULL || *group == NULL) {
904		/*
905		 * Group is empty; we are done.
906		 */
907		state->place = afterContents;
908		return;
909	    }
910	    state->place = duringGroup;
911	    subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src,
912					   PR_TRUE, NULL /* __APPLE__ */);
913	    state = sec_asn1e_push_state (state->top, subt, *group, PR_TRUE);
914	    if (state != NULL)
915		state = sec_asn1e_init_state_based_on_template (state);
916	}
917	break;
918
919      case SEC_ASN1_SEQUENCE:
920      case SEC_ASN1_SET:
921	/*
922	 * We need to push a child to handle the individual fields.
923	 */
924	state->place = duringSequence;
925	state = sec_asn1e_push_state (state->top, state->theTemplate + 1,
926				      state->src, PR_TRUE);
927	if (state != NULL) {
928	    /*
929	     * Do the "before" field notification.
930	     */
931	    sec_asn1e_notify_before (state->top, state->src, state->depth);
932	    state = sec_asn1e_init_state_based_on_template (state);
933	}
934	break;
935
936      default:
937	/*
938	 * I think we do not need to do anything else.
939	 * XXX Correct?
940	 */
941	state->place = duringContents;
942	break;
943    }
944}
945
946
947static void
948sec_asn1e_write_contents (sec_asn1e_state *state,
949			  const char *buf, unsigned long len)
950{
951    PORT_Assert (state->place == duringContents);
952
953    if (state->top->from_buf) {
954	/*
955	 * Probably they just turned on "take from buf", but have not
956	 * yet given us any bytes.  If there is nothing in the buffer
957	 * then we have nothing to do but return and wait.
958	 */
959	if (buf == NULL || len == 0) {
960	    state->top->status = needBytes;
961	    return;
962	}
963	/*
964	 * We are streaming, reading from a passed-in buffer.
965	 * This means we are encoding a simple string or an ANY.
966	 * For the former, we need to put out a substring, with its
967	 * own identifier and length.  For an ANY, we just write it
968	 * out as is (our caller is required to ensure that it
969	 * is a properly encoded entity).
970	 */
971	PORT_Assert (state->is_string);		/* includes ANY */
972	if (state->underlying_kind != SEC_ASN1_ANY) {
973	    unsigned char identifier;
974
975	    /*
976	     * Create the identifier based on underlying_kind.  We cannot
977	     * use tag_number and tag_modifiers because this can be an
978	     * implicitly encoded field.  In that case, the underlying
979	     * substrings *are* encoded with their real tag.
980	     */
981	    identifier = (unsigned char)state->underlying_kind & SEC_ASN1_TAG_MASK;
982	    /*
983	     * The underlying kind should just be a simple string; there
984	     * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
985	     */
986	    PORT_Assert ((identifier & SEC_ASN1_TAGNUM_MASK) == identifier);
987	    /*
988	     * Write out the tag and length for the substring.
989	     */
990	    sec_asn1e_write_identifier_bytes (state, identifier);
991	    if (state->underlying_kind == SEC_ASN1_BIT_STRING) {
992		char byte;
993		/*
994		 * Assume we have a length in bytes but we need to output
995		 * a proper bit string.  This interface only works for bit
996		 * strings that are full multiples of 8.  If support for
997		 * real, variable length bit strings is needed then the
998		 * caller will have to know to pass in a bit length instead
999		 * of a byte length and then this code will have to
1000		 * perform the encoding necessary (length written is length
1001		 * in bytes plus 1, and the first octet of string is the
1002		 * number of bits remaining between the end of the bit
1003		 * string and the next byte boundary).
1004		 */
1005		sec_asn1e_write_length_bytes (state, len + 1, PR_FALSE);
1006		byte = 0;
1007		sec_asn1e_write_contents_bytes (state, &byte, 1);
1008	    } else {
1009		sec_asn1e_write_length_bytes (state, len, PR_FALSE);
1010	    }
1011	}
1012	sec_asn1e_write_contents_bytes (state, buf, len);
1013	state->top->status = needBytes;
1014    } else {
1015	switch (state->underlying_kind) {
1016	  case SEC_ASN1_SET:
1017	  case SEC_ASN1_SEQUENCE:
1018	    PORT_Assert (0);
1019	    break;
1020
1021	  case SEC_ASN1_BIT_STRING:
1022	    {
1023		SecAsn1Item *item;
1024		char rem;
1025
1026		item = (SecAsn1Item *)state->src;
1027		len = (item->Length + 7) >> 3;
1028		rem = (unsigned char)((len << 3) - item->Length);	/* remaining bits */
1029		sec_asn1e_write_contents_bytes (state, &rem, 1);
1030		sec_asn1e_write_contents_bytes (state, (char *) item->Data,
1031						len);
1032	    }
1033	    break;
1034
1035	  case SEC_ASN1_BMP_STRING:
1036	    /* The number of bytes must be divisable by 2 */
1037	    if ((((SecAsn1Item *)state->src)->Length) % 2) {
1038		SEC_ASN1EncoderContext *cx;
1039
1040		cx = state->top;
1041		cx->status = encodeError;
1042		break;
1043	    }
1044	    /* otherwise, fall through to write the content */
1045	    goto process_string;
1046
1047	  case SEC_ASN1_UNIVERSAL_STRING:
1048	    /* The number of bytes must be divisable by 4 */
1049	    if ((((SecAsn1Item *)state->src)->Length) % 4) {
1050		SEC_ASN1EncoderContext *cx;
1051
1052		cx = state->top;
1053		cx->status = encodeError;
1054		break;
1055	    }
1056	    /* otherwise, fall through to write the content */
1057	    goto process_string;
1058
1059	  case SEC_ASN1_INTEGER:
1060	   /* ASN.1 INTEGERs are signed.  If the source is an unsigned
1061	    * integer, the encoder will need to handle the conversion here.
1062	    */
1063	    {
1064		size_t blen;
1065		unsigned char *intbuf;
1066		#ifdef	__APPLE__
1067		PRBool signedInt = state->signedInt;
1068		#else
1069		SECItemType integerType = ((SecAsn1Item *)state->src)->type;
1070		#endif
1071		blen = ((SecAsn1Item *)state->src)->Length;
1072		intbuf = ((SecAsn1Item *)state->src)->Data;
1073		while (blen > 0) {
1074			#ifdef	__APPLE__
1075		    if (*intbuf & 0x80 && !signedInt) {
1076			#else
1077		    if (*intbuf & 0x80 && integerType == siUnsignedInteger) {
1078			#endif
1079				char zero = 0; /* write a leading 0 */
1080				sec_asn1e_write_contents_bytes(state, &zero, 1);
1081				/* and then the remaining buffer */
1082				sec_asn1e_write_contents_bytes(state,
1083											(char *)intbuf, blen);
1084				break;
1085		    }
1086		    /* Check three possibilities:
1087		     * 1.  No leading zeros, msb of MSB is not 1;
1088		     * 2.  The number is zero itself;
1089		     * 3.  Encoding a signed integer with a leading zero,
1090		     *     keep the zero so that the number is positive.
1091		     */
1092		    if (*intbuf != 0 ||
1093		         blen == 1 ||
1094				 #ifdef	__APPLE__
1095		         (intbuf[1] & 0x80 && signedInt) )
1096				 #else
1097		         (intbuf[1] & 0x80 && integerType != siUnsignedInteger) )
1098				 #endif
1099		    {
1100				sec_asn1e_write_contents_bytes(state,
1101											(char *)intbuf, blen);
1102				break;
1103		    }
1104		    /* byte is 0, continue */
1105		    intbuf++;
1106		    blen--;
1107		}
1108	    }
1109	    /* done with this content */
1110	    break;
1111
1112process_string:
1113	  default:
1114	    {
1115		SecAsn1Item *item;
1116
1117		item = (SecAsn1Item *)state->src;
1118		sec_asn1e_write_contents_bytes (state, (char *) item->Data,
1119						item->Length);
1120	    }
1121	    break;
1122	}
1123	state->place = afterContents;
1124    }
1125}
1126
1127
1128/*
1129 * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
1130 */
1131static void
1132sec_asn1e_next_in_group (sec_asn1e_state *state)
1133{
1134    sec_asn1e_state *child;
1135    void **group;
1136    void *member;
1137
1138    PORT_Assert (state->place == duringGroup);
1139    PORT_Assert (state->child != NULL);
1140
1141    child = state->child;
1142
1143    group = *(void ***)state->src;
1144
1145    /*
1146     * Find placement of current item.
1147     */
1148    member = (char *)(state->child->src) - child->theTemplate->offset;
1149    while (*group != member)
1150	group++;
1151
1152    /*
1153     * Move forward to next item.
1154     */
1155    group++;
1156    if (*group == NULL) {
1157	/*
1158	 * That was our last one; we are done now.
1159	 */
1160	child->place = notInUse;
1161	state->place = afterContents;
1162	return;
1163    }
1164    child->src = (char *)(*group) + child->theTemplate->offset;
1165
1166    /*
1167     * Re-"push" child.
1168     */
1169    sec_asn1e_scrub_state (child);
1170    state->top->current = child;
1171}
1172
1173
1174/*
1175 * We are moving along through a sequence; move forward by one,
1176 * (detecting end-of-sequence when it happens).
1177 */
1178static void
1179sec_asn1e_next_in_sequence (sec_asn1e_state *state)
1180{
1181    sec_asn1e_state *child;
1182
1183    PORT_Assert (state->place == duringSequence);
1184    PORT_Assert (state->child != NULL);
1185
1186    child = state->child;
1187
1188    /*
1189     * Do the "after" field notification.
1190     */
1191    sec_asn1e_notify_after (state->top, child->src, child->depth);
1192
1193    /*
1194     * Move forward.
1195     */
1196    child->theTemplate++;
1197    if (child->theTemplate->kind == 0) {
1198	/*
1199	 * We are done with this sequence.
1200	 */
1201	child->place = notInUse;
1202	state->place = afterContents;
1203	return;
1204    }
1205
1206    /*
1207     * Reset state and push.
1208     */
1209
1210    child->src = (char *)state->src + child->theTemplate->offset;
1211
1212    /*
1213     * Do the "before" field notification.
1214     */
1215    sec_asn1e_notify_before (state->top, child->src, child->depth);
1216
1217    state->top->current = child;
1218    (void) sec_asn1e_init_state_based_on_template (child);
1219}
1220
1221
1222static void
1223sec_asn1e_after_contents (sec_asn1e_state *state)
1224{
1225    PORT_Assert (state->place == afterContents);
1226
1227    if (state->indefinite)
1228	sec_asn1e_write_end_of_contents_bytes (state);
1229
1230    /*
1231     * Just make my parent be the current state.  It will then clean
1232     * up after me and free me (or reuse me).
1233     */
1234    state->top->current = state->parent;
1235}
1236
1237
1238/*
1239 * This function is called whether or not we are streaming; if we
1240 * *are* streaming, our caller can also instruct us to take bytes
1241 * from the passed-in buffer (at buf, for length len, which is likely
1242 * bytes but could even mean bits if the current field is a bit string).
1243 * If we have been so instructed, we will gobble up bytes from there
1244 * (rather than from our src structure) and output them, and then
1245 * we will just return, expecting to be called again -- either with
1246 * more bytes or after our caller has instructed us that we are done
1247 * (for now) with the buffer.
1248 */
1249SECStatus
1250SEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext *cx,
1251		       const char *buf, unsigned long len)
1252{
1253    sec_asn1e_state *state;
1254
1255    if (cx->status == needBytes) {
1256	PORT_Assert (buf != NULL && len != 0);
1257	cx->status = keepGoing;
1258    }
1259
1260    while (cx->status == keepGoing) {
1261	state = cx->current;
1262	switch (state->place) {
1263	  case beforeHeader:
1264	    sec_asn1e_write_header (state);
1265	    break;
1266	  case duringContents:
1267	    sec_asn1e_write_contents (state, buf, len);
1268	    break;
1269	  case duringGroup:
1270	    sec_asn1e_next_in_group (state);
1271	    break;
1272	  case duringSequence:
1273	    sec_asn1e_next_in_sequence (state);
1274	    break;
1275	  case afterContents:
1276	    sec_asn1e_after_contents (state);
1277	    break;
1278	  case afterImplicit:
1279	  case afterInline:
1280	  case afterPointer:
1281	  case afterChoice:
1282	    /*
1283	     * These states are more documentation than anything.
1284	     * They just need to force a pop.
1285	     */
1286	    PORT_Assert (!state->indefinite);
1287	    state->place = afterContents;
1288	    break;
1289	  case notInUse:
1290	  default:
1291	    /* This is not an error, but rather a plain old BUG! */
1292	    PORT_Assert (0);
1293	    cx->status = encodeError;
1294	    break;
1295	}
1296
1297	if (cx->status == encodeError)
1298	    break;
1299
1300	/* It might have changed, so we have to update our local copy.  */
1301	state = cx->current;
1302
1303	/* If it is NULL, we have popped all the way to the top.  */
1304	if (state == NULL) {
1305	    cx->status = allDone;
1306	    break;
1307	}
1308    }
1309
1310    if (cx->status == encodeError) {
1311	return SECFailure;
1312    }
1313
1314    return SECSuccess;
1315}
1316
1317
1318void
1319SEC_ASN1EncoderFinish (SEC_ASN1EncoderContext *cx)
1320{
1321    /*
1322     * XXX anything else that needs to be finished?
1323     */
1324
1325    PORT_FreeArena (cx->our_pool, PR_FALSE);
1326}
1327
1328
1329SEC_ASN1EncoderContext *
1330SEC_ASN1EncoderStart (const void *src, const SecAsn1Template *theTemplate,
1331		      SEC_ASN1WriteProc output_proc, void *output_arg)
1332{
1333    PRArenaPool *our_pool;
1334    SEC_ASN1EncoderContext *cx;
1335
1336    our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
1337    if (our_pool == NULL)
1338	return NULL;
1339
1340    cx = (SEC_ASN1EncoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
1341    if (cx == NULL) {
1342	PORT_FreeArena (our_pool, PR_FALSE);
1343	return NULL;
1344    }
1345
1346    cx->our_pool = our_pool;
1347    cx->output_proc = output_proc;
1348    cx->output_arg = output_arg;
1349
1350    cx->status = keepGoing;
1351
1352    if (sec_asn1e_push_state(cx, theTemplate, src, PR_FALSE) == NULL
1353	|| sec_asn1e_init_state_based_on_template (cx->current) == NULL) {
1354	/*
1355	 * Trouble initializing (probably due to failed allocations)
1356	 * requires that we just give up.
1357	 */
1358	PORT_FreeArena (our_pool, PR_FALSE);
1359	return NULL;
1360    }
1361
1362    return cx;
1363}
1364
1365
1366/*
1367 * XXX Do we need a FilterProc, too?
1368 */
1369
1370
1371void
1372SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext *cx,
1373			      SEC_ASN1NotifyProc fn, void *arg)
1374{
1375    cx->notify_proc = fn;
1376    cx->notify_arg = arg;
1377}
1378
1379
1380void
1381SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext *cx)
1382{
1383    cx->notify_proc = NULL;
1384    cx->notify_arg = NULL;	/* not necessary; just being clean */
1385}
1386
1387
1388void
1389SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error)
1390{
1391    PORT_Assert(cx);
1392    PORT_SetError(error);
1393    cx->status = encodeError;
1394}
1395
1396
1397void
1398SEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext *cx)
1399{
1400    /* XXX is there a way to check that we are "between" fields here? */
1401
1402    cx->streaming = PR_TRUE;
1403}
1404
1405
1406void
1407SEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext *cx)
1408{
1409    /* XXX is there a way to check that we are "between" fields here? */
1410
1411    cx->streaming = PR_FALSE;
1412}
1413
1414
1415void
1416SEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext *cx)
1417{
1418    /*
1419     * XXX is there a way to check that we are "between" fields here?  this
1420     * needs to include a check for being in between groups of items in
1421     * a SET_OF or SEQUENCE_OF.
1422     */
1423    PORT_Assert (cx->streaming);
1424
1425    cx->from_buf = PR_TRUE;
1426}
1427
1428
1429void
1430SEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext *cx)
1431{
1432    /* we should actually be taking from buf *now* */
1433    PORT_Assert (cx->from_buf);
1434    if (! cx->from_buf)		/* if not, just do nothing */
1435	return;
1436
1437    cx->from_buf = PR_FALSE;
1438
1439    if (cx->status == needBytes) {
1440	cx->status = keepGoing;
1441	cx->current->place = afterContents;
1442    }
1443}
1444
1445
1446SECStatus
1447SEC_ASN1Encode (const void *src, const SecAsn1Template *theTemplate,
1448		SEC_ASN1WriteProc output_proc, void *output_arg)
1449{
1450    SEC_ASN1EncoderContext *ecx;
1451    SECStatus rv;
1452
1453    ecx = SEC_ASN1EncoderStart (src, theTemplate, output_proc, output_arg);
1454    if (ecx == NULL)
1455	return SECFailure;
1456
1457    rv = SEC_ASN1EncoderUpdate (ecx, NULL, 0);
1458
1459    SEC_ASN1EncoderFinish (ecx);
1460    return rv;
1461}
1462
1463
1464/*
1465 * XXX depth and data_kind are unused; is there a PC way to silence warnings?
1466 * (I mean "politically correct", not anything to do with intel/win platform)
1467 */
1468void
1469sec_asn1e_encode_item_count (void *arg, const char *buf, size_t len,
1470			     int depth, SEC_ASN1EncodingPart data_kind)
1471{
1472    size_t *count;
1473
1474    count = (unsigned long*)arg;
1475    PORT_Assert (count != NULL);
1476
1477    *count += len;
1478}
1479
1480
1481/* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
1482void
1483sec_asn1e_encode_item_store (void *arg, const char *buf, size_t len,
1484			     int depth, SEC_ASN1EncodingPart data_kind)
1485{
1486    SecAsn1Item *dest;
1487
1488    dest = (SecAsn1Item*)arg;
1489    PORT_Assert (dest != NULL);
1490
1491    PORT_Memcpy (dest->Data + dest->Length, buf, len);
1492    dest->Length += len;
1493}
1494
1495
1496/*
1497 * Allocate an entire SecAsn1Item, or just the data part of it, to hold
1498 * "len" bytes of stuff.  Allocate from the given pool, if specified,
1499 * otherwise just do a vanilla PORT_Alloc.
1500 *
1501 * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
1502 */
1503SecAsn1Item *
1504sec_asn1e_allocate_item (PRArenaPool *poolp, SecAsn1Item *dest, unsigned long len)
1505{
1506    if (poolp != NULL) {
1507	void *release;
1508
1509	release = PORT_ArenaMark (poolp);
1510	if (dest == NULL)
1511	    dest = (SecAsn1Item*)PORT_ArenaAlloc (poolp, sizeof(SecAsn1Item));
1512	if (dest != NULL) {
1513	    dest->Data = (unsigned char*)PORT_ArenaAlloc (poolp, len);
1514	    if (dest->Data == NULL) {
1515		dest = NULL;
1516	    }
1517	}
1518	if (dest == NULL) {
1519	    /* one or both allocations failed; release everything */
1520	    PORT_ArenaRelease (poolp, release);
1521	} else {
1522	    /* everything okay; unmark the arena */
1523	    PORT_ArenaUnmark (poolp, release);
1524	}
1525    } else {
1526	SecAsn1Item *indest;
1527
1528	indest = dest;
1529	if (dest == NULL)
1530	    dest = (SecAsn1Item*)PORT_Alloc (sizeof(SecAsn1Item));
1531	if (dest != NULL) {
1532		#ifndef	__APPLE__
1533	    dest->type = siBuffer;
1534		#endif
1535	    dest->Data = (unsigned char*)PORT_Alloc (len);
1536	    if (dest->Data == NULL) {
1537		if (indest == NULL)
1538		    PORT_Free (dest);
1539		dest = NULL;
1540	    }
1541	}
1542    }
1543
1544    return dest;
1545}
1546
1547
1548SecAsn1Item *
1549SEC_ASN1EncodeItem (PRArenaPool *poolp, SecAsn1Item *dest, const void *src,
1550		    const SecAsn1Template *theTemplate)
1551{
1552    unsigned long encoding_length;
1553    SECStatus rv;
1554
1555    PORT_Assert (dest == NULL || dest->Data == NULL);
1556
1557    encoding_length = 0;
1558    rv = SEC_ASN1Encode (src, theTemplate,
1559			 sec_asn1e_encode_item_count, &encoding_length);
1560    if (rv != SECSuccess)
1561	return NULL;
1562
1563    dest = sec_asn1e_allocate_item (poolp, dest, encoding_length);
1564    if (dest == NULL)
1565	return NULL;
1566
1567    /* XXX necessary?  This really just checks for a bug in the allocate fn */
1568    PORT_Assert (dest->Data != NULL);
1569    if (dest->Data == NULL)
1570	return NULL;
1571
1572    dest->Length = 0;
1573    (void) SEC_ASN1Encode (src, theTemplate, sec_asn1e_encode_item_store, dest);
1574
1575    PORT_Assert (encoding_length == dest->Length);
1576    return dest;
1577}
1578
1579
1580static SecAsn1Item *
1581sec_asn1e_integer(PRArenaPool *poolp, SecAsn1Item *dest, unsigned long value,
1582		  PRBool make_unsigned)
1583{
1584    unsigned long copy;
1585    unsigned char sign;
1586    int len = 0;
1587
1588    /*
1589     * Determine the length of the encoded value (minimum of 1).
1590     */
1591    copy = value;
1592    do {
1593	len++;
1594	sign = (unsigned char)(copy & 0x80);
1595	copy >>= 8;
1596    } while (copy);
1597
1598    /*
1599     * If this is an unsigned encoding, and the high bit of the last
1600     * byte we counted was set, we need to add one to the length so
1601     * we put a high-order zero byte in the encoding.
1602     */
1603    if (sign && make_unsigned)
1604	len++;
1605
1606    /*
1607     * Allocate the item (if necessary) and the data pointer within.
1608     */
1609    dest = sec_asn1e_allocate_item (poolp, dest, len);
1610    if (dest == NULL)
1611	return NULL;
1612
1613    /*
1614     * Store the value, byte by byte, in the item.
1615     */
1616    dest->Length = len;
1617    while (len) {
1618	dest->Data[--len] = (unsigned char)value;
1619	value >>= 8;
1620    }
1621    PORT_Assert (value == 0);
1622
1623    return dest;
1624}
1625
1626
1627SecAsn1Item *
1628SEC_ASN1EncodeInteger(PRArenaPool *poolp, SecAsn1Item *dest, long value)
1629{
1630    return sec_asn1e_integer (poolp, dest, (unsigned long) value, PR_FALSE);
1631}
1632
1633
1634extern SecAsn1Item *
1635SEC_ASN1EncodeUnsignedInteger(PRArenaPool *poolp,
1636			      SecAsn1Item *dest, unsigned long value)
1637{
1638    return sec_asn1e_integer (poolp, dest, value, PR_TRUE);
1639}
1640