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
;
64 hdr_normal
= 0, /* encode header normally */
65 hdr_any
= 1, /* header already encoded in content */
66 hdr_decoder
= 2, /* template only used by decoder. skip it. */
67 hdr_optional
= 3, /* optional component, to be omitted */
68 hdr_placeholder
= 4 /* place holder for from_buf content */
69 } sec_asn1e_hdr_encoding
;
71 typedef struct sec_asn1e_state_struct
{
72 SEC_ASN1EncoderContext
*top
;
73 const SecAsn1Template
*theTemplate
;
76 struct sec_asn1e_state_struct
*parent
; /* aka prev */
77 struct sec_asn1e_state_struct
*child
; /* aka next */
79 sec_asn1e_parse_place place
; /* where we are in encoding process */
82 * XXX explain the next fields as clearly as possible...
84 unsigned char tag_modifiers
;
85 unsigned char tag_number
;
86 unsigned long underlying_kind
;
90 PRBool
explicit, /* we are handling an explicit header */
91 indefinite
, /* need end-of-contents */
92 is_string
, /* encoding a simple string or an ANY */
93 may_stream
, /* when streaming, do indefinite encoding */
94 optional
, /* omit field if it has no contents */
95 ignore_stream
/* ignore streaming value of sub-template */
98 signedInt
/* signed alternate to SEC_ASN1_INTEGER */
104 * An "outsider" will have an opaque pointer to this, created by calling
105 * SEC_ASN1EncoderStart(). It will be passed back in to all subsequent
106 * calls to SEC_ASN1EncoderUpdate() and related routines, and when done
107 * it is passed to SEC_ASN1EncoderFinish().
109 struct sec_EncoderContext_struct
{
110 PRArenaPool
*our_pool
; /* for our internal allocs */
112 sec_asn1e_state
*current
;
113 sec_asn1e_parse_status status
;
118 SEC_ASN1NotifyProc notify_proc
; /* call before/after handling field */
119 void *notify_arg
; /* argument to notify_proc */
120 PRBool during_notify
; /* true during call to notify_proc */
122 SEC_ASN1WriteProc output_proc
; /* pass encoded bytes to this */
123 void *output_arg
; /* argument to that function */
127 static sec_asn1e_state
*
128 sec_asn1e_push_state(SEC_ASN1EncoderContext
*cx
,
129 const SecAsn1Template
*theTemplate
,
130 const void *src
, PRBool new_depth
)
132 sec_asn1e_state
*state
, *new_state
;
136 new_state
= (sec_asn1e_state
*)PORT_ArenaZAlloc(cx
->our_pool
, sizeof(*new_state
));
137 if (new_state
== NULL
) {
138 cx
->status
= encodeError
;
143 new_state
->parent
= state
;
144 new_state
->theTemplate
= theTemplate
;
145 new_state
->place
= notInUse
;
147 new_state
->src
= (char *)src
+ theTemplate
->offset
;
151 new_state
->depth
= state
->depth
;
155 state
->child
= new_state
;
158 cx
->current
= new_state
;
164 sec_asn1e_scrub_state(sec_asn1e_state
*state
)
167 * Some default "scrubbing".
168 * XXX right set of initializations?
170 state
->place
= beforeHeader
;
171 state
->indefinite
= PR_FALSE
;
176 sec_asn1e_notify_before(SEC_ASN1EncoderContext
*cx
, void *src
, int depth
)
178 if (cx
->notify_proc
== NULL
) {
182 cx
->during_notify
= PR_TRUE
;
183 (* cx
->notify_proc
)(cx
->notify_arg
, PR_TRUE
, src
, depth
);
184 cx
->during_notify
= PR_FALSE
;
189 sec_asn1e_notify_after(SEC_ASN1EncoderContext
*cx
, void *src
, int depth
)
191 if (cx
->notify_proc
== NULL
) {
195 cx
->during_notify
= PR_TRUE
;
196 (* cx
->notify_proc
)(cx
->notify_arg
, PR_FALSE
, src
, depth
);
197 cx
->during_notify
= PR_FALSE
;
201 static sec_asn1e_state
*
202 sec_asn1e_init_state_based_on_template(sec_asn1e_state
*state
)
204 PRBool
explicit, is_string
, may_stream
, optional
, universal
, ignore_stream
;
205 unsigned char tag_modifiers
;
206 unsigned long encode_kind
, under_kind
;
207 unsigned long tag_number
;
209 PRBool signedInt
, dynamic
;
212 encode_kind
= state
->theTemplate
->kind
;
214 universal
= ((encode_kind
& SEC_ASN1_CLASS_MASK
) == SEC_ASN1_UNIVERSAL
) ? PR_TRUE
: PR_FALSE
;
216 explicit = (encode_kind
& SEC_ASN1_EXPLICIT
) ? PR_TRUE
: PR_FALSE
;
217 encode_kind
&= ~SEC_ASN1_EXPLICIT
;
219 optional
= (encode_kind
& SEC_ASN1_OPTIONAL
) ? PR_TRUE
: PR_FALSE
;
220 encode_kind
&= ~SEC_ASN1_OPTIONAL
;
222 PORT_Assert(!(explicit && universal
)); /* bad templates */
224 may_stream
= (encode_kind
& SEC_ASN1_MAY_STREAM
) ? PR_TRUE
: PR_FALSE
;
225 encode_kind
&= ~SEC_ASN1_MAY_STREAM
;
227 ignore_stream
= (encode_kind
& SEC_ASN1_NO_STREAM
) ? PR_TRUE
: PR_FALSE
;
228 encode_kind
&= ~SEC_ASN1_NO_STREAM
;
231 signedInt
= (encode_kind
& SEC_ASN1_SIGNED_INT
) ? PR_TRUE
: PR_FALSE
;
232 encode_kind
&= ~SEC_ASN1_SIGNED_INT
;
236 dynamic
= (encode_kind
& SEC_ASN1_DYNAMIC
) ? PR_TRUE
: PR_FALSE
;
238 encode_kind
&= ~SEC_ASN1_DYNAMIC
;
240 if( encode_kind
& SEC_ASN1_CHOICE
) {
241 under_kind
= SEC_ASN1_CHOICE
;
242 } else if ((encode_kind
& (SEC_ASN1_POINTER
| SEC_ASN1_INLINE
)) ||
243 (!universal
&& !explicit)) {
244 const SecAsn1Template
*subt
;
247 PORT_Assert((encode_kind
& (SEC_ASN1_ANY
| SEC_ASN1_SKIP
)) == 0);
249 sec_asn1e_scrub_state(state
);
251 if (encode_kind
& SEC_ASN1_POINTER
) {
253 * XXX This used to PORT_Assert (encode_kind == SEC_ASN1_POINTER);
254 * but that was too restrictive. This needs to be fixed,
255 * probably copying what the decoder now checks for, and
256 * adding a big comment here to explain what the checks mean.
258 src
= *(void **)state
->src
;
259 state
->place
= afterPointer
;
262 * If this is optional, but NULL, then the field does
263 * not need to be encoded. In this case we are done;
264 * we do not want to push a subtemplate.
271 * XXX this is an error; need to figure out
277 if (encode_kind
& SEC_ASN1_INLINE
) {
278 /* check that there are no extraneous bits */
279 PORT_Assert(encode_kind
== SEC_ASN1_INLINE
&& !optional
);
280 state
->place
= afterInline
;
283 * Save the tag modifiers and tag number here before moving
284 * on to the next state in case this is a member of a
287 state
->tag_modifiers
= (unsigned char)encode_kind
& SEC_ASN1_TAG_MASK
& ~SEC_ASN1_TAGNUM_MASK
;
288 state
->tag_number
= (unsigned char)encode_kind
& SEC_ASN1_TAGNUM_MASK
;
290 state
->place
= afterImplicit
;
291 state
->optional
= optional
;
295 subt
= SEC_ASN1GetSubtemplate(state
->theTemplate
, state
->src
, PR_TRUE
,
296 NULL
/* __APPLE__ */, 0 /* __APPLE__ */);
297 state
= sec_asn1e_push_state(state
->top
, subt
, src
, PR_FALSE
);
304 * This is a POINTER or INLINE; just init based on that
307 return sec_asn1e_init_state_based_on_template(state
);
311 * This is an implicit, non-universal (meaning, application-private
312 * or context-specific) field. This results in a "magic" tag but
313 * encoding based on the underlying type. We pushed a new state
314 * that is based on the subtemplate (the underlying type), but
315 * now we will sort of alias it to give it some of our properties
316 * (tag, optional status, etc.).
319 under_kind
= state
->theTemplate
->kind
;
320 if (under_kind
& SEC_ASN1_MAY_STREAM
) {
321 if (!ignore_stream
) {
322 may_stream
= PR_TRUE
;
324 under_kind
&= ~SEC_ASN1_MAY_STREAM
;
327 under_kind
= encode_kind
;
331 * Sanity check that there are no unwanted bits marked in under_kind.
332 * These bits were either removed above (after we recorded them) or
333 * they simply should not be found (signalling a bad/broken template).
334 * XXX is this the right set of bits to test here? (i.e. need to add
337 PORT_Assert((under_kind
& (/*SEC_ASN1_EXPLICIT | */SEC_ASN1_OPTIONAL
338 | SEC_ASN1_SKIP
| SEC_ASN1_INNER
339 | SEC_ASN1_DYNAMIC
| SEC_ASN1_MAY_STREAM
340 | SEC_ASN1_INLINE
| SEC_ASN1_POINTER
)) == 0);
342 if (encode_kind
& SEC_ASN1_ANY
) {
343 PORT_Assert(encode_kind
== under_kind
);
348 tag_modifiers
= (unsigned char)encode_kind
& SEC_ASN1_TAG_MASK
& ~SEC_ASN1_TAGNUM_MASK
;
350 * XXX This assumes only single-octet identifiers. To handle
351 * the HIGH TAG form we would need to do some more work, especially
352 * in how to specify them in the template, because right now we
353 * do not provide a way to specify more *tag* bits in encode_kind.
358 * Apple change: if this is a DYNAMIC template, use the tag number
359 * from the subtemplate's kind
362 tag_number
= state
->theTemplate
->kind
& SEC_ASN1_TAGNUM_MASK
;
363 explicit = (state
->theTemplate
->kind
& SEC_ASN1_EXPLICIT
) ? PR_TRUE
: PR_FALSE
;
364 tag_modifiers
|= (state
->theTemplate
->kind
& SEC_ASN1_CONSTRUCTED
);
367 #endif /* __APPLE__ */
368 tag_number
= encode_kind
& SEC_ASN1_TAGNUM_MASK
;
370 is_string
= PR_FALSE
;
371 switch (under_kind
& SEC_ASN1_TAGNUM_MASK
) {
374 * XXX A plain old SET (as opposed to a SET OF) is not implemented.
375 * If it ever is, remove this assert...
377 PORT_Assert((under_kind
& SEC_ASN1_GROUP
) != 0);
379 case SEC_ASN1_SEQUENCE
:
380 tag_modifiers
|= SEC_ASN1_CONSTRUCTED
;
382 case SEC_ASN1_BIT_STRING
:
383 case SEC_ASN1_BMP_STRING
:
384 case SEC_ASN1_GENERALIZED_TIME
:
385 case SEC_ASN1_IA5_STRING
:
386 case SEC_ASN1_OCTET_STRING
:
387 case SEC_ASN1_PRINTABLE_STRING
:
388 case SEC_ASN1_T61_STRING
:
389 case SEC_ASN1_UNIVERSAL_STRING
:
390 case SEC_ASN1_UTC_TIME
:
391 case SEC_ASN1_UTF8_STRING
:
392 case SEC_ASN1_VISIBLE_STRING
:
394 * We do not yet know if we will be constructing the string,
395 * so we have to wait to do this final tag modification.
402 state
->tag_modifiers
= tag_modifiers
;
403 state
->tag_number
= (unsigned char)tag_number
;
404 state
->underlying_kind
= under_kind
;
405 state
->explicit = explicit;
406 state
->may_stream
= may_stream
;
407 state
->is_string
= is_string
;
408 state
->optional
= optional
;
409 state
->ignore_stream
= ignore_stream
;
411 state
->signedInt
= signedInt
;
414 sec_asn1e_scrub_state(state
);
421 sec_asn1e_write_part(sec_asn1e_state
*state
,
422 const char *buf
, size_t len
,
423 SEC_ASN1EncodingPart part
)
425 SEC_ASN1EncoderContext
*cx
;
428 (* cx
->output_proc
)(cx
->output_arg
, buf
, len
, state
->depth
, part
);
433 * XXX This assumes only single-octet identifiers. To handle
434 * the HIGH TAG form we would need to modify this interface and
435 * teach it to properly encode the special form.
438 sec_asn1e_write_identifier_bytes(sec_asn1e_state
*state
, unsigned char value
)
443 sec_asn1e_write_part(state
, &byte
, 1, SEC_ASN1_Identifier
);
447 SEC_ASN1EncodeLength(unsigned char *buf
,unsigned long value
) {
450 lenlen
= SEC_ASN1LengthLength(value
);
462 PORT_Assert(value
== 0);
468 sec_asn1e_write_length_bytes(sec_asn1e_state
*state
, unsigned long value
,
472 unsigned char buf
[sizeof(unsigned long) + 1];
475 PORT_Assert(value
== 0);
479 lenlen
= SEC_ASN1EncodeLength(buf
,value
);
482 sec_asn1e_write_part(state
, (char *) buf
, lenlen
, SEC_ASN1_Length
);
487 sec_asn1e_write_contents_bytes(sec_asn1e_state
*state
,
488 const char *buf
, unsigned long len
)
490 sec_asn1e_write_part(state
, buf
, len
, SEC_ASN1_Contents
);
495 sec_asn1e_write_end_of_contents_bytes(sec_asn1e_state
*state
)
497 const char eoc
[2] = {0, 0};
499 sec_asn1e_write_part(state
, eoc
, 2, SEC_ASN1_EndOfContents
);
503 sec_asn1e_which_choice(void *src
, const SecAsn1Template
*theTemplate
)
506 unsigned int which
= *(unsigned int *)src
;
508 for( rv
= 1, theTemplate
++; theTemplate
->kind
!= 0; rv
++, theTemplate
++ ) {
509 if( which
== theTemplate
->size
) {
518 sec_asn1e_contents_length(const SecAsn1Template
*theTemplate
, void *src
,
519 PRBool ignoresubstream
, PRBool insideIndefinite
,
520 sec_asn1e_hdr_encoding
*pHdrException
)
522 unsigned long encode_kind
, underlying_kind
;
523 PRBool
explicit, optional
, universal
, may_stream
;
530 * This function currently calculates the length in all cases
531 * except the following: when writing out the contents of a
532 * template that belongs to a state where it was a sub-template
533 * with the SEC_ASN1_MAY_STREAM bit set and it's parent had the
534 * optional bit set. The information that the parent is optional
535 * and that we should return the length of 0 when that length is
536 * present since that means the optional field is no longer present.
537 * So we add the ignoresubstream flag which is passed in when
538 * writing the contents, but for all recursive calls to
539 * sec_asn1e_contents_length, we pass PR_FALSE, because this
540 * function correctly calculates the length for children templates
541 * from that point on. Confused yet? At least you didn't have
542 * to figure it out. ;) -javi
544 encode_kind
= theTemplate
->kind
;
546 universal
= ((encode_kind
& SEC_ASN1_CLASS_MASK
) == SEC_ASN1_UNIVERSAL
) ? PR_TRUE
: PR_FALSE
;
548 explicit = (encode_kind
& SEC_ASN1_EXPLICIT
) ? PR_TRUE
: PR_FALSE
;
549 encode_kind
&= ~SEC_ASN1_EXPLICIT
;
551 optional
= (encode_kind
& SEC_ASN1_OPTIONAL
) ? PR_TRUE
: PR_FALSE
;
552 encode_kind
&= ~SEC_ASN1_OPTIONAL
;
554 PORT_Assert(!(explicit && universal
)); /* bad templates */
556 may_stream
= (encode_kind
& SEC_ASN1_MAY_STREAM
) ? PR_TRUE
: PR_FALSE
;
557 encode_kind
&= ~SEC_ASN1_MAY_STREAM
;
559 /* Just clear this to get it out of the way; we do not need it here */
560 encode_kind
&= ~SEC_ASN1_DYNAMIC
;
562 if (encode_kind
& SEC_ASN1_NO_STREAM
) {
563 ignoresubstream
= PR_TRUE
;
565 encode_kind
&= ~SEC_ASN1_NO_STREAM
;
567 if (encode_kind
& SEC_ASN1_CHOICE
) {
569 int indx
= sec_asn1e_which_choice(src
, theTemplate
);
571 /* XXX set an error? "choice not found" */
572 /* state->top->status = encodeError; */
576 src2
= (void *)((char *)src
- theTemplate
->offset
+ theTemplate
[indx
].offset
);
578 return sec_asn1e_contents_length(&theTemplate
[indx
], src2
,
579 ignoresubstream
, insideIndefinite
,
583 if ((encode_kind
& (SEC_ASN1_POINTER
| SEC_ASN1_INLINE
)) || !universal
) {
585 /* XXX any bits we want to disallow (PORT_Assert against) here? */
587 theTemplate
= SEC_ASN1GetSubtemplate(theTemplate
, src
, PR_TRUE
,
588 NULL
/* __APPLE__ */, 0 /* __APPLE__ */);
590 if (encode_kind
& SEC_ASN1_POINTER
) {
592 * XXX This used to PORT_Assert (encode_kind == SEC_ASN1_POINTER);
593 * but that was too restrictive. This needs to be fixed,
594 * probably copying what the decoder now checks for, and
595 * adding a big comment here to explain what the checks mean.
596 * Alternatively, the check here could be omitted altogether
597 * just letting sec_asn1e_init_state_based_on_template
598 * do it, since that routine can do better error handling, too.
602 *pHdrException
= optional
? hdr_optional
: hdr_normal
;
605 } else if (encode_kind
& SEC_ASN1_INLINE
) {
606 /* check that there are no extraneous bits */
607 PORT_Assert (encode_kind
== SEC_ASN1_INLINE
&& !optional
);
610 src
= (char *)src
+ theTemplate
->offset
;
612 len
= sec_asn1e_contents_length(theTemplate
, src
,
613 ignoresubstream
, insideIndefinite
,
615 if (len
== 0 && optional
) {
616 *pHdrException
= hdr_optional
;
617 } else if (explicit) {
618 if (*pHdrException
== hdr_any
) {
619 /* *we* do not want to add in a header,
620 ** but our caller still does.
622 *pHdrException
= hdr_normal
;
623 } else if (*pHdrException
== hdr_normal
) {
624 /* if the inner content exists, our length is
625 * len(identifier) + len(length) + len(innercontent)
626 * XXX we currently assume len(identifier) == 1;
627 * to support a high-tag-number this would need to be smarter.
629 len
+= 1 + SEC_ASN1LengthLength(len
);
635 underlying_kind
= encode_kind
;
638 signedInt
= (underlying_kind
& SEC_ASN1_SIGNED_INT
) ?
642 /* This is only used in decoding; it plays no part in encoding. */
643 if (underlying_kind
& SEC_ASN1_SAVE
) {
644 /* check that there are no extraneous bits */
645 PORT_Assert (underlying_kind
== SEC_ASN1_SAVE
);
646 *pHdrException
= hdr_decoder
;
650 /* Having any of these bits is not expected here... */
651 PORT_Assert ((underlying_kind
& (SEC_ASN1_EXPLICIT
| SEC_ASN1_OPTIONAL
652 | SEC_ASN1_INLINE
| SEC_ASN1_POINTER
653 | SEC_ASN1_DYNAMIC
| SEC_ASN1_MAY_STREAM
654 | SEC_ASN1_SAVE
| SEC_ASN1_SKIP
)) == 0);
656 if (underlying_kind
& SEC_ASN1_CHOICE
) {
658 int indx
= sec_asn1e_which_choice(src
, theTemplate
);
660 /* XXX set an error? "choice not found" */
661 /* state->top->status = encodeError; */
665 src2
= (void *)((char *)src
- theTemplate
->offset
+ theTemplate
[indx
].offset
);
666 len
= sec_asn1e_contents_length(&theTemplate
[indx
], src2
, ignoresubstream
,
667 insideIndefinite
, pHdrException
);
669 switch (underlying_kind
) {
670 case SEC_ASN1_SEQUENCE_OF
:
671 case SEC_ASN1_SET_OF
: {
672 const SecAsn1Template
*tmpt
;
674 unsigned long sub_len
;
679 group
= *(void ***)src
;
684 tmpt
= SEC_ASN1GetSubtemplate(theTemplate
, src
, PR_TRUE
,
685 NULL
/* __APPLE__ */, 0 /* __APPLE__ */);
687 for (; *group
!= NULL
; group
++) {
688 sub_src
= (char *)(*group
) + tmpt
->offset
;
689 sub_len
= sec_asn1e_contents_length(tmpt
, sub_src
, ignoresubstream
,
690 insideIndefinite
, pHdrException
);
693 * XXX The 1 below is the presumed length of the identifier;
694 * to support a high-tag-number this would need to be smarter.
696 if (*pHdrException
== hdr_normal
) {
697 len
+= 1 + SEC_ASN1LengthLength(sub_len
);
703 case SEC_ASN1_SEQUENCE
:
705 const SecAsn1Template
*tmpt
;
707 unsigned long sub_len
;
710 for (tmpt
= theTemplate
+ 1; tmpt
->kind
; tmpt
++) {
711 sub_src
= (char *)src
+ tmpt
->offset
;
712 sub_len
= sec_asn1e_contents_length(tmpt
, sub_src
, ignoresubstream
,
713 insideIndefinite
, pHdrException
);
716 * XXX The 1 below is the presumed length of the identifier;
717 * to support a high-tag-number this would need to be smarter.
719 if (*pHdrException
== hdr_normal
) {
720 len
+= 1 + SEC_ASN1LengthLength (sub_len
);
726 case SEC_ASN1_BIT_STRING
:
727 /* convert bit length to byte */
728 len
= (((SecAsn1Item
*)src
)->Length
+ 7) >> 3;
729 /* bit string contents involve an extra octet */
735 case SEC_ASN1_INTEGER
: {
736 /* ASN.1 INTEGERs are signed.
737 * If the source is an unsigned integer, the encoder will need
738 * to handle the conversion here.
740 unsigned char *buf
= ((SecAsn1Item
*)src
)->Data
;
742 SecAsn1ItemType integerType
= ((SecAsn1Item
*)src
)->type
;
744 len
= ((SecAsn1Item
*)src
)->Length
;
748 if (*buf
& 0x80 && !signedInt
)
750 if (*buf
& 0x80 && integerType
== siUnsignedInteger
)
753 len
++; /* leading zero needed to make number signed */
755 break; /* reached beginning of number */
758 break; /* the number 0 */
761 break; /* leading zero already present */
763 /* extraneous leading zero, keep going */
771 len
= ((SecAsn1Item
*)src
)->Length
;
775 #ifndef WHAT_PROBLEM_DOES_THIS_SOLVE
776 /* if we're streaming, we may have a secitem w/len 0 as placeholder */
777 if (!len
&& insideIndefinite
&& may_stream
&& !ignoresubstream
) {
783 if (len
== 0 && optional
)
784 *pHdrException
= hdr_optional
;
785 else if (underlying_kind
== SEC_ASN1_ANY
)
786 *pHdrException
= hdr_any
;
788 *pHdrException
= hdr_normal
;
795 sec_asn1e_write_header(sec_asn1e_state
*state
)
797 unsigned long contents_length
;
798 unsigned char tag_number
, tag_modifiers
;
799 sec_asn1e_hdr_encoding hdrException
= hdr_normal
;
800 PRBool indefinite
= PR_FALSE
;
802 PORT_Assert (state
->place
== beforeHeader
);
804 tag_number
= state
->tag_number
;
805 tag_modifiers
= state
->tag_modifiers
;
807 if (state
->underlying_kind
== SEC_ASN1_ANY
) {
808 state
->place
= duringContents
;
812 if (state
->underlying_kind
& SEC_ASN1_CHOICE
) {
813 int indx
= sec_asn1e_which_choice(state
->src
, state
->theTemplate
);
815 /* XXX set an error? "choice not found" */
816 state
->top
->status
= encodeError
;
820 state
->place
= afterChoice
;
821 state
= sec_asn1e_push_state(state
->top
, &state
->theTemplate
[indx
],
822 (char *)state
->src
- state
->theTemplate
->offset
,
827 * Do the "before" field notification.
829 sec_asn1e_notify_before (state
->top
, state
->src
, state
->depth
);
830 (void)sec_asn1e_init_state_based_on_template (state
);
835 /* The !isString test below is apparently intended to ensure that all
836 ** constructed types receive indefinite length encoding.
838 indefinite
= (PRBool
)(state
->top
->streaming
&& state
->may_stream
&&
839 (state
->top
->from_buf
|| !state
->is_string
));
842 * If we are doing a definite-length encoding, first we have to
843 * walk the data structure to calculate the entire contents length.
844 * If we are doing an indefinite-length encoding, we still need to
845 * know if the contents is:
846 * optional and to be omitted, or
847 * an ANY (header is pre-encoded), or
848 * a SAVE or some other kind of template used only by the decoder.
849 * So, we call this function either way.
851 contents_length
= sec_asn1e_contents_length(state
->theTemplate
,
853 state
->ignore_stream
,
857 * We might be told explicitly not to put out a header.
858 * But it can also be the case, via a pushed subtemplate, that
859 * sec_asn1e_contents_length could not know that this field is
860 * really optional. So check for that explicitly, too.
862 if (hdrException
!= hdr_normal
||
863 (contents_length
== 0 && state
->optional
)) {
864 state
->place
= afterContents
;
865 if (state
->top
->streaming
&&
867 state
->top
->from_buf
) {
868 /* we did not find an optional indefinite string, so we
869 * don't encode it. However, if TakeFromBuf is on, we stop
870 * here anyway to give our caller a chance to intercept at the
871 * same point where we would stop if the field were present.
873 state
->top
->status
= needBytes
;
880 * We need to put out an indefinite-length encoding.
881 * The only universal types that can be constructed are SETs,
882 * SEQUENCEs, and strings; so check that it is one of those,
883 * or that it is not universal (e.g. context-specific).
885 state
->indefinite
= PR_TRUE
;
886 PORT_Assert ((tag_number
== SEC_ASN1_SET
)
887 || (tag_number
== SEC_ASN1_SEQUENCE
)
888 || ((tag_modifiers
& SEC_ASN1_CLASS_MASK
) != 0)
889 || state
->is_string
);
890 tag_modifiers
|= SEC_ASN1_CONSTRUCTED
;
894 sec_asn1e_write_identifier_bytes(state
, (unsigned char)(tag_number
| tag_modifiers
));
895 sec_asn1e_write_length_bytes(state
, contents_length
, state
->indefinite
);
897 if (contents_length
== 0 && !state
->indefinite
) {
899 * If no real contents to encode, then we are done with this field.
901 state
->place
= afterContents
;
906 * An EXPLICIT is nothing but an outer header, which we have already
907 * written. Now we need to do the inner header and contents.
909 if (state
->explicit) {
910 state
->place
= afterContents
;
911 const SecAsn1Template
*subt
= SEC_ASN1GetSubtemplate(state
->theTemplate
, state
->src
, PR_TRUE
,
912 NULL
/* __APPLE__ */, 0 /* __APPLE__ */);
913 state
= sec_asn1e_push_state(state
->top
, subt
, state
->src
, PR_TRUE
);
915 (void)sec_asn1e_init_state_based_on_template(state
);
920 switch (state
->underlying_kind
) {
921 case SEC_ASN1_SET_OF
:
922 case SEC_ASN1_SEQUENCE_OF
: {
924 * We need to push a child to handle each member.
927 const SecAsn1Template
*subt
;
929 group
= *(void ***)state
->src
;
930 if (group
== NULL
|| *group
== NULL
) {
932 * Group is empty; we are done.
934 state
->place
= afterContents
;
937 state
->place
= duringGroup
;
938 subt
= SEC_ASN1GetSubtemplate(state
->theTemplate
, state
->src
,
939 PR_TRUE
, NULL
/* __APPLE__ */, 0 /* __APPLE__ */);
940 state
= sec_asn1e_push_state(state
->top
, subt
, *group
, PR_TRUE
);
942 (void)sec_asn1e_init_state_based_on_template(state
);
947 case SEC_ASN1_SEQUENCE
:
950 * We need to push a child to handle the individual fields.
952 state
->place
= duringSequence
;
953 state
= sec_asn1e_push_state(state
->top
, state
->theTemplate
+ 1,
954 state
->src
, PR_TRUE
);
957 * Do the "before" field notification.
959 sec_asn1e_notify_before(state
->top
, state
->src
, state
->depth
);
960 (void)sec_asn1e_init_state_based_on_template(state
);
966 * I think we do not need to do anything else.
969 state
->place
= duringContents
;
976 sec_asn1e_write_contents_from_buf(sec_asn1e_state
*state
,
977 const char *buf
, unsigned long len
)
979 PORT_Assert(state
->place
== duringContents
);
980 PORT_Assert(state
->top
->from_buf
);
981 PORT_Assert(state
->may_stream
&& !state
->ignore_stream
);
984 * Probably they just turned on "take from buf", but have not
985 * yet given us any bytes. If there is nothing in the buffer
986 * then we have nothing to do but return and wait.
988 if (buf
== NULL
|| len
== 0) {
989 state
->top
->status
= needBytes
;
993 * We are streaming, reading from a passed-in buffer.
994 * This means we are encoding a simple string or an ANY.
995 * For the former, we need to put out a substring, with its
996 * own identifier and length. For an ANY, we just write it
997 * out as is (our caller is required to ensure that it
998 * is a properly encoded entity).
1000 PORT_Assert(state
->is_string
); /* includes ANY */
1001 if (state
->underlying_kind
!= SEC_ASN1_ANY
) {
1002 unsigned char identifier
;
1005 * Create the identifier based on underlying_kind. We cannot
1006 * use tag_number and tag_modifiers because this can be an
1007 * implicitly encoded field. In that case, the underlying
1008 * substrings *are* encoded with their real tag.
1010 identifier
= (unsigned char)(state
->underlying_kind
& SEC_ASN1_TAG_MASK
);
1012 * The underlying kind should just be a simple string; there
1013 * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
1015 PORT_Assert((identifier
& SEC_ASN1_TAGNUM_MASK
) == identifier
);
1017 * Write out the tag and length for the substring.
1019 sec_asn1e_write_identifier_bytes(state
, identifier
);
1020 if (state
->underlying_kind
== SEC_ASN1_BIT_STRING
) {
1023 * Assume we have a length in bytes but we need to output
1024 * a proper bit string. This interface only works for bit
1025 * strings that are full multiples of 8. If support for
1026 * real, variable length bit strings is needed then the
1027 * caller will have to know to pass in a bit length instead
1028 * of a byte length and then this code will have to
1029 * perform the encoding necessary (length written is length
1030 * in bytes plus 1, and the first octet of string is the
1031 * number of bits remaining between the end of the bit
1032 * string and the next byte boundary).
1034 sec_asn1e_write_length_bytes(state
, len
+ 1, PR_FALSE
);
1036 sec_asn1e_write_contents_bytes(state
, &byte
, 1);
1038 sec_asn1e_write_length_bytes(state
, len
, PR_FALSE
);
1041 sec_asn1e_write_contents_bytes(state
, buf
, len
);
1042 state
->top
->status
= needBytes
;
1046 sec_asn1e_write_contents(sec_asn1e_state
*state
)
1048 unsigned long len
= 0;
1050 PORT_Assert(state
->place
== duringContents
);
1051 switch (state
->underlying_kind
) {
1053 case SEC_ASN1_SEQUENCE
:
1057 case SEC_ASN1_BIT_STRING
: {
1061 item
= (SecAsn1Item
*)state
->src
;
1062 len
= (item
->Length
+ 7) >> 3;
1063 rem
= (unsigned char)((len
<< 3) - item
->Length
); /* remaining bits */
1064 sec_asn1e_write_contents_bytes(state
, &rem
, 1);
1065 sec_asn1e_write_contents_bytes(state
, (char *) item
->Data
, len
);
1069 case SEC_ASN1_BMP_STRING
:
1070 /* The number of bytes must be divisable by 2 */
1071 if ((((SecAsn1Item
*)state
->src
)->Length
) % 2) {
1072 SEC_ASN1EncoderContext
*cx
;
1075 cx
->status
= encodeError
;
1078 /* otherwise, fall through to write the content */
1079 goto process_string
;
1081 case SEC_ASN1_UNIVERSAL_STRING
:
1082 /* The number of bytes must be divisable by 4 */
1083 if ((((SecAsn1Item
*)state
->src
)->Length
) % 4) {
1084 SEC_ASN1EncoderContext
*cx
;
1087 cx
->status
= encodeError
;
1090 /* otherwise, fall through to write the content */
1091 goto process_string
;
1093 case SEC_ASN1_INTEGER
: {
1094 /* ASN.1 INTEGERs are signed. If the source is an unsigned
1095 * integer, the encoder will need to handle the conversion here.
1098 unsigned char *intbuf
;
1100 PRBool signedInt
= state
->signedInt
;
1102 SECItemType integerType
= ((SecAsn1Item
*)state
->src
)->type
;
1104 blen
= ((SecAsn1Item
*)state
->src
)->Length
;
1105 intbuf
= ((SecAsn1Item
*)state
->src
)->Data
;
1108 if (*intbuf
& 0x80 && !signedInt
)
1110 if (*intbuf
& 0x80 && integerType
== siUnsignedInteger
)
1113 char zero
= 0; /* write a leading 0 */
1114 sec_asn1e_write_contents_bytes(state
, &zero
, 1);
1115 /* and then the remaining buffer */
1116 sec_asn1e_write_contents_bytes(state
, (char *)intbuf
, blen
);
1119 /* Check three possibilities:
1120 * 1. No leading zeros, msb of MSB is not 1;
1121 * 2. The number is zero itself;
1122 * 3. Encoding a signed integer with a leading zero,
1123 * keep the zero so that the number is positive.
1128 (intbuf
[1] & 0x80 && signedInt
) )
1130 (intbuf
[1] & 0x80 && integerType
!= siUnsignedInteger
) )
1133 sec_asn1e_write_contents_bytes(state
, (char *)intbuf
, blen
);
1136 /* byte is 0, continue */
1141 /* done with this content */
1149 item
= (SecAsn1Item
*)state
->src
;
1150 sec_asn1e_write_contents_bytes(state
, (char *) item
->Data
, item
->Length
);
1154 state
->place
= afterContents
;
1159 * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
1162 sec_asn1e_next_in_group(sec_asn1e_state
*state
)
1164 sec_asn1e_state
*child
;
1168 PORT_Assert(state
->place
== duringGroup
);
1169 PORT_Assert(state
->child
!= NULL
);
1171 child
= state
->child
;
1173 group
= *(void ***)state
->src
;
1176 * Find placement of current item.
1178 member
= (char *)(state
->child
->src
) - child
->theTemplate
->offset
;
1179 while (*group
!= member
) {
1184 * Move forward to next item.
1187 if (*group
== NULL
) {
1189 * That was our last one; we are done now.
1191 child
->place
= notInUse
;
1192 state
->place
= afterContents
;
1195 child
->src
= (char *)(*group
) + child
->theTemplate
->offset
;
1200 sec_asn1e_scrub_state(child
);
1201 state
->top
->current
= child
;
1206 * We are moving along through a sequence; move forward by one,
1207 * (detecting end-of-sequence when it happens).
1210 sec_asn1e_next_in_sequence(sec_asn1e_state
*state
)
1212 sec_asn1e_state
*child
;
1214 PORT_Assert(state
->place
== duringSequence
);
1215 PORT_Assert(state
->child
!= NULL
);
1217 child
= state
->child
;
1220 * Do the "after" field notification.
1222 sec_asn1e_notify_after(state
->top
, child
->src
, child
->depth
);
1227 child
->theTemplate
++;
1228 if (child
->theTemplate
->kind
== 0) {
1230 * We are done with this sequence.
1232 child
->place
= notInUse
;
1233 state
->place
= afterContents
;
1238 * Reset state and push.
1241 child
->src
= (char *)state
->src
+ child
->theTemplate
->offset
;
1244 * Do the "before" field notification.
1246 sec_asn1e_notify_before(state
->top
, child
->src
, child
->depth
);
1248 state
->top
->current
= child
;
1249 (void)sec_asn1e_init_state_based_on_template(child
);
1254 sec_asn1e_after_contents (sec_asn1e_state
*state
)
1256 PORT_Assert(state
->place
== afterContents
);
1258 if (state
->indefinite
) {
1259 sec_asn1e_write_end_of_contents_bytes(state
);
1263 * Just make my parent be the current state. It will then clean
1264 * up after me and free me (or reuse me).
1266 state
->top
->current
= state
->parent
;
1271 * This function is called whether or not we are streaming; if we
1272 * *are* streaming, our caller can also instruct us to take bytes
1273 * from the passed-in buffer (at buf, for length len, which is likely
1274 * bytes but could even mean bits if the current field is a bit string).
1275 * If we have been so instructed, we will gobble up bytes from there
1276 * (rather than from our src structure) and output them, and then
1277 * we will just return, expecting to be called again -- either with
1278 * more bytes or after our caller has instructed us that we are done
1279 * (for now) with the buffer.
1282 SEC_ASN1EncoderUpdate(SEC_ASN1EncoderContext
*cx
,
1283 const char *buf
, unsigned long len
)
1285 sec_asn1e_state
*state
;
1287 if (cx
->status
== needBytes
) {
1288 PORT_Assert(buf
!= NULL
&& len
!= 0);
1289 cx
->status
= keepGoing
;
1292 while (cx
->status
== keepGoing
) {
1293 state
= cx
->current
;
1294 switch (state
->place
) {
1296 sec_asn1e_write_header(state
);
1298 case duringContents
:
1300 sec_asn1e_write_contents_from_buf(state
, buf
, len
);
1302 sec_asn1e_write_contents(state
);
1305 sec_asn1e_next_in_group(state
);
1307 case duringSequence
:
1308 sec_asn1e_next_in_sequence(state
);
1311 sec_asn1e_after_contents(state
);
1318 * These states are more documentation than anything.
1319 * They just need to force a pop.
1321 PORT_Assert(!state
->indefinite
);
1322 state
->place
= afterContents
;
1326 /* This is not an error, but rather a plain old BUG! */
1328 cx
->status
= encodeError
;
1332 if (cx
->status
== encodeError
) {
1336 /* It might have changed, so we have to update our local copy. */
1337 state
= cx
->current
;
1339 /* If it is NULL, we have popped all the way to the top. */
1340 if (state
== NULL
) {
1341 cx
->status
= allDone
;
1346 if (cx
->status
== encodeError
) {
1355 SEC_ASN1EncoderFinish(SEC_ASN1EncoderContext
*cx
)
1358 * XXX anything else that needs to be finished?
1361 PORT_FreeArena(cx
->our_pool
, PR_FALSE
);
1365 SEC_ASN1EncoderContext
*
1366 SEC_ASN1EncoderStart(const void *src
, const SecAsn1Template
*theTemplate
,
1367 SEC_ASN1WriteProc output_proc
, void *output_arg
)
1369 PRArenaPool
*our_pool
;
1370 SEC_ASN1EncoderContext
*cx
;
1372 our_pool
= PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE
);
1373 if (our_pool
== NULL
) {
1377 cx
= (SEC_ASN1EncoderContext
*)PORT_ArenaZAlloc(our_pool
, sizeof(*cx
));
1379 PORT_FreeArena(our_pool
, PR_FALSE
);
1383 cx
->our_pool
= our_pool
;
1384 cx
->output_proc
= output_proc
;
1385 cx
->output_arg
= output_arg
;
1387 cx
->status
= keepGoing
;
1389 if (sec_asn1e_push_state(cx
, theTemplate
, src
, PR_FALSE
) == NULL
1390 || sec_asn1e_init_state_based_on_template(cx
->current
) == NULL
) {
1392 * Trouble initializing (probably due to failed allocations)
1393 * requires that we just give up.
1395 PORT_FreeArena (our_pool
,PR_FALSE
);
1404 * XXX Do we need a FilterProc, too?
1409 SEC_ASN1EncoderSetNotifyProc(SEC_ASN1EncoderContext
*cx
,
1410 SEC_ASN1NotifyProc fn
, void *arg
)
1412 cx
->notify_proc
= fn
;
1413 cx
->notify_arg
= arg
;
1418 SEC_ASN1EncoderClearNotifyProc(SEC_ASN1EncoderContext
*cx
)
1420 cx
->notify_proc
= NULL
;
1421 cx
->notify_arg
= NULL
; /* not necessary; just being clean */
1426 SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext
*cx
, int error
)
1429 PORT_SetError(error
);
1430 cx
->status
= encodeError
;
1435 SEC_ASN1EncoderSetStreaming(SEC_ASN1EncoderContext
*cx
)
1437 /* XXX is there a way to check that we are "between" fields here? */
1439 cx
->streaming
= PR_TRUE
;
1444 SEC_ASN1EncoderClearStreaming(SEC_ASN1EncoderContext
*cx
)
1446 /* XXX is there a way to check that we are "between" fields here? */
1448 cx
->streaming
= PR_FALSE
;
1453 SEC_ASN1EncoderSetTakeFromBuf(SEC_ASN1EncoderContext
*cx
)
1456 * XXX is there a way to check that we are "between" fields here? this
1457 * needs to include a check for being in between groups of items in
1458 * a SET_OF or SEQUENCE_OF.
1460 PORT_Assert(cx
->streaming
);
1461 cx
->from_buf
= PR_TRUE
;
1466 SEC_ASN1EncoderClearTakeFromBuf(SEC_ASN1EncoderContext
*cx
)
1468 /* we should actually be taking from buf *now* */
1469 PORT_Assert (cx
->from_buf
);
1470 if (! cx
->from_buf
) { /* if not, just do nothing */
1474 cx
->from_buf
= PR_FALSE
;
1476 if (cx
->status
== needBytes
) {
1477 cx
->status
= keepGoing
;
1478 cx
->current
->place
= afterContents
;
1484 SEC_ASN1Encode(const void *src
, const SecAsn1Template
*theTemplate
,
1485 SEC_ASN1WriteProc output_proc
, void *output_arg
)
1487 SEC_ASN1EncoderContext
*ecx
;
1490 ecx
= SEC_ASN1EncoderStart(src
, theTemplate
, output_proc
, output_arg
);
1495 rv
= SEC_ASN1EncoderUpdate(ecx
, NULL
, 0);
1497 SEC_ASN1EncoderFinish(ecx
);
1503 * XXX depth and data_kind are unused; is there a PC way to silence warnings?
1504 * (I mean "politically correct", not anything to do with intel/win platform)
1507 sec_asn1e_encode_item_count(void *arg
, const char *buf
, size_t len
,
1508 int depth
, SEC_ASN1EncodingPart data_kind
)
1512 count
= (unsigned long*)arg
;
1513 PORT_Assert(count
!= NULL
);
1519 /* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
1521 sec_asn1e_encode_item_store(void *arg
, const char *buf
, size_t len
,
1522 int depth
, SEC_ASN1EncodingPart data_kind
)
1526 dest
= (SecAsn1Item
*)arg
;
1527 PORT_Assert(dest
!= NULL
);
1530 PORT_Memcpy(dest
->Data
+ dest
->Length
, buf
, len
);
1531 dest
->Length
+= len
;
1537 * Allocate an entire SecAsn1Item, or just the data part of it, to hold
1538 * "len" bytes of stuff. Allocate from the given pool, if specified,
1539 * otherwise just do a vanilla PORT_Alloc.
1541 * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
1544 sec_asn1e_allocate_item(PRArenaPool
*poolp
, SecAsn1Item
*dest
, unsigned long len
)
1546 if (poolp
!= NULL
) {
1549 release
= PORT_ArenaMark(poolp
);
1551 dest
= (SecAsn1Item
*)PORT_ArenaAlloc(poolp
, sizeof(SecAsn1Item
));
1554 dest
->Data
= (unsigned char*)PORT_ArenaAlloc(poolp
, len
);
1555 if (dest
->Data
== NULL
) {
1560 /* one or both allocations failed; release everything */
1561 PORT_ArenaRelease(poolp
, release
);
1563 /* everything okay; unmark the arena */
1564 PORT_ArenaUnmark(poolp
, release
);
1567 SecAsn1Item
*indest
;
1571 dest
= (SecAsn1Item
*)PORT_Alloc(sizeof(SecAsn1Item
));
1575 dest
->type
= siBuffer
;
1577 dest
->Data
= (unsigned char*)PORT_Alloc(len
);
1578 if (dest
->Data
== NULL
) {
1579 if (indest
== NULL
) {
1592 SEC_ASN1EncodeItem(PRArenaPool
*poolp
, SecAsn1Item
*dest
, const void *src
,
1593 const SecAsn1Template
*theTemplate
)
1595 unsigned long encoding_length
;
1598 PORT_Assert(dest
== NULL
|| dest
->Data
== NULL
);
1600 encoding_length
= 0;
1601 rv
= SEC_ASN1Encode(src
, theTemplate
,
1602 sec_asn1e_encode_item_count
, &encoding_length
);
1603 if (rv
!= SECSuccess
) {
1607 dest
= sec_asn1e_allocate_item(poolp
, dest
, encoding_length
);
1612 /* XXX necessary? This really just checks for a bug in the allocate fn */
1613 PORT_Assert(dest
->Data
!= NULL
);
1614 if (dest
->Data
== NULL
) {
1619 (void)SEC_ASN1Encode(src
, theTemplate
, sec_asn1e_encode_item_store
, dest
);
1621 PORT_Assert(encoding_length
== dest
->Length
);
1626 static SecAsn1Item
*
1627 sec_asn1e_integer(PRArenaPool
*poolp
, SecAsn1Item
*dest
, unsigned long value
,
1628 PRBool make_unsigned
)
1635 * Determine the length of the encoded value (minimum of 1).
1640 sign
= (unsigned char)(copy
& 0x80);
1645 * If this is an unsigned encoding, and the high bit of the last
1646 * byte we counted was set, we need to add one to the length so
1647 * we put a high-order zero byte in the encoding.
1649 if (sign
&& make_unsigned
) {
1654 * Allocate the item (if necessary) and the data pointer within.
1656 dest
= sec_asn1e_allocate_item(poolp
, dest
, len
);
1662 * Store the value, byte by byte, in the item.
1666 dest
->Data
[--len
] = (unsigned char)value
;
1669 PORT_Assert(value
== 0);
1676 SEC_ASN1EncodeInteger(PRArenaPool
*poolp
, SecAsn1Item
*dest
, long value
)
1678 return sec_asn1e_integer(poolp
, dest
, (unsigned long) value
, PR_FALSE
);
1682 extern SecAsn1Item
*
1683 SEC_ASN1EncodeUnsignedInteger(PRArenaPool
*poolp
,
1684 SecAsn1Item
*dest
, unsigned long value
)
1686 return sec_asn1e_integer(poolp
, dest
, value
, PR_TRUE
);