security/nss/lib/util/secasn1e.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/util/secasn1e.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1613 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * Support for ENcoding ASN.1 data based on BER/DER (Basic/Distinguished
    1.10 + * Encoding Rules).
    1.11 + */
    1.12 +
    1.13 +#include "secasn1.h"
    1.14 +
    1.15 +typedef enum {
    1.16 +    beforeHeader,
    1.17 +    duringContents,
    1.18 +    duringGroup,
    1.19 +    duringSequence,
    1.20 +    afterContents,
    1.21 +    afterImplicit,
    1.22 +    afterInline,
    1.23 +    afterPointer,
    1.24 +    afterChoice,
    1.25 +    notInUse
    1.26 +} sec_asn1e_parse_place;
    1.27 +
    1.28 +typedef enum {
    1.29 +    allDone,
    1.30 +    encodeError,
    1.31 +    keepGoing,
    1.32 +    needBytes
    1.33 +} sec_asn1e_parse_status;
    1.34 +
    1.35 +typedef enum {
    1.36 +    hdr_normal      = 0,  /* encode header normally */
    1.37 +    hdr_any         = 1,  /* header already encoded in content */
    1.38 +    hdr_decoder     = 2,  /* template only used by decoder. skip it. */
    1.39 +    hdr_optional    = 3,  /* optional component, to be omitted */
    1.40 +    hdr_placeholder = 4   /* place holder for from_buf content */
    1.41 +} sec_asn1e_hdr_encoding;
    1.42 +
    1.43 +typedef struct sec_asn1e_state_struct {
    1.44 +    SEC_ASN1EncoderContext *top;
    1.45 +    const SEC_ASN1Template *theTemplate;
    1.46 +    void *src;
    1.47 +
    1.48 +    struct sec_asn1e_state_struct *parent;	/* aka prev */
    1.49 +    struct sec_asn1e_state_struct *child;	/* aka next */
    1.50 +
    1.51 +    sec_asn1e_parse_place place;	/* where we are in encoding process */
    1.52 +
    1.53 +    /*
    1.54 +     * XXX explain the next fields as clearly as possible...
    1.55 +     */
    1.56 +    unsigned char tag_modifiers;
    1.57 +    unsigned char tag_number;
    1.58 +    unsigned long underlying_kind;
    1.59 +
    1.60 +    int depth;
    1.61 +
    1.62 +    PRBool isExplicit,		/* we are handling an isExplicit header */
    1.63 +	   indefinite,		/* need end-of-contents */
    1.64 +	   is_string,		/* encoding a simple string or an ANY */
    1.65 +	   may_stream,		/* when streaming, do indefinite encoding */
    1.66 +	   optional,		/* omit field if it has no contents */
    1.67 +	   disallowStreaming;	/* disallow streaming in all sub-templates */	
    1.68 +} sec_asn1e_state;
    1.69 +
    1.70 +/*
    1.71 + * An "outsider" will have an opaque pointer to this, created by calling
    1.72 + * SEC_ASN1EncoderStart().  It will be passed back in to all subsequent
    1.73 + * calls to SEC_ASN1EncoderUpdate() and related routines, and when done
    1.74 + * it is passed to SEC_ASN1EncoderFinish().
    1.75 + */
    1.76 +struct sec_EncoderContext_struct {
    1.77 +    PLArenaPool *our_pool;		/* for our internal allocs */
    1.78 +
    1.79 +    sec_asn1e_state *current;
    1.80 +    sec_asn1e_parse_status status;
    1.81 +
    1.82 +    PRBool streaming;
    1.83 +    PRBool from_buf;
    1.84 +
    1.85 +    SEC_ASN1NotifyProc notify_proc;	/* call before/after handling field */
    1.86 +    void *notify_arg;			/* argument to notify_proc */
    1.87 +    PRBool during_notify;		/* true during call to notify_proc */
    1.88 +
    1.89 +    SEC_ASN1WriteProc output_proc;	/* pass encoded bytes to this  */
    1.90 +    void *output_arg;			/* argument to that function */
    1.91 +};
    1.92 +
    1.93 +
    1.94 +static sec_asn1e_state *
    1.95 +sec_asn1e_push_state (SEC_ASN1EncoderContext *cx,
    1.96 +		      const SEC_ASN1Template *theTemplate,
    1.97 +		      const void *src, PRBool new_depth)
    1.98 +{
    1.99 +    sec_asn1e_state *state, *new_state;
   1.100 +
   1.101 +    state = cx->current;
   1.102 +
   1.103 +    new_state = (sec_asn1e_state*)PORT_ArenaZAlloc (cx->our_pool, 
   1.104 +						    sizeof(*new_state));
   1.105 +    if (new_state == NULL) {
   1.106 +	cx->status = encodeError;
   1.107 +	return NULL;
   1.108 +    }
   1.109 +
   1.110 +    new_state->top = cx;
   1.111 +    new_state->parent = state;
   1.112 +    new_state->theTemplate = theTemplate;
   1.113 +    new_state->place = notInUse;
   1.114 +    if (src != NULL)
   1.115 +	new_state->src = (char *)src + theTemplate->offset;
   1.116 +
   1.117 +    if (state != NULL) {
   1.118 +	new_state->depth = state->depth;
   1.119 +	if (new_depth)
   1.120 +	    new_state->depth++;
   1.121 +	state->child = new_state;
   1.122 +    }
   1.123 +
   1.124 +    cx->current = new_state;
   1.125 +    return new_state;
   1.126 +}
   1.127 +
   1.128 +
   1.129 +static void
   1.130 +sec_asn1e_scrub_state (sec_asn1e_state *state)
   1.131 +{
   1.132 +    /*
   1.133 +     * Some default "scrubbing".
   1.134 +     * XXX right set of initializations?
   1.135 +     */
   1.136 +    state->place = beforeHeader;
   1.137 +    state->indefinite = PR_FALSE;
   1.138 +}
   1.139 +
   1.140 +
   1.141 +static void
   1.142 +sec_asn1e_notify_before (SEC_ASN1EncoderContext *cx, void *src, int depth)
   1.143 +{
   1.144 +    if (cx->notify_proc == NULL)
   1.145 +	return;
   1.146 +
   1.147 +    cx->during_notify = PR_TRUE;
   1.148 +    (* cx->notify_proc) (cx->notify_arg, PR_TRUE, src, depth);
   1.149 +    cx->during_notify = PR_FALSE;
   1.150 +}
   1.151 +
   1.152 +
   1.153 +static void
   1.154 +sec_asn1e_notify_after (SEC_ASN1EncoderContext *cx, void *src, int depth)
   1.155 +{
   1.156 +    if (cx->notify_proc == NULL)
   1.157 +	return;
   1.158 +
   1.159 +    cx->during_notify = PR_TRUE;
   1.160 +    (* cx->notify_proc) (cx->notify_arg, PR_FALSE, src, depth);
   1.161 +    cx->during_notify = PR_FALSE;
   1.162 +}
   1.163 +
   1.164 +
   1.165 +static sec_asn1e_state *
   1.166 +sec_asn1e_init_state_based_on_template (sec_asn1e_state *state)
   1.167 +{
   1.168 +    PRBool isExplicit, is_string, may_stream, optional, universal; 
   1.169 +    PRBool disallowStreaming;
   1.170 +    unsigned char tag_modifiers;
   1.171 +    unsigned long encode_kind, under_kind;
   1.172 +    unsigned long tag_number;
   1.173 +    PRBool isInline = PR_FALSE;
   1.174 +
   1.175 +
   1.176 +    encode_kind = state->theTemplate->kind;
   1.177 +
   1.178 +    universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
   1.179 +		? PR_TRUE : PR_FALSE;
   1.180 +
   1.181 +    isExplicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
   1.182 +    encode_kind &= ~SEC_ASN1_EXPLICIT;
   1.183 +
   1.184 +    optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
   1.185 +    encode_kind &= ~SEC_ASN1_OPTIONAL;
   1.186 +
   1.187 +    PORT_Assert (!(isExplicit && universal));	/* bad templates */
   1.188 +
   1.189 +    may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
   1.190 +    encode_kind &= ~SEC_ASN1_MAY_STREAM;
   1.191 +
   1.192 +    disallowStreaming = (encode_kind & SEC_ASN1_NO_STREAM) ? PR_TRUE : PR_FALSE;
   1.193 +    encode_kind &= ~SEC_ASN1_NO_STREAM;
   1.194 +
   1.195 +    /* Just clear this to get it out of the way; we do not need it here */
   1.196 +    encode_kind &= ~SEC_ASN1_DYNAMIC;
   1.197 +
   1.198 +    if( encode_kind & SEC_ASN1_CHOICE ) {
   1.199 +      under_kind = SEC_ASN1_CHOICE;
   1.200 +    } else if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || 
   1.201 +        (!universal && !isExplicit)) {
   1.202 +	const SEC_ASN1Template *subt;
   1.203 +	void *src = NULL;
   1.204 +
   1.205 +	PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);
   1.206 +
   1.207 +	sec_asn1e_scrub_state (state);
   1.208 +
   1.209 +	if (encode_kind & SEC_ASN1_POINTER) {
   1.210 +	    src = *(void **)state->src;
   1.211 +	    state->place = afterPointer;
   1.212 +
   1.213 +	    if (src == NULL) {
   1.214 +		/*
   1.215 +		 * If this is optional, but NULL, then the field does
   1.216 +		 * not need to be encoded.  In this case we are done;
   1.217 +		 * we do not want to push a subtemplate.
   1.218 +		 */
   1.219 +		if (optional)
   1.220 +		    return state;
   1.221 +
   1.222 +		/*
   1.223 +		 * XXX this is an error; need to figure out
   1.224 +		 * how to handle this
   1.225 +		 */
   1.226 +	    }
   1.227 +	} else {
   1.228 +	    src = state->src;
   1.229 +	    if (encode_kind & SEC_ASN1_INLINE) {
   1.230 +		/* check that there are no extraneous bits */
   1.231 +		/* PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional); */
   1.232 +		state->place = afterInline;
   1.233 +		isInline = PR_TRUE;
   1.234 +	    } else {
   1.235 +		/*
   1.236 +		 * Save the tag modifiers and tag number here before moving
   1.237 +		 * on to the next state in case this is a member of a
   1.238 +		 * SEQUENCE OF
   1.239 +		 */
   1.240 +		state->tag_modifiers = (unsigned char)
   1.241 +		    (encode_kind & (SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK));
   1.242 +		state->tag_number = (unsigned char)
   1.243 +		    (encode_kind & SEC_ASN1_TAGNUM_MASK);
   1.244 +		
   1.245 +		state->place = afterImplicit;
   1.246 +		state->optional = optional;
   1.247 +	    }
   1.248 +	}
   1.249 +
   1.250 +	subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src, PR_TRUE);
   1.251 +	if (isInline && optional) {
   1.252 +	    /* we only handle a very limited set of optional inline cases at
   1.253 +	       this time */
   1.254 +	    if (PR_FALSE != SEC_ASN1IsTemplateSimple(subt)) {
   1.255 +		/* we now know that the target is a SECItem*, so we can check
   1.256 +		   if the source contains one */
   1.257 +		SECItem* target = (SECItem*)state->src;
   1.258 +		if (!target || !target->data || !target->len) {
   1.259 +		    /* no valid data to encode subtemplate */
   1.260 +		    return state;
   1.261 +		}
   1.262 +	    } else {
   1.263 +		PORT_Assert(0); /* complex templates are not handled as
   1.264 +				   inline optional */
   1.265 +	    }
   1.266 +	}
   1.267 +	state = sec_asn1e_push_state (state->top, subt, src, PR_FALSE);
   1.268 +	if (state == NULL)
   1.269 +	    return state;
   1.270 +
   1.271 +	if (universal) {
   1.272 +	    /*
   1.273 +	     * This is a POINTER or INLINE; just init based on that
   1.274 +	     * and we are done.
   1.275 +	     */
   1.276 +	    return sec_asn1e_init_state_based_on_template (state);
   1.277 +	}
   1.278 +
   1.279 +	/*
   1.280 +	 * This is an implicit, non-universal (meaning, application-private
   1.281 +	 * or context-specific) field.  This results in a "magic" tag but
   1.282 +	 * encoding based on the underlying type.  We pushed a new state
   1.283 +	 * that is based on the subtemplate (the underlying type), but
   1.284 +	 * now we will sort of alias it to give it some of our properties
   1.285 +	 * (tag, optional status, etc.).
   1.286 +	 *
   1.287 +	 * NB: ALL the following flags in the subtemplate are disallowed
   1.288 +	 *     and/or ignored: EXPLICIT, OPTIONAL, INNER, INLINE, POINTER.
   1.289 +	 */
   1.290 +
   1.291 +	under_kind = state->theTemplate->kind;
   1.292 +	if ((under_kind & SEC_ASN1_MAY_STREAM) && !disallowStreaming) {
   1.293 +	    may_stream = PR_TRUE;
   1.294 +	}
   1.295 +	under_kind &= ~(SEC_ASN1_MAY_STREAM | SEC_ASN1_DYNAMIC);
   1.296 +    } else {
   1.297 +	under_kind = encode_kind;
   1.298 +    }
   1.299 +
   1.300 +    /*
   1.301 +     * Sanity check that there are no unwanted bits marked in under_kind.
   1.302 +     * These bits were either removed above (after we recorded them) or
   1.303 +     * they simply should not be found (signalling a bad/broken template).
   1.304 +     * XXX is this the right set of bits to test here? (i.e. need to add
   1.305 +     * or remove any?)
   1.306 +     */
   1.307 +#define UNEXPECTED_FLAGS \
   1.308 + (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_SKIP | SEC_ASN1_INNER | \
   1.309 +  SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_INLINE | SEC_ASN1_POINTER)
   1.310 +
   1.311 +    PORT_Assert ((under_kind & UNEXPECTED_FLAGS) == 0);
   1.312 +    under_kind &= ~UNEXPECTED_FLAGS;
   1.313 +#undef UNEXPECTED_FLAGS
   1.314 +
   1.315 +    if (encode_kind & SEC_ASN1_ANY) {
   1.316 +	PORT_Assert (encode_kind == under_kind);
   1.317 +	tag_modifiers = 0;
   1.318 +	tag_number = 0;
   1.319 +	is_string = PR_TRUE;
   1.320 +    } else {
   1.321 +	tag_modifiers = (unsigned char)
   1.322 +		(encode_kind & (SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK));
   1.323 +	/*
   1.324 +	 * XXX This assumes only single-octet identifiers.  To handle
   1.325 +	 * the HIGH TAG form we would need to do some more work, especially
   1.326 +	 * in how to specify them in the template, because right now we
   1.327 +	 * do not provide a way to specify more *tag* bits in encode_kind.
   1.328 +	 */
   1.329 +	tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
   1.330 +
   1.331 +	is_string = PR_FALSE;
   1.332 +	switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
   1.333 +	  case SEC_ASN1_SET:
   1.334 +	    /*
   1.335 +	     * XXX A plain old SET (as opposed to a SET OF) is not implemented.
   1.336 +	     * If it ever is, remove this assert...
   1.337 +	     */
   1.338 +	    PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
   1.339 +	    /* fallthru */
   1.340 +	  case SEC_ASN1_SEQUENCE:
   1.341 +	    tag_modifiers |= SEC_ASN1_CONSTRUCTED;
   1.342 +	    break;
   1.343 +	  case SEC_ASN1_BIT_STRING:
   1.344 +	  case SEC_ASN1_BMP_STRING: 
   1.345 +	  case SEC_ASN1_GENERALIZED_TIME:
   1.346 +	  case SEC_ASN1_IA5_STRING:
   1.347 +	  case SEC_ASN1_OCTET_STRING:
   1.348 +	  case SEC_ASN1_PRINTABLE_STRING:
   1.349 +	  case SEC_ASN1_T61_STRING:
   1.350 +	  case SEC_ASN1_UNIVERSAL_STRING: 
   1.351 +	  case SEC_ASN1_UTC_TIME:
   1.352 +	  case SEC_ASN1_UTF8_STRING:
   1.353 +	  case SEC_ASN1_VISIBLE_STRING: 
   1.354 +	    /*
   1.355 +	     * We do not yet know if we will be constructing the string,
   1.356 +	     * so we have to wait to do this final tag modification.
   1.357 +	     */
   1.358 +	    is_string = PR_TRUE;
   1.359 +	    break;
   1.360 +	}
   1.361 +    }
   1.362 +
   1.363 +    state->tag_modifiers = tag_modifiers;
   1.364 +    state->tag_number = (unsigned char)tag_number;
   1.365 +    state->underlying_kind = under_kind;
   1.366 +    state->isExplicit = isExplicit;
   1.367 +    state->may_stream = may_stream;
   1.368 +    state->is_string = is_string;
   1.369 +    state->optional = optional;
   1.370 +    state->disallowStreaming = disallowStreaming;
   1.371 +
   1.372 +    sec_asn1e_scrub_state (state);
   1.373 +
   1.374 +    return state;
   1.375 +}
   1.376 +
   1.377 +
   1.378 +static void
   1.379 +sec_asn1e_write_part (sec_asn1e_state *state,
   1.380 +		      const char *buf, unsigned long len,
   1.381 +		      SEC_ASN1EncodingPart part)
   1.382 +{
   1.383 +    SEC_ASN1EncoderContext *cx;
   1.384 +
   1.385 +    cx = state->top;
   1.386 +    (* cx->output_proc) (cx->output_arg, buf, len, state->depth, part);
   1.387 +}
   1.388 +
   1.389 +
   1.390 +/*
   1.391 + * XXX This assumes only single-octet identifiers.  To handle
   1.392 + * the HIGH TAG form we would need to modify this interface and
   1.393 + * teach it to properly encode the special form.
   1.394 + */
   1.395 +static void
   1.396 +sec_asn1e_write_identifier_bytes (sec_asn1e_state *state, unsigned char value)
   1.397 +{
   1.398 +    char byte;
   1.399 +
   1.400 +    byte = (char) value;
   1.401 +    sec_asn1e_write_part (state, &byte, 1, SEC_ASN1_Identifier);
   1.402 +}
   1.403 +
   1.404 +int
   1.405 +SEC_ASN1EncodeLength(unsigned char *buf,int value) {
   1.406 +    int lenlen;
   1.407 +
   1.408 +    lenlen = SEC_ASN1LengthLength (value);
   1.409 +    if (lenlen == 1) {
   1.410 +	buf[0] = value;
   1.411 +    } else {
   1.412 +	int i;
   1.413 +
   1.414 +	i = lenlen - 1;
   1.415 +	buf[0] = 0x80 | i;
   1.416 +	while (i) {
   1.417 +	    buf[i--] = value;
   1.418 +	    value >>= 8;
   1.419 +	}
   1.420 +        PORT_Assert (value == 0);
   1.421 +    }
   1.422 +    return lenlen;
   1.423 +}
   1.424 +
   1.425 +static void
   1.426 +sec_asn1e_write_length_bytes (sec_asn1e_state *state, unsigned long value,
   1.427 +			      PRBool indefinite)
   1.428 +{
   1.429 +    int lenlen;
   1.430 +    unsigned char buf[sizeof(unsigned long) + 1];
   1.431 +
   1.432 +    if (indefinite) {
   1.433 +	PORT_Assert (value == 0);
   1.434 +	buf[0] = 0x80;
   1.435 +	lenlen = 1;
   1.436 +    } else {
   1.437 +	lenlen = SEC_ASN1EncodeLength(buf,value);
   1.438 +    }
   1.439 +
   1.440 +    sec_asn1e_write_part (state, (char *) buf, lenlen, SEC_ASN1_Length);
   1.441 +}
   1.442 +
   1.443 +
   1.444 +static void
   1.445 +sec_asn1e_write_contents_bytes (sec_asn1e_state *state,
   1.446 +				const char *buf, unsigned long len)
   1.447 +{
   1.448 +    sec_asn1e_write_part (state, buf, len, SEC_ASN1_Contents);
   1.449 +}
   1.450 +
   1.451 +
   1.452 +static void
   1.453 +sec_asn1e_write_end_of_contents_bytes (sec_asn1e_state *state)
   1.454 +{
   1.455 +    const char eoc[2] = {0, 0};
   1.456 +
   1.457 +    sec_asn1e_write_part (state, eoc, 2, SEC_ASN1_EndOfContents);
   1.458 +}
   1.459 +
   1.460 +static int
   1.461 +sec_asn1e_which_choice
   1.462 +(
   1.463 +  void *src,
   1.464 +  const SEC_ASN1Template *theTemplate
   1.465 +)
   1.466 +{
   1.467 +  int rv;
   1.468 +  unsigned int which = *(unsigned int *)src;
   1.469 +
   1.470 +  for( rv = 1, theTemplate++; theTemplate->kind != 0; rv++, theTemplate++ ) {
   1.471 +    if( which == theTemplate->size ) {
   1.472 +      return rv;
   1.473 +    }
   1.474 +  }
   1.475 +
   1.476 +  return 0;
   1.477 +}
   1.478 +
   1.479 +static unsigned long
   1.480 +sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src,
   1.481 +			   PRBool disallowStreaming, PRBool insideIndefinite,
   1.482 +			   sec_asn1e_hdr_encoding *pHdrException)
   1.483 +{
   1.484 +    unsigned long encode_kind, underlying_kind;
   1.485 +    PRBool isExplicit, optional, universal, may_stream;
   1.486 +    unsigned long len;
   1.487 +
   1.488 +    /*
   1.489 +     * This function currently calculates the length in all cases
   1.490 +     * except the following: when writing out the contents of a 
   1.491 +     * template that belongs to a state where it was a sub-template
   1.492 +     * with the SEC_ASN1_MAY_STREAM bit set and it's parent had the
   1.493 +     * optional bit set.  The information that the parent is optional
   1.494 +     * and that we should return the length of 0 when that length is 
   1.495 +     * present since that means the optional field is no longer present.
   1.496 +     * So we add the disallowStreaming flag which is passed in when
   1.497 +     * writing the contents, but for all recursive calls to 
   1.498 +     * sec_asn1e_contents_length, we pass PR_FALSE, because this
   1.499 +     * function correctly calculates the length for children templates
   1.500 +     * from that point on.  Confused yet?  At least you didn't have
   1.501 +     * to figure it out.  ;)  -javi
   1.502 +     */
   1.503 +    encode_kind = theTemplate->kind;
   1.504 +
   1.505 +    universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
   1.506 +		? PR_TRUE : PR_FALSE;
   1.507 +
   1.508 +    isExplicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
   1.509 +    encode_kind &= ~SEC_ASN1_EXPLICIT;
   1.510 +
   1.511 +    optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
   1.512 +    encode_kind &= ~SEC_ASN1_OPTIONAL;
   1.513 +
   1.514 +    PORT_Assert (!(isExplicit && universal));	/* bad templates */
   1.515 +
   1.516 +    may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
   1.517 +    encode_kind &= ~SEC_ASN1_MAY_STREAM;
   1.518 +
   1.519 +    /* Just clear this to get it out of the way; we do not need it here */
   1.520 +    encode_kind &= ~SEC_ASN1_DYNAMIC;
   1.521 +
   1.522 +    if (encode_kind & SEC_ASN1_NO_STREAM) {
   1.523 +	disallowStreaming = PR_TRUE;
   1.524 +    }
   1.525 +    encode_kind &= ~SEC_ASN1_NO_STREAM;
   1.526 +
   1.527 +    if (encode_kind & SEC_ASN1_CHOICE) {
   1.528 +	void *src2;
   1.529 +	int indx = sec_asn1e_which_choice(src, theTemplate);
   1.530 +	if (0 == indx) {
   1.531 +	    /* XXX set an error? "choice not found" */
   1.532 +	    /* state->top->status = encodeError; */
   1.533 +	    return 0;
   1.534 +	}
   1.535 +
   1.536 +        src2 = (void *)
   1.537 +	        ((char *)src - theTemplate->offset + theTemplate[indx].offset);
   1.538 +
   1.539 +        return sec_asn1e_contents_length(&theTemplate[indx], src2, 
   1.540 +					 disallowStreaming, insideIndefinite,
   1.541 +					 pHdrException);
   1.542 +    }
   1.543 +
   1.544 +    if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || !universal) {
   1.545 +	/* XXX any bits we want to disallow (PORT_Assert against) here? */
   1.546 +	theTemplate = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);
   1.547 +	if (encode_kind & SEC_ASN1_POINTER) {
   1.548 +	    src = *(void **)src;
   1.549 +	    if (src == NULL) {
   1.550 +		*pHdrException = optional ? hdr_optional : hdr_normal;
   1.551 +		return 0;
   1.552 +	    }
   1.553 +	} else if (encode_kind & SEC_ASN1_INLINE) {
   1.554 +	    /* check that there are no extraneous bits */
   1.555 +	    if (optional) {
   1.556 +		if (PR_FALSE != SEC_ASN1IsTemplateSimple(theTemplate)) {
   1.557 +		    /* we now know that the target is a SECItem*, so we can check
   1.558 +		       if the source contains one */
   1.559 +		    SECItem* target = (SECItem*)src;
   1.560 +		    if (!target || !target->data || !target->len) {
   1.561 +			/* no valid data to encode subtemplate */
   1.562 +			*pHdrException = hdr_optional;
   1.563 +			return 0;
   1.564 +		    }
   1.565 +		} else {
   1.566 +		    PORT_Assert(0); /* complex templates not handled as inline
   1.567 +                                       optional */
   1.568 +		}
   1.569 +	    }
   1.570 +	}
   1.571 +
   1.572 +	src = (char *)src + theTemplate->offset;
   1.573 +
   1.574 +	/* recurse to find the length of the subtemplate */
   1.575 +	len = sec_asn1e_contents_length (theTemplate, src, disallowStreaming, 
   1.576 +	                                 insideIndefinite, pHdrException);
   1.577 +	if (len == 0 && optional) {
   1.578 +	    *pHdrException = hdr_optional;
   1.579 +	} else if (isExplicit) {
   1.580 +	    if (*pHdrException == hdr_any) {
   1.581 +		/* *we* do not want to add in a header, 
   1.582 +		** but our caller still does. 
   1.583 +		*/
   1.584 +		*pHdrException = hdr_normal;
   1.585 +	    } else if (*pHdrException == hdr_normal) {
   1.586 +		/* if the inner content exists, our length is
   1.587 +		 * len(identifier) + len(length) + len(innercontent)
   1.588 +		 * XXX we currently assume len(identifier) == 1;
   1.589 +		 * to support a high-tag-number this would need to be smarter.
   1.590 +		 */
   1.591 +		len += 1 + SEC_ASN1LengthLength (len);
   1.592 +	    }
   1.593 +	}
   1.594 +	return len;
   1.595 +    }
   1.596 +    underlying_kind = encode_kind;
   1.597 +
   1.598 +    /* This is only used in decoding; it plays no part in encoding.  */
   1.599 +    if (underlying_kind & SEC_ASN1_SAVE) {
   1.600 +	/* check that there are no extraneous bits */
   1.601 +	PORT_Assert (underlying_kind == SEC_ASN1_SAVE);
   1.602 +	*pHdrException = hdr_decoder;
   1.603 +	return 0;
   1.604 +    }
   1.605 +
   1.606 +#define UNEXPECTED_FLAGS \
   1.607 + (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_INLINE | SEC_ASN1_POINTER |\
   1.608 +  SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_SAVE | SEC_ASN1_SKIP)
   1.609 +
   1.610 +    /* Having any of these bits is not expected here...  */
   1.611 +    PORT_Assert ((underlying_kind & UNEXPECTED_FLAGS) == 0);
   1.612 +    underlying_kind &= ~UNEXPECTED_FLAGS;
   1.613 +#undef UNEXPECTED_FLAGS
   1.614 +
   1.615 +    if (underlying_kind & SEC_ASN1_CHOICE) {
   1.616 +	void *src2;
   1.617 +	int indx = sec_asn1e_which_choice(src, theTemplate);
   1.618 +	if (0 == indx) {
   1.619 +	    /* XXX set an error? "choice not found" */
   1.620 +	    /* state->top->status = encodeError; */
   1.621 +	    return 0;
   1.622 +	}
   1.623 +
   1.624 +        src2 = (void *)
   1.625 +		((char *)src - theTemplate->offset + theTemplate[indx].offset);
   1.626 +        len = sec_asn1e_contents_length(&theTemplate[indx], src2, 
   1.627 +	                                disallowStreaming, insideIndefinite, 
   1.628 +					pHdrException);
   1.629 +    } else {
   1.630 +      switch (underlying_kind) {
   1.631 +      case SEC_ASN1_SEQUENCE_OF:
   1.632 +      case SEC_ASN1_SET_OF:
   1.633 +	{
   1.634 +	    const SEC_ASN1Template *tmpt;
   1.635 +	    void *sub_src;
   1.636 +	    unsigned long sub_len;
   1.637 +	    void **group;
   1.638 +
   1.639 +	    len = 0;
   1.640 +
   1.641 +	    group = *(void ***)src;
   1.642 +	    if (group == NULL)
   1.643 +		break;
   1.644 +
   1.645 +	    tmpt = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);
   1.646 +
   1.647 +	    for (; *group != NULL; group++) {
   1.648 +		sub_src = (char *)(*group) + tmpt->offset;
   1.649 +		sub_len = sec_asn1e_contents_length (tmpt, sub_src, 
   1.650 +		                                     disallowStreaming,
   1.651 +						     insideIndefinite,
   1.652 +                                                     pHdrException);
   1.653 +		len += sub_len;
   1.654 +		/*
   1.655 +		 * XXX The 1 below is the presumed length of the identifier;
   1.656 +		 * to support a high-tag-number this would need to be smarter.
   1.657 +		 */
   1.658 +		if (*pHdrException == hdr_normal)
   1.659 +		    len += 1 + SEC_ASN1LengthLength (sub_len);
   1.660 +	    }
   1.661 +	}
   1.662 +	break;
   1.663 +
   1.664 +      case SEC_ASN1_SEQUENCE:
   1.665 +      case SEC_ASN1_SET:
   1.666 +	{
   1.667 +	    const SEC_ASN1Template *tmpt;
   1.668 +	    void *sub_src;
   1.669 +	    unsigned long sub_len;
   1.670 +
   1.671 +	    len = 0;
   1.672 +	    for (tmpt = theTemplate + 1; tmpt->kind; tmpt++) {
   1.673 +		sub_src = (char *)src + tmpt->offset;
   1.674 +		sub_len = sec_asn1e_contents_length (tmpt, sub_src, 
   1.675 +		                                     disallowStreaming,
   1.676 +						     insideIndefinite,
   1.677 +                                                     pHdrException);
   1.678 +		len += sub_len;
   1.679 +		/*
   1.680 +		 * XXX The 1 below is the presumed length of the identifier;
   1.681 +		 * to support a high-tag-number this would need to be smarter.
   1.682 +		 */
   1.683 +		if (*pHdrException == hdr_normal)
   1.684 +		    len += 1 + SEC_ASN1LengthLength (sub_len);
   1.685 +	    }
   1.686 +	}
   1.687 +	break;
   1.688 +
   1.689 +      case SEC_ASN1_BIT_STRING:
   1.690 +	/* convert bit length to byte */
   1.691 +	len = (((SECItem *)src)->len + 7) >> 3;
   1.692 +	/* bit string contents involve an extra octet */
   1.693 +	if (len)
   1.694 +	    len++;
   1.695 +	break;
   1.696 +
   1.697 +      case SEC_ASN1_INTEGER:
   1.698 +	/* ASN.1 INTEGERs are signed.
   1.699 +	 * If the source is an unsigned integer, the encoder will need 
   1.700 +	 * to handle the conversion here.
   1.701 +	 */
   1.702 +	{
   1.703 +	    unsigned char *buf = ((SECItem *)src)->data;
   1.704 +	    SECItemType integerType = ((SECItem *)src)->type;
   1.705 +	    len = ((SECItem *)src)->len;
   1.706 +	    while (len > 0) {
   1.707 +		if (*buf != 0) {
   1.708 +		    if (*buf & 0x80 && integerType == siUnsignedInteger) {
   1.709 +			len++; /* leading zero needed to make number signed */
   1.710 +		    }
   1.711 +		    break; /* reached beginning of number */
   1.712 +		}
   1.713 +		if (len == 1) {
   1.714 +		    break; /* the number 0 */
   1.715 +		}
   1.716 +		if (buf[1] & 0x80) {
   1.717 +		    break; /* leading zero already present */
   1.718 +		} 
   1.719 +		/* extraneous leading zero, keep going */
   1.720 +		buf++;
   1.721 +		len--;
   1.722 +	    }
   1.723 +	}
   1.724 +	break;
   1.725 +
   1.726 +      default:
   1.727 +	len = ((SECItem *)src)->len;
   1.728 +	break;
   1.729 +      }  /* end switch */
   1.730 +
   1.731 +#ifndef WHAT_PROBLEM_DOES_THIS_SOLVE
   1.732 +      /* if we're streaming, we may have a secitem w/len 0 as placeholder */
   1.733 +      if (!len && insideIndefinite && may_stream && !disallowStreaming) {
   1.734 +	  len = 1;
   1.735 +      }
   1.736 +#endif
   1.737 +    }    /* end else */
   1.738 +
   1.739 +    if (len == 0 && optional)
   1.740 +	*pHdrException = hdr_optional;
   1.741 +    else if (underlying_kind == SEC_ASN1_ANY)
   1.742 +	*pHdrException = hdr_any;
   1.743 +    else 
   1.744 +	*pHdrException = hdr_normal;
   1.745 +
   1.746 +    return len;
   1.747 +}
   1.748 +
   1.749 +
   1.750 +static void
   1.751 +sec_asn1e_write_header (sec_asn1e_state *state)
   1.752 +{
   1.753 +    unsigned long contents_length;
   1.754 +    unsigned char tag_number, tag_modifiers;
   1.755 +    sec_asn1e_hdr_encoding hdrException = hdr_normal;
   1.756 +    PRBool indefinite = PR_FALSE;
   1.757 +
   1.758 +    PORT_Assert (state->place == beforeHeader);
   1.759 +
   1.760 +    tag_number = state->tag_number;
   1.761 +    tag_modifiers = state->tag_modifiers;
   1.762 +
   1.763 +    if (state->underlying_kind == SEC_ASN1_ANY) {
   1.764 +	state->place = duringContents;
   1.765 +	return;
   1.766 +    }
   1.767 +
   1.768 +    if (state->underlying_kind & SEC_ASN1_CHOICE) {
   1.769 +	int indx = sec_asn1e_which_choice(state->src, state->theTemplate);
   1.770 +	if( 0 == indx ) {
   1.771 +	    /* XXX set an error? "choice not found" */
   1.772 +	    state->top->status = encodeError;
   1.773 +	    return;
   1.774 +	}
   1.775 +	state->place = afterChoice;
   1.776 +	state = sec_asn1e_push_state(state->top, &state->theTemplate[indx],
   1.777 +			       (char *)state->src - state->theTemplate->offset, 
   1.778 +			       PR_TRUE);
   1.779 +	if (state) {
   1.780 +	    /*
   1.781 +	     * Do the "before" field notification.
   1.782 +	     */
   1.783 +	    sec_asn1e_notify_before (state->top, state->src, state->depth);
   1.784 +	    state = sec_asn1e_init_state_based_on_template (state);
   1.785 +	}
   1.786 +	return;
   1.787 +    }
   1.788 +
   1.789 +    /* The !isString test below is apparently intended to ensure that all 
   1.790 +    ** constructed types receive indefinite length encoding.
   1.791 +    */
   1.792 +   indefinite = (PRBool) 
   1.793 +	(state->top->streaming && state->may_stream && 
   1.794 +	 (state->top->from_buf || !state->is_string));
   1.795 +
   1.796 +    /*
   1.797 +     * If we are doing a definite-length encoding, first we have to
   1.798 +     * walk the data structure to calculate the entire contents length.
   1.799 +     * If we are doing an indefinite-length encoding, we still need to 
   1.800 +     * know if the contents is:
   1.801 +     *    optional and to be omitted, or 
   1.802 +     *    an ANY (header is pre-encoded), or 
   1.803 +     *    a SAVE or some other kind of template used only by the decoder.
   1.804 +     * So, we call this function either way.
   1.805 +     */
   1.806 +    contents_length = sec_asn1e_contents_length (state->theTemplate,
   1.807 +						 state->src, 
   1.808 +                                                 state->disallowStreaming,
   1.809 +						 indefinite,
   1.810 +                                                 &hdrException);
   1.811 +    /*
   1.812 +     * We might be told explicitly not to put out a header.
   1.813 +     * But it can also be the case, via a pushed subtemplate, that
   1.814 +     * sec_asn1e_contents_length could not know that this field is
   1.815 +     * really optional.  So check for that explicitly, too.
   1.816 +     */
   1.817 +    if (hdrException != hdr_normal || 
   1.818 +	(contents_length == 0 && state->optional)) {
   1.819 +	state->place = afterContents;
   1.820 +	if (state->top->streaming && 
   1.821 +	    state->may_stream && 
   1.822 +	    state->top->from_buf) {
   1.823 +	    /* we did not find an optional indefinite string, so we 
   1.824 +	     * don't encode it.  However, if TakeFromBuf is on, we stop 
   1.825 +	     * here anyway to give our caller a chance to intercept at the 
   1.826 +	     * same point where we would stop if the field were present. 
   1.827 +	     */
   1.828 +	    state->top->status = needBytes;
   1.829 +	}
   1.830 +	return;
   1.831 +    }
   1.832 +
   1.833 +    if (indefinite) {
   1.834 +	/*
   1.835 +	 * We need to put out an indefinite-length encoding.
   1.836 +	 * The only universal types that can be constructed are SETs,
   1.837 +	 * SEQUENCEs, and strings; so check that it is one of those,
   1.838 +	 * or that it is not universal (e.g. context-specific).
   1.839 +	 */
   1.840 +	state->indefinite = PR_TRUE;
   1.841 +	PORT_Assert ((tag_number == SEC_ASN1_SET)
   1.842 +		     || (tag_number == SEC_ASN1_SEQUENCE)
   1.843 +		     || ((tag_modifiers & SEC_ASN1_CLASS_MASK) != 0)
   1.844 +		     || state->is_string);
   1.845 +	tag_modifiers |= SEC_ASN1_CONSTRUCTED;
   1.846 +	contents_length = 0;
   1.847 +    }
   1.848 +
   1.849 +    sec_asn1e_write_identifier_bytes (state, 
   1.850 +                                (unsigned char)(tag_number | tag_modifiers));
   1.851 +    sec_asn1e_write_length_bytes (state, contents_length, state->indefinite);
   1.852 +
   1.853 +    if (contents_length == 0 && !state->indefinite) {
   1.854 +	/*
   1.855 +	 * If no real contents to encode, then we are done with this field.
   1.856 +	 */
   1.857 +	state->place = afterContents;
   1.858 +	return;
   1.859 +    }
   1.860 +
   1.861 +    /*
   1.862 +     * An EXPLICIT is nothing but an outer header, which we have already
   1.863 +     * written.  Now we need to do the inner header and contents.
   1.864 +     */
   1.865 +    if (state->isExplicit) {
   1.866 +	const SEC_ASN1Template *subt =
   1.867 +	      SEC_ASN1GetSubtemplate(state->theTemplate, state->src, PR_TRUE);
   1.868 +	state->place = afterContents;
   1.869 +	state = sec_asn1e_push_state (state->top, subt, state->src, PR_TRUE);
   1.870 +	if (state != NULL)
   1.871 +	    state = sec_asn1e_init_state_based_on_template (state);
   1.872 +	return;
   1.873 +    }
   1.874 +
   1.875 +    switch (state->underlying_kind) {
   1.876 +      case SEC_ASN1_SET_OF:
   1.877 +      case SEC_ASN1_SEQUENCE_OF:
   1.878 +	/*
   1.879 +	 * We need to push a child to handle each member.
   1.880 +	 */
   1.881 +	{
   1.882 +	    void **group;
   1.883 +	    const SEC_ASN1Template *subt;
   1.884 +
   1.885 +	    group = *(void ***)state->src;
   1.886 +	    if (group == NULL || *group == NULL) {
   1.887 +		/*
   1.888 +		 * Group is empty; we are done.
   1.889 +		 */
   1.890 +		state->place = afterContents;
   1.891 +		return;
   1.892 +	    }
   1.893 +	    state->place = duringGroup;
   1.894 +	    subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src,
   1.895 +					   PR_TRUE);
   1.896 +	    state = sec_asn1e_push_state (state->top, subt, *group, PR_TRUE);
   1.897 +	    if (state != NULL)
   1.898 +		state = sec_asn1e_init_state_based_on_template (state);
   1.899 +	}
   1.900 +	break;
   1.901 +
   1.902 +      case SEC_ASN1_SEQUENCE:
   1.903 +      case SEC_ASN1_SET:
   1.904 +	/*
   1.905 +	 * We need to push a child to handle the individual fields.
   1.906 +	 */
   1.907 +	state->place = duringSequence;
   1.908 +	state = sec_asn1e_push_state (state->top, state->theTemplate + 1,
   1.909 +				      state->src, PR_TRUE);
   1.910 +	if (state != NULL) {
   1.911 +	    /*
   1.912 +	     * Do the "before" field notification.
   1.913 +	     */
   1.914 +	    sec_asn1e_notify_before (state->top, state->src, state->depth);
   1.915 +	    state = sec_asn1e_init_state_based_on_template (state);
   1.916 +	}
   1.917 +	break;
   1.918 +
   1.919 +      default:
   1.920 +	/*
   1.921 +	 * I think we do not need to do anything else.
   1.922 +	 * XXX Correct?
   1.923 +	 */
   1.924 +	state->place = duringContents;
   1.925 +	break;
   1.926 +    }
   1.927 +}
   1.928 +
   1.929 +
   1.930 +static void
   1.931 +sec_asn1e_write_contents_from_buf (sec_asn1e_state *state,
   1.932 +			  const char *buf, unsigned long len)
   1.933 +{
   1.934 +    PORT_Assert (state->place == duringContents);
   1.935 +    PORT_Assert (state->top->from_buf);
   1.936 +    PORT_Assert (state->may_stream && !state->disallowStreaming);
   1.937 +
   1.938 +    /*
   1.939 +     * Probably they just turned on "take from buf", but have not
   1.940 +     * yet given us any bytes.  If there is nothing in the buffer
   1.941 +     * then we have nothing to do but return and wait.
   1.942 +     */
   1.943 +    if (buf == NULL || len == 0) {
   1.944 +	state->top->status = needBytes;
   1.945 +	return;
   1.946 +    }
   1.947 +    /*
   1.948 +     * We are streaming, reading from a passed-in buffer.
   1.949 +     * This means we are encoding a simple string or an ANY.
   1.950 +     * For the former, we need to put out a substring, with its
   1.951 +     * own identifier and length.  For an ANY, we just write it
   1.952 +     * out as is (our caller is required to ensure that it
   1.953 +     * is a properly encoded entity).
   1.954 +     */
   1.955 +    PORT_Assert (state->is_string);		/* includes ANY */
   1.956 +    if (state->underlying_kind != SEC_ASN1_ANY) {
   1.957 +	unsigned char identifier;
   1.958 +
   1.959 +	/*
   1.960 +	 * Create the identifier based on underlying_kind.  We cannot
   1.961 +	 * use tag_number and tag_modifiers because this can be an
   1.962 +	 * implicitly encoded field.  In that case, the underlying
   1.963 +	 * substrings *are* encoded with their real tag.
   1.964 +	 */
   1.965 +	identifier = (unsigned char)
   1.966 +	                    (state->underlying_kind & SEC_ASN1_TAG_MASK);
   1.967 +	/*
   1.968 +	 * The underlying kind should just be a simple string; there
   1.969 +	 * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
   1.970 +	 */
   1.971 +	PORT_Assert ((identifier & SEC_ASN1_TAGNUM_MASK) == identifier);
   1.972 +	/*
   1.973 +	 * Write out the tag and length for the substring.
   1.974 +	 */
   1.975 +	sec_asn1e_write_identifier_bytes (state, identifier);
   1.976 +	if (state->underlying_kind == SEC_ASN1_BIT_STRING) {
   1.977 +	    char byte;
   1.978 +	    /*
   1.979 +	     * Assume we have a length in bytes but we need to output
   1.980 +	     * a proper bit string.  This interface only works for bit
   1.981 +	     * strings that are full multiples of 8.  If support for
   1.982 +	     * real, variable length bit strings is needed then the
   1.983 +	     * caller will have to know to pass in a bit length instead
   1.984 +	     * of a byte length and then this code will have to
   1.985 +	     * perform the encoding necessary (length written is length
   1.986 +	     * in bytes plus 1, and the first octet of string is the
   1.987 +	     * number of bits remaining between the end of the bit
   1.988 +	     * string and the next byte boundary).
   1.989 +	     */
   1.990 +	    sec_asn1e_write_length_bytes (state, len + 1, PR_FALSE);
   1.991 +	    byte = 0;
   1.992 +	    sec_asn1e_write_contents_bytes (state, &byte, 1);
   1.993 +	} else {
   1.994 +	    sec_asn1e_write_length_bytes (state, len, PR_FALSE);
   1.995 +	}
   1.996 +    }
   1.997 +    sec_asn1e_write_contents_bytes (state, buf, len);
   1.998 +    state->top->status = needBytes;
   1.999 +}
  1.1000 +
  1.1001 +static void
  1.1002 +sec_asn1e_write_contents (sec_asn1e_state *state)
  1.1003 +{
  1.1004 +    unsigned long len = 0;
  1.1005 +
  1.1006 +    PORT_Assert (state->place == duringContents);
  1.1007 +
  1.1008 +    switch (state->underlying_kind) {
  1.1009 +      case SEC_ASN1_SET:
  1.1010 +      case SEC_ASN1_SEQUENCE:
  1.1011 +	PORT_Assert (0);
  1.1012 +	break;
  1.1013 +
  1.1014 +      case SEC_ASN1_BIT_STRING:
  1.1015 +	{
  1.1016 +	    SECItem *item;
  1.1017 +	    char rem;
  1.1018 +
  1.1019 +	    item = (SECItem *)state->src;
  1.1020 +	    len = (item->len + 7) >> 3;
  1.1021 +	    rem = (unsigned char)((len << 3) - item->len); /* remaining bits */
  1.1022 +	    sec_asn1e_write_contents_bytes (state, &rem, 1);
  1.1023 +	    sec_asn1e_write_contents_bytes (state, (char *) item->data, len);
  1.1024 +	}
  1.1025 +	break;
  1.1026 +
  1.1027 +      case SEC_ASN1_BMP_STRING:
  1.1028 +	/* The number of bytes must be divisable by 2 */
  1.1029 +	if ((((SECItem *)state->src)->len) % 2) {
  1.1030 +	    SEC_ASN1EncoderContext *cx;
  1.1031 +
  1.1032 +	    cx = state->top;
  1.1033 +	    cx->status = encodeError;
  1.1034 +	    break;
  1.1035 +	}
  1.1036 +	/* otherwise, fall through to write the content */
  1.1037 +	goto process_string;
  1.1038 +
  1.1039 +      case SEC_ASN1_UNIVERSAL_STRING:
  1.1040 +	/* The number of bytes must be divisable by 4 */
  1.1041 +	if ((((SECItem *)state->src)->len) % 4) {
  1.1042 +	    SEC_ASN1EncoderContext *cx;
  1.1043 +
  1.1044 +	    cx = state->top;
  1.1045 +	    cx->status = encodeError;
  1.1046 +	    break;
  1.1047 +	}
  1.1048 +	/* otherwise, fall through to write the content */
  1.1049 +	goto process_string;
  1.1050 +
  1.1051 +      case SEC_ASN1_INTEGER:
  1.1052 +       /* ASN.1 INTEGERs are signed.  If the source is an unsigned
  1.1053 +	* integer, the encoder will need to handle the conversion here.
  1.1054 +	*/
  1.1055 +	{
  1.1056 +	    unsigned int blen;
  1.1057 +	    unsigned char *buf;
  1.1058 +	    SECItemType integerType;
  1.1059 +	    blen = ((SECItem *)state->src)->len;
  1.1060 +	    buf = ((SECItem *)state->src)->data;
  1.1061 +	    integerType = ((SECItem *)state->src)->type;
  1.1062 +	    while (blen > 0) {
  1.1063 +		if (*buf & 0x80 && integerType == siUnsignedInteger) {
  1.1064 +		    char zero = 0; /* write a leading 0 */
  1.1065 +		    sec_asn1e_write_contents_bytes(state, &zero, 1);
  1.1066 +		    /* and then the remaining buffer */
  1.1067 +		    sec_asn1e_write_contents_bytes(state, 
  1.1068 +						   (char *)buf, blen); 
  1.1069 +		    break;
  1.1070 +		} 
  1.1071 +		/* Check three possibilities:
  1.1072 +		 * 1.  No leading zeros, msb of MSB is not 1;
  1.1073 +		 * 2.  The number is zero itself;
  1.1074 +		 * 3.  Encoding a signed integer with a leading zero,
  1.1075 +		 *     keep the zero so that the number is positive.
  1.1076 +		 */
  1.1077 +		if (*buf != 0 || 
  1.1078 +		     blen == 1 || 
  1.1079 +		     (buf[1] & 0x80 && integerType != siUnsignedInteger) ) 
  1.1080 +		{
  1.1081 +		    sec_asn1e_write_contents_bytes(state, 
  1.1082 +						   (char *)buf, blen); 
  1.1083 +		    break;
  1.1084 +		}
  1.1085 +		/* byte is 0, continue */
  1.1086 +		buf++;
  1.1087 +		blen--;
  1.1088 +	    }
  1.1089 +	}
  1.1090 +	/* done with this content */
  1.1091 +	break;
  1.1092 +			
  1.1093 +process_string:			
  1.1094 +      default:
  1.1095 +	{
  1.1096 +	    SECItem *item;
  1.1097 +
  1.1098 +	    item = (SECItem *)state->src;
  1.1099 +	    sec_asn1e_write_contents_bytes (state, (char *) item->data,
  1.1100 +					    item->len);
  1.1101 +	}
  1.1102 +	break;
  1.1103 +    }
  1.1104 +    state->place = afterContents;
  1.1105 +}
  1.1106 +
  1.1107 +/*
  1.1108 + * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
  1.1109 + */
  1.1110 +static void
  1.1111 +sec_asn1e_next_in_group (sec_asn1e_state *state)
  1.1112 +{
  1.1113 +    sec_asn1e_state *child;
  1.1114 +    void **group;
  1.1115 +    void *member;
  1.1116 +
  1.1117 +    PORT_Assert (state->place == duringGroup);
  1.1118 +    PORT_Assert (state->child != NULL);
  1.1119 +
  1.1120 +    child = state->child;
  1.1121 +
  1.1122 +    group = *(void ***)state->src;
  1.1123 +
  1.1124 +    /*
  1.1125 +     * Find placement of current item.
  1.1126 +     */
  1.1127 +    member = (char *)(state->child->src) - child->theTemplate->offset;
  1.1128 +    while (*group != member)
  1.1129 +	group++;
  1.1130 +
  1.1131 +    /*
  1.1132 +     * Move forward to next item.
  1.1133 +     */
  1.1134 +    group++;
  1.1135 +    if (*group == NULL) {
  1.1136 +	/*
  1.1137 +	 * That was our last one; we are done now.
  1.1138 +	 */
  1.1139 +	child->place = notInUse;
  1.1140 +	state->place = afterContents;
  1.1141 +	return;
  1.1142 +    }
  1.1143 +    child->src = (char *)(*group) + child->theTemplate->offset;
  1.1144 +
  1.1145 +    /*
  1.1146 +     * Re-"push" child.
  1.1147 +     */
  1.1148 +    sec_asn1e_scrub_state (child);
  1.1149 +    state->top->current = child;
  1.1150 +}
  1.1151 +
  1.1152 +
  1.1153 +/*
  1.1154 + * We are moving along through a sequence; move forward by one,
  1.1155 + * (detecting end-of-sequence when it happens).
  1.1156 + */
  1.1157 +static void
  1.1158 +sec_asn1e_next_in_sequence (sec_asn1e_state *state)
  1.1159 +{
  1.1160 +    sec_asn1e_state *child;
  1.1161 +
  1.1162 +    PORT_Assert (state->place == duringSequence);
  1.1163 +    PORT_Assert (state->child != NULL);
  1.1164 +
  1.1165 +    child = state->child;
  1.1166 +
  1.1167 +    /*
  1.1168 +     * Do the "after" field notification.
  1.1169 +     */
  1.1170 +    sec_asn1e_notify_after (state->top, child->src, child->depth);
  1.1171 +
  1.1172 +    /*
  1.1173 +     * Move forward.
  1.1174 +     */
  1.1175 +    child->theTemplate++;
  1.1176 +    if (child->theTemplate->kind == 0) {
  1.1177 +	/*
  1.1178 +	 * We are done with this sequence.
  1.1179 +	 */
  1.1180 +	child->place = notInUse;
  1.1181 +	state->place = afterContents;
  1.1182 +	return;
  1.1183 +    }
  1.1184 +
  1.1185 +    /*
  1.1186 +     * Reset state and push.
  1.1187 +     */
  1.1188 +
  1.1189 +    child->src = (char *)state->src + child->theTemplate->offset;
  1.1190 +
  1.1191 +    /*
  1.1192 +     * Do the "before" field notification.
  1.1193 +     */
  1.1194 +    sec_asn1e_notify_before (state->top, child->src, child->depth);
  1.1195 +
  1.1196 +    state->top->current = child;
  1.1197 +    (void) sec_asn1e_init_state_based_on_template (child);
  1.1198 +}
  1.1199 +
  1.1200 +
  1.1201 +static void
  1.1202 +sec_asn1e_after_contents (sec_asn1e_state *state)
  1.1203 +{
  1.1204 +    PORT_Assert (state->place == afterContents);
  1.1205 +
  1.1206 +    if (state->indefinite)
  1.1207 +	sec_asn1e_write_end_of_contents_bytes (state);
  1.1208 +
  1.1209 +    /*
  1.1210 +     * Just make my parent be the current state.  It will then clean
  1.1211 +     * up after me and free me (or reuse me).
  1.1212 +     */
  1.1213 +    state->top->current = state->parent;
  1.1214 +}
  1.1215 +
  1.1216 +
  1.1217 +/*
  1.1218 + * This function is called whether or not we are streaming; if we
  1.1219 + * *are* streaming, our caller can also instruct us to take bytes
  1.1220 + * from the passed-in buffer (at buf, for length len, which is likely
  1.1221 + * bytes but could even mean bits if the current field is a bit string).
  1.1222 + * If we have been so instructed, we will gobble up bytes from there
  1.1223 + * (rather than from our src structure) and output them, and then
  1.1224 + * we will just return, expecting to be called again -- either with
  1.1225 + * more bytes or after our caller has instructed us that we are done
  1.1226 + * (for now) with the buffer.
  1.1227 + */
  1.1228 +SECStatus
  1.1229 +SEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext *cx,
  1.1230 +		       const char *buf, unsigned long len)
  1.1231 +{
  1.1232 +    sec_asn1e_state *state;
  1.1233 +
  1.1234 +    if (cx->status == needBytes) {
  1.1235 +	cx->status = keepGoing;
  1.1236 +    }
  1.1237 +
  1.1238 +    while (cx->status == keepGoing) {
  1.1239 +	state = cx->current;
  1.1240 +	switch (state->place) {
  1.1241 +	  case beforeHeader:
  1.1242 +	    sec_asn1e_write_header (state);
  1.1243 +	    break;
  1.1244 +	  case duringContents:
  1.1245 +	    if (cx->from_buf)
  1.1246 +		sec_asn1e_write_contents_from_buf (state, buf, len);
  1.1247 +	    else
  1.1248 +		sec_asn1e_write_contents (state);
  1.1249 +	    break;
  1.1250 +	  case duringGroup:
  1.1251 +	    sec_asn1e_next_in_group (state);
  1.1252 +	    break;
  1.1253 +	  case duringSequence:
  1.1254 +	    sec_asn1e_next_in_sequence (state);
  1.1255 +	    break;
  1.1256 +	  case afterContents:
  1.1257 +	    sec_asn1e_after_contents (state);
  1.1258 +	    break;
  1.1259 +	  case afterImplicit:
  1.1260 +	  case afterInline:
  1.1261 +	  case afterPointer:
  1.1262 +	  case afterChoice:
  1.1263 +	    /*
  1.1264 +	     * These states are more documentation than anything.
  1.1265 +	     * They just need to force a pop.
  1.1266 +	     */
  1.1267 +	    PORT_Assert (!state->indefinite);
  1.1268 +	    state->place = afterContents;
  1.1269 +	    break;
  1.1270 +	  case notInUse:
  1.1271 +	  default:
  1.1272 +	    /* This is not an error, but rather a plain old BUG! */
  1.1273 +	    PORT_Assert (0);
  1.1274 +	    cx->status = encodeError;
  1.1275 +	    break;
  1.1276 +	}
  1.1277 +
  1.1278 +	if (cx->status == encodeError)
  1.1279 +	    break;
  1.1280 +
  1.1281 +	/* It might have changed, so we have to update our local copy.  */
  1.1282 +	state = cx->current;
  1.1283 +
  1.1284 +	/* If it is NULL, we have popped all the way to the top.  */
  1.1285 +	if (state == NULL) {
  1.1286 +	    cx->status = allDone;
  1.1287 +	    break;
  1.1288 +	}
  1.1289 +    }
  1.1290 +
  1.1291 +    if (cx->status == encodeError) {
  1.1292 +	return SECFailure;
  1.1293 +    }
  1.1294 +
  1.1295 +    return SECSuccess;
  1.1296 +}
  1.1297 +
  1.1298 +
  1.1299 +void
  1.1300 +SEC_ASN1EncoderFinish (SEC_ASN1EncoderContext *cx)
  1.1301 +{
  1.1302 +    /*
  1.1303 +     * XXX anything else that needs to be finished?
  1.1304 +     */
  1.1305 +
  1.1306 +    PORT_FreeArena (cx->our_pool, PR_FALSE);
  1.1307 +}
  1.1308 +
  1.1309 +
  1.1310 +SEC_ASN1EncoderContext *
  1.1311 +SEC_ASN1EncoderStart (const void *src, const SEC_ASN1Template *theTemplate,
  1.1312 +		      SEC_ASN1WriteProc output_proc, void *output_arg)
  1.1313 +{
  1.1314 +    PLArenaPool *our_pool;
  1.1315 +    SEC_ASN1EncoderContext *cx;
  1.1316 +
  1.1317 +    our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
  1.1318 +    if (our_pool == NULL)
  1.1319 +	return NULL;
  1.1320 +
  1.1321 +    cx = (SEC_ASN1EncoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
  1.1322 +    if (cx == NULL) {
  1.1323 +	PORT_FreeArena (our_pool, PR_FALSE);
  1.1324 +	return NULL;
  1.1325 +    }
  1.1326 +
  1.1327 +    cx->our_pool = our_pool;
  1.1328 +    cx->output_proc = output_proc;
  1.1329 +    cx->output_arg = output_arg;
  1.1330 +
  1.1331 +    cx->status = keepGoing;
  1.1332 +
  1.1333 +    if (sec_asn1e_push_state(cx, theTemplate, src, PR_FALSE) == NULL
  1.1334 +	|| sec_asn1e_init_state_based_on_template (cx->current) == NULL) {
  1.1335 +	/*
  1.1336 +	 * Trouble initializing (probably due to failed allocations)
  1.1337 +	 * requires that we just give up.
  1.1338 +	 */
  1.1339 +	PORT_FreeArena (our_pool, PR_FALSE);
  1.1340 +	return NULL;
  1.1341 +    }
  1.1342 +
  1.1343 +    return cx;
  1.1344 +}
  1.1345 +
  1.1346 +
  1.1347 +/*
  1.1348 + * XXX Do we need a FilterProc, too?
  1.1349 + */
  1.1350 +
  1.1351 +
  1.1352 +void
  1.1353 +SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext *cx,
  1.1354 +			      SEC_ASN1NotifyProc fn, void *arg)
  1.1355 +{
  1.1356 +    cx->notify_proc = fn;
  1.1357 +    cx->notify_arg = arg;
  1.1358 +}
  1.1359 +
  1.1360 +
  1.1361 +void
  1.1362 +SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext *cx)
  1.1363 +{
  1.1364 +    cx->notify_proc = NULL;
  1.1365 +    cx->notify_arg = NULL;	/* not necessary; just being clean */
  1.1366 +}
  1.1367 +
  1.1368 +void
  1.1369 +SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error)
  1.1370 +{
  1.1371 +    PORT_Assert(cx);
  1.1372 +    PORT_SetError(error);
  1.1373 +    cx->status = encodeError;
  1.1374 +}
  1.1375 +
  1.1376 +void
  1.1377 +SEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext *cx)
  1.1378 +{
  1.1379 +    /* XXX is there a way to check that we are "between" fields here? */
  1.1380 +
  1.1381 +    cx->streaming = PR_TRUE;
  1.1382 +}
  1.1383 +
  1.1384 +
  1.1385 +void
  1.1386 +SEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext *cx)
  1.1387 +{
  1.1388 +    /* XXX is there a way to check that we are "between" fields here? */
  1.1389 +
  1.1390 +    cx->streaming = PR_FALSE;
  1.1391 +}
  1.1392 +
  1.1393 +
  1.1394 +void
  1.1395 +SEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext *cx)
  1.1396 +{
  1.1397 +    /* 
  1.1398 +     * XXX is there a way to check that we are "between" fields here?  this
  1.1399 +     * needs to include a check for being in between groups of items in
  1.1400 +     * a SET_OF or SEQUENCE_OF.
  1.1401 +     */
  1.1402 +    PORT_Assert (cx->streaming);
  1.1403 +
  1.1404 +    cx->from_buf = PR_TRUE;
  1.1405 +}
  1.1406 +
  1.1407 +
  1.1408 +void
  1.1409 +SEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext *cx)
  1.1410 +{
  1.1411 +    /* we should actually be taking from buf *now* */
  1.1412 +    PORT_Assert (cx->from_buf);
  1.1413 +    if (! cx->from_buf)		/* if not, just do nothing */
  1.1414 +	return;
  1.1415 +
  1.1416 +    cx->from_buf = PR_FALSE;
  1.1417 +
  1.1418 +    if (cx->status == needBytes) {
  1.1419 +	cx->status = keepGoing;
  1.1420 +	cx->current->place = afterContents;
  1.1421 +    }
  1.1422 +}
  1.1423 +
  1.1424 +
  1.1425 +SECStatus
  1.1426 +SEC_ASN1Encode (const void *src, const SEC_ASN1Template *theTemplate,
  1.1427 +		SEC_ASN1WriteProc output_proc, void *output_arg)
  1.1428 +{
  1.1429 +    SEC_ASN1EncoderContext *ecx;
  1.1430 +    SECStatus rv;
  1.1431 +
  1.1432 +    ecx = SEC_ASN1EncoderStart (src, theTemplate, output_proc, output_arg);
  1.1433 +    if (ecx == NULL)
  1.1434 +	return SECFailure;
  1.1435 +
  1.1436 +    rv = SEC_ASN1EncoderUpdate (ecx, NULL, 0);
  1.1437 +
  1.1438 +    SEC_ASN1EncoderFinish (ecx);
  1.1439 +    return rv;
  1.1440 +}
  1.1441 +
  1.1442 +
  1.1443 +/*
  1.1444 + * XXX depth and data_kind are unused; is there a PC way to silence warnings?
  1.1445 + * (I mean "politically correct", not anything to do with intel/win platform) 
  1.1446 + */
  1.1447 +static void
  1.1448 +sec_asn1e_encode_item_count (void *arg, const char *buf, unsigned long len,
  1.1449 +			     int depth, SEC_ASN1EncodingPart data_kind)
  1.1450 +{
  1.1451 +    unsigned long *count;
  1.1452 +
  1.1453 +    count = (unsigned long*)arg;
  1.1454 +    PORT_Assert (count != NULL);
  1.1455 +
  1.1456 +    *count += len;
  1.1457 +}
  1.1458 +
  1.1459 +
  1.1460 +/* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
  1.1461 +static void
  1.1462 +sec_asn1e_encode_item_store (void *arg, const char *buf, unsigned long len,
  1.1463 +			     int depth, SEC_ASN1EncodingPart data_kind)
  1.1464 +{
  1.1465 +    SECItem *dest;
  1.1466 +
  1.1467 +    dest = (SECItem*)arg;
  1.1468 +    PORT_Assert (dest != NULL);
  1.1469 +
  1.1470 +    PORT_Memcpy (dest->data + dest->len, buf, len);
  1.1471 +    dest->len += len;
  1.1472 +}
  1.1473 +
  1.1474 +
  1.1475 +/*
  1.1476 + * Allocate an entire SECItem, or just the data part of it, to hold
  1.1477 + * "len" bytes of stuff.  Allocate from the given pool, if specified,
  1.1478 + * otherwise just do a vanilla PORT_Alloc.
  1.1479 + *
  1.1480 + * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
  1.1481 + */
  1.1482 +static SECItem *
  1.1483 +sec_asn1e_allocate_item (PLArenaPool *poolp, SECItem *dest, unsigned long len)
  1.1484 +{
  1.1485 +    if (poolp != NULL) {
  1.1486 +	void *release;
  1.1487 +
  1.1488 +	release = PORT_ArenaMark (poolp);
  1.1489 +	if (dest == NULL)
  1.1490 +	    dest = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));
  1.1491 +	if (dest != NULL) {
  1.1492 +	    dest->data = (unsigned char*)PORT_ArenaAlloc (poolp, len);
  1.1493 +	    if (dest->data == NULL) {
  1.1494 +		dest = NULL;
  1.1495 +	    }
  1.1496 +	}
  1.1497 +	if (dest == NULL) {
  1.1498 +	    /* one or both allocations failed; release everything */
  1.1499 +	    PORT_ArenaRelease (poolp, release);
  1.1500 +	} else {
  1.1501 +	    /* everything okay; unmark the arena */
  1.1502 +	    PORT_ArenaUnmark (poolp, release);
  1.1503 +	}
  1.1504 +    } else {
  1.1505 +	SECItem *indest;
  1.1506 +
  1.1507 +	indest = dest;
  1.1508 +	if (dest == NULL)
  1.1509 +	    dest = (SECItem*)PORT_Alloc (sizeof(SECItem));
  1.1510 +	if (dest != NULL) {
  1.1511 +	    dest->type = siBuffer;
  1.1512 +	    dest->data = (unsigned char*)PORT_Alloc (len);
  1.1513 +	    if (dest->data == NULL) {
  1.1514 +		if (indest == NULL)
  1.1515 +		    PORT_Free (dest);
  1.1516 +		dest = NULL;
  1.1517 +	    }
  1.1518 +	}
  1.1519 +    }
  1.1520 +
  1.1521 +    return dest;
  1.1522 +}
  1.1523 +
  1.1524 +
  1.1525 +SECItem *
  1.1526 +SEC_ASN1EncodeItem (PLArenaPool *poolp, SECItem *dest, const void *src,
  1.1527 +		    const SEC_ASN1Template *theTemplate)
  1.1528 +{
  1.1529 +    unsigned long encoding_length;
  1.1530 +    SECStatus rv;
  1.1531 +
  1.1532 +    PORT_Assert (dest == NULL || dest->data == NULL);
  1.1533 +
  1.1534 +    encoding_length = 0;
  1.1535 +    rv = SEC_ASN1Encode (src, theTemplate,
  1.1536 +			 sec_asn1e_encode_item_count, &encoding_length);
  1.1537 +    if (rv != SECSuccess)
  1.1538 +	return NULL;
  1.1539 +
  1.1540 +    dest = sec_asn1e_allocate_item (poolp, dest, encoding_length);
  1.1541 +    if (dest == NULL)
  1.1542 +	return NULL;
  1.1543 +
  1.1544 +    /* XXX necessary?  This really just checks for a bug in the allocate fn */
  1.1545 +    PORT_Assert (dest->data != NULL);
  1.1546 +    if (dest->data == NULL)
  1.1547 +	return NULL;
  1.1548 +
  1.1549 +    dest->len = 0;
  1.1550 +    (void) SEC_ASN1Encode (src, theTemplate, sec_asn1e_encode_item_store, dest);
  1.1551 +
  1.1552 +    PORT_Assert (encoding_length == dest->len);
  1.1553 +    return dest;
  1.1554 +}
  1.1555 +
  1.1556 +
  1.1557 +static SECItem *
  1.1558 +sec_asn1e_integer(PLArenaPool *poolp, SECItem *dest, unsigned long value,
  1.1559 +		  PRBool is_unsigned)
  1.1560 +{
  1.1561 +    unsigned long copy;
  1.1562 +    unsigned char sign;
  1.1563 +    int len = 0;
  1.1564 +
  1.1565 +    /*
  1.1566 +     * Determine the length of the encoded value (minimum of 1).
  1.1567 +     */
  1.1568 +    copy = value;
  1.1569 +    do {
  1.1570 +	len++;
  1.1571 +	sign = (unsigned char)(copy & 0x80);
  1.1572 +	copy >>= 8;
  1.1573 +    } while (copy);
  1.1574 +
  1.1575 +    /*
  1.1576 +     * If 'value' is non-negative, and the high bit of the last
  1.1577 +     * byte we counted was set, we need to add one to the length so
  1.1578 +     * we put a high-order zero byte in the encoding.
  1.1579 +     */
  1.1580 +    if (sign && (is_unsigned || (long)value >= 0))
  1.1581 +	len++;
  1.1582 +
  1.1583 +    /*
  1.1584 +     * Allocate the item (if necessary) and the data pointer within.
  1.1585 +     */
  1.1586 +    dest = sec_asn1e_allocate_item (poolp, dest, len);
  1.1587 +    if (dest == NULL)
  1.1588 +	return NULL;
  1.1589 +
  1.1590 +    /*
  1.1591 +     * Store the value, byte by byte, in the item.
  1.1592 +     */
  1.1593 +    dest->len = len;
  1.1594 +    while (len) {
  1.1595 +	dest->data[--len] = (unsigned char)value;
  1.1596 +	value >>= 8;
  1.1597 +    }
  1.1598 +    PORT_Assert (value == 0);
  1.1599 +
  1.1600 +    return dest;
  1.1601 +}
  1.1602 +
  1.1603 +
  1.1604 +SECItem *
  1.1605 +SEC_ASN1EncodeInteger(PLArenaPool *poolp, SECItem *dest, long value)
  1.1606 +{
  1.1607 +    return sec_asn1e_integer (poolp, dest, (unsigned long) value, PR_FALSE);
  1.1608 +}
  1.1609 +
  1.1610 +
  1.1611 +SECItem *
  1.1612 +SEC_ASN1EncodeUnsignedInteger(PLArenaPool *poolp,
  1.1613 +			      SECItem *dest, unsigned long value)
  1.1614 +{
  1.1615 +    return sec_asn1e_integer (poolp, dest, value, PR_TRUE);
  1.1616 +}

mercurial