diff options
| author | jsing <> | 2022-05-07 15:50:25 +0000 |
|---|---|---|
| committer | jsing <> | 2022-05-07 15:50:25 +0000 |
| commit | b086dc9248d1d64c7321d1f5c391256424fc867b (patch) | |
| tree | 0652ba1a6643e456040ea8ed43807b83c60eceba /src | |
| parent | 0d00ae34d6e94054857b66fb87afcfa23e4a0095 (diff) | |
| download | openbsd-b086dc9248d1d64c7321d1f5c391256424fc867b.tar.gz openbsd-b086dc9248d1d64c7321d1f5c391256424fc867b.tar.bz2 openbsd-b086dc9248d1d64c7321d1f5c391256424fc867b.zip | |
Split asn1_item_ex_d2i() into three.
Factor out the handling of CHOICE and SEQUENCE into their own functions.
This reduces complexity, reduces indentation and will allow for further
clean up.
ok beck@ tb@
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/asn1/tasn_dec.c | 510 |
1 files changed, 287 insertions, 223 deletions
diff --git a/src/lib/libcrypto/asn1/tasn_dec.c b/src/lib/libcrypto/asn1/tasn_dec.c index 3cc2146e45..f9c5fa81b8 100644 --- a/src/lib/libcrypto/asn1/tasn_dec.c +++ b/src/lib/libcrypto/asn1/tasn_dec.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: tasn_dec.c,v 1.60 2022/05/07 10:13:56 jsing Exp $ */ | 1 | /* $OpenBSD: tasn_dec.c,v 1.61 2022/05/07 15:50:25 jsing Exp $ */ |
| 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
| 3 | * project 2000. | 3 | * project 2000. |
| 4 | */ | 4 | */ |
| @@ -121,38 +121,305 @@ ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, | |||
| 121 | return asn1_template_ex_d2i(pval, in, len, tt, 0, 0); | 121 | return asn1_template_ex_d2i(pval, in, len, tt, 0, 0); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | /* Decode an item, taking care of IMPLICIT tagging, if any. | 124 | static int |
| 125 | * If 'opt' set and tag mismatch return -1 to handle OPTIONAL | 125 | asn1_item_ex_d2i_choice(ASN1_VALUE **pval, const unsigned char **in, long len, |
| 126 | */ | 126 | const ASN1_ITEM *it, int tag, int aclass, char opt, int depth) |
| 127 | { | ||
| 128 | const ASN1_TEMPLATE *tt, *errtt = NULL; | ||
| 129 | const ASN1_AUX *aux = it->funcs; | ||
| 130 | ASN1_aux_cb *asn1_cb = NULL; | ||
| 131 | ASN1_VALUE **pchptr; | ||
| 132 | const unsigned char *p = NULL; | ||
| 133 | int i; | ||
| 134 | int ret = 0; | ||
| 135 | int combine; | ||
| 136 | |||
| 137 | combine = aclass & ASN1_TFLG_COMBINE; | ||
| 138 | aclass &= ~ASN1_TFLG_COMBINE; | ||
| 139 | |||
| 140 | if (it->itype != ASN1_ITYPE_CHOICE) | ||
| 141 | goto err; | ||
| 142 | |||
| 143 | if (aux && aux->asn1_cb) | ||
| 144 | asn1_cb = aux->asn1_cb; | ||
| 145 | |||
| 146 | /* | ||
| 147 | * It never makes sense for CHOICE types to have implicit | ||
| 148 | * tagging, so if tag != -1, then this looks like an error in | ||
| 149 | * the template. | ||
| 150 | */ | ||
| 151 | if (tag != -1) { | ||
| 152 | ASN1error(ASN1_R_BAD_TEMPLATE); | ||
| 153 | goto err; | ||
| 154 | } | ||
| 155 | |||
| 156 | if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) | ||
| 157 | goto auxerr; | ||
| 158 | |||
| 159 | if (*pval) { | ||
| 160 | /* Free up and zero CHOICE value if initialised */ | ||
| 161 | i = asn1_get_choice_selector(pval, it); | ||
| 162 | if ((i >= 0) && (i < it->tcount)) { | ||
| 163 | tt = it->templates + i; | ||
| 164 | pchptr = asn1_get_field_ptr(pval, tt); | ||
| 165 | ASN1_template_free(pchptr, tt); | ||
| 166 | asn1_set_choice_selector(pval, -1, it); | ||
| 167 | } | ||
| 168 | } else if (!ASN1_item_ex_new(pval, it)) { | ||
| 169 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 170 | goto err; | ||
| 171 | } | ||
| 172 | /* CHOICE type, try each possibility in turn */ | ||
| 173 | p = *in; | ||
| 174 | for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { | ||
| 175 | pchptr = asn1_get_field_ptr(pval, tt); | ||
| 176 | /* We mark field as OPTIONAL so its absence | ||
| 177 | * can be recognised. | ||
| 178 | */ | ||
| 179 | ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, | ||
| 180 | depth); | ||
| 181 | /* If field not present, try the next one */ | ||
| 182 | if (ret == -1) | ||
| 183 | continue; | ||
| 184 | /* If positive return, read OK, break loop */ | ||
| 185 | if (ret > 0) | ||
| 186 | break; | ||
| 187 | /* Otherwise must be an ASN1 parsing error */ | ||
| 188 | errtt = tt; | ||
| 189 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 190 | goto err; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* Did we fall off the end without reading anything? */ | ||
| 194 | if (i == it->tcount) { | ||
| 195 | /* If OPTIONAL, this is OK */ | ||
| 196 | if (opt) { | ||
| 197 | /* Free and zero it */ | ||
| 198 | ASN1_item_ex_free(pval, it); | ||
| 199 | return -1; | ||
| 200 | } | ||
| 201 | ASN1error(ASN1_R_NO_MATCHING_CHOICE_TYPE); | ||
| 202 | goto err; | ||
| 203 | } | ||
| 204 | |||
| 205 | asn1_set_choice_selector(pval, i, it); | ||
| 206 | *in = p; | ||
| 207 | if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) | ||
| 208 | goto auxerr; | ||
| 209 | return 1; | ||
| 210 | |||
| 211 | auxerr: | ||
| 212 | ASN1error(ASN1_R_AUX_ERROR); | ||
| 213 | err: | ||
| 214 | if (combine == 0) | ||
| 215 | ASN1_item_ex_free(pval, it); | ||
| 216 | if (errtt) | ||
| 217 | ERR_asprintf_error_data("Field=%s, Type=%s", errtt->field_name, | ||
| 218 | it->sname); | ||
| 219 | else | ||
| 220 | ERR_asprintf_error_data("Type=%s", it->sname); | ||
| 221 | return 0; | ||
| 222 | } | ||
| 127 | 223 | ||
| 128 | static int | 224 | static int |
| 129 | asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, | 225 | asn1_item_ex_d2i_sequence(ASN1_VALUE **pval, const unsigned char **in, long len, |
| 130 | const ASN1_ITEM *it, int tag, int aclass, char opt, int depth) | 226 | const ASN1_ITEM *it, int tag, int aclass, char opt, int depth) |
| 131 | { | 227 | { |
| 132 | const ASN1_TEMPLATE *tt, *errtt = NULL; | 228 | const ASN1_TEMPLATE *tt, *errtt = NULL; |
| 133 | const ASN1_EXTERN_FUNCS *ef; | ||
| 134 | const ASN1_AUX *aux = it->funcs; | 229 | const ASN1_AUX *aux = it->funcs; |
| 135 | ASN1_aux_cb *asn1_cb = NULL; | 230 | ASN1_aux_cb *asn1_cb = NULL; |
| 136 | ASN1_TLC ctx = { 0 }; | ||
| 137 | const unsigned char *p = NULL, *q; | ||
| 138 | unsigned char oclass; | ||
| 139 | char seq_eoc, seq_nolen, cst, isopt; | 231 | char seq_eoc, seq_nolen, cst, isopt; |
| 232 | const unsigned char *p = NULL, *q; | ||
| 140 | long tmplen; | 233 | long tmplen; |
| 141 | int i; | 234 | int i; |
| 142 | int otag; | ||
| 143 | int ret = 0; | 235 | int ret = 0; |
| 144 | ASN1_VALUE **pchptr; | ||
| 145 | int combine; | 236 | int combine; |
| 146 | 237 | ||
| 147 | combine = aclass & ASN1_TFLG_COMBINE; | 238 | combine = aclass & ASN1_TFLG_COMBINE; |
| 148 | aclass &= ~ASN1_TFLG_COMBINE; | 239 | aclass &= ~ASN1_TFLG_COMBINE; |
| 149 | 240 | ||
| 150 | if (!pval) | 241 | if (it->itype != ASN1_ITYPE_NDEF_SEQUENCE && |
| 151 | return 0; | 242 | it->itype != ASN1_ITYPE_SEQUENCE) |
| 243 | goto err; | ||
| 152 | 244 | ||
| 153 | if (aux && aux->asn1_cb) | 245 | if (aux && aux->asn1_cb) |
| 154 | asn1_cb = aux->asn1_cb; | 246 | asn1_cb = aux->asn1_cb; |
| 155 | 247 | ||
| 248 | p = *in; | ||
| 249 | tmplen = len; | ||
| 250 | |||
| 251 | /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ | ||
| 252 | if (tag == -1) { | ||
| 253 | tag = V_ASN1_SEQUENCE; | ||
| 254 | aclass = V_ASN1_UNIVERSAL; | ||
| 255 | } | ||
| 256 | /* Get SEQUENCE length and update len, p */ | ||
| 257 | ret = asn1_check_tag(&len, NULL, NULL, &seq_eoc, &cst, &p, len, | ||
| 258 | tag, aclass, opt); | ||
| 259 | if (!ret) { | ||
| 260 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 261 | goto err; | ||
| 262 | } else if (ret == -1) | ||
| 263 | return -1; | ||
| 264 | if (aux && (aux->flags & ASN1_AFLG_BROKEN)) { | ||
| 265 | len = tmplen - (p - *in); | ||
| 266 | seq_nolen = 1; | ||
| 267 | } | ||
| 268 | /* If indefinite we don't do a length check */ | ||
| 269 | else | ||
| 270 | seq_nolen = seq_eoc; | ||
| 271 | if (!cst) { | ||
| 272 | ASN1error(ASN1_R_SEQUENCE_NOT_CONSTRUCTED); | ||
| 273 | goto err; | ||
| 274 | } | ||
| 275 | |||
| 276 | if (!*pval && !ASN1_item_ex_new(pval, it)) { | ||
| 277 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 278 | goto err; | ||
| 279 | } | ||
| 280 | |||
| 281 | if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) | ||
| 282 | goto auxerr; | ||
| 283 | |||
| 284 | /* Free up and zero any ADB found */ | ||
| 285 | for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { | ||
| 286 | if (tt->flags & ASN1_TFLG_ADB_MASK) { | ||
| 287 | const ASN1_TEMPLATE *seqtt; | ||
| 288 | ASN1_VALUE **pseqval; | ||
| 289 | seqtt = asn1_do_adb(pval, tt, 1); | ||
| 290 | if (!seqtt) | ||
| 291 | goto err; | ||
| 292 | pseqval = asn1_get_field_ptr(pval, seqtt); | ||
| 293 | ASN1_template_free(pseqval, seqtt); | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | /* Get each field entry */ | ||
| 298 | for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { | ||
| 299 | const ASN1_TEMPLATE *seqtt; | ||
| 300 | ASN1_VALUE **pseqval; | ||
| 301 | seqtt = asn1_do_adb(pval, tt, 1); | ||
| 302 | if (!seqtt) | ||
| 303 | goto err; | ||
| 304 | pseqval = asn1_get_field_ptr(pval, seqtt); | ||
| 305 | /* Have we ran out of data? */ | ||
| 306 | if (!len) | ||
| 307 | break; | ||
| 308 | q = p; | ||
| 309 | if (asn1_check_eoc(&p, len)) { | ||
| 310 | if (!seq_eoc) { | ||
| 311 | ASN1error(ASN1_R_UNEXPECTED_EOC); | ||
| 312 | goto err; | ||
| 313 | } | ||
| 314 | len -= p - q; | ||
| 315 | seq_eoc = 0; | ||
| 316 | q = p; | ||
| 317 | break; | ||
| 318 | } | ||
| 319 | /* This determines the OPTIONAL flag value. The field | ||
| 320 | * cannot be omitted if it is the last of a SEQUENCE | ||
| 321 | * and there is still data to be read. This isn't | ||
| 322 | * strictly necessary but it increases efficiency in | ||
| 323 | * some cases. | ||
| 324 | */ | ||
| 325 | if (i == (it->tcount - 1)) | ||
| 326 | isopt = 0; | ||
| 327 | else | ||
| 328 | isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL); | ||
| 329 | /* attempt to read in field, allowing each to be | ||
| 330 | * OPTIONAL */ | ||
| 331 | |||
| 332 | ret = asn1_template_ex_d2i(pseqval, &p, len, | ||
| 333 | seqtt, isopt, depth); | ||
| 334 | if (!ret) { | ||
| 335 | errtt = seqtt; | ||
| 336 | goto err; | ||
| 337 | } else if (ret == -1) { | ||
| 338 | /* OPTIONAL component absent. | ||
| 339 | * Free and zero the field. | ||
| 340 | */ | ||
| 341 | ASN1_template_free(pseqval, seqtt); | ||
| 342 | continue; | ||
| 343 | } | ||
| 344 | /* Update length */ | ||
| 345 | len -= p - q; | ||
| 346 | } | ||
| 347 | |||
| 348 | /* Check for EOC if expecting one */ | ||
| 349 | if (seq_eoc && !asn1_check_eoc(&p, len)) { | ||
| 350 | ASN1error(ASN1_R_MISSING_EOC); | ||
| 351 | goto err; | ||
| 352 | } | ||
| 353 | /* Check all data read */ | ||
| 354 | if (!seq_nolen && len) { | ||
| 355 | ASN1error(ASN1_R_SEQUENCE_LENGTH_MISMATCH); | ||
| 356 | goto err; | ||
| 357 | } | ||
| 358 | |||
| 359 | /* If we get here we've got no more data in the SEQUENCE, | ||
| 360 | * however we may not have read all fields so check all | ||
| 361 | * remaining are OPTIONAL and clear any that are. | ||
| 362 | */ | ||
| 363 | for (; i < it->tcount; tt++, i++) { | ||
| 364 | const ASN1_TEMPLATE *seqtt; | ||
| 365 | seqtt = asn1_do_adb(pval, tt, 1); | ||
| 366 | if (!seqtt) | ||
| 367 | goto err; | ||
| 368 | if (seqtt->flags & ASN1_TFLG_OPTIONAL) { | ||
| 369 | ASN1_VALUE **pseqval; | ||
| 370 | pseqval = asn1_get_field_ptr(pval, seqtt); | ||
| 371 | ASN1_template_free(pseqval, seqtt); | ||
| 372 | } else { | ||
| 373 | errtt = seqtt; | ||
| 374 | ASN1error(ASN1_R_FIELD_MISSING); | ||
| 375 | goto err; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | /* Save encoding */ | ||
| 379 | if (!asn1_enc_save(pval, *in, p - *in, it)) { | ||
| 380 | ASN1error(ERR_R_MALLOC_FAILURE); | ||
| 381 | goto auxerr; | ||
| 382 | } | ||
| 383 | *in = p; | ||
| 384 | if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) | ||
| 385 | goto auxerr; | ||
| 386 | return 1; | ||
| 387 | |||
| 388 | auxerr: | ||
| 389 | ASN1error(ASN1_R_AUX_ERROR); | ||
| 390 | err: | ||
| 391 | if (combine == 0) | ||
| 392 | ASN1_item_ex_free(pval, it); | ||
| 393 | if (errtt) | ||
| 394 | ERR_asprintf_error_data("Field=%s, Type=%s", errtt->field_name, | ||
| 395 | it->sname); | ||
| 396 | else | ||
| 397 | ERR_asprintf_error_data("Type=%s", it->sname); | ||
| 398 | return 0; | ||
| 399 | } | ||
| 400 | |||
| 401 | /* | ||
| 402 | * Decode an item, taking care of IMPLICIT tagging, if any. | ||
| 403 | * If 'opt' set and tag mismatch return -1 to handle OPTIONAL | ||
| 404 | */ | ||
| 405 | static int | ||
| 406 | asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, | ||
| 407 | const ASN1_ITEM *it, int tag, int aclass, char opt, int depth) | ||
| 408 | { | ||
| 409 | const ASN1_EXTERN_FUNCS *ef; | ||
| 410 | ASN1_TLC ctx = { 0 }; | ||
| 411 | const unsigned char *p = NULL; | ||
| 412 | unsigned char oclass; | ||
| 413 | int otag; | ||
| 414 | int ret = 0; | ||
| 415 | int combine; | ||
| 416 | |||
| 417 | combine = aclass & ASN1_TFLG_COMBINE; | ||
| 418 | aclass &= ~ASN1_TFLG_COMBINE; | ||
| 419 | |||
| 420 | if (!pval) | ||
| 421 | return 0; | ||
| 422 | |||
| 156 | if (++depth > ASN1_MAX_CONSTRUCTED_NEST) { | 423 | if (++depth > ASN1_MAX_CONSTRUCTED_NEST) { |
| 157 | ASN1error(ASN1_R_NESTED_TOO_DEEP); | 424 | ASN1error(ASN1_R_NESTED_TOO_DEEP); |
| 158 | goto err; | 425 | goto err; |
| @@ -223,227 +490,24 @@ asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, | |||
| 223 | return ef->asn1_ex_d2i(pval, in, len, it, tag, aclass, opt, &ctx); | 490 | return ef->asn1_ex_d2i(pval, in, len, it, tag, aclass, opt, &ctx); |
| 224 | 491 | ||
| 225 | case ASN1_ITYPE_CHOICE: | 492 | case ASN1_ITYPE_CHOICE: |
| 226 | /* | 493 | return asn1_item_ex_d2i_choice(pval, in, len, it, tag, |
| 227 | * It never makes sense for CHOICE types to have implicit | 494 | aclass | combine, opt, depth); |
| 228 | * tagging, so if tag != -1, then this looks like an error in | ||
| 229 | * the template. | ||
| 230 | */ | ||
| 231 | if (tag != -1) { | ||
| 232 | ASN1error(ASN1_R_BAD_TEMPLATE); | ||
| 233 | goto err; | ||
| 234 | } | ||
| 235 | |||
| 236 | if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) | ||
| 237 | goto auxerr; | ||
| 238 | |||
| 239 | if (*pval) { | ||
| 240 | /* Free up and zero CHOICE value if initialised */ | ||
| 241 | i = asn1_get_choice_selector(pval, it); | ||
| 242 | if ((i >= 0) && (i < it->tcount)) { | ||
| 243 | tt = it->templates + i; | ||
| 244 | pchptr = asn1_get_field_ptr(pval, tt); | ||
| 245 | ASN1_template_free(pchptr, tt); | ||
| 246 | asn1_set_choice_selector(pval, -1, it); | ||
| 247 | } | ||
| 248 | } else if (!ASN1_item_ex_new(pval, it)) { | ||
| 249 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 250 | goto err; | ||
| 251 | } | ||
| 252 | /* CHOICE type, try each possibility in turn */ | ||
| 253 | p = *in; | ||
| 254 | for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { | ||
| 255 | pchptr = asn1_get_field_ptr(pval, tt); | ||
| 256 | /* We mark field as OPTIONAL so its absence | ||
| 257 | * can be recognised. | ||
| 258 | */ | ||
| 259 | ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, | ||
| 260 | depth); | ||
| 261 | /* If field not present, try the next one */ | ||
| 262 | if (ret == -1) | ||
| 263 | continue; | ||
| 264 | /* If positive return, read OK, break loop */ | ||
| 265 | if (ret > 0) | ||
| 266 | break; | ||
| 267 | /* Otherwise must be an ASN1 parsing error */ | ||
| 268 | errtt = tt; | ||
| 269 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 270 | goto err; | ||
| 271 | } | ||
| 272 | |||
| 273 | /* Did we fall off the end without reading anything? */ | ||
| 274 | if (i == it->tcount) { | ||
| 275 | /* If OPTIONAL, this is OK */ | ||
| 276 | if (opt) { | ||
| 277 | /* Free and zero it */ | ||
| 278 | ASN1_item_ex_free(pval, it); | ||
| 279 | return -1; | ||
| 280 | } | ||
| 281 | ASN1error(ASN1_R_NO_MATCHING_CHOICE_TYPE); | ||
| 282 | goto err; | ||
| 283 | } | ||
| 284 | |||
| 285 | asn1_set_choice_selector(pval, i, it); | ||
| 286 | *in = p; | ||
| 287 | if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) | ||
| 288 | goto auxerr; | ||
| 289 | return 1; | ||
| 290 | 495 | ||
| 291 | case ASN1_ITYPE_NDEF_SEQUENCE: | 496 | case ASN1_ITYPE_NDEF_SEQUENCE: |
| 292 | case ASN1_ITYPE_SEQUENCE: | 497 | case ASN1_ITYPE_SEQUENCE: |
| 293 | p = *in; | 498 | return asn1_item_ex_d2i_sequence(pval, in, len, it, tag, |
| 294 | tmplen = len; | 499 | aclass | combine, opt, depth); |
| 295 | |||
| 296 | /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ | ||
| 297 | if (tag == -1) { | ||
| 298 | tag = V_ASN1_SEQUENCE; | ||
| 299 | aclass = V_ASN1_UNIVERSAL; | ||
| 300 | } | ||
| 301 | /* Get SEQUENCE length and update len, p */ | ||
| 302 | ret = asn1_check_tag(&len, NULL, NULL, &seq_eoc, &cst, &p, len, | ||
| 303 | tag, aclass, opt); | ||
| 304 | if (!ret) { | ||
| 305 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 306 | goto err; | ||
| 307 | } else if (ret == -1) | ||
| 308 | return -1; | ||
| 309 | if (aux && (aux->flags & ASN1_AFLG_BROKEN)) { | ||
| 310 | len = tmplen - (p - *in); | ||
| 311 | seq_nolen = 1; | ||
| 312 | } | ||
| 313 | /* If indefinite we don't do a length check */ | ||
| 314 | else | ||
| 315 | seq_nolen = seq_eoc; | ||
| 316 | if (!cst) { | ||
| 317 | ASN1error(ASN1_R_SEQUENCE_NOT_CONSTRUCTED); | ||
| 318 | goto err; | ||
| 319 | } | ||
| 320 | |||
| 321 | if (!*pval && !ASN1_item_ex_new(pval, it)) { | ||
| 322 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 323 | goto err; | ||
| 324 | } | ||
| 325 | |||
| 326 | if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) | ||
| 327 | goto auxerr; | ||
| 328 | |||
| 329 | /* Free up and zero any ADB found */ | ||
| 330 | for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { | ||
| 331 | if (tt->flags & ASN1_TFLG_ADB_MASK) { | ||
| 332 | const ASN1_TEMPLATE *seqtt; | ||
| 333 | ASN1_VALUE **pseqval; | ||
| 334 | seqtt = asn1_do_adb(pval, tt, 1); | ||
| 335 | if (!seqtt) | ||
| 336 | goto err; | ||
| 337 | pseqval = asn1_get_field_ptr(pval, seqtt); | ||
| 338 | ASN1_template_free(pseqval, seqtt); | ||
| 339 | } | ||
| 340 | } | ||
| 341 | |||
| 342 | /* Get each field entry */ | ||
| 343 | for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { | ||
| 344 | const ASN1_TEMPLATE *seqtt; | ||
| 345 | ASN1_VALUE **pseqval; | ||
| 346 | seqtt = asn1_do_adb(pval, tt, 1); | ||
| 347 | if (!seqtt) | ||
| 348 | goto err; | ||
| 349 | pseqval = asn1_get_field_ptr(pval, seqtt); | ||
| 350 | /* Have we ran out of data? */ | ||
| 351 | if (!len) | ||
| 352 | break; | ||
| 353 | q = p; | ||
| 354 | if (asn1_check_eoc(&p, len)) { | ||
| 355 | if (!seq_eoc) { | ||
| 356 | ASN1error(ASN1_R_UNEXPECTED_EOC); | ||
| 357 | goto err; | ||
| 358 | } | ||
| 359 | len -= p - q; | ||
| 360 | seq_eoc = 0; | ||
| 361 | q = p; | ||
| 362 | break; | ||
| 363 | } | ||
| 364 | /* This determines the OPTIONAL flag value. The field | ||
| 365 | * cannot be omitted if it is the last of a SEQUENCE | ||
| 366 | * and there is still data to be read. This isn't | ||
| 367 | * strictly necessary but it increases efficiency in | ||
| 368 | * some cases. | ||
| 369 | */ | ||
| 370 | if (i == (it->tcount - 1)) | ||
| 371 | isopt = 0; | ||
| 372 | else | ||
| 373 | isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL); | ||
| 374 | /* attempt to read in field, allowing each to be | ||
| 375 | * OPTIONAL */ | ||
| 376 | |||
| 377 | ret = asn1_template_ex_d2i(pseqval, &p, len, | ||
| 378 | seqtt, isopt, depth); | ||
| 379 | if (!ret) { | ||
| 380 | errtt = seqtt; | ||
| 381 | goto err; | ||
| 382 | } else if (ret == -1) { | ||
| 383 | /* OPTIONAL component absent. | ||
| 384 | * Free and zero the field. | ||
| 385 | */ | ||
| 386 | ASN1_template_free(pseqval, seqtt); | ||
| 387 | continue; | ||
| 388 | } | ||
| 389 | /* Update length */ | ||
| 390 | len -= p - q; | ||
| 391 | } | ||
| 392 | |||
| 393 | /* Check for EOC if expecting one */ | ||
| 394 | if (seq_eoc && !asn1_check_eoc(&p, len)) { | ||
| 395 | ASN1error(ASN1_R_MISSING_EOC); | ||
| 396 | goto err; | ||
| 397 | } | ||
| 398 | /* Check all data read */ | ||
| 399 | if (!seq_nolen && len) { | ||
| 400 | ASN1error(ASN1_R_SEQUENCE_LENGTH_MISMATCH); | ||
| 401 | goto err; | ||
| 402 | } | ||
| 403 | |||
| 404 | /* If we get here we've got no more data in the SEQUENCE, | ||
| 405 | * however we may not have read all fields so check all | ||
| 406 | * remaining are OPTIONAL and clear any that are. | ||
| 407 | */ | ||
| 408 | for (; i < it->tcount; tt++, i++) { | ||
| 409 | const ASN1_TEMPLATE *seqtt; | ||
| 410 | seqtt = asn1_do_adb(pval, tt, 1); | ||
| 411 | if (!seqtt) | ||
| 412 | goto err; | ||
| 413 | if (seqtt->flags & ASN1_TFLG_OPTIONAL) { | ||
| 414 | ASN1_VALUE **pseqval; | ||
| 415 | pseqval = asn1_get_field_ptr(pval, seqtt); | ||
| 416 | ASN1_template_free(pseqval, seqtt); | ||
| 417 | } else { | ||
| 418 | errtt = seqtt; | ||
| 419 | ASN1error(ASN1_R_FIELD_MISSING); | ||
| 420 | goto err; | ||
| 421 | } | ||
| 422 | } | ||
| 423 | /* Save encoding */ | ||
| 424 | if (!asn1_enc_save(pval, *in, p - *in, it)) { | ||
| 425 | ASN1error(ERR_R_MALLOC_FAILURE); | ||
| 426 | goto auxerr; | ||
| 427 | } | ||
| 428 | *in = p; | ||
| 429 | if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) | ||
| 430 | goto auxerr; | ||
| 431 | return 1; | ||
| 432 | 500 | ||
| 433 | default: | 501 | default: |
| 434 | return 0; | 502 | return 0; |
| 435 | } | 503 | } |
| 436 | 504 | ||
| 437 | auxerr: | ||
| 438 | ASN1error(ASN1_R_AUX_ERROR); | ||
| 439 | err: | 505 | err: |
| 440 | if (combine == 0) | 506 | if (combine == 0) |
| 441 | ASN1_item_ex_free(pval, it); | 507 | ASN1_item_ex_free(pval, it); |
| 442 | if (errtt) | 508 | |
| 443 | ERR_asprintf_error_data("Field=%s, Type=%s", errtt->field_name, | 509 | ERR_asprintf_error_data("Type=%s", it->sname); |
| 444 | it->sname); | 510 | |
| 445 | else | ||
| 446 | ERR_asprintf_error_data("Type=%s", it->sname); | ||
| 447 | return 0; | 511 | return 0; |
| 448 | } | 512 | } |
| 449 | 513 | ||
