feat: Derandomize the rosenpass protocol by adding testvectors (#604)

This commit is contained in:
Karolin Varner
2025-08-28 15:08:51 +02:00
committed by GitHub
27 changed files with 1383 additions and 16 deletions

87
Cargo.lock generated
View File

@@ -126,6 +126,34 @@ dependencies = [
"derive_arbitrary",
]
[[package]]
name = "assert_tv"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a4141926c2544d566b0c5815040151fa6c1e96398810b43951d3c68e13dfc2a"
dependencies = [
"anyhow",
"assert_tv_macros",
"base64",
"log",
"serde",
"serde_json",
"serde_yaml",
"toml",
"zstd",
]
[[package]]
name = "assert_tv_macros"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49fe5672253d886b06afd14bf16aec6111e2d111cbc83cd094a4f5f69f003332"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.98",
]
[[package]]
name = "atomic-polyfill"
version = "1.0.3"
@@ -157,6 +185,12 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
version = "1.6.0"
@@ -2041,6 +2075,8 @@ name = "rosenpass"
version = "0.3.0-dev"
dependencies = [
"anyhow",
"assert_tv",
"base64",
"clap",
"clap_complete",
"clap_mangen",
@@ -2193,6 +2229,8 @@ dependencies = [
"allocator-api2",
"allocator-api2-tests",
"anyhow",
"assert_tv",
"base64",
"base64ct",
"log",
"memsec",
@@ -2200,6 +2238,8 @@ dependencies = [
"rand 0.8.5",
"rosenpass-to",
"rosenpass-util",
"serde",
"serde_json",
"tempfile",
"zeroize",
]
@@ -2396,6 +2436,19 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
[[package]]
name = "serial_test"
version = "3.2.0"
@@ -2753,6 +2806,12 @@ dependencies = [
"subtle",
]
[[package]]
name = "unsafe-libyaml"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "utf8parse"
version = "0.2.2"
@@ -3292,3 +3351,31 @@ dependencies = [
"quote",
"syn 2.0.98",
]
[[package]]
name = "zstd"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "7.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.15+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
dependencies = [
"cc",
"pkg-config",
]

View File

@@ -84,6 +84,8 @@ uds = { git = "https://github.com/rosenpass/uds" }
lazy_static = "1.5"
#Dev dependencies
assert_tv = { version = "0.6.4" }
base64 = { version = "0.22.1" }
serial_test = "3.2.0"
tempfile = "3"
stacker = "0.1.17"

View File

@@ -24,6 +24,7 @@ let
"service"
"target"
"toml"
"zstd" # used for offloaded test vector values
];
# Files to explicitly include
files = [ "to/README.md" ];

View File

@@ -0,0 +1,351 @@
[[entries]]
entry_type = "Const"
description = "test setup: peer a secret key"
name = "peer_a_sk"
code_location = "tests/test_vector_crypto_server.rs:95"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Const"
description = "test setup: peer a public key"
name = "peer_a_pk"
code_location = "tests/test_vector_crypto_server.rs:96"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Const"
description = "test setup: peer b secret key"
name = "peer_b_sk"
code_location = "tests/test_vector_crypto_server.rs:101"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Const"
description = "test setup: peer b public key"
name = "peer_b_pk"
code_location = "tests/test_vector_crypto_server.rs:102"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Const"
description = "pre-shared key"
name = "psk"
value = "Vw7bZ1vyXfZo4D5/633F5IbTOntNFBjZRCWf/0cP3Ss="
code_location = "tests/test_vector_crypto_server.rs:105"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
[[entries]]
entry_type = "Const"
name = "CryptoServer::cookie_secrets[0]"
value = "COU/279CXvyB3mwVxT6fCQ=="
code_location = "tests/test_vector_crypto_server.rs:167"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::cookie_secrets[1]"
value = "5Q+e2O020FTcmBWlAPnWlw=="
code_location = "tests/test_vector_crypto_server.rs:172"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::biscuit_keys[0]"
value = "5h9KZ2KfLP5uNbEdimMNLHUjPFm0L3helyg8QE7pd/E="
code_location = "tests/test_vector_crypto_server.rs:177"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::biscuit_keys[1]"
value = "uwyhSvwuEeXwVUg4+9CBoPWPL0AY+oSVUhFpGpnBaY8="
code_location = "tests/test_vector_crypto_server.rs:179"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::cookie_secrets[0]"
value = "KtKzsfp1NMN3mrln54w0TA=="
code_location = "tests/test_vector_crypto_server.rs:167"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::cookie_secrets[1]"
value = "cc1hSqM+Jhal8AII5NIWLA=="
code_location = "tests/test_vector_crypto_server.rs:172"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::biscuit_keys[0]"
value = "ih8UroUklL5NLdegMFQAEWE6huLEO4HBNL44jpk0VsI="
code_location = "tests/test_vector_crypto_server.rs:177"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::biscuit_keys[1]"
value = "mXEYSvzhz5E9eUskbKJBZlXlYF2N3Q1MwmbGeXmhXoI="
code_location = "tests/test_vector_crypto_server.rs:179"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "hs.cookie_value.value"
value = "BryZRk1KR5Gc+AEm0plH1Q=="
code_location = "rosenpass/src/protocol/protocol.rs:3559"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Const"
name = "hs.core.sidi"
value = "avpJ6g=="
code_location = "rosenpass/src/protocol/protocol.rs:3572"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Const"
name = "hs.eski"
value = "KpIH2rHL5MR1TQosRVTAUhpDGYUfE7FbeDA/VgN2shd0gdwBRkdeTEZqKKdAY+ikmKydZQwNlFQW8WuH8fwknbUt/SCzo2iPbDg22sAuClQFN1sXckmEpDG2G4cqXHqkdVSuwhymt9V0w1lKFotTwNIN9Fo0eKq19twT16DP+nIPwrkDveAAm8OqwNp1iAODI8GuB3aL3Str/HDC7YR8QtuuzJQwfEa8CbihEpk+zZqVCJVZDrlfH6ydcJsahypuWpJQ4RwS+NejEvJirvgKngsgdPkGXyYLzQQhS4qagQDMkklWaxwL5pdSqlB+M/Cbx1iqgXgOp2PEykkOpgpEBKfDoCQxBnIYNEisx9B8XuibzqQiq0qctty3GBUf+peApMdataC6WwGqH1KpQiW8aUufIWFDK8xW56t3/bMV/AIsMWx3XpaxbGOQOgqAmRAxeYh23TeQ6lVturw/aMsV2phXBkgG6iQnzyd9z6Zufgezz3Ui2hdeJ/iCzfG0A7SMWlS8zETM46wExxO5smNh8jCoTzeSMpOeH3GfFyRs44PFybSQHtAbdcpcA+pj2VljGfRzq5U1AjpdbSKm8JO6n2PDOQlXHaNp5wZMTHZeywq/BrRWO0FXU9davLcEqUJ2xkwRIvEo24ae0MSD1SSd0rRK5LFilFWZXpDCkaoHvst87mdMeIBUYppMD+WkSuKun0XMXXSSWNPIvrGKFJlt4yTCNYsdfRBthGEa5sEApYd4jmi49zKbRSGGm/u915gdo0AvsFYa85EZzzBI0wfK3uW0X+YvGSEzwHGOAMaAyJu3tCGHt2tuevqND2lybzkJS+ih80l3jyaBbNmqQzBRt8YZtLg+e0ijH/x8IyGq+efCioRQjeN50sBAJrsSgncVtgoSraWbPLNu9movqQMtLiwGkUaZSqVANtQPQuccOFyzK7XD8zy5V0Bx/We0ijOvlyUPJWW+1LoALiArHhG7xIRQL8oe9RDP1mzPoGQd1MNRvCuePNpRX+JAO7a49vwsqUtsK6iAY5C1WIxc1TAVhrIz2YzKuyOQYJCbtkOTx5EZ+AbCsTa/E7VHJacj5xQXtYpy3NogXpAnI/ubjABhCVKTfNFytwKkQUAR1ZcoqzJlngdFILIFBeTEUJChXpBb3/obCCQOFVWCKaYfuLam34JgWkmKYUoao4ZP68yn7yc1l4lDRswKSgFt6YI31PcWGAbKM9QeKLF1Tso2bQOXlEF8MssCQjhN+PimSYU/A1ANTHEyQMxM+uUGXBAJwViSGSshHpioLkF3nBc2h7FT5Fi6hMU4xqUwsBgkfZKYQ6gMsMIqZjd/gIkbawwGU6VdLNNf4tw1f4ssD3QbKSA9LfsSHHV8YjcJ3vVoIVVd/Pmbe/kV8Ccz0zLPYWxyrrEanTOJwPqzYxBqTOBilVWlEfREu1ddYaccILMGEMdsQ6eBj4ySZYhj24Ajc3R8afR+anR2NNorfgIlF1d7VuW1BQG+loA3UqdO9lE4mwrARoy87LZKagYHUshet/CAYxinr0UlfCKqbEydljslyafPC4x/mmRWqjTNsTAVfZdOc1ESLyQ6fCkZ/ewOMmsVgUZsBPHI5LgE/2qjYhgXxzg72OmYynR4+8EWunEd2JScjTAurTVZBEPDfGq9wvySBeMbyIGgY0yIfJF/oGRI6/oyNoOBMyKff7oCVNzH+UBGPQJE0De7U1wmEqBNIOu6MMx4nFVgdNzA3TyLrhaOT3uDoJMo/9NnnvWDS5xhp9l8URkcVsol12MhmZAhqlhtGIOR72e5Jml6DNkLvYCX49ZKfMGBbnHNk/RhN5k3dccuD+UvIwxR3irMUXt6jITE0RbPCYWX14N4Jlcdz2oxA6U+RXW8ccJ0YQYjsNgmj1xpsnwY8/O6LkiB+Sm/fsJAkRGsKrWeyPKRcNR1uioBr6YpqKa0aHC0meQX7YqKNWZujOQX6ZJb2aMgx4CRJOc/fbqrtgpQy8mEy4JG2dmEPCdYKmY3YTGlpiVb65pLciEtJRIRiCqh4QNmCwtrixM5QgO5Y5gNfX/fXULtbtZdCDgQJ8CKaJNgxosHESp7YfeW+bO2tmmEwSHG+/s4YEEVQZm2OfJ46gLFPIixcTmADwFGOKEgTRofmHFxOUlIH1gXBkuqH0zWp71FqEpAoucjrROw"
code_location = "rosenpass/src/protocol/protocol.rs:3579"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Const"
name = "hs.core.ck"
value = "qUtsK6iAY5C1WIxc1TAVhrIz2YzKuyOQYJCbtkOTx5EZ+AbCsTa/E7VHJacj5xQXtYpy3NogXpAnI/ubjABhCVKTfNFytwKkQUAR1ZcoqzJlngdFILIFBeTEUJChXpBb3/obCCQOFVWCKaYfuLam34JgWkmKYUoao4ZP68yn7yc1l4lDRswKSgFt6YI31PcWGAbKM9QeKLF1Tso2bQOXlEF8MssCQjhN+PimSYU/A1ANTHEyQMxM+uUGXBAJwViSGSshHpioLkF3nBc2h7FT5Fi6hMU4xqUwsBgkfZKYQ6gMsMIqZjd/gIkbawwGU6VdLNNf4tw1f4ssD3QbKSA9LfsSHHV8YjcJ3vVoIVVd/Pmbe/kV8Ccz0zLPYWxyrrEanTOJwPqzYxBqTOBilVWlEfREu1ddYaccILMGEMdsQ6eBj4ySZYhj24Ajc3R8afR+anR2NNorfgIlF1d7VuW1BQG+loA3UqdO9lE4mwrARoy87LZKagYHUshet/CAYxinr0UlfCKqbEydljslyafPC4x/mmRWqjTNsTAVfZdOc1ESLyQ6fCkZ/ewOMmsVgUZsBPHI5LgE/2qjYhgXxzg72OmYynR4+8EWunEd2JScjTAurTVZBEPDfGq9wvySBeMbyIGgY0yIfJF/oGRI6/oyNoOBMyKff7oCVNzH+UBGPQJE0De7U1wmEqBNIOu6MMx4nFVgdNzA3TyLrhaOT3uDoJMo/9NnnvWDS5xhp9l8URkcVsol12MhmZAhqlhtGIOR72e5Jml6DNkLvYCX49ZKfMGBbnHNk/RhN5k3dccuD+UvIwxR3irMUXt6jITE0RbPCYWX14N4Jlcdz2oxA6U+RXW8ccJ0YQYjsNgmj1xpsnwY8/O6LkiB+Sm/fsJAkRGsKrWeyPKRcNR1uioBr6YpqKa0aHC0meQX7YqKNWZujOQX6ZJb2aMgx4CRJOc/fbqrtgpQy8mEy4JG2dmEPCdYKmY3YTGlpiVb65pLciEtJRIRiCqh4QNmCwtrixM5QgO5Y5gNfX/fXULtbtZdCDgQJ8CKaJNgxosHESp7YfeW+bM="
code_location = "rosenpass/src/protocol/protocol.rs:3580"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
name = "hs.core.ck 1"
value = "z2JAxQ4DPIikqHMSpFDAlmhjSBumhLZatJMrFAP+D1U="
code_location = "rosenpass/src/protocol/protocol.rs:3587"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Const"
value = "crPEWzqlCERLJr83BrZupxLUOxWHsYZalisk94tma0k="
code_location = "rosenpass/src/protocol/protocol.rs:3263"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:23"
[[entries]]
entry_type = "Const"
value = "eJXlj5zOJo/Eq85TzOTi7QY8zqWBP0QOOl3PAcpFDYnZyWmuzdpwDZJTbagAP52Md9r+j2vME4SW9UvdvOQo+jbNfuCHytU5K3yxI77srR4aWepM+xPAmxbyIwD4VGjDOQNAjP4Rn8n5L9cCju1tgit7yeM0S4Mx2KDR/Emr8V7gQnERob6LrPJgu6BMWkbZA2+dLVZOsvWPFmmn"
code_location = "rosenpass/src/protocol/protocol.rs:3264"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:23"
[[entries]]
entry_type = "Output"
name = "hs.core.ck 2"
value = "UVoOgm+xgnV9tXlaLrlBHiM8XDAH+4tPm3DTbP9uJzs="
code_location = "rosenpass/src/protocol/protocol.rs:3602"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
name = "ih.pidic"
value = "Y3Wstn84+vmUb/a/CtWHFixkdyTFKEaE7joUFM0vBZPehPAeDOXls/u5I1PvViF6"
code_location = "rosenpass/src/protocol/protocol.rs:3615"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
name = "hs.core.ck 3"
value = "RTCFQy236fEakHlQn8Pq4+ZbWAg4zvkP5iSp+RU7CpQ="
code_location = "rosenpass/src/protocol/protocol.rs:3616"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
name = "hs.core.ck 4"
value = "9bjg2ICzmCeqYMt4ACfX5UMQUde7WgeuI6H+vdQuWck="
code_location = "rosenpass/src/protocol/protocol.rs:3627"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
name = "ih.auth"
value = "E+AP6wyOrpngo7vE9Vpkjg=="
code_location = "rosenpass/src/protocol/protocol.rs:3636"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
name = "hs.core.ck 5"
value = "MkkapMEoAWftWlVPIcroCCTpqOrMv5TYSff5h8Un/OE="
code_location = "rosenpass/src/protocol/protocol.rs:3637"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
description = "message exchanged by the protocol parties"
name = "message"
code_location = "tests/test_vector_crypto_server.rs:136"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr IHR 4"
value = "z2JAxQ4DPIikqHMSpFDAlmhjSBumhLZatJMrFAP+D1U="
code_location = "rosenpass/src/protocol/protocol.rs:3693"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr IHR 5"
value = "UVoOgm+xgnV9tXlaLrlBHiM8XDAH+4tPm3DTbP9uJzs="
code_location = "rosenpass/src/protocol/protocol.rs:3702"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr IHR 6"
value = "RTCFQy236fEakHlQn8Pq4+ZbWAg4zvkP5iSp+RU7CpQ="
code_location = "rosenpass/src/protocol/protocol.rs:3714"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr IHR 7"
value = "9bjg2ICzmCeqYMt4ACfX5UMQUde7WgeuI6H+vdQuWck="
code_location = "rosenpass/src/protocol/protocol.rs:3724"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr IHR 8"
value = "MkkapMEoAWftWlVPIcroCCTpqOrMv5TYSff5h8Un/OE="
code_location = "rosenpass/src/protocol/protocol.rs:3733"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Const"
name = "session_id"
value = "+qqWGQ=="
code_location = "rosenpass/src/protocol/protocol.rs:3741"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr RHR 3"
value = "rPSnj3sQzMcnolHZJZpDlZ71VcFEtIEENGLWUPyRZws="
code_location = "rosenpass/src/protocol/protocol.rs:3749"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Const"
value = "aQGM2N7OhVgSlsa7pEaqdiRZLacxgDhwuEplHORsv3s="
code_location = "rosenpass/src/protocol/protocol.rs:3263"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:23"
[[entries]]
entry_type = "Const"
value = "XIOzetMa7cemW0Qq+vEu1frv9J/MhfFiT68mfbWZrZbzM5AI2lVPLXi75KvjbNC7YrqVG20d2DhZ38g9vjIAG50Lc8LHw3C+tQV2g/lCa4p1XySyQOJUAj/CpBGito8MdcdcxpFzLhCnq0owBSonbgyboxZq/hsX5z+unJu+5UiJYlxpcvu++w954OQiXi9lJpfnC4biY8Mw+8UL5d2UgWp8Yn3y3ZoIKSNGA5hR5/JUg1QStbSvWrhNiiDrfNUR0k2zKmLPXPS1pmaBvSuWQptq3WiA1OtkRsCSrAzjOtyUPWSZyXrttAZ4VJCBkEnd4OZy7eC/mBa3FjwJAfcvVY7i8mU1yDpLtS7MtdAZKMeGn0fQDWOx5z+vM+jbwOxXer79jPKPcdigxjTfARz+SxhfWfqGO5hBh86Ra0F+vgw3KH/YQgTchroWVF8WIwZlNwp6DqvwXBXwRPbtrv+uxmRHT9Oe+ZxJr88Nd1gRtjL0FN6faE1quGDAHWPuAfhFcxa7kdPpHN46cHSC+nzO1gtabPX/b0PM2awmNPB5QPpWoGHzz4HTYV7MYHmC4mxdKU7BT+U3vJd4+vl+7wGQSVxSCwzWHqCjRwOkIDLeiyZss7iz8BnOeErDySbPTMYI/Jv/R7lalOk4+73a1m2m4uZKetXRGEjg8btiKfhFaPZMc9p8xZeJNbsUbqoMl8/R1QGRqXHxzk9tTZW0AHV0t4uLnvHJgu9mR6LApZ99sAJpNcuU9TnsSPfT32DlXWNxtb0DnTQXxLQ7TnSWFYPCYyv7hbfNk8lDdGJqStSvnCe16KYoYjxpExEIfCAFicYhhar5MOpkinJMeyhMhVd2ctVIIIzZXePfZXcdOod2JbYh6+dmp0bnTyussHv9R+qYCCv5AyU/crKSmTbjgyOsmaVpyoTljsozC32uhqZh4M7KBUz1XyPJfD6L4NE1ovCKSfwJepYOqBw0MkdWoXwScyhMWNpVhS8X1aZ/QOZFVIuyYxoiwqpF/y3xV6QYFZmd"
code_location = "rosenpass/src/protocol/protocol.rs:3264"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:23"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr RHR 4"
value = "WCh3N6kKat+5vvn3WNTxsF9yXGYTQS7hlMUplMac/14="
code_location = "rosenpass/src/protocol/protocol.rs:3764"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Const"
value = "Sx7y7DSdVQVHWxR4OOMjyrDr8vuZa7MPX/U8GnPCIHY="
code_location = "rosenpass/src/protocol/protocol.rs:3263"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:23"
[[entries]]
entry_type = "Const"
value = "VwqEOlvdW0Evc1CasejxXQ0dN3mZ4HPMA6ogk3Q7OUzzgCIvbTU8BvBK6d1UH2R7Y5Nd/JdHgag42f5FpjVljX2vlXMk3XxUtREpORxqJ5qUgHejsgJyRO9caOPX/ZXmUZ6vORP7pIulLt2i47ykPNNlWuJmxVJj6NK+lE1BDMIuivHebR31atigV/fFFJui26vy5V9y6xZmnCJm"
code_location = "rosenpass/src/protocol/protocol.rs:3264"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:23"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr RHR 5"
value = "7gd9Mw7X0ZFmkIkP/JDofflRSAw21F1RjG4HXeMJfTI="
code_location = "rosenpass/src/protocol/protocol.rs:3779"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
value = "QyffgzBjc8qAqK18vYsH9TKs9lc6Njg8Q8nANsF/FMMBAAAAAAAAAAAAAADuB30zDtfRkWaQiQ/8kOh9+VFIDDbUXVGMbgdd4wl9Mg=="
code_location = "rosenpass/src/protocol/protocol.rs:3336"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:31"
[[entries]]
entry_type = "Const"
description = "Biscuit key after being cycled"
name = "CryptoServer::biscuit_key[r]"
value = "TIDswcSHh8WKsEsuwMCyldE0zVH8IEjV97ES8v3nHw0="
code_location = "rosenpass/src/protocol/protocol.rs:1430"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:127"
[[entries]]
entry_type = "Const"
value = "iSR2RKOw5VeBICb4b+i8P4QtF8XnJq2N"
code_location = "rosenpass/src/protocol/protocol.rs:3353"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:31"
[[entries]]
entry_type = "Output"
value = "iSR2RKOw5VeBICb4b+i8P4QtF8XnJq2Nq1gaCMgEJ+v1LulDYsjbfU5O0alWStfs4fBy7zS69RkzT8p0m3mVcK0TY9RRdWfxmCzU1U8DP7CbhfZxZHJC9CO8xwIa5r1NjVE1gxJJUEJCTHvtCc3PtFj861c="
code_location = "rosenpass/src/protocol/protocol.rs:3361"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:31"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr RHR 6"
value = "urS3a0/ufhUxj7bAnafEQ3j7it4q2XOfO+DVCeQJp4U="
code_location = "rosenpass/src/protocol/protocol.rs:3788"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr RHR 7"
value = "bbWd4iHXPK6helZLik4t96JKB7yiyw+qcNWbvlDiaQs="
code_location = "rosenpass/src/protocol/protocol.rs:3797"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
description = "message exchanged by the protocol parties"
name = "message"
code_location = "tests/test_vector_crypto_server.rs:136"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Output"
description = "message exchanged by the protocol parties"
name = "message"
code_location = "tests/test_vector_crypto_server.rs:136"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Output"
description = "message exchanged by the protocol parties"
name = "message"
code_location = "tests/test_vector_crypto_server.rs:136"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Output"
description = "final exchanged key"
name = "exchanged_key"
value = "NKG5/vCPc0akKnm5RxctcPigO8fvd0zqJeO2+xbDpq4="
code_location = "tests/test_vector_crypto_server.rs:153"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"

View File

@@ -79,6 +79,9 @@ command-fds = { workspace = true, optional = true }
rustix = { workspace = true, optional = true }
uds = { workspace = true, optional = true, features = ["mio_1xx"] }
libcrux-test-utils = { workspace = true, optional = true }
assert_tv = { workspace = true }
base64 = { workspace = true }
serde_json = { workspace = true }
[build-dependencies]
anyhow = { workspace = true }

View File

@@ -86,6 +86,7 @@ pub mod constants;
pub mod cookies;
pub mod index;
pub mod osk_domain_separator;
pub mod test_vector_sets;
pub mod testutils;
pub mod timing;
pub mod zerocopy;

View File

@@ -15,6 +15,7 @@ use std::{
};
use anyhow::{bail, ensure, Context, Result};
use assert_tv::{TestVector, TestVectorNOP};
use memoffset::span_of;
use zerocopy::{AsBytes, FromBytes, Ref};
@@ -33,6 +34,10 @@ use rosenpass_util::{
time::Timebase,
};
use crate::protocol::test_vector_sets::{
CycledBiscuitSecretKeyTestValues, EncapsAndMixTestValues, HandleInitHelloTestValues,
HandleInitiationTestValues, StoreBiscuitTestValues,
};
use crate::{hash_domains, msgs::*, RosenpassError};
use super::basic_types::{
@@ -1392,6 +1397,20 @@ impl CryptoServer {
///
/// Swap the biscuit keys, also advancing both biscuit key's mortality
pub fn active_biscuit_key(&mut self) -> BiscuitKeyPtr {
self.active_biscuit_key_with_test_vector::<TestVectorNOP>()
}
/// Generic variant of [`Self::active_biscuit_key`] that allows selecting
/// a [`TestVector`] implementation.
///
/// This function is primarily intended for testing with different
/// test vector strategies. In production code, prefer using
/// [`Self::active_biscuit_key`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example
pub fn active_biscuit_key_with_test_vector<TV: TestVector>(&mut self) -> BiscuitKeyPtr {
let (a, b) = (BiscuitKeyPtr(0), BiscuitKeyPtr(1));
let (t, u) = (a.get(self).created_at, b.get(self).created_at);
@@ -1407,6 +1426,11 @@ impl CryptoServer {
let r = if t < u { a } else { b };
let tb = self.timebase.clone();
r.get_mut(self).randomize(&tb);
let test_values: CycledBiscuitSecretKeyTestValues = TV::initialize_values();
TV::expose_mut_value(
&test_values.cycled_biscuit_secret_key,
&mut self.biscuit_keys[r.0].value,
);
r
}
@@ -1725,6 +1749,7 @@ impl Mortal for KnownInitConfResponsePtr {
/// # Examples
///
/// ```
/// use assert_tv::TestVector;
/// use rosenpass::protocol::{timing::Timing, Mortal, MortalExt, Lifecycle, CryptoServer, ProtocolVersion};
/// use rosenpass::protocol::testutils::{ServerForTesting, time_travel_forward};
///
@@ -1865,13 +1890,31 @@ impl CryptoServer {
///
/// See [Self::poll] on how to use this function with poll.
pub fn initiate_handshake(&mut self, peer: PeerPtr, tx_buf: &mut [u8]) -> Result<usize> {
self.initiate_handshake_with_test_vector::<TestVectorNOP>(peer, tx_buf)
}
/// Generic variant of [`Self::initiate_handshake`] that allows selecting
/// a [`TestVector`] implementation.
///
/// This function is primarily intended for testing with different
/// test vector strategies. In production code, prefer using
/// [`Self::initiate_handshake`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example
pub fn initiate_handshake_with_test_vector<TV: TestVector>(
&mut self,
peer: PeerPtr,
tx_buf: &mut [u8],
) -> Result<usize> {
// NOTE retransmission? yes if initiator, no if responder
// TODO remove unnecessary copying between global tx_buf and per-peer buf
// TODO move retransmission storage to io server
//
// Envelope::<InitHello>::default(); // TODO
let mut msg = truncating_cast_into::<Envelope<InitHello>>(tx_buf)?;
self.handle_initiation(peer, &mut msg.payload)?;
self.handle_initiation_with_test_vector::<TV>(peer, &mut msg.payload)?;
let len = self.seal_and_commit_msg(peer, MsgType::InitHello, &mut msg)?;
peer.hs()
.store_msg_for_retransmission(self, msg.as_bytes())?;
@@ -2111,6 +2154,24 @@ impl CryptoServer {
///
/// See [Self::poll] on how to use this function with poll.
pub fn handle_msg(&mut self, rx_buf: &[u8], tx_buf: &mut [u8]) -> Result<HandleMsgResult> {
self.handle_msg_with_test_vector::<TestVectorNOP>(rx_buf, tx_buf)
}
/// Generic message handler that allows selecting a [`TestVector`]
/// implementation.
///
/// This function is primarily intended for **testing** with different
/// test vector strategies. In production code, prefer using
/// [`Self::handle_msg`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example
pub fn handle_msg_with_test_vector<TV: TestVector>(
&mut self,
rx_buf: &[u8],
tx_buf: &mut [u8],
) -> Result<HandleMsgResult> {
let seal_broken = "Message seal broken!";
// length of the response. We assume no response, so None for now
let mut len = 0;
@@ -2131,7 +2192,7 @@ impl CryptoServer {
// At this point, we do not know the hash functon used by the peer, thus we try both,
// with a preference for SHAKE256.
let peer_shake256 = self.handle_init_hello(
let peer_shake256 = self.handle_init_hello_with_test_vector::<TV>(
&msg_in.payload,
&mut msg_out.payload,
KeyedHash::keyed_shake256(),
@@ -2139,7 +2200,7 @@ impl CryptoServer {
let (peer, peer_hash_choice) = match peer_shake256 {
Ok(peer) => (peer, KeyedHash::keyed_shake256()),
Err(_) => {
let peer_blake2b = self.handle_init_hello(
let peer_blake2b = self.handle_init_hello_with_test_vector::<TV>(
&msg_in.payload,
&mut msg_out.payload,
KeyedHash::incorrect_hmac_blake2b(),
@@ -3159,8 +3220,48 @@ impl HandshakeState {
ct: &mut [u8; KEM_CT_LEN],
pk: &[u8; KEM_PK_LEN],
) -> Result<&mut Self> {
self.encaps_and_mix_with_test_vector(kem, ct, pk, std::marker::PhantomData::<TestVectorNOP>)
}
/// Generic variant of [`Self::encaps_and_mix`] that allows selecting
/// a [`TestVector`] implementation.
///
/// This function is primarily intended for testing with different
/// test vector strategies. In production code, prefer using
/// [`Self::encaps_and_mix`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example.
///
/// Note on `_tv: PhantomData<TV>` parameter:
/// - Rusts type inference ties generic parameter specification together;
/// explicitly selecting `TV` with turbofish can force you to also spell
/// out the const generics.
/// - By adding a value parameter of type `PhantomData<TV>`, you can choose
/// `TV` at the call site while allowing the compiler to infer `KEM_*`
/// const generics from `ct` and `pk`.
/// - Call like: `encaps_and_mix_with_test_vector(&StaticKem, &mut ct, pk,
/// PhantomData::<TestVectorActive>)?;`
pub fn encaps_and_mix_with_test_vector<
const KEM_SK_LEN: usize,
const KEM_PK_LEN: usize,
const KEM_CT_LEN: usize,
const KEM_SHK_LEN: usize,
KemImpl: Kem<KEM_SK_LEN, KEM_PK_LEN, KEM_CT_LEN, KEM_SHK_LEN>,
TV: TestVector,
>(
&mut self,
kem: &KemImpl,
ct: &mut [u8; KEM_CT_LEN],
pk: &[u8; KEM_PK_LEN],
_tv: std::marker::PhantomData<TV>,
) -> Result<&mut Self> {
let test_values: EncapsAndMixTestValues<KEM_CT_LEN, KEM_SHK_LEN> = TV::initialize_values();
let mut shk = Secret::<KEM_SHK_LEN>::zero();
kem.encaps(shk.secret_mut(), ct, pk)?;
TV::expose_mut_value(&test_values.shk, &mut shk);
TV::expose_mut_value(&test_values.ct, ct);
self.mix(pk)?.mix(shk.secret())?.mix(ct)
}
@@ -3199,6 +3300,26 @@ impl HandshakeState {
peer: PeerPtr,
biscuit_ct: &mut [u8],
) -> Result<&mut Self> {
self.store_biscuit_with_test_vector::<TestVectorNOP>(srv, peer, biscuit_ct)
}
/// Generic variant of [`Self::store_biscuit`] that allows selecting
/// a [`TestVector`] implementation.
///
/// This function is primarily intended for testing with different
/// test vector strategies. In production code, prefer using
/// [`Self::store_biscuit`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example
pub fn store_biscuit_with_test_vector<TV: TestVector>(
&mut self,
srv: &mut CryptoServer,
peer: PeerPtr,
biscuit_ct: &mut [u8],
) -> Result<&mut Self> {
let test_values: StoreBiscuitTestValues = TV::initialize_values();
let mut biscuit = Secret::<BISCUIT_PT_LEN>::zero(); // pt buffer
let mut biscuit: Ref<&mut [u8], Biscuit> =
Ref::new(biscuit.secret_mut().as_mut_slice()).unwrap();
@@ -3212,6 +3333,8 @@ impl HandshakeState {
.ck
.copy_from_slice(self.ck.clone().danger_into_secret().secret());
TV::check_value(&test_values.biscuit, &biscuit.as_bytes().to_vec());
// calculate ad contents
let ad = hash_domains::biscuit_ad(peer.get(srv).protocol_version.keyed_hash())?
.mix(srv.spkm.deref())?
@@ -3224,14 +3347,18 @@ impl HandshakeState {
// The first bit of the nonce indicates which biscuit key was used
// TODO: This is premature optimization. Remove!
let bk = srv.active_biscuit_key();
let bk = srv.active_biscuit_key_with_test_vector::<TV>();
let mut n = XAEADNonce::random();
TV::expose_mut_value(&test_values.n, &mut n);
n[0] &= 0b0111_1111;
n[0] |= (bk.0 as u8 & 0x1) << 7;
let k = bk.get(srv).value.secret();
let pt = biscuit.as_bytes();
XAead.encrypt_with_nonce_in_ctxt(biscuit_ct, k, &n, &ad, pt)?;
TV::check_value(&test_values.biscuit_ct, &biscuit_ct.to_vec());
self.mix(biscuit_ct)
}
@@ -3400,6 +3527,26 @@ impl CryptoServer {
/// Core cryptographic protocol implementation: Kicks of the handshake
/// on the initiator side, producing the InitHello message.
pub fn handle_initiation(&mut self, peer: PeerPtr, ih: &mut InitHello) -> Result<PeerPtr> {
self.handle_initiation_with_test_vector::<TestVectorNOP>(peer, ih)
}
/// Generic variant of [`Self::handle_initiation`] that allows selecting
/// a [`TestVector`] implementation.
///
/// This function is primarily intended for testing with different
/// test vector strategies. In production code, prefer using
/// [`Self::handle_initiation`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example
pub fn handle_initiation_with_test_vector<TV: TestVector>(
&mut self,
peer: PeerPtr,
ih: &mut InitHello,
) -> Result<PeerPtr> {
let test_values: HandleInitiationTestValues = TV::initialize_values();
#[cfg(feature = "trace_bench")]
let _span_guard = rosenpass_util::trace_bench::trace().emit_span("handle_initiation");
@@ -3408,6 +3555,12 @@ impl CryptoServer {
peer.get(self).protocol_version.keyed_hash(),
);
// hs.cookie_value.created_at = tv_const!(hs.cookie_value.created_at, "init_handshake-cookie-created_at");
TV::expose_mut_value(
&test_values.init_handshake_cookie,
&mut hs.cookie_value.value,
);
// IHI1
protocol_section!("IHI1", {
hs.core.init(peer.get(self).spkt.deref())?;
@@ -3416,24 +3569,40 @@ impl CryptoServer {
// IHI2
protocol_section!("IHI2", {
hs.core.sidi.randomize();
TV::expose_mut_value(&test_values.init_handshake_sidi, &mut hs.core.sidi);
ih.sidi.copy_from_slice(&hs.core.sidi.value);
});
// IHI3
protocol_section!("IHI3", {
EphemeralKem.keygen(hs.eski.secret_mut(), &mut hs.epki)?;
TV::expose_mut_value(&test_values.init_handshake_eski, &mut hs.eski);
TV::expose_mut_value(&test_values.init_handshake_epki, &mut hs.epki);
ih.epki.copy_from_slice(&hs.epki.value);
});
// IHI4
protocol_section!("IHI4", {
hs.core.mix(ih.sidi.as_slice())?.mix(ih.epki.as_slice())?;
TV::check_value(
&test_values.init_handshake_mix_1,
&hs.core.ck.clone().danger_into_secret(),
);
});
// IHI5
protocol_section!("IHI5", {
hs.core
.encaps_and_mix(&StaticKem, &mut ih.sctr, peer.get(self).spkt.deref())?;
use std::marker::PhantomData;
hs.core.encaps_and_mix_with_test_vector(
&StaticKem,
&mut ih.sctr,
peer.get(self).spkt.deref(),
PhantomData::<TV>,
)?;
TV::check_value(
&test_values.init_handshake_mix_2,
&hs.core.ck.clone().danger_into_secret(),
);
});
// IHI6
@@ -3443,6 +3612,11 @@ impl CryptoServer {
self.pidm(peer.get(self).protocol_version.keyed_hash())?
.as_ref(),
)?;
TV::check_value(&test_values.init_hello_pidic, &ih.pidic);
TV::check_value(
&test_values.init_handshake_mix_3,
&hs.core.ck.clone().danger_into_secret(),
);
});
// IHI7
@@ -3450,16 +3624,24 @@ impl CryptoServer {
hs.core
.mix(self.spkm.deref())?
.mix(peer.get(self).psk.secret())?;
TV::check_value(
&test_values.init_handshake_mix_4,
&hs.core.ck.clone().danger_into_secret(),
);
});
// IHI8
protocol_section!("IHI8", {
hs.core.encrypt_and_mix(ih.auth.as_mut_slice(), &[])?;
TV::check_value(&test_values.init_hello_auth, &ih.auth);
TV::check_value(
&test_values.init_handshake_mix_5,
&hs.core.ck.clone().danger_into_secret(),
);
});
// Update the handshake hash last (not changing any state on prior error
peer.hs().insert(self, hs)?;
Ok(peer)
}
@@ -3471,6 +3653,27 @@ impl CryptoServer {
rh: &mut RespHello,
keyed_hash: KeyedHash,
) -> Result<PeerPtr> {
self.handle_init_hello_with_test_vector::<TestVectorNOP>(ih, rh, keyed_hash)
}
/// Generic variant of [`Self::handle_init_hello`] that allows selecting
/// a [`TestVector`] implementation.
///
/// This function is primarily intended for testing with different
/// test vector strategies. In production code, prefer using
/// [`Self::handle_init_hello`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example
pub fn handle_init_hello_with_test_vector<TV: TestVector>(
&mut self,
ih: &InitHello,
rh: &mut RespHello,
keyed_hash: KeyedHash,
) -> Result<PeerPtr> {
let test_values: HandleInitHelloTestValues = TV::initialize_values();
#[cfg(feature = "trace_bench")]
let _span_guard = rosenpass_util::trace_bench::trace().emit_span("handle_init_hello");
@@ -3487,11 +3690,19 @@ impl CryptoServer {
protocol_section!("IHR4", {
core.mix(&ih.sidi)?.mix(&ih.epki)?;
});
TV::check_value(
&test_values.chaining_key_ihr_4,
&core.ck.clone().danger_into_secret(),
);
// IHR5
protocol_section!("IHR5", {
core.decaps_and_mix(&StaticKem, self.sskm.secret(), self.spkm.deref(), &ih.sctr)?;
});
TV::check_value(
&test_values.chaining_key_ihr_5,
&core.ck.clone().danger_into_secret(),
);
// IHR6
let peer = protocol_section!("IHR6", {
@@ -3500,21 +3711,34 @@ impl CryptoServer {
self.find_peer(peerid)
.with_context(|| format!("No such peer {peerid:?}."))?
});
TV::check_value(
&test_values.chaining_key_ihr_6,
&core.ck.clone().danger_into_secret(),
);
// IHR7
protocol_section!("IHR7", {
core.mix(peer.get(self).spkt.deref())?
.mix(peer.get(self).psk.secret())?;
});
TV::check_value(
&test_values.chaining_key_ihr_7,
&core.ck.clone().danger_into_secret(),
);
// IHR8
protocol_section!("IHR8", {
core.decrypt_and_mix(&mut [0u8; 0], &ih.auth)?;
});
TV::check_value(
&test_values.chaining_key_ihr_8,
&core.ck.clone().danger_into_secret(),
);
// RHR1
protocol_section!("RHR1", {
core.sidr.randomize();
TV::expose_mut_value(&test_values.session_id, &mut core.sidr);
rh.sidi.copy_from_slice(core.sidi.as_ref());
rh.sidr.copy_from_slice(core.sidr.as_ref());
});
@@ -3522,28 +3746,59 @@ impl CryptoServer {
// RHR3
protocol_section!("RHR3", {
core.mix(&rh.sidr)?.mix(&rh.sidi)?;
TV::check_value(
&test_values.chaining_key_rhr_3,
&core.ck.clone().danger_into_secret(),
);
});
// RHR4
protocol_section!("RHR4", {
core.encaps_and_mix(&EphemeralKem, &mut rh.ecti, &ih.epki)?;
use std::marker::PhantomData;
core.encaps_and_mix_with_test_vector(
&EphemeralKem,
&mut rh.ecti,
&ih.epki,
PhantomData::<TV>,
)?;
TV::check_value(
&test_values.chaining_key_rhr_4,
&core.ck.clone().danger_into_secret(),
);
});
// RHR5
protocol_section!("RHR5", {
core.encaps_and_mix(&StaticKem, &mut rh.scti, peer.get(self).spkt.deref())?;
use std::marker::PhantomData;
core.encaps_and_mix_with_test_vector(
&StaticKem,
&mut rh.scti,
peer.get(self).spkt.deref(),
PhantomData::<TV>,
)?;
TV::check_value(
&test_values.chaining_key_rhr_5,
&core.ck.clone().danger_into_secret(),
);
});
// RHR6
protocol_section!("RHR6", {
core.store_biscuit(self, peer, &mut rh.biscuit)?;
core.store_biscuit_with_test_vector::<TV>(self, peer, &mut rh.biscuit)?;
TV::check_value(
&test_values.chaining_key_rhr_6,
&core.ck.clone().danger_into_secret(),
);
});
// RHR7
protocol_section!("RHR7", {
core.encrypt_and_mix(&mut rh.auth, &[])?;
TV::check_value(
&test_values.chaining_key_rhr_7,
&core.ck.clone().danger_into_secret(),
);
});
Ok(peer)
}

View File

@@ -0,0 +1,176 @@
//! Test vector definitions for derandomizing protocol internals.
//!
//! This module contains the definitions of internal test vector values used by
//! `CryptoServer` and the functions in `protocol.rs`. These values allow the
//! protocol implementation to be derandomized for deterministic testing and
//! reproducible behavior across runs.
//!
//! For an example of a test that uses these test vector values, see:
//! `rosenpass/tests/test_vector_crypto_server.rs`.
use crate::msgs::SESSION_ID_LEN;
use crate::protocol::basic_types::SessionId;
use crate::protocol::constants::COOKIE_VALUE_LEN;
use anyhow::anyhow;
use assert_tv::TestValue;
use assert_tv::TestVectorSet;
use base64::Engine;
use rosenpass_cipher_traits::primitives::{Aead, Kem};
use rosenpass_ciphers::{EphemeralKem, XAead, KEY_LEN};
use rosenpass_secret_memory::{Public, PublicBox, Secret};
use serde_json::Value;
#[derive(TestVectorSet)]
pub struct EncapsAndMixTestValues<const KEM_CT_LEN: usize, const KEM_SHK_LEN: usize> {
#[test_vec(serialize_with = "serialize_byte_arr")]
#[test_vec(deserialize_with = "deserialize_byte_arr")]
pub ct: TestValue<[u8; KEM_CT_LEN]>,
pub shk: TestValue<Secret<KEM_SHK_LEN>>,
}
#[derive(TestVectorSet)]
pub struct StoreBiscuitTestValues {
#[test_vec(serialize_with = "serialize_byte_vec")]
#[test_vec(deserialize_with = "deserialize_byte_vec")]
pub biscuit: TestValue<Vec<u8>>,
pub n: TestValue<Public<{ XAead::NONCE_LEN }>>,
#[test_vec(serialize_with = "serialize_byte_vec")]
#[test_vec(deserialize_with = "deserialize_byte_vec")]
pub biscuit_ct: TestValue<Vec<u8>>,
}
#[derive(TestVectorSet)]
pub struct HandleInitiationTestValues {
#[test_vec(name = "hs.cookie_value.value")]
pub init_handshake_cookie: TestValue<Secret<COOKIE_VALUE_LEN>>,
#[test_vec(name = "hs.core.sidi")]
pub init_handshake_sidi: TestValue<Public<SESSION_ID_LEN>>,
#[test_vec(name = "hs.eski")]
pub init_handshake_eski: TestValue<Secret<{ EphemeralKem::SK_LEN }>>,
#[test_vec(name = "hs.core.ck")]
pub init_handshake_epki: TestValue<Public<{ EphemeralKem::PK_LEN }>>,
#[test_vec(name = "hs.core.ck 1")]
pub init_handshake_mix_1: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "hs.core.ck 2")]
pub init_handshake_mix_2: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "ih.pidic")]
#[test_vec(serialize_with = "serialize_byte_arr")]
#[test_vec(deserialize_with = "deserialize_byte_arr")]
pub init_hello_pidic: TestValue<[u8; rosenpass_ciphers::Aead::TAG_LEN + 32]>,
#[test_vec(name = "hs.core.ck 3")]
pub init_handshake_mix_3: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "hs.core.ck 4")]
pub init_handshake_mix_4: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "ih.auth")]
#[test_vec(serialize_with = "serialize_byte_arr")]
#[test_vec(deserialize_with = "deserialize_byte_arr")]
pub init_hello_auth: TestValue<[u8; rosenpass_ciphers::Aead::TAG_LEN]>,
#[test_vec(name = "hs.core.ck 5")]
pub init_handshake_mix_5: TestValue<Secret<KEY_LEN>>,
}
#[derive(TestVectorSet)]
pub struct HandleInitHelloTestValues {
#[test_vec(name = "chaining_key_ihr IHR 4")]
pub chaining_key_ihr_4: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr IHR 5")]
pub chaining_key_ihr_5: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr IHR 6")]
pub chaining_key_ihr_6: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr IHR 7")]
pub chaining_key_ihr_7: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr IHR 8")]
pub chaining_key_ihr_8: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "session_id")]
pub session_id: TestValue<SessionId>,
#[test_vec(name = "chaining_key_ihr RHR 3")]
pub chaining_key_rhr_3: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr RHR 4")]
pub chaining_key_rhr_4: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr RHR 5")]
pub chaining_key_rhr_5: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr RHR 6")]
pub chaining_key_rhr_6: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr RHR 7")]
pub chaining_key_rhr_7: TestValue<Secret<KEY_LEN>>,
}
#[derive(TestVectorSet)]
pub struct InitHandshakeTestValues {
#[test_vec(serialize_with = "serialize_byte_vec")]
#[test_vec(deserialize_with = "deserialize_byte_vec")]
pub msg: TestValue<Vec<u8>>,
}
#[derive(TestVectorSet)]
pub struct CycledBiscuitSecretKeyTestValues {
#[test_vec(name = "CryptoServer::biscuit_key[r]")]
#[test_vec(description = "Biscuit key after being cycled")]
pub cycled_biscuit_secret_key: TestValue<Secret<KEY_LEN>>,
}
// Serialization helpers for raw byte arrays and vectors.
//
// These functions provide a small bridge implementation to serialize/deserialize
// standard values that do not carry serde implementations with the desired
// base64 format by default. They are used by the test vector machinery to
// encode `[u8; N]` and `Vec<u8>` values consistently.
/// Serialize a byte array as a base64 JSON string (bridge for `[u8; N]`).
pub fn serialize_byte_arr<const N: usize>(observed_value: &[u8; N]) -> anyhow::Result<Value> {
let encoded = base64::engine::general_purpose::STANDARD.encode(observed_value);
Ok(Value::String(encoded))
}
/// Deserialize a base64 JSON string into a byte array (bridge for `[u8; N]`).
pub fn deserialize_byte_arr<const N: usize>(value: &Value) -> anyhow::Result<[u8; N]> {
let value: &str = value
.as_str()
.ok_or_else(|| anyhow!("Unexpected value, expected string"))?;
let decoded = base64::engine::general_purpose::STANDARD
.decode(value.as_bytes())
.map_err(|e| anyhow!("Couldn't decode value: {e}"))?;
decoded
.as_slice()
.try_into()
.map_err(|e| anyhow!("Couldn't convert to array of size={}: {e}", N))
}
/// Serialize a byte vector as a base64 JSON string (bridge for `Vec<u8>`).
pub fn serialize_byte_vec(observed_value: &Vec<u8>) -> anyhow::Result<Value> {
let encoded = base64::engine::general_purpose::STANDARD.encode(observed_value);
Ok(Value::String(encoded))
}
/// Deserialize a base64 JSON string into a byte vector (bridge for `Vec<u8>`).
pub fn deserialize_byte_vec(value: &Value) -> anyhow::Result<Vec<u8>> {
let value: &str = value
.as_str()
.ok_or_else(|| anyhow!("Unexpected value, expected string"))?;
let decoded = base64::engine::general_purpose::STANDARD
.decode(value.as_bytes())
.map_err(|e| anyhow!("Couldn't decode value: {e}"))?;
Ok(decoded)
}

View File

@@ -0,0 +1,180 @@
//! # Deterministic protocol test based on captured internal randomness
//!
//! This test validates the rosenpass protocol implementation by recording all internal randomness
//! during execution and saving it to a test vector file (`crypto_server_test_vector_1.toml`).
//! On subsequent runs, the test replays this randomness to enforce deterministic behavior,
//! making any changes to the protocol's internal logic observable through test failures.
//!
//! ## Reinitializing the Test Vector
//!
//! If the test fails due to a mismatch between current output and the recorded test vector,
//! it likely indicates a change in implementation. To accept and re-record the new behavior,
//! re-run the test in initialization mode by setting the environment variable:
//!
//! ```bash
//! TEST_MODE=init cargo test crypto_server_test_vector_1
//! ```
use assert_tv::{test_vec_case, TestValue, TestVector, TestVectorActive, TestVectorSet};
use rosenpass::protocol::basic_types::{MsgBuf, SPk, SSk, SymKey};
use rosenpass::protocol::osk_domain_separator::OskDomainSeparator;
use rosenpass::protocol::test_vector_sets::deserialize_byte_vec;
use rosenpass::protocol::test_vector_sets::serialize_byte_vec;
use rosenpass::protocol::{CryptoServer, PeerPtr, ProtocolVersion};
use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::StaticKem;
use rosenpass_secret_memory::policy::*;
use rosenpass_secret_memory::{PublicBox, Secret};
use std::ops::DerefMut;
use rosenpass::protocol::constants::COOKIE_SECRET_LEN;
use rosenpass_ciphers::KEY_LEN;
#[derive(TestVectorSet)]
pub struct TestCaseValues {
#[test_vec(name = "peer_a_sk")]
#[test_vec(description = "test setup: peer a secret key")]
#[test_vec(offload = true)]
peer_a_sk: TestValue<Secret<{ StaticKem::SK_LEN }>>,
#[test_vec(name = "peer_a_pk")]
#[test_vec(description = "test setup: peer a public key")]
#[test_vec(offload = true)]
peer_a_pk: TestValue<PublicBox<{ StaticKem::PK_LEN }>>,
#[test_vec(name = "peer_b_sk")]
#[test_vec(description = "test setup: peer b secret key")]
#[test_vec(offload = true)]
peer_b_sk: TestValue<Secret<{ StaticKem::SK_LEN }>>,
#[test_vec(name = "peer_b_pk")]
#[test_vec(description = "test setup: peer b public key")]
#[test_vec(offload = true)]
peer_b_pk: TestValue<PublicBox<{ StaticKem::PK_LEN }>>,
#[test_vec(name = "psk")]
#[test_vec(description = "pre-shared key")]
psk: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "message")]
#[test_vec(description = "message exchanged by the protocol parties")]
#[test_vec(serialize_with = "serialize_byte_vec")]
#[test_vec(deserialize_with = "deserialize_byte_vec")]
#[test_vec(offload = true)]
message: TestValue<Vec<u8>>,
#[test_vec(name = "exchanged_key")]
#[test_vec(description = "final exchanged key")]
exchanged_key: TestValue<Secret<KEY_LEN>>,
}
#[derive(TestVectorSet)]
struct CryptoServerTestValues {
#[test_vec(name = "CryptoServer::cookie_secrets[0]")]
cookie_secret_0: TestValue<Secret<COOKIE_SECRET_LEN>>,
#[test_vec(name = "CryptoServer::cookie_secrets[1]")]
cookie_secret_1: TestValue<Secret<COOKIE_SECRET_LEN>>,
#[test_vec(name = "CryptoServer::biscuit_keys[0]")]
biscuit_key_0: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "CryptoServer::biscuit_keys[1]")]
biscuit_key_1: TestValue<Secret<KEY_LEN>>,
}
#[test_vec_case(format = "toml")]
fn crypto_server_test_vector_1() -> anyhow::Result<()> {
type TV = TestVectorActive;
let test_values: TestCaseValues = TV::initialize_values();
// Set security policy for storing secrets
secret_policy_try_use_memfd_secrets();
// initialize secret and public key for peer a ...
let (mut peer_a_sk, mut peer_a_pk) = gen_keypair::<TV>();
TV::expose_mut_value(&test_values.peer_a_sk, &mut peer_a_sk);
TV::expose_mut_value(&test_values.peer_a_pk, &mut peer_a_pk);
// ... and for peer b
let (mut peer_b_sk, mut peer_b_pk) = gen_keypair::<TV>();
TV::expose_mut_value(&test_values.peer_b_sk, &mut peer_b_sk);
TV::expose_mut_value(&test_values.peer_b_pk, &mut peer_b_pk);
// initialize server and a pre-shared key
let psk = TV::expose_value(&test_values.psk, SymKey::random());
let mut a = CryptoServer::new(peer_a_sk, peer_a_pk.clone());
de_randomize_time_base_cookie_secrets::<TV>(&mut a);
let mut b = CryptoServer::new(peer_b_sk, peer_b_pk.clone());
de_randomize_time_base_cookie_secrets::<TV>(&mut b);
// introduce peers to each other
a.add_peer(
Some(psk.clone()),
peer_b_pk,
ProtocolVersion::V03,
OskDomainSeparator::default(),
)?;
b.add_peer(
Some(psk),
peer_a_pk,
ProtocolVersion::V03,
OskDomainSeparator::default(),
)?;
// declare buffers for message exchange
let (mut a_buf, mut b_buf) = (MsgBuf::zero(), MsgBuf::zero());
// let a initiate a handshake
let mut maybe_len =
Some(a.initiate_handshake_with_test_vector::<TV>(PeerPtr(0), a_buf.as_mut_slice())?);
// let a and b communicate
while let Some(len) = maybe_len {
TV::check_value(&test_values.message, &a_buf[..len].to_vec());
maybe_len = b
.handle_msg_with_test_vector::<TV>(&a_buf[..len], &mut b_buf[..])?
.resp;
std::mem::swap(&mut a, &mut b);
std::mem::swap(&mut a_buf, &mut b_buf);
}
// all done! Extract the shared keys and ensure they are identical
let a_key = a.osk(PeerPtr(0))?;
let b_key = b.osk(PeerPtr(0))?;
assert_eq!(
a_key.secret(),
b_key.secret(),
"the key exchanged failed to establish a shared secret"
);
TV::check_value(&test_values.exchanged_key, &a_key);
Ok(())
}
fn gen_keypair<TV: TestVector>() -> (SSk, SPk) {
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
StaticKem
.keygen(sk.secret_mut(), pk.deref_mut())
.expect("Error generating keypair");
(sk, pk)
}
pub fn de_randomize_time_base_cookie_secrets<TV: TestVector>(cs: &mut CryptoServer) {
let test_values: CryptoServerTestValues = TV::initialize_values();
TV::expose_mut_value(
&test_values.cookie_secret_0,
&mut cs.cookie_secrets[0].value,
);
TV::expose_mut_value(
&test_values.cookie_secret_1,
&mut cs.cookie_secrets[1].value,
);
TV::expose_mut_value(&test_values.biscuit_key_0, &mut cs.biscuit_keys[0].value);
TV::expose_mut_value(&test_values.biscuit_key_1, &mut cs.biscuit_keys[1].value);
}

View File

@@ -19,6 +19,10 @@ rand = { workspace = true }
memsec = { workspace = true }
allocator-api2 = { workspace = true }
log = { workspace = true }
assert_tv = { workspace = true }
base64 = { workspace = true }
serde_json = { workspace = true }
serde = { workspace = true }
[dev-dependencies]
allocator-api2-tests = { workspace = true }

View File

@@ -47,4 +47,6 @@ mod secret;
pub use crate::secret::Secret;
pub mod policy;
mod serialization;
pub use crate::policy::*;

View File

@@ -0,0 +1,214 @@
use crate::{Public, PublicBox, Secret};
use base64::Engine;
use serde::de::{Error as DeError, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
fn encode_b64(bytes: &[u8]) -> String {
base64::engine::general_purpose::STANDARD.encode(bytes)
}
fn decode_b64(s: &str) -> Result<Vec<u8>, String> {
base64::engine::general_purpose::STANDARD
.decode(s.as_bytes())
.map_err(|e| format!("Couldn't decode base64: {e}"))
}
struct B64BytesVisitor;
impl<'de> Visitor<'de> for B64BytesVisitor {
type Value = Vec<u8>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "a base64-encoded string")
}
fn visit_str<E: DeError>(self, v: &str) -> Result<Self::Value, E> {
decode_b64(v).map_err(E::custom)
}
fn visit_string<E: DeError>(self, v: String) -> Result<Self::Value, E> {
self.visit_str(&v)
}
}
impl<const N: usize> Serialize for Secret<N> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&encode_b64(self.secret()))
}
}
impl<'de, const N: usize> Deserialize<'de> for Secret<N> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let bytes: Vec<u8> = deserializer.deserialize_string(B64BytesVisitor)?;
if bytes.len() != N {
return Err(D::Error::custom(format!(
"Unexpected length: got {}, expected {}",
bytes.len(),
N
)));
}
// Copies from heap bytes into the internal storage;
// no large stack temporaries.
Ok(Secret::<N>::from_slice(bytes.as_slice()))
}
}
impl<const N: usize> Serialize for Public<N> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&encode_b64(&self.value))
}
}
impl<'de, const N: usize> Deserialize<'de> for Public<N> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let bytes: Vec<u8> = deserializer.deserialize_string(B64BytesVisitor)?;
if bytes.len() != N {
return Err(D::Error::custom(format!(
"Unexpected length: got {}, expected {}",
bytes.len(),
N
)));
}
Ok(Public::<N>::from_slice(bytes.as_slice()))
}
}
impl<const N: usize> Serialize for PublicBox<N> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&encode_b64(self.inner.value.as_slice()))
}
}
impl<'de, const N: usize> Deserialize<'de> for PublicBox<N> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let bytes: Vec<u8> = deserializer.deserialize_string(B64BytesVisitor)?;
if bytes.len() != N {
return Err(D::Error::custom(format!(
"Unexpected length: got {}, expected {}",
bytes.len(),
N
)));
}
// Allocate Public<N> on the heap and copy bytes into it
let mut inner = Box::new(Public::<N>::zero());
inner.copy_from_slice(bytes.as_slice());
Ok(PublicBox { inner })
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::secret_policy_use_only_malloc_secrets;
use serde::{de::DeserializeOwned, Serialize};
use serde_json;
// Generic helper: serialize to JSON, then deserialize back.
fn roundtrip_json<T>(value: &T) -> T
where
T: Serialize + DeserializeOwned,
{
let json = serde_json::to_string(value).expect("serialize");
serde_json::from_str::<T>(&json).expect("deserialize")
}
pub fn test_init_secret_memory_policy() {
secret_policy_use_only_malloc_secrets();
}
#[test]
fn secret_roundtrip_json() {
test_init_secret_memory_policy();
const N: usize = 32;
let src = [0xABu8; N];
let original = Secret::<N>::from_slice(&src);
let recovered: Secret<N> = roundtrip_json(&original);
assert_eq!(
original.secret(),
recovered.secret(),
"Secret bytes must match after roundtrip"
);
}
#[test]
fn public_roundtrip_json() {
const N: usize = 48;
let src = [0x11u8; N];
let original = Public::<N>::from_slice(&src);
let json = serde_json::to_string(&original).expect("serialize");
let recovered: Public<N> = serde_json::from_str(&json).expect("deserialize");
// Avoid relying on private fields: compare canonical serialization strings.
let json2 = serde_json::to_string(&recovered).expect("re-serialize");
assert_eq!(
json, json2,
"Public must serialize identically after roundtrip"
);
}
#[test]
fn public_box_roundtrip_json() {
const N: usize = 64;
let src = [0x7Fu8; N];
let original = PublicBox::<N>::new(src);
let json = serde_json::to_string(&original).expect("serialize");
let recovered: PublicBox<N> = serde_json::from_str(&json).expect("deserialize");
let json2 = serde_json::to_string(&recovered).expect("re-serialize");
assert_eq!(
json, json2,
"PublicBox must serialize identically after roundtrip"
);
}
#[test]
fn secret_len_mismatch_is_error() {
test_init_secret_memory_policy();
const N_SMALL: usize = 16;
const N_BIG: usize = 32;
let src = [0x55u8; N_SMALL];
let small = Secret::<N_SMALL>::from_slice(&src);
let json = serde_json::to_string(&small).expect("serialize");
// Attempt to deserialize a 16-byte payload into Secret<32> should fail.
let res = serde_json::from_str::<Secret<N_BIG>>(&json);
assert!(
res.is_err(),
"Deserializing into a larger fixed size must error"
);
}
#[test]
fn public_len_mismatch_is_error() {
const N_SMALL: usize = 24;
const N_BIG: usize = 40;
let src = [0x33u8; N_SMALL];
let small = Public::<N_SMALL>::from_slice(&src);
let json = serde_json::to_string(&small).expect("serialize");
let res = serde_json::from_str::<Public<N_BIG>>(&json);
assert!(
res.is_err(),
"Deserializing into a larger fixed size must error"
);
}
#[test]
fn public_box_len_mismatch_is_error() {
const N_SMALL: usize = 8;
const N_BIG: usize = 12;
let src = [0xE0u8; N_SMALL];
let small = PublicBox::<N_SMALL>::new(src);
let json = serde_json::to_string(&small).expect("serialize");
let res = serde_json::from_str::<PublicBox<N_BIG>>(&json);
assert!(
res.is_err(),
"Deserializing into a different fixed size must error"
);
}
}

