diff options
| author | jsing <> | 2022-05-16 20:06:15 +0000 |
|---|---|---|
| committer | jsing <> | 2022-05-16 20:06:15 +0000 |
| commit | 099e71940fb5dfd26306132403ccd056f392028b (patch) | |
| tree | 95f318cdce39ad662a17e93c2e5311a2d519b9ff /src | |
| parent | f648ab881a6fac5b945b1961a4bddceaf78a4af4 (diff) | |
| download | openbsd-099e71940fb5dfd26306132403ccd056f392028b.tar.gz openbsd-099e71940fb5dfd26306132403ccd056f392028b.tar.bz2 openbsd-099e71940fb5dfd26306132403ccd056f392028b.zip | |
Rewrite asn1_item_ex_d2i_sequence() using CBS and readable variable names.
Now that combine no longer exists, we can also free and reallocate.
ok tb@
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/asn1/tasn_dec.c | 244 |
1 files changed, 113 insertions, 131 deletions
diff --git a/src/lib/libcrypto/asn1/tasn_dec.c b/src/lib/libcrypto/asn1/tasn_dec.c index 48ac38a883..744dde23c0 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.67 2022/05/12 20:06:46 jsing Exp $ */ | 1 | /* $OpenBSD: tasn_dec.c,v 1.68 2022/05/16 20:06:15 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 | */ |
| @@ -129,13 +129,13 @@ asn1_item_ex_d2i_choice(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 129 | int tag_number, int tag_class, char optional, int depth) | 129 | int tag_number, int tag_class, char optional, int depth) |
| 130 | { | 130 | { |
| 131 | const ASN1_TEMPLATE *tt, *errtt = NULL; | 131 | const ASN1_TEMPLATE *tt, *errtt = NULL; |
| 132 | const ASN1_AUX *aux = it->funcs; | 132 | const ASN1_AUX *aux; |
| 133 | ASN1_aux_cb *asn1_cb = NULL; | 133 | ASN1_aux_cb *asn1_cb = NULL; |
| 134 | ASN1_VALUE *achoice = NULL; | 134 | ASN1_VALUE *achoice = NULL; |
| 135 | ASN1_VALUE **pchptr; | 135 | ASN1_VALUE **pchptr; |
| 136 | int i, ret; | 136 | int i, ret; |
| 137 | 137 | ||
| 138 | if (aux != NULL) | 138 | if ((aux = it->funcs) != NULL) |
| 139 | asn1_cb = aux->asn1_cb; | 139 | asn1_cb = aux->asn1_cb; |
| 140 | 140 | ||
| 141 | if (it->itype != ASN1_ITYPE_CHOICE) | 141 | if (it->itype != ASN1_ITYPE_CHOICE) |
| @@ -171,11 +171,8 @@ asn1_item_ex_d2i_choice(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 171 | 171 | ||
| 172 | /* Mark field as OPTIONAL so its absence can be identified. */ | 172 | /* Mark field as OPTIONAL so its absence can be identified. */ |
| 173 | ret = asn1_template_ex_d2i_cbs(pchptr, cbs, tt, 1, depth); | 173 | ret = asn1_template_ex_d2i_cbs(pchptr, cbs, tt, 1, depth); |
| 174 | |||
| 175 | /* If field not present, try the next one */ | ||
| 176 | if (ret == -1) | 174 | if (ret == -1) |
| 177 | continue; | 175 | continue; |
| 178 | |||
| 179 | if (ret != 1) { | 176 | if (ret != 1) { |
| 180 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 177 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 181 | errtt = tt; | 178 | errtt = tt; |
| @@ -220,190 +217,175 @@ asn1_item_ex_d2i_choice(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 220 | } | 217 | } |
| 221 | 218 | ||
| 222 | static int | 219 | static int |
| 223 | asn1_item_ex_d2i_sequence(ASN1_VALUE **pval, const unsigned char **in, long len, | 220 | asn1_item_ex_d2i_sequence(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, |
| 224 | const ASN1_ITEM *it, int tag, int aclass, char opt, int depth) | 221 | int tag_number, int tag_class, char optional, int depth) |
| 225 | { | 222 | { |
| 226 | const ASN1_TEMPLATE *tt, *errtt = NULL; | 223 | CBS cbs_seq, cbs_seq_content, cbs_object; |
| 227 | const ASN1_AUX *aux = it->funcs; | 224 | char constructed, indefinite, optional_field; |
| 225 | const ASN1_TEMPLATE *errtt = NULL; | ||
| 226 | const ASN1_TEMPLATE *seqtt, *tt; | ||
| 228 | ASN1_aux_cb *asn1_cb = NULL; | 227 | ASN1_aux_cb *asn1_cb = NULL; |
| 229 | char seq_eoc, seq_nolen, cst, isopt; | 228 | const ASN1_AUX *aux; |
| 230 | const unsigned char *p = NULL, *q; | 229 | ASN1_VALUE *aseq = NULL; |
| 231 | CBS cbs; | 230 | ASN1_VALUE **pseqval; |
| 232 | int i; | 231 | int eoc_needed, i; |
| 232 | size_t length; | ||
| 233 | int ret = 0; | 233 | int ret = 0; |
| 234 | 234 | ||
| 235 | CBS_init(&cbs_seq, CBS_data(cbs), CBS_len(cbs)); | ||
| 236 | |||
| 237 | if ((aux = it->funcs) != NULL) | ||
| 238 | asn1_cb = aux->asn1_cb; | ||
| 239 | |||
| 235 | if (it->itype != ASN1_ITYPE_NDEF_SEQUENCE && | 240 | if (it->itype != ASN1_ITYPE_NDEF_SEQUENCE && |
| 236 | it->itype != ASN1_ITYPE_SEQUENCE) | 241 | it->itype != ASN1_ITYPE_SEQUENCE) |
| 237 | goto err; | 242 | goto err; |
| 238 | 243 | ||
| 239 | if (aux && aux->asn1_cb) | 244 | if (*pval != NULL) { |
| 240 | asn1_cb = aux->asn1_cb; | 245 | ASN1_item_ex_free(pval, it); |
| 241 | 246 | *pval = NULL; | |
| 242 | p = *in; | 247 | } |
| 243 | 248 | ||
| 244 | /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ | 249 | /* If no IMPLICIT tagging use UNIVERSAL/SEQUENCE. */ |
| 245 | if (tag == -1) { | 250 | if (tag_number == -1) { |
| 246 | tag = V_ASN1_SEQUENCE; | 251 | tag_class = V_ASN1_UNIVERSAL; |
| 247 | aclass = V_ASN1_UNIVERSAL; | 252 | tag_number = V_ASN1_SEQUENCE; |
| 248 | } | 253 | } |
| 249 | /* Get SEQUENCE length and update len, p */ | 254 | |
| 250 | ret = asn1_check_tag(&len, NULL, NULL, &seq_eoc, &cst, &p, len, | 255 | /* Read ASN.1 SEQUENCE header. */ |
| 251 | tag, aclass, opt); | 256 | ret = asn1_check_tag_cbs(&cbs_seq, &length, NULL, NULL, &indefinite, |
| 252 | if (!ret) { | 257 | &constructed, tag_number, tag_class, optional); |
| 258 | if (ret == -1) | ||
| 259 | return -1; | ||
| 260 | if (ret != 1) { | ||
| 253 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 261 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 254 | goto err; | 262 | goto err; |
| 255 | } else if (ret == -1) | 263 | } |
| 256 | return -1; | 264 | |
| 257 | seq_nolen = seq_eoc; | 265 | if (!constructed) { |
| 258 | if (!cst) { | ||
| 259 | ASN1error(ASN1_R_SEQUENCE_NOT_CONSTRUCTED); | 266 | ASN1error(ASN1_R_SEQUENCE_NOT_CONSTRUCTED); |
| 260 | goto err; | 267 | goto err; |
| 261 | } | 268 | } |
| 262 | 269 | ||
| 263 | if (!*pval && !ASN1_item_ex_new(pval, it)) { | 270 | if (indefinite) { |
| 271 | eoc_needed = 1; | ||
| 272 | CBS_init(&cbs_seq_content, CBS_data(&cbs_seq), CBS_len(&cbs_seq)); | ||
| 273 | } else { | ||
| 274 | eoc_needed = 0; | ||
| 275 | if (!CBS_get_bytes(&cbs_seq, &cbs_seq_content, length)) | ||
| 276 | goto err; | ||
| 277 | } | ||
| 278 | |||
| 279 | if (!ASN1_item_ex_new(&aseq, it)) { | ||
| 264 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 280 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 265 | goto err; | 281 | goto err; |
| 266 | } | 282 | } |
| 267 | 283 | ||
| 268 | if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) | 284 | if (asn1_cb != NULL && !asn1_cb(ASN1_OP_D2I_PRE, &aseq, it, NULL)) { |
| 269 | goto auxerr; | 285 | ASN1error(ASN1_R_AUX_ERROR); |
| 270 | 286 | goto err; | |
| 271 | /* Free up and zero any ADB found */ | ||
| 272 | for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { | ||
| 273 | if (tt->flags & ASN1_TFLG_ADB_MASK) { | ||
| 274 | const ASN1_TEMPLATE *seqtt; | ||
| 275 | ASN1_VALUE **pseqval; | ||
| 276 | seqtt = asn1_do_adb(pval, tt, 1); | ||
| 277 | if (!seqtt) | ||
| 278 | goto err; | ||
| 279 | pseqval = asn1_get_field_ptr(pval, seqtt); | ||
| 280 | ASN1_template_free(pseqval, seqtt); | ||
| 281 | } | ||
| 282 | } | 287 | } |
| 283 | 288 | ||
| 284 | /* Get each field entry */ | ||
| 285 | for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { | 289 | for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { |
| 286 | const ASN1_TEMPLATE *seqtt; | 290 | if (asn1_check_eoc_cbs(&cbs_seq_content)) { |
| 287 | ASN1_VALUE **pseqval; | 291 | if (!indefinite) { |
| 288 | seqtt = asn1_do_adb(pval, tt, 1); | ||
| 289 | if (!seqtt) | ||
| 290 | goto err; | ||
| 291 | pseqval = asn1_get_field_ptr(pval, seqtt); | ||
| 292 | /* Have we ran out of data? */ | ||
| 293 | if (!len) | ||
| 294 | break; | ||
| 295 | q = p; | ||
| 296 | if (asn1_check_eoc(&p, len)) { | ||
| 297 | if (!seq_eoc) { | ||
| 298 | ASN1error(ASN1_R_UNEXPECTED_EOC); | 292 | ASN1error(ASN1_R_UNEXPECTED_EOC); |
| 299 | goto err; | 293 | goto err; |
| 300 | } | 294 | } |
| 301 | len -= p - q; | 295 | eoc_needed = 0; |
| 302 | seq_eoc = 0; | ||
| 303 | q = p; | ||
| 304 | break; | 296 | break; |
| 305 | } | 297 | } |
| 306 | /* This determines the OPTIONAL flag value. The field | 298 | if (CBS_len(&cbs_seq_content) == 0) |
| 307 | * cannot be omitted if it is the last of a SEQUENCE | 299 | break; |
| 308 | * and there is still data to be read. This isn't | 300 | |
| 309 | * strictly necessary but it increases efficiency in | 301 | if ((seqtt = asn1_do_adb(&aseq, tt, 1)) == NULL) |
| 310 | * some cases. | ||
| 311 | */ | ||
| 312 | if (i == (it->tcount - 1)) | ||
| 313 | isopt = 0; | ||
| 314 | else | ||
| 315 | isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL); | ||
| 316 | /* attempt to read in field, allowing each to be | ||
| 317 | * OPTIONAL */ | ||
| 318 | |||
| 319 | ret = asn1_template_ex_d2i(pseqval, &p, len, | ||
| 320 | seqtt, isopt, depth); | ||
| 321 | if (!ret) { | ||
| 322 | errtt = seqtt; | ||
| 323 | goto err; | 302 | goto err; |
| 324 | } else if (ret == -1) { | 303 | |
| 325 | /* OPTIONAL component absent. | 304 | pseqval = asn1_get_field_ptr(&aseq, seqtt); |
| 326 | * Free and zero the field. | 305 | |
| 327 | */ | 306 | /* |
| 307 | * This was originally implemented to "increase efficiency", | ||
| 308 | * however it currently needs to remain since it papers over | ||
| 309 | * the use of ASN.1 ANY with OPTIONAL in SEQUENCEs (which | ||
| 310 | * asn1_d2i_ex_primitive() currently rejects). | ||
| 311 | */ | ||
| 312 | optional_field = (seqtt->flags & ASN1_TFLG_OPTIONAL) != 0; | ||
| 313 | if (i == it->tcount - 1) | ||
| 314 | optional_field = 0; | ||
| 315 | |||
| 316 | ret = asn1_template_ex_d2i_cbs(pseqval, &cbs_seq_content, | ||
| 317 | seqtt, optional_field, depth); | ||
| 318 | if (ret == -1) { | ||
| 319 | /* Absent OPTIONAL component. */ | ||
| 328 | ASN1_template_free(pseqval, seqtt); | 320 | ASN1_template_free(pseqval, seqtt); |
| 329 | continue; | 321 | continue; |
| 330 | } | 322 | } |
| 331 | /* Update length */ | 323 | if (ret != 1) { |
| 332 | len -= p - q; | 324 | errtt = seqtt; |
| 325 | goto err; | ||
| 326 | } | ||
| 333 | } | 327 | } |
| 334 | 328 | ||
| 335 | /* Check for EOC if expecting one */ | 329 | if (eoc_needed && !asn1_check_eoc_cbs(&cbs_seq_content)) { |
| 336 | if (seq_eoc && !asn1_check_eoc(&p, len)) { | ||
| 337 | ASN1error(ASN1_R_MISSING_EOC); | 330 | ASN1error(ASN1_R_MISSING_EOC); |
| 338 | goto err; | 331 | goto err; |
| 339 | } | 332 | } |
| 340 | /* Check all data read */ | 333 | |
| 341 | if (!seq_nolen && len) { | 334 | if (indefinite) { |
| 335 | if (!CBS_skip(&cbs_seq, CBS_offset(&cbs_seq_content))) | ||
| 336 | goto err; | ||
| 337 | } else if (CBS_len(&cbs_seq_content) != 0) { | ||
| 342 | ASN1error(ASN1_R_SEQUENCE_LENGTH_MISMATCH); | 338 | ASN1error(ASN1_R_SEQUENCE_LENGTH_MISMATCH); |
| 343 | goto err; | 339 | goto err; |
| 344 | } | 340 | } |
| 345 | 341 | ||
| 346 | /* If we get here we've got no more data in the SEQUENCE, | 342 | /* |
| 347 | * however we may not have read all fields so check all | 343 | * There is no more data in the ASN.1 SEQUENCE, however we may not have |
| 348 | * remaining are OPTIONAL and clear any that are. | 344 | * populated all fields - check that any remaining are OPTIONAL. |
| 349 | */ | 345 | */ |
| 350 | for (; i < it->tcount; tt++, i++) { | 346 | for (; i < it->tcount; tt++, i++) { |
| 351 | const ASN1_TEMPLATE *seqtt; | 347 | if ((seqtt = asn1_do_adb(&aseq, tt, 1)) == NULL) |
| 352 | seqtt = asn1_do_adb(pval, tt, 1); | ||
| 353 | if (!seqtt) | ||
| 354 | goto err; | 348 | goto err; |
| 355 | if (seqtt->flags & ASN1_TFLG_OPTIONAL) { | 349 | |
| 356 | ASN1_VALUE **pseqval; | 350 | if ((seqtt->flags & ASN1_TFLG_OPTIONAL) == 0) { |
| 357 | pseqval = asn1_get_field_ptr(pval, seqtt); | ||
| 358 | ASN1_template_free(pseqval, seqtt); | ||
| 359 | } else { | ||
| 360 | errtt = seqtt; | ||
| 361 | ASN1error(ASN1_R_FIELD_MISSING); | 351 | ASN1error(ASN1_R_FIELD_MISSING); |
| 352 | errtt = seqtt; | ||
| 362 | goto err; | 353 | goto err; |
| 363 | } | 354 | } |
| 355 | |||
| 356 | /* XXX - this is probably unnecessary with earlier free. */ | ||
| 357 | pseqval = asn1_get_field_ptr(&aseq, seqtt); | ||
| 358 | ASN1_template_free(pseqval, seqtt); | ||
| 364 | } | 359 | } |
| 365 | /* Save encoding */ | 360 | |
| 366 | CBS_init(&cbs, *in, p - *in); | 361 | if (!CBS_get_bytes(cbs, &cbs_object, CBS_offset(&cbs_seq))) |
| 367 | if (!asn1_enc_save(pval, &cbs, it)) { | 362 | goto err; |
| 363 | |||
| 364 | if (!asn1_enc_save(&aseq, &cbs_object, it)) { | ||
| 368 | ASN1error(ERR_R_MALLOC_FAILURE); | 365 | ASN1error(ERR_R_MALLOC_FAILURE); |
| 369 | goto err; | 366 | goto err; |
| 370 | } | 367 | } |
| 371 | *in = p; | 368 | |
| 372 | if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) | 369 | if (asn1_cb != NULL && !asn1_cb(ASN1_OP_D2I_POST, &aseq, it, NULL)) { |
| 373 | goto auxerr; | 370 | ASN1error(ASN1_R_AUX_ERROR); |
| 371 | goto err; | ||
| 372 | } | ||
| 373 | |||
| 374 | *pval = aseq; | ||
| 375 | aseq = NULL; | ||
| 376 | |||
| 374 | return 1; | 377 | return 1; |
| 375 | 378 | ||
| 376 | auxerr: | ||
| 377 | ASN1error(ASN1_R_AUX_ERROR); | ||
| 378 | err: | 379 | err: |
| 379 | ASN1_item_ex_free(pval, it); | 380 | ASN1_item_ex_free(&aseq, it); |
| 380 | 381 | ||
| 381 | if (errtt) | 382 | if (errtt != NULL) |
| 382 | ERR_asprintf_error_data("Field=%s, Type=%s", errtt->field_name, | 383 | ERR_asprintf_error_data("Field=%s, Type=%s", errtt->field_name, |
| 383 | it->sname); | 384 | it->sname); |
| 384 | else | 385 | else |
| 385 | ERR_asprintf_error_data("Type=%s", it->sname); | 386 | ERR_asprintf_error_data("Type=%s", it->sname); |
| 386 | return 0; | ||
| 387 | } | ||
| 388 | 387 | ||
| 389 | static int | 388 | return 0; |
| 390 | asn1_item_ex_d2i_sequence_cbs(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | ||
| 391 | int tag_number, int tag_class, char optional, int depth) | ||
| 392 | { | ||
| 393 | const unsigned char *p; | ||
| 394 | int ret; | ||
| 395 | |||
| 396 | if (CBS_len(cbs) > LONG_MAX) | ||
| 397 | return 0; | ||
| 398 | |||
| 399 | p = CBS_data(cbs); | ||
| 400 | ret = asn1_item_ex_d2i_sequence(pval, &p, (long)CBS_len(cbs), it, | ||
| 401 | tag_number, tag_class, optional, depth); | ||
| 402 | if (ret == 1) { | ||
| 403 | if (!CBS_skip(cbs, p - CBS_data(cbs))) | ||
| 404 | return 0; | ||
| 405 | } | ||
| 406 | return ret; | ||
| 407 | } | 389 | } |
| 408 | 390 | ||
| 409 | /* | 391 | /* |
| @@ -502,7 +484,7 @@ asn1_item_ex_d2i_cbs(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 502 | 484 | ||
| 503 | case ASN1_ITYPE_NDEF_SEQUENCE: | 485 | case ASN1_ITYPE_NDEF_SEQUENCE: |
| 504 | case ASN1_ITYPE_SEQUENCE: | 486 | case ASN1_ITYPE_SEQUENCE: |
| 505 | return asn1_item_ex_d2i_sequence_cbs(pval, cbs, it, tag_number, | 487 | return asn1_item_ex_d2i_sequence(pval, cbs, it, tag_number, |
| 506 | tag_class, optional, depth); | 488 | tag_class, optional, depth); |
| 507 | 489 | ||
| 508 | default: | 490 | default: |
