]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_asn1/lib/secasn1e.c
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / libsecurity_asn1 / lib / secasn1e.c
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
43 #include <syslog.h>
44
45 typedef enum {
46 beforeHeader,
47 duringContents,
48 duringGroup,
49 duringSequence,
50 afterContents,
51 afterImplicit,
52 afterInline,
53 afterPointer,
54 afterChoice,
55 notInUse
56 } sec_asn1e_parse_place;
57
58 typedef enum {
59 allDone,
60 encodeError,
61 keepGoing,
62 needBytes
63 } sec_asn1e_parse_status;
64
65 typedef struct sec_asn1e_state_struct {
66 SEC_ASN1EncoderContext *top;
67 const SecAsn1Template *theTemplate;
68 void *src;
69
70 struct sec_asn1e_state_struct *parent; /* aka prev */
71 struct sec_asn1e_state_struct *child; /* aka next */
72
73 sec_asn1e_parse_place place; /* where we are in encoding process */
74
75 /*
76 * XXX explain the next fields as clearly as possible...
77 */
78 unsigned char tag_modifiers;
79 unsigned char tag_number;
80 unsigned long underlying_kind;
81
82 int depth;
83
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 */
90 #ifdef __APPLE__
91 ,
92 signedInt /* signed alternate to SEC_ASN1_INTEGER */
93 #endif
94 ;
95 } sec_asn1e_state;
96
97 /*
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().
102 */
103 struct sec_EncoderContext_struct {
104 PRArenaPool *our_pool; /* for our internal allocs */
105
106 sec_asn1e_state *current;
107 sec_asn1e_parse_status status;
108
109 PRBool streaming;
110 PRBool from_buf;
111
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 */
115
116 SEC_ASN1WriteProc output_proc; /* pass encoded bytes to this */
117 void *output_arg; /* argument to that function */
118 };
119
120
121 static sec_asn1e_state *
122 sec_asn1e_push_state (SEC_ASN1EncoderContext *cx,
123 const SecAsn1Template *theTemplate,
124 const void *src, PRBool new_depth)
125 {
126 sec_asn1e_state *state, *new_state;
127
128 state = cx->current;
129
130 new_state = (sec_asn1e_state*)PORT_ArenaZAlloc (cx->our_pool,
131 sizeof(*new_state));
132 if (new_state == NULL) {
133 cx->status = encodeError;
134 return NULL;
135 }
136
137 new_state->top = cx;
138 new_state->parent = state;
139 new_state->theTemplate = theTemplate;
140 new_state->place = notInUse;
141 if (src != NULL)
142 new_state->src = (char *)src + theTemplate->offset;
143
144 if (state != NULL) {
145 new_state->depth = state->depth;
146 if (new_depth)
147 new_state->depth++;
148 state->child = new_state;
149 }
150
151 cx->current = new_state;
152 return new_state;
153 }
154
155
156 static void
157 sec_asn1e_scrub_state (sec_asn1e_state *state)
158 {
159 /*
160 * Some default "scrubbing".
161 * XXX right set of initializations?
162 */
163 state->place = beforeHeader;
164 state->indefinite = PR_FALSE;
165 }
166
167
168 static void
169 sec_asn1e_notify_before (SEC_ASN1EncoderContext *cx, void *src, int depth)
170 {
171 if (cx->notify_proc == NULL)
172 return;
173
174 cx->during_notify = PR_TRUE;
175 (* cx->notify_proc) (cx->notify_arg, PR_TRUE, src, depth);
176 cx->during_notify = PR_FALSE;
177 }
178
179
180 static void
181 sec_asn1e_notify_after (SEC_ASN1EncoderContext *cx, void *src, int depth)
182 {
183 if (cx->notify_proc == NULL)
184 return;
185
186 cx->during_notify = PR_TRUE;
187 (* cx->notify_proc) (cx->notify_arg, PR_FALSE, src, depth);
188 cx->during_notify = PR_FALSE;
189 }
190
191
192 static sec_asn1e_state *
193 sec_asn1e_init_state_based_on_template (sec_asn1e_state *state)
194 {
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;
199 #ifdef __APPLE__
200 PRBool signedInt, dynamic;
201 #endif
202
203 encode_kind = state->theTemplate->kind;
204
205 universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
206 ? PR_TRUE : PR_FALSE;
207
208 explicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
209 encode_kind &= ~SEC_ASN1_EXPLICIT;
210
211 optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
212 encode_kind &= ~SEC_ASN1_OPTIONAL;
213
214 PORT_Assert (!(explicit && universal)); /* bad templates */
215
216 may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
217 encode_kind &= ~SEC_ASN1_MAY_STREAM;
218
219 ignore_stream = (encode_kind & SEC_ASN1_NO_STREAM) ? PR_TRUE : PR_FALSE;
220 encode_kind &= ~SEC_ASN1_NO_STREAM;
221
222 #ifdef __APPLE__
223 signedInt = (encode_kind & SEC_ASN1_SIGNED_INT) ? PR_TRUE : PR_FALSE;
224 encode_kind &= ~SEC_ASN1_SIGNED_INT;
225 #endif
226
227 #ifdef __APPLE__
228 dynamic = (encode_kind & SEC_ASN1_DYNAMIC) ? PR_TRUE : PR_FALSE;
229 #endif
230 encode_kind &= ~SEC_ASN1_DYNAMIC;
231
232 if( encode_kind & SEC_ASN1_CHOICE ) {
233 under_kind = SEC_ASN1_CHOICE;
234 } else
235
236 if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || (!universal
237 && !explicit)) {
238 const SecAsn1Template *subt;
239 void *src;
240
241 PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);
242
243 sec_asn1e_scrub_state (state);
244
245 if (encode_kind & SEC_ASN1_POINTER) {
246 /*
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.
251 */
252 src = *(void **)state->src;
253 state->place = afterPointer;
254 if (src == NULL) {
255 /*
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.
259 */
260 if (optional)
261 return state;
262
263 /*
264 * XXX this is an error; need to figure out
265 * how to handle this
266 */
267 }
268 } else {
269 src = state->src;
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;
274 } else {
275 /*
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
278 * SEQUENCE OF
279 */
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;
283
284 state->place = afterImplicit;
285 state->optional = optional;
286 }
287 }
288
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);
292 if (state == NULL)
293 return NULL;
294
295 if (universal) {
296 /*
297 * This is a POINTER or INLINE; just init based on that
298 * and we are done.
299 */
300 return sec_asn1e_init_state_based_on_template (state);
301 }
302
303 /*
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.).
310 */
311
312 under_kind = state->theTemplate->kind;
313 if (under_kind & SEC_ASN1_MAY_STREAM) {
314 if (!ignore_stream)
315 may_stream = PR_TRUE;
316 under_kind &= ~SEC_ASN1_MAY_STREAM;
317 }
318 } else {
319 under_kind = encode_kind;
320 }
321
322 /*
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
327 * or remove any?)
328 */
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);
333
334 if (encode_kind & SEC_ASN1_ANY) {
335 PORT_Assert (encode_kind == under_kind);
336 tag_modifiers = 0;
337 tag_number = 0;
338 is_string = PR_TRUE;
339 } else {
340 tag_modifiers = (unsigned char)encode_kind & SEC_ASN1_TAG_MASK &
341 ~SEC_ASN1_TAGNUM_MASK;
342 /*
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.
347 */
348
349 #ifdef __APPLE__
350 /*
351 * Apple change: if this is a DYNAMIC template, use the tag number
352 * from the subtemplate's kind
353 */
354 if(dynamic) {
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);
358 }
359 else
360 #endif /* __APPLE__ */
361 tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
362
363 is_string = PR_FALSE;
364 switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
365 case SEC_ASN1_SET:
366 /*
367 * XXX A plain old SET (as opposed to a SET OF) is not implemented.
368 * If it ever is, remove this assert...
369 */
370 PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
371 /* fallthru */
372 case SEC_ASN1_SEQUENCE:
373 tag_modifiers |= SEC_ASN1_CONSTRUCTED;
374 break;
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:
386 /*
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.
389 */
390 is_string = PR_TRUE;
391 break;
392 }
393 }
394
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;
403 #ifdef __APPLE__
404 state->signedInt = signedInt;
405 #endif
406
407 sec_asn1e_scrub_state (state);
408
409 return state;
410 }
411
412
413 static void
414 sec_asn1e_write_part (sec_asn1e_state *state,
415 const char *buf, size_t len,
416 SEC_ASN1EncodingPart part)
417 {
418 SEC_ASN1EncoderContext *cx;
419
420 cx = state->top;
421 (* cx->output_proc) (cx->output_arg, buf, len, state->depth, part);
422 }
423
424
425 /*
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.
429 */
430 static void
431 sec_asn1e_write_identifier_bytes (sec_asn1e_state *state, unsigned char value)
432 {
433 char byte;
434
435 byte = (char) value;
436 sec_asn1e_write_part (state, &byte, 1, SEC_ASN1_Identifier);
437 }
438
439 int
440 SEC_ASN1EncodeLength(unsigned char *buf,unsigned long value) {
441 int lenlen;
442
443 lenlen = SEC_ASN1LengthLength (value);
444 if (lenlen == 1) {
445 buf[0] = value;
446 } else {
447 int i;
448
449 i = lenlen - 1;
450 buf[0] = 0x80 | i;
451 while (i) {
452 buf[i--] = value;
453 value >>= 8;
454 }
455 PORT_Assert (value == 0);
456 }
457 return lenlen;
458 }
459
460 static void
461 sec_asn1e_write_length_bytes (sec_asn1e_state *state, unsigned long value,
462 PRBool indefinite)
463 {
464 int lenlen;
465 unsigned char buf[sizeof(unsigned long) + 1];
466
467 if (indefinite) {
468 PORT_Assert (value == 0);
469 buf[0] = 0x80;
470 lenlen = 1;
471 } else {
472 lenlen = SEC_ASN1EncodeLength(buf,value);
473 }
474
475 sec_asn1e_write_part (state, (char *) buf, lenlen, SEC_ASN1_Length);
476 }
477
478
479 static void
480 sec_asn1e_write_contents_bytes (sec_asn1e_state *state,
481 const char *buf, unsigned long len)
482 {
483 sec_asn1e_write_part (state, buf, len, SEC_ASN1_Contents);
484 }
485
486
487 static void
488 sec_asn1e_write_end_of_contents_bytes (sec_asn1e_state *state)
489 {
490 const char eoc[2] = {0, 0};
491
492 sec_asn1e_write_part (state, eoc, 2, SEC_ASN1_EndOfContents);
493 }
494
495 static int
496 sec_asn1e_which_choice
497 (
498 void *src,
499 const SecAsn1Template *theTemplate
500 )
501 {
502 int rv;
503 unsigned int which = *(unsigned int *)src;
504
505 for( rv = 1, theTemplate++; theTemplate->kind != 0; rv++, theTemplate++ ) {
506 if( which == theTemplate->size ) {
507 return rv;
508 }
509 }
510
511 return 0;
512 }
513
514 static unsigned long
515 sec_asn1e_contents_length (const SecAsn1Template *theTemplate, void *src,
516 PRBool ignoresubstream, PRBool *noheaderp)
517 {
518 unsigned long encode_kind, underlying_kind;
519 PRBool explicit, optional, universal, may_stream;
520 unsigned long len;
521 #ifdef __APPLE__
522 PRBool signedInt;
523 #endif
524
525 /*
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
539 */
540 encode_kind = theTemplate->kind;
541
542 universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
543 ? PR_TRUE : PR_FALSE;
544
545 explicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
546 encode_kind &= ~SEC_ASN1_EXPLICIT;
547
548 optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
549 encode_kind &= ~SEC_ASN1_OPTIONAL;
550
551 PORT_Assert (!(explicit && universal)); /* bad templates */
552
553 may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
554 encode_kind &= ~SEC_ASN1_MAY_STREAM;
555
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;
559
560 if( encode_kind & SEC_ASN1_CHOICE ) {
561 void *src2;
562 int indx = sec_asn1e_which_choice(src, theTemplate);
563 if( 0 == indx ) {
564 /* XXX set an error? "choice not found" */
565 /* state->top->status = encodeError; */
566 return 0;
567 }
568
569 src2 = (void *)((char *)src - theTemplate->offset + theTemplate[indx].offset);
570
571 return sec_asn1e_contents_length(&theTemplate[indx], src2,
572 PR_FALSE, noheaderp);
573 }
574
575 if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || !universal) {
576
577 /* XXX any bits we want to disallow (PORT_Assert against) here? */
578
579 theTemplate = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE,
580 NULL /* __APPLE__ */, 0 /* __APPLE__ */);
581
582 if (encode_kind & SEC_ASN1_POINTER) {
583 /*
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.
591 */
592 src = *(void **)src;
593 if (src == NULL) {
594 if (optional)
595 *noheaderp = PR_TRUE;
596 else
597 *noheaderp = PR_FALSE;
598 return 0;
599 }
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);
603 }
604
605 src = (char *)src + theTemplate->offset;
606
607 if (explicit) {
608 len = sec_asn1e_contents_length (theTemplate, src, PR_FALSE,
609 noheaderp);
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;
615 } else {
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.
620 */
621 len += 1 + SEC_ASN1LengthLength (len);
622 }
623 return len;
624 }
625
626 underlying_kind = theTemplate->kind;
627 underlying_kind &= ~SEC_ASN1_MAY_STREAM;
628 /* XXX Should we recurse here? */
629 } else {
630 underlying_kind = encode_kind;
631 }
632
633 #ifdef __APPLE__
634 signedInt = (underlying_kind & SEC_ASN1_SIGNED_INT) ?
635 PR_TRUE : PR_FALSE;
636 #endif
637
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;
643 return 0;
644 }
645
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);
651
652 if( underlying_kind & SEC_ASN1_CHOICE ) {
653 void *src2;
654 int indx = sec_asn1e_which_choice(src, theTemplate);
655 if( 0 == indx ) {
656 /* XXX set an error? "choice not found" */
657 /* state->top->status = encodeError; */
658 return 0;
659 }
660
661 src2 = (void *)((char *)src - theTemplate->offset + theTemplate[indx].offset);
662 len = sec_asn1e_contents_length(&theTemplate[indx], src2, PR_FALSE,
663 noheaderp);
664 } else
665
666 switch (underlying_kind) {
667 case SEC_ASN1_SEQUENCE_OF:
668 case SEC_ASN1_SET_OF:
669 {
670 const SecAsn1Template *tmpt;
671 void *sub_src;
672 unsigned long sub_len;
673 void **group;
674
675 len = 0;
676
677 group = *(void ***)src;
678 if (group == NULL)
679 break;
680
681 tmpt = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE,
682 NULL /* __APPLE__ */, 0 /* __APPLE__ */);
683
684 for (; *group != NULL; group++) {
685 sub_src = (char *)(*group) + tmpt->offset;
686 sub_len = sec_asn1e_contents_length (tmpt, sub_src, PR_FALSE,
687 noheaderp);
688 len += sub_len;
689 /*
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.
692 */
693 if (!*noheaderp)
694 len += 1 + SEC_ASN1LengthLength (sub_len);
695 }
696 }
697 break;
698
699 case SEC_ASN1_SEQUENCE:
700 case SEC_ASN1_SET:
701 {
702 const SecAsn1Template *tmpt;
703 void *sub_src;
704 unsigned long sub_len;
705
706 len = 0;
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,
710 noheaderp);
711 len += sub_len;
712 /*
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.
715 */
716 if (!*noheaderp)
717 len += 1 + SEC_ASN1LengthLength (sub_len);
718 }
719 }
720 break;
721
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 */
726 if (len)
727 len++;
728 break;
729
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.
734 */
735 {
736 unsigned char *buf = ((SecAsn1Item *)src)->Data;
737 #ifndef __APPLE__
738 SecAsn1ItemType integerType = ((SecAsn1Item *)src)->type;
739 #endif
740 len = ((SecAsn1Item *)src)->Length;
741 while (len > 0) {
742 if (*buf != 0) {
743 #ifdef __APPLE__
744 if (*buf & 0x80 && !signedInt) {
745 #else
746 if (*buf & 0x80 && integerType == siUnsignedInteger) {
747 #endif // __APPLE__
748 len++; /* leading zero needed to make number signed */
749 }
750 break; /* reached beginning of number */
751 }
752 if (len == 1) {
753 break; /* the number 0 */
754 }
755 if (buf[1] & 0x80) {
756 break; /* leading zero already present */
757 }
758 /* extraneous leading zero, keep going */
759 buf++;
760 len--;
761 }
762 }
763 break;
764
765 default:
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 */
769 break;
770 }
771
772 if ((len == 0 && optional) || underlying_kind == SEC_ASN1_ANY)
773 *noheaderp = PR_TRUE;
774 else
775 *noheaderp = PR_FALSE;
776
777 return len;
778 }
779
780
781 static void
782 sec_asn1e_write_header (sec_asn1e_state *state)
783 {
784 unsigned long contents_length;
785 unsigned char tag_number, tag_modifiers;
786 PRBool noheader;
787
788 PORT_Assert (state->place == beforeHeader);
789
790 tag_number = state->tag_number;
791 tag_modifiers = state->tag_modifiers;
792
793 if (state->underlying_kind == SEC_ASN1_ANY) {
794 state->place = duringContents;
795 return;
796 }
797
798 if( state->underlying_kind & SEC_ASN1_CHOICE ) {
799 int indx = sec_asn1e_which_choice(state->src, state->theTemplate);
800 if( 0 == indx ) {
801 /* XXX set an error? "choice not found" */
802 state->top->status = encodeError;
803 return;
804 }
805
806 state->place = afterChoice;
807 state = sec_asn1e_push_state(state->top, &state->theTemplate[indx],
808 (char *)state->src - state->theTemplate->offset,
809 PR_TRUE);
810
811 if( (sec_asn1e_state *)NULL != state ) {
812 /*
813 * Do the "before" field notification.
814 */
815 sec_asn1e_notify_before (state->top, state->src, state->depth);
816 state = sec_asn1e_init_state_based_on_template (state);
817 }
818
819 (void) state;
820
821 return;
822 }
823
824 /*
825 * We are doing a definite-length encoding. First we have to
826 * walk the data structure to calculate the entire contents length.
827 */
828 contents_length = sec_asn1e_contents_length (state->theTemplate,
829 state->src,
830 state->ignore_stream,
831 &noheader);
832 /*
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.
837 */
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;
846 return;
847 }
848
849 if (state->top->streaming && state->may_stream
850 && (state->top->from_buf || !state->is_string)) {
851 /*
852 * We need to put out an indefinite-length encoding.
853 */
854 state->indefinite = PR_TRUE;
855 /*
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).
859 */
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;
865 contents_length = 0;
866 }
867
868 sec_asn1e_write_identifier_bytes (state, (unsigned char)(tag_number | tag_modifiers));
869 sec_asn1e_write_length_bytes (state, contents_length, state->indefinite);
870
871 if (contents_length == 0 && !state->indefinite) {
872 /*
873 * If no real contents to encode, then we are done with this field.
874 */
875 state->place = afterContents;
876 return;
877 }
878
879 /*
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.
882 */
883 if (state->explicit) {
884 state->place = afterContents;
885 state = sec_asn1e_push_state (state->top,
886 SEC_ASN1GetSubtemplate(state->theTemplate,
887 state->src,
888 PR_TRUE,
889 NULL /* __APPLE__ */, 0 /* __APPLE__ */),
890 state->src, PR_TRUE);
891 if (state != NULL)
892 state = sec_asn1e_init_state_based_on_template (state);
893
894 (void) state;
895
896 return;
897 }
898
899 switch (state->underlying_kind) {
900 case SEC_ASN1_SET_OF:
901 case SEC_ASN1_SEQUENCE_OF:
902 /*
903 * We need to push a child to handle each member.
904 */
905 {
906 void **group;
907 const SecAsn1Template *subt;
908
909 group = *(void ***)state->src;
910 if (group == NULL || *group == NULL) {
911 /*
912 * Group is empty; we are done.
913 */
914 state->place = afterContents;
915 return;
916 }
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);
921 if (state != NULL)
922 state = sec_asn1e_init_state_based_on_template (state);
923 }
924 break;
925
926 case SEC_ASN1_SEQUENCE:
927 case SEC_ASN1_SET:
928 /*
929 * We need to push a child to handle the individual fields.
930 */
931 state->place = duringSequence;
932 state = sec_asn1e_push_state (state->top, state->theTemplate + 1,
933 state->src, PR_TRUE);
934 if (state != NULL) {
935 /*
936 * Do the "before" field notification.
937 */
938 sec_asn1e_notify_before (state->top, state->src, state->depth);
939 state = sec_asn1e_init_state_based_on_template (state);
940 }
941 break;
942
943 default:
944 /*
945 * I think we do not need to do anything else.
946 * XXX Correct?
947 */
948 state->place = duringContents;
949 break;
950 }
951
952 (void) state;
953 }
954
955
956 static void
957 sec_asn1e_write_contents (sec_asn1e_state *state,
958 const char *buf, unsigned long len)
959 {
960 PORT_Assert (state->place == duringContents);
961
962 if (state->top->from_buf) {
963 /*
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.
967 */
968 if (buf == NULL || len == 0) {
969 state->top->status = needBytes;
970 return;
971 }
972 /*
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).
979 */
980 PORT_Assert (state->is_string); /* includes ANY */
981 if (state->underlying_kind != SEC_ASN1_ANY) {
982 unsigned char identifier;
983
984 /*
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.
989 */
990 identifier = (unsigned char)state->underlying_kind & SEC_ASN1_TAG_MASK;
991 /*
992 * The underlying kind should just be a simple string; there
993 * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
994 */
995 PORT_Assert ((identifier & SEC_ASN1_TAGNUM_MASK) == identifier);
996 /*
997 * Write out the tag and length for the substring.
998 */
999 sec_asn1e_write_identifier_bytes (state, identifier);
1000 if (state->underlying_kind == SEC_ASN1_BIT_STRING) {
1001 char byte;
1002 /*
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).
1013 */
1014 sec_asn1e_write_length_bytes (state, len + 1, PR_FALSE);
1015 byte = 0;
1016 sec_asn1e_write_contents_bytes (state, &byte, 1);
1017 } else {
1018 sec_asn1e_write_length_bytes (state, len, PR_FALSE);
1019 }
1020 }
1021 sec_asn1e_write_contents_bytes (state, buf, len);
1022 state->top->status = needBytes;
1023 } else {
1024 switch (state->underlying_kind) {
1025 case SEC_ASN1_SET:
1026 case SEC_ASN1_SEQUENCE:
1027 PORT_Assert (0);
1028 break;
1029
1030 case SEC_ASN1_BIT_STRING:
1031 {
1032 SecAsn1Item *item;
1033 char rem;
1034
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,
1040 len);
1041 }
1042 break;
1043
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;
1048
1049 cx = state->top;
1050 cx->status = encodeError;
1051 break;
1052 }
1053 /* otherwise, fall through to write the content */
1054 goto process_string;
1055
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;
1060
1061 cx = state->top;
1062 cx->status = encodeError;
1063 break;
1064 }
1065 /* otherwise, fall through to write the content */
1066 goto process_string;
1067
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.
1071 */
1072 {
1073 size_t blen;
1074 unsigned char *intbuf;
1075 #ifdef __APPLE__
1076 PRBool signedInt = state->signedInt;
1077 #else
1078 SECItemType integerType = ((SecAsn1Item *)state->src)->type;
1079 #endif
1080 blen = ((SecAsn1Item *)state->src)->Length;
1081 intbuf = ((SecAsn1Item *)state->src)->Data;
1082 while (blen > 0) {
1083 #ifdef __APPLE__
1084 if (*intbuf & 0x80 && !signedInt) {
1085 #else
1086 if (*intbuf & 0x80 && integerType == siUnsignedInteger) {
1087 #endif
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);
1093 break;
1094 }
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.
1100 */
1101 if (*intbuf != 0 ||
1102 blen == 1 ||
1103 #ifdef __APPLE__
1104 (intbuf[1] & 0x80 && signedInt) )
1105 #else
1106 (intbuf[1] & 0x80 && integerType != siUnsignedInteger) )
1107 #endif
1108 {
1109 sec_asn1e_write_contents_bytes(state,
1110 (char *)intbuf, blen);
1111 break;
1112 }
1113 /* byte is 0, continue */
1114 intbuf++;
1115 blen--;
1116 }
1117 }
1118 /* done with this content */
1119 break;
1120
1121 process_string:
1122 default:
1123 {
1124 SecAsn1Item *item;
1125
1126 item = (SecAsn1Item *)state->src;
1127 sec_asn1e_write_contents_bytes (state, (char *) item->Data,
1128 item->Length);
1129 }
1130 break;
1131 }
1132 state->place = afterContents;
1133 }
1134 }
1135
1136
1137 /*
1138 * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
1139 */
1140 static void
1141 sec_asn1e_next_in_group (sec_asn1e_state *state)
1142 {
1143 sec_asn1e_state *child;
1144 void **group;
1145 void *member;
1146
1147 PORT_Assert (state->place == duringGroup);
1148 PORT_Assert (state->child != NULL);
1149
1150 child = state->child;
1151
1152 group = *(void ***)state->src;
1153
1154 /*
1155 * Find placement of current item.
1156 */
1157 member = (char *)(state->child->src) - child->theTemplate->offset;
1158 while (*group != member)
1159 group++;
1160
1161 /*
1162 * Move forward to next item.
1163 */
1164 group++;
1165 if (*group == NULL) {
1166 /*
1167 * That was our last one; we are done now.
1168 */
1169 child->place = notInUse;
1170 state->place = afterContents;
1171 return;
1172 }
1173 child->src = (char *)(*group) + child->theTemplate->offset;
1174
1175 /*
1176 * Re-"push" child.
1177 */
1178 sec_asn1e_scrub_state (child);
1179 state->top->current = child;
1180 }
1181
1182
1183 /*
1184 * We are moving along through a sequence; move forward by one,
1185 * (detecting end-of-sequence when it happens).
1186 */
1187 static void
1188 sec_asn1e_next_in_sequence (sec_asn1e_state *state)
1189 {
1190 sec_asn1e_state *child;
1191
1192 PORT_Assert (state->place == duringSequence);
1193 PORT_Assert (state->child != NULL);
1194
1195 child = state->child;
1196
1197 /*
1198 * Do the "after" field notification.
1199 */
1200 sec_asn1e_notify_after (state->top, child->src, child->depth);
1201
1202 /*
1203 * Move forward.
1204 */
1205 child->theTemplate++;
1206 if (child->theTemplate->kind == 0) {
1207 /*
1208 * We are done with this sequence.
1209 */
1210 child->place = notInUse;
1211 state->place = afterContents;
1212 return;
1213 }
1214
1215 /*
1216 * Reset state and push.
1217 */
1218
1219 child->src = (char *)state->src + child->theTemplate->offset;
1220
1221 /*
1222 * Do the "before" field notification.
1223 */
1224 sec_asn1e_notify_before (state->top, child->src, child->depth);
1225
1226 state->top->current = child;
1227 (void) sec_asn1e_init_state_based_on_template (child);
1228 }
1229
1230
1231 static void
1232 sec_asn1e_after_contents (sec_asn1e_state *state)
1233 {
1234 PORT_Assert (state->place == afterContents);
1235
1236 if (state->indefinite)
1237 sec_asn1e_write_end_of_contents_bytes (state);
1238
1239 /*
1240 * Just make my parent be the current state. It will then clean
1241 * up after me and free me (or reuse me).
1242 */
1243 state->top->current = state->parent;
1244 }
1245
1246
1247 /*
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.
1257 */
1258 SECStatus
1259 SEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext *cx,
1260 const char *buf, unsigned long len)
1261 {
1262 sec_asn1e_state *state;
1263
1264 if (cx->status == needBytes) {
1265 PORT_Assert (buf != NULL && len != 0);
1266 cx->status = keepGoing;
1267 }
1268
1269 while (cx->status == keepGoing) {
1270 state = cx->current;
1271 switch (state->place) {
1272 case beforeHeader:
1273 sec_asn1e_write_header (state);
1274 break;
1275 case duringContents:
1276 sec_asn1e_write_contents (state, buf, len);
1277 break;
1278 case duringGroup:
1279 sec_asn1e_next_in_group (state);
1280 break;
1281 case duringSequence:
1282 sec_asn1e_next_in_sequence (state);
1283 break;
1284 case afterContents:
1285 sec_asn1e_after_contents (state);
1286 break;
1287 case afterImplicit:
1288 case afterInline:
1289 case afterPointer:
1290 case afterChoice:
1291 /*
1292 * These states are more documentation than anything.
1293 * They just need to force a pop.
1294 */
1295 PORT_Assert (!state->indefinite);
1296 state->place = afterContents;
1297 break;
1298 case notInUse:
1299 default:
1300 /* This is not an error, but rather a plain old BUG! */
1301 PORT_Assert (0);
1302 cx->status = encodeError;
1303 break;
1304 }
1305
1306 if (cx->status == encodeError)
1307 break;
1308
1309 /* It might have changed, so we have to update our local copy. */
1310 state = cx->current;
1311
1312 /* If it is NULL, we have popped all the way to the top. */
1313 if (state == NULL) {
1314 cx->status = allDone;
1315 break;
1316 }
1317 }
1318
1319 if (cx->status == encodeError) {
1320 return SECFailure;
1321 }
1322
1323 return SECSuccess;
1324 }
1325
1326
1327 void
1328 SEC_ASN1EncoderFinish (SEC_ASN1EncoderContext *cx)
1329 {
1330 /*
1331 * XXX anything else that needs to be finished?
1332 */
1333
1334 PORT_FreeArena (cx->our_pool, PR_FALSE);
1335 }
1336
1337
1338 SEC_ASN1EncoderContext *
1339 SEC_ASN1EncoderStart (const void *src, const SecAsn1Template *theTemplate,
1340 SEC_ASN1WriteProc output_proc, void *output_arg)
1341 {
1342 PRArenaPool *our_pool;
1343 SEC_ASN1EncoderContext *cx;
1344
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");
1348 return NULL;
1349 }
1350
1351 cx = (SEC_ASN1EncoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
1352 if (cx == NULL) {
1353 syslog(LOG_ERR,"SEC_ASN1EncoderStart: failed to alloc");
1354 PORT_FreeArena (our_pool, PR_FALSE);
1355 return NULL;
1356 }
1357
1358 cx->our_pool = our_pool;
1359 cx->output_proc = output_proc;
1360 cx->output_arg = output_arg;
1361
1362 cx->status = keepGoing;
1363
1364 if (sec_asn1e_push_state(cx, theTemplate, src, PR_FALSE) == NULL
1365 || sec_asn1e_init_state_based_on_template (cx->current) == NULL) {
1366 /*
1367 * Trouble initializing (probably due to failed allocations)
1368 * requires that we just give up.
1369 */
1370 syslog(LOG_ERR, "SEC_ASN1EncoderStart: unable to initialize state");
1371 PORT_FreeArena (our_pool, PR_FALSE);
1372 return NULL;
1373 }
1374
1375 return cx;
1376 }
1377
1378
1379 /*
1380 * XXX Do we need a FilterProc, too?
1381 */
1382
1383
1384 void
1385 SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext *cx,
1386 SEC_ASN1NotifyProc fn, void *arg)
1387 {
1388 cx->notify_proc = fn;
1389 cx->notify_arg = arg;
1390 }
1391
1392
1393 void
1394 SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext *cx)
1395 {
1396 cx->notify_proc = NULL;
1397 cx->notify_arg = NULL; /* not necessary; just being clean */
1398 }
1399
1400
1401 void
1402 SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error)
1403 {
1404 PORT_Assert(cx);
1405 PORT_SetError(error);
1406 cx->status = encodeError;
1407 }
1408
1409
1410 void
1411 SEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext *cx)
1412 {
1413 /* XXX is there a way to check that we are "between" fields here? */
1414
1415 cx->streaming = PR_TRUE;
1416 }
1417
1418
1419 void
1420 SEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext *cx)
1421 {
1422 /* XXX is there a way to check that we are "between" fields here? */
1423
1424 cx->streaming = PR_FALSE;
1425 }
1426
1427
1428 void
1429 SEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext *cx)
1430 {
1431 /*
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.
1435 */
1436 PORT_Assert (cx->streaming);
1437
1438 cx->from_buf = PR_TRUE;
1439 }
1440
1441
1442 void
1443 SEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext *cx)
1444 {
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 */
1448 return;
1449
1450 cx->from_buf = PR_FALSE;
1451
1452 if (cx->status == needBytes) {
1453 cx->status = keepGoing;
1454 cx->current->place = afterContents;
1455 }
1456 }
1457
1458
1459 SECStatus
1460 SEC_ASN1Encode (const void *src, const SecAsn1Template *theTemplate,
1461 SEC_ASN1WriteProc output_proc, void *output_arg)
1462 {
1463 SEC_ASN1EncoderContext *ecx;
1464 SECStatus rv;
1465
1466 ecx = SEC_ASN1EncoderStart (src, theTemplate, output_proc, output_arg);
1467 if (ecx == NULL)
1468 return SECFailure;
1469
1470 rv = SEC_ASN1EncoderUpdate (ecx, NULL, 0);
1471
1472 if (rv != SECSuccess)
1473 syslog(LOG_ERR,"SEC_ASN1Encode: encode failure");
1474
1475 SEC_ASN1EncoderFinish (ecx);
1476 return rv;
1477 }
1478
1479
1480 /*
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)
1483 */
1484 void
1485 sec_asn1e_encode_item_count (void *arg, const char *buf, size_t len,
1486 int depth, SEC_ASN1EncodingPart data_kind)
1487 {
1488 size_t *count;
1489
1490 count = (unsigned long*)arg;
1491 PORT_Assert (count != NULL);
1492
1493 *count += len;
1494 }
1495
1496
1497 /* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
1498 void
1499 sec_asn1e_encode_item_store (void *arg, const char *buf, size_t len,
1500 int depth, SEC_ASN1EncodingPart data_kind)
1501 {
1502 SecAsn1Item *dest;
1503
1504 dest = (SecAsn1Item*)arg;
1505 PORT_Assert (dest != NULL);
1506
1507 PORT_Memcpy (dest->Data + dest->Length, buf, len);
1508 dest->Length += len;
1509 }
1510
1511
1512 /*
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.
1516 *
1517 * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
1518 */
1519 SecAsn1Item *
1520 sec_asn1e_allocate_item (PRArenaPool *poolp, SecAsn1Item *dest, unsigned long len)
1521 {
1522 if (poolp != NULL) {
1523 void *release;
1524
1525 release = PORT_ArenaMark (poolp);
1526 if (dest == NULL)
1527 dest = (SecAsn1Item*)PORT_ArenaAlloc (poolp, sizeof(SecAsn1Item));
1528 if (dest != NULL) {
1529 dest->Data = (unsigned char*)PORT_ArenaAlloc (poolp, len);
1530 if (dest->Data == NULL) {
1531 dest = NULL;
1532 }
1533 }
1534 if (dest == NULL) {
1535 /* one or both allocations failed; release everything */
1536 PORT_ArenaRelease (poolp, release);
1537 } else {
1538 /* everything okay; unmark the arena */
1539 PORT_ArenaUnmark (poolp, release);
1540 }
1541 } else {
1542 SecAsn1Item *indest;
1543
1544 indest = dest;
1545 if (dest == NULL)
1546 dest = (SecAsn1Item*)PORT_Alloc (sizeof(SecAsn1Item));
1547 if (dest != NULL) {
1548 #ifndef __APPLE__
1549 dest->type = siBuffer;
1550 #endif
1551 dest->Data = (unsigned char*)PORT_Alloc (len);
1552 if (dest->Data == NULL) {
1553 if (indest == NULL)
1554 PORT_Free (dest);
1555 dest = NULL;
1556 }
1557 }
1558 }
1559
1560 return dest;
1561 }
1562
1563
1564 SecAsn1Item *
1565 SEC_ASN1EncodeItem (PRArenaPool *poolp, SecAsn1Item *dest, const void *src,
1566 const SecAsn1Template *theTemplate)
1567 {
1568 unsigned long encoding_length;
1569 SECStatus rv;
1570
1571 PORT_Assert (dest == NULL || dest->Data == NULL);
1572
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);
1578 return NULL;
1579 }
1580
1581 dest = sec_asn1e_allocate_item (poolp, dest, encoding_length);
1582 if (dest == NULL) {
1583 syslog(LOG_ERR, "SEC_ASN1EncodeItem: allocate failure");
1584 return NULL;
1585 }
1586
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");
1591 return NULL;
1592 }
1593
1594 dest->Length = 0;
1595 (void) SEC_ASN1Encode (src, theTemplate, sec_asn1e_encode_item_store, dest);
1596
1597 PORT_Assert (encoding_length == dest->Length);
1598 return dest;
1599 }
1600
1601
1602 static SecAsn1Item *
1603 sec_asn1e_integer(PRArenaPool *poolp, SecAsn1Item *dest, unsigned long value,
1604 PRBool make_unsigned)
1605 {
1606 unsigned long copy;
1607 unsigned char sign;
1608 int len = 0;
1609
1610 /*
1611 * Determine the length of the encoded value (minimum of 1).
1612 */
1613 copy = value;
1614 do {
1615 len++;
1616 sign = (unsigned char)(copy & 0x80);
1617 copy >>= 8;
1618 } while (copy);
1619
1620 /*
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.
1624 */
1625 if (sign && make_unsigned)
1626 len++;
1627
1628 /*
1629 * Allocate the item (if necessary) and the data pointer within.
1630 */
1631 dest = sec_asn1e_allocate_item (poolp, dest, len);
1632 if (dest == NULL)
1633 return NULL;
1634
1635 /*
1636 * Store the value, byte by byte, in the item.
1637 */
1638 dest->Length = len;
1639 while (len) {
1640 dest->Data[--len] = (unsigned char)value;
1641 value >>= 8;
1642 }
1643 PORT_Assert (value == 0);
1644
1645 return dest;
1646 }
1647
1648
1649 SecAsn1Item *
1650 SEC_ASN1EncodeInteger(PRArenaPool *poolp, SecAsn1Item *dest, long value)
1651 {
1652 return sec_asn1e_integer (poolp, dest, (unsigned long) value, PR_FALSE);
1653 }
1654
1655
1656 extern SecAsn1Item *
1657 SEC_ASN1EncodeUnsignedInteger(PRArenaPool *poolp,
1658 SecAsn1Item *dest, unsigned long value)
1659 {
1660 return sec_asn1e_integer (poolp, dest, value, PR_TRUE);
1661 }