summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbeck <>2023-04-28 08:15:11 +0000
committerbeck <>2023-04-28 08:15:11 +0000
commitb1facd30ebc9043df21c1ebc4d94040bbe9a86f4 (patch)
tree26fa582e1189f96ab469d403d9993d591c4d0c08 /src
parent74349f45383b238069c51062b033d10e40dc5a19 (diff)
downloadopenbsd-b1facd30ebc9043df21c1ebc4d94040bbe9a86f4.tar.gz
openbsd-b1facd30ebc9043df21c1ebc4d94040bbe9a86f4.tar.bz2
openbsd-b1facd30ebc9043df21c1ebc4d94040bbe9a86f4.zip
Add the rest of the boringssl policy unit tests.
We currently still fail two of these, looks like one more bug in extracting the depth for require policy from the certificate..
Diffstat (limited to 'src')
-rw-r--r--src/regress/lib/libcrypto/x509/policy/policy.c227
1 files changed, 223 insertions, 4 deletions
diff --git a/src/regress/lib/libcrypto/x509/policy/policy.c b/src/regress/lib/libcrypto/x509/policy/policy.c
index 593f43bed1..f5f2d42ddd 100644
--- a/src/regress/lib/libcrypto/x509/policy/policy.c
+++ b/src/regress/lib/libcrypto/x509/policy/policy.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: policy.c,v 1.2 2023/04/27 13:26:57 beck Exp $ */ 1/* $OpenBSD: policy.c,v 1.3 2023/04/28 08:15:11 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2020 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2020 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2020-2021 Bob Beck <beck@openbsd.org> 4 * Copyright (c) 2020-2021 Bob Beck <beck@openbsd.org>
@@ -119,7 +119,8 @@ verify_cert_cb(int ok, X509_STORE_CTX *xsc)
119static void 119static void
120verify_cert(const char *roots_file, const char *intermediate_file, 120verify_cert(const char *roots_file, const char *intermediate_file,
121 const char *leaf_file, int *chains, int *error, int *error_depth, 121 const char *leaf_file, int *chains, int *error, int *error_depth,
122 int mode, ASN1_OBJECT *policy_oid, ASN1_OBJECT *policy_oid2) 122 int mode, ASN1_OBJECT *policy_oid, ASN1_OBJECT *policy_oid2,
123 int verify_flags)
123{ 124{
124 STACK_OF(X509) *roots = NULL, *bundle = NULL; 125 STACK_OF(X509) *roots = NULL, *bundle = NULL;
125 X509_STORE_CTX *xsc = NULL; 126 X509_STORE_CTX *xsc = NULL;
@@ -153,7 +154,7 @@ verify_cert(const char *roots_file, const char *intermediate_file,
153 } 154 }
154 155
155 int flags = X509_V_FLAG_POLICY_CHECK; 156 int flags = X509_V_FLAG_POLICY_CHECK;
156 flags |= X509_V_FLAG_EXPLICIT_POLICY; 157 flags |= verify_flags;
157 // flags |= X509_V_FLAG_INHIBIT_MAP; 158 // flags |= X509_V_FLAG_INHIBIT_MAP;
158 if (mode == MODE_LEGACY_VFY) 159 if (mode == MODE_LEGACY_VFY)
159 flags |= X509_V_FLAG_LEGACY_VERIFY; 160 flags |= X509_V_FLAG_LEGACY_VERIFY;
@@ -277,9 +278,11 @@ struct verify_cert_test {
277 int want_legacy_error; 278 int want_legacy_error;
278 int want_legacy_error_depth; 279 int want_legacy_error_depth;
279 int failing; 280 int failing;
281 int verify_flags;
280}; 282};
281 283
282struct verify_cert_test verify_cert_tests[] = { 284struct verify_cert_test verify_cert_tests[] = {
285 // Comments here are from boringssl/crypto/x509/x509_test.cc
283 // The chain is good for |oid1| and |oid2|, but not |oid3|. 286 // The chain is good for |oid1| and |oid2|, but not |oid3|.
284 { 287 {
285 .id = "nothing in 1 and 2", 288 .id = "nothing in 1 and 2",
@@ -287,6 +290,7 @@ struct verify_cert_test verify_cert_tests[] = {
287 .intermediate_file = CERTSDIR "/" "policy_intermediate.pem", 290 .intermediate_file = CERTSDIR "/" "policy_intermediate.pem",
288 .leaf_file = CERTSDIR "/" "policy_leaf.pem", 291 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
289 .want_chains = 1, 292 .want_chains = 1,
293 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
290 }, 294 },
291 { 295 {
292 .id = "1, in 1 and 2", 296 .id = "1, in 1 and 2",
@@ -295,6 +299,7 @@ struct verify_cert_test verify_cert_tests[] = {
295 .leaf_file = CERTSDIR "/" "policy_leaf.pem", 299 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
296 .policy_oid_to_check = OID1, 300 .policy_oid_to_check = OID1,
297 .want_chains = 1, 301 .want_chains = 1,
302 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
298 }, 303 },
299 { 304 {
300 .id = "2, in 1 and 2", 305 .id = "2, in 1 and 2",
@@ -303,6 +308,7 @@ struct verify_cert_test verify_cert_tests[] = {
303 .leaf_file = CERTSDIR "/" "policy_leaf.pem", 308 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
304 .policy_oid_to_check = OID2, 309 .policy_oid_to_check = OID2,
305 .want_chains = 1, 310 .want_chains = 1,
311 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
306 }, 312 },
307 { 313 {
308 .id = "3, in 1 and 2", 314 .id = "3, in 1 and 2",
@@ -311,6 +317,7 @@ struct verify_cert_test verify_cert_tests[] = {
311 .leaf_file = CERTSDIR "/" "policy_leaf.pem", 317 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
312 .policy_oid_to_check = OID3, 318 .policy_oid_to_check = OID3,
313 .want_chains = 0, 319 .want_chains = 0,
320 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
314 .want_error = X509_V_ERR_NO_EXPLICIT_POLICY, 321 .want_error = X509_V_ERR_NO_EXPLICIT_POLICY,
315 .want_error_depth = 0, 322 .want_error_depth = 0,
316 .want_legacy_error = X509_V_ERR_NO_EXPLICIT_POLICY, 323 .want_legacy_error = X509_V_ERR_NO_EXPLICIT_POLICY,
@@ -324,6 +331,7 @@ struct verify_cert_test verify_cert_tests[] = {
324 .policy_oid_to_check = OID1, 331 .policy_oid_to_check = OID1,
325 .policy_oid_to_check2 = OID2, 332 .policy_oid_to_check2 = OID2,
326 .want_chains = 1, 333 .want_chains = 1,
334 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
327 }, 335 },
328 { 336 {
329 .id = "1 and 3, in 1 and 2", 337 .id = "1 and 3, in 1 and 2",
@@ -342,6 +350,7 @@ struct verify_cert_test verify_cert_tests[] = {
342 .leaf_file = CERTSDIR "/" "policy_leaf.pem", 350 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
343 .policy_oid_to_check = OID1, 351 .policy_oid_to_check = OID1,
344 .want_chains = 0, 352 .want_chains = 0,
353 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
345 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION, 354 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
346 .want_error_depth = 0, 355 .want_error_depth = 0,
347 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION, 356 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
@@ -353,6 +362,7 @@ struct verify_cert_test verify_cert_tests[] = {
353 .intermediate_file = CERTSDIR "/" "policy_intermediate_invalid.pem", 362 .intermediate_file = CERTSDIR "/" "policy_intermediate_invalid.pem",
354 .leaf_file = CERTSDIR "/" "policy_leaf.pem", 363 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
355 .want_chains = 0, 364 .want_chains = 0,
365 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
356 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION, 366 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
357 .want_error_depth = 0, 367 .want_error_depth = 0,
358 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION, 368 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
@@ -365,6 +375,7 @@ struct verify_cert_test verify_cert_tests[] = {
365 .leaf_file = CERTSDIR "/" "policy_leaf_invalid.pem", 375 .leaf_file = CERTSDIR "/" "policy_leaf_invalid.pem",
366 .policy_oid_to_check = OID1, 376 .policy_oid_to_check = OID1,
367 .want_chains = 0, 377 .want_chains = 0,
378 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
368 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION, 379 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
369 .want_error_depth = 0, 380 .want_error_depth = 0,
370 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION, 381 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
@@ -376,6 +387,7 @@ struct verify_cert_test verify_cert_tests[] = {
376 .intermediate_file = CERTSDIR "/" "policy_intermediate.pem", 387 .intermediate_file = CERTSDIR "/" "policy_intermediate.pem",
377 .leaf_file = CERTSDIR "/" "policy_leaf_invalid.pem", 388 .leaf_file = CERTSDIR "/" "policy_leaf_invalid.pem",
378 .want_chains = 0, 389 .want_chains = 0,
390 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
379 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION, 391 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
380 .want_error_depth = 0, 392 .want_error_depth = 0,
381 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION, 393 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
@@ -389,6 +401,7 @@ struct verify_cert_test verify_cert_tests[] = {
389 .leaf_file = CERTSDIR "/" "policy_leaf_duplicate.pem", 401 .leaf_file = CERTSDIR "/" "policy_leaf_duplicate.pem",
390 .policy_oid_to_check = OID1, 402 .policy_oid_to_check = OID1,
391 .want_chains = 0, 403 .want_chains = 0,
404 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
392 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION, 405 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
393 .want_error_depth = 0, 406 .want_error_depth = 0,
394 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION, 407 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
@@ -402,11 +415,217 @@ struct verify_cert_test verify_cert_tests[] = {
402 .leaf_file = CERTSDIR "/" "policy_leaf.pem", 415 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
403 .policy_oid_to_check = OID1, 416 .policy_oid_to_check = OID1,
404 .want_chains = 0, 417 .want_chains = 0,
418 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
405 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION, 419 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
406 .want_error_depth = 0, 420 .want_error_depth = 0,
407 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION, 421 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
408 .want_legacy_error_depth = 0, 422 .want_legacy_error_depth = 0,
409 }, 423 },
424 // Without |X509_V_FLAG_EXPLICIT_POLICY|, the policy tree is built and
425 // intersected with user-specified policies, but it is not required to result
426 // in any valid policies.
427 {
428 .id = "nothing with explicit_policy unset",
429 .root_file = CERTSDIR "/" "policy_root.pem",
430 .intermediate_file = CERTSDIR "/" "policy_intermediate.pem",
431 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
432 .want_chains = 1,
433 },
434 {
435 .id = "oid3 with explicit_policy unset",
436 .root_file = CERTSDIR "/" "policy_root.pem",
437 .intermediate_file = CERTSDIR "/" "policy_intermediate.pem",
438 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
439 .policy_oid_to_check = OID3,
440 .want_chains = 1,
441 },
442 // However, a CA with policy constraints can require an explicit policy.
443 {
444 .id = "oid1 with explicit_policy unset, intermediate requiring policy",
445 .root_file = CERTSDIR "/" "policy_root.pem",
446 .intermediate_file = CERTSDIR "/" "policy_intermediate_require.pem",
447 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
448 .policy_oid_to_check = OID1,
449 .want_chains = 1,
450 },
451 {
452 .id = "oid3 with explicit_policy unset, intermediate requiring policy",
453 .root_file = CERTSDIR "/" "policy_root.pem",
454 .intermediate_file = CERTSDIR "/" "policy_intermediate_require.pem",
455 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
456 .policy_oid_to_check = OID3,
457 .want_chains = 0,
458 .want_error = X509_V_ERR_NO_EXPLICIT_POLICY,
459 .want_error_depth = 0,
460 .want_legacy_error = X509_V_ERR_NO_EXPLICIT_POLICY,
461 .want_legacy_error_depth = 0,
462 },
463 // requireExplicitPolicy applies even if the application does not configure a
464 // user-initial-policy-set. If the validation results in no policies, the
465 // chain is invalid.
466 {
467 .id = "nothing explict_policy unset, with intermediate requiring policy",
468 .root_file = CERTSDIR "/" "policy_root.pem",
469 .intermediate_file = CERTSDIR "/" "policy_intermediate_require.pem",
470 .leaf_file = CERTSDIR "/" "policy_leaf_none.pem",
471 .want_chains = 0,
472 .want_error = X509_V_ERR_NO_EXPLICIT_POLICY,
473 .want_error_depth = 0,
474 .want_legacy_error = X509_V_ERR_NO_EXPLICIT_POLICY,
475 .want_legacy_error_depth = 0,
476 },
477 // A leaf can also set requireExplicitPolicy but should work with none
478 {
479 .id = "nothing explicit_policy unset, with leaf requiring policy",
480 .root_file = CERTSDIR "/" "policy_root.pem",
481 .intermediate_file = CERTSDIR "/" "policy_intermediate.pem",
482 .leaf_file = CERTSDIR "/" "policy_leaf_require.pem",
483 .want_chains = 1,
484 },
485 // A leaf can also set requireExplicitPolicy but should fail with policy
486 {
487 .id = "oid3, explicit policy unset, with leaf requiring policy",
488 .root_file = CERTSDIR "/" "policy_root.pem",
489 .intermediate_file = CERTSDIR "/" "policy_intermediate.pem",
490 .leaf_file = CERTSDIR "/" "policy_leaf_require.pem",
491 .policy_oid_to_check = OID3,
492 .want_chains = 0,
493 .want_error = X509_V_ERR_NO_EXPLICIT_POLICY,
494 .want_error_depth = 0,
495 .want_legacy_error = X509_V_ERR_NO_EXPLICIT_POLICY,
496 .want_legacy_error_depth = 0,
497 },
498 // requireExplicitPolicy is a count of certificates to skip. If the value is
499 // not zero by the end of the chain, it doesn't count.
500 {
501 .id = "oid3, with intermediate requiring explicit depth 1",
502 .root_file = CERTSDIR "/" "policy_root.pem",
503 .intermediate_file = CERTSDIR "/" "policy_intermediate_require1.pem",
504 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
505 .policy_oid_to_check = OID3,
506 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
507 .want_chains = 0,
508 .want_error = X509_V_ERR_NO_EXPLICIT_POLICY,
509 .want_error_depth = 0,
510 .want_legacy_error = X509_V_ERR_NO_EXPLICIT_POLICY,
511 .want_legacy_error_depth = 0,
512 },
513 {
514 .id = "oid3, with intermediate requiring explicit depth 2",
515 .root_file = CERTSDIR "/" "policy_root.pem",
516 .intermediate_file = CERTSDIR "/" "policy_intermediate_require2.pem",
517 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
518 .policy_oid_to_check = OID3,
519 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
520 .want_chains = 1,
521 },
522 {
523 .id = "oid3, with leaf requiring explicit depth 1",
524 .root_file = CERTSDIR "/" "policy_root.pem",
525 .intermediate_file = CERTSDIR "/" "policy_intermediate.pem",
526 .leaf_file = CERTSDIR "/" "policy_leaf_require1.pem",
527 .policy_oid_to_check = OID3,
528 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
529 .want_chains = 1,
530 },
531 // If multiple certificates specify the constraint, the more constrained value
532 // wins.
533 {
534 .id = "oid3, with leaf and intermediate requiring explicit depth 1",
535 .root_file = CERTSDIR "/" "policy_root.pem",
536 .intermediate_file = CERTSDIR "/" "policy_intermediate_require1.pem",
537 .leaf_file = CERTSDIR "/" "policy_leaf_require1.pem",
538 .policy_oid_to_check = OID3,
539 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
540 .want_chains = 0,
541 .want_error = X509_V_ERR_NO_EXPLICIT_POLICY,
542 .want_error_depth = 0,
543 .want_legacy_error = X509_V_ERR_NO_EXPLICIT_POLICY,
544 .want_legacy_error_depth = 0,
545 },
546 {
547 .id = "oid3, with leaf requiring explicit depth 1 and intermediate depth 2",
548 .root_file = CERTSDIR "/" "policy_root.pem",
549 .intermediate_file = CERTSDIR "/" "policy_intermediate_require2.pem",
550 .leaf_file = CERTSDIR "/" "policy_leaf_require.pem",
551 .policy_oid_to_check = OID3,
552 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
553 .want_chains = 0,
554 .want_error = X509_V_ERR_NO_EXPLICIT_POLICY,
555 .want_error_depth = 0,
556 .want_legacy_error = X509_V_ERR_NO_EXPLICIT_POLICY,
557 .want_legacy_error_depth = 0,
558 },
559 // An intermediate that requires an explicit policy, but then specifies no
560 // policies should fail verification as a result.
561 {
562 .id = "oid1 with explicit_policy unset, intermediate requiring policy but specifying none",
563 .root_file = CERTSDIR "/" "policy_root.pem",
564 .intermediate_file = CERTSDIR "/" "policy_intermediate_require_no_policies.pem",
565 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
566 .policy_oid_to_check = OID3,
567 .want_chains = 0,
568 .want_error = X509_V_ERR_NO_EXPLICIT_POLICY,
569 .want_error_depth = 0,
570 .want_legacy_error = X509_V_ERR_NO_EXPLICIT_POLICY,
571 .want_legacy_error_depth = 0,
572 },
573 // A constrained intermediate's policy extension has a duplicate policy, which
574 // is invalid. Historically this, and the above case, leaked memory.
575 {
576 .id = "oid1 with explicit_policy unset, intermediate requiring policy but has duplicate",
577 .root_file = CERTSDIR "/" "policy_root.pem",
578 .intermediate_file = CERTSDIR "/" "policy_intermediate_require_duplicate.pem",
579 .leaf_file = CERTSDIR "/" "policy_leaf.pem",
580 .policy_oid_to_check = OID3,
581 .want_chains = 0,
582 .want_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
583 .want_error_depth = 0,
584 .want_legacy_error = X509_V_ERR_INVALID_POLICY_EXTENSION,
585 .want_legacy_error_depth = 0,
586 },
587 // The leaf asserts anyPolicy, but the intermediate does not. The resulting
588 // valid policies are the intersection.
589 // (and vice versa)
590 {
591 .id = "oid1, with explicit_policy set, with leaf asserting any",
592 .root_file = CERTSDIR "/" "policy_root.pem",
593 .intermediate_file = CERTSDIR "/" "policy_intermediate.pem",
594 .leaf_file = CERTSDIR "/" "policy_leaf_any.pem",
595 .policy_oid_to_check = OID1,
596 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
597 .want_chains = 1,
598 },
599 {
600 .id = "oid3, with explicit_policy set, with leaf asserting any",
601 .root_file = CERTSDIR "/" "policy_root.pem",
602 .intermediate_file = CERTSDIR "/" "policy_intermediate.pem",
603 .leaf_file = CERTSDIR "/" "policy_leaf_any.pem",
604 .policy_oid_to_check = OID1,
605 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
606 .want_chains = 1,
607 },
608 // Both assert anyPolicy. All policies are valid.
609 {
610 .id = "oid1, with explicit_policy set, with leaf and intermediate asserting any",
611 .root_file = CERTSDIR "/" "policy_root.pem",
612 .intermediate_file = CERTSDIR "/" "policy_intermediate_any.pem",
613 .leaf_file = CERTSDIR "/" "policy_leaf_any.pem",
614 .policy_oid_to_check = OID1,
615 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
616 .want_chains = 1,
617 },
618 {
619 .id = "oid3, with explicit_policy set, with leaf and intermediate asserting any",
620 .root_file = CERTSDIR "/" "policy_root.pem",
621 .intermediate_file = CERTSDIR "/" "policy_intermediate_any.pem",
622 .leaf_file = CERTSDIR "/" "policy_leaf_any.pem",
623 .policy_oid_to_check = OID1,
624 .verify_flags = X509_V_FLAG_EXPLICIT_POLICY,
625 .want_chains = 1,
626 },
627 // boring tests just a trust anchor but behaves differently in this corner case.
628 // for reasons that have nothing to do wiht policy
410}; 629};
411 630
412#define N_VERIFY_CERT_TESTS \ 631#define N_VERIFY_CERT_TESTS \
@@ -437,7 +656,7 @@ verify_cert_test(int mode)
437 else 656 else
438 verify_cert(vct->root_file, vct->intermediate_file, 657 verify_cert(vct->root_file, vct->intermediate_file,
439 vct->leaf_file, &chains, &error, &error_depth, 658 vct->leaf_file, &chains, &error, &error_depth,
440 mode, policy_oid, policy_oid2); 659 mode, policy_oid, policy_oid2, vct->verify_flags);
441 660
442 if ((mode == MODE_VERIFY && chains == vct->want_chains) || 661 if ((mode == MODE_VERIFY && chains == vct->want_chains) ||
443 (chains == 0 && vct->want_chains == 0) || 662 (chains == 0 && vct->want_chains == 0) ||