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/
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.
12 * The Original Code is the Netscape security libraries.
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
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
35 * Support for ENcoding ASN.1 data based on BER/DER (Basic/Distinguished
38 * $Id: secasn1e.c,v 1.7 2004/05/13 15:29:13 dmitch Exp $
54 } sec_asn1e_parse_place
;
61 } sec_asn1e_parse_status
;
63 typedef struct sec_asn1e_state_struct
{
64 SEC_ASN1EncoderContext
*top
;
65 const SecAsn1Template
*theTemplate
;
68 struct sec_asn1e_state_struct
*parent
; /* aka prev */
69 struct sec_asn1e_state_struct
*child
; /* aka next */
71 sec_asn1e_parse_place place
; /* where we are in encoding process */
74 * XXX explain the next fields as clearly as possible...
76 unsigned char tag_modifiers
;
77 unsigned char tag_number
;
78 unsigned long underlying_kind
;
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 */
90 signedInt
/* signed alternate to SEC_ASN1_INTEGER */
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().
101 struct sec_EncoderContext_struct
{
102 PRArenaPool
*our_pool
; /* for our internal allocs */
104 sec_asn1e_state
*current
;
105 sec_asn1e_parse_status status
;
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 */
114 SEC_ASN1WriteProc output_proc
; /* pass encoded bytes to this */
115 void *output_arg
; /* argument to that function */
119 static sec_asn1e_state
*
120 sec_asn1e_push_state (SEC_ASN1EncoderContext
*cx
,
121 const SecAsn1Template
*theTemplate
,
122 const void *src
, PRBool new_depth
)
124 sec_asn1e_state
*state
, *new_state
;
128 new_state
= (sec_asn1e_state
*)PORT_ArenaZAlloc (cx
->our_pool
,
130 if (new_state
== NULL
) {
131 cx
->status
= encodeError
;
136 new_state
->parent
= state
;
137 new_state
->theTemplate
= theTemplate
;
138 new_state
->place
= notInUse
;
140 new_state
->src
= (char *)src
+ theTemplate
->offset
;
143 new_state
->depth
= state
->depth
;
146 state
->child
= new_state
;
149 cx
->current
= new_state
;
155 sec_asn1e_scrub_state (sec_asn1e_state
*state
)
158 * Some default "scrubbing".
159 * XXX right set of initializations?
161 state
->place
= beforeHeader
;
162 state
->indefinite
= PR_FALSE
;
167 sec_asn1e_notify_before (SEC_ASN1EncoderContext
*cx
, void *src
, int depth
)
169 if (cx
->notify_proc
== NULL
)
172 cx
->during_notify
= PR_TRUE
;
173 (* cx
->notify_proc
) (cx
->notify_arg
, PR_TRUE
, src
, depth
);
174 cx
->during_notify
= PR_FALSE
;
179 sec_asn1e_notify_after (SEC_ASN1EncoderContext
*cx
, void *src
, int depth
)
181 if (cx
->notify_proc
== NULL
)
184 cx
->during_notify
= PR_TRUE
;
185 (* cx
->notify_proc
) (cx
->notify_arg
, PR_FALSE
, src
, depth
);
186 cx
->during_notify
= PR_FALSE
;
190 static sec_asn1e_state
*
191 sec_asn1e_init_state_based_on_template (sec_asn1e_state
*state
)
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
;
198 PRBool signedInt
, dynamic
;
201 encode_kind
= state
->theTemplate
->kind
;
203 universal
= ((encode_kind
& SEC_ASN1_CLASS_MASK
) == SEC_ASN1_UNIVERSAL
)
204 ? PR_TRUE
: PR_FALSE
;
206 explicit = (encode_kind
& SEC_ASN1_EXPLICIT
) ? PR_TRUE
: PR_FALSE
;
207 encode_kind
&= ~SEC_ASN1_EXPLICIT
;
209 optional
= (encode_kind
& SEC_ASN1_OPTIONAL
) ? PR_TRUE
: PR_FALSE
;
210 encode_kind
&= ~SEC_ASN1_OPTIONAL
;
212 PORT_Assert (!(explicit && universal
)); /* bad templates */
214 may_stream
= (encode_kind
& SEC_ASN1_MAY_STREAM
) ? PR_TRUE
: PR_FALSE
;
215 encode_kind
&= ~SEC_ASN1_MAY_STREAM
;
217 ignore_stream
= (encode_kind
& SEC_ASN1_NO_STREAM
) ? PR_TRUE
: PR_FALSE
;
218 encode_kind
&= ~SEC_ASN1_NO_STREAM
;
221 signedInt
= (encode_kind
& SEC_ASN1_SIGNED_INT
) ? PR_TRUE
: PR_FALSE
;
222 encode_kind
&= ~SEC_ASN1_SIGNED_INT
;
226 dynamic
= (encode_kind
& SEC_ASN1_DYNAMIC
) ? PR_TRUE
: PR_FALSE
;
228 encode_kind
&= ~SEC_ASN1_DYNAMIC
;
230 if( encode_kind
& SEC_ASN1_CHOICE
) {
231 under_kind
= SEC_ASN1_CHOICE
;
234 if ((encode_kind
& (SEC_ASN1_POINTER
| SEC_ASN1_INLINE
)) || (!universal
236 const SecAsn1Template
*subt
;
239 PORT_Assert ((encode_kind
& (SEC_ASN1_ANY
| SEC_ASN1_SKIP
)) == 0);
241 sec_asn1e_scrub_state (state
);
243 if (encode_kind
& SEC_ASN1_POINTER
) {
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.
250 src
= *(void **)state
->src
;
251 state
->place
= afterPointer
;
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.
262 * XXX this is an error; need to figure out
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
;
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
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
;
282 state
->place
= afterImplicit
;
283 state
->optional
= optional
;
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
);
295 * This is a POINTER or INLINE; just init based on that
298 return sec_asn1e_init_state_based_on_template (state
);
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.).
310 under_kind
= state
->theTemplate
->kind
;
311 if (under_kind
& SEC_ASN1_MAY_STREAM
) {
313 may_stream
= PR_TRUE
;
314 under_kind
&= ~SEC_ASN1_MAY_STREAM
;
317 under_kind
= encode_kind
;
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
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);
332 if (encode_kind
& SEC_ASN1_ANY
) {
333 PORT_Assert (encode_kind
== under_kind
);
338 tag_modifiers
= (unsigned char)encode_kind
& SEC_ASN1_TAG_MASK
&
339 ~SEC_ASN1_TAGNUM_MASK
;
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.
349 * Apple change: if this is a DYNAMIC template, use the tag number
350 * from the subtemplate's kind
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
);
358 #endif /* __APPLE__ */
359 tag_number
= encode_kind
& SEC_ASN1_TAGNUM_MASK
;
361 is_string
= PR_FALSE
;
362 switch (under_kind
& SEC_ASN1_TAGNUM_MASK
) {
365 * XXX A plain old SET (as opposed to a SET OF) is not implemented.
366 * If it ever is, remove this assert...
368 PORT_Assert ((under_kind
& SEC_ASN1_GROUP
) != 0);
370 case SEC_ASN1_SEQUENCE
:
371 tag_modifiers
|= SEC_ASN1_CONSTRUCTED
;
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
:
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.
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
;
402 state
->signedInt
= signedInt
;
405 sec_asn1e_scrub_state (state
);
412 sec_asn1e_write_part (sec_asn1e_state
*state
,
413 const char *buf
, size_t len
,
414 SEC_ASN1EncodingPart part
)
416 SEC_ASN1EncoderContext
*cx
;
419 (* cx
->output_proc
) (cx
->output_arg
, buf
, len
, state
->depth
, part
);
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.
429 sec_asn1e_write_identifier_bytes (sec_asn1e_state
*state
, unsigned char value
)
434 sec_asn1e_write_part (state
, &byte
, 1, SEC_ASN1_Identifier
);
438 SEC_ASN1EncodeLength(unsigned char *buf
,unsigned long value
) {
441 lenlen
= SEC_ASN1LengthLength (value
);
453 PORT_Assert (value
== 0);
459 sec_asn1e_write_length_bytes (sec_asn1e_state
*state
, unsigned long value
,
463 unsigned char buf
[sizeof(unsigned long) + 1];
466 PORT_Assert (value
== 0);
470 lenlen
= SEC_ASN1EncodeLength(buf
,value
);
473 sec_asn1e_write_part (state
, (char *) buf
, lenlen
, SEC_ASN1_Length
);
478 sec_asn1e_write_contents_bytes (sec_asn1e_state
*state
,
479 const char *buf
, unsigned long len
)
481 sec_asn1e_write_part (state
, buf
, len
, SEC_ASN1_Contents
);
486 sec_asn1e_write_end_of_contents_bytes (sec_asn1e_state
*state
)
488 const char eoc
[2] = {0, 0};
490 sec_asn1e_write_part (state
, eoc
, 2, SEC_ASN1_EndOfContents
);
494 sec_asn1e_which_choice
497 const SecAsn1Template
*theTemplate
501 unsigned int which
= *(unsigned int *)src
;
503 for( rv
= 1, theTemplate
++; theTemplate
->kind
!= 0; rv
++, theTemplate
++ ) {
504 if( which
== theTemplate
->size
) {
513 sec_asn1e_contents_length (const SecAsn1Template
*theTemplate
, void *src
,
514 PRBool ignoresubstream
, PRBool
*noheaderp
)
516 unsigned long encode_kind
, underlying_kind
;
517 PRBool
explicit, optional
, universal
, may_stream
;
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
538 encode_kind
= theTemplate
->kind
;
540 universal
= ((encode_kind
& SEC_ASN1_CLASS_MASK
) == SEC_ASN1_UNIVERSAL
)
541 ? PR_TRUE
: PR_FALSE
;
543 explicit = (encode_kind
& SEC_ASN1_EXPLICIT
) ? PR_TRUE
: PR_FALSE
;
544 encode_kind
&= ~SEC_ASN1_EXPLICIT
;
546 optional
= (encode_kind
& SEC_ASN1_OPTIONAL
) ? PR_TRUE
: PR_FALSE
;
547 encode_kind
&= ~SEC_ASN1_OPTIONAL
;
549 PORT_Assert (!(explicit && universal
)); /* bad templates */
551 may_stream
= (encode_kind
& SEC_ASN1_MAY_STREAM
) ? PR_TRUE
: PR_FALSE
;
552 encode_kind
&= ~SEC_ASN1_MAY_STREAM
;
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
;
558 if( encode_kind
& SEC_ASN1_CHOICE
) {
560 int indx
= sec_asn1e_which_choice(src
, theTemplate
);
562 /* XXX set an error? "choice not found" */
563 /* state->top->status = encodeError; */
567 src2
= (void *)((char *)src
- theTemplate
->offset
+ theTemplate
[indx
].offset
);
569 return sec_asn1e_contents_length(&theTemplate
[indx
], src2
,
570 PR_FALSE
, noheaderp
);
573 if ((encode_kind
& (SEC_ASN1_POINTER
| SEC_ASN1_INLINE
)) || !universal
) {
575 /* XXX any bits we want to disallow (PORT_Assert against) here? */
577 theTemplate
= SEC_ASN1GetSubtemplate (theTemplate
, src
, PR_TRUE
,
578 NULL
/* __APPLE__ */);
580 if (encode_kind
& SEC_ASN1_POINTER
) {
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.
593 *noheaderp
= PR_TRUE
;
595 *noheaderp
= PR_FALSE
;
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
);
603 src
= (char *)src
+ theTemplate
->offset
;
606 len
= sec_asn1e_contents_length (theTemplate
, src
, PR_FALSE
,
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
;
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.
619 len
+= 1 + SEC_ASN1LengthLength (len
);
624 underlying_kind
= theTemplate
->kind
;
625 underlying_kind
&= ~SEC_ASN1_MAY_STREAM
;
626 /* XXX Should we recurse here? */
628 underlying_kind
= encode_kind
;
632 signedInt
= (underlying_kind
& SEC_ASN1_SIGNED_INT
) ?
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
;
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);
650 if( underlying_kind
& SEC_ASN1_CHOICE
) {
652 int indx
= sec_asn1e_which_choice(src
, theTemplate
);
654 /* XXX set an error? "choice not found" */
655 /* state->top->status = encodeError; */
659 src2
= (void *)((char *)src
- theTemplate
->offset
+ theTemplate
[indx
].offset
);
660 len
= sec_asn1e_contents_length(&theTemplate
[indx
], src2
, PR_FALSE
,
664 switch (underlying_kind
) {
665 case SEC_ASN1_SEQUENCE_OF
:
666 case SEC_ASN1_SET_OF
:
668 const SecAsn1Template
*tmpt
;
670 unsigned long sub_len
;
675 group
= *(void ***)src
;
679 tmpt
= SEC_ASN1GetSubtemplate (theTemplate
, src
, PR_TRUE
,
680 NULL
/* __APPLE__ */);
682 for (; *group
!= NULL
; group
++) {
683 sub_src
= (char *)(*group
) + tmpt
->offset
;
684 sub_len
= sec_asn1e_contents_length (tmpt
, sub_src
, PR_FALSE
,
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.
692 len
+= 1 + SEC_ASN1LengthLength (sub_len
);
697 case SEC_ASN1_SEQUENCE
:
700 const SecAsn1Template
*tmpt
;
702 unsigned long sub_len
;
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
,
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.
715 len
+= 1 + SEC_ASN1LengthLength (sub_len
);
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 */
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.
734 unsigned char *buf
= ((SecAsn1Item
*)src
)->Data
;
736 SecAsn1ItemType integerType
= ((SecAsn1Item
*)src
)->type
;
738 len
= ((SecAsn1Item
*)src
)->Length
;
742 if (*buf
& 0x80 && !signedInt
) {
744 if (*buf
& 0x80 && integerType
== siUnsignedInteger
) {
746 len
++; /* leading zero needed to make number signed */
748 break; /* reached beginning of number */
751 break; /* the number 0 */
754 break; /* leading zero already present */
756 /* extraneous leading zero, keep going */
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 */
770 if ((len
== 0 && optional
) || underlying_kind
== SEC_ASN1_ANY
)
771 *noheaderp
= PR_TRUE
;
773 *noheaderp
= PR_FALSE
;
780 sec_asn1e_write_header (sec_asn1e_state
*state
)
782 unsigned long contents_length
;
783 unsigned char tag_number
, tag_modifiers
;
786 PORT_Assert (state
->place
== beforeHeader
);
788 tag_number
= state
->tag_number
;
789 tag_modifiers
= state
->tag_modifiers
;
791 if (state
->underlying_kind
== SEC_ASN1_ANY
) {
792 state
->place
= duringContents
;
796 if( state
->underlying_kind
& SEC_ASN1_CHOICE
) {
797 int indx
= sec_asn1e_which_choice(state
->src
, state
->theTemplate
);
799 /* XXX set an error? "choice not found" */
800 state
->top
->status
= encodeError
;
804 state
->place
= afterChoice
;
805 state
= sec_asn1e_push_state(state
->top
, &state
->theTemplate
[indx
],
806 (char *)state
->src
- state
->theTemplate
->offset
,
809 if( (sec_asn1e_state
*)NULL
!= state
) {
811 * Do the "before" field notification.
813 sec_asn1e_notify_before (state
->top
, state
->src
, state
->depth
);
814 state
= sec_asn1e_init_state_based_on_template (state
);
821 * We are doing a definite-length encoding. First we have to
822 * walk the data structure to calculate the entire contents length.
824 contents_length
= sec_asn1e_contents_length (state
->theTemplate
,
826 state
->ignore_stream
,
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.
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
;
845 if (state
->top
->streaming
&& state
->may_stream
846 && (state
->top
->from_buf
|| !state
->is_string
)) {
848 * We need to put out an indefinite-length encoding.
850 state
->indefinite
= PR_TRUE
;
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).
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
;
864 sec_asn1e_write_identifier_bytes (state
, (unsigned char)(tag_number
| tag_modifiers
));
865 sec_asn1e_write_length_bytes (state
, contents_length
, state
->indefinite
);
867 if (contents_length
== 0 && !state
->indefinite
) {
869 * If no real contents to encode, then we are done with this field.
871 state
->place
= afterContents
;
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.
879 if (state
->explicit) {
880 state
->place
= afterContents
;
881 state
= sec_asn1e_push_state (state
->top
,
882 SEC_ASN1GetSubtemplate(state
->theTemplate
,
885 NULL
/* __APPLE__ */),
886 state
->src
, PR_TRUE
);
888 state
= sec_asn1e_init_state_based_on_template (state
);
892 switch (state
->underlying_kind
) {
893 case SEC_ASN1_SET_OF
:
894 case SEC_ASN1_SEQUENCE_OF
:
896 * We need to push a child to handle each member.
900 const SecAsn1Template
*subt
;
902 group
= *(void ***)state
->src
;
903 if (group
== NULL
|| *group
== NULL
) {
905 * Group is empty; we are done.
907 state
->place
= afterContents
;
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
);
915 state
= sec_asn1e_init_state_based_on_template (state
);
919 case SEC_ASN1_SEQUENCE
:
922 * We need to push a child to handle the individual fields.
924 state
->place
= duringSequence
;
925 state
= sec_asn1e_push_state (state
->top
, state
->theTemplate
+ 1,
926 state
->src
, PR_TRUE
);
929 * Do the "before" field notification.
931 sec_asn1e_notify_before (state
->top
, state
->src
, state
->depth
);
932 state
= sec_asn1e_init_state_based_on_template (state
);
938 * I think we do not need to do anything else.
941 state
->place
= duringContents
;
948 sec_asn1e_write_contents (sec_asn1e_state
*state
,
949 const char *buf
, unsigned long len
)
951 PORT_Assert (state
->place
== duringContents
);
953 if (state
->top
->from_buf
) {
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.
959 if (buf
== NULL
|| len
== 0) {
960 state
->top
->status
= needBytes
;
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).
971 PORT_Assert (state
->is_string
); /* includes ANY */
972 if (state
->underlying_kind
!= SEC_ASN1_ANY
) {
973 unsigned char identifier
;
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.
981 identifier
= (unsigned char)state
->underlying_kind
& SEC_ASN1_TAG_MASK
;
983 * The underlying kind should just be a simple string; there
984 * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
986 PORT_Assert ((identifier
& SEC_ASN1_TAGNUM_MASK
) == identifier
);
988 * Write out the tag and length for the substring.
990 sec_asn1e_write_identifier_bytes (state
, identifier
);
991 if (state
->underlying_kind
== SEC_ASN1_BIT_STRING
) {
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).
1005 sec_asn1e_write_length_bytes (state
, len
+ 1, PR_FALSE
);
1007 sec_asn1e_write_contents_bytes (state
, &byte
, 1);
1009 sec_asn1e_write_length_bytes (state
, len
, PR_FALSE
);
1012 sec_asn1e_write_contents_bytes (state
, buf
, len
);
1013 state
->top
->status
= needBytes
;
1015 switch (state
->underlying_kind
) {
1017 case SEC_ASN1_SEQUENCE
:
1021 case SEC_ASN1_BIT_STRING
:
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
,
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
;
1041 cx
->status
= encodeError
;
1044 /* otherwise, fall through to write the content */
1045 goto process_string
;
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
;
1053 cx
->status
= encodeError
;
1056 /* otherwise, fall through to write the content */
1057 goto process_string
;
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.
1065 unsigned char *intbuf
;
1067 PRBool signedInt
= state
->signedInt
;
1069 SECItemType integerType
= ((SecAsn1Item
*)state
->src
)->type
;
1071 blen
= ((SecAsn1Item
*)state
->src
)->Length
;
1072 intbuf
= ((SecAsn1Item
*)state
->src
)->Data
;
1075 if (*intbuf
& 0x80 && !signedInt
) {
1077 if (*intbuf
& 0x80 && integerType
== siUnsignedInteger
) {
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
);
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.
1095 (intbuf
[1] & 0x80 && signedInt
) )
1097 (intbuf
[1] & 0x80 && integerType
!= siUnsignedInteger
) )
1100 sec_asn1e_write_contents_bytes(state
,
1101 (char *)intbuf
, blen
);
1104 /* byte is 0, continue */
1109 /* done with this content */
1117 item
= (SecAsn1Item
*)state
->src
;
1118 sec_asn1e_write_contents_bytes (state
, (char *) item
->Data
,
1123 state
->place
= afterContents
;
1129 * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
1132 sec_asn1e_next_in_group (sec_asn1e_state
*state
)
1134 sec_asn1e_state
*child
;
1138 PORT_Assert (state
->place
== duringGroup
);
1139 PORT_Assert (state
->child
!= NULL
);
1141 child
= state
->child
;
1143 group
= *(void ***)state
->src
;
1146 * Find placement of current item.
1148 member
= (char *)(state
->child
->src
) - child
->theTemplate
->offset
;
1149 while (*group
!= member
)
1153 * Move forward to next item.
1156 if (*group
== NULL
) {
1158 * That was our last one; we are done now.
1160 child
->place
= notInUse
;
1161 state
->place
= afterContents
;
1164 child
->src
= (char *)(*group
) + child
->theTemplate
->offset
;
1169 sec_asn1e_scrub_state (child
);
1170 state
->top
->current
= child
;
1175 * We are moving along through a sequence; move forward by one,
1176 * (detecting end-of-sequence when it happens).
1179 sec_asn1e_next_in_sequence (sec_asn1e_state
*state
)
1181 sec_asn1e_state
*child
;
1183 PORT_Assert (state
->place
== duringSequence
);
1184 PORT_Assert (state
->child
!= NULL
);
1186 child
= state
->child
;
1189 * Do the "after" field notification.
1191 sec_asn1e_notify_after (state
->top
, child
->src
, child
->depth
);
1196 child
->theTemplate
++;
1197 if (child
->theTemplate
->kind
== 0) {
1199 * We are done with this sequence.
1201 child
->place
= notInUse
;
1202 state
->place
= afterContents
;
1207 * Reset state and push.
1210 child
->src
= (char *)state
->src
+ child
->theTemplate
->offset
;
1213 * Do the "before" field notification.
1215 sec_asn1e_notify_before (state
->top
, child
->src
, child
->depth
);
1217 state
->top
->current
= child
;
1218 (void) sec_asn1e_init_state_based_on_template (child
);
1223 sec_asn1e_after_contents (sec_asn1e_state
*state
)
1225 PORT_Assert (state
->place
== afterContents
);
1227 if (state
->indefinite
)
1228 sec_asn1e_write_end_of_contents_bytes (state
);
1231 * Just make my parent be the current state. It will then clean
1232 * up after me and free me (or reuse me).
1234 state
->top
->current
= state
->parent
;
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.
1250 SEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext
*cx
,
1251 const char *buf
, unsigned long len
)
1253 sec_asn1e_state
*state
;
1255 if (cx
->status
== needBytes
) {
1256 PORT_Assert (buf
!= NULL
&& len
!= 0);
1257 cx
->status
= keepGoing
;
1260 while (cx
->status
== keepGoing
) {
1261 state
= cx
->current
;
1262 switch (state
->place
) {
1264 sec_asn1e_write_header (state
);
1266 case duringContents
:
1267 sec_asn1e_write_contents (state
, buf
, len
);
1270 sec_asn1e_next_in_group (state
);
1272 case duringSequence
:
1273 sec_asn1e_next_in_sequence (state
);
1276 sec_asn1e_after_contents (state
);
1283 * These states are more documentation than anything.
1284 * They just need to force a pop.
1286 PORT_Assert (!state
->indefinite
);
1287 state
->place
= afterContents
;
1291 /* This is not an error, but rather a plain old BUG! */
1293 cx
->status
= encodeError
;
1297 if (cx
->status
== encodeError
)
1300 /* It might have changed, so we have to update our local copy. */
1301 state
= cx
->current
;
1303 /* If it is NULL, we have popped all the way to the top. */
1304 if (state
== NULL
) {
1305 cx
->status
= allDone
;
1310 if (cx
->status
== encodeError
) {
1319 SEC_ASN1EncoderFinish (SEC_ASN1EncoderContext
*cx
)
1322 * XXX anything else that needs to be finished?
1325 PORT_FreeArena (cx
->our_pool
, PR_FALSE
);
1329 SEC_ASN1EncoderContext
*
1330 SEC_ASN1EncoderStart (const void *src
, const SecAsn1Template
*theTemplate
,
1331 SEC_ASN1WriteProc output_proc
, void *output_arg
)
1333 PRArenaPool
*our_pool
;
1334 SEC_ASN1EncoderContext
*cx
;
1336 our_pool
= PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE
);
1337 if (our_pool
== NULL
)
1340 cx
= (SEC_ASN1EncoderContext
*)PORT_ArenaZAlloc (our_pool
, sizeof(*cx
));
1342 PORT_FreeArena (our_pool
, PR_FALSE
);
1346 cx
->our_pool
= our_pool
;
1347 cx
->output_proc
= output_proc
;
1348 cx
->output_arg
= output_arg
;
1350 cx
->status
= keepGoing
;
1352 if (sec_asn1e_push_state(cx
, theTemplate
, src
, PR_FALSE
) == NULL
1353 || sec_asn1e_init_state_based_on_template (cx
->current
) == NULL
) {
1355 * Trouble initializing (probably due to failed allocations)
1356 * requires that we just give up.
1358 PORT_FreeArena (our_pool
, PR_FALSE
);
1367 * XXX Do we need a FilterProc, too?
1372 SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext
*cx
,
1373 SEC_ASN1NotifyProc fn
, void *arg
)
1375 cx
->notify_proc
= fn
;
1376 cx
->notify_arg
= arg
;
1381 SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext
*cx
)
1383 cx
->notify_proc
= NULL
;
1384 cx
->notify_arg
= NULL
; /* not necessary; just being clean */
1389 SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext
*cx
, int error
)
1392 PORT_SetError(error
);
1393 cx
->status
= encodeError
;
1398 SEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext
*cx
)
1400 /* XXX is there a way to check that we are "between" fields here? */
1402 cx
->streaming
= PR_TRUE
;
1407 SEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext
*cx
)
1409 /* XXX is there a way to check that we are "between" fields here? */
1411 cx
->streaming
= PR_FALSE
;
1416 SEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext
*cx
)
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.
1423 PORT_Assert (cx
->streaming
);
1425 cx
->from_buf
= PR_TRUE
;
1430 SEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext
*cx
)
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 */
1437 cx
->from_buf
= PR_FALSE
;
1439 if (cx
->status
== needBytes
) {
1440 cx
->status
= keepGoing
;
1441 cx
->current
->place
= afterContents
;
1447 SEC_ASN1Encode (const void *src
, const SecAsn1Template
*theTemplate
,
1448 SEC_ASN1WriteProc output_proc
, void *output_arg
)
1450 SEC_ASN1EncoderContext
*ecx
;
1453 ecx
= SEC_ASN1EncoderStart (src
, theTemplate
, output_proc
, output_arg
);
1457 rv
= SEC_ASN1EncoderUpdate (ecx
, NULL
, 0);
1459 SEC_ASN1EncoderFinish (ecx
);
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)
1469 sec_asn1e_encode_item_count (void *arg
, const char *buf
, size_t len
,
1470 int depth
, SEC_ASN1EncodingPart data_kind
)
1474 count
= (unsigned long*)arg
;
1475 PORT_Assert (count
!= NULL
);
1481 /* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
1483 sec_asn1e_encode_item_store (void *arg
, const char *buf
, size_t len
,
1484 int depth
, SEC_ASN1EncodingPart data_kind
)
1488 dest
= (SecAsn1Item
*)arg
;
1489 PORT_Assert (dest
!= NULL
);
1491 PORT_Memcpy (dest
->Data
+ dest
->Length
, buf
, len
);
1492 dest
->Length
+= len
;
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.
1501 * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
1504 sec_asn1e_allocate_item (PRArenaPool
*poolp
, SecAsn1Item
*dest
, unsigned long len
)
1506 if (poolp
!= NULL
) {
1509 release
= PORT_ArenaMark (poolp
);
1511 dest
= (SecAsn1Item
*)PORT_ArenaAlloc (poolp
, sizeof(SecAsn1Item
));
1513 dest
->Data
= (unsigned char*)PORT_ArenaAlloc (poolp
, len
);
1514 if (dest
->Data
== NULL
) {
1519 /* one or both allocations failed; release everything */
1520 PORT_ArenaRelease (poolp
, release
);
1522 /* everything okay; unmark the arena */
1523 PORT_ArenaUnmark (poolp
, release
);
1526 SecAsn1Item
*indest
;
1530 dest
= (SecAsn1Item
*)PORT_Alloc (sizeof(SecAsn1Item
));
1533 dest
->type
= siBuffer
;
1535 dest
->Data
= (unsigned char*)PORT_Alloc (len
);
1536 if (dest
->Data
== NULL
) {
1549 SEC_ASN1EncodeItem (PRArenaPool
*poolp
, SecAsn1Item
*dest
, const void *src
,
1550 const SecAsn1Template
*theTemplate
)
1552 unsigned long encoding_length
;
1555 PORT_Assert (dest
== NULL
|| dest
->Data
== NULL
);
1557 encoding_length
= 0;
1558 rv
= SEC_ASN1Encode (src
, theTemplate
,
1559 sec_asn1e_encode_item_count
, &encoding_length
);
1560 if (rv
!= SECSuccess
)
1563 dest
= sec_asn1e_allocate_item (poolp
, dest
, encoding_length
);
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
)
1573 (void) SEC_ASN1Encode (src
, theTemplate
, sec_asn1e_encode_item_store
, dest
);
1575 PORT_Assert (encoding_length
== dest
->Length
);
1580 static SecAsn1Item
*
1581 sec_asn1e_integer(PRArenaPool
*poolp
, SecAsn1Item
*dest
, unsigned long value
,
1582 PRBool make_unsigned
)
1589 * Determine the length of the encoded value (minimum of 1).
1594 sign
= (unsigned char)(copy
& 0x80);
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.
1603 if (sign
&& make_unsigned
)
1607 * Allocate the item (if necessary) and the data pointer within.
1609 dest
= sec_asn1e_allocate_item (poolp
, dest
, len
);
1614 * Store the value, byte by byte, in the item.
1618 dest
->Data
[--len
] = (unsigned char)value
;
1621 PORT_Assert (value
== 0);
1628 SEC_ASN1EncodeInteger(PRArenaPool
*poolp
, SecAsn1Item
*dest
, long value
)
1630 return sec_asn1e_integer (poolp
, dest
, (unsigned long) value
, PR_FALSE
);
1634 extern SecAsn1Item
*
1635 SEC_ASN1EncodeUnsignedInteger(PRArenaPool
*poolp
,
1636 SecAsn1Item
*dest
, unsigned long value
)
1638 return sec_asn1e_integer (poolp
, dest
, value
, PR_TRUE
);