diff options
-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: |