secasn1e.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:38k
源码类别:

CA认证

开发平台:

WINDOWS

  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.  * Support for ENcoding ASN.1 data based on BER/DER (Basic/Distinguished
  35.  * Encoding Rules).
  36.  *
  37.  * $Id: secasn1e.c,v 1.2 2000/06/13 21:56:37 chrisk%netscape.com Exp $
  38.  */
  39. #include "secasn1.h"
  40. typedef enum {
  41.     beforeHeader,
  42.     duringContents,
  43.     duringGroup,
  44.     duringSequence,
  45.     afterContents,
  46.     afterImplicit,
  47.     afterInline,
  48.     afterPointer,
  49.     afterChoice,
  50.     notInUse
  51. } sec_asn1e_parse_place;
  52. typedef enum {
  53.     allDone,
  54.     encodeError,
  55.     keepGoing,
  56.     needBytes
  57. } sec_asn1e_parse_status;
  58. typedef struct sec_asn1e_state_struct {
  59.     SEC_ASN1EncoderContext *top;
  60.     const SEC_ASN1Template *theTemplate;
  61.     void *src;
  62.     struct sec_asn1e_state_struct *parent; /* aka prev */
  63.     struct sec_asn1e_state_struct *child; /* aka next */
  64.     sec_asn1e_parse_place place; /* where we are in encoding process */
  65.     /*
  66.      * XXX explain the next fields as clearly as possible...
  67.      */
  68.     unsigned char tag_modifiers;
  69.     unsigned char tag_number;
  70.     unsigned long underlying_kind;
  71.     int depth;
  72.     PRBool explicit, /* we are handling an explicit header */
  73.    indefinite, /* need end-of-contents */
  74.    is_string, /* encoding a simple string or an ANY */
  75.    may_stream, /* when streaming, do indefinite encoding */
  76.    optional; /* omit field if it has no contents */
  77. } sec_asn1e_state;
  78. /*
  79.  * An "outsider" will have an opaque pointer to this, created by calling
  80.  * SEC_ASN1EncoderStart().  It will be passed back in to all subsequent
  81.  * calls to SEC_ASN1EncoderUpdate() and related routines, and when done
  82.  * it is passed to SEC_ASN1EncoderFinish().
  83.  */
  84. struct sec_EncoderContext_struct {
  85.     PRArenaPool *our_pool; /* for our internal allocs */
  86.     sec_asn1e_state *current;
  87.     sec_asn1e_parse_status status;
  88.     PRBool streaming;
  89.     PRBool from_buf;
  90.     SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */
  91.     void *notify_arg; /* argument to notify_proc */
  92.     PRBool during_notify; /* true during call to notify_proc */
  93.     SEC_ASN1WriteProc output_proc; /* pass encoded bytes to this  */
  94.     void *output_arg; /* argument to that function */
  95. };
  96. static sec_asn1e_state *
  97. sec_asn1e_push_state (SEC_ASN1EncoderContext *cx,
  98.       const SEC_ASN1Template *theTemplate,
  99.       void *src, PRBool new_depth)
  100. {
  101.     sec_asn1e_state *state, *new_state;
  102.     state = cx->current;
  103.     new_state = (sec_asn1e_state*)PORT_ArenaZAlloc (cx->our_pool, 
  104.     sizeof(*new_state));
  105.     if (new_state == NULL) {
  106. cx->status = encodeError;
  107. return NULL;
  108.     }
  109.     new_state->top = cx;
  110.     new_state->parent = state;
  111.     new_state->theTemplate = theTemplate;
  112.     new_state->place = notInUse;
  113.     if (src != NULL)
  114. new_state->src = (char *)src + theTemplate->offset;
  115.     if (state != NULL) {
  116. new_state->depth = state->depth;
  117. if (new_depth)
  118.     new_state->depth++;
  119. state->child = new_state;
  120.     }
  121.     cx->current = new_state;
  122.     return new_state;
  123. }
  124. static void
  125. sec_asn1e_scrub_state (sec_asn1e_state *state)
  126. {
  127.     /*
  128.      * Some default "scrubbing".
  129.      * XXX right set of initializations?
  130.      */
  131.     state->place = beforeHeader;
  132.     state->indefinite = PR_FALSE;
  133. }
  134. static void
  135. sec_asn1e_notify_before (SEC_ASN1EncoderContext *cx, void *src, int depth)
  136. {
  137.     if (cx->notify_proc == NULL)
  138. return;
  139.     cx->during_notify = PR_TRUE;
  140.     (* cx->notify_proc) (cx->notify_arg, PR_TRUE, src, depth);
  141.     cx->during_notify = PR_FALSE;
  142. }
  143. static void
  144. sec_asn1e_notify_after (SEC_ASN1EncoderContext *cx, void *src, int depth)
  145. {
  146.     if (cx->notify_proc == NULL)
  147. return;
  148.     cx->during_notify = PR_TRUE;
  149.     (* cx->notify_proc) (cx->notify_arg, PR_FALSE, src, depth);
  150.     cx->during_notify = PR_FALSE;
  151. }
  152. static sec_asn1e_state *
  153. sec_asn1e_init_state_based_on_template (sec_asn1e_state *state)
  154. {
  155.     PRBool explicit, is_string, may_stream, optional, universal;
  156.     unsigned char tag_modifiers;
  157.     unsigned long encode_kind, under_kind;
  158.     unsigned long tag_number;
  159.     encode_kind = state->theTemplate->kind;
  160.     universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
  161. ? PR_TRUE : PR_FALSE;
  162.     explicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
  163.     encode_kind &= ~SEC_ASN1_EXPLICIT;
  164.     optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
  165.     encode_kind &= ~SEC_ASN1_OPTIONAL;
  166.     PORT_Assert (!(explicit && universal)); /* bad templates */
  167.     may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
  168.     encode_kind &= ~SEC_ASN1_MAY_STREAM;
  169.     /* Just clear this to get it out of the way; we do not need it here */
  170.     encode_kind &= ~SEC_ASN1_DYNAMIC;
  171.     if( encode_kind & SEC_ASN1_CHOICE ) {
  172.       under_kind = SEC_ASN1_CHOICE;
  173.     } else
  174.     if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || (!universal
  175.       && !explicit)) {
  176. const SEC_ASN1Template *subt;
  177. void *src;
  178. PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);
  179. sec_asn1e_scrub_state (state);
  180. if (encode_kind & SEC_ASN1_POINTER) {
  181.     /*
  182.      * XXX This used to PORT_Assert (encode_kind == SEC_ASN1_POINTER);
  183.      * but that was too restrictive.  This needs to be fixed,
  184.      * probably copying what the decoder now checks for, and
  185.      * adding a big comment here to explain what the checks mean.
  186.      */
  187.     src = *(void **)state->src;
  188.     state->place = afterPointer;
  189.     if (src == NULL) {
  190. /*
  191.  * If this is optional, but NULL, then the field does
  192.  * not need to be encoded.  In this case we are done;
  193.  * we do not want to push a subtemplate.
  194.  */
  195. if (optional)
  196.     return state;
  197. /*
  198.  * XXX this is an error; need to figure out
  199.  * how to handle this
  200.  */
  201.     }
  202. } else {
  203.     src = state->src;
  204.     if (encode_kind & SEC_ASN1_INLINE) {
  205. /* check that there are no extraneous bits */
  206. PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional);
  207. state->place = afterInline;
  208.     } else {
  209. /*
  210.  * Save the tag modifiers and tag number here before moving
  211.  * on to the next state in case this is a member of a
  212.  * SEQUENCE OF
  213.  */
  214. state->tag_modifiers = encode_kind & SEC_ASN1_TAG_MASK
  215. & ~SEC_ASN1_TAGNUM_MASK;
  216. state->tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
  217. state->place = afterImplicit;
  218. state->optional = optional;
  219.     }
  220. }
  221. subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src, PR_TRUE);
  222. state = sec_asn1e_push_state (state->top, subt, src, PR_FALSE);
  223. if (state == NULL)
  224.     return NULL;
  225. if (universal) {
  226.     /*
  227.      * This is a POINTER or INLINE; just init based on that
  228.      * and we are done.
  229.      */
  230.     return sec_asn1e_init_state_based_on_template (state);
  231. }
  232. /*
  233.  * This is an implicit, non-universal (meaning, application-private
  234.  * or context-specific) field.  This results in a "magic" tag but
  235.  * encoding based on the underlying type.  We pushed a new state
  236.  * that is based on the subtemplate (the underlying type), but
  237.  * now we will sort of alias it to give it some of our properties
  238.  * (tag, optional status, etc.).
  239.  */
  240. under_kind = state->theTemplate->kind;
  241. if (under_kind & SEC_ASN1_MAY_STREAM) {
  242.     may_stream = PR_TRUE;
  243.     under_kind &= ~SEC_ASN1_MAY_STREAM;
  244. }
  245.     } else {
  246. under_kind = encode_kind;
  247.     }
  248.     /*
  249.      * Sanity check that there are no unwanted bits marked in under_kind.
  250.      * These bits were either removed above (after we recorded them) or
  251.      * they simply should not be found (signalling a bad/broken template).
  252.      * XXX is this the right set of bits to test here? (i.e. need to add
  253.      * or remove any?)
  254.      */
  255.     PORT_Assert ((under_kind & (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL
  256. | SEC_ASN1_SKIP | SEC_ASN1_INNER
  257. | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM
  258. | SEC_ASN1_INLINE | SEC_ASN1_POINTER)) == 0);
  259.     if (encode_kind & SEC_ASN1_ANY) {
  260. PORT_Assert (encode_kind == under_kind);
  261. tag_modifiers = 0;
  262. tag_number = 0;
  263. is_string = PR_TRUE;
  264.     } else {
  265. tag_modifiers = encode_kind & SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK;
  266. /*
  267.  * XXX This assumes only single-octet identifiers.  To handle
  268.  * the HIGH TAG form we would need to do some more work, especially
  269.  * in how to specify them in the template, because right now we
  270.  * do not provide a way to specify more *tag* bits in encode_kind.
  271.  */
  272. tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
  273. is_string = PR_FALSE;
  274. switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
  275.   case SEC_ASN1_SET:
  276.     /*
  277.      * XXX A plain old SET (as opposed to a SET OF) is not implemented.
  278.      * If it ever is, remove this assert...
  279.      */
  280.     PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
  281.     /* fallthru */
  282.   case SEC_ASN1_SEQUENCE:
  283.     tag_modifiers |= SEC_ASN1_CONSTRUCTED;
  284.     break;
  285.   case SEC_ASN1_BIT_STRING:
  286.   case SEC_ASN1_BMP_STRING: 
  287.   case SEC_ASN1_GENERALIZED_TIME:
  288.   case SEC_ASN1_IA5_STRING:
  289.   case SEC_ASN1_OCTET_STRING:
  290.   case SEC_ASN1_PRINTABLE_STRING:
  291.   case SEC_ASN1_T61_STRING:
  292.   case SEC_ASN1_UNIVERSAL_STRING: 
  293.   case SEC_ASN1_UTC_TIME:
  294.   case SEC_ASN1_UTF8_STRING:
  295.   case SEC_ASN1_VISIBLE_STRING: 
  296.     /*
  297.      * We do not yet know if we will be constructing the string,
  298.      * so we have to wait to do this final tag modification.
  299.      */
  300.     is_string = PR_TRUE;
  301.     break;
  302. }
  303.     }
  304.     state->tag_modifiers = tag_modifiers;
  305.     state->tag_number = tag_number;
  306.     state->underlying_kind = under_kind;
  307.     state->explicit = explicit;
  308.     state->may_stream = may_stream;
  309.     state->is_string = is_string;
  310.     state->optional = optional;
  311.     sec_asn1e_scrub_state (state);
  312.     return state;
  313. }
  314. static void
  315. sec_asn1e_write_part (sec_asn1e_state *state,
  316.       const char *buf, unsigned long len,
  317.       SEC_ASN1EncodingPart part)
  318. {
  319.     SEC_ASN1EncoderContext *cx;
  320.     cx = state->top;
  321.     (* cx->output_proc) (cx->output_arg, buf, len, state->depth, part);
  322. }
  323. /*
  324.  * XXX This assumes only single-octet identifiers.  To handle
  325.  * the HIGH TAG form we would need to modify this interface and
  326.  * teach it to properly encode the special form.
  327.  */
  328. static void
  329. sec_asn1e_write_identifier_bytes (sec_asn1e_state *state, unsigned char value)
  330. {
  331.     char byte;
  332.     byte = (char) value;
  333.     sec_asn1e_write_part (state, &byte, 1, SEC_ASN1_Identifier);
  334. }
  335. int
  336. SEC_ASN1EncodeLength(unsigned char *buf,int value) {
  337.     int lenlen;
  338.     lenlen = SEC_ASN1LengthLength (value);
  339.     if (lenlen == 1) {
  340. buf[0] = value;
  341.     } else {
  342. int i;
  343. i = lenlen - 1;
  344. buf[0] = 0x80 | i;
  345. while (i) {
  346.     buf[i--] = value;
  347.     value >>= 8;
  348. }
  349.         PORT_Assert (value == 0);
  350.     }
  351.     return lenlen;
  352. }
  353. static void
  354. sec_asn1e_write_length_bytes (sec_asn1e_state *state, unsigned long value,
  355.       PRBool indefinite)
  356. {
  357.     int lenlen;
  358.     unsigned char buf[sizeof(unsigned long) + 1];
  359.     if (indefinite) {
  360. PORT_Assert (value == 0);
  361. buf[0] = 0x80;
  362. lenlen = 1;
  363.     } else {
  364. lenlen = SEC_ASN1EncodeLength(buf,value);
  365.     }
  366.     sec_asn1e_write_part (state, (char *) buf, lenlen, SEC_ASN1_Length);
  367. }
  368. static void
  369. sec_asn1e_write_contents_bytes (sec_asn1e_state *state,
  370. const char *buf, unsigned long len)
  371. {
  372.     sec_asn1e_write_part (state, buf, len, SEC_ASN1_Contents);
  373. }
  374. static void
  375. sec_asn1e_write_end_of_contents_bytes (sec_asn1e_state *state)
  376. {
  377.     const char eoc[2] = {0, 0};
  378.     sec_asn1e_write_part (state, eoc, 2, SEC_ASN1_EndOfContents);
  379. }
  380. static int
  381. sec_asn1e_which_choice
  382. (
  383.   void *src,
  384.   const SEC_ASN1Template *theTemplate
  385. )
  386. {
  387.   int rv;
  388.   int which = *(int *)((char *)src + theTemplate->offset);
  389.   for( rv = 1, theTemplate++; theTemplate->kind != 0; rv++, theTemplate++ ) {
  390.     if( which == theTemplate->size ) {
  391.       return rv;
  392.     }
  393.   }
  394.   return 0;
  395. }
  396. static unsigned long
  397. sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src,
  398.    PRBool *noheaderp)
  399. {
  400.     unsigned long encode_kind, underlying_kind;
  401.     PRBool explicit, optional, universal, may_stream;
  402.     unsigned long len;
  403.     encode_kind = theTemplate->kind;
  404.     universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
  405. ? PR_TRUE : PR_FALSE;
  406.     explicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
  407.     encode_kind &= ~SEC_ASN1_EXPLICIT;
  408.     optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
  409.     encode_kind &= ~SEC_ASN1_OPTIONAL;
  410.     PORT_Assert (!(explicit && universal)); /* bad templates */
  411.     may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
  412.     encode_kind &= ~SEC_ASN1_MAY_STREAM;
  413.     /* Just clear this to get it out of the way; we do not need it here */
  414.     encode_kind &= ~SEC_ASN1_DYNAMIC;
  415.     if( encode_kind & SEC_ASN1_CHOICE ) {
  416.       void *src2;
  417.       int indx = sec_asn1e_which_choice(src, theTemplate);
  418.       if( 0 == indx ) {
  419.         /* XXX set an error? "choice not found" */
  420.         /* state->top->status = encodeError; */
  421.         return 0;
  422.       }
  423.       src2 = (void *)((char *)src + theTemplate[indx].offset);
  424.       return sec_asn1e_contents_length(&theTemplate[indx], src2, noheaderp);
  425.     }
  426.     if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || !universal) {
  427. /* XXX any bits we want to disallow (PORT_Assert against) here? */
  428. theTemplate = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);
  429. if (encode_kind & SEC_ASN1_POINTER) {
  430.     /*
  431.      * XXX This used to PORT_Assert (encode_kind == SEC_ASN1_POINTER);
  432.      * but that was too restrictive.  This needs to be fixed,
  433.      * probably copying what the decoder now checks for, and
  434.      * adding a big comment here to explain what the checks mean.
  435.      * Alternatively, the check here could be omitted altogether
  436.      * just letting sec_asn1e_init_state_based_on_template
  437.      * do it, since that routine can do better error handling, too.
  438.      */
  439.     src = *(void **)src;
  440.     if (src == NULL) {
  441. if (optional)
  442.     *noheaderp = PR_TRUE;
  443. else 
  444.     *noheaderp = PR_FALSE;
  445. return 0;
  446.     }
  447. } else if (encode_kind & SEC_ASN1_INLINE) {
  448.     /* check that there are no extraneous bits */
  449.     PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional);
  450. }
  451. src = (char *)src + theTemplate->offset;
  452. if (explicit) {
  453.     len = sec_asn1e_contents_length (theTemplate, src, noheaderp);
  454.     if (len == 0 && optional) {
  455. *noheaderp = PR_TRUE;
  456.     } else if (*noheaderp) {
  457. /* Okay, *we* do not want to add in a header, but our caller still does. */
  458. *noheaderp = PR_FALSE;
  459.     } else {
  460. /* if the inner content exists, our length is
  461.  * len(identifier) + len(length) + len(innercontent)
  462.  * XXX we currently assume len(identifier) == 1;
  463.  * to support a high-tag-number this would need to be smarter.
  464.  */
  465. len += 1 + SEC_ASN1LengthLength (len);
  466.     }
  467.     return len;
  468. }
  469. underlying_kind = theTemplate->kind;
  470. underlying_kind &= ~SEC_ASN1_MAY_STREAM;
  471. /* XXX Should we recurse here? */
  472.     } else {
  473. underlying_kind = encode_kind;
  474.     }
  475.     /* This is only used in decoding; it plays no part in encoding.  */
  476.     if (underlying_kind & SEC_ASN1_SAVE) {
  477. /* check that there are no extraneous bits */
  478. PORT_Assert (underlying_kind == SEC_ASN1_SAVE);
  479. *noheaderp = PR_TRUE;
  480. return 0;
  481.     }
  482.     /* Having any of these bits is not expected here...  */
  483.     PORT_Assert ((underlying_kind & (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL
  484.      | SEC_ASN1_INLINE | SEC_ASN1_POINTER
  485.      | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM
  486.      | SEC_ASN1_SAVE | SEC_ASN1_SKIP)) == 0);
  487.     if( underlying_kind & SEC_ASN1_CHOICE ) {
  488.       void *src2;
  489.       int indx = sec_asn1e_which_choice(src, theTemplate);
  490.       if( 0 == indx ) {
  491.         /* XXX set an error? "choice not found" */
  492.         /* state->top->status = encodeError; */
  493.         return 0;
  494.       }
  495.       src2 = (void *)((char *)src - theTemplate->offset + theTemplate[indx].offset);
  496.       len = sec_asn1e_contents_length(&theTemplate[indx], src2, noheaderp);
  497.     } else
  498.     switch (underlying_kind) {
  499.       case SEC_ASN1_SEQUENCE_OF:
  500.       case SEC_ASN1_SET_OF:
  501. {
  502.     const SEC_ASN1Template *tmpt;
  503.     void *sub_src;
  504.     unsigned long sub_len;
  505.     void **group;
  506.     len = 0;
  507.     group = *(void ***)src;
  508.     if (group == NULL)
  509. break;
  510.     tmpt = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);
  511.     for (; *group != NULL; group++) {
  512. sub_src = (char *)(*group) + tmpt->offset;
  513. sub_len = sec_asn1e_contents_length (tmpt, sub_src, noheaderp);
  514. len += sub_len;
  515. /*
  516.  * XXX The 1 below is the presumed length of the identifier;
  517.  * to support a high-tag-number this would need to be smarter.
  518.  */
  519. if (!*noheaderp)
  520.     len += 1 + SEC_ASN1LengthLength (sub_len);
  521.     }
  522. }
  523. break;
  524.       case SEC_ASN1_SEQUENCE:
  525.       case SEC_ASN1_SET:
  526. {
  527.     const SEC_ASN1Template *tmpt;
  528.     void *sub_src;
  529.     unsigned long sub_len;
  530.     len = 0;
  531.     for (tmpt = theTemplate + 1; tmpt->kind; tmpt++) {
  532. sub_src = (char *)src + tmpt->offset;
  533. sub_len = sec_asn1e_contents_length (tmpt, sub_src, noheaderp);
  534. len += sub_len;
  535. /*
  536.  * XXX The 1 below is the presumed length of the identifier;
  537.  * to support a high-tag-number this would need to be smarter.
  538.  */
  539. if (!*noheaderp)
  540.     len += 1 + SEC_ASN1LengthLength (sub_len);
  541.     }
  542. }
  543. break;
  544.       case SEC_ASN1_BIT_STRING:
  545. /* convert bit length to byte */
  546. len = (((SECItem *)src)->len + 7) >> 3;
  547. /* bit string contents involve an extra octet */
  548. if (len)
  549.     len++;
  550. break;
  551.       default:
  552. len = ((SECItem *)src)->len;
  553. if (may_stream && len == 0)
  554.     len = 1; /* if we're streaming, we may have a secitem w/len 0 as placeholder */
  555. break;
  556.     }
  557.     if ((len == 0 && optional) || underlying_kind == SEC_ASN1_ANY)
  558. *noheaderp = PR_TRUE;
  559.     else 
  560. *noheaderp = PR_FALSE;
  561.     return len;
  562. }
  563. static void
  564. sec_asn1e_write_header (sec_asn1e_state *state)
  565. {
  566.     unsigned long contents_length;
  567.     unsigned char tag_number, tag_modifiers;
  568.     PRBool noheader;
  569.     PORT_Assert (state->place == beforeHeader);
  570.     tag_number = state->tag_number;
  571.     tag_modifiers = state->tag_modifiers;
  572.     if (state->underlying_kind == SEC_ASN1_ANY) {
  573. state->place = duringContents;
  574. return;
  575.     }
  576.     if( state->underlying_kind & SEC_ASN1_CHOICE ) {
  577.       void *src2;
  578.       int indx = sec_asn1e_which_choice(state->src, state->theTemplate);
  579.       if( 0 == indx ) {
  580.         /* XXX set an error? "choice not found" */
  581.         state->top->status = encodeError;
  582.         return;
  583.       }
  584.       state->place = afterChoice;
  585.       state = sec_asn1e_push_state(state->top, &state->theTemplate[indx],
  586.                                    state->src, PR_TRUE);
  587.       if( (sec_asn1e_state *)NULL != state ) {
  588.         /*
  589.          * Do the "before" field notification.
  590.          */
  591.         sec_asn1e_notify_before (state->top, state->src, state->depth);
  592.         state = sec_asn1e_init_state_based_on_template (state);
  593.       }
  594.       
  595.       return;
  596.     }
  597.     /*
  598.      * We are doing a definite-length encoding.  First we have to
  599.      * walk the data structure to calculate the entire contents length.
  600.      */
  601.     contents_length = sec_asn1e_contents_length (state->theTemplate,
  602.  state->src, &noheader);
  603.     /*
  604.      * We might be told explicitly not to put out a header.
  605.      * But it can also be the case, via a pushed subtemplate, that
  606.      * sec_asn1e_contents_length could not know that this field is
  607.      * really optional.  So check for that explicitly, too.
  608.      */
  609.     if (noheader || (contents_length == 0 && state->optional)) {
  610. state->place = afterContents;
  611. if (state->top->streaming && state->may_stream && state->top->from_buf)
  612.     /* we did not find an optional indefinite string, so we don't encode it.
  613.      * However, if TakeFromBuf is on, we stop here anyway to give our caller
  614.      * a chance to intercept at the same point where we would stop if the
  615.      * field were present. */
  616.     state->top->status = needBytes;
  617. return;
  618.     }
  619.     if (state->top->streaming && state->may_stream
  620.       && (state->top->from_buf || !state->is_string)) {
  621. /*
  622.  * We need to put out an indefinite-length encoding.
  623.  */
  624. state->indefinite = PR_TRUE;
  625. /*
  626.  * The only universal types that can be constructed are SETs,
  627.  * SEQUENCEs, and strings; so check that it is one of those,
  628.  * or that it is not universal (e.g. context-specific).
  629.  */
  630. PORT_Assert ((tag_number == SEC_ASN1_SET)
  631.      || (tag_number == SEC_ASN1_SEQUENCE)
  632.      || ((tag_modifiers & SEC_ASN1_CLASS_MASK) != 0)
  633.      || state->is_string);
  634. tag_modifiers |= SEC_ASN1_CONSTRUCTED;
  635. contents_length = 0;
  636.     }
  637.     sec_asn1e_write_identifier_bytes (state, tag_number | tag_modifiers);
  638.     sec_asn1e_write_length_bytes (state, contents_length, state->indefinite);
  639.     if (contents_length == 0 && !state->indefinite) {
  640. /*
  641.  * If no real contents to encode, then we are done with this field.
  642.  */
  643. state->place = afterContents;
  644. return;
  645.     }
  646.     /*
  647.      * An EXPLICIT is nothing but an outer header, which we have already
  648.      * written.  Now we need to do the inner header and contents.
  649.      */
  650.     if (state->explicit) {
  651. state->place = afterContents;
  652. state = sec_asn1e_push_state (state->top,
  653.       SEC_ASN1GetSubtemplate(state->theTemplate,
  654.      state->src,
  655.      PR_TRUE),
  656.       state->src, PR_TRUE);
  657. if (state != NULL)
  658.     state = sec_asn1e_init_state_based_on_template (state);
  659. return;
  660.     }
  661.     switch (state->underlying_kind) {
  662.       case SEC_ASN1_SET_OF:
  663.       case SEC_ASN1_SEQUENCE_OF:
  664. /*
  665.  * We need to push a child to handle each member.
  666.  */
  667. {
  668.     void **group;
  669.     const SEC_ASN1Template *subt;
  670.     group = *(void ***)state->src;
  671.     if (group == NULL || *group == NULL) {
  672. /*
  673.  * Group is empty; we are done.
  674.  */
  675. state->place = afterContents;
  676. return;
  677.     }
  678.     state->place = duringGroup;
  679.     subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src,
  680.    PR_TRUE);
  681.     state = sec_asn1e_push_state (state->top, subt, *group, PR_TRUE);
  682.     if (state != NULL)
  683. state = sec_asn1e_init_state_based_on_template (state);
  684. }
  685. break;
  686.       case SEC_ASN1_SEQUENCE:
  687.       case SEC_ASN1_SET:
  688. /*
  689.  * We need to push a child to handle the individual fields.
  690.  */
  691. state->place = duringSequence;
  692. state = sec_asn1e_push_state (state->top, state->theTemplate + 1,
  693.       state->src, PR_TRUE);
  694. if (state != NULL) {
  695.     /*
  696.      * Do the "before" field notification.
  697.      */
  698.     sec_asn1e_notify_before (state->top, state->src, state->depth);
  699.     state = sec_asn1e_init_state_based_on_template (state);
  700. }
  701. break;
  702.       default:
  703. /*
  704.  * I think we do not need to do anything else.
  705.  * XXX Correct?
  706.  */
  707. state->place = duringContents;
  708. break;
  709.     }
  710. }
  711. static void
  712. sec_asn1e_write_contents (sec_asn1e_state *state,
  713.   const char *buf, unsigned long len)
  714. {
  715.     PORT_Assert (state->place == duringContents);
  716.     if (state->top->from_buf) {
  717. /*
  718.  * Probably they just turned on "take from buf", but have not
  719.  * yet given us any bytes.  If there is nothing in the buffer
  720.  * then we have nothing to do but return and wait.
  721.  */
  722. if (buf == NULL || len == 0) {
  723.     state->top->status = needBytes;
  724.     return;
  725. }
  726. /*
  727.  * We are streaming, reading from a passed-in buffer.
  728.  * This means we are encoding a simple string or an ANY.
  729.  * For the former, we need to put out a substring, with its
  730.  * own identifier and length.  For an ANY, we just write it
  731.  * out as is (our caller is required to ensure that it
  732.  * is a properly encoded entity).
  733.  */
  734. PORT_Assert (state->is_string); /* includes ANY */
  735. if (state->underlying_kind != SEC_ASN1_ANY) {
  736.     unsigned char identifier;
  737.     /*
  738.      * Create the identifier based on underlying_kind.  We cannot
  739.      * use tag_number and tag_modifiers because this can be an
  740.      * implicitly encoded field.  In that case, the underlying
  741.      * substrings *are* encoded with their real tag.
  742.      */
  743.     identifier = state->underlying_kind & SEC_ASN1_TAG_MASK;
  744.     /*
  745.      * The underlying kind should just be a simple string; there
  746.      * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
  747.      */
  748.     PORT_Assert ((identifier & SEC_ASN1_TAGNUM_MASK) == identifier);
  749.     /*
  750.      * Write out the tag and length for the substring.
  751.      */
  752.     sec_asn1e_write_identifier_bytes (state, identifier);
  753.     if (state->underlying_kind == SEC_ASN1_BIT_STRING) {
  754. char byte;
  755. /*
  756.  * Assume we have a length in bytes but we need to output
  757.  * a proper bit string.  This interface only works for bit
  758.  * strings that are full multiples of 8.  If support for
  759.  * real, variable length bit strings is needed then the
  760.  * caller will have to know to pass in a bit length instead
  761.  * of a byte length and then this code will have to
  762.  * perform the encoding necessary (length written is length
  763.  * in bytes plus 1, and the first octet of string is the
  764.  * number of bits remaining between the end of the bit
  765.  * string and the next byte boundary).
  766.  */
  767. sec_asn1e_write_length_bytes (state, len + 1, PR_FALSE);
  768. byte = 0;
  769. sec_asn1e_write_contents_bytes (state, &byte, 1);
  770.     } else {
  771. sec_asn1e_write_length_bytes (state, len, PR_FALSE);
  772.     }
  773. }
  774. sec_asn1e_write_contents_bytes (state, buf, len);
  775. state->top->status = needBytes;
  776.     } else {
  777. switch (state->underlying_kind) {
  778.   case SEC_ASN1_SET:
  779.   case SEC_ASN1_SEQUENCE:
  780.     PORT_Assert (0);
  781.     break;
  782.   case SEC_ASN1_BIT_STRING:
  783.     {
  784. SECItem *item;
  785. char rem;
  786. item = (SECItem *)state->src;
  787. len = (item->len + 7) >> 3;
  788. rem = (len << 3) - item->len; /* remaining bits */
  789. sec_asn1e_write_contents_bytes (state, &rem, 1);
  790. sec_asn1e_write_contents_bytes (state, (char *) item->data,
  791. len);
  792.     }
  793.     break;
  794.   case SEC_ASN1_BMP_STRING:
  795.     /* The number of bytes must be divisable by 2 */
  796.     if ((((SECItem *)state->src)->len) % 2) {
  797. SEC_ASN1EncoderContext *cx;
  798. cx = state->top;
  799. cx->status = encodeError;
  800. break;
  801.     }
  802.     /* otherwise, fall through to write the content */
  803.     goto process_string;
  804.   case SEC_ASN1_UNIVERSAL_STRING:
  805.     /* The number of bytes must be divisable by 4 */
  806.     if ((((SECItem *)state->src)->len) % 4) {
  807. SEC_ASN1EncoderContext *cx;
  808. cx = state->top;
  809. cx->status = encodeError;
  810. break;
  811.     }
  812.     /* otherwise, fall through to write the content */
  813.     goto process_string;
  814. process_string:
  815.   default:
  816.     {
  817. SECItem *item;
  818. item = (SECItem *)state->src;
  819. sec_asn1e_write_contents_bytes (state, (char *) item->data,
  820. item->len);
  821.     }
  822.     break;
  823. }
  824. state->place = afterContents;
  825.     }
  826. }
  827. /*
  828.  * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
  829.  */
  830. static void
  831. sec_asn1e_next_in_group (sec_asn1e_state *state)
  832. {
  833.     sec_asn1e_state *child;
  834.     void **group;
  835.     void *member;
  836.     PORT_Assert (state->place == duringGroup);
  837.     PORT_Assert (state->child != NULL);
  838.     child = state->child;
  839.     group = *(void ***)state->src;
  840.     /*
  841.      * Find placement of current item.
  842.      */
  843.     member = (char *)(state->child->src) - child->theTemplate->offset;
  844.     while (*group != member)
  845. group++;
  846.     /*
  847.      * Move forward to next item.
  848.      */
  849.     group++;
  850.     if (*group == NULL) {
  851. /*
  852.  * That was our last one; we are done now.
  853.  */
  854. child->place = notInUse;
  855. state->place = afterContents;
  856. return;
  857.     }
  858.     child->src = (char *)(*group) + child->theTemplate->offset;
  859.     /*
  860.      * Re-"push" child.
  861.      */
  862.     sec_asn1e_scrub_state (child);
  863.     state->top->current = child;
  864. }
  865. /*
  866.  * We are moving along through a sequence; move forward by one,
  867.  * (detecting end-of-sequence when it happens).
  868.  */
  869. static void
  870. sec_asn1e_next_in_sequence (sec_asn1e_state *state)
  871. {
  872.     sec_asn1e_state *child;
  873.     PORT_Assert (state->place == duringSequence);
  874.     PORT_Assert (state->child != NULL);
  875.     child = state->child;
  876.     /*
  877.      * Do the "after" field notification.
  878.      */
  879.     sec_asn1e_notify_after (state->top, child->src, child->depth);
  880.     /*
  881.      * Move forward.
  882.      */
  883.     child->theTemplate++;
  884.     if (child->theTemplate->kind == 0) {
  885. /*
  886.  * We are done with this sequence.
  887.  */
  888. child->place = notInUse;
  889. state->place = afterContents;
  890. return;
  891.     }
  892.     /*
  893.      * Reset state and push.
  894.      */
  895.     child->src = (char *)state->src + child->theTemplate->offset;
  896.     /*
  897.      * Do the "before" field notification.
  898.      */
  899.     sec_asn1e_notify_before (state->top, child->src, child->depth);
  900.     state->top->current = child;
  901.     (void) sec_asn1e_init_state_based_on_template (child);
  902. }
  903. static void
  904. sec_asn1e_after_contents (sec_asn1e_state *state)
  905. {
  906.     PORT_Assert (state->place == afterContents);
  907.     if (state->indefinite)
  908. sec_asn1e_write_end_of_contents_bytes (state);
  909.     /*
  910.      * Just make my parent be the current state.  It will then clean
  911.      * up after me and free me (or reuse me).
  912.      */
  913.     state->top->current = state->parent;
  914. }
  915. /*
  916.  * This function is called whether or not we are streaming; if we
  917.  * *are* streaming, our caller can also instruct us to take bytes
  918.  * from the passed-in buffer (at buf, for length len, which is likely
  919.  * bytes but could even mean bits if the current field is a bit string).
  920.  * If we have been so instructed, we will gobble up bytes from there
  921.  * (rather than from our src structure) and output them, and then
  922.  * we will just return, expecting to be called again -- either with
  923.  * more bytes or after our caller has instructed us that we are done
  924.  * (for now) with the buffer.
  925.  */
  926. SECStatus
  927. SEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext *cx,
  928.        const char *buf, unsigned long len)
  929. {
  930.     sec_asn1e_state *state;
  931.     if (cx->status == needBytes) {
  932. PORT_Assert (buf != NULL && len != 0);
  933. cx->status = keepGoing;
  934.     }
  935.     while (cx->status == keepGoing) {
  936. state = cx->current;
  937. switch (state->place) {
  938.   case beforeHeader:
  939.     sec_asn1e_write_header (state);
  940.     break;
  941.   case duringContents:
  942.     sec_asn1e_write_contents (state, buf, len);
  943.     break;
  944.   case duringGroup:
  945.     sec_asn1e_next_in_group (state);
  946.     break;
  947.   case duringSequence:
  948.     sec_asn1e_next_in_sequence (state);
  949.     break;
  950.   case afterContents:
  951.     sec_asn1e_after_contents (state);
  952.     break;
  953.   case afterImplicit:
  954.   case afterInline:
  955.   case afterPointer:
  956.   case afterChoice:
  957.     /*
  958.      * These states are more documentation than anything.
  959.      * They just need to force a pop.
  960.      */
  961.     PORT_Assert (!state->indefinite);
  962.     state->place = afterContents;
  963.     break;
  964.   case notInUse:
  965.   default:
  966.     /* This is not an error, but rather a plain old BUG! */
  967.     PORT_Assert (0);
  968.     cx->status = encodeError;
  969.     break;
  970. }
  971. if (cx->status == encodeError)
  972.     break;
  973. /* It might have changed, so we have to update our local copy.  */
  974. state = cx->current;
  975. /* If it is NULL, we have popped all the way to the top.  */
  976. if (state == NULL) {
  977.     cx->status = allDone;
  978.     break;
  979. }
  980.     }
  981.     if (cx->status == encodeError) {
  982. return SECFailure;
  983.     }
  984.     return SECSuccess;
  985. }
  986. void
  987. SEC_ASN1EncoderFinish (SEC_ASN1EncoderContext *cx)
  988. {
  989.     /*
  990.      * XXX anything else that needs to be finished?
  991.      */
  992.     PORT_FreeArena (cx->our_pool, PR_FALSE);
  993. }
  994. SEC_ASN1EncoderContext *
  995. SEC_ASN1EncoderStart (void *src, const SEC_ASN1Template *theTemplate,
  996.       SEC_ASN1WriteProc output_proc, void *output_arg)
  997. {
  998.     PRArenaPool *our_pool;
  999.     SEC_ASN1EncoderContext *cx;
  1000.     our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
  1001.     if (our_pool == NULL)
  1002. return NULL;
  1003.     cx = (SEC_ASN1EncoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
  1004.     if (cx == NULL) {
  1005. PORT_FreeArena (our_pool, PR_FALSE);
  1006. return NULL;
  1007.     }
  1008.     cx->our_pool = our_pool;
  1009.     cx->output_proc = output_proc;
  1010.     cx->output_arg = output_arg;
  1011.     cx->status = keepGoing;
  1012.     if (sec_asn1e_push_state(cx, theTemplate, src, PR_FALSE) == NULL
  1013. || sec_asn1e_init_state_based_on_template (cx->current) == NULL) {
  1014. /*
  1015.  * Trouble initializing (probably due to failed allocations)
  1016.  * requires that we just give up.
  1017.  */
  1018. PORT_FreeArena (our_pool, PR_FALSE);
  1019. return NULL;
  1020.     }
  1021.     return cx;
  1022. }
  1023. /*
  1024.  * XXX Do we need a FilterProc, too?
  1025.  */
  1026. void
  1027. SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext *cx,
  1028.       SEC_ASN1NotifyProc fn, void *arg)
  1029. {
  1030.     cx->notify_proc = fn;
  1031.     cx->notify_arg = arg;
  1032. }
  1033. void
  1034. SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext *cx)
  1035. {
  1036.     cx->notify_proc = NULL;
  1037.     cx->notify_arg = NULL; /* not necessary; just being clean */
  1038. }
  1039. void
  1040. SEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext *cx)
  1041. {
  1042.     /* XXX is there a way to check that we are "between" fields here? */
  1043.     cx->streaming = PR_TRUE;
  1044. }
  1045. void
  1046. SEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext *cx)
  1047. {
  1048.     /* XXX is there a way to check that we are "between" fields here? */
  1049.     cx->streaming = PR_FALSE;
  1050. }
  1051. void
  1052. SEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext *cx)
  1053. {
  1054.     /* 
  1055.      * XXX is there a way to check that we are "between" fields here?  this
  1056.      * needs to include a check for being in between groups of items in
  1057.      * a SET_OF or SEQUENCE_OF.
  1058.      */
  1059.     PORT_Assert (cx->streaming);
  1060.     cx->from_buf = PR_TRUE;
  1061. }
  1062. void
  1063. SEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext *cx)
  1064. {
  1065.     /* we should actually be taking from buf *now* */
  1066.     PORT_Assert (cx->from_buf);
  1067.     if (! cx->from_buf) /* if not, just do nothing */
  1068. return;
  1069.     cx->from_buf = PR_FALSE;
  1070.     if (cx->status == needBytes) {
  1071. cx->status = keepGoing;
  1072. cx->current->place = afterContents;
  1073.     }
  1074. }
  1075. SECStatus
  1076. SEC_ASN1Encode (void *src, const SEC_ASN1Template *theTemplate,
  1077. SEC_ASN1WriteProc output_proc, void *output_arg)
  1078. {
  1079.     SEC_ASN1EncoderContext *ecx;
  1080.     SECStatus rv;
  1081.     ecx = SEC_ASN1EncoderStart (src, theTemplate, output_proc, output_arg);
  1082.     if (ecx == NULL)
  1083. return SECFailure;
  1084.     rv = SEC_ASN1EncoderUpdate (ecx, NULL, 0);
  1085.     SEC_ASN1EncoderFinish (ecx);
  1086.     return rv;
  1087. }
  1088. /*
  1089.  * XXX depth and data_kind are unused; is there a PC way to silence warnings?
  1090.  * (I mean "politically correct", not anything to do with intel/win platform) 
  1091.  */
  1092. static void
  1093. sec_asn1e_encode_item_count (void *arg, const char *buf, unsigned long len,
  1094.      int depth, SEC_ASN1EncodingPart data_kind)
  1095. {
  1096.     unsigned long *count;
  1097.     count = (unsigned long*)arg;
  1098.     PORT_Assert (count != NULL);
  1099.     *count += len;
  1100. }
  1101. /* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
  1102. static void
  1103. sec_asn1e_encode_item_store (void *arg, const char *buf, unsigned long len,
  1104.      int depth, SEC_ASN1EncodingPart data_kind)
  1105. {
  1106.     SECItem *dest;
  1107.     dest = (SECItem*)arg;
  1108.     PORT_Assert (dest != NULL);
  1109.     PORT_Memcpy (dest->data + dest->len, buf, len);
  1110.     dest->len += len;
  1111. }
  1112. /*
  1113.  * Allocate an entire SECItem, or just the data part of it, to hold
  1114.  * "len" bytes of stuff.  Allocate from the given pool, if specified,
  1115.  * otherwise just do a vanilla PORT_Alloc.
  1116.  *
  1117.  * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
  1118.  */
  1119. static SECItem *
  1120. sec_asn1e_allocate_item (PRArenaPool *poolp, SECItem *dest, unsigned long len)
  1121. {
  1122.     if (poolp != NULL) {
  1123. void *release;
  1124. release = PORT_ArenaMark (poolp);
  1125. if (dest == NULL)
  1126.     dest = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));
  1127. if (dest != NULL) {
  1128.     dest->data = (unsigned char*)PORT_ArenaAlloc (poolp, len);
  1129.     if (dest->data == NULL) {
  1130. dest = NULL;
  1131.     }
  1132. }
  1133. if (dest == NULL) {
  1134.     /* one or both allocations failed; release everything */
  1135.     PORT_ArenaRelease (poolp, release);
  1136. } else {
  1137.     /* everything okay; unmark the arena */
  1138.     PORT_ArenaUnmark (poolp, release);
  1139. }
  1140.     } else {
  1141. SECItem *indest;
  1142. indest = dest;
  1143. if (dest == NULL)
  1144.     dest = (SECItem*)PORT_Alloc (sizeof(SECItem));
  1145. if (dest != NULL) {
  1146.     dest->data = (unsigned char*)PORT_Alloc (len);
  1147.     if (dest->data == NULL) {
  1148. if (indest == NULL)
  1149.     PORT_Free (dest);
  1150. dest = NULL;
  1151.     }
  1152. }
  1153.     }
  1154.     return dest;
  1155. }
  1156. SECItem *
  1157. SEC_ASN1EncodeItem (PRArenaPool *poolp, SECItem *dest, void *src,
  1158.     const SEC_ASN1Template *theTemplate)
  1159. {
  1160.     unsigned long encoding_length;
  1161.     SECStatus rv;
  1162.     PORT_Assert (dest == NULL || dest->data == NULL);
  1163.     encoding_length = 0;
  1164.     rv = SEC_ASN1Encode (src, theTemplate,
  1165.  sec_asn1e_encode_item_count, &encoding_length);
  1166.     if (rv != SECSuccess)
  1167. return NULL;
  1168.     dest = sec_asn1e_allocate_item (poolp, dest, encoding_length);
  1169.     if (dest == NULL)
  1170. return NULL;
  1171.     /* XXX necessary?  This really just checks for a bug in the allocate fn */
  1172.     PORT_Assert (dest->data != NULL);
  1173.     if (dest->data == NULL)
  1174. return NULL;
  1175.     dest->len = 0;
  1176.     (void) SEC_ASN1Encode (src, theTemplate, sec_asn1e_encode_item_store, dest);
  1177.     PORT_Assert (encoding_length == dest->len);
  1178.     return dest;
  1179. }
  1180. static SECItem *
  1181. sec_asn1e_integer(PRArenaPool *poolp, SECItem *dest, unsigned long value,
  1182.   PRBool make_unsigned)
  1183. {
  1184.     unsigned long copy;
  1185.     unsigned char sign;
  1186.     int len = 0;
  1187.     /*
  1188.      * Determine the length of the encoded value (minimum of 1).
  1189.      */
  1190.     copy = value;
  1191.     do {
  1192. len++;
  1193. sign = copy & 0x80;
  1194. copy >>= 8;
  1195.     } while (copy);
  1196.     /*
  1197.      * If this is an unsigned encoding, and the high bit of the last
  1198.      * byte we counted was set, we need to add one to the length so
  1199.      * we put a high-order zero byte in the encoding.
  1200.      */
  1201.     if (sign && make_unsigned)
  1202. len++;
  1203.     /*
  1204.      * Allocate the item (if necessary) and the data pointer within.
  1205.      */
  1206.     dest = sec_asn1e_allocate_item (poolp, dest, len);
  1207.     if (dest == NULL)
  1208. return NULL;
  1209.     /*
  1210.      * Store the value, byte by byte, in the item.
  1211.      */
  1212.     dest->len = len;
  1213.     while (len) {
  1214. dest->data[--len] = value;
  1215. value >>= 8;
  1216.     }
  1217.     PORT_Assert (value == 0);
  1218.     return dest;
  1219. }
  1220. SECItem *
  1221. SEC_ASN1EncodeInteger(PRArenaPool *poolp, SECItem *dest, long value)
  1222. {
  1223.     return sec_asn1e_integer (poolp, dest, (unsigned long) value, PR_FALSE);
  1224. }
  1225. extern SECItem *
  1226. SEC_ASN1EncodeUnsignedInteger(PRArenaPool *poolp,
  1227.       SECItem *dest, unsigned long value)
  1228. {
  1229.     return sec_asn1e_integer (poolp, dest, value, PR_TRUE);
  1230. }