View File

@@ -1,4 +1,27 @@
# cargo-vet audits file
[audits]
[[audits.assert_tv]]
who = "Amin Faez <amin.faez.inbox@gmail.com>"
criteria = "safe-to-deploy"
version = "0.5.1"
[[audits.assert_tv]]
who = "Amin Faez <amin.faez.inbox@gmail.com>"
criteria = "safe-to-deploy"
version = "0.5.1"
[[audits.assert_tv_macros]]
who = "Amin Faez <amin.faez.inbox@gmail.com>"
criteria = "safe-to-run"
version = "0.5.1"
[[audits.ryu]]
who = "Amin Faez <amin.faez.inbox@gmail.com>"
criteria = "safe-to-deploy"
version = "1.0.10"
[[audits.serde_json]]
who = "Amin Faez <amin.faez.inbox@gmail.com>"
criteria = "safe-to-deploy"
version = "1.0.138"

View File

@@ -77,6 +77,14 @@ criteria = "safe-to-deploy"
version = "1.0.98"
criteria = "safe-to-deploy"
[[exemptions.assert_tv]]
version = "0.6.4"
criteria = "safe-to-deploy"
[[exemptions.assert_tv_macros]]
version = "0.6.4"
criteria = "safe-to-deploy"
[[exemptions.atomic-polyfill]]
version = "1.0.3"
criteria = "safe-to-deploy"
@@ -597,10 +605,6 @@ criteria = "safe-to-deploy"
version = "0.38.44"
criteria = "safe-to-deploy"
[[exemptions.ryu]]
version = "1.0.19"
criteria = "safe-to-deploy"
[[exemptions.scc]]
version = "2.3.3"
criteria = "safe-to-run"
@@ -621,6 +625,10 @@ criteria = "safe-to-deploy"
version = "0.6.8"
criteria = "safe-to-deploy"
[[exemptions.serde_yaml]]
version = "0.9.34+deprecated"
criteria = "safe-to-deploy"
[[exemptions.serial_test]]
version = "3.2.0"
criteria = "safe-to-run"
@@ -721,6 +729,10 @@ criteria = "safe-to-deploy"
version = "1.0.17"
criteria = "safe-to-deploy"
[[exemptions.unsafe-libyaml]]
version = "0.2.11"
criteria = "safe-to-deploy"
[[exemptions.uuid]]
version = "1.14.0"
criteria = "safe-to-deploy"
@@ -952,3 +964,15 @@ criteria = "safe-to-deploy"
[[exemptions.zerocopy-derive]]
version = "0.8.24"
criteria = "safe-to-deploy"
[[exemptions.zstd]]
version = "0.13.3"
criteria = "safe-to-deploy"
[[exemptions.zstd-safe]]
version = "7.2.4"
criteria = "safe-to-deploy"
[[exemptions.zstd-sys]]
version = "2.0.15+zstd.1.5.7"
criteria = "safe-to-deploy"

