diff --git a/Cargo.lock b/Cargo.lock index 0dc2c0bf1e26d..364f94d67823a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9306,6 +9306,18 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder", + "sha2 0.10.8", +] + [[package]] name = "pairing" version = "0.23.0" @@ -15747,6 +15759,7 @@ dependencies = [ "bincode", "byteorder", "chrono", + "ciborium", "consensus-config", "coset", "criterion", @@ -15776,6 +15789,7 @@ dependencies = [ "num_enum 0.6.1", "once_cell", "p256", + "p384", "parking_lot 0.12.1", "passkey-authenticator", "passkey-client", @@ -15785,6 +15799,7 @@ dependencies = [ "proptest-derive 0.5.1", "rand 0.8.5", "roaring", + "rustls-pemfile 2.1.2", "schemars", "serde", "serde-name", @@ -15807,6 +15822,7 @@ dependencies = [ "tracing", "typed-store-error", "url", + "x509-parser", ] [[package]] @@ -18377,6 +18393,7 @@ dependencies = [ "lazy_static", "nom", "oid-registry", + "ring 0.16.20", "rusticata-macros", "thiserror 1.0.64", "time", diff --git a/Cargo.toml b/Cargo.toml index 20f5007a09d17..48d5ddd0e5be3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -539,7 +539,7 @@ webpki = { version = "0.102", package = "rustls-webpki", features = [ "std", ] } wiremock = "0.5" -x509-parser = "0.14.0" +x509-parser = { version = "0.14.0", features = ["verify"] } zstd = "0.12.3" zeroize = "1.6.0" versions = "4.1.0" @@ -585,6 +585,9 @@ passkey-authenticator = { version = "0.2.0" } coset = "0.3" p256 = { version = "0.13.2", features = ["ecdsa"] } +p384 = { version = "0.13.0", default-features = false, features = ["ecdsa","sha384"] } +ciborium = "0.2" + # anemo dependencies anemo = { git = "https://github.com/mystenlabs/anemo.git", rev = "e609f7697ed6169bf0760882a0b6c032a57e4f3b" } anemo-build = { git = "https://github.com/mystenlabs/anemo.git", rev = "e609f7697ed6169bf0760882a0b6c032a57e4f3b" } diff --git a/crates/sui-framework/docs/sui-framework/nitro_attestation.md b/crates/sui-framework/docs/sui-framework/nitro_attestation.md new file mode 100644 index 0000000000000..196f0117d5b71 --- /dev/null +++ b/crates/sui-framework/docs/sui-framework/nitro_attestation.md @@ -0,0 +1,71 @@ +--- +title: Module `0x2::nitro_attestation` +--- + + + +- [Function `verify_nitro_attestation_internal`](#0x2_nitro_attestation_verify_nitro_attestation_internal) +- [Function `verify_nitro_attestation`](#0x2_nitro_attestation_verify_nitro_attestation) + + +
use 0x2::clock;
+
+ + + + + +## Function `verify_nitro_attestation_internal` + +Internal native function + + +
fun verify_nitro_attestation_internal(attestation: &vector<u8>, current_timestamp: u64): vector<vector<u8>>
+
+ + + +
+Implementation + + +
native fun verify_nitro_attestation_internal(
+    attestation: &vector<u8>,
+    current_timestamp: u64
+): vector<vector<u8>>;
+
+ + + +
+ + + +## Function `verify_nitro_attestation` + +@param attestation: attesttaion documents bytes data. +@param clock: the clock object. + +Returns parsed pcrs after verifying the attestation. + + +
public fun verify_nitro_attestation(attestation: &vector<u8>, clock: &clock::Clock): vector<vector<u8>>
+
+ + + +
+Implementation + + +
public fun verify_nitro_attestation(
+    attestation: &vector<u8>,
+    clock: &Clock
+): vector<vector<u8>> {
+    verify_nitro_attestation_internal(attestation, clock::timestamp_ms(clock))
+}
+
+ + + +
diff --git a/crates/sui-framework/packages/sui-framework/sources/crypto/nitro_attestation.move b/crates/sui-framework/packages/sui-framework/sources/crypto/nitro_attestation.move new file mode 100644 index 0000000000000..b92a16dfb5f72 --- /dev/null +++ b/crates/sui-framework/packages/sui-framework/sources/crypto/nitro_attestation.move @@ -0,0 +1,23 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +module sui::nitro_attestation; + +use sui::clock::{Self, Clock}; + +/// Internal native function +native fun verify_nitro_attestation_internal( + attestation: &vector, + current_timestamp: u64 +): vector>; + +/// @param attestation: attesttaion documents bytes data. +/// @param clock: the clock object. +/// +/// Returns parsed pcrs after verifying the attestation. +public fun verify_nitro_attestation( + attestation: &vector, + clock: &Clock +): vector> { + verify_nitro_attestation_internal(attestation, clock::timestamp_ms(clock)) +} \ No newline at end of file diff --git a/crates/sui-framework/packages/sui-framework/tests/crypto/nitro_attestation_test.move b/crates/sui-framework/packages/sui-framework/tests/crypto/nitro_attestation_test.move new file mode 100644 index 0000000000000..8e7f4339f6f31 --- /dev/null +++ b/crates/sui-framework/packages/sui-framework/tests/crypto/nitro_attestation_test.move @@ -0,0 +1,21 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[test_only] +module sui::nitro_attestation_tests { + use sui::nitro_attestation; + use sui::test_scenario; + + #[test] + fun test_nitro_attestation() { + let mut scenario = test_scenario::begin(@0x0); + let ctx = scenario.ctx(); + let payload = x"8444a1013822a0591121a9696d6f64756c655f69647827692d30663733613462346362373463633966322d656e633031393265343138386665663738316466646967657374665348413338346974696d657374616d701b000001932d1239ca6470637273b0005830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035830639a8b65f68b0223cbb14a0032487e5656d260434e3d1a10e7ec1407fb86143860717fc8afee90df7a1604111709af460458309ab5a1aba055ee41ee254b9b251a58259b29fa1096859762744e9ac73b5869b25e51223854d9f86adbb37fe69f3e5d1c0558300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000658300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000758300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000858300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000958300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b636572746966696361746559027e3082027a30820201a00302010202100192e4188fef781d0000000067366a8d300a06082a8648ce3d04030330818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343231323432365a170d3234313131353030323432395a308193310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753313e303c06035504030c35692d30663733613462346362373463633966322d656e63303139326534313838666566373831642e75732d656173742d312e6177733076301006072a8648ce3d020106052b810400220362000442e0526fc41af71feac64fc6f68a8ac8aae831a9e945ab7d482b842acaf05d6b762d00cbc2115da270187c44597b1c16dcf497c70e543b41612e9041ea143d11d58bd1c847496e5d41ec78a49fe445348cf9a47af9387e0451d9ec145b56ec12a31d301b300c0603551d130101ff04023000300b0603551d0f0404030206c0300a06082a8648ce3d0403030367003064023078001466c0c64293b9bde3d0834edb67ff18417f6075a8f7d137701e10164ce6cf45c508bf383ed0d8d41c51a5977a43023033cb8e4a6ad2686b86c2533accbab5dd5e98cf25d3612b1a48502f327ce00acc921641242d5a3a27d222df1f7dfc3e2c68636162756e646c65845902153082021130820196a003020102021100f93175681b90afe11d46ccb4e4e7f856300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3139313032383133323830355a170d3439313032383134323830355a3049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004fc0254eba608c1f36870e29ada90be46383292736e894bfff672d989444b5051e534a4b1f6dbe3c0bc581a32b7b176070ede12d69a3fea211b66e752cf7dd1dd095f6f1370f4170843d9dc100121e4cf63012809664487c9796284304dc53ff4a3423040300f0603551d130101ff040530030101ff301d0603551d0e041604149025b50dd90547e796c396fa729dcf99a9df4b96300e0603551d0f0101ff040403020186300a06082a8648ce3d0403030369003066023100a37f2f91a1c9bd5ee7b8627c1698d255038e1f0343f95b63a9628c3d39809545a11ebcbf2e3b55d8aeee71b4c3d6adf3023100a2f39b1605b27028a5dd4ba069b5016e65b4fbde8fe0061d6a53197f9cdaf5d943bc61fc2beb03cb6fee8d2302f3dff65902c2308202be30820245a003020102021100ab314210a819b4842e3be045e7daddbe300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3234313131333037333235355a170d3234313230333038333235355a3064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004cbd3e3fe8793852d952a214ee1c7f17e13eff238c5952ffc6c48f2b8e70beec10194585089829f4818d012a6061cdc9f4d8c5a67aada1233f75b65d3f7704e1c02460cfcc74f0e94193c8d4030f6d1662de0427836c1d32c571c919230fae73aa381d53081d230120603551d130101ff040830060101ff020102301f0603551d230418301680149025b50dd90547e796c396fa729dcf99a9df4b96301d0603551d0e04160414b5f0f617140aa7057c7977f361eee896fd9a58b4300e0603551d0f0101ff040403020186306c0603551d1f046530633061a05fa05d865b687474703a2f2f6177732d6e6974726f2d656e636c617665732d63726c2e73332e616d617a6f6e6177732e636f6d2f63726c2f61623439363063632d376436332d343262642d396539662d3539333338636236376638342e63726c300a06082a8648ce3d04030303670030640230038362cf11e189755d6a2306d728a7f356740eefe623d5e0e9e7c33c1b061ade2224127ac3a2e4bce60b43fc8c53326902306aceccf6f45a8d5c066bd10ce3ffaeeebdee56eedb86deb18ea22172c07196750924dd8f4656c70bd95eb6714cb8ecdd59031a308203163082029ba0030201020211009a0f4f29c1649826edb5b5f9f93b6326300a06082a8648ce3d0403033064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343034323230325a170d3234313132303033323230325a308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c653076301006072a8648ce3d020106052b810400220362000496f4565c489625767e8e2d3006ba06bd48ba3e384027a205b93d1ad4958128887c38ddbb2f4922888708ef0985e1e5d3bd73b33f86785ac66a204eed3a6b663686434f64e19fb39cd7b33068edb2108b79774a961e7080cb1b4eaa60a5e63e22a381ea3081e730120603551d130101ff040830060101ff020101301f0603551d23041830168014b5f0f617140aa7057c7977f361eee896fd9a58b4301d0603551d0e0416041484b6dc9994365b56081f5d1bc8ee21f58e45d7df300e0603551d0f0101ff0404030201863081800603551d1f047930773075a073a071866f687474703a2f2f63726c2d75732d656173742d312d6177732d6e6974726f2d656e636c617665732e73332e75732d656173742d312e616d617a6f6e6177732e636f6d2f63726c2f34396230376261342d303533622d346435622d616434612d3364626533653065396637652e63726c300a06082a8648ce3d0403030369003066023100d00c2999e66fbcce624d91aedf41f5532b04c300c86a61d78ed968716a7f7ff565e2c361f4f46fe5c5486a9d2bfe0d60023100bc46872a45820fb552b926d420d4f6a1be831bb26821d374e95bff5ed042b3313465b5b4cde79f16f6a57bd5b541353c5902c3308202bf30820245a003020102021500eaa3f0b662c2a61c96f94194fa33d5baf26eeb84300a06082a8648ce3d040303308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c65301e170d3234313131343130313032345a170d3234313131353130313032345a30818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b81040022036200040fe46adf864a558a00a9ca4b64ece5ba124ed1d29656a1f16ca71d0dc8fca56b0fb15aafd309f6258374e8c7b4a5b0521c76d1812a7873474dae9322aef1cd782db19fc2ece4d36fa08acbe65e4bec2a3cfe70960d179778ea7e7711f827b36ea366306430120603551d130101ff040830060101ff020100300e0603551d0f0101ff040403020204301d0603551d0e041604143e40d423bf86e9565c378487843389bd2f471a56301f0603551d2304183016801484b6dc9994365b56081f5d1bc8ee21f58e45d7df300a06082a8648ce3d0403030368003065023100c2767f29cc6e40e087617cf680d81e3b77962c29d8ace426b3c4a62a560354da73de6f80986d44da2593a3c268fea94302306056e2f3c88c30170c4940f578acc279a01fe689123e81def4f8c313e1f0cbc44a562a171d12810e847e441aee233f676a7075626c69635f6b6579f669757365725f6461746158205a264748a62368075d34b9494634a3e096e0e48f6647f965b81d2a653de684f2656e6f6e6365f65860284d57f029e1b3beb76455a607b9a86360d6451370f718a0d7bdcad729eea248c25461166ab684ad31fb52713918ee3e401d1b56251d6f9d85bf870e850e0b47559d17091778dbafc3d1989a94bd54c0991053675dcc3686402b189172aae196"; + let mut clock = sui::clock::create_for_testing(ctx); + clock.set_for_testing(1731627987382); + let res = nitro_attestation::verify_nitro_attestation(&payload, &clock); + assert!(vector::length(&res) == 16); + scenario.end(); + clock.destroy_for_testing(); + } +} diff --git a/crates/sui-framework/packages_compiled/sui-framework b/crates/sui-framework/packages_compiled/sui-framework index e008cceb39c5a..06426565c5836 100644 Binary files a/crates/sui-framework/packages_compiled/sui-framework and b/crates/sui-framework/packages_compiled/sui-framework differ diff --git a/crates/sui-framework/published_api.txt b/crates/sui-framework/published_api.txt index 775880de57e60..8dcaa5e2942f5 100644 --- a/crates/sui-framework/published_api.txt +++ b/crates/sui-framework/published_api.txt @@ -2788,6 +2788,12 @@ sqrt_u128 divide_and_round_up public fun 0x2::math +verify_nitro_attestation_internal + fun + 0x2::nitro_attestation +verify_nitro_attestation + public fun + 0x2::nitro_attestation ObjectBag public struct 0x2::object_bag diff --git a/crates/sui-protocol-config/src/lib.rs b/crates/sui-protocol-config/src/lib.rs index 1de0575ea5fc4..8a8457d9366ca 100644 --- a/crates/sui-protocol-config/src/lib.rs +++ b/crates/sui-protocol-config/src/lib.rs @@ -598,6 +598,10 @@ struct FeatureFlags { // Properly convert certain type argument errors in the execution layer. #[serde(skip_serializing_if = "is_false")] convert_type_argument_error: bool, + + // Enable native functions for nitro attestation. + #[serde(skip_serializing_if = "is_false")] + enable_nitro_attestation: bool, } fn is_false(b: &bool) -> bool { @@ -1206,6 +1210,10 @@ pub struct ProtocolConfig { vdf_verify_vdf_cost: Option, vdf_hash_to_input_cost: Option, + nitro_attestation_parse_cost: Option, + nitro_attestation_verify_base_cost: Option, + nitro_attestation_verify_cost_per_cert: Option, + // Stdlib costs bcs_per_byte_serialized_cost: Option, bcs_legacy_min_output_size_cost: Option, @@ -1755,6 +1763,10 @@ impl ProtocolConfig { pub fn convert_type_argument_error(&self) -> bool { self.feature_flags.convert_type_argument_error } + + pub fn enable_nitro_attestation(&self) -> bool { + self.feature_flags.enable_nitro_attestation + } } #[cfg(not(msim))] @@ -2189,6 +2201,10 @@ impl ProtocolConfig { vdf_verify_vdf_cost: None, vdf_hash_to_input_cost: None, + nitro_attestation_parse_cost: None, + nitro_attestation_verify_base_cost: None, + nitro_attestation_verify_cost_per_cert: None, + bcs_per_byte_serialized_cost: None, bcs_legacy_min_output_size_cost: None, bcs_failure_cost: None, @@ -3130,6 +3146,13 @@ impl ProtocolConfig { } 72 => { cfg.feature_flags.convert_type_argument_error = true; + if chain != Chain::Mainnet && chain != Chain::Testnet { + cfg.feature_flags.enable_nitro_attestation = true; + // todo: change this + cfg.nitro_attestation_parse_cost = Some(100); + cfg.nitro_attestation_verify_base_cost = Some(300); + cfg.nitro_attestation_verify_cost_per_cert = Some(100); + } } // Use this template when making changes: // diff --git a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap index 4b150ff109724..752f4896f2bdb 100644 --- a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap +++ b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap @@ -1,6 +1,7 @@ --- source: crates/sui-swarm-config/tests/snapshot_tests.rs expression: genesis.sui_system_object().into_genesis_version_for_tooling() +snapshot_kind: text --- epoch: 0 protocol_version: 72 @@ -240,13 +241,13 @@ validators: next_epoch_worker_address: ~ extra_fields: id: - id: "0xe1736cf478d38b4e97ac9cff325aedd9d71c156d43cf1e49a821a8b20dfe877a" + id: "0x6b9519d549ce6946d20ace22c5325a01e0c2b604b76b52bd27d18b7bd1257910" size: 0 voting_power: 10000 - operation_cap_id: "0x92ca0c15c751ed16f4ba61cf7a2561bcdacea7c14ff8734bb187c305bee96176" + operation_cap_id: "0x81a3e2b4c5cb950d7a8fb82260cf31ea5f82742ffc78bbbd6f76b6e76f8cab78" gas_price: 1000 staking_pool: - id: "0x65826f03944fd73127bd792daed69eddbc1ddc147f8c99da50324c64a90df0e0" + id: "0x4d46cc19f159de39a8421b7e1855b1a1a4df12b10aa714908b1e52439f3bd8a1" activation_epoch: 0 deactivation_epoch: ~ sui_balance: 20000000000000000 @@ -254,14 +255,14 @@ validators: value: 0 pool_token_balance: 20000000000000000 exchange_rates: - id: "0xae8b647a4c501c2b62396ff783139eb9d60594dcdb68f8b53aa6e612fde7ad55" + id: "0x3303a9b548b4ca3d0c67025cea60cc496e078e310f6542150b352b300440b181" size: 1 pending_stake: 0 pending_total_sui_withdraw: 0 pending_pool_token_withdraw: 0 extra_fields: id: - id: "0x9074457c10ce082304550f2edb9e55fc0ec12e5b0ade37806debfb378d9a1b9d" + id: "0x4ca2230585b23b5b03587ecfe8d29cfb9444e342d312b4ee42c4af429f611f70" size: 0 commission_rate: 200 next_epoch_stake: 20000000000000000 @@ -269,27 +270,27 @@ validators: next_epoch_commission_rate: 200 extra_fields: id: - id: "0x3307d52632bb86f142fa40561bb2b46365a5612225a0b0891a63809fcdcb691f" + id: "0x8439885d5e80c15835f67b1dea087c1e0ae4672b39ad7711491847aaf2cd0ef3" size: 0 pending_active_validators: contents: - id: "0x60cea2865bd42d6a782798762fa70c2d717be27f8873c1a512882a190629e254" + id: "0x8a4748ce2eaf5fc5f4cd3b5dd8a15782b4abfd1885818f862820e2d883d791cb" size: 0 pending_removals: [] staking_pool_mappings: - id: "0xbcdff2f0bca8d3c90783a19a68012d10c6c52c187817395fe91b220957ae65dd" + id: "0x6015e1edaec640adcfb74e2a60571ec1558e75a9c36891583197dff3d37fc4b8" size: 1 inactive_validators: - id: "0xb126b6b0efdfd66f0a14c159a5828b7844065267efb83637e59922dd28a2dec9" + id: "0x2d3479e08fc3802090272b22e8d9bee0a87edb67f5893e4e5e5955ca56c8de12" size: 0 validator_candidates: - id: "0x35e1d26ec23453bfb7007fb2882ced97a1d19a102d2320bfbd136a6e35220688" + id: "0x88107f2c31161269c29e65ff3cbf555b6647a55e3db1aaae39cf30ea7fb8433b" size: 0 at_risk_validators: contents: [] extra_fields: id: - id: "0x30f3634e8f7220afff05b96d87ab9020bc62538f5b0910b9c5d5e12646d944ea" + id: "0x8a316b068fe4452177d9333acd479e216e26518aa76c04685959c71490fdc782" size: 0 storage_fund: total_object_storage_rebates: @@ -306,7 +307,7 @@ parameters: validator_low_stake_grace_period: 7 extra_fields: id: - id: "0x8f0219b14d05d238a48c0f75c3cc9c675acb9b5f6c50e0b7a9b9bbecaaaea232" + id: "0x17688697efa33d4e503e9b2e35623dee777add49e4d1768c8e3f076e2184920c" size: 0 reference_gas_price: 1000 validator_report_records: @@ -320,7 +321,7 @@ stake_subsidy: stake_subsidy_decrease_rate: 1000 extra_fields: id: - id: "0x3e45c6ab50494f16b32675da9b00233b08f0ca281c2f763ed5838518045a13b6" + id: "0x4a59e2082c239d5aa2bf50b2a66e4374c671579528e42d3078958b9037a74b8d" size: 0 safe_mode: false safe_mode_storage_rewards: @@ -332,6 +333,5 @@ safe_mode_non_refundable_storage_fee: 0 epoch_start_timestamp_ms: 10 extra_fields: id: - id: "0xf741efb1558fc976c1b7ba102a1c0ad5b814a15913c08fe18c3abf20f74547a2" + id: "0x27767762fce0685db078584b6d5e20bd121eb317eba327acc96d404bd41bd769" size: 0 - diff --git a/crates/sui-types/Cargo.toml b/crates/sui-types/Cargo.toml index 5ebeaba9333d1..052f67faa9d5c 100644 --- a/crates/sui-types/Cargo.toml +++ b/crates/sui-types/Cargo.toml @@ -74,6 +74,18 @@ lru.workspace = true sui-sdk-types.workspace = true +ciborium.workspace = true +<<<<<<< HEAD +x509-parser.workspace = true +======= +serde_bytes.workspace = true +rustls.workspace = true +x509-parser.workspace = true +webpki.workspace = true +>>>>>>> 2d6ee73be2 (feat: add attestation verify in sui-types) +p384.workspace = true +rustls-pemfile.workspace = true + [dev-dependencies] bincode.workspace = true criterion.workspace = true @@ -94,6 +106,10 @@ passkey-authenticator.workspace = true name = "accumulator_bench" harness = false +[[bench]] +name = "nitro_attestation_bench" +harness = false + [features] default = [] tracing = [ diff --git a/crates/sui-types/benches/nitro_attestation_bench.rs b/crates/sui-types/benches/nitro_attestation_bench.rs new file mode 100644 index 0000000000000..5a4e3fbc603a6 --- /dev/null +++ b/crates/sui-types/benches/nitro_attestation_bench.rs @@ -0,0 +1,43 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use criterion::*; +use fastcrypto::encoding::Encoding; +use fastcrypto::encoding::Hex; +use p384::ecdsa::signature::Signer; +use p384::ecdsa::signature::Verifier; +use p384::ecdsa::{Signature, SigningKey, VerifyingKey}; +use rand::rngs::OsRng; +use sui_types::nitro_attestation::{parse_nitro_attestation_inner, verify_nitro_attestation_inner}; +fn nitro_attestation_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("attestation"); + + group.bench_function("verify_attestation", |b| { + b.iter(|| { + let parsed = parse_nitro_attestation_inner(&Hex::decode("8444a1013822a0591121a9696d6f64756c655f69647827692d30663733613462346362373463633966322d656e633031393265343138386665663738316466646967657374665348413338346974696d657374616d701b000001932d1239ca6470637273b0005830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035830639a8b65f68b0223cbb14a0032487e5656d260434e3d1a10e7ec1407fb86143860717fc8afee90df7a1604111709af460458309ab5a1aba055ee41ee254b9b251a58259b29fa1096859762744e9ac73b5869b25e51223854d9f86adbb37fe69f3e5d1c0558300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000658300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000758300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000858300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000958300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b636572746966696361746559027e3082027a30820201a00302010202100192e4188fef781d0000000067366a8d300a06082a8648ce3d04030330818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343231323432365a170d3234313131353030323432395a308193310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753313e303c06035504030c35692d30663733613462346362373463633966322d656e63303139326534313838666566373831642e75732d656173742d312e6177733076301006072a8648ce3d020106052b810400220362000442e0526fc41af71feac64fc6f68a8ac8aae831a9e945ab7d482b842acaf05d6b762d00cbc2115da270187c44597b1c16dcf497c70e543b41612e9041ea143d11d58bd1c847496e5d41ec78a49fe445348cf9a47af9387e0451d9ec145b56ec12a31d301b300c0603551d130101ff04023000300b0603551d0f0404030206c0300a06082a8648ce3d0403030367003064023078001466c0c64293b9bde3d0834edb67ff18417f6075a8f7d137701e10164ce6cf45c508bf383ed0d8d41c51a5977a43023033cb8e4a6ad2686b86c2533accbab5dd5e98cf25d3612b1a48502f327ce00acc921641242d5a3a27d222df1f7dfc3e2c68636162756e646c65845902153082021130820196a003020102021100f93175681b90afe11d46ccb4e4e7f856300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3139313032383133323830355a170d3439313032383134323830355a3049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004fc0254eba608c1f36870e29ada90be46383292736e894bfff672d989444b5051e534a4b1f6dbe3c0bc581a32b7b176070ede12d69a3fea211b66e752cf7dd1dd095f6f1370f4170843d9dc100121e4cf63012809664487c9796284304dc53ff4a3423040300f0603551d130101ff040530030101ff301d0603551d0e041604149025b50dd90547e796c396fa729dcf99a9df4b96300e0603551d0f0101ff040403020186300a06082a8648ce3d0403030369003066023100a37f2f91a1c9bd5ee7b8627c1698d255038e1f0343f95b63a9628c3d39809545a11ebcbf2e3b55d8aeee71b4c3d6adf3023100a2f39b1605b27028a5dd4ba069b5016e65b4fbde8fe0061d6a53197f9cdaf5d943bc61fc2beb03cb6fee8d2302f3dff65902c2308202be30820245a003020102021100ab314210a819b4842e3be045e7daddbe300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3234313131333037333235355a170d3234313230333038333235355a3064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004cbd3e3fe8793852d952a214ee1c7f17e13eff238c5952ffc6c48f2b8e70beec10194585089829f4818d012a6061cdc9f4d8c5a67aada1233f75b65d3f7704e1c02460cfcc74f0e94193c8d4030f6d1662de0427836c1d32c571c919230fae73aa381d53081d230120603551d130101ff040830060101ff020102301f0603551d230418301680149025b50dd90547e796c396fa729dcf99a9df4b96301d0603551d0e04160414b5f0f617140aa7057c7977f361eee896fd9a58b4300e0603551d0f0101ff040403020186306c0603551d1f046530633061a05fa05d865b687474703a2f2f6177732d6e6974726f2d656e636c617665732d63726c2e73332e616d617a6f6e6177732e636f6d2f63726c2f61623439363063632d376436332d343262642d396539662d3539333338636236376638342e63726c300a06082a8648ce3d04030303670030640230038362cf11e189755d6a2306d728a7f356740eefe623d5e0e9e7c33c1b061ade2224127ac3a2e4bce60b43fc8c53326902306aceccf6f45a8d5c066bd10ce3ffaeeebdee56eedb86deb18ea22172c07196750924dd8f4656c70bd95eb6714cb8ecdd59031a308203163082029ba0030201020211009a0f4f29c1649826edb5b5f9f93b6326300a06082a8648ce3d0403033064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343034323230325a170d3234313132303033323230325a308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c653076301006072a8648ce3d020106052b810400220362000496f4565c489625767e8e2d3006ba06bd48ba3e384027a205b93d1ad4958128887c38ddbb2f4922888708ef0985e1e5d3bd73b33f86785ac66a204eed3a6b663686434f64e19fb39cd7b33068edb2108b79774a961e7080cb1b4eaa60a5e63e22a381ea3081e730120603551d130101ff040830060101ff020101301f0603551d23041830168014b5f0f617140aa7057c7977f361eee896fd9a58b4301d0603551d0e0416041484b6dc9994365b56081f5d1bc8ee21f58e45d7df300e0603551d0f0101ff0404030201863081800603551d1f047930773075a073a071866f687474703a2f2f63726c2d75732d656173742d312d6177732d6e6974726f2d656e636c617665732e73332e75732d656173742d312e616d617a6f6e6177732e636f6d2f63726c2f34396230376261342d303533622d346435622d616434612d3364626533653065396637652e63726c300a06082a8648ce3d0403030369003066023100d00c2999e66fbcce624d91aedf41f5532b04c300c86a61d78ed968716a7f7ff565e2c361f4f46fe5c5486a9d2bfe0d60023100bc46872a45820fb552b926d420d4f6a1be831bb26821d374e95bff5ed042b3313465b5b4cde79f16f6a57bd5b541353c5902c3308202bf30820245a003020102021500eaa3f0b662c2a61c96f94194fa33d5baf26eeb84300a06082a8648ce3d040303308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c65301e170d3234313131343130313032345a170d3234313131353130313032345a30818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b81040022036200040fe46adf864a558a00a9ca4b64ece5ba124ed1d29656a1f16ca71d0dc8fca56b0fb15aafd309f6258374e8c7b4a5b0521c76d1812a7873474dae9322aef1cd782db19fc2ece4d36fa08acbe65e4bec2a3cfe70960d179778ea7e7711f827b36ea366306430120603551d130101ff040830060101ff020100300e0603551d0f0101ff040403020204301d0603551d0e041604143e40d423bf86e9565c378487843389bd2f471a56301f0603551d2304183016801484b6dc9994365b56081f5d1bc8ee21f58e45d7df300a06082a8648ce3d0403030368003065023100c2767f29cc6e40e087617cf680d81e3b77962c29d8ace426b3c4a62a560354da73de6f80986d44da2593a3c268fea94302306056e2f3c88c30170c4940f578acc279a01fe689123e81def4f8c313e1f0cbc44a562a171d12810e847e441aee233f676a7075626c69635f6b6579f669757365725f6461746158205a264748a62368075d34b9494634a3e096e0e48f6647f965b81d2a653de684f2656e6f6e6365f65860284d57f029e1b3beb76455a607b9a86360d6451370f718a0d7bdcad729eea248c25461166ab684ad31fb52713918ee3e401d1b56251d6f9d85bf870e850e0b47559d17091778dbafc3d1989a94bd54c0991053675dcc3686402b189172aae196").unwrap()).unwrap(); + verify_nitro_attestation_inner( + &parsed.0, + &parsed.1, + &parsed.2, + 1731627987382, + ) + }) + }); + + let signing_key = SigningKey::random(&mut OsRng); // Generate a key for testing + let verifying_key = VerifyingKey::from(&signing_key); + let message = b"test message"; + let signature: Signature = signing_key.sign(message); + + group.bench_function("verify_p384", |b| { + b.iter(|| { + verifying_key + .verify(message, &signature) + .expect("signature should verify"); + }) + }); + group.finish(); +} + +criterion_group!(benches, nitro_attestation_benchmark); +criterion_main!(benches); diff --git a/crates/sui-types/src/error.rs b/crates/sui-types/src/error.rs index db8b5a0968b1b..4e3fd07c1a430 100644 --- a/crates/sui-types/src/error.rs +++ b/crates/sui-types/src/error.rs @@ -675,6 +675,9 @@ pub enum SuiError { #[error("The request did not contain a certificate")] NoCertificateProvidedError, + + #[error("Enclave attestation failed: {0}")] + AttestationFailedToVerify(String), } #[repr(u64)] diff --git a/crates/sui-types/src/lib.rs b/crates/sui-types/src/lib.rs index c815c98822274..e65ba98825e13 100644 --- a/crates/sui-types/src/lib.rs +++ b/crates/sui-types/src/lib.rs @@ -68,6 +68,7 @@ pub mod mock_checkpoint_builder; pub mod move_package; pub mod multisig; pub mod multisig_legacy; +pub mod nitro_attestation; pub mod object; pub mod passkey_authenticator; pub mod programmable_transaction_builder; diff --git a/crates/sui-types/src/nitro_attestation.rs b/crates/sui-types/src/nitro_attestation.rs new file mode 100644 index 0000000000000..b56a3589d0e93 --- /dev/null +++ b/crates/sui-types/src/nitro_attestation.rs @@ -0,0 +1,607 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use serde::de::{MapAccess, Visitor}; +use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer}; +use std::fmt; +use x509_parser::public_key::PublicKey; +use x509_parser::time::ASN1Time; +use x509_parser::x509::SubjectPublicKeyInfo; + +use crate::error::{SuiError, SuiResult}; + +use ciborium::value::{Integer, Value}; +use once_cell::sync::Lazy; +use p384::ecdsa::signature::Verifier; +use p384::ecdsa::{Signature, VerifyingKey}; +use x509_parser::{certificate::X509Certificate, prelude::FromDer}; + +#[cfg(test)] +#[path = "unit_tests/nitro_attestation_tests.rs"] +mod nitro_attestation_tests; + +/// Maximum length of the certificate chain. This is to limit the absolute upper bound on execution. +const MAX_CERT_CHAIN_LENGTH: usize = 10; + +/// Root certificate for AWS Nitro Attestation. +static ROOT_CERTIFICATE: Lazy> = Lazy::new(|| { + let pem_bytes = include_bytes!("./nitro_root_certificate.pem"); + let mut pem_cursor = std::io::Cursor::new(pem_bytes); + let cert = rustls_pemfile::certs(&mut pem_cursor) + .next() + .expect("should have root cert") + .expect("root cert should be valid"); + cert.to_vec() +}); + +/// Error type for Nitro attestation verification. +#[derive(Debug, PartialEq, Eq)] +pub enum NitroAttestationVerifyError { + /// Invalid COSE_Sign1: {0} + InvalidCoseSign1(String), + /// Invalid signature + InvalidSignature, + /// Invalid public key + InvalidPublicKey, + /// Siganture failed to verify + SignatureFailedToVerify, + /// Invalid attestation document + InvalidAttestationDoc(String), + /// Invalid user data. + InvalidUserData, + /// Invalid certificate: {0} + InvalidCertificate(String), + /// Invalid PCRs + InvalidPcrs, +} + +impl fmt::Display for NitroAttestationVerifyError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + NitroAttestationVerifyError::InvalidCoseSign1(msg) => { + write!(f, "InvalidCoseSign1: {}", msg) + } + NitroAttestationVerifyError::InvalidSignature => write!(f, "InvalidSignature"), + NitroAttestationVerifyError::InvalidPublicKey => write!(f, "InvalidPublicKey"), + NitroAttestationVerifyError::SignatureFailedToVerify => { + write!(f, "SignatureFailedToVerify") + } + NitroAttestationVerifyError::InvalidAttestationDoc(msg) => { + write!(f, "InvalidAttestationDoc: {}", msg) + } + NitroAttestationVerifyError::InvalidCertificate(msg) => { + write!(f, "InvalidCertificate: {}", msg) + } + NitroAttestationVerifyError::InvalidPcrs => write!(f, "InvalidPcrs"), + NitroAttestationVerifyError::InvalidUserData => write!(f, "InvalidUserData"), + } + } +} + +impl From for SuiError { + fn from(err: NitroAttestationVerifyError) -> Self { + SuiError::AttestationFailedToVerify(err.to_string()) + } +} + +/// Given an attestation in bytes, parse it into signature, signed message and a parsed payload. +pub fn parse_nitro_attestation_inner( + attestation_bytes: &[u8], +) -> SuiResult<(Vec, Vec, AttestationDocument)> { + let cose_sign1 = CoseSign1::parse_and_validate(attestation_bytes)?; + let doc = AttestationDocument::parse_and_validate_payload(&cose_sign1.payload)?; + let signature = cose_sign1.clone().signature; + Ok((signature, cose_sign1.to_signed_message(), doc)) +} + +/// Given the signature bytes, signed message and parsed payload, verify everything according to +/// and +/// . +pub fn verify_nitro_attestation_inner( + signature: &[u8], + signed_message: &[u8], + payload: &AttestationDocument, + timestamp: u64, +) -> SuiResult<()> { + // Extract public key from cert and signature as P384. + let signature = Signature::from_slice(signature) + .map_err(|_| NitroAttestationVerifyError::InvalidSignature)?; + let cert = X509Certificate::from_der(payload.certificate.as_slice()) + .map_err(|e| NitroAttestationVerifyError::InvalidCertificate(e.to_string()))?; + let pk_bytes = SubjectPublicKeyInfo::parsed(cert.1.public_key()) + .map_err(|err| NitroAttestationVerifyError::InvalidCertificate(err.to_string()))?; + + // Verify the signature against the public key and the message. + match pk_bytes { + PublicKey::EC(ec) => { + let verifying_key = VerifyingKey::from_sec1_bytes(ec.data()) + .map_err(|_| NitroAttestationVerifyError::InvalidPublicKey)?; + verifying_key + .verify(signed_message, &signature) + .map_err(|_| NitroAttestationVerifyError::SignatureFailedToVerify)?; + } + _ => { + return Err(NitroAttestationVerifyError::InvalidPublicKey.into()); + } + } + + payload.validate_cert(timestamp)?; + Ok(()) +} + +/// Implementation of the COSE_Sign1 structure as defined in [RFC8152](https://tools.ietf.org/html/rfc8152). +/// protected_header: See Section 3 (Note: AWS Nitro does not have unprotected header.) +/// payload: See Section 4.2. +/// signature: See Section 4.2. +/// Class and trait impl adapted from +#[derive(Debug, Clone)] +pub struct CoseSign1 { + /// protected: empty_or_serialized_map, + protected: Vec, + /// unprotected: HeaderMap + unprotected: HeaderMap, + /// payload: bstr + /// The spec allows payload to be nil and transported separately, but it's not useful at the + /// moment, so this is just a Bytes for simplicity. + payload: Vec, + /// signature: bstr + signature: Vec, +} + +/// Empty map wrapper for COSE headers. +#[derive(Clone, Debug, Default)] +pub struct HeaderMap; + +impl Serialize for HeaderMap { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeMap; + let map = serializer.serialize_map(Some(0))?; + map.end() + } +} + +impl<'de> Deserialize<'de> for HeaderMap { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct MapVisitor; + + impl<'de> Visitor<'de> for MapVisitor { + type Value = HeaderMap; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a map") + } + + fn visit_map(self, mut access: A) -> Result + where + A: MapAccess<'de>, + { + // Consume but ignore any map entries + while access.next_entry::()?.is_some() {} + Ok(HeaderMap) + } + } + + deserializer.deserialize_map(MapVisitor) + } +} + +impl Serialize for CoseSign1 { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(4))?; + seq.serialize_element(&Value::Bytes(self.protected.to_vec()))?; + seq.serialize_element(&self.unprotected)?; + seq.serialize_element(&Value::Bytes(self.payload.to_vec()))?; + seq.serialize_element(&Value::Bytes(self.signature.to_vec()))?; + seq.end() + } +} + +impl<'de> Deserialize<'de> for CoseSign1 { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::{Error, SeqAccess, Visitor}; + use std::fmt; + + struct CoseSign1Visitor; + + impl<'de> Visitor<'de> for CoseSign1Visitor { + type Value = CoseSign1; + + fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("a possibly tagged CoseSign1 structure") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + fn extract_bytes(value: Value) -> Option> { + match value { + Value::Bytes(bytes) => Some(bytes), + _ => None, + } + } + + // Get protected header bytes + let protected = match seq.next_element::()? { + Some(v) => extract_bytes(v) + .ok_or_else(|| A::Error::custom("protected header must be bytes"))?, + None => return Err(A::Error::missing_field("protected")), + }; + + let unprotected = match seq.next_element()? { + Some(v) => v, + None => return Err(A::Error::missing_field("unprotected")), + }; + // Get payload bytes + let payload = match seq.next_element::()? { + Some(v) => { + extract_bytes(v).ok_or_else(|| A::Error::custom("payload must be bytes"))? + } + None => return Err(A::Error::missing_field("payload")), + }; + + // Get signature bytes + let signature = match seq.next_element::()? { + Some(v) => extract_bytes(v) + .ok_or_else(|| A::Error::custom("signature must be bytes"))?, + None => return Err(A::Error::missing_field("signature")), + }; + + Ok(CoseSign1 { + protected, + unprotected, + payload, + signature, + }) + } + + fn visit_newtype_struct(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // This is the tagged version: we ignore the tag part, and just go into it + deserializer.deserialize_seq(CoseSign1Visitor) + } + } + + deserializer.deserialize_any(CoseSign1Visitor) + } +} + +impl CoseSign1 { + /// Parse CBOR bytes into struct. Adapted from + pub fn parse_and_validate(bytes: &[u8]) -> Result { + let tagged_value: ciborium::value::Value = ciborium::de::from_reader(bytes) + .map_err(|e| NitroAttestationVerifyError::InvalidCoseSign1(e.to_string()))?; + + let (tag, value) = match tagged_value { + ciborium::value::Value::Tag(tag, box_value) => (Some(tag), *box_value), + other => (None, other), + }; + + // Validate tag (18 is the COSE_Sign1 tag) + match tag { + None | Some(18) => (), + Some(_) => { + return Err(NitroAttestationVerifyError::InvalidCoseSign1( + "invalid tag".to_string(), + )) + } + } + + // Create a buffer for serialization + let mut buf = Vec::new(); + + // Serialize the value into the buffer + ciborium::ser::into_writer(&value, &mut buf) + .map_err(|e| NitroAttestationVerifyError::InvalidCoseSign1(e.to_string()))?; + + // Deserialize the COSE_Sign1 structure from the buffer + let cosesign1: Self = ciborium::de::from_reader(&buf[..]) + .map_err(|e| NitroAttestationVerifyError::InvalidCoseSign1(e.to_string()))?; + + // Validate protected header + let _: HeaderMap = ciborium::de::from_reader(cosesign1.protected.as_slice()) + .map_err(|e| NitroAttestationVerifyError::InvalidCoseSign1(e.to_string()))?; + + cosesign1.validate_header()?; + Ok(cosesign1) + } + + /// Validate protected header, payload and signature length. + pub fn validate_header(&self) -> Result<(), NitroAttestationVerifyError> { + if !(Self::is_valid_protected_header(self.protected.as_slice()) + && (1..16384).contains(&self.payload.len()) + && self.signature.len() == 96) + { + return Err(NitroAttestationVerifyError::InvalidCoseSign1( + "invalid cbor header".to_string(), + )); + } + Ok(()) + } + + // Check protected header: https://docs.aws.amazon.com/enclaves/latest/user/verify-root.html#COSE-CBOR + // 18(/* COSE_Sign1 CBOR tag is 18 */ + // {1: -35}, /* This is equivalent with {algorithm: ECDS 384} */ + // {}, /* We have nothing in unprotected */ + // $ATTESTATION_DOCUMENT_CONTENT /* Attestation Document */, + // signature /* This is the signature */ + // ) + fn is_valid_protected_header(bytes: &[u8]) -> bool { + let expected_key: Integer = Integer::from(1); + let expected_val: Integer = Integer::from(-35); + let value: Value = match ciborium::de::from_reader(bytes) { + Ok(v) => v, + Err(_) => return false, + }; + match value { + Value::Map(vec) => match &vec[..] { + [(Value::Integer(key), Value::Integer(val))] => { + key == &expected_key && val == &expected_val + } + _ => false, + }, + _ => false, + } + } + + /// This is the content that the signature is committed over. + fn to_signed_message(&self) -> Vec { + let value = Value::Array(vec![ + Value::Text("Signature1".to_string()), + Value::Bytes(self.protected.as_slice().to_vec()), + Value::Bytes(vec![]), + Value::Bytes(self.payload.as_slice().to_vec()), + ]); + let mut bytes = Vec::with_capacity(self.protected.len() + self.payload.len()); + ciborium::ser::into_writer(&value, &mut bytes).expect("can write bytes"); + bytes + } +} + +/// The AWS Nitro Attestation Document, see https://docs.aws.amazon.com/enclaves/latest/user/verify-root.html#doc-def +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub struct AttestationDocument { + module_id: String, + timestamp: u64, + digest: String, + pcrs: Vec>, + certificate: Vec, + cabundle: Vec>, + public_key: Option>, + user_data: Option>, + nonce: Option>, +} + +impl AttestationDocument { + /// Parse the payload of the attestation document, validate the cert based on timestamp, and the pcrs match. + /// Adapted from + pub fn parse_and_validate_payload( + payload: &Vec, + ) -> Result { + let document_data: ciborium::value::Value = ciborium::de::from_reader(payload.as_slice()) + .map_err(|err| { + NitroAttestationVerifyError::InvalidAttestationDoc(format!( + "cannot parse payload CBOR: {}", + err + )) + })?; + + let document_map = match document_data { + ciborium::value::Value::Map(map) => map, + _ => { + return Err(NitroAttestationVerifyError::InvalidAttestationDoc(format!( + "expected map, got {:?}", + document_data + ))) + } + }; + + let get_string = |key: &str| -> Result { + match document_map + .iter() + .find(|(k, _)| matches!(k, ciborium::value::Value::Text(s) if s == key)) + { + Some((_, ciborium::value::Value::Text(val))) => Ok(val.clone()), + _ => Err(NitroAttestationVerifyError::InvalidAttestationDoc(format!( + "cannot parse {}", + key + ))), + } + }; + + let get_bytes = |key: &str| -> Result, NitroAttestationVerifyError> { + match document_map + .iter() + .find(|(k, _)| matches!(k, ciborium::value::Value::Text(s) if s == key)) + { + Some((_, ciborium::value::Value::Bytes(val))) => Ok(val.clone()), + _ => Err(NitroAttestationVerifyError::InvalidAttestationDoc(format!( + "cannot parse {}", + key + ))), + } + }; + + let get_optional_bytes = |key: &str| -> Option> { + document_map + .iter() + .find(|(k, _)| matches!(k, ciborium::value::Value::Text(s) if s == key)) + .and_then(|(_, v)| match v { + ciborium::value::Value::Bytes(val) => Some(val.clone()), + _ => None, + }) + }; + + let module_id = get_string("module_id")?; + let digest = get_string("digest")?; + let certificate = get_bytes("certificate")?; + + let timestamp = match document_map + .iter() + .find(|(k, _)| matches!(k, ciborium::value::Value::Text(s) if s == "timestamp")) + { + Some((_, ciborium::value::Value::Integer(val))) => { + // Convert Integer to i128 first, then to u64 + let i128_val: i128 = (*val).into(); + u64::try_from(i128_val).map_err(|err| { + NitroAttestationVerifyError::InvalidAttestationDoc(format!( + "cannot convert timestamp to u64: {}", + err + )) + })? + } + _ => { + return Err(NitroAttestationVerifyError::InvalidAttestationDoc( + "cannot parse timestamp".to_string(), + )) + } + }; + + let public_key = get_optional_bytes("public_key"); + + let pcrs = match document_map + .iter() + .find(|(k, _)| matches!(k, ciborium::value::Value::Text(s) if s == "pcrs")) + { + Some((_, ciborium::value::Value::Map(pcr_map))) => { + let mut pcr_vec = Vec::new(); + for i in 0..pcr_map.len() { + if let Some((_, ciborium::value::Value::Bytes(val))) = pcr_map.iter().find( + |(k, _)| matches!(k, ciborium::value::Value::Integer(n) if *n == i.into()), + ) { + pcr_vec.push(val.clone()); + } else { + return Err(NitroAttestationVerifyError::InvalidAttestationDoc( + "invalid PCR format".to_string(), + )); + } + } + pcr_vec + } + _ => { + return Err(NitroAttestationVerifyError::InvalidAttestationDoc( + "cannot parse PCRs".to_string(), + )) + } + }; + + let user_data = get_optional_bytes("user_data"); + let nonce = get_optional_bytes("nonce"); + + let cabundle = match document_map + .iter() + .find(|(k, _)| matches!(k, ciborium::value::Value::Text(s) if s == "cabundle")) + { + Some((_, ciborium::value::Value::Array(arr))) => arr + .iter() + .map(|v| match v { + ciborium::value::Value::Bytes(bytes) => Ok(bytes.clone()), + _ => Err(NitroAttestationVerifyError::InvalidAttestationDoc( + "invalid cabundle format".to_string(), + )), + }) + .collect::, _>>()?, + _ => { + return Err(NitroAttestationVerifyError::InvalidAttestationDoc( + "cannot parse cabundle".to_string(), + )) + } + }; + + let doc = AttestationDocument { + module_id, + timestamp, + digest, + pcrs, + certificate, + cabundle, + public_key, + user_data, + nonce, + }; + Ok(doc) + } + + /// Verify the certificate against AWS Nitro root of trust and checks expiry. + fn validate_cert(&self, now: u64) -> Result<(), NitroAttestationVerifyError> { + // Create chain starting with leaf cert all the way to root. + let mut chain = Vec::with_capacity(1 + self.cabundle.len()); + chain.push(self.certificate.as_slice()); + chain.extend(self.cabundle.iter().rev().map(|cert| cert.as_slice())); + validate_cert_chain(&chain, now) + } +} + +/// Validate the certificate chain against the root of trust. +fn validate_cert_chain( + cert_chain: &[&[u8]], + now_ms: u64, +) -> Result<(), NitroAttestationVerifyError> { + if cert_chain.is_empty() || cert_chain.len() > MAX_CERT_CHAIN_LENGTH { + return Err(NitroAttestationVerifyError::InvalidCertificate( + "invalid certificate chain length".to_string(), + )); + } + + let root_cert = X509Certificate::from_der(ROOT_CERTIFICATE.as_slice()) + .map_err(|e| NitroAttestationVerifyError::InvalidCertificate(e.to_string()))? + .1; + + let now_secs = ASN1Time::from_timestamp(now_ms as i64 / 1000_i64) + .map_err(|e| NitroAttestationVerifyError::InvalidCertificate(e.to_string()))?; + + // Validate the chain starting from the leaf + for i in 0..cert_chain.len() { + let cert = X509Certificate::from_der(cert_chain[i]) + .map_err(|e| NitroAttestationVerifyError::InvalidCertificate(e.to_string()))? + .1; + + // Check timestamp validity + if !cert.validity().is_valid_at(now_secs) { + return Err(NitroAttestationVerifyError::InvalidCertificate( + "Certificate timestamp not valid".to_string(), + )); + } + + // Get issuer cert from either next in chain or root + let issuer_cert = if i < cert_chain.len() - 1 { + X509Certificate::from_der(cert_chain[i + 1]) + .map_err(|e| NitroAttestationVerifyError::InvalidCertificate(e.to_string()))? + .1 + } else { + root_cert.clone() + }; + + // Verify issuer/subject chaining + if cert.issuer() != issuer_cert.subject() { + return Err(NitroAttestationVerifyError::InvalidCertificate( + "certificate chain issuer mismatch".to_string(), + )); + } + + // Verify signature + cert.verify_signature(Some(issuer_cert.public_key())) + .map_err(|_| { + NitroAttestationVerifyError::InvalidCertificate( + "certificate fails to verify".to_string(), + ) + })?; + } + + Ok(()) +} diff --git a/crates/sui-types/src/nitro_root_certificate.pem b/crates/sui-types/src/nitro_root_certificate.pem new file mode 100644 index 0000000000000..221cc0b1d310f --- /dev/null +++ b/crates/sui-types/src/nitro_root_certificate.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYD +VQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4 +MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQL +DANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEG +BSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb +48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZE +h8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkF +R+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYC +MQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPW +rfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6N +IwLz3/Y= +-----END CERTIFICATE----- diff --git a/crates/sui-types/src/unit_tests/nitro_attestation_tests.rs b/crates/sui-types/src/unit_tests/nitro_attestation_tests.rs new file mode 100644 index 0000000000000..de5e193be2f20 --- /dev/null +++ b/crates/sui-types/src/unit_tests/nitro_attestation_tests.rs @@ -0,0 +1,59 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use crate::error::SuiError; + +use super::{parse_nitro_attestation_inner, verify_nitro_attestation_inner}; +use fastcrypto::encoding::Encoding; +use fastcrypto::encoding::Hex; + +#[test] +fn attestation_parse() { + let parsed = parse_nitro_attestation_inner(&Hex::decode("8444a1013822a0591121a9696d6f64756c655f69647827692d30663733613462346362373463633966322d656e633031393265343138386665663738316466646967657374665348413338346974696d657374616d701b000001932d1239ca6470637273b0005830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035830639a8b65f68b0223cbb14a0032487e5656d260434e3d1a10e7ec1407fb86143860717fc8afee90df7a1604111709af460458309ab5a1aba055ee41ee254b9b251a58259b29fa1096859762744e9ac73b5869b25e51223854d9f86adbb37fe69f3e5d1c0558300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000658300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000758300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000858300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000958300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b636572746966696361746559027e3082027a30820201a00302010202100192e4188fef781d0000000067366a8d300a06082a8648ce3d04030330818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343231323432365a170d3234313131353030323432395a308193310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753313e303c06035504030c35692d30663733613462346362373463633966322d656e63303139326534313838666566373831642e75732d656173742d312e6177733076301006072a8648ce3d020106052b810400220362000442e0526fc41af71feac64fc6f68a8ac8aae831a9e945ab7d482b842acaf05d6b762d00cbc2115da270187c44597b1c16dcf497c70e543b41612e9041ea143d11d58bd1c847496e5d41ec78a49fe445348cf9a47af9387e0451d9ec145b56ec12a31d301b300c0603551d130101ff04023000300b0603551d0f0404030206c0300a06082a8648ce3d0403030367003064023078001466c0c64293b9bde3d0834edb67ff18417f6075a8f7d137701e10164ce6cf45c508bf383ed0d8d41c51a5977a43023033cb8e4a6ad2686b86c2533accbab5dd5e98cf25d3612b1a48502f327ce00acc921641242d5a3a27d222df1f7dfc3e2c68636162756e646c65845902153082021130820196a003020102021100f93175681b90afe11d46ccb4e4e7f856300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3139313032383133323830355a170d3439313032383134323830355a3049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004fc0254eba608c1f36870e29ada90be46383292736e894bfff672d989444b5051e534a4b1f6dbe3c0bc581a32b7b176070ede12d69a3fea211b66e752cf7dd1dd095f6f1370f4170843d9dc100121e4cf63012809664487c9796284304dc53ff4a3423040300f0603551d130101ff040530030101ff301d0603551d0e041604149025b50dd90547e796c396fa729dcf99a9df4b96300e0603551d0f0101ff040403020186300a06082a8648ce3d0403030369003066023100a37f2f91a1c9bd5ee7b8627c1698d255038e1f0343f95b63a9628c3d39809545a11ebcbf2e3b55d8aeee71b4c3d6adf3023100a2f39b1605b27028a5dd4ba069b5016e65b4fbde8fe0061d6a53197f9cdaf5d943bc61fc2beb03cb6fee8d2302f3dff65902c2308202be30820245a003020102021100ab314210a819b4842e3be045e7daddbe300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3234313131333037333235355a170d3234313230333038333235355a3064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004cbd3e3fe8793852d952a214ee1c7f17e13eff238c5952ffc6c48f2b8e70beec10194585089829f4818d012a6061cdc9f4d8c5a67aada1233f75b65d3f7704e1c02460cfcc74f0e94193c8d4030f6d1662de0427836c1d32c571c919230fae73aa381d53081d230120603551d130101ff040830060101ff020102301f0603551d230418301680149025b50dd90547e796c396fa729dcf99a9df4b96301d0603551d0e04160414b5f0f617140aa7057c7977f361eee896fd9a58b4300e0603551d0f0101ff040403020186306c0603551d1f046530633061a05fa05d865b687474703a2f2f6177732d6e6974726f2d656e636c617665732d63726c2e73332e616d617a6f6e6177732e636f6d2f63726c2f61623439363063632d376436332d343262642d396539662d3539333338636236376638342e63726c300a06082a8648ce3d04030303670030640230038362cf11e189755d6a2306d728a7f356740eefe623d5e0e9e7c33c1b061ade2224127ac3a2e4bce60b43fc8c53326902306aceccf6f45a8d5c066bd10ce3ffaeeebdee56eedb86deb18ea22172c07196750924dd8f4656c70bd95eb6714cb8ecdd59031a308203163082029ba0030201020211009a0f4f29c1649826edb5b5f9f93b6326300a06082a8648ce3d0403033064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343034323230325a170d3234313132303033323230325a308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c653076301006072a8648ce3d020106052b810400220362000496f4565c489625767e8e2d3006ba06bd48ba3e384027a205b93d1ad4958128887c38ddbb2f4922888708ef0985e1e5d3bd73b33f86785ac66a204eed3a6b663686434f64e19fb39cd7b33068edb2108b79774a961e7080cb1b4eaa60a5e63e22a381ea3081e730120603551d130101ff040830060101ff020101301f0603551d23041830168014b5f0f617140aa7057c7977f361eee896fd9a58b4301d0603551d0e0416041484b6dc9994365b56081f5d1bc8ee21f58e45d7df300e0603551d0f0101ff0404030201863081800603551d1f047930773075a073a071866f687474703a2f2f63726c2d75732d656173742d312d6177732d6e6974726f2d656e636c617665732e73332e75732d656173742d312e616d617a6f6e6177732e636f6d2f63726c2f34396230376261342d303533622d346435622d616434612d3364626533653065396637652e63726c300a06082a8648ce3d0403030369003066023100d00c2999e66fbcce624d91aedf41f5532b04c300c86a61d78ed968716a7f7ff565e2c361f4f46fe5c5486a9d2bfe0d60023100bc46872a45820fb552b926d420d4f6a1be831bb26821d374e95bff5ed042b3313465b5b4cde79f16f6a57bd5b541353c5902c3308202bf30820245a003020102021500eaa3f0b662c2a61c96f94194fa33d5baf26eeb84300a06082a8648ce3d040303308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c65301e170d3234313131343130313032345a170d3234313131353130313032345a30818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b81040022036200040fe46adf864a558a00a9ca4b64ece5ba124ed1d29656a1f16ca71d0dc8fca56b0fb15aafd309f6258374e8c7b4a5b0521c76d1812a7873474dae9322aef1cd782db19fc2ece4d36fa08acbe65e4bec2a3cfe70960d179778ea7e7711f827b36ea366306430120603551d130101ff040830060101ff020100300e0603551d0f0101ff040403020204301d0603551d0e041604143e40d423bf86e9565c378487843389bd2f471a56301f0603551d2304183016801484b6dc9994365b56081f5d1bc8ee21f58e45d7df300a06082a8648ce3d0403030368003065023100c2767f29cc6e40e087617cf680d81e3b77962c29d8ace426b3c4a62a560354da73de6f80986d44da2593a3c268fea94302306056e2f3c88c30170c4940f578acc279a01fe689123e81def4f8c313e1f0cbc44a562a171d12810e847e441aee233f676a7075626c69635f6b6579f669757365725f6461746158205a264748a62368075d34b9494634a3e096e0e48f6647f965b81d2a653de684f2656e6f6e6365f65860284d57f029e1b3beb76455a607b9a86360d6451370f718a0d7bdcad729eea248c25461166ab684ad31fb52713918ee3e401d1b56251d6f9d85bf870e850e0b47559d17091778dbafc3d1989a94bd54c0991053675dcc3686402b189172aae196").unwrap()).unwrap(); + + let res = verify_nitro_attestation_inner(&parsed.0, &parsed.1, &parsed.2, 1731627987382); + assert!(res.is_ok()); +} + +#[test] +fn test_over_certificate_expiration() { + let now = 1731627987382 + 10 * 60 * 1000; // add 10 minute, still valid + let parsed = parse_nitro_attestation_inner(&Hex::decode("8444a1013822a0591121a9696d6f64756c655f69647827692d30663733613462346362373463633966322d656e633031393265343138386665663738316466646967657374665348413338346974696d657374616d701b000001932d1239ca6470637273b0005830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035830639a8b65f68b0223cbb14a0032487e5656d260434e3d1a10e7ec1407fb86143860717fc8afee90df7a1604111709af460458309ab5a1aba055ee41ee254b9b251a58259b29fa1096859762744e9ac73b5869b25e51223854d9f86adbb37fe69f3e5d1c0558300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000658300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000758300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000858300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000958300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b636572746966696361746559027e3082027a30820201a00302010202100192e4188fef781d0000000067366a8d300a06082a8648ce3d04030330818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343231323432365a170d3234313131353030323432395a308193310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753313e303c06035504030c35692d30663733613462346362373463633966322d656e63303139326534313838666566373831642e75732d656173742d312e6177733076301006072a8648ce3d020106052b810400220362000442e0526fc41af71feac64fc6f68a8ac8aae831a9e945ab7d482b842acaf05d6b762d00cbc2115da270187c44597b1c16dcf497c70e543b41612e9041ea143d11d58bd1c847496e5d41ec78a49fe445348cf9a47af9387e0451d9ec145b56ec12a31d301b300c0603551d130101ff04023000300b0603551d0f0404030206c0300a06082a8648ce3d0403030367003064023078001466c0c64293b9bde3d0834edb67ff18417f6075a8f7d137701e10164ce6cf45c508bf383ed0d8d41c51a5977a43023033cb8e4a6ad2686b86c2533accbab5dd5e98cf25d3612b1a48502f327ce00acc921641242d5a3a27d222df1f7dfc3e2c68636162756e646c65845902153082021130820196a003020102021100f93175681b90afe11d46ccb4e4e7f856300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3139313032383133323830355a170d3439313032383134323830355a3049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004fc0254eba608c1f36870e29ada90be46383292736e894bfff672d989444b5051e534a4b1f6dbe3c0bc581a32b7b176070ede12d69a3fea211b66e752cf7dd1dd095f6f1370f4170843d9dc100121e4cf63012809664487c9796284304dc53ff4a3423040300f0603551d130101ff040530030101ff301d0603551d0e041604149025b50dd90547e796c396fa729dcf99a9df4b96300e0603551d0f0101ff040403020186300a06082a8648ce3d0403030369003066023100a37f2f91a1c9bd5ee7b8627c1698d255038e1f0343f95b63a9628c3d39809545a11ebcbf2e3b55d8aeee71b4c3d6adf3023100a2f39b1605b27028a5dd4ba069b5016e65b4fbde8fe0061d6a53197f9cdaf5d943bc61fc2beb03cb6fee8d2302f3dff65902c2308202be30820245a003020102021100ab314210a819b4842e3be045e7daddbe300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3234313131333037333235355a170d3234313230333038333235355a3064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004cbd3e3fe8793852d952a214ee1c7f17e13eff238c5952ffc6c48f2b8e70beec10194585089829f4818d012a6061cdc9f4d8c5a67aada1233f75b65d3f7704e1c02460cfcc74f0e94193c8d4030f6d1662de0427836c1d32c571c919230fae73aa381d53081d230120603551d130101ff040830060101ff020102301f0603551d230418301680149025b50dd90547e796c396fa729dcf99a9df4b96301d0603551d0e04160414b5f0f617140aa7057c7977f361eee896fd9a58b4300e0603551d0f0101ff040403020186306c0603551d1f046530633061a05fa05d865b687474703a2f2f6177732d6e6974726f2d656e636c617665732d63726c2e73332e616d617a6f6e6177732e636f6d2f63726c2f61623439363063632d376436332d343262642d396539662d3539333338636236376638342e63726c300a06082a8648ce3d04030303670030640230038362cf11e189755d6a2306d728a7f356740eefe623d5e0e9e7c33c1b061ade2224127ac3a2e4bce60b43fc8c53326902306aceccf6f45a8d5c066bd10ce3ffaeeebdee56eedb86deb18ea22172c07196750924dd8f4656c70bd95eb6714cb8ecdd59031a308203163082029ba0030201020211009a0f4f29c1649826edb5b5f9f93b6326300a06082a8648ce3d0403033064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343034323230325a170d3234313132303033323230325a308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c653076301006072a8648ce3d020106052b810400220362000496f4565c489625767e8e2d3006ba06bd48ba3e384027a205b93d1ad4958128887c38ddbb2f4922888708ef0985e1e5d3bd73b33f86785ac66a204eed3a6b663686434f64e19fb39cd7b33068edb2108b79774a961e7080cb1b4eaa60a5e63e22a381ea3081e730120603551d130101ff040830060101ff020101301f0603551d23041830168014b5f0f617140aa7057c7977f361eee896fd9a58b4301d0603551d0e0416041484b6dc9994365b56081f5d1bc8ee21f58e45d7df300e0603551d0f0101ff0404030201863081800603551d1f047930773075a073a071866f687474703a2f2f63726c2d75732d656173742d312d6177732d6e6974726f2d656e636c617665732e73332e75732d656173742d312e616d617a6f6e6177732e636f6d2f63726c2f34396230376261342d303533622d346435622d616434612d3364626533653065396637652e63726c300a06082a8648ce3d0403030369003066023100d00c2999e66fbcce624d91aedf41f5532b04c300c86a61d78ed968716a7f7ff565e2c361f4f46fe5c5486a9d2bfe0d60023100bc46872a45820fb552b926d420d4f6a1be831bb26821d374e95bff5ed042b3313465b5b4cde79f16f6a57bd5b541353c5902c3308202bf30820245a003020102021500eaa3f0b662c2a61c96f94194fa33d5baf26eeb84300a06082a8648ce3d040303308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c65301e170d3234313131343130313032345a170d3234313131353130313032345a30818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b81040022036200040fe46adf864a558a00a9ca4b64ece5ba124ed1d29656a1f16ca71d0dc8fca56b0fb15aafd309f6258374e8c7b4a5b0521c76d1812a7873474dae9322aef1cd782db19fc2ece4d36fa08acbe65e4bec2a3cfe70960d179778ea7e7711f827b36ea366306430120603551d130101ff040830060101ff020100300e0603551d0f0101ff040403020204301d0603551d0e041604143e40d423bf86e9565c378487843389bd2f471a56301f0603551d2304183016801484b6dc9994365b56081f5d1bc8ee21f58e45d7df300a06082a8648ce3d0403030368003065023100c2767f29cc6e40e087617cf680d81e3b77962c29d8ace426b3c4a62a560354da73de6f80986d44da2593a3c268fea94302306056e2f3c88c30170c4940f578acc279a01fe689123e81def4f8c313e1f0cbc44a562a171d12810e847e441aee233f676a7075626c69635f6b6579f669757365725f6461746158205a264748a62368075d34b9494634a3e096e0e48f6647f965b81d2a653de684f2656e6f6e6365f65860284d57f029e1b3beb76455a607b9a86360d6451370f718a0d7bdcad729eea248c25461166ab684ad31fb52713918ee3e401d1b56251d6f9d85bf870e850e0b47559d17091778dbafc3d1989a94bd54c0991053675dcc3686402b189172aae196").unwrap()).unwrap(); + let res = verify_nitro_attestation_inner(&parsed.0, &parsed.1, &parsed.2, now); + assert!(res.is_ok()); + + let now = 1731627987382 - 10 * 60 * 1000; // substract 10 minute, still valid + let parsed = parse_nitro_attestation_inner(&Hex::decode("8444a1013822a0591121a9696d6f64756c655f69647827692d30663733613462346362373463633966322d656e633031393265343138386665663738316466646967657374665348413338346974696d657374616d701b000001932d1239ca6470637273b0005830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035830639a8b65f68b0223cbb14a0032487e5656d260434e3d1a10e7ec1407fb86143860717fc8afee90df7a1604111709af460458309ab5a1aba055ee41ee254b9b251a58259b29fa1096859762744e9ac73b5869b25e51223854d9f86adbb37fe69f3e5d1c0558300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000658300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000758300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000858300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000958300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b636572746966696361746559027e3082027a30820201a00302010202100192e4188fef781d0000000067366a8d300a06082a8648ce3d04030330818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343231323432365a170d3234313131353030323432395a308193310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753313e303c06035504030c35692d30663733613462346362373463633966322d656e63303139326534313838666566373831642e75732d656173742d312e6177733076301006072a8648ce3d020106052b810400220362000442e0526fc41af71feac64fc6f68a8ac8aae831a9e945ab7d482b842acaf05d6b762d00cbc2115da270187c44597b1c16dcf497c70e543b41612e9041ea143d11d58bd1c847496e5d41ec78a49fe445348cf9a47af9387e0451d9ec145b56ec12a31d301b300c0603551d130101ff04023000300b0603551d0f0404030206c0300a06082a8648ce3d0403030367003064023078001466c0c64293b9bde3d0834edb67ff18417f6075a8f7d137701e10164ce6cf45c508bf383ed0d8d41c51a5977a43023033cb8e4a6ad2686b86c2533accbab5dd5e98cf25d3612b1a48502f327ce00acc921641242d5a3a27d222df1f7dfc3e2c68636162756e646c65845902153082021130820196a003020102021100f93175681b90afe11d46ccb4e4e7f856300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3139313032383133323830355a170d3439313032383134323830355a3049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004fc0254eba608c1f36870e29ada90be46383292736e894bfff672d989444b5051e534a4b1f6dbe3c0bc581a32b7b176070ede12d69a3fea211b66e752cf7dd1dd095f6f1370f4170843d9dc100121e4cf63012809664487c9796284304dc53ff4a3423040300f0603551d130101ff040530030101ff301d0603551d0e041604149025b50dd90547e796c396fa729dcf99a9df4b96300e0603551d0f0101ff040403020186300a06082a8648ce3d0403030369003066023100a37f2f91a1c9bd5ee7b8627c1698d255038e1f0343f95b63a9628c3d39809545a11ebcbf2e3b55d8aeee71b4c3d6adf3023100a2f39b1605b27028a5dd4ba069b5016e65b4fbde8fe0061d6a53197f9cdaf5d943bc61fc2beb03cb6fee8d2302f3dff65902c2308202be30820245a003020102021100ab314210a819b4842e3be045e7daddbe300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3234313131333037333235355a170d3234313230333038333235355a3064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004cbd3e3fe8793852d952a214ee1c7f17e13eff238c5952ffc6c48f2b8e70beec10194585089829f4818d012a6061cdc9f4d8c5a67aada1233f75b65d3f7704e1c02460cfcc74f0e94193c8d4030f6d1662de0427836c1d32c571c919230fae73aa381d53081d230120603551d130101ff040830060101ff020102301f0603551d230418301680149025b50dd90547e796c396fa729dcf99a9df4b96301d0603551d0e04160414b5f0f617140aa7057c7977f361eee896fd9a58b4300e0603551d0f0101ff040403020186306c0603551d1f046530633061a05fa05d865b687474703a2f2f6177732d6e6974726f2d656e636c617665732d63726c2e73332e616d617a6f6e6177732e636f6d2f63726c2f61623439363063632d376436332d343262642d396539662d3539333338636236376638342e63726c300a06082a8648ce3d04030303670030640230038362cf11e189755d6a2306d728a7f356740eefe623d5e0e9e7c33c1b061ade2224127ac3a2e4bce60b43fc8c53326902306aceccf6f45a8d5c066bd10ce3ffaeeebdee56eedb86deb18ea22172c07196750924dd8f4656c70bd95eb6714cb8ecdd59031a308203163082029ba0030201020211009a0f4f29c1649826edb5b5f9f93b6326300a06082a8648ce3d0403033064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343034323230325a170d3234313132303033323230325a308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c653076301006072a8648ce3d020106052b810400220362000496f4565c489625767e8e2d3006ba06bd48ba3e384027a205b93d1ad4958128887c38ddbb2f4922888708ef0985e1e5d3bd73b33f86785ac66a204eed3a6b663686434f64e19fb39cd7b33068edb2108b79774a961e7080cb1b4eaa60a5e63e22a381ea3081e730120603551d130101ff040830060101ff020101301f0603551d23041830168014b5f0f617140aa7057c7977f361eee896fd9a58b4301d0603551d0e0416041484b6dc9994365b56081f5d1bc8ee21f58e45d7df300e0603551d0f0101ff0404030201863081800603551d1f047930773075a073a071866f687474703a2f2f63726c2d75732d656173742d312d6177732d6e6974726f2d656e636c617665732e73332e75732d656173742d312e616d617a6f6e6177732e636f6d2f63726c2f34396230376261342d303533622d346435622d616434612d3364626533653065396637652e63726c300a06082a8648ce3d0403030369003066023100d00c2999e66fbcce624d91aedf41f5532b04c300c86a61d78ed968716a7f7ff565e2c361f4f46fe5c5486a9d2bfe0d60023100bc46872a45820fb552b926d420d4f6a1be831bb26821d374e95bff5ed042b3313465b5b4cde79f16f6a57bd5b541353c5902c3308202bf30820245a003020102021500eaa3f0b662c2a61c96f94194fa33d5baf26eeb84300a06082a8648ce3d040303308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c65301e170d3234313131343130313032345a170d3234313131353130313032345a30818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b81040022036200040fe46adf864a558a00a9ca4b64ece5ba124ed1d29656a1f16ca71d0dc8fca56b0fb15aafd309f6258374e8c7b4a5b0521c76d1812a7873474dae9322aef1cd782db19fc2ece4d36fa08acbe65e4bec2a3cfe70960d179778ea7e7711f827b36ea366306430120603551d130101ff040830060101ff020100300e0603551d0f0101ff040403020204301d0603551d0e041604143e40d423bf86e9565c378487843389bd2f471a56301f0603551d2304183016801484b6dc9994365b56081f5d1bc8ee21f58e45d7df300a06082a8648ce3d0403030368003065023100c2767f29cc6e40e087617cf680d81e3b77962c29d8ace426b3c4a62a560354da73de6f80986d44da2593a3c268fea94302306056e2f3c88c30170c4940f578acc279a01fe689123e81def4f8c313e1f0cbc44a562a171d12810e847e441aee233f676a7075626c69635f6b6579f669757365725f6461746158205a264748a62368075d34b9494634a3e096e0e48f6647f965b81d2a653de684f2656e6f6e6365f65860284d57f029e1b3beb76455a607b9a86360d6451370f718a0d7bdcad729eea248c25461166ab684ad31fb52713918ee3e401d1b56251d6f9d85bf870e850e0b47559d17091778dbafc3d1989a94bd54c0991053675dcc3686402b189172aae196").unwrap()).unwrap(); + let res = verify_nitro_attestation_inner(&parsed.0, &parsed.1, &parsed.2, now); + assert!(res.is_ok()); + + let now = 1731627987382 + 3 * 60 * 60 * 1000; // add 3 hours, cert expired + let parsed = parse_nitro_attestation_inner(&Hex::decode("8444a1013822a0591121a9696d6f64756c655f69647827692d30663733613462346362373463633966322d656e633031393265343138386665663738316466646967657374665348413338346974696d657374616d701b000001932d1239ca6470637273b0005830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035830639a8b65f68b0223cbb14a0032487e5656d260434e3d1a10e7ec1407fb86143860717fc8afee90df7a1604111709af460458309ab5a1aba055ee41ee254b9b251a58259b29fa1096859762744e9ac73b5869b25e51223854d9f86adbb37fe69f3e5d1c0558300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000658300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000758300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000858300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000958300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b636572746966696361746559027e3082027a30820201a00302010202100192e4188fef781d0000000067366a8d300a06082a8648ce3d04030330818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343231323432365a170d3234313131353030323432395a308193310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753313e303c06035504030c35692d30663733613462346362373463633966322d656e63303139326534313838666566373831642e75732d656173742d312e6177733076301006072a8648ce3d020106052b810400220362000442e0526fc41af71feac64fc6f68a8ac8aae831a9e945ab7d482b842acaf05d6b762d00cbc2115da270187c44597b1c16dcf497c70e543b41612e9041ea143d11d58bd1c847496e5d41ec78a49fe445348cf9a47af9387e0451d9ec145b56ec12a31d301b300c0603551d130101ff04023000300b0603551d0f0404030206c0300a06082a8648ce3d0403030367003064023078001466c0c64293b9bde3d0834edb67ff18417f6075a8f7d137701e10164ce6cf45c508bf383ed0d8d41c51a5977a43023033cb8e4a6ad2686b86c2533accbab5dd5e98cf25d3612b1a48502f327ce00acc921641242d5a3a27d222df1f7dfc3e2c68636162756e646c65845902153082021130820196a003020102021100f93175681b90afe11d46ccb4e4e7f856300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3139313032383133323830355a170d3439313032383134323830355a3049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004fc0254eba608c1f36870e29ada90be46383292736e894bfff672d989444b5051e534a4b1f6dbe3c0bc581a32b7b176070ede12d69a3fea211b66e752cf7dd1dd095f6f1370f4170843d9dc100121e4cf63012809664487c9796284304dc53ff4a3423040300f0603551d130101ff040530030101ff301d0603551d0e041604149025b50dd90547e796c396fa729dcf99a9df4b96300e0603551d0f0101ff040403020186300a06082a8648ce3d0403030369003066023100a37f2f91a1c9bd5ee7b8627c1698d255038e1f0343f95b63a9628c3d39809545a11ebcbf2e3b55d8aeee71b4c3d6adf3023100a2f39b1605b27028a5dd4ba069b5016e65b4fbde8fe0061d6a53197f9cdaf5d943bc61fc2beb03cb6fee8d2302f3dff65902c2308202be30820245a003020102021100ab314210a819b4842e3be045e7daddbe300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3234313131333037333235355a170d3234313230333038333235355a3064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004cbd3e3fe8793852d952a214ee1c7f17e13eff238c5952ffc6c48f2b8e70beec10194585089829f4818d012a6061cdc9f4d8c5a67aada1233f75b65d3f7704e1c02460cfcc74f0e94193c8d4030f6d1662de0427836c1d32c571c919230fae73aa381d53081d230120603551d130101ff040830060101ff020102301f0603551d230418301680149025b50dd90547e796c396fa729dcf99a9df4b96301d0603551d0e04160414b5f0f617140aa7057c7977f361eee896fd9a58b4300e0603551d0f0101ff040403020186306c0603551d1f046530633061a05fa05d865b687474703a2f2f6177732d6e6974726f2d656e636c617665732d63726c2e73332e616d617a6f6e6177732e636f6d2f63726c2f61623439363063632d376436332d343262642d396539662d3539333338636236376638342e63726c300a06082a8648ce3d04030303670030640230038362cf11e189755d6a2306d728a7f356740eefe623d5e0e9e7c33c1b061ade2224127ac3a2e4bce60b43fc8c53326902306aceccf6f45a8d5c066bd10ce3ffaeeebdee56eedb86deb18ea22172c07196750924dd8f4656c70bd95eb6714cb8ecdd59031a308203163082029ba0030201020211009a0f4f29c1649826edb5b5f9f93b6326300a06082a8648ce3d0403033064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343034323230325a170d3234313132303033323230325a308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c653076301006072a8648ce3d020106052b810400220362000496f4565c489625767e8e2d3006ba06bd48ba3e384027a205b93d1ad4958128887c38ddbb2f4922888708ef0985e1e5d3bd73b33f86785ac66a204eed3a6b663686434f64e19fb39cd7b33068edb2108b79774a961e7080cb1b4eaa60a5e63e22a381ea3081e730120603551d130101ff040830060101ff020101301f0603551d23041830168014b5f0f617140aa7057c7977f361eee896fd9a58b4301d0603551d0e0416041484b6dc9994365b56081f5d1bc8ee21f58e45d7df300e0603551d0f0101ff0404030201863081800603551d1f047930773075a073a071866f687474703a2f2f63726c2d75732d656173742d312d6177732d6e6974726f2d656e636c617665732e73332e75732d656173742d312e616d617a6f6e6177732e636f6d2f63726c2f34396230376261342d303533622d346435622d616434612d3364626533653065396637652e63726c300a06082a8648ce3d0403030369003066023100d00c2999e66fbcce624d91aedf41f5532b04c300c86a61d78ed968716a7f7ff565e2c361f4f46fe5c5486a9d2bfe0d60023100bc46872a45820fb552b926d420d4f6a1be831bb26821d374e95bff5ed042b3313465b5b4cde79f16f6a57bd5b541353c5902c3308202bf30820245a003020102021500eaa3f0b662c2a61c96f94194fa33d5baf26eeb84300a06082a8648ce3d040303308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c65301e170d3234313131343130313032345a170d3234313131353130313032345a30818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b81040022036200040fe46adf864a558a00a9ca4b64ece5ba124ed1d29656a1f16ca71d0dc8fca56b0fb15aafd309f6258374e8c7b4a5b0521c76d1812a7873474dae9322aef1cd782db19fc2ece4d36fa08acbe65e4bec2a3cfe70960d179778ea7e7711f827b36ea366306430120603551d130101ff040830060101ff020100300e0603551d0f0101ff040403020204301d0603551d0e041604143e40d423bf86e9565c378487843389bd2f471a56301f0603551d2304183016801484b6dc9994365b56081f5d1bc8ee21f58e45d7df300a06082a8648ce3d0403030368003065023100c2767f29cc6e40e087617cf680d81e3b77962c29d8ace426b3c4a62a560354da73de6f80986d44da2593a3c268fea94302306056e2f3c88c30170c4940f578acc279a01fe689123e81def4f8c313e1f0cbc44a562a171d12810e847e441aee233f676a7075626c69635f6b6579f669757365725f6461746158205a264748a62368075d34b9494634a3e096e0e48f6647f965b81d2a653de684f2656e6f6e6365f65860284d57f029e1b3beb76455a607b9a86360d6451370f718a0d7bdcad729eea248c25461166ab684ad31fb52713918ee3e401d1b56251d6f9d85bf870e850e0b47559d17091778dbafc3d1989a94bd54c0991053675dcc3686402b189172aae196").unwrap()).unwrap(); + let res = verify_nitro_attestation_inner(&parsed.0, &parsed.1, &parsed.2, now); + assert_eq!( + res.unwrap_err(), + SuiError::AttestationFailedToVerify( + "InvalidCertificate: Certificate timestamp not valid".to_string() + ) + ); + + let now = 1731627987382 - 3 * 60 * 60 * 1000; // subtract 3 hours, cert is not valid yet + let parsed = parse_nitro_attestation_inner(&Hex::decode("8444a1013822a0591121a9696d6f64756c655f69647827692d30663733613462346362373463633966322d656e633031393265343138386665663738316466646967657374665348413338346974696d657374616d701b000001932d1239ca6470637273b0005830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035830639a8b65f68b0223cbb14a0032487e5656d260434e3d1a10e7ec1407fb86143860717fc8afee90df7a1604111709af460458309ab5a1aba055ee41ee254b9b251a58259b29fa1096859762744e9ac73b5869b25e51223854d9f86adbb37fe69f3e5d1c0558300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000658300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000758300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000858300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000958300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f58300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b636572746966696361746559027e3082027a30820201a00302010202100192e4188fef781d0000000067366a8d300a06082a8648ce3d04030330818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343231323432365a170d3234313131353030323432395a308193310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753313e303c06035504030c35692d30663733613462346362373463633966322d656e63303139326534313838666566373831642e75732d656173742d312e6177733076301006072a8648ce3d020106052b810400220362000442e0526fc41af71feac64fc6f68a8ac8aae831a9e945ab7d482b842acaf05d6b762d00cbc2115da270187c44597b1c16dcf497c70e543b41612e9041ea143d11d58bd1c847496e5d41ec78a49fe445348cf9a47af9387e0451d9ec145b56ec12a31d301b300c0603551d130101ff04023000300b0603551d0f0404030206c0300a06082a8648ce3d0403030367003064023078001466c0c64293b9bde3d0834edb67ff18417f6075a8f7d137701e10164ce6cf45c508bf383ed0d8d41c51a5977a43023033cb8e4a6ad2686b86c2533accbab5dd5e98cf25d3612b1a48502f327ce00acc921641242d5a3a27d222df1f7dfc3e2c68636162756e646c65845902153082021130820196a003020102021100f93175681b90afe11d46ccb4e4e7f856300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3139313032383133323830355a170d3439313032383134323830355a3049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004fc0254eba608c1f36870e29ada90be46383292736e894bfff672d989444b5051e534a4b1f6dbe3c0bc581a32b7b176070ede12d69a3fea211b66e752cf7dd1dd095f6f1370f4170843d9dc100121e4cf63012809664487c9796284304dc53ff4a3423040300f0603551d130101ff040530030101ff301d0603551d0e041604149025b50dd90547e796c396fa729dcf99a9df4b96300e0603551d0f0101ff040403020186300a06082a8648ce3d0403030369003066023100a37f2f91a1c9bd5ee7b8627c1698d255038e1f0343f95b63a9628c3d39809545a11ebcbf2e3b55d8aeee71b4c3d6adf3023100a2f39b1605b27028a5dd4ba069b5016e65b4fbde8fe0061d6a53197f9cdaf5d943bc61fc2beb03cb6fee8d2302f3dff65902c2308202be30820245a003020102021100ab314210a819b4842e3be045e7daddbe300a06082a8648ce3d0403033049310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c03415753311b301906035504030c126177732e6e6974726f2d656e636c61766573301e170d3234313131333037333235355a170d3234313230333038333235355a3064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b8104002203620004cbd3e3fe8793852d952a214ee1c7f17e13eff238c5952ffc6c48f2b8e70beec10194585089829f4818d012a6061cdc9f4d8c5a67aada1233f75b65d3f7704e1c02460cfcc74f0e94193c8d4030f6d1662de0427836c1d32c571c919230fae73aa381d53081d230120603551d130101ff040830060101ff020102301f0603551d230418301680149025b50dd90547e796c396fa729dcf99a9df4b96301d0603551d0e04160414b5f0f617140aa7057c7977f361eee896fd9a58b4300e0603551d0f0101ff040403020186306c0603551d1f046530633061a05fa05d865b687474703a2f2f6177732d6e6974726f2d656e636c617665732d63726c2e73332e616d617a6f6e6177732e636f6d2f63726c2f61623439363063632d376436332d343262642d396539662d3539333338636236376638342e63726c300a06082a8648ce3d04030303670030640230038362cf11e189755d6a2306d728a7f356740eefe623d5e0e9e7c33c1b061ade2224127ac3a2e4bce60b43fc8c53326902306aceccf6f45a8d5c066bd10ce3ffaeeebdee56eedb86deb18ea22172c07196750924dd8f4656c70bd95eb6714cb8ecdd59031a308203163082029ba0030201020211009a0f4f29c1649826edb5b5f9f93b6326300a06082a8648ce3d0403033064310b3009060355040613025553310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533136303406035504030c2d343834633637303131656563376235332e75732d656173742d312e6177732e6e6974726f2d656e636c61766573301e170d3234313131343034323230325a170d3234313132303033323230325a308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c653076301006072a8648ce3d020106052b810400220362000496f4565c489625767e8e2d3006ba06bd48ba3e384027a205b93d1ad4958128887c38ddbb2f4922888708ef0985e1e5d3bd73b33f86785ac66a204eed3a6b663686434f64e19fb39cd7b33068edb2108b79774a961e7080cb1b4eaa60a5e63e22a381ea3081e730120603551d130101ff040830060101ff020101301f0603551d23041830168014b5f0f617140aa7057c7977f361eee896fd9a58b4301d0603551d0e0416041484b6dc9994365b56081f5d1bc8ee21f58e45d7df300e0603551d0f0101ff0404030201863081800603551d1f047930773075a073a071866f687474703a2f2f63726c2d75732d656173742d312d6177732d6e6974726f2d656e636c617665732e73332e75732d656173742d312e616d617a6f6e6177732e636f6d2f63726c2f34396230376261342d303533622d346435622d616434612d3364626533653065396637652e63726c300a06082a8648ce3d0403030369003066023100d00c2999e66fbcce624d91aedf41f5532b04c300c86a61d78ed968716a7f7ff565e2c361f4f46fe5c5486a9d2bfe0d60023100bc46872a45820fb552b926d420d4f6a1be831bb26821d374e95bff5ed042b3313465b5b4cde79f16f6a57bd5b541353c5902c3308202bf30820245a003020102021500eaa3f0b662c2a61c96f94194fa33d5baf26eeb84300a06082a8648ce3d040303308189313c303a06035504030c33373532313933346262636164353432622e7a6f6e616c2e75732d656173742d312e6177732e6e6974726f2d656e636c61766573310c300a060355040b0c03415753310f300d060355040a0c06416d617a6f6e310b3009060355040613025553310b300906035504080c0257413110300e06035504070c0753656174746c65301e170d3234313131343130313032345a170d3234313131353130313032345a30818e310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3110300e06035504070c0753656174746c65310f300d060355040a0c06416d617a6f6e310c300a060355040b0c034157533139303706035504030c30692d30663733613462346362373463633966322e75732d656173742d312e6177732e6e6974726f2d656e636c617665733076301006072a8648ce3d020106052b81040022036200040fe46adf864a558a00a9ca4b64ece5ba124ed1d29656a1f16ca71d0dc8fca56b0fb15aafd309f6258374e8c7b4a5b0521c76d1812a7873474dae9322aef1cd782db19fc2ece4d36fa08acbe65e4bec2a3cfe70960d179778ea7e7711f827b36ea366306430120603551d130101ff040830060101ff020100300e0603551d0f0101ff040403020204301d0603551d0e041604143e40d423bf86e9565c378487843389bd2f471a56301f0603551d2304183016801484b6dc9994365b56081f5d1bc8ee21f58e45d7df300a06082a8648ce3d0403030368003065023100c2767f29cc6e40e087617cf680d81e3b77962c29d8ace426b3c4a62a560354da73de6f80986d44da2593a3c268fea94302306056e2f3c88c30170c4940f578acc279a01fe689123e81def4f8c313e1f0cbc44a562a171d12810e847e441aee233f676a7075626c69635f6b6579f669757365725f6461746158205a264748a62368075d34b9494634a3e096e0e48f6647f965b81d2a653de684f2656e6f6e6365f65860284d57f029e1b3beb76455a607b9a86360d6451370f718a0d7bdcad729eea248c25461166ab684ad31fb52713918ee3e401d1b56251d6f9d85bf870e850e0b47559d17091778dbafc3d1989a94bd54c0991053675dcc3686402b189172aae196").unwrap()).unwrap(); + let res = verify_nitro_attestation_inner(&parsed.0, &parsed.1, &parsed.2, now); + assert_eq!( + res.unwrap_err(), + SuiError::AttestationFailedToVerify( + "InvalidCertificate: Certificate timestamp not valid".to_string() + ) + ); +} + +#[test] +fn test_with_malformed_attestation() { + let err = parse_nitro_attestation_inner(&Hex::decode("0000").unwrap()).unwrap_err(); + + assert!(matches!( + err, + SuiError::AttestationFailedToVerify(msg) if msg.starts_with("InvalidCoseSign1") + )); +} diff --git a/external-crates/move/crates/move-vm-types/src/natives/function.rs b/external-crates/move/crates/move-vm-types/src/natives/function.rs index d6bf71a2809a5..52e091792166a 100644 --- a/external-crates/move/crates/move-vm-types/src/natives/function.rs +++ b/external-crates/move/crates/move-vm-types/src/natives/function.rs @@ -89,7 +89,7 @@ impl NativeResult { Err(err) if err.major_status() == StatusCode::ABORTED => { let (_, abort_code, _, _, _, _) = err.all_data(); NativeResult::err( - cost, + cost, abort_code.unwrap_or(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR as u64), ) } diff --git a/sui-execution/latest/sui-move-natives/src/crypto/mod.rs b/sui-execution/latest/sui-move-natives/src/crypto/mod.rs index c77afbd81f24e..6303f68c5a05b 100644 --- a/sui-execution/latest/sui-move-natives/src/crypto/mod.rs +++ b/sui-execution/latest/sui-move-natives/src/crypto/mod.rs @@ -10,6 +10,7 @@ pub mod groth16; pub mod group_ops; pub mod hash; pub mod hmac; +pub mod nitro_attestation; pub mod poseidon; pub mod vdf; pub mod zklogin; diff --git a/sui-execution/latest/sui-move-natives/src/crypto/nitro_attestation.rs b/sui-execution/latest/sui-move-natives/src/crypto/nitro_attestation.rs new file mode 100644 index 0000000000000..628bdb1d85715 --- /dev/null +++ b/sui-execution/latest/sui-move-natives/src/crypto/nitro_attestation.rs @@ -0,0 +1,110 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use move_binary_format::errors::PartialVMResult; +use move_core_types::gas_algebra::InternalGas; +use move_vm_runtime::native_functions::NativeContext; +use move_vm_types::{ + loaded_data::runtime_types::Type, + natives::function::NativeResult, + pop_arg, + values::{Value, VectorRef}, +}; +use smallvec::smallvec; +use std::collections::VecDeque; +use sui_types::nitro_attestation::{parse_nitro_attestation_inner, verify_nitro_attestation_inner}; + +use crate::{object_runtime::ObjectRuntime, NativesCostTable}; +use move_vm_runtime::native_charge_gas_early_exit; + +pub const NOT_SUPPORTED_ERROR: u64 = 0; +pub const PARSE_ERROR: u64 = 1; +pub const VERIFY_ERROR: u64 = 2; +// Gas related structs and functions. + +#[derive(Clone)] +pub struct NitroAttestationCostParams { + pub parse_cost: Option, + pub verify_base_cost: Option, + pub verify_cost_per_cert: Option, +} + +macro_rules! native_charge_gas_early_exit_option { + ($native_context:ident, $cost:expr) => {{ + use move_binary_format::errors::PartialVMError; + use move_core_types::vm_status::StatusCode; + native_charge_gas_early_exit!( + $native_context, + $cost.ok_or_else(|| { + PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) + .with_message("Gas cost for group ops is missing".to_string()) + })? + ); + }}; +} + +fn is_supported(context: &NativeContext) -> bool { + context + .extensions() + .get::() + .protocol_config + .enable_nitro_attestation() +} + +pub fn verify_nitro_attestation_internal( + context: &mut NativeContext, + ty_args: Vec, + mut args: VecDeque, +) -> PartialVMResult { + debug_assert!(ty_args.is_empty()); + debug_assert!(args.len() == 2); + + let cost = context.gas_used(); + if !is_supported(context) { + return Ok(NativeResult::err(cost, NOT_SUPPORTED_ERROR)); + } + + let current_timestamp = pop_arg!(args, u64); + let attestation_ref = pop_arg!(args, VectorRef); + let attestation_bytes = attestation_ref.as_bytes_ref(); + + let cost_params = &context + .extensions() + .get::() + .nitro_attestation_cost_params + .clone(); + + match parse_nitro_attestation_inner(&attestation_bytes) { + Ok((signature, signed_message, payload)) => { + native_charge_gas_early_exit_option!(context, cost_params.parse_cost); + let cert_chain_length = payload.cabundle.len(); + native_charge_gas_early_exit_option!( + context, + cost_params + .verify_base_cost + .and_then(|base_cost| cost_params + .verify_cost_per_cert + .map(|per_byte| base_cost + per_byte * (cert_chain_length as u64).into())) + ); + match verify_nitro_attestation_inner( + &signature, + &signed_message, + &payload, + current_timestamp, + ) { + Ok(()) => Ok(NativeResult::ok( + context.gas_used(), + smallvec![Value::vector_for_testing_only( + payload + .pcrs + .iter() + .map(|pcr| Value::vector_u8(pcr.to_vec())) + .collect::>() + )], + )), + Err(_) => Ok(NativeResult::err(context.gas_used(), VERIFY_ERROR)), + } + } + Err(_) => Ok(NativeResult::err(context.gas_used(), PARSE_ERROR)), + } +} diff --git a/sui-execution/latest/sui-move-natives/src/lib.rs b/sui-execution/latest/sui-move-natives/src/lib.rs index 193d2f1d51935..6a7fd640d1b76 100644 --- a/sui-execution/latest/sui-move-natives/src/lib.rs +++ b/sui-execution/latest/sui-move-natives/src/lib.rs @@ -41,6 +41,7 @@ use crate::crypto::poseidon::PoseidonBN254CostParams; use crate::crypto::zklogin; use crate::crypto::zklogin::{CheckZkloginIdCostParams, CheckZkloginIssuerCostParams}; use better_any::{Tid, TidAble}; +use crypto::nitro_attestation::{self, NitroAttestationCostParams}; use crypto::vdf::{self, VDFCostParams}; use move_binary_format::errors::{PartialVMError, PartialVMResult}; use move_core_types::{ @@ -167,6 +168,9 @@ pub struct NativesCostTable { // Receive object pub transfer_receive_object_internal_cost_params: TransferReceiveObjectInternalCostParams, + + // nitro attestation + pub nitro_attestation_cost_params: NitroAttestationCostParams, } impl NativesCostTable { @@ -651,6 +655,17 @@ impl NativesCostTable { .vdf_hash_to_input_cost_as_option() .map(Into::into), }, + nitro_attestation_cost_params: NitroAttestationCostParams { + parse_cost: protocol_config + .nitro_attestation_parse_cost_as_option() + .map(Into::into), + verify_base_cost: protocol_config + .nitro_attestation_verify_base_cost_as_option() + .map(Into::into), + verify_cost_per_cert: protocol_config + .nitro_attestation_verify_cost_per_cert_as_option() + .map(Into::into), + }, } } } @@ -1063,6 +1078,11 @@ pub fn all_natives(silent: bool, protocol_config: &ProtocolConfig) -> NativeFunc "secp256k1_keypair_from_seed", make_native!(ecdsa_k1::secp256k1_keypair_from_seed), ), + ( + "nitro_attestation", + "verify_nitro_attestation_internal", + make_native!(nitro_attestation::verify_nitro_attestation_internal), + ), ]; let sui_framework_natives_iter = sui_framework_natives