]> git.saurik.com Git - apple/security.git/blame_incremental - libsecurity_asn1/lib/secasn1e.c
Security-55471.14.18.tar.gz
[apple/security.git] / libsecurity_asn1 / lib / secasn1e.c
... / ...
CommitLineData
1/*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is the Netscape security libraries.
13 *
14 * The Initial Developer of the Original Code is Netscape
15 * Communications Corporation. Portions created by Netscape are
16 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
17 * Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU General Public License Version 2 or later (the
23 * "GPL"), in which case the provisions of the GPL are applicable
24 * instead of those above. If you wish to allow use of your
25 * version of this file only under the terms of the GPL and not to
26 * allow others to use your version of this file under the MPL,
27 * indicate your decision by deleting the provisions above and
28 * replace them with the notice and other provisions required by
29 * the GPL. If you do not delete the provisions above, a recipient
30 * may use your version of this file under either the MPL or the
31 * GPL.
32 */
33
34/*
35 * Support for ENcoding ASN.1 data based on BER/DER (Basic/Distinguished
36 * Encoding Rules).
37 *
38 * $Id: secasn1e.c,v 1.7 2004/05/13 15:29:13 dmitch Exp $
39 */
40
41#include "secasn1.h"
42
43typedef enum {
44 beforeHeader,
45 duringContents,
46 duringGroup,
47 duringSequence,
48 afterContents,
49 afterImplicit,
50 afterInline,
51 afterPointer,
52 afterChoice,
53 notInUse
54} sec_asn1e_parse_place;
55
56typedef enum {
57 allDone,
58 encodeError,
59 keepGoing,
60 needBytes
61} sec_asn1e_parse_status;
62
63typedef struct sec_asn1e_state_struct {
64 SEC_ASN1EncoderContext *top;
65 const SecAsn1Template *theTemplate;
66 void *src;
67
68 struct sec_asn1e_state_struct *parent; /* aka prev */
69 struct sec_asn1e_state_struct *child; /* aka next */
70
71 sec_asn1e_parse_place place; /* where we are in encoding process */
72
73 /*
74 * XXX explain the next fields as clearly as possible...
75 */
76 unsigned char tag_modifiers;
77 unsigned char tag_number;
78 unsigned long underlying_kind;
79
80 int depth;
81
82 PRBool explicit, /* we are handling an explicit header */
83 indefinite, /* need end-of-contents */
84 is_string, /* encoding a simple string or an ANY */
85 may_stream, /* when streaming, do indefinite encoding */
86 optional, /* omit field if it has no contents */
87 ignore_stream /* ignore streaming value of sub-template */
88 #ifdef __APPLE__
89 ,
90 signedInt /* signed alternate to SEC_ASN1_INTEGER */
91 #endif
92 ;
93} sec_asn1e_state;
94
95/*
96 * An "outsider" will have an opaque pointer to this, created by calling
97 * SEC_ASN1EncoderStart(). It will be passed back in to all subsequent
98 * calls to SEC_ASN1EncoderUpdate() and related routines, and when done
99 * it is passed to SEC_ASN1EncoderFinish().
100 */
101struct sec_EncoderContext_struct {
102 PRArenaPool *our_pool; /* for our internal allocs */
103
104 sec_asn1e_state *current;
105 sec_asn1e_parse_status status;
106
107 PRBool streaming;
108 PRBool from_buf;
109
110 SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */
111 void *notify_arg; /* argument to notify_proc */
112 PRBool during_notify; /* true during call to notify_proc */
113
114 SEC_ASN1WriteProc output_proc; /* pass encoded bytes to this */
115 void *output_arg; /* argument to that function */
116};
117
118
119static sec_asn1e_state *
120sec_asn1e_push_state (SEC_ASN1EncoderContext *cx,
121 const SecAsn1Template *theTemplate,
122 const void *src, PRBool new_depth)
123{
124 sec_asn1e_state *state, *new_state;
125
126 state = cx->current;
127
128 new_state = (sec_asn1e_state*)PORT_ArenaZAlloc (cx->our_pool,
129 sizeof(*new_state));
130 if (new_state == NULL) {
131 cx->status = encodeError;
132 return NULL;
133 }
134
135 new_state->top = cx;
136 new_state->parent = state;
137 new_state->theTemplate = theTemplate;
138 new_state->place = notInUse;
139 if (src != NULL)
140 new_state->src = (char *)src + theTemplate->offset;
141
142 if (state != NULL) {
143 new_state->depth = state->depth;
144 if (new_depth)
145 new_state->depth++;
146 state->child = new_state;
147 }
148
149 cx->current = new_state;
150 return new_state;
151}
152
153
154static void
155sec_asn1e_scrub_state (sec_asn1e_state *state)
156{
157 /*
158 * Some default "scrubbing".
159 * XXX right set of initializations?
160 */
161 state->place = beforeHeader;
162 state->indefinite = PR_FALSE;
163}
164
165
166static void
167sec_asn1e_notify_before (SEC_ASN1EncoderContext *cx, void *src, int depth)
168{
169 if (cx->notify_proc == NULL)
170 return;
171
172 cx->during_notify = PR_TRUE;
173 (* cx->notify_proc) (cx->notify_arg, PR_TRUE, src, depth);
174 cx->during_notify = PR_FALSE;
175}
176
177
178static void
179sec_asn1e_notify_after (SEC_ASN1EncoderContext *cx, void *src, int depth)
180{
181 if (cx->notify_proc == NULL)
182 return;
183
184 cx->during_notify = PR_TRUE;
185 (* cx->notify_proc) (cx->notify_arg, PR_FALSE, src, depth);
186 cx->during_notify = PR_FALSE;
187}
188
189
190static sec_asn1e_state *
191sec_asn1e_init_state_based_on_template (sec_asn1e_state *state)
192{
193 PRBool explicit, is_string, may_stream, optional, universal, ignore_stream;
194 unsigned char tag_modifiers;
195 unsigned long encode_kind, under_kind;
196 unsigned long tag_number;
197 #ifdef __APPLE__
198 PRBool signedInt, dynamic;
199 #endif
200
201 encode_kind = state->theTemplate->kind;
202
203 universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
204 ? PR_TRUE : PR_FALSE;
205
206 explicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
207 encode_kind &= ~SEC_ASN1_EXPLICIT;
208
209 optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
210 encode_kind &= ~SEC_ASN1_OPTIONAL;
211
212 PORT_Assert (!(explicit && universal)); /* bad templates */
213
214 may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
215 encode_kind &= ~SEC_ASN1_MAY_STREAM;
216
217 ignore_stream = (encode_kind & SEC_ASN1_NO_STREAM) ? PR_TRUE : PR_FALSE;
218 encode_kind &= ~SEC_ASN1_NO_STREAM;
219
220 #ifdef __APPLE__
221 signedInt = (encode_kind & SEC_ASN1_SIGNED_INT) ? PR_TRUE : PR_FALSE;
222 encode_kind &= ~SEC_ASN1_SIGNED_INT;
223 #endif
224
225 #ifdef __APPLE__
226 dynamic = (encode_kind & SEC_ASN1_DYNAMIC) ? PR_TRUE : PR_FALSE;
227 #endif
228 encode_kind &= ~SEC_ASN1_DYNAMIC;
229
230 if( encode_kind & SEC_ASN1_CHOICE ) {
231 under_kind = SEC_ASN1_CHOICE;
232 } else
233
234 if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || (!universal
235 && !explicit)) {
236 const SecAsn1Template *subt;
237 void *src;
238
239 PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);
240
241 sec_asn1e_scrub_state (state);
242
243 if (encode_kind & SEC_ASN1_POINTER) {
244 /*
245 * XXX This used to PORT_Assert (encode_kind == SEC_ASN1_POINTER);
246 * but that was too restrictive. This needs to be fixed,
247 * probably copying what the decoder now checks for, and
248 * adding a big comment here to explain what the checks mean.
249 */
250 src = *(void **)state->src;
251 state->place = afterPointer;
252 if (src == NULL) {
253 /*
254 * If this is optional, but NULL, then the field does
255 * not need to be encoded. In this case we are done;
256 * we do not want to push a subtemplate.
257 */
258 if (optional)
259 return state;
260
261 /*
262 * XXX this is an error; need to figure out
263 * how to handle this
264 */
265 }
266 } else {
267 src = state->src;
268 if (encode_kind & SEC_ASN1_INLINE) {
269 /* check that there are no extraneous bits */
270 PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional);
271 state->place = afterInline;
272 } else {
273 /*
274 * Save the tag modifiers and tag number here before moving
275 * on to the next state in case this is a member of a
276 * SEQUENCE OF
277 */
278 state->tag_modifiers = (unsigned char)encode_kind & SEC_ASN1_TAG_MASK
279 & ~SEC_ASN1_TAGNUM_MASK;
280 state->tag_number = (unsigned char)encode_kind & SEC_ASN1_TAGNUM_MASK;
281
282 state->place = afterImplicit;
283 state->optional = optional;
284 }
285 }
286
287 subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src, PR_TRUE,
288 NULL /* __APPLE__ */);
289 state = sec_asn1e_push_state (state->top, subt, src, PR_FALSE);
290 if (state == NULL)
291 return NULL;
292
293 if (universal) {
294 /*
295 * This is a POINTER or INLINE; just init based on that
296 * and we are done.
297 */
298 return sec_asn1e_init_state_based_on_template (state);
299 }
300
301 /*
302 * This is an implicit, non-universal (meaning, application-private
303 * or context-specific) field. This results in a "magic" tag but
304 * encoding based on the underlying type. We pushed a new state
305 * that is based on the subtemplate (the underlying type), but
306 * now we will sort of alias it to give it some of our properties
307 * (tag, optional status, etc.).
308 */
309
310 under_kind = state->theTemplate->kind;
311 if (under_kind & SEC_ASN1_MAY_STREAM) {
312 if (!ignore_stream)
313 may_stream = PR_TRUE;
314 under_kind &= ~SEC_ASN1_MAY_STREAM;
315 }
316 } else {
317 under_kind = encode_kind;
318 }
319
320 /*
321 * Sanity check that there are no unwanted bits marked in under_kind.
322 * These bits were either removed above (after we recorded them) or
323 * they simply should not be found (signalling a bad/broken template).
324 * XXX is this the right set of bits to test here? (i.e. need to add
325 * or remove any?)
326 */
327 PORT_Assert ((under_kind & (/*SEC_ASN1_EXPLICIT | */SEC_ASN1_OPTIONAL
328 | SEC_ASN1_SKIP | SEC_ASN1_INNER
329 | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM
330 | SEC_ASN1_INLINE | SEC_ASN1_POINTER)) == 0);
331
332 if (encode_kind & SEC_ASN1_ANY) {
333 PORT_Assert (encode_kind == under_kind);
334 tag_modifiers = 0;
335 tag_number = 0;
336 is_string = PR_TRUE;
337 } else {
338 tag_modifiers = (unsigned char)encode_kind & SEC_ASN1_TAG_MASK &
339 ~SEC_ASN1_TAGNUM_MASK;
340 /*
341 * XXX This assumes only single-octet identifiers. To handle
342 * the HIGH TAG form we would need to do some more work, especially
343 * in how to specify them in the template, because right now we
344 * do not provide a way to specify more *tag* bits in encode_kind.
345 */
346
347 #ifdef __APPLE__
348 /*
349 * Apple change: if this is a DYNAMIC template, use the tag number
350 * from the subtemplate's kind
351 */
352 if(dynamic) {
353 tag_number = state->theTemplate->kind & SEC_ASN1_TAGNUM_MASK;
354 explicit = (state->theTemplate->kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
355 tag_modifiers |= (state->theTemplate->kind & SEC_ASN1_CONSTRUCTED);
356 }
357 else
358 #endif /* __APPLE__ */
359 tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
360
361 is_string = PR_FALSE;
362 switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
363 case SEC_ASN1_SET:
364 /*
365 * XXX A plain old SET (as opposed to a SET OF) is not implemented.
366 * If it ever is, remove this assert...
367 */
368 PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
369 /* fallthru */
370 case SEC_ASN1_SEQUENCE:
371 tag_modifiers |= SEC_ASN1_CONSTRUCTED;
372 break;
373 case SEC_ASN1_BIT_STRING:
374 case SEC_ASN1_BMP_STRING:
375 case SEC_ASN1_GENERALIZED_TIME:
376 case SEC_ASN1_IA5_STRING:
377 case SEC_ASN1_OCTET_STRING:
378 case SEC_ASN1_PRINTABLE_STRING:
379 case SEC_ASN1_T61_STRING:
380 case SEC_ASN1_UNIVERSAL_STRING:
381 case SEC_ASN1_UTC_TIME:
382 case SEC_ASN1_UTF8_STRING:
383 case SEC_ASN1_VISIBLE_STRING:
384 /*
385 * We do not yet know if we will be constructing the string,
386 * so we have to wait to do this final tag modification.
387 */
388 is_string = PR_TRUE;
389 break;
390 }
391 }
392
393 state->tag_modifiers = tag_modifiers;
394 state->tag_number = (unsigned char)tag_number;
395 state->underlying_kind = under_kind;
396 state->explicit = explicit;
397 state->may_stream = may_stream;
398 state->is_string = is_string;
399 state->optional = optional;
400 state->ignore_stream = ignore_stream;
401 #ifdef __APPLE__
402 state->signedInt = signedInt;
403 #endif
404
405 sec_asn1e_scrub_state (state);
406
407 return state;
408}
409
410
411static void
412sec_asn1e_write_part (sec_asn1e_state *state,
413 const char *buf, size_t len,
414 SEC_ASN1EncodingPart part)
415{
416 SEC_ASN1EncoderContext *cx;
417
418 cx = state->top;
419 (* cx->output_proc) (cx->output_arg, buf, len, state->depth, part);
420}
421
422
423/*
424 * XXX This assumes only single-octet identifiers. To handle
425 * the HIGH TAG form we would need to modify this interface and
426 * teach it to properly encode the special form.
427 */
428static void
429sec_asn1e_write_identifier_bytes (sec_asn1e_state *state, unsigned char value)
430{
431 char byte;
432
433 byte = (char) value;
434 sec_asn1e_write_part (state, &byte, 1, SEC_ASN1_Identifier);
435}
436
437int
438SEC_ASN1EncodeLength(unsigned char *buf,unsigned long value) {
439 int lenlen;
440
441 lenlen = SEC_ASN1LengthLength (value);
442 if (lenlen == 1) {
443 buf[0] = value;
444 } else {
445 int i;
446
447 i = lenlen - 1;
448 buf[0] = 0x80 | i;
449 while (i) {
450 buf[i--] = value;
451 value >>= 8;
452 }
453 PORT_Assert (value == 0);
454 }
455 return lenlen;
456}
457
458static void
459sec_asn1e_write_length_bytes (sec_asn1e_state *state, unsigned long value,
460 PRBool indefinite)
461{
462 int lenlen;
463 unsigned char buf[sizeof(unsigned long) + 1];
464
465 if (indefinite) {
466 PORT_Assert (value == 0);
467 buf[0] = 0x80;
468 lenlen = 1;
469 } else {
470 lenlen = SEC_ASN1EncodeLength(buf,value);
471 }
472
473 sec_asn1e_write_part (state, (char *) buf, lenlen, SEC_ASN1_Length);
474}
475
476
477static void
478sec_asn1e_write_contents_bytes (sec_asn1e_state *state,
479 const char *buf, unsigned long len)
480{
481 sec_asn1e_write_part (state, buf, len, SEC_ASN1_Contents);
482}
483
484
485static void
486sec_asn1e_write_end_of_contents_bytes (sec_asn1e_state *state)
487{
488 const char eoc[2] = {0, 0};
489
490 sec_asn1e_write_part (state, eoc, 2, SEC_ASN1_EndOfContents);
491}
492
493static int
494sec_asn1e_which_choice
495(
496 void *src,
497 const SecAsn1Template *theTemplate
498)
499{
500 int rv;
501 unsigned int which = *(unsigned int *)src;
502
503 for( rv = 1, theTemplate++; theTemplate->kind != 0; rv++, theTemplate++ ) {
504 if( which == theTemplate->size ) {
505 return rv;
506 }
507 }
508
509 return 0;
510}
511
512static unsigned long
513sec_asn1e_contents_length (const SecAsn1Template *theTemplate, void *src,
514 PRBool ignoresubstream, PRBool *noheaderp)
515{
516 unsigned long encode_kind, underlying_kind;
517 PRBool explicit, optional, universal, may_stream;
518 unsigned long len;
519 #ifdef __APPLE__
520 PRBool signedInt;
521 #endif
522
523 /*
524 * This function currently calculates the length in all cases
525 * except the following: when writing out the contents of a
526 * template that belongs to a state where it was a sub-template
527 * with the SEC_ASN1_MAY_STREAM bit set and it's parent had the
528 * optional bit set. The information that the parent is optional
529 * and that we should return the length of 0 when that length is
530 * present since that means the optional field is no longer present.
531 * So we add the ignoresubstream flag which is passed in when
532 * writing the contents, but for all recursive calls to
533 * sec_asn1e_contents_length, we pass PR_FALSE, because this
534 * function correctly calculates the length for children templates
535 * from that point on. Confused yet? At least you didn't have
536 * to figure it out. ;) -javi
537 */
538 encode_kind = theTemplate->kind;
539
540 universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
541 ? PR_TRUE : PR_FALSE;
542
543 explicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
544 encode_kind &= ~SEC_ASN1_EXPLICIT;
545
546 optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
547 encode_kind &= ~SEC_ASN1_OPTIONAL;
548
549 PORT_Assert (!(explicit && universal)); /* bad templates */
550
551 may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
552 encode_kind &= ~SEC_ASN1_MAY_STREAM;
553
554 /* Just clear this to get it out of the way; we do not need it here */
555 encode_kind &= ~SEC_ASN1_DYNAMIC;
556 encode_kind &= ~SEC_ASN1_NO_STREAM;
557
558 if( encode_kind & SEC_ASN1_CHOICE ) {
559 void *src2;
560 int indx = sec_asn1e_which_choice(src, theTemplate);
561 if( 0 == indx ) {
562 /* XXX set an error? "choice not found" */
563 /* state->top->status = encodeError; */
564 return 0;
565 }
566
567 src2 = (void *)((char *)src - theTemplate->offset + theTemplate[indx].offset);
568
569 return sec_asn1e_contents_length(&theTemplate[indx], src2,
570 PR_FALSE, noheaderp);
571 }
572
573 if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || !universal) {
574
575 /* XXX any bits we want to disallow (PORT_Assert against) here? */
576
577 theTemplate = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE,
578 NULL /* __APPLE__ */);
579
580 if (encode_kind & SEC_ASN1_POINTER) {
581 /*
582 * XXX This used to PORT_Assert (encode_kind == SEC_ASN1_POINTER);
583 * but that was too restrictive. This needs to be fixed,
584 * probably copying what the decoder now checks for, and
585 * adding a big comment here to explain what the checks mean.
586 * Alternatively, the check here could be omitted altogether
587 * just letting sec_asn1e_init_state_based_on_template
588 * do it, since that routine can do better error handling, too.
589 */
590 src = *(void **)src;
591 if (src == NULL) {
592 if (optional)
593 *noheaderp = PR_TRUE;
594 else
595 *noheaderp = PR_FALSE;
596 return 0;
597 }
598 } else if (encode_kind & SEC_ASN1_INLINE) {
599 /* check that there are no extraneous bits */
600 PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional);
601 }
602
603 src = (char *)src + theTemplate->offset;
604
605 if (explicit) {
606 len = sec_asn1e_contents_length (theTemplate, src, PR_FALSE,
607 noheaderp);
608 if (len == 0 && optional) {
609 *noheaderp = PR_TRUE;
610 } else if (*noheaderp) {
611 /* Okay, *we* do not want to add in a header, but our caller still does. */
612 *noheaderp = PR_FALSE;
613 } else {
614 /* if the inner content exists, our length is
615 * len(identifier) + len(length) + len(innercontent)
616 * XXX we currently assume len(identifier) == 1;
617 * to support a high-tag-number this would need to be smarter.
618 */
619 len += 1 + SEC_ASN1LengthLength (len);
620 }
621 return len;
622 }
623
624 underlying_kind = theTemplate->kind;
625 underlying_kind &= ~SEC_ASN1_MAY_STREAM;
626 /* XXX Should we recurse here? */
627 } else {
628 underlying_kind = encode_kind;
629 }
630
631 #ifdef __APPLE__
632 signedInt = (underlying_kind & SEC_ASN1_SIGNED_INT) ?
633 PR_TRUE : PR_FALSE;
634 #endif
635
636 /* This is only used in decoding; it plays no part in encoding. */
637 if (underlying_kind & SEC_ASN1_SAVE) {
638 /* check that there are no extraneous bits */
639 PORT_Assert (underlying_kind == SEC_ASN1_SAVE);
640 *noheaderp = PR_TRUE;
641 return 0;
642 }
643
644 /* Having any of these bits is not expected here... */
645 PORT_Assert ((underlying_kind & (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL
646 | SEC_ASN1_INLINE | SEC_ASN1_POINTER
647 | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM
648 | SEC_ASN1_SAVE | SEC_ASN1_SKIP)) == 0);
649
650 if( underlying_kind & SEC_ASN1_CHOICE ) {
651 void *src2;
652 int indx = sec_asn1e_which_choice(src, theTemplate);
653 if( 0 == indx ) {
654 /* XXX set an error? "choice not found" */
655 /* state->top->status = encodeError; */
656 return 0;
657 }
658
659 src2 = (void *)((char *)src - theTemplate->offset + theTemplate[indx].offset);
660 len = sec_asn1e_contents_length(&theTemplate[indx], src2, PR_FALSE,
661 noheaderp);
662 } else
663
664 switch (underlying_kind) {
665 case SEC_ASN1_SEQUENCE_OF:
666 case SEC_ASN1_SET_OF:
667 {
668 const SecAsn1Template *tmpt;
669 void *sub_src;
670 unsigned long sub_len;
671 void **group;
672
673 len = 0;
674
675 group = *(void ***)src;
676 if (group == NULL)
677 break;
678
679 tmpt = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE,
680 NULL /* __APPLE__ */);
681
682 for (; *group != NULL; group++) {
683 sub_src = (char *)(*group) + tmpt->offset;
684 sub_len = sec_asn1e_contents_length (tmpt, sub_src, PR_FALSE,
685 noheaderp);
686 len += sub_len;
687 /*
688 * XXX The 1 below is the presumed length of the identifier;
689 * to support a high-tag-number this would need to be smarter.
690 */
691 if (!*noheaderp)
692 len += 1 + SEC_ASN1LengthLength (sub_len);
693 }
694 }
695 break;
696
697 case SEC_ASN1_SEQUENCE:
698 case SEC_ASN1_SET:
699 {
700 const SecAsn1Template *tmpt;
701 void *sub_src;
702 unsigned long sub_len;
703
704 len = 0;
705 for (tmpt = theTemplate + 1; tmpt->kind; tmpt++) {
706 sub_src = (char *)src + tmpt->offset;
707 sub_len = sec_asn1e_contents_length (tmpt, sub_src, PR_FALSE,
708 noheaderp);
709 len += sub_len;
710 /*
711 * XXX The 1 below is the presumed length of the identifier;
712 * to support a high-tag-number this would need to be smarter.
713 */
714 if (!*noheaderp)
715 len += 1 + SEC_ASN1LengthLength (sub_len);
716 }
717 }
718 break;
719
720 case SEC_ASN1_BIT_STRING:
721 /* convert bit length to byte */
722 len = (((SecAsn1Item *)src)->Length + 7) >> 3;
723 /* bit string contents involve an extra octet */
724 if (len)
725 len++;
726 break;
727
728 case SEC_ASN1_INTEGER:
729 /* ASN.1 INTEGERs are signed.
730 * If the source is an unsigned integer, the encoder will need
731 * to handle the conversion here.
732 */
733 {
734 unsigned char *buf = ((SecAsn1Item *)src)->Data;
735 #ifndef __APPLE__
736 SecAsn1ItemType integerType = ((SecAsn1Item *)src)->type;
737 #endif
738 len = ((SecAsn1Item *)src)->Length;
739 while (len > 0) {
740 if (*buf != 0) {
741 #ifdef __APPLE__
742 if (*buf & 0x80 && !signedInt) {
743 #else
744 if (*buf & 0x80 && integerType == siUnsignedInteger) {
745 #endif // __APPLE__
746 len++; /* leading zero needed to make number signed */
747 }
748 break; /* reached beginning of number */
749 }
750 if (len == 1) {
751 break; /* the number 0 */
752 }
753 if (buf[1] & 0x80) {
754 break; /* leading zero already present */
755 }
756 /* extraneous leading zero, keep going */
757 buf++;
758 len--;
759 }
760 }
761 break;
762
763 default:
764 len = ((SecAsn1Item *)src)->Length;
765 if (may_stream && len == 0 && !ignoresubstream)
766 len = 1; /* if we're streaming, we may have a secitem w/len 0 as placeholder */
767 break;
768 }
769
770 if ((len == 0 && optional) || underlying_kind == SEC_ASN1_ANY)
771 *noheaderp = PR_TRUE;
772 else
773 *noheaderp = PR_FALSE;
774
775 return len;
776}
777
778
779static void
780sec_asn1e_write_header (sec_asn1e_state *state)
781{
782 unsigned long contents_length;
783 unsigned char tag_number, tag_modifiers;
784 PRBool noheader;
785
786 PORT_Assert (state->place == beforeHeader);
787
788 tag_number = state->tag_number;
789 tag_modifiers = state->tag_modifiers;
790
791 if (state->underlying_kind == SEC_ASN1_ANY) {
792 state->place = duringContents;
793 return;
794 }
795
796 if( state->underlying_kind & SEC_ASN1_CHOICE ) {
797 int indx = sec_asn1e_which_choice(state->src, state->theTemplate);
798 if( 0 == indx ) {
799 /* XXX set an error? "choice not found" */
800 state->top->status = encodeError;
801 return;
802 }
803
804 state->place = afterChoice;
805 state = sec_asn1e_push_state(state->top, &state->theTemplate[indx],
806 (char *)state->src - state->theTemplate->offset,
807 PR_TRUE);
808
809 if( (sec_asn1e_state *)NULL != state ) {
810 /*
811 * Do the "before" field notification.
812 */
813 sec_asn1e_notify_before (state->top, state->src, state->depth);
814 state = sec_asn1e_init_state_based_on_template (state);
815 }
816
817 return;
818 }
819
820 /*
821 * We are doing a definite-length encoding. First we have to
822 * walk the data structure to calculate the entire contents length.
823 */
824 contents_length = sec_asn1e_contents_length (state->theTemplate,
825 state->src,
826 state->ignore_stream,
827 &noheader);
828 /*
829 * We might be told explicitly not to put out a header.
830 * But it can also be the case, via a pushed subtemplate, that
831 * sec_asn1e_contents_length could not know that this field is
832 * really optional. So check for that explicitly, too.
833 */
834 if (noheader || (contents_length == 0 && state->optional)) {
835 state->place = afterContents;
836 if (state->top->streaming && state->may_stream && state->top->from_buf)
837 /* we did not find an optional indefinite string, so we don't encode it.
838 * However, if TakeFromBuf is on, we stop here anyway to give our caller
839 * a chance to intercept at the same point where we would stop if the
840 * field were present. */
841 state->top->status = needBytes;
842 return;
843 }
844
845 if (state->top->streaming && state->may_stream
846 && (state->top->from_buf || !state->is_string)) {
847 /*
848 * We need to put out an indefinite-length encoding.
849 */
850 state->indefinite = PR_TRUE;
851 /*
852 * The only universal types that can be constructed are SETs,
853 * SEQUENCEs, and strings; so check that it is one of those,
854 * or that it is not universal (e.g. context-specific).
855 */
856 PORT_Assert ((tag_number == SEC_ASN1_SET)
857 || (tag_number == SEC_ASN1_SEQUENCE)
858 || ((tag_modifiers & SEC_ASN1_CLASS_MASK) != 0)
859 || state->is_string);
860 tag_modifiers |= SEC_ASN1_CONSTRUCTED;
861 contents_length = 0;
862 }
863
864 sec_asn1e_write_identifier_bytes (state, (unsigned char)(tag_number | tag_modifiers));
865 sec_asn1e_write_length_bytes (state, contents_length, state->indefinite);
866
867 if (contents_length == 0 && !state->indefinite) {
868 /*
869 * If no real contents to encode, then we are done with this field.
870 */
871 state->place = afterContents;
872 return;
873 }
874
875 /*
876 * An EXPLICIT is nothing but an outer header, which we have already
877 * written. Now we need to do the inner header and contents.
878 */
879 if (state->explicit) {
880 state->place = afterContents;
881 state = sec_asn1e_push_state (state->top,
882 SEC_ASN1GetSubtemplate(state->theTemplate,
883 state->src,
884 PR_TRUE,
885 NULL /* __APPLE__ */),
886 state->src, PR_TRUE);
887 if (state != NULL)
888 state = sec_asn1e_init_state_based_on_template (state);
889 return;
890 }
891
892 switch (state->underlying_kind) {
893 case SEC_ASN1_SET_OF:
894 case SEC_ASN1_SEQUENCE_OF:
895 /*
896 * We need to push a child to handle each member.
897 */
898 {
899 void **group;
900 const SecAsn1Template *subt;
901
902 group = *(void ***)state->src;
903 if (group == NULL || *group == NULL) {
904 /*
905 * Group is empty; we are done.
906 */
907 state->place = afterContents;
908 return;
909 }
910 state->place = duringGroup;
911 subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src,
912 PR_TRUE, NULL /* __APPLE__ */);
913 state = sec_asn1e_push_state (state->top, subt, *group, PR_TRUE);
914 if (state != NULL)
915 state = sec_asn1e_init_state_based_on_template (state);
916 }
917 break;
918
919 case SEC_ASN1_SEQUENCE:
920 case SEC_ASN1_SET:
921 /*
922 * We need to push a child to handle the individual fields.
923 */
924 state->place = duringSequence;
925 state = sec_asn1e_push_state (state->top, state->theTemplate + 1,
926 state->src, PR_TRUE);
927 if (state != NULL) {
928 /*
929 * Do the "before" field notification.
930 */
931 sec_asn1e_notify_before (state->top, state->src, state->depth);
932 state = sec_asn1e_init_state_based_on_template (state);
933 }
934 break;
935
936 default:
937 /*
938 * I think we do not need to do anything else.
939 * XXX Correct?
940 */
941 state->place = duringContents;
942 break;
943 }
944}
945
946
947static void
948sec_asn1e_write_contents (sec_asn1e_state *state,
949 const char *buf, unsigned long len)
950{
951 PORT_Assert (state->place == duringContents);
952
953 if (state->top->from_buf) {
954 /*
955 * Probably they just turned on "take from buf", but have not
956 * yet given us any bytes. If there is nothing in the buffer
957 * then we have nothing to do but return and wait.
958 */
959 if (buf == NULL || len == 0) {
960 state->top->status = needBytes;
961 return;
962 }
963 /*
964 * We are streaming, reading from a passed-in buffer.
965 * This means we are encoding a simple string or an ANY.
966 * For the former, we need to put out a substring, with its
967 * own identifier and length. For an ANY, we just write it
968 * out as is (our caller is required to ensure that it
969 * is a properly encoded entity).
970 */
971 PORT_Assert (state->is_string); /* includes ANY */
972 if (state->underlying_kind != SEC_ASN1_ANY) {
973 unsigned char identifier;
974
975 /*
976 * Create the identifier based on underlying_kind. We cannot
977 * use tag_number and tag_modifiers because this can be an
978 * implicitly encoded field. In that case, the underlying
979 * substrings *are* encoded with their real tag.
980 */
981 identifier = (unsigned char)state->underlying_kind & SEC_ASN1_TAG_MASK;
982 /*
983 * The underlying kind should just be a simple string; there
984 * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
985 */
986 PORT_Assert ((identifier & SEC_ASN1_TAGNUM_MASK) == identifier);
987 /*
988 * Write out the tag and length for the substring.
989 */
990 sec_asn1e_write_identifier_bytes (state, identifier);
991 if (state->underlying_kind == SEC_ASN1_BIT_STRING) {
992 char byte;
993 /*
994 * Assume we have a length in bytes but we need to output
995 * a proper bit string. This interface only works for bit
996 * strings that are full multiples of 8. If support for
997 * real, variable length bit strings is needed then the
998 * caller will have to know to pass in a bit length instead
999 * of a byte length and then this code will have to
1000 * perform the encoding necessary (length written is length
1001 * in bytes plus 1, and the first octet of string is the
1002 * number of bits remaining between the end of the bit
1003 * string and the next byte boundary).
1004 */
1005 sec_asn1e_write_length_bytes (state, len + 1, PR_FALSE);
1006 byte = 0;
1007 sec_asn1e_write_contents_bytes (state, &byte, 1);
1008 } else {
1009 sec_asn1e_write_length_bytes (state, len, PR_FALSE);
1010 }
1011 }
1012 sec_asn1e_write_contents_bytes (state, buf, len);
1013 state->top->status = needBytes;
1014 } else {
1015 switch (state->underlying_kind) {
1016 case SEC_ASN1_SET:
1017 case SEC_ASN1_SEQUENCE:
1018 PORT_Assert (0);
1019 break;
1020
1021 case SEC_ASN1_BIT_STRING:
1022 {
1023 SecAsn1Item *item;
1024 char rem;
1025
1026 item = (SecAsn1Item *)state->src;
1027 len = (item->Length + 7) >> 3;
1028 rem = (unsigned char)((len << 3) - item->Length); /* remaining bits */
1029 sec_asn1e_write_contents_bytes (state, &rem, 1);
1030 sec_asn1e_write_contents_bytes (state, (char *) item->Data,
1031 len);
1032 }
1033 break;
1034
1035 case SEC_ASN1_BMP_STRING:
1036 /* The number of bytes must be divisable by 2 */
1037 if ((((SecAsn1Item *)state->src)->Length) % 2) {
1038 SEC_ASN1EncoderContext *cx;
1039
1040 cx = state->top;
1041 cx->status = encodeError;
1042 break;
1043 }
1044 /* otherwise, fall through to write the content */
1045 goto process_string;
1046
1047 case SEC_ASN1_UNIVERSAL_STRING:
1048 /* The number of bytes must be divisable by 4 */
1049 if ((((SecAsn1Item *)state->src)->Length) % 4) {
1050 SEC_ASN1EncoderContext *cx;
1051
1052 cx = state->top;
1053 cx->status = encodeError;
1054 break;
1055 }
1056 /* otherwise, fall through to write the content */
1057 goto process_string;
1058
1059 case SEC_ASN1_INTEGER:
1060 /* ASN.1 INTEGERs are signed. If the source is an unsigned
1061 * integer, the encoder will need to handle the conversion here.
1062 */
1063 {
1064 size_t blen;
1065 unsigned char *intbuf;
1066 #ifdef __APPLE__
1067 PRBool signedInt = state->signedInt;
1068 #else
1069 SECItemType integerType = ((SecAsn1Item *)state->src)->type;
1070 #endif
1071 blen = ((SecAsn1Item *)state->src)->Length;
1072 intbuf = ((SecAsn1Item *)state->src)->Data;
1073 while (blen > 0) {
1074 #ifdef __APPLE__
1075 if (*intbuf & 0x80 && !signedInt) {
1076 #else
1077 if (*intbuf & 0x80 && integerType == siUnsignedInteger) {
1078 #endif
1079 char zero = 0; /* write a leading 0 */
1080 sec_asn1e_write_contents_bytes(state, &zero, 1);
1081 /* and then the remaining buffer */
1082 sec_asn1e_write_contents_bytes(state,
1083 (char *)intbuf, blen);
1084 break;
1085 }
1086 /* Check three possibilities:
1087 * 1. No leading zeros, msb of MSB is not 1;
1088 * 2. The number is zero itself;
1089 * 3. Encoding a signed integer with a leading zero,
1090 * keep the zero so that the number is positive.
1091 */
1092 if (*intbuf != 0 ||
1093 blen == 1 ||
1094 #ifdef __APPLE__
1095 (intbuf[1] & 0x80 && signedInt) )
1096 #else
1097 (intbuf[1] & 0x80 && integerType != siUnsignedInteger) )
1098 #endif
1099 {
1100 sec_asn1e_write_contents_bytes(state,
1101 (char *)intbuf, blen);
1102 break;
1103 }
1104 /* byte is 0, continue */
1105 intbuf++;
1106 blen--;
1107 }
1108 }
1109 /* done with this content */
1110 break;
1111
1112process_string:
1113 default:
1114 {
1115 SecAsn1Item *item;
1116
1117 item = (SecAsn1Item *)state->src;
1118 sec_asn1e_write_contents_bytes (state, (char *) item->Data,
1119 item->Length);
1120 }
1121 break;
1122 }
1123 state->place = afterContents;
1124 }
1125}
1126
1127
1128/*
1129 * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
1130 */
1131static void
1132sec_asn1e_next_in_group (sec_asn1e_state *state)
1133{
1134 sec_asn1e_state *child;
1135 void **group;
1136 void *member;
1137
1138 PORT_Assert (state->place == duringGroup);
1139 PORT_Assert (state->child != NULL);
1140
1141 child = state->child;
1142
1143 group = *(void ***)state->src;
1144
1145 /*
1146 * Find placement of current item.
1147 */
1148 member = (char *)(state->child->src) - child->theTemplate->offset;
1149 while (*group != member)
1150 group++;
1151
1152 /*
1153 * Move forward to next item.
1154 */
1155 group++;
1156 if (*group == NULL) {
1157 /*
1158 * That was our last one; we are done now.
1159 */
1160 child->place = notInUse;
1161 state->place = afterContents;
1162 return;
1163 }
1164 child->src = (char *)(*group) + child->theTemplate->offset;
1165
1166 /*
1167 * Re-"push" child.
1168 */
1169 sec_asn1e_scrub_state (child);
1170 state->top->current = child;
1171}
1172
1173
1174/*
1175 * We are moving along through a sequence; move forward by one,
1176 * (detecting end-of-sequence when it happens).
1177 */
1178static void
1179sec_asn1e_next_in_sequence (sec_asn1e_state *state)
1180{
1181 sec_asn1e_state *child;
1182
1183 PORT_Assert (state->place == duringSequence);
1184 PORT_Assert (state->child != NULL);
1185
1186 child = state->child;
1187
1188 /*
1189 * Do the "after" field notification.
1190 */
1191 sec_asn1e_notify_after (state->top, child->src, child->depth);
1192
1193 /*
1194 * Move forward.
1195 */
1196 child->theTemplate++;
1197 if (child->theTemplate->kind == 0) {
1198 /*
1199 * We are done with this sequence.
1200 */
1201 child->place = notInUse;
1202 state->place = afterContents;
1203 return;
1204 }
1205
1206 /*
1207 * Reset state and push.
1208 */
1209
1210 child->src = (char *)state->src + child->theTemplate->offset;
1211
1212 /*
1213 * Do the "before" field notification.
1214 */
1215 sec_asn1e_notify_before (state->top, child->src, child->depth);
1216
1217 state->top->current = child;
1218 (void) sec_asn1e_init_state_based_on_template (child);
1219}
1220
1221
1222static void
1223sec_asn1e_after_contents (sec_asn1e_state *state)
1224{
1225 PORT_Assert (state->place == afterContents);
1226
1227 if (state->indefinite)
1228 sec_asn1e_write_end_of_contents_bytes (state);
1229
1230 /*
1231 * Just make my parent be the current state. It will then clean
1232 * up after me and free me (or reuse me).
1233 */
1234 state->top->current = state->parent;
1235}
1236
1237
1238/*
1239 * This function is called whether or not we are streaming; if we
1240 * *are* streaming, our caller can also instruct us to take bytes
1241 * from the passed-in buffer (at buf, for length len, which is likely
1242 * bytes but could even mean bits if the current field is a bit string).
1243 * If we have been so instructed, we will gobble up bytes from there
1244 * (rather than from our src structure) and output them, and then
1245 * we will just return, expecting to be called again -- either with
1246 * more bytes or after our caller has instructed us that we are done
1247 * (for now) with the buffer.
1248 */
1249SECStatus
1250SEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext *cx,
1251 const char *buf, unsigned long len)
1252{
1253 sec_asn1e_state *state;
1254
1255 if (cx->status == needBytes) {
1256 PORT_Assert (buf != NULL && len != 0);
1257 cx->status = keepGoing;
1258 }
1259
1260 while (cx->status == keepGoing) {
1261 state = cx->current;
1262 switch (state->place) {
1263 case beforeHeader:
1264 sec_asn1e_write_header (state);
1265 break;
1266 case duringContents:
1267 sec_asn1e_write_contents (state, buf, len);
1268 break;
1269 case duringGroup:
1270 sec_asn1e_next_in_group (state);
1271 break;
1272 case duringSequence:
1273 sec_asn1e_next_in_sequence (state);
1274 break;
1275 case afterContents:
1276 sec_asn1e_after_contents (state);
1277 break;
1278 case afterImplicit:
1279 case afterInline:
1280 case afterPointer:
1281 case afterChoice:
1282 /*
1283 * These states are more documentation than anything.
1284 * They just need to force a pop.
1285 */
1286 PORT_Assert (!state->indefinite);
1287 state->place = afterContents;
1288 break;
1289 case notInUse:
1290 default:
1291 /* This is not an error, but rather a plain old BUG! */
1292 PORT_Assert (0);
1293 cx->status = encodeError;
1294 break;
1295 }
1296
1297 if (cx->status == encodeError)
1298 break;
1299
1300 /* It might have changed, so we have to update our local copy. */
1301 state = cx->current;
1302
1303 /* If it is NULL, we have popped all the way to the top. */
1304 if (state == NULL) {
1305 cx->status = allDone;
1306 break;
1307 }
1308 }
1309
1310 if (cx->status == encodeError) {
1311 return SECFailure;
1312 }
1313
1314 return SECSuccess;
1315}
1316
1317
1318void
1319SEC_ASN1EncoderFinish (SEC_ASN1EncoderContext *cx)
1320{
1321 /*
1322 * XXX anything else that needs to be finished?
1323 */
1324
1325 PORT_FreeArena (cx->our_pool, PR_FALSE);
1326}
1327
1328
1329SEC_ASN1EncoderContext *
1330SEC_ASN1EncoderStart (const void *src, const SecAsn1Template *theTemplate,
1331 SEC_ASN1WriteProc output_proc, void *output_arg)
1332{
1333 PRArenaPool *our_pool;
1334 SEC_ASN1EncoderContext *cx;
1335
1336 our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
1337 if (our_pool == NULL)
1338 return NULL;
1339
1340 cx = (SEC_ASN1EncoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
1341 if (cx == NULL) {
1342 PORT_FreeArena (our_pool, PR_FALSE);
1343 return NULL;
1344 }
1345
1346 cx->our_pool = our_pool;
1347 cx->output_proc = output_proc;
1348 cx->output_arg = output_arg;
1349
1350 cx->status = keepGoing;
1351
1352 if (sec_asn1e_push_state(cx, theTemplate, src, PR_FALSE) == NULL
1353 || sec_asn1e_init_state_based_on_template (cx->current) == NULL) {
1354 /*
1355 * Trouble initializing (probably due to failed allocations)
1356 * requires that we just give up.
1357 */
1358 PORT_FreeArena (our_pool, PR_FALSE);
1359 return NULL;
1360 }
1361
1362 return cx;
1363}
1364
1365
1366/*
1367 * XXX Do we need a FilterProc, too?
1368 */
1369
1370
1371void
1372SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext *cx,
1373 SEC_ASN1NotifyProc fn, void *arg)
1374{
1375 cx->notify_proc = fn;
1376 cx->notify_arg = arg;
1377}
1378
1379
1380void
1381SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext *cx)
1382{
1383 cx->notify_proc = NULL;
1384 cx->notify_arg = NULL; /* not necessary; just being clean */
1385}
1386
1387
1388void
1389SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error)
1390{
1391 PORT_Assert(cx);
1392 PORT_SetError(error);
1393 cx->status = encodeError;
1394}
1395
1396
1397void
1398SEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext *cx)
1399{
1400 /* XXX is there a way to check that we are "between" fields here? */
1401
1402 cx->streaming = PR_TRUE;
1403}
1404
1405
1406void
1407SEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext *cx)
1408{
1409 /* XXX is there a way to check that we are "between" fields here? */
1410
1411 cx->streaming = PR_FALSE;
1412}
1413
1414
1415void
1416SEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext *cx)
1417{
1418 /*
1419 * XXX is there a way to check that we are "between" fields here? this
1420 * needs to include a check for being in between groups of items in
1421 * a SET_OF or SEQUENCE_OF.
1422 */
1423 PORT_Assert (cx->streaming);
1424
1425 cx->from_buf = PR_TRUE;
1426}
1427
1428
1429void
1430SEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext *cx)
1431{
1432 /* we should actually be taking from buf *now* */
1433 PORT_Assert (cx->from_buf);
1434 if (! cx->from_buf) /* if not, just do nothing */
1435 return;
1436
1437 cx->from_buf = PR_FALSE;
1438
1439 if (cx->status == needBytes) {
1440 cx->status = keepGoing;
1441 cx->current->place = afterContents;
1442 }
1443}
1444
1445
1446SECStatus
1447SEC_ASN1Encode (const void *src, const SecAsn1Template *theTemplate,
1448 SEC_ASN1WriteProc output_proc, void *output_arg)
1449{
1450 SEC_ASN1EncoderContext *ecx;
1451 SECStatus rv;
1452
1453 ecx = SEC_ASN1EncoderStart (src, theTemplate, output_proc, output_arg);
1454 if (ecx == NULL)
1455 return SECFailure;
1456
1457 rv = SEC_ASN1EncoderUpdate (ecx, NULL, 0);
1458
1459 SEC_ASN1EncoderFinish (ecx);
1460 return rv;
1461}
1462
1463
1464/*
1465 * XXX depth and data_kind are unused; is there a PC way to silence warnings?
1466 * (I mean "politically correct", not anything to do with intel/win platform)
1467 */
1468void
1469sec_asn1e_encode_item_count (void *arg, const char *buf, size_t len,
1470 int depth, SEC_ASN1EncodingPart data_kind)
1471{
1472 size_t *count;
1473
1474 count = (unsigned long*)arg;
1475 PORT_Assert (count != NULL);
1476
1477 *count += len;
1478}
1479
1480
1481/* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
1482void
1483sec_asn1e_encode_item_store (void *arg, const char *buf, size_t len,
1484 int depth, SEC_ASN1EncodingPart data_kind)
1485{
1486 SecAsn1Item *dest;
1487
1488 dest = (SecAsn1Item*)arg;
1489 PORT_Assert (dest != NULL);
1490
1491 PORT_Memcpy (dest->Data + dest->Length, buf, len);
1492 dest->Length += len;
1493}
1494
1495
1496/*
1497 * Allocate an entire SecAsn1Item, or just the data part of it, to hold
1498 * "len" bytes of stuff. Allocate from the given pool, if specified,
1499 * otherwise just do a vanilla PORT_Alloc.
1500 *
1501 * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
1502 */
1503SecAsn1Item *
1504sec_asn1e_allocate_item (PRArenaPool *poolp, SecAsn1Item *dest, unsigned long len)
1505{
1506 if (poolp != NULL) {
1507 void *release;
1508
1509 release = PORT_ArenaMark (poolp);
1510 if (dest == NULL)
1511 dest = (SecAsn1Item*)PORT_ArenaAlloc (poolp, sizeof(SecAsn1Item));
1512 if (dest != NULL) {
1513 dest->Data = (unsigned char*)PORT_ArenaAlloc (poolp, len);
1514 if (dest->Data == NULL) {
1515 dest = NULL;
1516 }
1517 }
1518 if (dest == NULL) {
1519 /* one or both allocations failed; release everything */
1520 PORT_ArenaRelease (poolp, release);
1521 } else {
1522 /* everything okay; unmark the arena */
1523 PORT_ArenaUnmark (poolp, release);
1524 }
1525 } else {
1526 SecAsn1Item *indest;
1527
1528 indest = dest;
1529 if (dest == NULL)
1530 dest = (SecAsn1Item*)PORT_Alloc (sizeof(SecAsn1Item));
1531 if (dest != NULL) {
1532 #ifndef __APPLE__
1533 dest->type = siBuffer;
1534 #endif
1535 dest->Data = (unsigned char*)PORT_Alloc (len);
1536 if (dest->Data == NULL) {
1537 if (indest == NULL)
1538 PORT_Free (dest);
1539 dest = NULL;
1540 }
1541 }
1542 }
1543
1544 return dest;
1545}
1546
1547
1548SecAsn1Item *
1549SEC_ASN1EncodeItem (PRArenaPool *poolp, SecAsn1Item *dest, const void *src,
1550 const SecAsn1Template *theTemplate)
1551{
1552 unsigned long encoding_length;
1553 SECStatus rv;
1554
1555 PORT_Assert (dest == NULL || dest->Data == NULL);
1556
1557 encoding_length = 0;
1558 rv = SEC_ASN1Encode (src, theTemplate,
1559 sec_asn1e_encode_item_count, &encoding_length);
1560 if (rv != SECSuccess)
1561 return NULL;
1562
1563 dest = sec_asn1e_allocate_item (poolp, dest, encoding_length);
1564 if (dest == NULL)
1565 return NULL;
1566
1567 /* XXX necessary? This really just checks for a bug in the allocate fn */
1568 PORT_Assert (dest->Data != NULL);
1569 if (dest->Data == NULL)
1570 return NULL;
1571
1572 dest->Length = 0;
1573 (void) SEC_ASN1Encode (src, theTemplate, sec_asn1e_encode_item_store, dest);
1574
1575 PORT_Assert (encoding_length == dest->Length);
1576 return dest;
1577}
1578
1579
1580static SecAsn1Item *
1581sec_asn1e_integer(PRArenaPool *poolp, SecAsn1Item *dest, unsigned long value,
1582 PRBool make_unsigned)
1583{
1584 unsigned long copy;
1585 unsigned char sign;
1586 int len = 0;
1587
1588 /*
1589 * Determine the length of the encoded value (minimum of 1).
1590 */
1591 copy = value;
1592 do {
1593 len++;
1594 sign = (unsigned char)(copy & 0x80);
1595 copy >>= 8;
1596 } while (copy);
1597
1598 /*
1599 * If this is an unsigned encoding, and the high bit of the last
1600 * byte we counted was set, we need to add one to the length so
1601 * we put a high-order zero byte in the encoding.
1602 */
1603 if (sign && make_unsigned)
1604 len++;
1605
1606 /*
1607 * Allocate the item (if necessary) and the data pointer within.
1608 */
1609 dest = sec_asn1e_allocate_item (poolp, dest, len);
1610 if (dest == NULL)
1611 return NULL;
1612
1613 /*
1614 * Store the value, byte by byte, in the item.
1615 */
1616 dest->Length = len;
1617 while (len) {
1618 dest->Data[--len] = (unsigned char)value;
1619 value >>= 8;
1620 }
1621 PORT_Assert (value == 0);
1622
1623 return dest;
1624}
1625
1626
1627SecAsn1Item *
1628SEC_ASN1EncodeInteger(PRArenaPool *poolp, SecAsn1Item *dest, long value)
1629{
1630 return sec_asn1e_integer (poolp, dest, (unsigned long) value, PR_FALSE);
1631}
1632
1633
1634extern SecAsn1Item *
1635SEC_ASN1EncodeUnsignedInteger(PRArenaPool *poolp,
1636 SecAsn1Item *dest, unsigned long value)
1637{
1638 return sec_asn1e_integer (poolp, dest, value, PR_TRUE);
1639}