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
);
823 * We are doing a definite-length encoding. First we have to
824 * walk the data structure to calculate the entire contents length.
826 contents_length
= sec_asn1e_contents_length (state
->theTemplate
,
828 state
->ignore_stream
,
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.
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
;
847 if (state
->top
->streaming
&& state
->may_stream
848 && (state
->top
->from_buf
|| !state
->is_string
)) {
850 * We need to put out an indefinite-length encoding.
852 state
->indefinite
= PR_TRUE
;
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).
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
;
866 sec_asn1e_write_identifier_bytes (state
, (unsigned char)(tag_number
| tag_modifiers
));
867 sec_asn1e_write_length_bytes (state
, contents_length
, state
->indefinite
);
869 if (contents_length
== 0 && !state
->indefinite
) {
871 * If no real contents to encode, then we are done with this field.
873 state
->place
= afterContents
;
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.
881 if (state
->explicit) {
882 state
->place
= afterContents
;
883 state
= sec_asn1e_push_state (state
->top
,
884 SEC_ASN1GetSubtemplate(state
->theTemplate
,
887 NULL
/* __APPLE__ */),
888 state
->src
, PR_TRUE
);
890 state
= sec_asn1e_init_state_based_on_template (state
);
897 switch (state
->underlying_kind
) {
898 case SEC_ASN1_SET_OF
:
899 case SEC_ASN1_SEQUENCE_OF
:
901 * We need to push a child to handle each member.
905 const SecAsn1Template
*subt
;
907 group
= *(void ***)state
->src
;
908 if (group
== NULL
|| *group
== NULL
) {
910 * Group is empty; we are done.
912 state
->place
= afterContents
;
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
);
920 state
= sec_asn1e_init_state_based_on_template (state
);
924 case SEC_ASN1_SEQUENCE
:
927 * We need to push a child to handle the individual fields.
929 state
->place
= duringSequence
;
930 state
= sec_asn1e_push_state (state
->top
, state
->theTemplate
+ 1,
931 state
->src
, PR_TRUE
);
934 * Do the "before" field notification.
936 sec_asn1e_notify_before (state
->top
, state
->src
, state
->depth
);
937 state
= sec_asn1e_init_state_based_on_template (state
);
943 * I think we do not need to do anything else.
946 state
->place
= duringContents
;
955 sec_asn1e_write_contents (sec_asn1e_state
*state
,
956 const char *buf
, unsigned long len
)
958 PORT_Assert (state
->place
== duringContents
);
960 if (state
->top
->from_buf
) {
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.
966 if (buf
== NULL
|| len
== 0) {
967 state
->top
->status
= needBytes
;
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).
978 PORT_Assert (state
->is_string
); /* includes ANY */
979 if (state
->underlying_kind
!= SEC_ASN1_ANY
) {
980 unsigned char identifier
;
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.
988 identifier
= (unsigned char)state
->underlying_kind
& SEC_ASN1_TAG_MASK
;
990 * The underlying kind should just be a simple string; there
991 * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
993 PORT_Assert ((identifier
& SEC_ASN1_TAGNUM_MASK
) == identifier
);
995 * Write out the tag and length for the substring.
997 sec_asn1e_write_identifier_bytes (state
, identifier
);
998 if (state
->underlying_kind
== SEC_ASN1_BIT_STRING
) {
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).
1012 sec_asn1e_write_length_bytes (state
, len
+ 1, PR_FALSE
);
1014 sec_asn1e_write_contents_bytes (state
, &byte
, 1);
1016 sec_asn1e_write_length_bytes (state
, len
, PR_FALSE
);
1019 sec_asn1e_write_contents_bytes (state
, buf
, len
);
1020 state
->top
->status
= needBytes
;
1022 switch (state
->underlying_kind
) {
1024 case SEC_ASN1_SEQUENCE
:
1028 case SEC_ASN1_BIT_STRING
:
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
,
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
;
1048 cx
->status
= encodeError
;
1051 /* otherwise, fall through to write the content */
1052 goto process_string
;
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
;
1060 cx
->status
= encodeError
;
1063 /* otherwise, fall through to write the content */
1064 goto process_string
;
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.
1072 unsigned char *intbuf
;
1074 PRBool signedInt
= state
->signedInt
;
1076 SECItemType integerType
= ((SecAsn1Item
*)state
->src
)->type
;
1078 blen
= ((SecAsn1Item
*)state
->src
)->Length
;
1079 intbuf
= ((SecAsn1Item
*)state
->src
)->Data
;
1082 if (*intbuf
& 0x80 && !signedInt
) {
1084 if (*intbuf
& 0x80 && integerType
== siUnsignedInteger
) {
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
);
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.
1102 (intbuf
[1] & 0x80 && signedInt
) )
1104 (intbuf
[1] & 0x80 && integerType
!= siUnsignedInteger
) )
1107 sec_asn1e_write_contents_bytes(state
,
1108 (char *)intbuf
, blen
);
1111 /* byte is 0, continue */
1116 /* done with this content */
1124 item
= (SecAsn1Item
*)state
->src
;
1125 sec_asn1e_write_contents_bytes (state
, (char *) item
->Data
,
1130 state
->place
= afterContents
;
1136 * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
1139 sec_asn1e_next_in_group (sec_asn1e_state
*state
)
1141 sec_asn1e_state
*child
;
1145 PORT_Assert (state
->place
== duringGroup
);
1146 PORT_Assert (state
->child
!= NULL
);
1148 child
= state
->child
;
1150 group
= *(void ***)state
->src
;
1153 * Find placement of current item.
1155 member
= (char *)(state
->child
->src
) - child
->theTemplate
->offset
;
1156 while (*group
!= member
)
1160 * Move forward to next item.
1163 if (*group
== NULL
) {
1165 * That was our last one; we are done now.
1167 child
->place
= notInUse
;
1168 state
->place
= afterContents
;
1171 child
->src
= (char *)(*group
) + child
->theTemplate
->offset
;
1176 sec_asn1e_scrub_state (child
);
1177 state
->top
->current
= child
;
1182 * We are moving along through a sequence; move forward by one,
1183 * (detecting end-of-sequence when it happens).
1186 sec_asn1e_next_in_sequence (sec_asn1e_state
*state
)
1188 sec_asn1e_state
*child
;
1190 PORT_Assert (state
->place
== duringSequence
);
1191 PORT_Assert (state
->child
!= NULL
);
1193 child
= state
->child
;
1196 * Do the "after" field notification.
1198 sec_asn1e_notify_after (state
->top
, child
->src
, child
->depth
);
1203 child
->theTemplate
++;
1204 if (child
->theTemplate
->kind
== 0) {
1206 * We are done with this sequence.
1208 child
->place
= notInUse
;
1209 state
->place
= afterContents
;
1214 * Reset state and push.
1217 child
->src
= (char *)state
->src
+ child
->theTemplate
->offset
;
1220 * Do the "before" field notification.
1222 sec_asn1e_notify_before (state
->top
, child
->src
, child
->depth
);
1224 state
->top
->current
= child
;
1225 (void) sec_asn1e_init_state_based_on_template (child
);
1230 sec_asn1e_after_contents (sec_asn1e_state
*state
)
1232 PORT_Assert (state
->place
== afterContents
);
1234 if (state
->indefinite
)
1235 sec_asn1e_write_end_of_contents_bytes (state
);
1238 * Just make my parent be the current state. It will then clean
1239 * up after me and free me (or reuse me).
1241 state
->top
->current
= state
->parent
;
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.
1257 SEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext
*cx
,
1258 const char *buf
, unsigned long len
)
1260 sec_asn1e_state
*state
;
1262 if (cx
->status
== needBytes
) {
1263 PORT_Assert (buf
!= NULL
&& len
!= 0);
1264 cx
->status
= keepGoing
;
1267 while (cx
->status
== keepGoing
) {
1268 state
= cx
->current
;
1269 switch (state
->place
) {
1271 sec_asn1e_write_header (state
);
1273 case duringContents
:
1274 sec_asn1e_write_contents (state
, buf
, len
);
1277 sec_asn1e_next_in_group (state
);
1279 case duringSequence
:
1280 sec_asn1e_next_in_sequence (state
);
1283 sec_asn1e_after_contents (state
);
1290 * These states are more documentation than anything.
1291 * They just need to force a pop.
1293 PORT_Assert (!state
->indefinite
);
1294 state
->place
= afterContents
;
1298 /* This is not an error, but rather a plain old BUG! */
1300 cx
->status
= encodeError
;
1304 if (cx
->status
== encodeError
)
1307 /* It might have changed, so we have to update our local copy. */
1308 state
= cx
->current
;
1310 /* If it is NULL, we have popped all the way to the top. */
1311 if (state
== NULL
) {
1312 cx
->status
= allDone
;
1317 if (cx
->status
== encodeError
) {
1326 SEC_ASN1EncoderFinish (SEC_ASN1EncoderContext
*cx
)
1329 * XXX anything else that needs to be finished?
1332 PORT_FreeArena (cx
->our_pool
, PR_FALSE
);
1336 SEC_ASN1EncoderContext
*
1337 SEC_ASN1EncoderStart (const void *src
, const SecAsn1Template
*theTemplate
,
1338 SEC_ASN1WriteProc output_proc
, void *output_arg
)
1340 PRArenaPool
*our_pool
;
1341 SEC_ASN1EncoderContext
*cx
;
1343 our_pool
= PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE
);
1344 if (our_pool
== NULL
)
1347 cx
= (SEC_ASN1EncoderContext
*)PORT_ArenaZAlloc (our_pool
, sizeof(*cx
));
1349 PORT_FreeArena (our_pool
, PR_FALSE
);
1353 cx
->our_pool
= our_pool
;
1354 cx
->output_proc
= output_proc
;
1355 cx
->output_arg
= output_arg
;
1357 cx
->status
= keepGoing
;
1359 if (sec_asn1e_push_state(cx
, theTemplate
, src
, PR_FALSE
) == NULL
1360 || sec_asn1e_init_state_based_on_template (cx
->current
) == NULL
) {
1362 * Trouble initializing (probably due to failed allocations)
1363 * requires that we just give up.
1365 PORT_FreeArena (our_pool
, PR_FALSE
);
1374 * XXX Do we need a FilterProc, too?
1379 SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext
*cx
,
1380 SEC_ASN1NotifyProc fn
, void *arg
)
1382 cx
->notify_proc
= fn
;
1383 cx
->notify_arg
= arg
;
1388 SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext
*cx
)
1390 cx
->notify_proc
= NULL
;
1391 cx
->notify_arg
= NULL
; /* not necessary; just being clean */
1396 SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext
*cx
, int error
)
1399 PORT_SetError(error
);
1400 cx
->status
= encodeError
;
1405 SEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext
*cx
)
1407 /* XXX is there a way to check that we are "between" fields here? */
1409 cx
->streaming
= PR_TRUE
;
1414 SEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext
*cx
)
1416 /* XXX is there a way to check that we are "between" fields here? */
1418 cx
->streaming
= PR_FALSE
;
1423 SEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext
*cx
)
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.
1430 PORT_Assert (cx
->streaming
);
1432 cx
->from_buf
= PR_TRUE
;
1437 SEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext
*cx
)
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 */
1444 cx
->from_buf
= PR_FALSE
;
1446 if (cx
->status
== needBytes
) {
1447 cx
->status
= keepGoing
;
1448 cx
->current
->place
= afterContents
;
1454 SEC_ASN1Encode (const void *src
, const SecAsn1Template
*theTemplate
,
1455 SEC_ASN1WriteProc output_proc
, void *output_arg
)
1457 SEC_ASN1EncoderContext
*ecx
;
1460 ecx
= SEC_ASN1EncoderStart (src
, theTemplate
, output_proc
, output_arg
);
1464 rv
= SEC_ASN1EncoderUpdate (ecx
, NULL
, 0);
1466 SEC_ASN1EncoderFinish (ecx
);
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)
1476 sec_asn1e_encode_item_count (void *arg
, const char *buf
, size_t len
,
1477 int depth
, SEC_ASN1EncodingPart data_kind
)
1481 count
= (unsigned long*)arg
;
1482 PORT_Assert (count
!= NULL
);
1488 /* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
1490 sec_asn1e_encode_item_store (void *arg
, const char *buf
, size_t len
,
1491 int depth
, SEC_ASN1EncodingPart data_kind
)
1495 dest
= (SecAsn1Item
*)arg
;
1496 PORT_Assert (dest
!= NULL
);
1498 PORT_Memcpy (dest
->Data
+ dest
->Length
, buf
, len
);
1499 dest
->Length
+= len
;
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.
1508 * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
1511 sec_asn1e_allocate_item (PRArenaPool
*poolp
, SecAsn1Item
*dest
, unsigned long len
)
1513 if (poolp
!= NULL
) {
1516 release
= PORT_ArenaMark (poolp
);
1518 dest
= (SecAsn1Item
*)PORT_ArenaAlloc (poolp
, sizeof(SecAsn1Item
));
1520 dest
->Data
= (unsigned char*)PORT_ArenaAlloc (poolp
, len
);
1521 if (dest
->Data
== NULL
) {
1526 /* one or both allocations failed; release everything */
1527 PORT_ArenaRelease (poolp
, release
);
1529 /* everything okay; unmark the arena */
1530 PORT_ArenaUnmark (poolp
, release
);
1533 SecAsn1Item
*indest
;
1537 dest
= (SecAsn1Item
*)PORT_Alloc (sizeof(SecAsn1Item
));
1540 dest
->type
= siBuffer
;
1542 dest
->Data
= (unsigned char*)PORT_Alloc (len
);
1543 if (dest
->Data
== NULL
) {
1556 SEC_ASN1EncodeItem (PRArenaPool
*poolp
, SecAsn1Item
*dest
, const void *src
,
1557 const SecAsn1Template
*theTemplate
)
1559 unsigned long encoding_length
;
1562 PORT_Assert (dest
== NULL
|| dest
->Data
== NULL
);
1564 encoding_length
= 0;
1565 rv
= SEC_ASN1Encode (src
, theTemplate
,
1566 sec_asn1e_encode_item_count
, &encoding_length
);
1567 if (rv
!= SECSuccess
)
1570 dest
= sec_asn1e_allocate_item (poolp
, dest
, encoding_length
);
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
)
1580 (void) SEC_ASN1Encode (src
, theTemplate
, sec_asn1e_encode_item_store
, dest
);
1582 PORT_Assert (encoding_length
== dest
->Length
);
1587 static SecAsn1Item
*
1588 sec_asn1e_integer(PRArenaPool
*poolp
, SecAsn1Item
*dest
, unsigned long value
,
1589 PRBool make_unsigned
)
1596 * Determine the length of the encoded value (minimum of 1).
1601 sign
= (unsigned char)(copy
& 0x80);
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.
1610 if (sign
&& make_unsigned
)
1614 * Allocate the item (if necessary) and the data pointer within.
1616 dest
= sec_asn1e_allocate_item (poolp
, dest
, len
);
1621 * Store the value, byte by byte, in the item.
1625 dest
->Data
[--len
] = (unsigned char)value
;
1628 PORT_Assert (value
== 0);
1635 SEC_ASN1EncodeInteger(PRArenaPool
*poolp
, SecAsn1Item
*dest
, long value
)
1637 return sec_asn1e_integer (poolp
, dest
, (unsigned long) value
, PR_FALSE
);
1641 extern SecAsn1Item
*
1642 SEC_ASN1EncodeUnsignedInteger(PRArenaPool
*poolp
,
1643 SecAsn1Item
*dest
, unsigned long value
)
1645 return sec_asn1e_integer (poolp
, dest
, value
, PR_TRUE
);