View File

@@ -59,6 +59,17 @@ who = "Nick Fitzgerald <fitzgen@gmail.com>"
criteria = "safe-to-deploy"
version = "1.4.1"
[[audits.bytecode-alliance.audits.base64]]
who = "Pat Hickey <phickey@fastly.com>"
criteria = "safe-to-deploy"
version = "0.21.0"
notes = "This crate has no dependencies, no build.rs, and contains no unsafe code."
[[audits.bytecode-alliance.audits.base64]]
who = "Andrew Brown <andrew.brown@intel.com>"
criteria = "safe-to-deploy"
delta = "0.21.3 -> 0.22.1"
[[audits.bytecode-alliance.audits.bitflags]]
who = "Jamey Sharp <jsharp@fastly.com>"
criteria = "safe-to-deploy"
@@ -1138,6 +1149,21 @@ criteria = "safe-to-run"
version = "1.2.1"
aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT"
[[audits.isrg.audits.base64]]
who = "Tim Geoghegan <timg@letsencrypt.org>"
criteria = "safe-to-deploy"
delta = "0.21.0 -> 0.21.1"
[[audits.isrg.audits.base64]]
who = "Brandon Pitman <bran@bran.land>"
criteria = "safe-to-deploy"
delta = "0.21.1 -> 0.21.2"
[[audits.isrg.audits.base64]]
who = "David Cook <dcook@divviup.org>"
criteria = "safe-to-deploy"
delta = "0.21.2 -> 0.21.3"
[[audits.isrg.audits.block-buffer]]
who = "David Cook <dcook@divviup.org>"
criteria = "safe-to-deploy"
@@ -1567,6 +1593,24 @@ version = "1.1.0"
notes = "Straightforward crate with no unsafe code, does what it says on the tin."
aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
[[audits.mozilla.audits.ryu]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "1.0.10 -> 1.0.11"
aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
[[audits.mozilla.audits.ryu]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "1.0.11 -> 1.0.12"
aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
[[audits.mozilla.audits.ryu]]
who = "Jan-Erik Rediger <jrediger@mozilla.com>"
criteria = "safe-to-deploy"
delta = "1.0.12 -> 1.0.19"
aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml"
[[audits.mozilla.audits.semver]]
who = "Jan-Erik Rediger <jrediger@mozilla.com>"
criteria = "safe-to-deploy"