Supply Chain Integrity, Transparency, and Trust (IETF SCITT)
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Reject unknown algorithm_id in SCITT receipt verification

verify_receipts silently fell back to SHA-256 when find_hash returned
None for an unregistered algorithm_id. Now returns Invalid_receipt
error. The check_receipt_leaf error for unknown IDs was previously
unreachable because verify_receipts masked it.

New test: receipt with algorithm_id=999 is rejected by both verify
and verify_receipt_only.

+45 -12
+14 -12
lib/scitt.ml
··· 658 658 match acc with 659 659 | Error _ as e -> e 660 660 | Ok level -> ( 661 - let hash = 662 - match find_hash r.Receipt.algorithm_id with 663 - | Some h -> h 664 - | None -> sha256 665 - in 666 - let expected_leaf = leaf_hash_with hash encoded_signed in 667 - match Cose.Sign1.verify ~key:ts_key r.Receipt.cose with 668 - | Error e -> Error (Cose_error e) 669 - | Ok payload -> 670 - Result.map 671 - (fun rlevel -> weaker_level level rlevel) 672 - (check_receipt_leaf ~expected_leaf payload r))) 661 + match find_hash r.Receipt.algorithm_id with 662 + | None -> 663 + Error 664 + (Invalid_receipt 665 + (Fmt.str "unknown hash algorithm_id %d" 666 + r.Receipt.algorithm_id)) 667 + | Some hash -> ( 668 + let expected_leaf = leaf_hash_with hash encoded_signed in 669 + match Cose.Sign1.verify ~key:ts_key r.Receipt.cose with 670 + | Error e -> Error (Cose_error e) 671 + | Ok payload -> 672 + Result.map 673 + (fun rlevel -> weaker_level level rlevel) 674 + (check_receipt_leaf ~expected_leaf payload r)))) 673 675 (Ok Merkle_proof) receipts 674 676 675 677 let verify ~ts_key ~issuer_key t =
+31
test/test_scitt.ml
··· 592 592 | Ok _ -> Alcotest.fail "should reject wrong issuer key" 593 593 | Error _ -> () 594 594 595 + (** A receipt with an unregistered algorithm_id must be rejected, not silently 596 + fall back to SHA-256. *) 597 + let test_unknown_algorithm_id () = 598 + Crypto_rng_unix.use_default (); 599 + let issuer_key, issuer_pub = gen_key () in 600 + let ts_key, ts_pub = gen_key () in 601 + let ts = make_ts ts_key in 602 + let stmt = make_statement () in 603 + let signed = sign_statement issuer_key stmt in 604 + let receipt = register ts signed in 605 + (* Tamper: set algorithm_id to 999 which is not in the VDS registry *) 606 + let bad_receipt = { receipt with Scitt.Receipt.algorithm_id = 999 } in 607 + let transparent = Scitt.Transparent_statement.v signed [ bad_receipt ] in 608 + (match 609 + Scitt.Transparent_statement.verify ~ts_key:ts_pub ~issuer_key:issuer_pub 610 + transparent 611 + with 612 + | Ok _ -> Alcotest.fail "unknown algorithm_id should be rejected" 613 + | Error (Scitt.Invalid_receipt msg) -> 614 + Alcotest.(check bool) "mentions algorithm_id" true (String.length msg > 0) 615 + | Error _ -> ()); 616 + (* Also test verify_receipt_only *) 617 + match 618 + Scitt.Transparent_statement.verify_receipt_only ~ts_key:ts_pub transparent 619 + with 620 + | Ok _ -> 621 + Alcotest.fail "unknown algorithm_id should be rejected (receipt only)" 622 + | Error _ -> () 623 + 595 624 let test_verify_receipt_only () = 596 625 Crypto_rng_unix.use_default (); 597 626 let issuer_key, _ = gen_key () in ··· 973 1002 Alcotest.test_case "lookup" `Quick test_lookup; 974 1003 Alcotest.test_case "wrong TS key" `Quick test_wrong_ts_key; 975 1004 Alcotest.test_case "wrong issuer key" `Quick test_wrong_issuer_key; 1005 + Alcotest.test_case "unknown algorithm_id" `Quick 1006 + test_unknown_algorithm_id; 976 1007 Alcotest.test_case "verify receipt only" `Quick 977 1008 test_verify_receipt_only; 978 1009 Alcotest.test_case "no receipts" `Quick test_no_receipts;