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 $
56 } sec_asn1e_parse_place
;
63 } sec_asn1e_parse_status
;
65 typedef struct sec_asn1e_state_struct
{
66 SEC_ASN1EncoderContext
*top
;
67 const SecAsn1Template
*theTemplate
;
70 struct sec_asn1e_state_struct
*parent
; /* aka prev */
71 struct sec_asn1e_state_struct
*child
; /* aka next */
73 sec_asn1e_parse_place place
; /* where we are in encoding process */
76 * XXX explain the next fields as clearly as possible...
78 unsigned char tag_modifiers
;
79 unsigned char tag_number
;
80 unsigned long underlying_kind
;
84 PRBool
explicit, /* we are handling an explicit header */
85 indefinite
, /* need end-of-contents */
86 is_string
, /* encoding a simple string or an ANY */
87 may_stream
, /* when streaming, do indefinite encoding */
88 optional
, /* omit field if it has no contents */
89 ignore_stream
/* ignore streaming value of sub-template */
92 signedInt
/* signed alternate to SEC_ASN1_INTEGER */
98 * An "outsider" will have an opaque pointer to this, created by calling
99 * SEC_ASN1EncoderStart(). It will be passed back in to all subsequent
100 * calls to SEC_ASN1EncoderUpdate() and related routines, and when done
101 * it is passed to SEC_ASN1EncoderFinish().
103 struct sec_EncoderContext_struct
{
104 PRArenaPool
*our_pool
; /* for our internal allocs */
106 sec_asn1e_state
*current
;
107 sec_asn1e_parse_status status
;
112 SEC_ASN1NotifyProc notify_proc
; /* call before/after handling field */
113 void *notify_arg
; /* argument to notify_proc */
114 PRBool during_notify
; /* true during call to notify_proc */
116 SEC_ASN1WriteProc output_proc
; /* pass encoded bytes to this */
117 void *output_arg
; /* argument to that function */
121 static sec_asn1e_state
*
122 sec_asn1e_push_state (SEC_ASN1EncoderContext
*cx
,
123 const SecAsn1Template
*theTemplate
,
124 const void *src
, PRBool new_depth
)
126 sec_asn1e_state
*state
, *new_state
;
130 new_state
= (sec_asn1e_state
*)PORT_ArenaZAlloc (cx
->our_pool
,
132 if (new_state
== NULL
) {
133 cx
->status
= encodeError
;
138 new_state
->parent
= state
;
139 new_state
->theTemplate
= theTemplate
;
140 new_state
->place
= notInUse
;
142 new_state
->src
= (char *)src
+ theTemplate
->offset
;
145 new_state
->depth
= state
->depth
;
148 state
->child
= new_state
;
151 cx
->current
= new_state
;
157 sec_asn1e_scrub_state (sec_asn1e_state
*state
)
160 * Some default "scrubbing".
161 * XXX right set of initializations?
163 state
->place
= beforeHeader
;
164 state
->indefinite
= PR_FALSE
;
169 sec_asn1e_notify_before (SEC_ASN1EncoderContext
*cx
, void *src
, int depth
)
171 if (cx
->notify_proc
== NULL
)
174 cx
->during_notify
= PR_TRUE
;
175 (* cx
->notify_proc
) (cx
->notify_arg
, PR_TRUE
, src
, depth
);
176 cx
->during_notify
= PR_FALSE
;
181 sec_asn1e_notify_after (SEC_ASN1EncoderContext
*cx
, void *src
, int depth
)
183 if (cx
->notify_proc
== NULL
)
186 cx
->during_notify
= PR_TRUE
;
187 (* cx
->notify_proc
) (cx
->notify_arg
, PR_FALSE
, src
, depth
);
188 cx
->during_notify
= PR_FALSE
;
192 static sec_asn1e_state
*
193 sec_asn1e_init_state_based_on_template (sec_asn1e_state
*state
)
195 PRBool
explicit, is_string
, may_stream
, optional
, universal
, ignore_stream
;
196 unsigned char tag_modifiers
;
197 unsigned long encode_kind
, under_kind
;
198 unsigned long tag_number
;
200 PRBool signedInt
, dynamic
;
203 encode_kind
= state
->theTemplate
->kind
;
205 universal
= ((encode_kind
& SEC_ASN1_CLASS_MASK
) == SEC_ASN1_UNIVERSAL
)
206 ? PR_TRUE
: PR_FALSE
;
208 explicit = (encode_kind
& SEC_ASN1_EXPLICIT
) ? PR_TRUE
: PR_FALSE
;
209 encode_kind
&= ~SEC_ASN1_EXPLICIT
;
211 optional
= (encode_kind
& SEC_ASN1_OPTIONAL
) ? PR_TRUE
: PR_FALSE
;
212 encode_kind
&= ~SEC_ASN1_OPTIONAL
;
214 PORT_Assert (!(explicit && universal
)); /* bad templates */
216 may_stream
= (encode_kind
& SEC_ASN1_MAY_STREAM
) ? PR_TRUE
: PR_FALSE
;
217 encode_kind
&= ~SEC_ASN1_MAY_STREAM
;
219 ignore_stream
= (encode_kind
& SEC_ASN1_NO_STREAM
) ? PR_TRUE
: PR_FALSE
;
220 encode_kind
&= ~SEC_ASN1_NO_STREAM
;
223 signedInt
= (encode_kind
& SEC_ASN1_SIGNED_INT
) ? PR_TRUE
: PR_FALSE
;
224 encode_kind
&= ~SEC_ASN1_SIGNED_INT
;
228 dynamic
= (encode_kind
& SEC_ASN1_DYNAMIC
) ? PR_TRUE
: PR_FALSE
;
230 encode_kind
&= ~SEC_ASN1_DYNAMIC
;
232 if( encode_kind
& SEC_ASN1_CHOICE
) {
233 under_kind
= SEC_ASN1_CHOICE
;
236 if ((encode_kind
& (SEC_ASN1_POINTER
| SEC_ASN1_INLINE
)) || (!universal
238 const SecAsn1Template
*subt
;
241 PORT_Assert ((encode_kind
& (SEC_ASN1_ANY
| SEC_ASN1_SKIP
)) == 0);
243 sec_asn1e_scrub_state (state
);
245 if (encode_kind
& SEC_ASN1_POINTER
) {
247 * XXX This used to PORT_Assert (encode_kind == SEC_ASN1_POINTER);
248 * but that was too restrictive. This needs to be fixed,
249 * probably copying what the decoder now checks for, and
250 * adding a big comment here to explain what the checks mean.
252 src
= *(void **)state
->src
;
253 state
->place
= afterPointer
;
256 * If this is optional, but NULL, then the field does
257 * not need to be encoded. In this case we are done;
258 * we do not want to push a subtemplate.
264 * XXX this is an error; need to figure out
270 if (encode_kind
& SEC_ASN1_INLINE
) {
271 /* check that there are no extraneous bits */
272 PORT_Assert (encode_kind
== SEC_ASN1_INLINE
&& !optional
);
273 state
->place
= afterInline
;
276 * Save the tag modifiers and tag number here before moving
277 * on to the next state in case this is a member of a
280 state
->tag_modifiers
= (unsigned char)encode_kind
& SEC_ASN1_TAG_MASK
281 & ~SEC_ASN1_TAGNUM_MASK
;
282 state
->tag_number
= (unsigned char)encode_kind
& SEC_ASN1_TAGNUM_MASK
;
284 state
->place
= afterImplicit
;
285 state
->optional
= optional
;
289 subt
= SEC_ASN1GetSubtemplate (state
->theTemplate
, state
->src
, PR_TRUE
,
290 NULL
/* __APPLE__ */, 0 /* __APPLE__ */);
291 state
= sec_asn1e_push_state (state
->top
, subt
, src
, PR_FALSE
);
297 * This is a POINTER or INLINE; just init based on that
300 return sec_asn1e_init_state_based_on_template (state
);
304 * This is an implicit, non-universal (meaning, application-private
305 * or context-specific) field. This results in a "magic" tag but
306 * encoding based on the underlying type. We pushed a new state
307 * that is based on the subtemplate (the underlying type), but
308 * now we will sort of alias it to give it some of our properties
309 * (tag, optional status, etc.).
312 under_kind
= state
->theTemplate
->kind
;
313 if (under_kind
& SEC_ASN1_MAY_STREAM
) {
315 may_stream
= PR_TRUE
;
316 under_kind
&= ~SEC_ASN1_MAY_STREAM
;
319 under_kind
= encode_kind
;
323 * Sanity check that there are no unwanted bits marked in under_kind.
324 * These bits were either removed above (after we recorded them) or
325 * they simply should not be found (signalling a bad/broken template).
326 * XXX is this the right set of bits to test here? (i.e. need to add
329 PORT_Assert ((under_kind
& (/*SEC_ASN1_EXPLICIT | */SEC_ASN1_OPTIONAL
330 | SEC_ASN1_SKIP
| SEC_ASN1_INNER
331 | SEC_ASN1_DYNAMIC
| SEC_ASN1_MAY_STREAM
332 | SEC_ASN1_INLINE
| SEC_ASN1_POINTER
)) == 0);
334 if (encode_kind
& SEC_ASN1_ANY
) {
335 PORT_Assert (encode_kind
== under_kind
);
340 tag_modifiers
= (unsigned char)encode_kind
& SEC_ASN1_TAG_MASK
&
341 ~SEC_ASN1_TAGNUM_MASK
;
343 * XXX This assumes only single-octet identifiers. To handle
344 * the HIGH TAG form we would need to do some more work, especially
345 * in how to specify them in the template, because right now we
346 * do not provide a way to specify more *tag* bits in encode_kind.
351 * Apple change: if this is a DYNAMIC template, use the tag number
352 * from the subtemplate's kind
355 tag_number
= state
->theTemplate
->kind
& SEC_ASN1_TAGNUM_MASK
;
356 explicit = (state
->theTemplate
->kind
& SEC_ASN1_EXPLICIT
) ? PR_TRUE
: PR_FALSE
;
357 tag_modifiers
|= (state
->theTemplate
->kind
& SEC_ASN1_CONSTRUCTED
);
360 #endif /* __APPLE__ */
361 tag_number
= encode_kind
& SEC_ASN1_TAGNUM_MASK
;
363 is_string
= PR_FALSE
;
364 switch (under_kind
& SEC_ASN1_TAGNUM_MASK
) {
367 * XXX A plain old SET (as opposed to a SET OF) is not implemented.
368 * If it ever is, remove this assert...
370 PORT_Assert ((under_kind
& SEC_ASN1_GROUP
) != 0);
372 case SEC_ASN1_SEQUENCE
:
373 tag_modifiers
|= SEC_ASN1_CONSTRUCTED
;
375 case SEC_ASN1_BIT_STRING
:
376 case SEC_ASN1_BMP_STRING
:
377 case SEC_ASN1_GENERALIZED_TIME
:
378 case SEC_ASN1_IA5_STRING
:
379 case SEC_ASN1_OCTET_STRING
:
380 case SEC_ASN1_PRINTABLE_STRING
:
381 case SEC_ASN1_T61_STRING
:
382 case SEC_ASN1_UNIVERSAL_STRING
:
383 case SEC_ASN1_UTC_TIME
:
384 case SEC_ASN1_UTF8_STRING
:
385 case SEC_ASN1_VISIBLE_STRING
:
387 * We do not yet know if we will be constructing the string,
388 * so we have to wait to do this final tag modification.
395 state
->tag_modifiers
= tag_modifiers
;
396 state
->tag_number
= (unsigned char)tag_number
;
397 state
->underlying_kind
= under_kind
;
398 state
->explicit = explicit;
399 state
->may_stream
= may_stream
;
400 state
->is_string
= is_string
;
401 state
->optional
= optional
;
402 state
->ignore_stream
= ignore_stream
;
404 state
->signedInt
= signedInt
;
407 sec_asn1e_scrub_state (state
);
414 sec_asn1e_write_part (sec_asn1e_state
*state
,
415 const char *buf
, size_t len
,
416 SEC_ASN1EncodingPart part
)
418 SEC_ASN1EncoderContext
*cx
;
421 (* cx
->output_proc
) (cx
->output_arg
, buf
, len
, state
->depth
, part
);
426 * XXX This assumes only single-octet identifiers. To handle
427 * the HIGH TAG form we would need to modify this interface and
428 * teach it to properly encode the special form.
431 sec_asn1e_write_identifier_bytes (sec_asn1e_state
*state
, unsigned char value
)
436 sec_asn1e_write_part (state
, &byte
, 1, SEC_ASN1_Identifier
);
440 SEC_ASN1EncodeLength(unsigned char *buf
,unsigned long value
) {
443 lenlen
= SEC_ASN1LengthLength (value
);
455 PORT_Assert (value
== 0);
461 sec_asn1e_write_length_bytes (sec_asn1e_state
*state
, unsigned long value
,
465 unsigned char buf
[sizeof(unsigned long) + 1];
468 PORT_Assert (value
== 0);
472 lenlen
= SEC_ASN1EncodeLength(buf
,value
);
475 sec_asn1e_write_part (state
, (char *) buf
, lenlen
, SEC_ASN1_Length
);
480 sec_asn1e_write_contents_bytes (sec_asn1e_state
*state
,
481 const char *buf
, unsigned long len
)
483 sec_asn1e_write_part (state
, buf
, len
, SEC_ASN1_Contents
);
488 sec_asn1e_write_end_of_contents_bytes (sec_asn1e_state
*state
)
490 const char eoc
[2] = {0, 0};
492 sec_asn1e_write_part (state
, eoc
, 2, SEC_ASN1_EndOfContents
);
496 sec_asn1e_which_choice
499 const SecAsn1Template
*theTemplate
503 unsigned int which
= *(unsigned int *)src
;
505 for( rv
= 1, theTemplate
++; theTemplate
->kind
!= 0; rv
++, theTemplate
++ ) {
506 if( which
== theTemplate
->size
) {
515 sec_asn1e_contents_length (const SecAsn1Template
*theTemplate
, void *src
,
516 PRBool ignoresubstream
, PRBool
*noheaderp
)
518 unsigned long encode_kind
, underlying_kind
;
519 PRBool
explicit, optional
, universal
, may_stream
;
526 * This function currently calculates the length in all cases
527 * except the following: when writing out the contents of a
528 * template that belongs to a state where it was a sub-template
529 * with the SEC_ASN1_MAY_STREAM bit set and it's parent had the
530 * optional bit set. The information that the parent is optional
531 * and that we should return the length of 0 when that length is
532 * present since that means the optional field is no longer present.
533 * So we add the ignoresubstream flag which is passed in when
534 * writing the contents, but for all recursive calls to
535 * sec_asn1e_contents_length, we pass PR_FALSE, because this
536 * function correctly calculates the length for children templates
537 * from that point on. Confused yet? At least you didn't have
538 * to figure it out. ;) -javi
540 encode_kind
= theTemplate
->kind
;
542 universal
= ((encode_kind
& SEC_ASN1_CLASS_MASK
) == SEC_ASN1_UNIVERSAL
)
543 ? PR_TRUE
: PR_FALSE
;
545 explicit = (encode_kind
& SEC_ASN1_EXPLICIT
) ? PR_TRUE
: PR_FALSE
;
546 encode_kind
&= ~SEC_ASN1_EXPLICIT
;
548 optional
= (encode_kind
& SEC_ASN1_OPTIONAL
) ? PR_TRUE
: PR_FALSE
;
549 encode_kind
&= ~SEC_ASN1_OPTIONAL
;
551 PORT_Assert (!(explicit && universal
)); /* bad templates */
553 may_stream
= (encode_kind
& SEC_ASN1_MAY_STREAM
) ? PR_TRUE
: PR_FALSE
;
554 encode_kind
&= ~SEC_ASN1_MAY_STREAM
;
556 /* Just clear this to get it out of the way; we do not need it here */
557 encode_kind
&= ~SEC_ASN1_DYNAMIC
;
558 encode_kind
&= ~SEC_ASN1_NO_STREAM
;
560 if( encode_kind
& SEC_ASN1_CHOICE
) {
562 int indx
= sec_asn1e_which_choice(src
, theTemplate
);
564 /* XXX set an error? "choice not found" */
565 /* state->top->status = encodeError; */
569 src2
= (void *)((char *)src
- theTemplate
->offset
+ theTemplate
[indx
].offset
);
571 return sec_asn1e_contents_length(&theTemplate
[indx
], src2
,
572 PR_FALSE
, noheaderp
);
575 if ((encode_kind
& (SEC_ASN1_POINTER
| SEC_ASN1_INLINE
)) || !universal
) {
577 /* XXX any bits we want to disallow (PORT_Assert against) here? */
579 theTemplate
= SEC_ASN1GetSubtemplate (theTemplate
, src
, PR_TRUE
,
580 NULL
/* __APPLE__ */, 0 /* __APPLE__ */);
582 if (encode_kind
& SEC_ASN1_POINTER
) {
584 * XXX This used to PORT_Assert (encode_kind == SEC_ASN1_POINTER);
585 * but that was too restrictive. This needs to be fixed,
586 * probably copying what the decoder now checks for, and
587 * adding a big comment here to explain what the checks mean.
588 * Alternatively, the check here could be omitted altogether
589 * just letting sec_asn1e_init_state_based_on_template
590 * do it, since that routine can do better error handling, too.
595 *noheaderp
= PR_TRUE
;
597 *noheaderp
= PR_FALSE
;
600 } else if (encode_kind
& SEC_ASN1_INLINE
) {
601 /* check that there are no extraneous bits */
602 PORT_Assert (encode_kind
== SEC_ASN1_INLINE
&& !optional
);
605 src
= (char *)src
+ theTemplate
->offset
;
608 len
= sec_asn1e_contents_length (theTemplate
, src
, PR_FALSE
,
610 if (len
== 0 && optional
) {
611 *noheaderp
= PR_TRUE
;
612 } else if (*noheaderp
) {
613 /* Okay, *we* do not want to add in a header, but our caller still does. */
614 *noheaderp
= PR_FALSE
;
616 /* if the inner content exists, our length is
617 * len(identifier) + len(length) + len(innercontent)
618 * XXX we currently assume len(identifier) == 1;
619 * to support a high-tag-number this would need to be smarter.
621 len
+= 1 + SEC_ASN1LengthLength (len
);
626 underlying_kind
= theTemplate
->kind
;
627 underlying_kind
&= ~SEC_ASN1_MAY_STREAM
;
628 /* XXX Should we recurse here? */
630 underlying_kind
= encode_kind
;
634 signedInt
= (underlying_kind
& SEC_ASN1_SIGNED_INT
) ?
638 /* This is only used in decoding; it plays no part in encoding. */
639 if (underlying_kind
& SEC_ASN1_SAVE
) {
640 /* check that there are no extraneous bits */
641 PORT_Assert (underlying_kind
== SEC_ASN1_SAVE
);
642 *noheaderp
= PR_TRUE
;
646 /* Having any of these bits is not expected here... */
647 PORT_Assert ((underlying_kind
& (SEC_ASN1_EXPLICIT
| SEC_ASN1_OPTIONAL
648 | SEC_ASN1_INLINE
| SEC_ASN1_POINTER
649 | SEC_ASN1_DYNAMIC
| SEC_ASN1_MAY_STREAM
650 | SEC_ASN1_SAVE
| SEC_ASN1_SKIP
)) == 0);
652 if( underlying_kind
& SEC_ASN1_CHOICE
) {
654 int indx
= sec_asn1e_which_choice(src
, theTemplate
);
656 /* XXX set an error? "choice not found" */
657 /* state->top->status = encodeError; */
661 src2
= (void *)((char *)src
- theTemplate
->offset
+ theTemplate
[indx
].offset
);
662 len
= sec_asn1e_contents_length(&theTemplate
[indx
], src2
, PR_FALSE
,
666 switch (underlying_kind
) {
667 case SEC_ASN1_SEQUENCE_OF
:
668 case SEC_ASN1_SET_OF
:
670 const SecAsn1Template
*tmpt
;
672 unsigned long sub_len
;
677 group
= *(void ***)src
;
681 tmpt
= SEC_ASN1GetSubtemplate (theTemplate
, src
, PR_TRUE
,
682 NULL
/* __APPLE__ */, 0 /* __APPLE__ */);
684 for (; *group
!= NULL
; group
++) {
685 sub_src
= (char *)(*group
) + tmpt
->offset
;
686 sub_len
= sec_asn1e_contents_length (tmpt
, sub_src
, PR_FALSE
,
690 * XXX The 1 below is the presumed length of the identifier;
691 * to support a high-tag-number this would need to be smarter.
694 len
+= 1 + SEC_ASN1LengthLength (sub_len
);
699 case SEC_ASN1_SEQUENCE
:
702 const SecAsn1Template
*tmpt
;
704 unsigned long sub_len
;
707 for (tmpt
= theTemplate
+ 1; tmpt
->kind
; tmpt
++) {
708 sub_src
= (char *)src
+ tmpt
->offset
;
709 sub_len
= sec_asn1e_contents_length (tmpt
, sub_src
, PR_FALSE
,
713 * XXX The 1 below is the presumed length of the identifier;
714 * to support a high-tag-number this would need to be smarter.
717 len
+= 1 + SEC_ASN1LengthLength (sub_len
);
722 case SEC_ASN1_BIT_STRING
:
723 /* convert bit length to byte */
724 len
= (((SecAsn1Item
*)src
)->Length
+ 7) >> 3;
725 /* bit string contents involve an extra octet */
730 case SEC_ASN1_INTEGER
:
731 /* ASN.1 INTEGERs are signed.
732 * If the source is an unsigned integer, the encoder will need
733 * to handle the conversion here.
736 unsigned char *buf
= ((SecAsn1Item
*)src
)->Data
;
738 SecAsn1ItemType integerType
= ((SecAsn1Item
*)src
)->type
;
740 len
= ((SecAsn1Item
*)src
)->Length
;
744 if (*buf
& 0x80 && !signedInt
) {
746 if (*buf
& 0x80 && integerType
== siUnsignedInteger
) {
748 len
++; /* leading zero needed to make number signed */
750 break; /* reached beginning of number */
753 break; /* the number 0 */
756 break; /* leading zero already present */
758 /* extraneous leading zero, keep going */
766 len
= ((SecAsn1Item
*)src
)->Length
;
767 if (may_stream
&& len
== 0 && !ignoresubstream
)
768 len
= 1; /* if we're streaming, we may have a secitem w/len 0 as placeholder */
772 if ((len
== 0 && optional
) || underlying_kind
== SEC_ASN1_ANY
)
773 *noheaderp
= PR_TRUE
;
775 *noheaderp
= PR_FALSE
;
782 sec_asn1e_write_header (sec_asn1e_state
*state
)
784 unsigned long contents_length
;
785 unsigned char tag_number
, tag_modifiers
;
788 PORT_Assert (state
->place
== beforeHeader
);
790 tag_number
= state
->tag_number
;
791 tag_modifiers
= state
->tag_modifiers
;
793 if (state
->underlying_kind
== SEC_ASN1_ANY
) {
794 state
->place
= duringContents
;
798 if( state
->underlying_kind
& SEC_ASN1_CHOICE
) {
799 int indx
= sec_asn1e_which_choice(state
->src
, state
->theTemplate
);
801 /* XXX set an error? "choice not found" */
802 state
->top
->status
= encodeError
;
806 state
->place
= afterChoice
;
807 state
= sec_asn1e_push_state(state
->top
, &state
->theTemplate
[indx
],
808 (char *)state
->src
- state
->theTemplate
->offset
,
811 if( (sec_asn1e_state
*)NULL
!= state
) {
813 * Do the "before" field notification.
815 sec_asn1e_notify_before (state
->top
, state
->src
, state
->depth
);
816 state
= sec_asn1e_init_state_based_on_template (state
);
825 * We are doing a definite-length encoding. First we have to
826 * walk the data structure to calculate the entire contents length.
828 contents_length
= sec_asn1e_contents_length (state
->theTemplate
,
830 state
->ignore_stream
,
833 * We might be told explicitly not to put out a header.
834 * But it can also be the case, via a pushed subtemplate, that
835 * sec_asn1e_contents_length could not know that this field is
836 * really optional. So check for that explicitly, too.
838 if (noheader
|| (contents_length
== 0 && state
->optional
)) {
839 state
->place
= afterContents
;
840 if (state
->top
->streaming
&& state
->may_stream
&& state
->top
->from_buf
)
841 /* we did not find an optional indefinite string, so we don't encode it.
842 * However, if TakeFromBuf is on, we stop here anyway to give our caller
843 * a chance to intercept at the same point where we would stop if the
844 * field were present. */
845 state
->top
->status
= needBytes
;
849 if (state
->top
->streaming
&& state
->may_stream
850 && (state
->top
->from_buf
|| !state
->is_string
)) {
852 * We need to put out an indefinite-length encoding.
854 state
->indefinite
= PR_TRUE
;
856 * The only universal types that can be constructed are SETs,
857 * SEQUENCEs, and strings; so check that it is one of those,
858 * or that it is not universal (e.g. context-specific).
860 PORT_Assert ((tag_number
== SEC_ASN1_SET
)
861 || (tag_number
== SEC_ASN1_SEQUENCE
)
862 || ((tag_modifiers
& SEC_ASN1_CLASS_MASK
) != 0)
863 || state
->is_string
);
864 tag_modifiers
|= SEC_ASN1_CONSTRUCTED
;
868 sec_asn1e_write_identifier_bytes (state
, (unsigned char)(tag_number
| tag_modifiers
));
869 sec_asn1e_write_length_bytes (state
, contents_length
, state
->indefinite
);
871 if (contents_length
== 0 && !state
->indefinite
) {
873 * If no real contents to encode, then we are done with this field.
875 state
->place
= afterContents
;
880 * An EXPLICIT is nothing but an outer header, which we have already
881 * written. Now we need to do the inner header and contents.
883 if (state
->explicit) {
884 state
->place
= afterContents
;
885 state
= sec_asn1e_push_state (state
->top
,
886 SEC_ASN1GetSubtemplate(state
->theTemplate
,
889 NULL
/* __APPLE__ */, 0 /* __APPLE__ */),
890 state
->src
, PR_TRUE
);
892 state
= sec_asn1e_init_state_based_on_template (state
);
899 switch (state
->underlying_kind
) {
900 case SEC_ASN1_SET_OF
:
901 case SEC_ASN1_SEQUENCE_OF
:
903 * We need to push a child to handle each member.
907 const SecAsn1Template
*subt
;
909 group
= *(void ***)state
->src
;
910 if (group
== NULL
|| *group
== NULL
) {
912 * Group is empty; we are done.
914 state
->place
= afterContents
;
917 state
->place
= duringGroup
;
918 subt
= SEC_ASN1GetSubtemplate (state
->theTemplate
, state
->src
,
919 PR_TRUE
, NULL
/* __APPLE__ */, 0 /* __APPLE__ */);
920 state
= sec_asn1e_push_state (state
->top
, subt
, *group
, PR_TRUE
);
922 state
= sec_asn1e_init_state_based_on_template (state
);
926 case SEC_ASN1_SEQUENCE
:
929 * We need to push a child to handle the individual fields.
931 state
->place
= duringSequence
;
932 state
= sec_asn1e_push_state (state
->top
, state
->theTemplate
+ 1,
933 state
->src
, PR_TRUE
);
936 * Do the "before" field notification.
938 sec_asn1e_notify_before (state
->top
, state
->src
, state
->depth
);
939 state
= sec_asn1e_init_state_based_on_template (state
);
945 * I think we do not need to do anything else.
948 state
->place
= duringContents
;
957 sec_asn1e_write_contents (sec_asn1e_state
*state
,
958 const char *buf
, unsigned long len
)
960 PORT_Assert (state
->place
== duringContents
);
962 if (state
->top
->from_buf
) {
964 * Probably they just turned on "take from buf", but have not
965 * yet given us any bytes. If there is nothing in the buffer
966 * then we have nothing to do but return and wait.
968 if (buf
== NULL
|| len
== 0) {
969 state
->top
->status
= needBytes
;
973 * We are streaming, reading from a passed-in buffer.
974 * This means we are encoding a simple string or an ANY.
975 * For the former, we need to put out a substring, with its
976 * own identifier and length. For an ANY, we just write it
977 * out as is (our caller is required to ensure that it
978 * is a properly encoded entity).
980 PORT_Assert (state
->is_string
); /* includes ANY */
981 if (state
->underlying_kind
!= SEC_ASN1_ANY
) {
982 unsigned char identifier
;
985 * Create the identifier based on underlying_kind. We cannot
986 * use tag_number and tag_modifiers because this can be an
987 * implicitly encoded field. In that case, the underlying
988 * substrings *are* encoded with their real tag.
990 identifier
= (unsigned char)state
->underlying_kind
& SEC_ASN1_TAG_MASK
;
992 * The underlying kind should just be a simple string; there
993 * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
995 PORT_Assert ((identifier
& SEC_ASN1_TAGNUM_MASK
) == identifier
);
997 * Write out the tag and length for the substring.
999 sec_asn1e_write_identifier_bytes (state
, identifier
);
1000 if (state
->underlying_kind
== SEC_ASN1_BIT_STRING
) {
1003 * Assume we have a length in bytes but we need to output
1004 * a proper bit string. This interface only works for bit
1005 * strings that are full multiples of 8. If support for
1006 * real, variable length bit strings is needed then the
1007 * caller will have to know to pass in a bit length instead
1008 * of a byte length and then this code will have to
1009 * perform the encoding necessary (length written is length
1010 * in bytes plus 1, and the first octet of string is the
1011 * number of bits remaining between the end of the bit
1012 * string and the next byte boundary).
1014 sec_asn1e_write_length_bytes (state
, len
+ 1, PR_FALSE
);
1016 sec_asn1e_write_contents_bytes (state
, &byte
, 1);
1018 sec_asn1e_write_length_bytes (state
, len
, PR_FALSE
);
1021 sec_asn1e_write_contents_bytes (state
, buf
, len
);
1022 state
->top
->status
= needBytes
;
1024 switch (state
->underlying_kind
) {
1026 case SEC_ASN1_SEQUENCE
:
1030 case SEC_ASN1_BIT_STRING
:
1035 item
= (SecAsn1Item
*)state
->src
;
1036 len
= (item
->Length
+ 7) >> 3;
1037 rem
= (unsigned char)((len
<< 3) - item
->Length
); /* remaining bits */
1038 sec_asn1e_write_contents_bytes (state
, &rem
, 1);
1039 sec_asn1e_write_contents_bytes (state
, (char *) item
->Data
,
1044 case SEC_ASN1_BMP_STRING
:
1045 /* The number of bytes must be divisable by 2 */
1046 if ((((SecAsn1Item
*)state
->src
)->Length
) % 2) {
1047 SEC_ASN1EncoderContext
*cx
;
1050 cx
->status
= encodeError
;
1053 /* otherwise, fall through to write the content */
1054 goto process_string
;
1056 case SEC_ASN1_UNIVERSAL_STRING
:
1057 /* The number of bytes must be divisable by 4 */
1058 if ((((SecAsn1Item
*)state
->src
)->Length
) % 4) {
1059 SEC_ASN1EncoderContext
*cx
;
1062 cx
->status
= encodeError
;
1065 /* otherwise, fall through to write the content */
1066 goto process_string
;
1068 case SEC_ASN1_INTEGER
:
1069 /* ASN.1 INTEGERs are signed. If the source is an unsigned
1070 * integer, the encoder will need to handle the conversion here.
1074 unsigned char *intbuf
;
1076 PRBool signedInt
= state
->signedInt
;
1078 SECItemType integerType
= ((SecAsn1Item
*)state
->src
)->type
;
1080 blen
= ((SecAsn1Item
*)state
->src
)->Length
;
1081 intbuf
= ((SecAsn1Item
*)state
->src
)->Data
;
1084 if (*intbuf
& 0x80 && !signedInt
) {
1086 if (*intbuf
& 0x80 && integerType
== siUnsignedInteger
) {
1088 char zero
= 0; /* write a leading 0 */
1089 sec_asn1e_write_contents_bytes(state
, &zero
, 1);
1090 /* and then the remaining buffer */
1091 sec_asn1e_write_contents_bytes(state
,
1092 (char *)intbuf
, blen
);
1095 /* Check three possibilities:
1096 * 1. No leading zeros, msb of MSB is not 1;
1097 * 2. The number is zero itself;
1098 * 3. Encoding a signed integer with a leading zero,
1099 * keep the zero so that the number is positive.
1104 (intbuf
[1] & 0x80 && signedInt
) )
1106 (intbuf
[1] & 0x80 && integerType
!= siUnsignedInteger
) )
1109 sec_asn1e_write_contents_bytes(state
,
1110 (char *)intbuf
, blen
);
1113 /* byte is 0, continue */
1118 /* done with this content */
1126 item
= (SecAsn1Item
*)state
->src
;
1127 sec_asn1e_write_contents_bytes (state
, (char *) item
->Data
,
1132 state
->place
= afterContents
;
1138 * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
1141 sec_asn1e_next_in_group (sec_asn1e_state
*state
)
1143 sec_asn1e_state
*child
;
1147 PORT_Assert (state
->place
== duringGroup
);
1148 PORT_Assert (state
->child
!= NULL
);
1150 child
= state
->child
;
1152 group
= *(void ***)state
->src
;
1155 * Find placement of current item.
1157 member
= (char *)(state
->child
->src
) - child
->theTemplate
->offset
;
1158 while (*group
!= member
)
1162 * Move forward to next item.
1165 if (*group
== NULL
) {
1167 * That was our last one; we are done now.
1169 child
->place
= notInUse
;
1170 state
->place
= afterContents
;
1173 child
->src
= (char *)(*group
) + child
->theTemplate
->offset
;
1178 sec_asn1e_scrub_state (child
);
1179 state
->top
->current
= child
;
1184 * We are moving along through a sequence; move forward by one,
1185 * (detecting end-of-sequence when it happens).
1188 sec_asn1e_next_in_sequence (sec_asn1e_state
*state
)
1190 sec_asn1e_state
*child
;
1192 PORT_Assert (state
->place
== duringSequence
);
1193 PORT_Assert (state
->child
!= NULL
);
1195 child
= state
->child
;
1198 * Do the "after" field notification.
1200 sec_asn1e_notify_after (state
->top
, child
->src
, child
->depth
);
1205 child
->theTemplate
++;
1206 if (child
->theTemplate
->kind
== 0) {
1208 * We are done with this sequence.
1210 child
->place
= notInUse
;
1211 state
->place
= afterContents
;
1216 * Reset state and push.
1219 child
->src
= (char *)state
->src
+ child
->theTemplate
->offset
;
1222 * Do the "before" field notification.
1224 sec_asn1e_notify_before (state
->top
, child
->src
, child
->depth
);
1226 state
->top
->current
= child
;
1227 (void) sec_asn1e_init_state_based_on_template (child
);
1232 sec_asn1e_after_contents (sec_asn1e_state
*state
)
1234 PORT_Assert (state
->place
== afterContents
);
1236 if (state
->indefinite
)
1237 sec_asn1e_write_end_of_contents_bytes (state
);
1240 * Just make my parent be the current state. It will then clean
1241 * up after me and free me (or reuse me).
1243 state
->top
->current
= state
->parent
;
1248 * This function is called whether or not we are streaming; if we
1249 * *are* streaming, our caller can also instruct us to take bytes
1250 * from the passed-in buffer (at buf, for length len, which is likely
1251 * bytes but could even mean bits if the current field is a bit string).
1252 * If we have been so instructed, we will gobble up bytes from there
1253 * (rather than from our src structure) and output them, and then
1254 * we will just return, expecting to be called again -- either with
1255 * more bytes or after our caller has instructed us that we are done
1256 * (for now) with the buffer.
1259 SEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext
*cx
,
1260 const char *buf
, unsigned long len
)
1262 sec_asn1e_state
*state
;
1264 if (cx
->status
== needBytes
) {
1265 PORT_Assert (buf
!= NULL
&& len
!= 0);
1266 cx
->status
= keepGoing
;
1269 while (cx
->status
== keepGoing
) {
1270 state
= cx
->current
;
1271 switch (state
->place
) {
1273 sec_asn1e_write_header (state
);
1275 case duringContents
:
1276 sec_asn1e_write_contents (state
, buf
, len
);
1279 sec_asn1e_next_in_group (state
);
1281 case duringSequence
:
1282 sec_asn1e_next_in_sequence (state
);
1285 sec_asn1e_after_contents (state
);
1292 * These states are more documentation than anything.
1293 * They just need to force a pop.
1295 PORT_Assert (!state
->indefinite
);
1296 state
->place
= afterContents
;
1300 /* This is not an error, but rather a plain old BUG! */
1302 cx
->status
= encodeError
;
1306 if (cx
->status
== encodeError
)
1309 /* It might have changed, so we have to update our local copy. */
1310 state
= cx
->current
;
1312 /* If it is NULL, we have popped all the way to the top. */
1313 if (state
== NULL
) {
1314 cx
->status
= allDone
;
1319 if (cx
->status
== encodeError
) {
1328 SEC_ASN1EncoderFinish (SEC_ASN1EncoderContext
*cx
)
1331 * XXX anything else that needs to be finished?
1334 PORT_FreeArena (cx
->our_pool
, PR_FALSE
);
1338 SEC_ASN1EncoderContext
*
1339 SEC_ASN1EncoderStart (const void *src
, const SecAsn1Template
*theTemplate
,
1340 SEC_ASN1WriteProc output_proc
, void *output_arg
)
1342 PRArenaPool
*our_pool
;
1343 SEC_ASN1EncoderContext
*cx
;
1345 our_pool
= PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE
);
1346 if (our_pool
== NULL
) {
1347 syslog(LOG_ERR
,"SEC_ASN1EncoderStart: failed to create new arena");
1351 cx
= (SEC_ASN1EncoderContext
*)PORT_ArenaZAlloc (our_pool
, sizeof(*cx
));
1353 syslog(LOG_ERR
,"SEC_ASN1EncoderStart: failed to alloc");
1354 PORT_FreeArena (our_pool
, PR_FALSE
);
1358 cx
->our_pool
= our_pool
;
1359 cx
->output_proc
= output_proc
;
1360 cx
->output_arg
= output_arg
;
1362 cx
->status
= keepGoing
;
1364 if (sec_asn1e_push_state(cx
, theTemplate
, src
, PR_FALSE
) == NULL
1365 || sec_asn1e_init_state_based_on_template (cx
->current
) == NULL
) {
1367 * Trouble initializing (probably due to failed allocations)
1368 * requires that we just give up.
1370 syslog(LOG_ERR
, "SEC_ASN1EncoderStart: unable to initialize state");
1371 PORT_FreeArena (our_pool
, PR_FALSE
);
1380 * XXX Do we need a FilterProc, too?
1385 SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext
*cx
,
1386 SEC_ASN1NotifyProc fn
, void *arg
)
1388 cx
->notify_proc
= fn
;
1389 cx
->notify_arg
= arg
;
1394 SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext
*cx
)
1396 cx
->notify_proc
= NULL
;
1397 cx
->notify_arg
= NULL
; /* not necessary; just being clean */
1402 SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext
*cx
, int error
)
1405 PORT_SetError(error
);
1406 cx
->status
= encodeError
;
1411 SEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext
*cx
)
1413 /* XXX is there a way to check that we are "between" fields here? */
1415 cx
->streaming
= PR_TRUE
;
1420 SEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext
*cx
)
1422 /* XXX is there a way to check that we are "between" fields here? */
1424 cx
->streaming
= PR_FALSE
;
1429 SEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext
*cx
)
1432 * XXX is there a way to check that we are "between" fields here? this
1433 * needs to include a check for being in between groups of items in
1434 * a SET_OF or SEQUENCE_OF.
1436 PORT_Assert (cx
->streaming
);
1438 cx
->from_buf
= PR_TRUE
;
1443 SEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext
*cx
)
1445 /* we should actually be taking from buf *now* */
1446 PORT_Assert (cx
->from_buf
);
1447 if (! cx
->from_buf
) /* if not, just do nothing */
1450 cx
->from_buf
= PR_FALSE
;
1452 if (cx
->status
== needBytes
) {
1453 cx
->status
= keepGoing
;
1454 cx
->current
->place
= afterContents
;
1460 SEC_ASN1Encode (const void *src
, const SecAsn1Template
*theTemplate
,
1461 SEC_ASN1WriteProc output_proc
, void *output_arg
)
1463 SEC_ASN1EncoderContext
*ecx
;
1466 ecx
= SEC_ASN1EncoderStart (src
, theTemplate
, output_proc
, output_arg
);
1470 rv
= SEC_ASN1EncoderUpdate (ecx
, NULL
, 0);
1472 if (rv
!= SECSuccess
)
1473 syslog(LOG_ERR
,"SEC_ASN1Encode: encode failure");
1475 SEC_ASN1EncoderFinish (ecx
);
1481 * XXX depth and data_kind are unused; is there a PC way to silence warnings?
1482 * (I mean "politically correct", not anything to do with intel/win platform)
1485 sec_asn1e_encode_item_count (void *arg
, const char *buf
, size_t len
,
1486 int depth
, SEC_ASN1EncodingPart data_kind
)
1490 count
= (unsigned long*)arg
;
1491 PORT_Assert (count
!= NULL
);
1497 /* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
1499 sec_asn1e_encode_item_store (void *arg
, const char *buf
, size_t len
,
1500 int depth
, SEC_ASN1EncodingPart data_kind
)
1504 dest
= (SecAsn1Item
*)arg
;
1505 PORT_Assert (dest
!= NULL
);
1507 PORT_Memcpy (dest
->Data
+ dest
->Length
, buf
, len
);
1508 dest
->Length
+= len
;
1513 * Allocate an entire SecAsn1Item, or just the data part of it, to hold
1514 * "len" bytes of stuff. Allocate from the given pool, if specified,
1515 * otherwise just do a vanilla PORT_Alloc.
1517 * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
1520 sec_asn1e_allocate_item (PRArenaPool
*poolp
, SecAsn1Item
*dest
, unsigned long len
)
1522 if (poolp
!= NULL
) {
1525 release
= PORT_ArenaMark (poolp
);
1527 dest
= (SecAsn1Item
*)PORT_ArenaAlloc (poolp
, sizeof(SecAsn1Item
));
1529 dest
->Data
= (unsigned char*)PORT_ArenaAlloc (poolp
, len
);
1530 if (dest
->Data
== NULL
) {
1535 /* one or both allocations failed; release everything */
1536 PORT_ArenaRelease (poolp
, release
);
1538 /* everything okay; unmark the arena */
1539 PORT_ArenaUnmark (poolp
, release
);
1542 SecAsn1Item
*indest
;
1546 dest
= (SecAsn1Item
*)PORT_Alloc (sizeof(SecAsn1Item
));
1549 dest
->type
= siBuffer
;
1551 dest
->Data
= (unsigned char*)PORT_Alloc (len
);
1552 if (dest
->Data
== NULL
) {
1565 SEC_ASN1EncodeItem (PRArenaPool
*poolp
, SecAsn1Item
*dest
, const void *src
,
1566 const SecAsn1Template
*theTemplate
)
1568 unsigned long encoding_length
;
1571 PORT_Assert (dest
== NULL
|| dest
->Data
== NULL
);
1573 encoding_length
= 0;
1574 rv
= SEC_ASN1Encode (src
, theTemplate
,
1575 sec_asn1e_encode_item_count
, &encoding_length
);
1576 if (rv
!= SECSuccess
) {
1577 syslog(LOG_ERR
, "SEC_ASN1EncodeItem: Encode failed %d", rv
);
1581 dest
= sec_asn1e_allocate_item (poolp
, dest
, encoding_length
);
1583 syslog(LOG_ERR
, "SEC_ASN1EncodeItem: allocate failure");
1587 /* XXX necessary? This really just checks for a bug in the allocate fn */
1588 PORT_Assert (dest
->Data
!= NULL
);
1589 if (dest
->Data
== NULL
) {
1590 syslog(LOG_ERR
, "SEC_ASN1EncodeItem: data allocate failure");
1595 (void) SEC_ASN1Encode (src
, theTemplate
, sec_asn1e_encode_item_store
, dest
);
1597 PORT_Assert (encoding_length
== dest
->Length
);
1602 static SecAsn1Item
*
1603 sec_asn1e_integer(PRArenaPool
*poolp
, SecAsn1Item
*dest
, unsigned long value
,
1604 PRBool make_unsigned
)
1611 * Determine the length of the encoded value (minimum of 1).
1616 sign
= (unsigned char)(copy
& 0x80);
1621 * If this is an unsigned encoding, and the high bit of the last
1622 * byte we counted was set, we need to add one to the length so
1623 * we put a high-order zero byte in the encoding.
1625 if (sign
&& make_unsigned
)
1629 * Allocate the item (if necessary) and the data pointer within.
1631 dest
= sec_asn1e_allocate_item (poolp
, dest
, len
);
1636 * Store the value, byte by byte, in the item.
1640 dest
->Data
[--len
] = (unsigned char)value
;
1643 PORT_Assert (value
== 0);
1650 SEC_ASN1EncodeInteger(PRArenaPool
*poolp
, SecAsn1Item
*dest
, long value
)
1652 return sec_asn1e_integer (poolp
, dest
, (unsigned long) value
, PR_FALSE
);
1656 extern SecAsn1Item
*
1657 SEC_ASN1EncodeUnsignedInteger(PRArenaPool
*poolp
,
1658 SecAsn1Item
*dest
, unsigned long value
)
1660 return sec_asn1e_integer (poolp
, dest
, value
, PR_TRUE
);