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 +}