1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/util/quickder.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,897 @@ 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 + Optimized ASN.1 DER decoder 1.10 + 1.11 +*/ 1.12 + 1.13 +#include "secerr.h" 1.14 +#include "secasn1.h" /* for SEC_ASN1GetSubtemplate */ 1.15 +#include "secitem.h" 1.16 + 1.17 +/* 1.18 + * simple definite-length ASN.1 decoder 1.19 + */ 1.20 + 1.21 +static unsigned char* definite_length_decoder(const unsigned char *buf, 1.22 + const unsigned int length, 1.23 + unsigned int *data_length, 1.24 + PRBool includeTag) 1.25 +{ 1.26 + unsigned char tag; 1.27 + unsigned int used_length= 0; 1.28 + unsigned int data_len; 1.29 + 1.30 + if (used_length >= length) 1.31 + { 1.32 + return NULL; 1.33 + } 1.34 + tag = buf[used_length++]; 1.35 + 1.36 + /* blow out when we come to the end */ 1.37 + if (tag == 0) 1.38 + { 1.39 + return NULL; 1.40 + } 1.41 + 1.42 + if (used_length >= length) 1.43 + { 1.44 + return NULL; 1.45 + } 1.46 + data_len = buf[used_length++]; 1.47 + 1.48 + if (data_len&0x80) 1.49 + { 1.50 + int len_count = data_len & 0x7f; 1.51 + 1.52 + data_len = 0; 1.53 + 1.54 + while (len_count-- > 0) 1.55 + { 1.56 + if (used_length >= length) 1.57 + { 1.58 + return NULL; 1.59 + } 1.60 + data_len = (data_len << 8) | buf[used_length++]; 1.61 + } 1.62 + } 1.63 + 1.64 + if (data_len > (length-used_length) ) 1.65 + { 1.66 + return NULL; 1.67 + } 1.68 + if (includeTag) data_len += used_length; 1.69 + 1.70 + *data_length = data_len; 1.71 + return ((unsigned char*)buf + (includeTag ? 0 : used_length)); 1.72 +} 1.73 + 1.74 +static SECStatus GetItem(SECItem* src, SECItem* dest, PRBool includeTag) 1.75 +{ 1.76 + if ( (!src) || (!dest) || (!src->data && src->len) ) 1.77 + { 1.78 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.79 + return SECFailure; 1.80 + } 1.81 + 1.82 + if (!src->len) 1.83 + { 1.84 + /* reaching the end of the buffer is not an error */ 1.85 + dest->data = NULL; 1.86 + dest->len = 0; 1.87 + return SECSuccess; 1.88 + } 1.89 + 1.90 + dest->data = definite_length_decoder(src->data, src->len, &dest->len, 1.91 + includeTag); 1.92 + if (dest->data == NULL) 1.93 + { 1.94 + PORT_SetError(SEC_ERROR_BAD_DER); 1.95 + return SECFailure; 1.96 + } 1.97 + src->len -= (dest->data - src->data) + dest->len; 1.98 + src->data = dest->data + dest->len; 1.99 + return SECSuccess; 1.100 +} 1.101 + 1.102 +/* check if the actual component's type matches the type in the template */ 1.103 + 1.104 +static SECStatus MatchComponentType(const SEC_ASN1Template* templateEntry, 1.105 + SECItem* item, PRBool* match, void* dest) 1.106 +{ 1.107 + unsigned long kind = 0; 1.108 + unsigned char tag = 0; 1.109 + 1.110 + if ( (!item) || (!item->data && item->len) || (!templateEntry) || (!match) ) 1.111 + { 1.112 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.113 + return SECFailure; 1.114 + } 1.115 + 1.116 + if (!item->len) 1.117 + { 1.118 + *match = PR_FALSE; 1.119 + return SECSuccess; 1.120 + } 1.121 + 1.122 + kind = templateEntry->kind; 1.123 + tag = *(unsigned char*) item->data; 1.124 + 1.125 + if ( ( (kind & SEC_ASN1_INLINE) || 1.126 + (kind & SEC_ASN1_POINTER) ) && 1.127 + (0 == (kind & SEC_ASN1_TAG_MASK) ) ) 1.128 + { 1.129 + /* These cases are special because the template's "kind" does not 1.130 + give us the information for the ASN.1 tag of the next item. It can 1.131 + only be figured out from the subtemplate. */ 1.132 + if (!(kind & SEC_ASN1_OPTIONAL)) 1.133 + { 1.134 + /* This is a required component. If there is a type mismatch, 1.135 + the decoding of the subtemplate will fail, so assume this 1.136 + is a match at the parent level and let it fail later. This 1.137 + avoids a redundant check in matching cases */ 1.138 + *match = PR_TRUE; 1.139 + return SECSuccess; 1.140 + } 1.141 + else 1.142 + { 1.143 + /* optional component. This is the hard case. Now we need to 1.144 + look at the subtemplate to get the expected kind */ 1.145 + const SEC_ASN1Template* subTemplate = 1.146 + SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE); 1.147 + if (!subTemplate) 1.148 + { 1.149 + PORT_SetError(SEC_ERROR_BAD_TEMPLATE); 1.150 + return SECFailure; 1.151 + } 1.152 + if ( (subTemplate->kind & SEC_ASN1_INLINE) || 1.153 + (subTemplate->kind & SEC_ASN1_POINTER) ) 1.154 + { 1.155 + /* disallow nesting SEC_ASN1_POINTER and SEC_ASN1_INLINE, 1.156 + otherwise you may get a false positive due to the recursion 1.157 + optimization above that always matches the type if the 1.158 + component is required . Nesting these should never be 1.159 + required, so that no one should miss this ability */ 1.160 + PORT_SetError(SEC_ERROR_BAD_TEMPLATE); 1.161 + return SECFailure; 1.162 + } 1.163 + return MatchComponentType(subTemplate, item, match, 1.164 + (void*)((char*)dest + templateEntry->offset)); 1.165 + } 1.166 + } 1.167 + 1.168 + if (kind & SEC_ASN1_CHOICE) 1.169 + { 1.170 + /* we need to check the component's tag against each choice's tag */ 1.171 + /* XXX it would be nice to save the index of the choice here so that 1.172 + DecodeChoice wouldn't have to do this again. However, due to the 1.173 + recursivity of MatchComponentType, we don't know if we are in a 1.174 + required or optional component, so we can't write anywhere in 1.175 + the destination within this function */ 1.176 + unsigned choiceIndex = 1; 1.177 + const SEC_ASN1Template* choiceEntry; 1.178 + while ( (choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind)) 1.179 + { 1.180 + if ( (SECSuccess == MatchComponentType(choiceEntry, item, match, 1.181 + (void*)((char*)dest + choiceEntry->offset))) && 1.182 + (PR_TRUE == *match) ) 1.183 + { 1.184 + return SECSuccess; 1.185 + } 1.186 + } 1.187 + /* no match, caller must decide if this is BAD DER, or not. */ 1.188 + *match = PR_FALSE; 1.189 + return SECSuccess; 1.190 + } 1.191 + 1.192 + if (kind & SEC_ASN1_ANY) 1.193 + { 1.194 + /* SEC_ASN1_ANY always matches */ 1.195 + *match = PR_TRUE; 1.196 + return SECSuccess; 1.197 + } 1.198 + 1.199 + if ( (0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) && 1.200 + (!(kind & SEC_ASN1_EXPLICIT)) && 1.201 + ( ( (kind & SEC_ASN1_SAVE) || 1.202 + (kind & SEC_ASN1_SKIP) ) && 1.203 + (!(kind & SEC_ASN1_OPTIONAL)) 1.204 + ) 1.205 + ) 1.206 + { 1.207 + /* when saving or skipping a required component, a type is not 1.208 + required in the template. This is for legacy support of 1.209 + SEC_ASN1_SAVE and SEC_ASN1_SKIP only. XXX I would like to 1.210 + deprecate these usages and always require a type, as this 1.211 + disables type checking, and effectively forbids us from 1.212 + transparently ignoring optional components we aren't aware of */ 1.213 + *match = PR_TRUE; 1.214 + return SECSuccess; 1.215 + } 1.216 + 1.217 + /* first, do a class check */ 1.218 + if ( (tag & SEC_ASN1_CLASS_MASK) != 1.219 + (((unsigned char)kind) & SEC_ASN1_CLASS_MASK) ) 1.220 + { 1.221 +#ifdef DEBUG 1.222 + /* this is only to help debugging of the decoder in case of problems */ 1.223 + unsigned char tagclass = tag & SEC_ASN1_CLASS_MASK; 1.224 + unsigned char expectedclass = (unsigned char)kind & SEC_ASN1_CLASS_MASK; 1.225 + tagclass = tagclass; 1.226 + expectedclass = expectedclass; 1.227 +#endif 1.228 + *match = PR_FALSE; 1.229 + return SECSuccess; 1.230 + } 1.231 + 1.232 + /* now do a tag check */ 1.233 + if ( ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) != 1.234 + (tag & SEC_ASN1_TAGNUM_MASK)) 1.235 + { 1.236 + *match = PR_FALSE; 1.237 + return SECSuccess; 1.238 + } 1.239 + 1.240 + /* now, do a method check. This depends on the class */ 1.241 + switch (tag & SEC_ASN1_CLASS_MASK) 1.242 + { 1.243 + case SEC_ASN1_UNIVERSAL: 1.244 + /* For types of the SEC_ASN1_UNIVERSAL class, we know which must be 1.245 + primitive or constructed based on the tag */ 1.246 + switch (tag & SEC_ASN1_TAGNUM_MASK) 1.247 + { 1.248 + case SEC_ASN1_SEQUENCE: 1.249 + case SEC_ASN1_SET: 1.250 + case SEC_ASN1_EMBEDDED_PDV: 1.251 + /* this component must be a constructed type */ 1.252 + /* XXX add any new universal constructed type here */ 1.253 + if (tag & SEC_ASN1_CONSTRUCTED) 1.254 + { 1.255 + *match = PR_TRUE; 1.256 + return SECSuccess; 1.257 + } 1.258 + break; 1.259 + 1.260 + default: 1.261 + /* this component must be a primitive type */ 1.262 + if (! (tag & SEC_ASN1_CONSTRUCTED)) 1.263 + { 1.264 + *match = PR_TRUE; 1.265 + return SECSuccess; 1.266 + } 1.267 + break; 1.268 + } 1.269 + break; 1.270 + 1.271 + default: 1.272 + /* for all other classes, we check the method based on the template */ 1.273 + if ( (unsigned char)(kind & SEC_ASN1_METHOD_MASK) == 1.274 + (tag & SEC_ASN1_METHOD_MASK) ) 1.275 + { 1.276 + *match = PR_TRUE; 1.277 + return SECSuccess; 1.278 + } 1.279 + /* method does not match between template and component */ 1.280 + break; 1.281 + } 1.282 + 1.283 + *match = PR_FALSE; 1.284 + return SECSuccess; 1.285 +} 1.286 + 1.287 +#ifdef DEBUG 1.288 + 1.289 +static SECStatus CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate) 1.290 +{ 1.291 + SECStatus rv = SECSuccess; 1.292 + const SEC_ASN1Template* sequenceEntry = NULL; 1.293 + unsigned long seqIndex = 0; 1.294 + unsigned long lastEntryIndex = 0; 1.295 + unsigned long ambiguityIndex = 0; 1.296 + PRBool foundAmbiguity = PR_FALSE; 1.297 + 1.298 + do 1.299 + { 1.300 + sequenceEntry = &sequenceTemplate[seqIndex++]; 1.301 + if (sequenceEntry->kind) 1.302 + { 1.303 + /* ensure that we don't have an optional component of SEC_ASN1_ANY 1.304 + in the middle of the sequence, since we could not handle it */ 1.305 + /* XXX this function needs to dig into the subtemplates to find 1.306 + the next tag */ 1.307 + if ( (PR_FALSE == foundAmbiguity) && 1.308 + (sequenceEntry->kind & SEC_ASN1_OPTIONAL) && 1.309 + (sequenceEntry->kind & SEC_ASN1_ANY) ) 1.310 + { 1.311 + foundAmbiguity = PR_TRUE; 1.312 + ambiguityIndex = seqIndex - 1; 1.313 + } 1.314 + } 1.315 + } while (sequenceEntry->kind); 1.316 + 1.317 + lastEntryIndex = seqIndex - 2; 1.318 + 1.319 + if (PR_FALSE != foundAmbiguity) 1.320 + { 1.321 + if (ambiguityIndex < lastEntryIndex) 1.322 + { 1.323 + /* ambiguity can only be tolerated on the last entry */ 1.324 + PORT_SetError(SEC_ERROR_BAD_TEMPLATE); 1.325 + rv = SECFailure; 1.326 + } 1.327 + } 1.328 + 1.329 + /* XXX also enforce ASN.1 requirement that tags be 1.330 + distinct for consecutive optional components */ 1.331 + 1.332 + return rv; 1.333 +} 1.334 + 1.335 +#endif 1.336 + 1.337 +static SECStatus DecodeItem(void* dest, 1.338 + const SEC_ASN1Template* templateEntry, 1.339 + SECItem* src, PLArenaPool* arena, PRBool checkTag); 1.340 + 1.341 +static SECStatus DecodeSequence(void* dest, 1.342 + const SEC_ASN1Template* templateEntry, 1.343 + SECItem* src, PLArenaPool* arena) 1.344 +{ 1.345 + SECStatus rv = SECSuccess; 1.346 + SECItem source; 1.347 + SECItem sequence; 1.348 + const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]); 1.349 + const SEC_ASN1Template* sequenceEntry = NULL; 1.350 + unsigned long seqindex = 0; 1.351 + 1.352 +#ifdef DEBUG 1.353 + /* for a sequence, we need to validate the template. */ 1.354 + rv = CheckSequenceTemplate(sequenceTemplate); 1.355 +#endif 1.356 + 1.357 + source = *src; 1.358 + 1.359 + /* get the sequence */ 1.360 + if (SECSuccess == rv) 1.361 + { 1.362 + rv = GetItem(&source, &sequence, PR_FALSE); 1.363 + } 1.364 + 1.365 + /* process it */ 1.366 + if (SECSuccess == rv) 1.367 + do 1.368 + { 1.369 + sequenceEntry = &sequenceTemplate[seqindex++]; 1.370 + if ( (sequenceEntry && sequenceEntry->kind) && 1.371 + (sequenceEntry->kind != SEC_ASN1_SKIP_REST) ) 1.372 + { 1.373 + rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE); 1.374 + } 1.375 + } while ( (SECSuccess == rv) && 1.376 + (sequenceEntry->kind && 1.377 + sequenceEntry->kind != SEC_ASN1_SKIP_REST) ); 1.378 + /* we should have consumed all the bytes in the sequence by now 1.379 + unless the caller doesn't care about the rest of the sequence */ 1.380 + if (SECSuccess == rv && sequence.len && 1.381 + sequenceEntry && sequenceEntry->kind != SEC_ASN1_SKIP_REST) 1.382 + { 1.383 + /* it isn't 100% clear whether this is a bad DER or a bad template. 1.384 + The problem is that logically, they don't match - there is extra 1.385 + data in the DER that the template doesn't know about */ 1.386 + PORT_SetError(SEC_ERROR_BAD_DER); 1.387 + rv = SECFailure; 1.388 + } 1.389 + 1.390 + return rv; 1.391 +} 1.392 + 1.393 +static SECStatus DecodeInline(void* dest, 1.394 + const SEC_ASN1Template* templateEntry, 1.395 + SECItem* src, PLArenaPool* arena, PRBool checkTag) 1.396 +{ 1.397 + const SEC_ASN1Template* inlineTemplate = 1.398 + SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE); 1.399 + return DecodeItem((void*)((char*)dest + templateEntry->offset), 1.400 + inlineTemplate, src, arena, checkTag); 1.401 +} 1.402 + 1.403 +static SECStatus DecodePointer(void* dest, 1.404 + const SEC_ASN1Template* templateEntry, 1.405 + SECItem* src, PLArenaPool* arena, PRBool checkTag) 1.406 +{ 1.407 + const SEC_ASN1Template* ptrTemplate = 1.408 + SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE); 1.409 + void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size); 1.410 + *(void**)((char*)dest + templateEntry->offset) = subdata; 1.411 + if (subdata) 1.412 + { 1.413 + return DecodeItem(subdata, ptrTemplate, src, arena, checkTag); 1.414 + } 1.415 + else 1.416 + { 1.417 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.418 + return SECFailure; 1.419 + } 1.420 +} 1.421 + 1.422 +static SECStatus DecodeImplicit(void* dest, 1.423 + const SEC_ASN1Template* templateEntry, 1.424 + SECItem* src, PLArenaPool* arena) 1.425 +{ 1.426 + if (templateEntry->kind & SEC_ASN1_POINTER) 1.427 + { 1.428 + return DecodePointer((void*)((char*)dest ), 1.429 + templateEntry, src, arena, PR_FALSE); 1.430 + } 1.431 + else 1.432 + { 1.433 + return DecodeInline((void*)((char*)dest ), 1.434 + templateEntry, src, arena, PR_FALSE); 1.435 + } 1.436 +} 1.437 + 1.438 +static SECStatus DecodeChoice(void* dest, 1.439 + const SEC_ASN1Template* templateEntry, 1.440 + SECItem* src, PLArenaPool* arena) 1.441 +{ 1.442 + SECStatus rv = SECSuccess; 1.443 + SECItem choice; 1.444 + const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]); 1.445 + const SEC_ASN1Template* choiceEntry = NULL; 1.446 + unsigned long choiceindex = 0; 1.447 + 1.448 + /* XXX for a choice component, we should validate the template to make 1.449 + sure the tags are distinct, in debug builds. This hasn't been 1.450 + implemented yet */ 1.451 + /* rv = CheckChoiceTemplate(sequenceTemplate); */ 1.452 + 1.453 + /* process it */ 1.454 + do 1.455 + { 1.456 + choice = *src; 1.457 + choiceEntry = &choiceTemplate[choiceindex++]; 1.458 + if (choiceEntry->kind) 1.459 + { 1.460 + rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE); 1.461 + } 1.462 + } while ( (SECFailure == rv) && (choiceEntry->kind)); 1.463 + 1.464 + if (SECFailure == rv) 1.465 + { 1.466 + /* the component didn't match any of the choices */ 1.467 + PORT_SetError(SEC_ERROR_BAD_DER); 1.468 + } 1.469 + else 1.470 + { 1.471 + /* set the type in the union here */ 1.472 + int *which = (int *)((char *)dest + templateEntry->offset); 1.473 + *which = (int)choiceEntry->size; 1.474 + } 1.475 + 1.476 + /* we should have consumed all the bytes by now */ 1.477 + /* fail if we have not */ 1.478 + if (SECSuccess == rv && choice.len) 1.479 + { 1.480 + /* there is extra data that isn't listed in the template */ 1.481 + PORT_SetError(SEC_ERROR_BAD_DER); 1.482 + rv = SECFailure; 1.483 + } 1.484 + return rv; 1.485 +} 1.486 + 1.487 +static SECStatus DecodeGroup(void* dest, 1.488 + const SEC_ASN1Template* templateEntry, 1.489 + SECItem* src, PLArenaPool* arena) 1.490 +{ 1.491 + SECStatus rv = SECSuccess; 1.492 + SECItem source; 1.493 + SECItem group; 1.494 + PRUint32 totalEntries = 0; 1.495 + PRUint32 entryIndex = 0; 1.496 + void** entries = NULL; 1.497 + 1.498 + const SEC_ASN1Template* subTemplate = 1.499 + SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE); 1.500 + 1.501 + source = *src; 1.502 + 1.503 + /* get the group */ 1.504 + if (SECSuccess == rv) 1.505 + { 1.506 + rv = GetItem(&source, &group, PR_FALSE); 1.507 + } 1.508 + 1.509 + /* XXX we should check the subtemplate in debug builds */ 1.510 + if (SECSuccess == rv) 1.511 + { 1.512 + /* first, count the number of entries. Benchmarking showed that this 1.513 + counting pass is more efficient than trying to allocate entries as 1.514 + we read the DER, even if allocating many entries at a time 1.515 + */ 1.516 + SECItem counter = group; 1.517 + do 1.518 + { 1.519 + SECItem anitem; 1.520 + rv = GetItem(&counter, &anitem, PR_TRUE); 1.521 + if (SECSuccess == rv && (anitem.len) ) 1.522 + { 1.523 + totalEntries++; 1.524 + } 1.525 + } while ( (SECSuccess == rv) && (counter.len) ); 1.526 + 1.527 + if (SECSuccess == rv) 1.528 + { 1.529 + /* allocate room for pointer array and entries */ 1.530 + /* we want to allocate the array even if there is 0 entry */ 1.531 + entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*)* 1.532 + (totalEntries + 1 ) + /* the extra one is for NULL termination */ 1.533 + subTemplate->size*totalEntries); 1.534 + 1.535 + if (entries) 1.536 + { 1.537 + entries[totalEntries] = NULL; /* terminate the array */ 1.538 + } 1.539 + else 1.540 + { 1.541 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.542 + rv = SECFailure; 1.543 + } 1.544 + if (SECSuccess == rv) 1.545 + { 1.546 + void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*)*(totalEntries + 1 )); 1.547 + /* and fix the pointers in the array */ 1.548 + PRUint32 entriesIndex = 0; 1.549 + for (entriesIndex = 0;entriesIndex<totalEntries;entriesIndex++) 1.550 + { 1.551 + entries[entriesIndex] = 1.552 + (char*)entriesData + (subTemplate->size*entriesIndex); 1.553 + } 1.554 + } 1.555 + } 1.556 + } 1.557 + 1.558 + if (SECSuccess == rv && totalEntries) 1.559 + do 1.560 + { 1.561 + if (!(entryIndex<totalEntries)) 1.562 + { 1.563 + rv = SECFailure; 1.564 + break; 1.565 + } 1.566 + rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE); 1.567 + } while ( (SECSuccess == rv) && (group.len) ); 1.568 + /* we should be at the end of the set by now */ 1.569 + /* save the entries where requested */ 1.570 + memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**)); 1.571 + 1.572 + return rv; 1.573 +} 1.574 + 1.575 +static SECStatus DecodeExplicit(void* dest, 1.576 + const SEC_ASN1Template* templateEntry, 1.577 + SECItem* src, PLArenaPool* arena) 1.578 +{ 1.579 + SECStatus rv = SECSuccess; 1.580 + SECItem subItem; 1.581 + SECItem constructed = *src; 1.582 + 1.583 + rv = GetItem(&constructed, &subItem, PR_FALSE); 1.584 + 1.585 + if (SECSuccess == rv) 1.586 + { 1.587 + if (templateEntry->kind & SEC_ASN1_POINTER) 1.588 + { 1.589 + rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE); 1.590 + } 1.591 + else 1.592 + { 1.593 + rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE); 1.594 + } 1.595 + } 1.596 + 1.597 + return rv; 1.598 +} 1.599 + 1.600 +/* new decoder implementation. This is a recursive function */ 1.601 + 1.602 +static SECStatus DecodeItem(void* dest, 1.603 + const SEC_ASN1Template* templateEntry, 1.604 + SECItem* src, PLArenaPool* arena, PRBool checkTag) 1.605 +{ 1.606 + SECStatus rv = SECSuccess; 1.607 + SECItem temp; 1.608 + SECItem mark; 1.609 + PRBool pop = PR_FALSE; 1.610 + PRBool decode = PR_TRUE; 1.611 + PRBool save = PR_FALSE; 1.612 + unsigned long kind; 1.613 + PRBool match = PR_TRUE; 1.614 + PRBool optional = PR_FALSE; 1.615 + 1.616 + PR_ASSERT(src && dest && templateEntry && arena); 1.617 +#if 0 1.618 + if (!src || !dest || !templateEntry || !arena) 1.619 + { 1.620 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.621 + rv = SECFailure; 1.622 + } 1.623 +#endif 1.624 + 1.625 + if (SECSuccess == rv) 1.626 + { 1.627 + /* do the template validation */ 1.628 + kind = templateEntry->kind; 1.629 + optional = (0 != (kind & SEC_ASN1_OPTIONAL)); 1.630 + if (!kind) 1.631 + { 1.632 + PORT_SetError(SEC_ERROR_BAD_TEMPLATE); 1.633 + rv = SECFailure; 1.634 + } 1.635 + } 1.636 + 1.637 + if (SECSuccess == rv) 1.638 + { 1.639 +#ifdef DEBUG 1.640 + if (kind & SEC_ASN1_DEBUG_BREAK) 1.641 + { 1.642 + /* when debugging the decoder or a template that fails to 1.643 + decode, put SEC_ASN1_DEBUG in the component that gives you 1.644 + trouble. The decoder will then get to this block and assert. 1.645 + If you want to debug the rest of the code, you can set a 1.646 + breakpoint and set dontassert to PR_TRUE, which will let 1.647 + you skip over the assert and continue the debugging session 1.648 + past it. */ 1.649 + PRBool dontassert = PR_FALSE; 1.650 + PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/ 1.651 + } 1.652 +#endif 1.653 + 1.654 + if ((kind & SEC_ASN1_SKIP) || 1.655 + (kind & SEC_ASN1_SAVE)) 1.656 + { 1.657 + /* if skipping or saving this component, don't decode it */ 1.658 + decode = PR_FALSE; 1.659 + } 1.660 + 1.661 + if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL)) 1.662 + { 1.663 + /* if saving this component, or if it is optional, we may not want to 1.664 + move past it, so save the position in case we have to rewind */ 1.665 + mark = *src; 1.666 + if (kind & SEC_ASN1_SAVE) 1.667 + { 1.668 + save = PR_TRUE; 1.669 + if (0 == (kind & SEC_ASN1_SKIP)) 1.670 + { 1.671 + /* we will for sure have to rewind when saving this 1.672 + component and not skipping it. This is true for all 1.673 + legacy uses of SEC_ASN1_SAVE where the following entry 1.674 + in the template would causes the same component to be 1.675 + processed again */ 1.676 + pop = PR_TRUE; 1.677 + } 1.678 + } 1.679 + } 1.680 + 1.681 + rv = GetItem(src, &temp, PR_TRUE); 1.682 + } 1.683 + 1.684 + if (SECSuccess == rv) 1.685 + { 1.686 + /* now check if the component matches what we expect in the template */ 1.687 + 1.688 + if (PR_TRUE == checkTag) 1.689 + 1.690 + { 1.691 + rv = MatchComponentType(templateEntry, &temp, &match, dest); 1.692 + } 1.693 + 1.694 + if ( (SECSuccess == rv) && (PR_TRUE != match) ) 1.695 + { 1.696 + if (kind & SEC_ASN1_OPTIONAL) 1.697 + { 1.698 + 1.699 + /* the optional component is missing. This is not fatal. */ 1.700 + /* Rewind, don't decode, and don't save */ 1.701 + pop = PR_TRUE; 1.702 + decode = PR_FALSE; 1.703 + save = PR_FALSE; 1.704 + } 1.705 + else 1.706 + { 1.707 + /* a required component is missing. abort */ 1.708 + PORT_SetError(SEC_ERROR_BAD_DER); 1.709 + rv = SECFailure; 1.710 + } 1.711 + } 1.712 + } 1.713 + 1.714 + if ((SECSuccess == rv) && (PR_TRUE == decode)) 1.715 + { 1.716 + /* the order of processing here is is the tricky part */ 1.717 + /* we start with our special cases */ 1.718 + /* first, check the component class */ 1.719 + if (kind & SEC_ASN1_INLINE) 1.720 + { 1.721 + /* decode inline template */ 1.722 + rv = DecodeInline(dest, templateEntry, &temp , arena, PR_TRUE); 1.723 + } 1.724 + 1.725 + else 1.726 + if (kind & SEC_ASN1_EXPLICIT) 1.727 + { 1.728 + rv = DecodeExplicit(dest, templateEntry, &temp, arena); 1.729 + } 1.730 + else 1.731 + if ( (SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) && 1.732 + 1.733 + (!(kind & SEC_ASN1_EXPLICIT))) 1.734 + { 1.735 + 1.736 + /* decode implicitly tagged components */ 1.737 + rv = DecodeImplicit(dest, templateEntry, &temp , arena); 1.738 + } 1.739 + else 1.740 + if (kind & SEC_ASN1_POINTER) 1.741 + { 1.742 + rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE); 1.743 + } 1.744 + else 1.745 + if (kind & SEC_ASN1_CHOICE) 1.746 + { 1.747 + rv = DecodeChoice(dest, templateEntry, &temp, arena); 1.748 + } 1.749 + else 1.750 + if (kind & SEC_ASN1_ANY) 1.751 + { 1.752 + /* catch-all ANY type, don't decode */ 1.753 + save = PR_TRUE; 1.754 + if (kind & SEC_ASN1_INNER) 1.755 + { 1.756 + /* skip the tag and length */ 1.757 + SECItem newtemp = temp; 1.758 + rv = GetItem(&newtemp, &temp, PR_FALSE); 1.759 + } 1.760 + } 1.761 + else 1.762 + if (kind & SEC_ASN1_GROUP) 1.763 + { 1.764 + if ( (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) || 1.765 + (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK)) ) 1.766 + { 1.767 + rv = DecodeGroup(dest, templateEntry, &temp , arena); 1.768 + } 1.769 + else 1.770 + { 1.771 + /* a group can only be a SET OF or SEQUENCE OF */ 1.772 + PORT_SetError(SEC_ERROR_BAD_TEMPLATE); 1.773 + rv = SECFailure; 1.774 + } 1.775 + } 1.776 + else 1.777 + if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) 1.778 + { 1.779 + /* plain SEQUENCE */ 1.780 + rv = DecodeSequence(dest, templateEntry, &temp , arena); 1.781 + } 1.782 + else 1.783 + { 1.784 + /* handle all other types as "save" */ 1.785 + /* we should only get here for primitive universal types */ 1.786 + SECItem newtemp = temp; 1.787 + rv = GetItem(&newtemp, &temp, PR_FALSE); 1.788 + save = PR_TRUE; 1.789 + if ((SECSuccess == rv) && 1.790 + SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK)) 1.791 + { 1.792 + unsigned long tagnum = kind & SEC_ASN1_TAGNUM_MASK; 1.793 + if ( temp.len == 0 && (tagnum == SEC_ASN1_BOOLEAN || 1.794 + tagnum == SEC_ASN1_INTEGER || 1.795 + tagnum == SEC_ASN1_BIT_STRING || 1.796 + tagnum == SEC_ASN1_OBJECT_ID || 1.797 + tagnum == SEC_ASN1_ENUMERATED || 1.798 + tagnum == SEC_ASN1_UTC_TIME || 1.799 + tagnum == SEC_ASN1_GENERALIZED_TIME) ) 1.800 + { 1.801 + /* these types MUST have at least one content octet */ 1.802 + PORT_SetError(SEC_ERROR_BAD_DER); 1.803 + rv = SECFailure; 1.804 + } 1.805 + else 1.806 + switch (tagnum) 1.807 + { 1.808 + /* special cases of primitive types */ 1.809 + case SEC_ASN1_INTEGER: 1.810 + { 1.811 + /* remove leading zeroes if the caller requested 1.812 + siUnsignedInteger 1.813 + This is to allow RSA key operations to work */ 1.814 + SECItem* destItem = (SECItem*) ((char*)dest + 1.815 + templateEntry->offset); 1.816 + if (destItem && (siUnsignedInteger == destItem->type)) 1.817 + { 1.818 + while (temp.len > 1 && temp.data[0] == 0) 1.819 + { /* leading 0 */ 1.820 + temp.data++; 1.821 + temp.len--; 1.822 + } 1.823 + } 1.824 + break; 1.825 + } 1.826 + 1.827 + case SEC_ASN1_BIT_STRING: 1.828 + { 1.829 + /* change the length in the SECItem to be the number 1.830 + of bits */ 1.831 + temp.len = (temp.len-1)*8 - (temp.data[0] & 0x7); 1.832 + temp.data++; 1.833 + break; 1.834 + } 1.835 + 1.836 + default: 1.837 + { 1.838 + break; 1.839 + } 1.840 + } 1.841 + } 1.842 + } 1.843 + } 1.844 + 1.845 + if ((SECSuccess == rv) && (PR_TRUE == save)) 1.846 + { 1.847 + SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset); 1.848 + if (destItem) 1.849 + { 1.850 + /* we leave the type alone in the destination SECItem. 1.851 + If part of the destination was allocated by the decoder, in 1.852 + cases of POINTER, SET OF and SEQUENCE OF, then type is set to 1.853 + siBuffer due to the use of PORT_ArenaZAlloc*/ 1.854 + destItem->data = temp.len ? temp.data : NULL; 1.855 + destItem->len = temp.len; 1.856 + } 1.857 + else 1.858 + { 1.859 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.860 + rv = SECFailure; 1.861 + } 1.862 + } 1.863 + 1.864 + if (PR_TRUE == pop) 1.865 + { 1.866 + /* we don't want to move ahead, so restore the position */ 1.867 + *src = mark; 1.868 + } 1.869 + return rv; 1.870 +} 1.871 + 1.872 +/* the function below is the public one */ 1.873 + 1.874 +SECStatus SEC_QuickDERDecodeItem(PLArenaPool* arena, void* dest, 1.875 + const SEC_ASN1Template* templateEntry, 1.876 + const SECItem* src) 1.877 +{ 1.878 + SECStatus rv = SECSuccess; 1.879 + SECItem newsrc; 1.880 + 1.881 + if (!arena || !templateEntry || !src) 1.882 + { 1.883 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.884 + rv = SECFailure; 1.885 + } 1.886 + 1.887 + if (SECSuccess == rv) 1.888 + { 1.889 + newsrc = *src; 1.890 + rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE); 1.891 + if (SECSuccess == rv && newsrc.len) 1.892 + { 1.893 + rv = SECFailure; 1.894 + PORT_SetError(SEC_ERROR_EXTRA_INPUT); 1.895 + } 1.896 + } 1.897 + 1.898 + return rv; 1.899 +} 1.900 +