diff --git a/Cargo.lock b/Cargo.lock index a751d40..2ac8894 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -335,6 +335,12 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "asn1_der" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "155a5a185e42c6b77ac7b88a15143d930a9e9727a5b7b77eed417404ab15c247" + [[package]] name = "async-priority-channel" version = "0.2.0" @@ -571,6 +577,18 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "blake2" version = "0.10.6" @@ -643,6 +661,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "bytemuck" version = "1.18.0" @@ -777,6 +801,33 @@ dependencies = [ "serde", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half 2.4.1", +] + [[package]] name = "cipher" version = "0.4.4" @@ -1395,6 +1446,35 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +[[package]] +name = "dcap-qvl" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce457039c23109abe934b0b255e932c1077eee32eeafb87d2b8a930622e59cf0" +dependencies = [ + "anyhow", + "asn1_der", + "base64 0.21.7", + "byteorder", + "chrono", + "const-oid", + "der", + "futures", + "hex", + "log", + "parity-scale-codec", + "pem", + "reqwest 0.11.27", + "ring 0.16.20", + "rustls-webpki 0.102.8", + "scale-info", + "serde", + "serde_json", + "tracing", + "urlencoding", + "x509-cert", +] + [[package]] name = "der" version = "0.7.9" @@ -1705,6 +1785,18 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "env_filter" version = "0.1.2" @@ -1888,6 +1980,12 @@ dependencies = [ "libc", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.30" @@ -2401,6 +2499,16 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -2453,6 +2561,51 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hickory-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "hkdf" version = "0.12.4" @@ -2480,6 +2633,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.12" @@ -2628,7 +2792,7 @@ dependencies = [ "tokio", "tokio-rustls 0.26.0", "tower-service", - "webpki-roots", + "webpki-roots 0.26.5", ] [[package]] @@ -2687,6 +2851,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.5.0" @@ -2732,6 +2906,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "indenter" version = "0.3.3" @@ -2816,6 +3001,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + [[package]] name = "ipnet" version = "2.10.0" @@ -3039,6 +3236,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -3118,6 +3321,21 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matchers" version = "0.1.0" @@ -3607,6 +3825,32 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "parking" version = "2.2.1" @@ -3720,6 +3964,16 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3aeb8f54c078314c2065ee649a7241f46b9d8e418e1a9581ba0546657d7aa3a" +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -3938,6 +4192,25 @@ dependencies = [ "elliptic-curve", ] +[[package]] +name = "print-fmspc" +version = "0.1.0" +dependencies = [ + "dcap-qvl", + "hex", + "serde_json", + "tokio", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -4138,20 +4411,42 @@ dependencies = [ name = "quartz-cw" version = "0.1.0" dependencies = [ + "ciborium", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus", "hex", "k256", + "quartz-dcap-verifier-msgs", "quartz-tee-ra", "serde", "serde_json", "serde_with", "sha2 0.10.8", - "tcbinfo", + "tcbinfo-msgs", "thiserror", ] +[[package]] +name = "quartz-dcap-verifier" +version = "0.1.0" +dependencies = [ + "ciborium", + "cosmwasm-schema", + "cosmwasm-std", + "getrandom", + "quartz-dcap-verifier-msgs", + "quartz-tee-ra", +] + +[[package]] +name = "quartz-dcap-verifier-msgs" +version = "0.1.0" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", +] + [[package]] name = "quartz-enclave" version = "0.1.0" @@ -4167,11 +4462,13 @@ dependencies = [ "futures-util", "hex", "k256", + "mc-sgx-dcap-sys-types", "mtcs", "quartz-cw", "quartz-proto", "quartz-tee-ra", "rand", + "reqwest 0.12.7", "serde", "serde_json", "sha2 0.10.8", @@ -4183,6 +4480,7 @@ dependencies = [ "tokio", "tonic", "tower 0.5.1", + "urlencoding", ] [[package]] @@ -4201,7 +4499,6 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "der", - "displaydoc", "hex", "hex-literal", "mc-attestation-verifier", @@ -4215,9 +4512,14 @@ dependencies = [ "thiserror", "x509-cert", "x509-parser", - "zeroize", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quinn" version = "0.11.5" @@ -4244,7 +4546,7 @@ checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand", - "ring", + "ring 0.17.8", "rustc-hash", "rustls 0.23.13", "slab", @@ -4275,6 +4577,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "radix_trie" version = "0.2.1" @@ -4425,6 +4733,7 @@ dependencies = [ "futures-core", "futures-util", "h2 0.3.26", + "hickory-resolver", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.30", @@ -4451,6 +4760,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 0.25.4", "winreg", ] @@ -4462,6 +4772,7 @@ checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" dependencies = [ "base64 0.22.1", "bytes", + "futures-channel", "futures-core", "futures-util", "http 1.1.0", @@ -4492,10 +4803,20 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.26.5", "windows-registry", ] +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -4534,6 +4855,21 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + [[package]] name = "ring" version = "0.17.8" @@ -4544,8 +4880,8 @@ dependencies = [ "cfg-if", "getrandom", "libc", - "spin", - "untrusted", + "spin 0.9.8", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -4608,7 +4944,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring", + "ring 0.17.8", "rustls-webpki 0.101.7", "sct", ] @@ -4620,7 +4956,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", - "ring", + "ring 0.17.8", "rustls-pki-types", "rustls-webpki 0.102.8", "subtle", @@ -4634,7 +4970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "once_cell", - "ring", + "ring 0.17.8", "rustls-pki-types", "rustls-webpki 0.102.8", "subtle", @@ -4697,8 +5033,8 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -4707,9 +5043,9 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "ring", + "ring 0.17.8", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -4743,6 +5079,31 @@ dependencies = [ "regex", ] +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more 0.99.18", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "schannel" version = "0.1.24" @@ -4788,8 +5149,8 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -4871,7 +5232,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ - "half", + "half 1.8.3", "serde", ] @@ -4903,6 +5264,7 @@ version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ + "indexmap 2.5.0", "itoa", "memchr", "ryu", @@ -5102,6 +5464,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" @@ -5226,6 +5594,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "target-lexicon" version = "0.12.16" @@ -5250,10 +5624,18 @@ dependencies = [ "schemars", "serde", "serde_json", + "tcbinfo-msgs", "thiserror", "x509-cert", ] +[[package]] +name = "tcbinfo-msgs" +version = "0.1.0" +dependencies = [ + "cosmwasm-schema", +] + [[package]] name = "tempfile" version = "3.10.1" @@ -5976,6 +6358,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -5989,10 +6377,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", - "idna", + "idna 0.5.0", "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf-8" version = "0.7.6" @@ -6203,6 +6597,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + [[package]] name = "webpki-roots" version = "0.26.5" @@ -6224,6 +6624,12 @@ dependencies = [ "winsafe", ] +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -6511,6 +6917,15 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x509-cert" version = "0.2.5" @@ -6534,7 +6949,7 @@ dependencies = [ "lazy_static", "nom", "oid-registry", - "ring", + "ring 0.17.8", "rusticata-macros", "thiserror", "time", diff --git a/Cargo.toml b/Cargo.toml index 2d312e8..c4216bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,8 @@ authors = ["Informal Systems "] anyhow = { version = "1.0.86", features = ["std", "backtrace"] } async-trait = { version = "0.1.79", default-features = false } bip32 = { version = "0.5.1", default-features = false, features = ["alloc", "secp256k1", "bip39"] } -cargo-generate = "0.21.3" +ciborium = { version = "0.2.2", default-features = false } +cargo-generate = { version = "0.21.3", default-features = false } clap = { version = "4.1.8", default-features = false, features = ["derive", "std"] } color-eyre = { version = "0.6.2", default-features = false } der = { version = "0.7.9", default-features = false } @@ -37,10 +38,12 @@ hex = { version = "0.4.3", default-features = false } hex-literal = { version = "0.4.1", default-features = false } k256 = { version = "0.13.2", default-features = false, features = ["ecdsa", "alloc"] } num-bigint = { version = "0.4.4", default-features = false } +p256 = { version = "0.13.2", default-features = false } prost = { version = "0.13.1", default-features = false } rand = { version = "0.8.5", default-features = false, features = ["getrandom"] } rand_core = { version = "0.6", default-features = false, features = ["std"] } reqwest = { version = "0.12.2", default-features = false, features = ["json", "rustls-tls"] } +schemars = { version = "0.8.16", default-features = false } serde = { version = "1.0.203", default-features = false, features = ["derive"] } serde_json = { version = "1.0.94", default-features = false, features = ["alloc"] } serde_with = { version = "3.4.0", default-features = false, features = ["hex", "macros"] } @@ -54,17 +57,19 @@ tonic-build = { version = "=0.12.1", default-features = false, features = ["pros tower = { version = "0.5.0" } tracing = { version = "0.1.39", default-features = false } tracing-subscriber = { version = "0.3.17", default-features = false, features = ["fmt"] } +urlencoding = { version = "2.1.3", default-features = false } uuid = { version = "1.4.1", default-features = false, features = ["serde"] } x509-cert = { version = "0.2.5", default-features = false } -x509-parser = { version = "0.16.0", features = ["default", "verify"] } +x509-parser = { version = "0.16.0", default-features = false, features = ["verify"] } zeroize = { version = "1.7.0", default-features = false } # cosmos -cosmos-sdk-proto = { version = "0.22.0" } +cosmos-sdk-proto = { version = "0.22.0", default-features = false } cosmrs = { version = "=0.17.0", default-features = false } cosmwasm-schema = { version = "2.1.1", default-features = false } -cosmwasm-std = { version = "2.1.1", default-features = false, features = ["std"] } +cosmwasm-std = { version = "2.1.1", default-features = false, features = ["std", "abort"] } cw-storage-plus = { version = "2.0.0", default-features = false } +cw2 = { version = "2.0.0", default-features = false } ics23 = { version = "0.12.0", default-features = false, features = ["host-functions"] } tendermint = { version = "=0.38.1", default-features = false } tendermint-light-client = { version = "=0.38.1", default-features = false, features = ["rust-crypto"] } @@ -79,12 +84,14 @@ mc-attestation-verifier = { git = "https://github.com/informalsystems/attestatio # quartz cw-proof = { path = "core/light-client-proofs/cw-proof", default-features = false } -quartz-common = { path = "core/quartz-common" } +quartz-common = { path = "core/quartz-common", default-features = false } quartz-cw = { path = "cosmwasm/packages/quartz-cw", default-features = false } +quartz-dcap-verifier-msgs = { path = "cosmwasm/packages/quartz-dcap-verifier/msgs", default-features = false } quartz-enclave = { path = "core/quartz", default-features = false } quartz-proto = { path = "core/quartz-proto", default-features = false } quartz-tee-ra = { path = "cosmwasm/packages/quartz-tee-ra", default-features = false } -tcbinfo = { path = "cosmwasm/packages/tcbinfo", features = ["library"] } +tcbinfo = { path = "cosmwasm/packages/tcbinfo", default-features = false, features = ["library"] } +tcbinfo-msgs = { path = "cosmwasm/packages/tcbinfo/msgs", default-features = false } tm-prover = { path = "utils/tm-prover", default-features = false } tm-stateless-verifier = { path = "core/light-client-proofs/tm-stateless-verifier", default-features = false } wasmd-client = { path = "cosmwasm/packages/wasmd-client", default-features = false } @@ -92,10 +99,10 @@ wasmd-client = { path = "cosmwasm/packages/wasmd-client", default-features = fal # quartz apps cw-tee-mtcs = { path = "apps/mtcs/contracts/cw-tee-mtcs", default-features = false } mtcs = { git = "ssh://git@github.com/informalsystems/mtcs.git", default-features = false } -mtcs-enclave = { path = "apps/mtcs/enclave" } +mtcs-enclave = { path = "apps/mtcs/enclave", default-features = false } [profile.release] -opt-level = 3 +opt-level = "z" debug = false rpath = false lto = true diff --git a/apps/mtcs/contracts/cw-tee-mtcs/Cargo.lock b/apps/mtcs/contracts/cw-tee-mtcs/Cargo.lock index 44b12f4..fe8ba28 100644 --- a/apps/mtcs/contracts/cw-tee-mtcs/Cargo.lock +++ b/apps/mtcs/contracts/cw-tee-mtcs/Cargo.lock @@ -280,6 +280,33 @@ dependencies = [ "serde", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -407,6 +434,12 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -841,6 +874,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.13.2" @@ -1205,20 +1248,30 @@ dependencies = [ name = "quartz-cw" version = "0.1.0" dependencies = [ + "ciborium", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus", "hex", "k256", + "quartz-dcap-verifier-msgs", "quartz-tee-ra", "serde", "serde_json", "serde_with", "sha2", - "tcbinfo", + "tcbinfo-msgs", "thiserror", ] +[[package]] +name = "quartz-dcap-verifier-msgs" +version = "0.1.0" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", +] + [[package]] name = "quartz-tee-ra" version = "0.1.0" @@ -1226,11 +1279,8 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "der", - "displaydoc", "hex-literal", "mc-attestation-verifier", - "mc-sgx-core-types", - "mc-sgx-dcap-sys-types", "mc-sgx-dcap-types", "num-bigint", "serde", @@ -1239,7 +1289,6 @@ dependencies = [ "thiserror", "x509-cert", "x509-parser", - "zeroize", ] [[package]] @@ -1568,24 +1617,10 @@ dependencies = [ ] [[package]] -name = "tcbinfo" +name = "tcbinfo-msgs" version = "0.1.0" dependencies = [ "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus", - "cw2", - "der", - "getrandom", - "hex", - "mc-attestation-verifier", - "p256", - "quartz-tee-ra", - "schemars", - "serde", - "serde_json", - "thiserror", - "x509-cert", ] [[package]] diff --git a/apps/mtcs/contracts/cw-tee-mtcs/Cargo.toml b/apps/mtcs/contracts/cw-tee-mtcs/Cargo.toml index 3052f2d..3cd5454 100644 --- a/apps/mtcs/contracts/cw-tee-mtcs/Cargo.toml +++ b/apps/mtcs/contracts/cw-tee-mtcs/Cargo.toml @@ -13,7 +13,7 @@ path = "bin/schema.rs" crate-type = ["cdylib", "rlib"] [profile.release] -opt-level = 3 +opt-level = "z" debug = false rpath = false lto = true @@ -38,14 +38,14 @@ thiserror = { version = "1.0.49" } # cosmwasm cosmwasm-schema = { version = "2.1.1", default-features = false } -cosmwasm-std = { version = "2.1.1", default-features = false, features = ["std"] } +cosmwasm-std = { version = "2.1.1", default-features = false, features = ["std", "abort"] } cw-storage-plus = { version = "2.0.0", default-features = false } cw20-base = { version = "2.0.0", features = ["library"] } cw20 = "2.0.0" cw2 = "2.0.0" # quartz -quartz-common = { path = "../../../../core/quartz-common", features = ["contract"]} +quartz-common = { path = "../../../../core/quartz-common", features = ["contract"] } # patch indirect deps getrandom = { version = "0.2.15", features = ["js"] } diff --git a/apps/mtcs/contracts/cw-tee-mtcs/src/lib.rs b/apps/mtcs/contracts/cw-tee-mtcs/src/lib.rs index eca0b7f..f6258e2 100644 --- a/apps/mtcs/contracts/cw-tee-mtcs/src/lib.rs +++ b/apps/mtcs/contracts/cw-tee-mtcs/src/lib.rs @@ -5,8 +5,7 @@ // unused_import_braces, // unused_qualifications // )] -// #![forbid(unsafe_code)] - +#![forbid(unsafe_code)] pub mod contract; mod error; pub mod msg; diff --git a/apps/mtcs/contracts/cw-tee-mtcs/src/msg.rs b/apps/mtcs/contracts/cw-tee-mtcs/src/msg.rs index 2894f71..c484871 100644 --- a/apps/mtcs/contracts/cw-tee-mtcs/src/msg.rs +++ b/apps/mtcs/contracts/cw-tee-mtcs/src/msg.rs @@ -19,7 +19,7 @@ pub struct InstantiateMsg { #[cw_serde] #[allow(clippy::large_enum_variant)] pub enum ExecuteMsg { - Quartz(QuartzExecuteMsg), + Quartz(QuartzExecuteMsg), FaucetMint(execute::FaucetMintMsg), Transfer(execute::Cw20Transfer), SubmitObligation(execute::SubmitObligationMsg), @@ -184,30 +184,13 @@ mod tests { "max_clock_drift": 5, "max_block_lag": 5 }, - "tcbinfo_contract": "wasm14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s0phg4d" + "tcbinfo_contract": "wasm14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s0phg4d", + "dcap_verifier_contract": "wasm14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s0phg4d" } }, "attestation": { - "report": { - "report": { - "id": "5246688123689513540899231107533660789", - "timestamp": "2024-02-07T17:06:23.913745", - "version": 4, - "epidPseudonym": "+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=", - "advisoryURL": "https://security-center.intel.com", - "advisoryIDs": [ - "INTEL-SA-00161", - "INTEL-SA-00219", - "INTEL-SA-00289", - "INTEL-SA-00334", - "INTEL-SA-00615" - ], - "isvEnclaveQuoteStatus": "CONFIGURATION_AND_SW_HARDENING_NEEDED", - "platformInfoBlob": "150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1", - "isvEnclaveQuoteBody": "AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - }, - "reportsig": "YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg==" - } + "quote": "03000200000000000a000f00939a7233f79c4ca9940a0db3957f06077944f37bdafec57cf7d4ab6bc395e0a1000000000e0e100fffff0100000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000e700000000000000e76ee038f2c61c4edee980be5b80fa5c6ff7934ef3458c72868dbaaa569705ee0000000000000000000000000000000000000000000000000000000000000000255197a6388e504446dbf83726c2a9cb3cef9035cc3dabd6cf47d69a994f959400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c91fdf2b07731beb31190c6e492588aff1be719d725a8c685f337d85bd7fd2480000000000000000000000000000000000000000000000000000000000000000ca1000002529e2f0229c295e0cd8973cc3ad54b214ee0d0cb8efb022694b95bf767587b2fe4d049214f263c4539b36422343567401ac2931fcf4d7bbf27b8021d9dc8957bae275a28eae9b7d785811e4e967e6f5c03cd850bc8087600262e38756786ae09d931d4e77d1b928f25b3c3ff67b42da0a149b07e49fc570ddeff8a8386120880e0e100fffff0100000000000000000000000000000000000000000000000000000000000000000000000000000000001500000000000000e70000000000000096b347a64e5a045e27369c26e6dcda51fd7c850e9b3a3a79e718f43261dee1e400000000000000000000000000000000000000000000000000000000000000008c4f5775d796503e96137f77c68a829a0056ac8ded70140b081b094490c57bff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000254f579e046f1423f1f2da170254f912bb49097a0e041f3f670793e3fd6dd63f000000000000000000000000000000000000000000000000000000000000000058d5d2a9c79533eeac51c24d3bc062c7c26c1e2ffd62e224dfe899251e5fddca4fb757d9edc0d27f50f7954eb81523f8db6054921e66ec8d187685b732d2f25b2000000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f0500620e00002d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d494945386a4343424a696741774942416749554854525a7054426e4d59655063575531354542316643507561485177436759494b6f5a497a6a3045417749770a634445694d434147413155454177775a535735305a577767553064594946424453794251624746305a6d397962534244515445614d42674741315545436777520a535735305a577767513239796347397959585270623234784644415342674e564241634d43314e68626e526849454e7359584a684d51737743515944565151490a44414a445154454c4d416b474131554542684d4356564d774868634e4d6a51774e5445344d5449314e4451325768634e4d7a45774e5445344d5449314e4451320a576a42774d534977494159445651514444426c4a626e526c624342545231676755454e4c49454e6c636e52705a6d6c6a5958526c4d526f77474159445651514b0a4442464a626e526c6243424462334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e560a4241674d416b4e424d517377435159445651514745774a56557a425a4d424d4742797147534d34394167454743437147534d34394177454841304941424f64700a696252626a7639566159476a7159584a766f7670333253752f594861313541727943546735566c384762744348417a396e5952786d4e6a303372553548687a4d0a513030752b364a6d794748744b4f773866364f6a67674d4f4d494944436a416642674e5648534d4547444157674253566231334e765276683655424a796454300a4d383442567776655644427242674e56485238455a4442694d47436758714263686c706f64485277637a6f764c32467761533530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c334e6e6543396a5a584a3061575a7059324630615739754c3359304c33426a61324e796244396a595431770a624746305a6d397962535a6c626d4e765a476c755a7a316b5a584977485159445652304f42425945464167706b386e6b7a4c6371776b6749376f7567574844560a574d67314d41344741315564447745422f775145417749477744414d42674e5648524d4241663845416a41414d4949434f77594a4b6f5a496876684e415130420a424949434c444343416967774867594b4b6f5a496876684e415130424151515151576f736c643645563066526f62747368385149737a434341575547436971470a534962345451454e41514977676746564d42414743797147534962345451454e415149424167454f4d42414743797147534962345451454e415149434167454f0a4d42414743797147534962345451454e41514944416745444d42414743797147534962345451454e41514945416745444d42454743797147534962345451454e0a41514946416749412f7a415242677371686b69472b4530424451454342674943415038774541594c4b6f5a496876684e4151304241676343415145774541594c0a4b6f5a496876684e4151304241676743415141774541594c4b6f5a496876684e4151304241676b43415141774541594c4b6f5a496876684e4151304241676f430a415141774541594c4b6f5a496876684e4151304241677343415141774541594c4b6f5a496876684e4151304241677743415141774541594c4b6f5a496876684e0a4151304241673043415141774541594c4b6f5a496876684e4151304241673443415141774541594c4b6f5a496876684e4151304241673843415141774541594c0a4b6f5a496876684e4151304241684143415141774541594c4b6f5a496876684e4151304241684543415130774877594c4b6f5a496876684e41513042416849450a4541344f4177502f2f7745414141414141414141414141774541594b4b6f5a496876684e4151304241775143414141774641594b4b6f5a496876684e415130420a4241514741474271414141414d41384743697147534962345451454e4151554b415145774867594b4b6f5a496876684e4151304242675151446758512b3446660a2b6c2b4853522f457161474d737a424542676f71686b69472b453042445145484d4459774541594c4b6f5a496876684e4151304242774542416638774541594c0a4b6f5a496876684e4151304242774942415141774541594c4b6f5a496876684e4151304242774d4241514177436759494b6f5a497a6a304541774944534141770a52514968414c3047436752526b30764e6c585a594e506d5738634f313632364c4353332f2f4c6d6f416638756a4457484169426d41324d56347058774f386d6d0a4171444e4c345a6843792f64657a4842796c746f307271377149664c51773d3d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436c6a4343416a32674177494241674956414a567658633239472b487051456e4a3150517a7a674658433935554d416f4743437147534d343942414d430a4d476778476a415942674e5642414d4d45556c756447567349464e48574342536232393049454e424d526f77474159445651514b4442464a626e526c624342440a62334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e424d5173770a435159445651514745774a56557a4165467730784f4441314d6a45784d4455774d5442614677307a4d7a41314d6a45784d4455774d5442614d484178496a41670a42674e5642414d4d47556c756447567349464e4857434251513073675547786864475a76636d306751304578476a415942674e5642416f4d45556c75644756730a49454e76636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b474131554543417743513045780a437a414a42674e5642415954416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741454e53422f377432316c58534f0a3243757a7078773734654a423732457944476757357258437478327456544c7136684b6b367a2b5569525a436e71523770734f766771466553786c6d546c4a6c0a65546d693257597a33714f42757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f536347724442530a42674e5648523845537a424a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e5648513445466751556c5739640a7a62306234656c4153636e553944504f4156634c336c517744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159420a4166384341514177436759494b6f5a497a6a30454177494452774177524149675873566b6930772b6936565947573355462f32327561586530594a446a3155650a6e412b546a44316169356343494359623153416d4435786b66545670766f34556f79695359787244574c6d5552344349394e4b7966504e2b0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436a7a4343416a53674177494241674955496d554d316c71644e496e7a6737535655723951477a6b6e42717777436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e4455784d466f58445451354d54497a4d54497a4e546b314f566f77614445614d4267470a4131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e76636e4276636d46300a615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a42674e56424159540a416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414543366e45774d4449595a4f6a2f69505773437a61454b69370a314f694f534c52466857476a626e42564a66566e6b59347533496a6b4459594c304d784f346d717379596a6c42616c54565978465032734a424b357a6c4b4f420a757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f5363477244425342674e5648523845537a424a0a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b63325679646d6c6a5a584d75615735300a5a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e564851344546675155496d554d316c71644e496e7a673753560a55723951477a6b6e4271777744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159424166384341514577436759490a4b6f5a497a6a3045417749445351417752674968414f572f35516b522b533943695344634e6f6f774c7550524c735747662f59693747535839344267775477670a41694541344a306c72486f4d732b586f356f2f7358364f39515778485241765a55474f6452513763767152586171493d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a00", + "collateral": "a76b726f6f745f63615f63726c590125308201213081c8020101300a06082a8648ce3d0403023068311a301806035504030c11496e74656c2053475820526f6f74204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3233303430333130323235315a170d3234303430323130323235315aa02f302d300a0603551d140403020101301f0603551d2304183016801422650cd65a9d3489f383b49552bf501b392706ac300a06082a8648ce3d0403020348003045022051577d47d9fba157b65f1eb5f4657bbc5e56ccaf735a03f1b963d704805ab118022100939015ec1636e7eafa5f426c1e402647c673132b6850cabd68cef6bad7682a037470636b5f63726c5f6973737565725f636861696e8299029c183018820218981830188202183e18a00302010202150018d018e818aa18da187518d718f9182e1849171898183c187b14186518d018d518f21859184d18300a0608182a1886184818ce183d040302183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b1830090603185504061302185518531830181e170d183118381830183518321831183118301835183018311830185a170d183318331830183518321831183118301835183018311830185a1830187118311823183018210603185504030c181a1849186e18741865186c1820185318471858182018501843184b182018501872186f1863186518731873186f18721820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b183009060318550406130218551853183018591830130607182a1886184818ce183d02010608182a1886184818ce183d030107031842000418bf186a18f818d3182918d8188318a018b518d91875186e184f18ee1859189e187e184c1864182618f118a018a218f3183e18fc187e18cf189f182818241837187718eb188318cd187918d5184c0418f618661018c2188918fc188818b8189c182f1837187c0d06189f1862181c141892183018930918ac1318a3188118bb1830188118b81830181f06031855181d1823041818183016188014182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac1830185206031855181d181f04184b183018491830184718a0184518a018431886184118681874187418701873183a182f182f186318651872187418691866186918631861187418651873182e187418721875187318741865186418731865187218761869186318651873182e1869186e18741865186c182e1863186f186d182f1849186e18741865186c1853184718581852186f186f187418431841182e1864186518721830181d06031855181d0e0416041418d018e818aa18da187518d718f9182e1849171898183c187b14186518d018d518f21859184d18300e06031855181d0f010118ff04040302010618301206031855181d13010118ff0408183006010118ff02010018300a0608182a1886184818ce183d04030203184800183018450218210018891881183618ed185618a318b21867185918b7188e18a81880185c18ce1890186118ae18ab18e618c5189218e3182f18c618ef182f182e1820189118b11877021820184618a318ef05182218b318cd0618a00418b4182a18e618ce184018ef184a185d18a218261891182718cc18ff18d218e018f318e018d81518f718599902931830188202188f1830188202183418a0030201020214182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac18300a0608182a1886184818ce183d040302183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b1830090603185504061302185518531830181e170d183118381830183518321831183118301834183518311830185a170d183418391831183218331831183218331835183918351839185a183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b183009060318550406130218551853183018591830130607182a1886184818ce183d02010608182a1886184818ce183d03010703184200040b18a918c418c018c018c81861189318a318fe182318d618b0182c18da1018a818bb18d418e8188e184818b418451885186118a3186e18701855182518f518671891188e182e18dc188818e40d18860b18d018cc184e18e2186a18ac18c9188818e50518a918531855188c1845183f186b090418ae1873189418a3188118bb1830188118b81830181f06031855181d1823041818183016188014182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac1830185206031855181d181f04184b183018491830184718a0184518a018431886184118681874187418701873183a182f182f186318651872187418691866186918631861187418651873182e187418721875187318741865186418731865187218761869186318651873182e1869186e18741865186c182e1863186f186d182f1849186e18741865186c1853184718581852186f186f187418431841182e1864186518721830181d06031855181d0e04160414182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac18300e06031855181d0f010118ff04040302010618301206031855181d13010118ff0408183006010118ff02010118300a0608182a1886184818ce183d04030203184900183018460218210018e518bf18e5091118f9182f18421889182018dc1836188a1830182e18e318d1182e18c51886187f18f6182218ec1864189718f71880186018c1183c18200218210018e0189d182518ac187a0c18b318e518e818e6188f18ec185f18a318bd1841186c184718440b18d918501863189d18450e18dc18be18a41857186a18a26770636b5f63726c59012f3082012b3081d1020101300a06082a8648ce3d04030230713123302106035504030c1a496e74656c205347582050434b2050726f636573736f72204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3234303932313233343530315a170d3234313032313233343530315aa02f302d300a0603551d140403020101301f0603551d23041830168014d0e8aada75d7f92e4917983c7b1465d0d5f2594d300a06082a8648ce3d0403020349003046022100b4e36f8ada6cbf883bdf686706552eeb9bea8079a55f24d478e732ca975f569e022100d61085414d0906dfc14abb3ec6098102adda31a4a9d05f32e54434ff212d23d3707463625f6973737565725f636861696e8299028f1830188202188b1830188202183218a0030201020214187e1838188218d518fb18551829184a18401849188e184518840318e914189118bd18f4185518300a0608182a1886184818ce183d040302183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b1830090603185504061302185518531830181e170d183118381830183518321831183118301835183018311830185a170d183218351830183518321831183118301835183018311830185a1830186c1831181e1830181c0603185504030c151849186e18741865186c182018531847185818201854184318421820185318691867186e1869186e18671831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b183009060318550406130218551853183018591830130607182a1886184818ce183d02010608182a1886184818ce183d030107031842000418431845181b18cc187318c918d51891187c18af1876186e186118af183f18e91880188718dd184f131825187b1826181e1885181818971879189d18d1183d18681118fb1847187118380318bb189b18ae1858187f18cc18dd18c218e3181b18e918a2188b18861896182a18cc186d18af189618da185818ee18ca189618a3188118b51830188118b21830181f06031855181d1823041818183016188014182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac1830185206031855181d181f04184b183018491830184718a0184518a018431886184118681874187418701873183a182f182f186318651872187418691866186918631861187418651873182e187418721875187318741865186418731865187218761869186318651873182e1869186e18741865186c182e1863186f186d182f1849186e18741865186c1853184718581852186f186f187418431841182e1864186518721830181d06031855181d0e04160414187e1838188218d518fb18551829184a18401849188e184518840318e914189118bd18f4185518300e06031855181d0f010118ff040403020618c018300c06031855181d13010118ff040218300018300a0608182a1886184818ce183d0403020318470018301844021820181f184218f3031880183718f2182618c4183b1846001825187618e318a2189c18aa183618a0186418e4187418931827182d18c8181a18ec1818186218550218201823187e18d618eb1834186b06185318c60718db185d185d184618260d18a018f318ee18d718d6186918ff183718bc18261868186e188c181d1828079902931830188202188f1830188202183418a0030201020214182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac18300a0608182a1886184818ce183d040302183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b1830090603185504061302185518531830181e170d183118381830183518321831183118301834183518311830185a170d183418391831183218331831183218331835183918351839185a183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b183009060318550406130218551853183018591830130607182a1886184818ce183d02010608182a1886184818ce183d03010703184200040b18a918c418c018c018c81861189318a318fe182318d618b0182c18da1018a818bb18d418e8188e184818b418451885186118a3186e18701855182518f518671891188e182e18dc188818e40d18860b18d018cc184e18e2186a18ac18c9188818e50518a918531855188c1845183f186b090418ae1873189418a3188118bb1830188118b81830181f06031855181d1823041818183016188014182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac1830185206031855181d181f04184b183018491830184718a0184518a018431886184118681874187418701873183a182f182f186318651872187418691866186918631861187418651873182e187418721875187318741865186418731865187218761869186318651873182e1869186e18741865186c182e1863186f186d182f1849186e18741865186c1853184718581852186f186f187418431841182e1864186518721830181d06031855181d0e04160414182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac18300e06031855181d0f010118ff04040302010618301206031855181d13010118ff0408183006010118ff02010118300a0608182a1886184818ce183d04030203184900183018460218210018e518bf18e5091118f9182f18421889182018dc1836188a1830182e18e318d1182e18c51886187f18f6182218ec1864189718f71880186018c1183c18200218210018e0189d182518ac187a0c18b318e518e818e6188f18ec185f18a318bd1841186c184718440b18d918501863189d18450e18dc18be18a41857186a18a2687463625f696e666f6c303036303661303030303030781871655f6964656e746974795f6973737565725f636861696e8299028f1830188202188b1830188202183218a0030201020214187e1838188218d518fb18551829184a18401849188e184518840318e914189118bd18f4185518300a0608182a1886184818ce183d040302183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b1830090603185504061302185518531830181e170d183118381830183518321831183118301835183018311830185a170d183218351830183518321831183118301835183018311830185a1830186c1831181e1830181c0603185504030c151849186e18741865186c182018531847185818201854184318421820185318691867186e1869186e18671831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b183009060318550406130218551853183018591830130607182a1886184818ce183d02010608182a1886184818ce183d030107031842000418431845181b18cc187318c918d51891187c18af1876186e186118af183f18e91880188718dd184f131825187b1826181e1885181818971879189d18d1183d18681118fb1847187118380318bb189b18ae1858187f18cc18dd18c218e3181b18e918a2188b18861896182a18cc186d18af189618da185818ee18ca189618a3188118b51830188118b21830181f06031855181d1823041818183016188014182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac1830185206031855181d181f04184b183018491830184718a0184518a018431886184118681874187418701873183a182f182f186318651872187418691866186918631861187418651873182e187418721875187318741865186418731865187218761869186318651873182e1869186e18741865186c182e1863186f186d182f1849186e18741865186c1853184718581852186f186f187418431841182e1864186518721830181d06031855181d0e04160414187e1838188218d518fb18551829184a18401849188e184518840318e914189118bd18f4185518300e06031855181d0f010118ff040403020618c018300c06031855181d13010118ff040218300018300a0608182a1886184818ce183d0403020318470018301844021820181f184218f3031880183718f2182618c4183b1846001825187618e318a2189c18aa183618a0186418e4187418931827182d18c8181a18ec1818186218550218201823187e18d618eb1834186b06185318c60718db185d185d184618260d18a018f318ee18d718d6186918ff183718bc18261868186e188c181d1828079902931830188202188f1830188202183418a0030201020214182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac18300a0608182a1886184818ce183d040302183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b1830090603185504061302185518531830181e170d183118381830183518321831183118301834183518311830185a170d183418391831183218331831183218331835183918351839185a183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b183009060318550406130218551853183018591830130607182a1886184818ce183d02010608182a1886184818ce183d03010703184200040b18a918c418c018c018c81861189318a318fe182318d618b0182c18da1018a818bb18d418e8188e184818b418451885186118a3186e18701855182518f518671891188e182e18dc188818e40d18860b18d018cc184e18e2186a18ac18c9188818e50518a918531855188c1845183f186b090418ae1873189418a3188118bb1830188118b81830181f06031855181d1823041818183016188014182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac1830185206031855181d181f04184b183018491830184718a0184518a018431886184118681874187418701873183a182f182f186318651872187418691866186918631861187418651873182e187418721875187318741865186418731865187218761869186318651873182e1869186e18741865186c182e1863186f186d182f1849186e18741865186c1853184718581852186f186f187418431841182e1864186518721830181d06031855181d0e04160414182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac18300e06031855181d0f010118ff04040302010618301206031855181d13010118ff0408183006010118ff02010118300a0608182a1886184818ce183d04030203184900183018460218210018e518bf18e5091118f9182f18421889182018dc1836188a1830182e18e318d1182e18c51886187f18f6182218ec1864189718f71880186018c1183c18200218210018e0189d182518ac187a0c18b318e518e818e6188f18ec185f18a318bd1841186c184718440b18d918501863189d18450e18dc18be18a41857186a18a26b71655f6964656e746974797905647b22656e636c6176654964656e74697479223a7b226964223a225145222c2276657273696f6e223a322c22697373756544617465223a22323032332d30372d31325432303a34383a32355a222c226e657874557064617465223a22323032332d30382d31315432303a34383a32355a222c227463624576616c756174696f6e446174614e756d626572223a31352c226d69736373656c656374223a223030303030303030222c226d69736373656c6563744d61736b223a224646464646464646222c2261747472696275746573223a223131303030303030303030303030303030303030303030303030303030303030222c22617474726962757465734d61736b223a224642464646464646464646464646464630303030303030303030303030303030222c226d727369676e6572223a2238433446353737354437393635303345393631333746373743363841383239413030353641433844454437303134304230383142303934343930433537424646222c2269737670726f646964223a312c227463624c6576656c73223a5b7b22746362223a7b2269737673766e223a387d2c2274636244617465223a22323032332d30322d31355430303a30303a30305a222c22746362537461747573223a225570546f44617465227d2c7b22746362223a7b2269737673766e223a367d2c2274636244617465223a22323032312d31312d31305430303a30303a30305a222c22746362537461747573223a224f75744f6644617465222c2261647669736f7279494473223a5b22494e54454c2d53412d3030363135225d7d2c7b22746362223a7b2269737673766e223a357d2c2274636244617465223a22323032302d31312d31315430303a30303a30305a222c22746362537461747573223a224f75744f6644617465222c2261647669736f7279494473223a5b22494e54454c2d53412d3030343737222c22494e54454c2d53412d3030363135225d7d2c7b22746362223a7b2269737673766e223a347d2c2274636244617465223a22323031392d31312d31335430303a30303a30305a222c22746362537461747573223a224f75744f6644617465222c2261647669736f7279494473223a5b22494e54454c2d53412d3030333334222c22494e54454c2d53412d3030343737222c22494e54454c2d53412d3030363135225d7d2c7b22746362223a7b2269737673766e223a327d2c2274636244617465223a22323031392d30352d31355430303a30303a30305a222c22746362537461747573223a224f75744f6644617465222c2261647669736f7279494473223a5b22494e54454c2d53412d3030323139222c22494e54454c2d53412d3030323933222c22494e54454c2d53412d3030333334222c22494e54454c2d53412d3030343737222c22494e54454c2d53412d3030363135225d7d2c7b22746362223a7b2269737673766e223a317d2c2274636244617465223a22323031382d30382d31355430303a30303a30305a222c22746362537461747573223a224f75744f6644617465222c2261647669736f7279494473223a5b22494e54454c2d53412d3030323032222c22494e54454c2d53412d3030323139222c22494e54454c2d53412d3030323933222c22494e54454c2d53412d3030333334222c22494e54454c2d53412d3030343737222c22494e54454c2d53412d3030363135225d7d5d7d2c227369676e6174757265223a223935336164643639613536346238306334336164623963396462633838386461383161616438616632343063643764666437353166303230396432363261373164393234303630336135323863623736366539666333323738373232653539613433663261326534336235356337373661376234386163626538636436316133227d" } } }"#, @@ -221,29 +204,11 @@ mod tests { "quartz": { "session_create": { "msg": { - "nonce": "425d87f8620e1dedeee70590cc55b164b8f01480ee59e0b1da35436a2f7c2777" + "nonce":"9eec5e41e5a715c5a89eb182054daa1877796549a3bde865d7f2196b5f0811ca" }, "attestation": { - "report": { - "report": { - "id": "5246688123689513540899231107533660789", - "timestamp": "2024-02-07T17:06:23.913745", - "version": 4, - "epidPseudonym": "+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=", - "advisoryURL": "https://security-center.intel.com", - "advisoryIDs": [ - "INTEL-SA-00161", - "INTEL-SA-00219", - "INTEL-SA-00289", - "INTEL-SA-00334", - "INTEL-SA-00615" - ], - "isvEnclaveQuoteStatus": "CONFIGURATION_AND_SW_HARDENING_NEEDED", - "platformInfoBlob": "150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1", - "isvEnclaveQuoteBody": "AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - }, - "reportsig": "YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg==" - } + "quote":"03000200000000000a000f00939a7233f79c4ca9940a0db3957f06077944f37bdafec57cf7d4ab6bc395e0a1000000000e0e100fffff0100000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000e7000000000000008821f6c6bf4c800c4852addc5b10a422d01ed714573258ac67f9e4b2478ffec90000000000000000000000000000000000000000000000000000000000000000255197a6388e504446dbf83726c2a9cb3cef9035cc3dabd6cf47d69a994f95940000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000056f352bac0614437a144a771ab582a979b301a5b8e5aaa80fd02f8f8de19a5da0000000000000000000000000000000000000000000000000000000000000000ca100000146a1ca7a9ddcdf55d220b8267d64915e91c3c789aefa2805248bc55472ba2faddc3108c86edb59b3c03981bc7a8a16f653eccc4ba82bf9192e88a2fa1c4c6f1bae275a28eae9b7d785811e4e967e6f5c03cd850bc8087600262e38756786ae09d931d4e77d1b928f25b3c3ff67b42da0a149b07e49fc570ddeff8a8386120880e0e100fffff0100000000000000000000000000000000000000000000000000000000000000000000000000000000001500000000000000e70000000000000096b347a64e5a045e27369c26e6dcda51fd7c850e9b3a3a79e718f43261dee1e400000000000000000000000000000000000000000000000000000000000000008c4f5775d796503e96137f77c68a829a0056ac8ded70140b081b094490c57bff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000254f579e046f1423f1f2da170254f912bb49097a0e041f3f670793e3fd6dd63f000000000000000000000000000000000000000000000000000000000000000058d5d2a9c79533eeac51c24d3bc062c7c26c1e2ffd62e224dfe899251e5fddca4fb757d9edc0d27f50f7954eb81523f8db6054921e66ec8d187685b732d2f25b2000000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f0500620e00002d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d494945386a4343424a696741774942416749554854525a7054426e4d59655063575531354542316643507561485177436759494b6f5a497a6a3045417749770a634445694d434147413155454177775a535735305a577767553064594946424453794251624746305a6d397962534244515445614d42674741315545436777520a535735305a577767513239796347397959585270623234784644415342674e564241634d43314e68626e526849454e7359584a684d51737743515944565151490a44414a445154454c4d416b474131554542684d4356564d774868634e4d6a51774e5445344d5449314e4451325768634e4d7a45774e5445344d5449314e4451320a576a42774d534977494159445651514444426c4a626e526c624342545231676755454e4c49454e6c636e52705a6d6c6a5958526c4d526f77474159445651514b0a4442464a626e526c6243424462334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e560a4241674d416b4e424d517377435159445651514745774a56557a425a4d424d4742797147534d34394167454743437147534d34394177454841304941424f64700a696252626a7639566159476a7159584a766f7670333253752f594861313541727943546735566c384762744348417a396e5952786d4e6a303372553548687a4d0a513030752b364a6d794748744b4f773866364f6a67674d4f4d494944436a416642674e5648534d4547444157674253566231334e765276683655424a796454300a4d383442567776655644427242674e56485238455a4442694d47436758714263686c706f64485277637a6f764c32467761533530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c334e6e6543396a5a584a3061575a7059324630615739754c3359304c33426a61324e796244396a595431770a624746305a6d397962535a6c626d4e765a476c755a7a316b5a584977485159445652304f42425945464167706b386e6b7a4c6371776b6749376f7567574844560a574d67314d41344741315564447745422f775145417749477744414d42674e5648524d4241663845416a41414d4949434f77594a4b6f5a496876684e415130420a424949434c444343416967774867594b4b6f5a496876684e415130424151515151576f736c643645563066526f62747368385149737a434341575547436971470a534962345451454e41514977676746564d42414743797147534962345451454e415149424167454f4d42414743797147534962345451454e415149434167454f0a4d42414743797147534962345451454e41514944416745444d42414743797147534962345451454e41514945416745444d42454743797147534962345451454e0a41514946416749412f7a415242677371686b69472b4530424451454342674943415038774541594c4b6f5a496876684e4151304241676343415145774541594c0a4b6f5a496876684e4151304241676743415141774541594c4b6f5a496876684e4151304241676b43415141774541594c4b6f5a496876684e4151304241676f430a415141774541594c4b6f5a496876684e4151304241677343415141774541594c4b6f5a496876684e4151304241677743415141774541594c4b6f5a496876684e0a4151304241673043415141774541594c4b6f5a496876684e4151304241673443415141774541594c4b6f5a496876684e4151304241673843415141774541594c0a4b6f5a496876684e4151304241684143415141774541594c4b6f5a496876684e4151304241684543415130774877594c4b6f5a496876684e41513042416849450a4541344f4177502f2f7745414141414141414141414141774541594b4b6f5a496876684e4151304241775143414141774641594b4b6f5a496876684e415130420a4241514741474271414141414d41384743697147534962345451454e4151554b415145774867594b4b6f5a496876684e4151304242675151446758512b3446660a2b6c2b4853522f457161474d737a424542676f71686b69472b453042445145484d4459774541594c4b6f5a496876684e4151304242774542416638774541594c0a4b6f5a496876684e4151304242774942415141774541594c4b6f5a496876684e4151304242774d4241514177436759494b6f5a497a6a304541774944534141770a52514968414c3047436752526b30764e6c585a594e506d5738634f313632364c4353332f2f4c6d6f416638756a4457484169426d41324d56347058774f386d6d0a4171444e4c345a6843792f64657a4842796c746f307271377149664c51773d3d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436c6a4343416a32674177494241674956414a567658633239472b487051456e4a3150517a7a674658433935554d416f4743437147534d343942414d430a4d476778476a415942674e5642414d4d45556c756447567349464e48574342536232393049454e424d526f77474159445651514b4442464a626e526c624342440a62334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e424d5173770a435159445651514745774a56557a4165467730784f4441314d6a45784d4455774d5442614677307a4d7a41314d6a45784d4455774d5442614d484178496a41670a42674e5642414d4d47556c756447567349464e4857434251513073675547786864475a76636d306751304578476a415942674e5642416f4d45556c75644756730a49454e76636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b474131554543417743513045780a437a414a42674e5642415954416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741454e53422f377432316c58534f0a3243757a7078773734654a423732457944476757357258437478327456544c7136684b6b367a2b5569525a436e71523770734f766771466553786c6d546c4a6c0a65546d693257597a33714f42757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f536347724442530a42674e5648523845537a424a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e5648513445466751556c5739640a7a62306234656c4153636e553944504f4156634c336c517744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159420a4166384341514177436759494b6f5a497a6a30454177494452774177524149675873566b6930772b6936565947573355462f32327561586530594a446a3155650a6e412b546a44316169356343494359623153416d4435786b66545670766f34556f79695359787244574c6d5552344349394e4b7966504e2b0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436a7a4343416a53674177494241674955496d554d316c71644e496e7a6737535655723951477a6b6e42717777436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e4455784d466f58445451354d54497a4d54497a4e546b314f566f77614445614d4267470a4131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e76636e4276636d46300a615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a42674e56424159540a416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414543366e45774d4449595a4f6a2f69505773437a61454b69370a314f694f534c52466857476a626e42564a66566e6b59347533496a6b4459594c304d784f346d717379596a6c42616c54565978465032734a424b357a6c4b4f420a757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f5363477244425342674e5648523845537a424a0a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b63325679646d6c6a5a584d75615735300a5a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e564851344546675155496d554d316c71644e496e7a673753560a55723951477a6b6e4271777744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159424166384341514577436759490a4b6f5a497a6a3045417749445351417752674968414f572f35516b522b533943695344634e6f6f774c7550524c735747662f59693747535839344267775477670a41694541344a306c72486f4d732b586f356f2f7358364f39515778485241765a55474f6452513763767152586171493d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a00", + "collateral":"a76b726f6f745f63615f63726c590125308201213081c8020101300a06082a8648ce3d0403023068311a301806035504030c11496e74656c2053475820526f6f74204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3233303430333130323235315a170d3234303430323130323235315aa02f302d300a0603551d140403020101301f0603551d2304183016801422650cd65a9d3489f383b49552bf501b392706ac300a06082a8648ce3d0403020348003045022051577d47d9fba157b65f1eb5f4657bbc5e56ccaf735a03f1b963d704805ab118022100939015ec1636e7eafa5f426c1e402647c673132b6850cabd68cef6bad7682a037470636b5f63726c5f6973737565725f636861696e8299029c183018820218981830188202183e18a00302010202150018d018e818aa18da187518d718f9182e1849171898183c187b14186518d018d518f21859184d18300a0608182a1886184818ce183d040302183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b1830090603185504061302185518531830181e170d183118381830183518321831183118301835183018311830185a170d183318331830183518321831183118301835183018311830185a1830187118311823183018210603185504030c181a1849186e18741865186c1820185318471858182018501843184b182018501872186f1863186518731873186f18721820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b183009060318550406130218551853183018591830130607182a1886184818ce183d02010608182a1886184818ce183d030107031842000418bf186a18f818d3182918d8188318a018b518d91875186e184f18ee1859189e187e184c1864182618f118a018a218f3183e18fc187e18cf189f182818241837187718eb188318cd187918d5184c0418f618661018c2188918fc188818b8189c182f1837187c0d06189f1862181c141892183018930918ac1318a3188118bb1830188118b81830181f06031855181d1823041818183016188014182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac1830185206031855181d181f04184b183018491830184718a0184518a018431886184118681874187418701873183a182f182f186318651872187418691866186918631861187418651873182e187418721875187318741865186418731865187218761869186318651873182e1869186e18741865186c182e1863186f186d182f1849186e18741865186c1853184718581852186f186f187418431841182e1864186518721830181d06031855181d0e0416041418d018e818aa18da187518d718f9182e1849171898183c187b14186518d018d518f21859184d18300e06031855181d0f010118ff04040302010618301206031855181d13010118ff0408183006010118ff02010018300a0608182a1886184818ce183d04030203184800183018450218210018891881183618ed185618a318b21867185918b7188e18a81880185c18ce1890186118ae18ab18e618c5189218e3182f18c618ef182f182e1820189118b11877021820184618a318ef05182218b318cd0618a00418b4182a18e618ce184018ef184a185d18a218261891182718cc18ff18d218e018f318e018d81518f718599902931830188202188f1830188202183418a0030201020214182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac18300a0608182a1886184818ce183d040302183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b1830090603185504061302185518531830181e170d183118381830183518321831183118301834183518311830185a170d183418391831183218331831183218331835183918351839185a183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b183009060318550406130218551853183018591830130607182a1886184818ce183d02010608182a1886184818ce183d03010703184200040b18a918c418c018c018c81861189318a318fe182318d618b0182c18da1018a818bb18d418e8188e184818b418451885186118a3186e18701855182518f518671891188e182e18dc188818e40d18860b18d018cc184e18e2186a18ac18c9188818e50518a918531855188c1845183f186b090418ae1873189418a3188118bb1830188118b81830181f06031855181d1823041818183016188014182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac1830185206031855181d181f04184b183018491830184718a0184518a018431886184118681874187418701873183a182f182f186318651872187418691866186918631861187418651873182e187418721875187318741865186418731865187218761869186318651873182e1869186e18741865186c182e1863186f186d182f1849186e18741865186c1853184718581852186f186f187418431841182e1864186518721830181d06031855181d0e04160414182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac18300e06031855181d0f010118ff04040302010618301206031855181d13010118ff0408183006010118ff02010118300a0608182a1886184818ce183d04030203184900183018460218210018e518bf18e5091118f9182f18421889182018dc1836188a1830182e18e318d1182e18c51886187f18f6182218ec1864189718f71880186018c1183c18200218210018e0189d182518ac187a0c18b318e518e818e6188f18ec185f18a318bd1841186c184718440b18d918501863189d18450e18dc18be18a41857186a18a26770636b5f63726c59012f3082012b3081d1020101300a06082a8648ce3d04030230713123302106035504030c1a496e74656c205347582050434b2050726f636573736f72204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3234303932343030343030305a170d3234313032343030343030305aa02f302d300a0603551d140403020101301f0603551d23041830168014d0e8aada75d7f92e4917983c7b1465d0d5f2594d300a06082a8648ce3d040302034900304602210093195ebc95f8d6eb2d9200c6926f1348d1c03e53fd0f66bdc349e660f091a0fe022100c8dd1c4c657ec607aa0737a498ea2cd41aac8be39b94502ee00b6d6cb2d4c155707463625f6973737565725f636861696e8299028f1830188202188b1830188202183218a0030201020214187e1838188218d518fb18551829184a18401849188e184518840318e914189118bd18f4185518300a0608182a1886184818ce183d040302183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b1830090603185504061302185518531830181e170d183118381830183518321831183118301835183018311830185a170d183218351830183518321831183118301835183018311830185a1830186c1831181e1830181c0603185504030c151849186e18741865186c182018531847185818201854184318421820185318691867186e1869186e18671831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b183009060318550406130218551853183018591830130607182a1886184818ce183d02010608182a1886184818ce183d030107031842000418431845181b18cc187318c918d51891187c18af1876186e186118af183f18e91880188718dd184f131825187b1826181e1885181818971879189d18d1183d18681118fb1847187118380318bb189b18ae1858187f18cc18dd18c218e3181b18e918a2188b18861896182a18cc186d18af189618da185818ee18ca189618a3188118b51830188118b21830181f06031855181d1823041818183016188014182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac1830185206031855181d181f04184b183018491830184718a0184518a018431886184118681874187418701873183a182f182f186318651872187418691866186918631861187418651873182e187418721875187318741865186418731865187218761869186318651873182e1869186e18741865186c182e1863186f186d182f1849186e18741865186c1853184718581852186f186f187418431841182e1864186518721830181d06031855181d0e04160414187e1838188218d518fb18551829184a18401849188e184518840318e914189118bd18f4185518300e06031855181d0f010118ff040403020618c018300c06031855181d13010118ff040218300018300a0608182a1886184818ce183d0403020318470018301844021820181f184218f3031880183718f2182618c4183b1846001825187618e318a2189c18aa183618a0186418e4187418931827182d18c8181a18ec1818186218550218201823187e18d618eb1834186b06185318c60718db185d185d184618260d18a018f318ee18d718d6186918ff183718bc18261868186e188c181d1828079902931830188202188f1830188202183418a0030201020214182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac18300a0608182a1886184818ce183d040302183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b1830090603185504061302185518531830181e170d183118381830183518321831183118301834183518311830185a170d183418391831183218331831183218331835183918351839185a183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b183009060318550406130218551853183018591830130607182a1886184818ce183d02010608182a1886184818ce183d03010703184200040b18a918c418c018c018c81861189318a318fe182318d618b0182c18da1018a818bb18d418e8188e184818b418451885186118a3186e18701855182518f518671891188e182e18dc188818e40d18860b18d018cc184e18e2186a18ac18c9188818e50518a918531855188c1845183f186b090418ae1873189418a3188118bb1830188118b81830181f06031855181d1823041818183016188014182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac1830185206031855181d181f04184b183018491830184718a0184518a018431886184118681874187418701873183a182f182f186318651872187418691866186918631861187418651873182e187418721875187318741865186418731865187218761869186318651873182e1869186e18741865186c182e1863186f186d182f1849186e18741865186c1853184718581852186f186f187418431841182e1864186518721830181d06031855181d0e04160414182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac18300e06031855181d0f010118ff04040302010618301206031855181d13010118ff0408183006010118ff02010118300a0608182a1886184818ce183d04030203184900183018460218210018e518bf18e5091118f9182f18421889182018dc1836188a1830182e18e318d1182e18c51886187f18f6182218ec1864189718f71880186018c1183c18200218210018e0189d182518ac187a0c18b318e518e818e6188f18ec185f18a318bd1841186c184718440b18d918501863189d18450e18dc18be18a41857186a18a2687463625f696e666f6c303036303661303030303030781871655f6964656e746974795f6973737565725f636861696e8299028f1830188202188b1830188202183218a0030201020214187e1838188218d518fb18551829184a18401849188e184518840318e914189118bd18f4185518300a0608182a1886184818ce183d040302183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b1830090603185504061302185518531830181e170d183118381830183518321831183118301835183018311830185a170d183218351830183518321831183118301835183018311830185a1830186c1831181e1830181c0603185504030c151849186e18741865186c182018531847185818201854184318421820185318691867186e1869186e18671831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b183009060318550406130218551853183018591830130607182a1886184818ce183d02010608182a1886184818ce183d030107031842000418431845181b18cc187318c918d51891187c18af1876186e186118af183f18e91880188718dd184f131825187b1826181e1885181818971879189d18d1183d18681118fb1847187118380318bb189b18ae1858187f18cc18dd18c218e3181b18e918a2188b18861896182a18cc186d18af189618da185818ee18ca189618a3188118b51830188118b21830181f06031855181d1823041818183016188014182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac1830185206031855181d181f04184b183018491830184718a0184518a018431886184118681874187418701873183a182f182f186318651872187418691866186918631861187418651873182e187418721875187318741865186418731865187218761869186318651873182e1869186e18741865186c182e1863186f186d182f1849186e18741865186c1853184718581852186f186f187418431841182e1864186518721830181d06031855181d0e04160414187e1838188218d518fb18551829184a18401849188e184518840318e914189118bd18f4185518300e06031855181d0f010118ff040403020618c018300c06031855181d13010118ff040218300018300a0608182a1886184818ce183d0403020318470018301844021820181f184218f3031880183718f2182618c4183b1846001825187618e318a2189c18aa183618a0186418e4187418931827182d18c8181a18ec1818186218550218201823187e18d618eb1834186b06185318c60718db185d185d184618260d18a018f318ee18d718d6186918ff183718bc18261868186e188c181d1828079902931830188202188f1830188202183418a0030201020214182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac18300a0608182a1886184818ce183d040302183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b1830090603185504061302185518531830181e170d183118381830183518321831183118301834183518311830185a170d183418391831183218331831183218331835183918351839185a183018681831181a183018180603185504030c111849186e18741865186c182018531847185818201852186f186f18741820184318411831181a1830181806031855040a0c111849186e18741865186c18201843186f18721870186f1872186118741869186f186e1831141830120603185504070c0b18531861186e1874186118201843186c18611872186118310b1830090603185504080c021843184118310b183009060318550406130218551853183018591830130607182a1886184818ce183d02010608182a1886184818ce183d03010703184200040b18a918c418c018c018c81861189318a318fe182318d618b0182c18da1018a818bb18d418e8188e184818b418451885186118a3186e18701855182518f518671891188e182e18dc188818e40d18860b18d018cc184e18e2186a18ac18c9188818e50518a918531855188c1845183f186b090418ae1873189418a3188118bb1830188118b81830181f06031855181d1823041818183016188014182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac1830185206031855181d181f04184b183018491830184718a0184518a018431886184118681874187418701873183a182f182f186318651872187418691866186918631861187418651873182e187418721875187318741865186418731865187218761869186318651873182e1869186e18741865186c182e1863186f186d182f1849186e18741865186c1853184718581852186f186f187418431841182e1864186518721830181d06031855181d0e04160414182218650c18d6185a189d1834188918f3188318b41895185218bf1850181b183918270618ac18300e06031855181d0f010118ff04040302010618301206031855181d13010118ff0408183006010118ff02010118300a0608182a1886184818ce183d04030203184900183018460218210018e518bf18e5091118f9182f18421889182018dc1836188a1830182e18e318d1182e18c51886187f18f6182218ec1864189718f71880186018c1183c18200218210018e0189d182518ac187a0c18b318e518e818e6188f18ec185f18a318bd1841186c184718440b18d918501863189d18450e18dc18be18a41857186a18a26b71655f6964656e746974797905647b22656e636c6176654964656e74697479223a7b226964223a225145222c2276657273696f6e223a322c22697373756544617465223a22323032332d30372d31325432303a34383a32355a222c226e657874557064617465223a22323032332d30382d31315432303a34383a32355a222c227463624576616c756174696f6e446174614e756d626572223a31352c226d69736373656c656374223a223030303030303030222c226d69736373656c6563744d61736b223a224646464646464646222c2261747472696275746573223a223131303030303030303030303030303030303030303030303030303030303030222c22617474726962757465734d61736b223a224642464646464646464646464646464630303030303030303030303030303030222c226d727369676e6572223a2238433446353737354437393635303345393631333746373743363841383239413030353641433844454437303134304230383142303934343930433537424646222c2269737670726f646964223a312c227463624c6576656c73223a5b7b22746362223a7b2269737673766e223a387d2c2274636244617465223a22323032332d30322d31355430303a30303a30305a222c22746362537461747573223a225570546f44617465227d2c7b22746362223a7b2269737673766e223a367d2c2274636244617465223a22323032312d31312d31305430303a30303a30305a222c22746362537461747573223a224f75744f6644617465222c2261647669736f7279494473223a5b22494e54454c2d53412d3030363135225d7d2c7b22746362223a7b2269737673766e223a357d2c2274636244617465223a22323032302d31312d31315430303a30303a30305a222c22746362537461747573223a224f75744f6644617465222c2261647669736f7279494473223a5b22494e54454c2d53412d3030343737222c22494e54454c2d53412d3030363135225d7d2c7b22746362223a7b2269737673766e223a347d2c2274636244617465223a22323031392d31312d31335430303a30303a30305a222c22746362537461747573223a224f75744f6644617465222c2261647669736f7279494473223a5b22494e54454c2d53412d3030333334222c22494e54454c2d53412d3030343737222c22494e54454c2d53412d3030363135225d7d2c7b22746362223a7b2269737673766e223a327d2c2274636244617465223a22323031392d30352d31355430303a30303a30305a222c22746362537461747573223a224f75744f6644617465222c2261647669736f7279494473223a5b22494e54454c2d53412d3030323139222c22494e54454c2d53412d3030323933222c22494e54454c2d53412d3030333334222c22494e54454c2d53412d3030343737222c22494e54454c2d53412d3030363135225d7d2c7b22746362223a7b2269737673766e223a317d2c2274636244617465223a22323031382d30382d31355430303a30303a30305a222c22746362537461747573223a224f75744f6644617465222c2261647669736f7279494473223a5b22494e54454c2d53412d3030323032222c22494e54454c2d53412d3030323139222c22494e54454c2d53412d3030323933222c22494e54454c2d53412d3030333334222c22494e54454c2d53412d3030343737222c22494e54454c2d53412d3030363135225d7d5d7d2c227369676e6174757265223a223935336164643639613536346238306334336164623963396462633838386461383161616438616632343063643764666437353166303230396432363261373164393234303630336135323863623736366539666333323738373232653539613433663261326534336235356337373661376234386163626538636436316133227d" } } } diff --git a/apps/mtcs/enclave/Cargo.toml b/apps/mtcs/enclave/Cargo.toml index 52c29b6..51054f5 100644 --- a/apps/mtcs/enclave/Cargo.toml +++ b/apps/mtcs/enclave/Cargo.toml @@ -4,17 +4,6 @@ version = "0.1.0" edition = "2021" authors = ["Informal Systems "] -[profile.release] -opt-level = 3 -debug = false -rpath = false -lto = true -debug-assertions = false -codegen-units = 1 -panic = 'abort' -incremental = false -overflow-checks = true - [features] mock-sgx = ["quartz-common/mock-sgx-cw", "quartz-common/mock-sgx-enclave"] diff --git a/apps/mtcs/enclave/quartz.manifest.template b/apps/mtcs/enclave/quartz.manifest.template index 9e69220..8cd7187 100644 --- a/apps/mtcs/enclave/quartz.manifest.template +++ b/apps/mtcs/enclave/quartz.manifest.template @@ -22,6 +22,9 @@ loader.env.QUARTZ_PORT = { passthrough = true } loader.argv = ["enclave", "--chain-id", "testing", + "--fmspc", "{{ fmspc }}", + "--tcbinfo-contract", "{{ tcbinfo_contract }}", + "--dcap-verifier-contract", "{{ dcap_verifier_contract }}", "--trusted-height", "{{ trusted_height }}", "--trusted-hash", "{{ trusted_hash }}"] diff --git a/apps/mtcs/enclave/src/cli.rs b/apps/mtcs/enclave/src/cli.rs index b4979ee..469161b 100644 --- a/apps/mtcs/enclave/src/cli.rs +++ b/apps/mtcs/enclave/src/cli.rs @@ -3,6 +3,7 @@ use std::net::SocketAddr; use clap::Parser; use color_eyre::eyre::{eyre, Result}; use cosmrs::AccountId; +use quartz_common::enclave::types::Fmspc; use tendermint::Hash; use tendermint_light_client::types::{Height, TrustThreshold}; @@ -27,10 +28,18 @@ pub struct Cli { #[clap(long)] pub chain_id: String, + /// FMSPC (Family-Model-Stepping-Platform-Custom SKU) + #[clap(long)] + pub fmspc: Option, + /// TcbInfo contract address #[clap(long)] pub tcbinfo_contract: Option, + /// DCAP verifier contract address + #[clap(long)] + pub dcap_verifier_contract: Option, + /// Height of the trusted header (AKA root-of-trust) #[clap(long)] pub trusted_height: Height, diff --git a/apps/mtcs/enclave/src/main.rs b/apps/mtcs/enclave/src/main.rs index 3775bb1..315b15f 100644 --- a/apps/mtcs/enclave/src/main.rs +++ b/apps/mtcs/enclave/src/main.rs @@ -29,7 +29,7 @@ use mtcs_server::MtcsService; use quartz_common::{ contract::state::{Config, LightClientOpts}, enclave::{ - attestor::{Attestor, DefaultAttestor}, + attestor::{self, Attestor}, server::{QuartzServer, WsListenerConfig}, }, }; @@ -53,13 +53,20 @@ async fn main() -> Result<(), Box> { args.max_block_lag, )?; - let attestor = DefaultAttestor::default(); + #[cfg(not(feature = "mock-sgx"))] + let attestor = attestor::DcapAttestor { + fmspc: args.fmspc.expect("FMSPC is required for DCAP"), + }; + + #[cfg(feature = "mock-sgx")] + let attestor = attestor::MockAttestor; let config: Config = Config::new( attestor.mr_enclave()?, Duration::from_secs(30 * 24 * 60), light_client_opts, args.tcbinfo_contract.map(|c| c.to_string()), + args.dcap_verifier_contract.map(|c| c.to_string()), ); let ws_config = WsListenerConfig { diff --git a/apps/mtcs/enclave/src/mtcs_server.rs b/apps/mtcs/enclave/src/mtcs_server.rs index 954cbe0..7abda9b 100644 --- a/apps/mtcs/enclave/src/mtcs_server.rs +++ b/apps/mtcs/enclave/src/mtcs_server.rs @@ -41,6 +41,7 @@ impl IntoServer for MtcsService { #[derive(Clone, Debug)] pub struct MtcsService { + #[allow(dead_code)] config: Config, // TODO: this config is not used anywhere sk: Arc>>, attestor: A, @@ -107,12 +108,16 @@ where let msg = SubmitSetoffsMsg { setoffs_enc }; println!("setoff_msg: {:?}", msg); + let attestation = self .attestor - .quote(msg.clone()) + .attestation(msg.clone()) .map_err(|e| Status::internal(e.to_string()))?; - let attested_msg = RawAttested { msg, attestation }; + let attested_msg = RawAttested { + msg, + attestation: A::RawAttestation::from(attestation), + }; let message = serde_json::to_string(&attested_msg).unwrap(); Ok(Response::new(RunClearingResponse { message })) } @@ -150,25 +155,6 @@ fn into_settle_offs( } } -// fn wasm_address(pk: VerifyingKey) -> String { -// let tm_pk = TmAccountId::from(pk); -// AccountId::new("wasm", tm_pk.as_bytes()) -// .unwrap() -// .to_string() -// } - -// fn encrypt_setoff( -// so: SimpleSetoff, -// debtor_pk: VerifyingKey, -// creditor_pk: VerifyingKey, -// ) -> Vec { -// let so_ser = serde_json::to_string(&so).expect("infallible serializer"); -// let so_debtor = encrypt(&debtor_pk.to_sec1_bytes(), so_ser.as_bytes()).unwrap(); -// let so_creditor = encrypt(&creditor_pk.to_sec1_bytes(), so_ser.as_bytes()).unwrap(); - -// vec![so_debtor.into(), so_creditor.into()] -// } - fn decrypt_obligation( sk: &SigningKey, ciphertext: &RawCipherText, diff --git a/apps/transfers/contracts/Cargo.lock b/apps/transfers/contracts/Cargo.lock index 29a7232..d678117 100644 --- a/apps/transfers/contracts/Cargo.lock +++ b/apps/transfers/contracts/Cargo.lock @@ -280,6 +280,33 @@ dependencies = [ "serde", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -407,6 +434,12 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -500,51 +533,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "cw2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b04852cd38f044c0751259d5f78255d07590d136b8a86d4e09efdd7666bd6d27" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus", - "schemars", - "semver", - "serde", - "thiserror", -] - -[[package]] -name = "cw20" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a42212b6bf29bbdda693743697c621894723f35d3db0d5df930be22903d0e27c" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-utils", - "schemars", - "serde", -] - -[[package]] -name = "cw20-base" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6de8c32e100f1fca306972d86b617234a5e6b00594ea2b48716fd6804d4d95d" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus", - "cw2", - "cw20", - "schemars", - "semver", - "serde", - "thiserror", -] - [[package]] name = "darling" version = "0.20.10" @@ -820,6 +808,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.13.2" @@ -1184,20 +1182,30 @@ dependencies = [ name = "quartz-cw" version = "0.1.0" dependencies = [ + "ciborium", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus", "hex", "k256", + "quartz-dcap-verifier-msgs", "quartz-tee-ra", "serde", "serde_json", "serde_with", "sha2", - "tcbinfo", + "tcbinfo-msgs", "thiserror", ] +[[package]] +name = "quartz-dcap-verifier-msgs" +version = "0.1.0" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", +] + [[package]] name = "quartz-tee-ra" version = "0.1.0" @@ -1205,11 +1213,8 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "der", - "displaydoc", "hex-literal", "mc-attestation-verifier", - "mc-sgx-core-types", - "mc-sgx-dcap-sys-types", "mc-sgx-dcap-types", "num-bigint", "serde", @@ -1218,7 +1223,6 @@ dependencies = [ "thiserror", "x509-cert", "x509-parser", - "zeroize", ] [[package]] @@ -1547,24 +1551,10 @@ dependencies = [ ] [[package]] -name = "tcbinfo" +name = "tcbinfo-msgs" version = "0.1.0" dependencies = [ "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus", - "cw2", - "der", - "getrandom", - "hex", - "mc-attestation-verifier", - "p256", - "quartz-tee-ra", - "schemars", - "serde", - "serde_json", - "thiserror", - "x509-cert", ] [[package]] @@ -1627,11 +1617,8 @@ dependencies = [ "cw-multi-test", "cw-storage-plus", "cw-utils", - "cw2", - "cw20-base", "getrandom", "quartz-common", - "serde", "serde_json", "sha2", "thiserror", diff --git a/apps/transfers/contracts/Cargo.toml b/apps/transfers/contracts/Cargo.toml index 56d6523..5f04a71 100644 --- a/apps/transfers/contracts/Cargo.toml +++ b/apps/transfers/contracts/Cargo.toml @@ -13,7 +13,7 @@ path = "bin/schema.rs" crate-type = ["cdylib", "rlib"] [profile.release] -opt-level = 3 +opt-level = "z" debug = false rpath = false lto = true @@ -23,7 +23,6 @@ panic = 'abort' incremental = false overflow-checks = true - [features] mock-sgx = ["quartz-common/mock-sgx-cw"] library = [] @@ -31,24 +30,20 @@ library = [] [dependencies] # external sha2 = "0.10.8" -serde_json = { version = "1.0.122", default-features = false, features = ["alloc"] } -serde = { version = "1.0.204", default-features = false, features = ["derive"] } +serde_json = { version = "1.0.122", default-features = false } thiserror = { version = "1.0.63" } # cosmwasm -cosmwasm-std = { version = "2.1.1", default-features = false } +cosmwasm-std = { version = "2.1.1", default-features = false, features = ["abort"] } cosmwasm-schema = { version = "2.1.1", default-features = false } -cw2 = { version = "2.0.0", default-features = false } cw-storage-plus = { version = "2.0.0", default-features = false } -cw20-base = { version = "2.0.0", default-features = false, features = ["library"] } cw-utils = { version = "2.0.0", default-features = false } # quartz -# quartz-common = { git = "ssh://git@github.com/informalsystems/cycles-quartz.git", features=["contract"]} -quartz-common = { path = "../../../core/quartz-common", features=["contract"]} +quartz-common = { path = "../../../core/quartz-common", default-features = false, features = ["contract"] } # patch indirect deps -getrandom = { version = "0.2.15", default-features = false, features = ["js"] } +getrandom = { version = "0.2.15", features = ["js"] } [dev-dependencies] cw-multi-test = { version = "2.1.0", default-features = false } diff --git a/apps/transfers/contracts/src/error.rs b/apps/transfers/contracts/src/error.rs index 4f84be9..1abcdae 100644 --- a/apps/transfers/contracts/src/error.rs +++ b/apps/transfers/contracts/src/error.rs @@ -1,5 +1,4 @@ use cosmwasm_std::StdError; -use cw20_base::ContractError as Cw20ContractError; use cw_utils::PaymentError; use quartz_common::contract::error::Error as QuartzError; use thiserror::Error; @@ -21,19 +20,10 @@ pub enum ContractError { #[error("Invalid length")] BadLength, - #[error("Cw20 error: {0}")] - Cw20(Cw20ContractError), - #[error("Payment error: {0}")] CwUtil(PaymentError), } -impl From for ContractError { - fn from(e: Cw20ContractError) -> Self { - Self::Cw20(e) - } -} - impl From for ContractError { fn from(e: PaymentError) -> Self { Self::CwUtil(e) diff --git a/apps/transfers/contracts/src/msg.rs b/apps/transfers/contracts/src/msg.rs index 4db7d86..8a5301b 100644 --- a/apps/transfers/contracts/src/msg.rs +++ b/apps/transfers/contracts/src/msg.rs @@ -23,8 +23,8 @@ pub enum QueryMsg { #[allow(clippy::large_enum_variant)] pub enum ExecuteMsg { // quartz initialization - Quartz(QuartzExecuteMsg), - + Quartz(QuartzExecuteMsg), + // User msgs // clear text Deposit, diff --git a/apps/transfers/enclave/Cargo.lock b/apps/transfers/enclave/Cargo.lock index 6bb05cb..c7ff3eb 100644 --- a/apps/transfers/enclave/Cargo.lock +++ b/apps/transfers/enclave/Cargo.lock @@ -530,6 +530,33 @@ dependencies = [ "serde", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half 2.4.1", +] + [[package]] name = "cipher" version = "0.4.4" @@ -926,51 +953,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "cw2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b04852cd38f044c0751259d5f78255d07590d136b8a86d4e09efdd7666bd6d27" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus", - "schemars", - "semver", - "serde", - "thiserror", -] - -[[package]] -name = "cw20" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a42212b6bf29bbdda693743697c621894723f35d3db0d5df930be22903d0e27c" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-utils", - "schemars", - "serde", -] - -[[package]] -name = "cw20-base" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6de8c32e100f1fca306972d86b617234a5e6b00594ea2b48716fd6804d4d95d" -dependencies = [ - "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus", - "cw2", - "cw20", - "schemars", - "semver", - "serde", - "thiserror", -] - [[package]] name = "darling" version = "0.20.10" @@ -1410,9 +1392,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", + "futures-io", "futures-macro", "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -1513,6 +1497,16 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -2677,20 +2671,30 @@ dependencies = [ name = "quartz-cw" version = "0.1.0" dependencies = [ + "ciborium", "cosmwasm-schema", "cosmwasm-std", "cw-storage-plus", "hex", "k256", + "quartz-dcap-verifier-msgs", "quartz-tee-ra", "serde", "serde_json", "serde_with", "sha2 0.10.8", - "tcbinfo", + "tcbinfo-msgs", "thiserror", ] +[[package]] +name = "quartz-dcap-verifier-msgs" +version = "0.1.0" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", +] + [[package]] name = "quartz-enclave" version = "0.1.0" @@ -2706,11 +2710,13 @@ dependencies = [ "futures-util", "hex", "k256", + "mc-sgx-dcap-sys-types", "mtcs", "quartz-cw", "quartz-proto", "quartz-tee-ra", "rand", + "reqwest 0.12.7", "serde", "serde_json", "sha2 0.10.8", @@ -2722,6 +2728,7 @@ dependencies = [ "tokio", "tonic", "tower 0.5.1", + "urlencoding", ] [[package]] @@ -2740,11 +2747,8 @@ dependencies = [ "cosmwasm-schema", "cosmwasm-std", "der", - "displaydoc", "hex-literal", "mc-attestation-verifier", - "mc-sgx-core-types", - "mc-sgx-dcap-sys-types", "mc-sgx-dcap-types", "num-bigint", "serde", @@ -2753,7 +2757,6 @@ dependencies = [ "thiserror", "x509-cert", "x509-parser", - "zeroize", ] [[package]] @@ -2966,6 +2969,7 @@ dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", + "futures-channel", "futures-core", "futures-util", "h2 0.4.6", @@ -3339,7 +3343,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ - "half", + "half 1.8.3", "serde", ] @@ -3672,24 +3676,10 @@ dependencies = [ ] [[package]] -name = "tcbinfo" +name = "tcbinfo-msgs" version = "0.1.0" dependencies = [ "cosmwasm-schema", - "cosmwasm-std", - "cw-storage-plus", - "cw2", - "der", - "getrandom", - "hex", - "mc-attestation-verifier", - "p256", - "quartz-tee-ra", - "schemars", - "serde", - "serde_json", - "thiserror", - "x509-cert", ] [[package]] @@ -4277,11 +4267,8 @@ dependencies = [ "cosmwasm-std", "cw-storage-plus", "cw-utils", - "cw2", - "cw20-base", "getrandom", "quartz-common", - "serde", "serde_json", "sha2 0.10.8", "thiserror", @@ -4374,6 +4361,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf-8" version = "0.7.6" diff --git a/apps/transfers/enclave/quartz.manifest.template b/apps/transfers/enclave/quartz.manifest.template index 6bf2328..7d8651b 100644 --- a/apps/transfers/enclave/quartz.manifest.template +++ b/apps/transfers/enclave/quartz.manifest.template @@ -22,6 +22,9 @@ loader.env.QUARTZ_PORT = { passthrough = true } loader.argv = ["quartz-app-transfers-enclave", "--chain-id", "testing", + "--fmspc", "{{ fmspc }}", + "--tcbinfo-contract", "{{ tcbinfo_contract }}", + "--dcap-verifier-contract", "{{ dcap_verifier_contract }}", "--rpc-addr", "0.0.0.0:11090", "--trusted-height", "{{ trusted_height }}", "--trusted-hash", "{{ trusted_hash }}"] diff --git a/apps/transfers/enclave/src/cli.rs b/apps/transfers/enclave/src/cli.rs index 2464fcf..307038b 100644 --- a/apps/transfers/enclave/src/cli.rs +++ b/apps/transfers/enclave/src/cli.rs @@ -3,6 +3,7 @@ use std::{env, net::SocketAddr}; use clap::Parser; use color_eyre::eyre::{eyre, Result}; use cosmrs::AccountId; +use quartz_common::enclave::types::Fmspc; use tendermint::Hash; use tendermint_light_client::types::{Height, TrustThreshold}; @@ -27,10 +28,18 @@ pub struct Cli { #[clap(long)] pub chain_id: String, + /// FMSPC (Family-Model-Stepping-Platform-Custom SKU) + #[clap(long)] + pub fmspc: Option, + /// TcbInfo contract address #[clap(long)] pub tcbinfo_contract: Option, + /// DCAP verifier contract address + #[clap(long)] + pub dcap_verifier_contract: Option, + /// Height of the trusted header (AKA root-of-trust) #[clap(long)] pub trusted_height: Height, diff --git a/apps/transfers/enclave/src/main.rs b/apps/transfers/enclave/src/main.rs index c11a7dc..59c0fd6 100644 --- a/apps/transfers/enclave/src/main.rs +++ b/apps/transfers/enclave/src/main.rs @@ -28,7 +28,7 @@ use cli::Cli; use quartz_common::{ contract::state::{Config, LightClientOpts}, enclave::{ - attestor::{Attestor, DefaultAttestor}, + attestor::{self, Attestor}, server::{QuartzServer, WsListenerConfig}, }, }; @@ -53,13 +53,20 @@ async fn main() -> Result<(), Box> { args.max_block_lag, )?; - let attestor = DefaultAttestor::default(); + #[cfg(not(feature = "mock-sgx"))] + let attestor = attestor::DcapAttestor { + fmspc: args.fmspc.expect("FMSPC is required for DCAP"), + }; + + #[cfg(feature = "mock-sgx")] + let attestor = attestor::MockAttestor::default(); let config = Config::new( attestor.mr_enclave()?, Duration::from_secs(30 * 24 * 60), light_client_opts, args.tcbinfo_contract.map(|c| c.to_string()), + args.dcap_verifier_contract.map(|c| c.to_string()), ); let ws_config = WsListenerConfig { diff --git a/apps/transfers/enclave/src/prost/transfers.rs b/apps/transfers/enclave/src/prost/transfers.rs index bf1d818..5f31588 100644 --- a/apps/transfers/enclave/src/prost/transfers.rs +++ b/apps/transfers/enclave/src/prost/transfers.rs @@ -23,12 +23,6 @@ pub struct QueryResponse { #[prost(string, tag = "1")] pub message: ::prost::alloc::string::String, } -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, Copy, PartialEq, ::prost::Message)] -pub struct ListenRequest {} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, Copy, PartialEq, ::prost::Message)] -pub struct ListenResponse {} /// Generated client implementations. pub mod settlement_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] @@ -157,115 +151,6 @@ pub mod settlement_client { } } } -/// Generated client implementations. -pub mod event_listener_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - use tonic::codegen::http::Uri; - #[derive(Debug, Clone)] - pub struct EventListenerClient { - inner: tonic::client::Grpc, - } - impl EventListenerClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl EventListenerClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> EventListenerClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - , - >>::Error: Into + Send + Sync, - { - EventListenerClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - pub async fn listen( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/transfers.EventListener/Listen", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("transfers.EventListener", "Listen")); - self.inner.unary(req, path, codec).await - } - } -} /// Generated server implementations. pub mod settlement_server { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] @@ -478,170 +363,3 @@ pub mod settlement_server { const NAME: &'static str = "transfers.Settlement"; } } -/// Generated server implementations. -pub mod event_listener_server { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with EventListenerServer. - #[async_trait] - pub trait EventListener: Send + Sync + 'static { - async fn listen( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - } - #[derive(Debug)] - pub struct EventListenerServer { - inner: Arc, - accept_compression_encodings: EnabledCompressionEncodings, - send_compression_encodings: EnabledCompressionEncodings, - max_decoding_message_size: Option, - max_encoding_message_size: Option, - } - impl EventListenerServer { - pub fn new(inner: T) -> Self { - Self::from_arc(Arc::new(inner)) - } - pub fn from_arc(inner: Arc) -> Self { - Self { - inner, - accept_compression_encodings: Default::default(), - send_compression_encodings: Default::default(), - max_decoding_message_size: None, - max_encoding_message_size: None, - } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> InterceptedService - where - F: tonic::service::Interceptor, - { - InterceptedService::new(Self::new(inner), interceptor) - } - /// Enable decompressing requests with the given encoding. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.accept_compression_encodings.enable(encoding); - self - } - /// Compress responses with the given encoding, if the client supports it. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.send_compression_encodings.enable(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.max_decoding_message_size = Some(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.max_encoding_message_size = Some(limit); - self - } - } - impl tonic::codegen::Service> for EventListenerServer - where - T: EventListener, - B: Body + Send + 'static, - B::Error: Into + Send + 'static, - { - type Response = http::Response; - type Error = std::convert::Infallible; - type Future = BoxFuture; - fn poll_ready( - &mut self, - _cx: &mut Context<'_>, - ) -> Poll> { - Poll::Ready(Ok(())) - } - fn call(&mut self, req: http::Request) -> Self::Future { - match req.uri().path() { - "/transfers.EventListener/Listen" => { - #[allow(non_camel_case_types)] - struct ListenSvc(pub Arc); - impl< - T: EventListener, - > tonic::server::UnaryService - for ListenSvc { - type Response = super::ListenResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::listen(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = ListenSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - _ => { - Box::pin(async move { - Ok( - http::Response::builder() - .status(200) - .header("grpc-status", tonic::Code::Unimplemented as i32) - .header( - http::header::CONTENT_TYPE, - tonic::metadata::GRPC_CONTENT_TYPE, - ) - .body(empty_body()) - .unwrap(), - ) - }) - } - } - } - } - impl Clone for EventListenerServer { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - Self { - inner, - accept_compression_encodings: self.accept_compression_encodings, - send_compression_encodings: self.send_compression_encodings, - max_decoding_message_size: self.max_decoding_message_size, - max_encoding_message_size: self.max_encoding_message_size, - } - } - } - impl tonic::server::NamedService for EventListenerServer { - const NAME: &'static str = "transfers.EventListener"; - } -} diff --git a/apps/transfers/enclave/src/transfers_server.rs b/apps/transfers/enclave/src/transfers_server.rs index 848e4b8..d960b64 100644 --- a/apps/transfers/enclave/src/transfers_server.rs +++ b/apps/transfers/enclave/src/transfers_server.rs @@ -102,12 +102,6 @@ pub struct StatusResponseMessage { encrypted_bal: HexBinary, } -#[derive(Clone, Debug, Serialize, Deserialize)] -struct AttestedMsg { - msg: M, - quote: Vec, -} - impl TransfersService where A: Attestor, @@ -238,13 +232,15 @@ where }; // Attest to message - let attestation: HexBinary = self + let attestation = self .attestor - .quote(msg.clone()) - .map_err(|e| Status::internal(e.to_string()))? - .into(); + .attestation(msg.clone()) + .map_err(|e| Status::internal(e.to_string()))?; - let attested_msg = RawAttested { msg, attestation }; + let attested_msg = RawAttested { + msg, + attestation: A::RawAttestation::from(attestation), + }; let message = serde_json::to_string(&attested_msg).map_err(|e| Status::internal(e.to_string()))?; @@ -300,13 +296,15 @@ where }; // Attest to message - let attestation: HexBinary = self + let attestation = self .attestor - .quote(msg.clone()) - .map_err(|e| Status::internal(e.to_string()))? - .into(); + .attestation(msg.clone()) + .map_err(|e| Status::internal(e.to_string()))?; - let attested_msg = RawAttested { msg, attestation }; + let attested_msg = RawAttested { + msg, + attestation: A::RawAttestation::from(attestation), + }; let message = serde_json::to_string(&attested_msg).map_err(|e| Status::internal(e.to_string()))?; diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 39a7421..5a656ce 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" [dependencies] async-trait.workspace = true cargo-generate.workspace = true -clap = { workspace = true, features=["env"] } +clap = { workspace = true, features = ["env"] } color-eyre.workspace = true displaydoc.workspace = true dirs = "5.0.1" @@ -38,9 +38,9 @@ watchexec = "4.1.0" watchexec-events = "3.0.0" watchexec-signals = "3.0.0" miette = "7.2.0" -xxhash-rust = { version = "0.8.12", features=["xxh3"] } +xxhash-rust = { version = "0.8.12", features = ["xxh3"] } toml = "0.8.19" -figment = { version = "0.10.19", features=["env", "toml"] } +figment = { version = "0.10.19", features = ["env", "toml"] } clearscreen = "3.0.0" cargo_metadata = "0.18.1" @@ -49,10 +49,9 @@ cosmrs.workspace = true cosmwasm-std.workspace = true tendermint.workspace = true tendermint-light-client.workspace = true -tendermint-rpc = { workspace = true, features=["websocket-client", "http-client"]} - -tm-prover = { workspace = true} -quartz-common = { workspace = true, features=["contract", "proto"]} -quartz-tee-ra = { workspace = true} +tendermint-rpc = { workspace = true, features = ["websocket-client", "http-client"] } +tm-prover = { workspace = true } +quartz-common = { workspace = true, features = ["full"] } +quartz-tee-ra = { workspace = true } wasmd-client.workspace = true tempfile.workspace = true diff --git a/cli/scripts/relay.sh b/cli/scripts/relay.sh index f9beded..767edbe 100755 --- a/cli/scripts/relay.sh +++ b/cli/scripts/relay.sh @@ -10,11 +10,6 @@ usage() { DIR_QUARTZ=$(git rev-parse --show-toplevel) DIR_PROTO="$DIR_QUARTZ/core/quartz-proto/proto" -IAS_API_KEY="669244b3e6364b5888289a11d2a1726d" -RA_CLIENT_SPID="51CAF5A48B450D624AEFE3286D314894" -QUOTE_FILE="/tmp/${USER}_test.quote" -REPORT_FILE="/tmp/${USER}_datareport" -REPORT_SIG_FILE="/tmp/${USER}_datareportsig" REQUEST="$1" REQUEST_MSG=${2:-"{}"} @@ -22,9 +17,6 @@ REQUEST_MSG=${2:-"{}"} # Use the QUARTZ_PORT environment variable if set, otherwise default to 11090 QUARTZ_PORT="${QUARTZ_PORT:-11090}" -# clear tmp files from previous runs -rm -f "$QUOTE_FILE" "$REPORT_FILE" "$REPORT_SIG_FILE" - # query the gRPC quartz enclave service ATTESTED_MSG=$(grpcurl -plaintext -import-path "$DIR_PROTO" -proto quartz.proto -d "$REQUEST_MSG" "127.0.0.1:$QUARTZ_PORT" quartz.Core/"$REQUEST" | jq -c '.message | fromjson') @@ -32,9 +24,7 @@ ATTESTED_MSG=$(grpcurl -plaintext -import-path "$DIR_PROTO" -proto quartz.proto QUOTE=$(echo "$ATTESTED_MSG" | jq -c '.quote') MSG=$(echo "$ATTESTED_MSG" | jq 'del(.quote)') - if [ "$MOCK_SGX" ]; then - case "$REQUEST" in "Instantiate") jq -nc --argjson msg "$MSG" --argjson "attestation" "$QUOTE" '$ARGS.named' @@ -52,34 +42,21 @@ if [ "$MOCK_SGX" ]; then exit 0 fi -# clear tmp files from previous runs -rm -f "$QUOTE_FILE" "$REPORT_FILE" "$REPORT_SIG_FILE" - -# request the IAS report for EPID attestations -echo -n "$QUOTE" | xxd -r -p - > "$QUOTE_FILE" -docker run --rm -it \ - -v /tmp:/tmp:rw \ - gramineproject/gramine:1.7-jammy \ - "gramine-sgx-ias-request report -g \"$RA_CLIENT_SPID\" -k \"$IAS_API_KEY\" -q \"$QUOTE_FILE\" -r \"$REPORT_FILE\" -s \"$REPORT_SIG_FILE\" > /dev/null 2>&1" -REPORT=$(cat "$REPORT_FILE") -REPORTSIG=$(cat "$REPORT_SIG_FILE" | tr -d '\r') - -#echo "$QUOTE" -#echo "$REPORT" -#echo "$REPORTSIG" - case "$REQUEST" in -"Instantiate") - jq -nc --argjson msg "$MSG" --argjson "attestation" \ - "$(jq -nc --argjson report "$(jq -nc --argjson report "$REPORT" --arg reportsig "$REPORTSIG" '$ARGS.named')" '$ARGS.named')" \ - '$ARGS.named' ;; + "Instantiate") + jq -nc --argjson msg "$MSG" --argjson "attestation" \ + "$(jq -nc --argjson collateral "$COLLATERAL" '$ARGS.named')" \ + '$ARGS.named' + ;; "SessionCreate" | "SessionSetPubKey") - REQUEST_KEY=$(echo "$REQUEST" | perl -pe 's/([A-Z])/_\L$1/g;s/^_//') - jq -nc --argjson quartz "$(jq -nc --argjson "$REQUEST_KEY" "$(jq -nc --argjson msg "$MSG" --argjson attestation \ - "$(jq -nc --argjson report "$(jq -nc --argjson report "$REPORT" --arg reportsig "$REPORTSIG" '$ARGS.named')" '$ARGS.named')" \ - '$ARGS.named')" '$ARGS.named')" '$ARGS.named' ;; + REQUEST_KEY=$(echo "$REQUEST" | perl -pe 's/([A-Z])/_\L$1/g;s/^_//') + jq -nc --argjson quartz "$(jq -nc --argjson "$REQUEST_KEY" "$(jq -nc --argjson msg "$MSG" --argjson attestation \ + "$(jq -nc --argjson collateral "$COLLATERAL" '$ARGS.named')" \ + '$ARGS.named')" '$ARGS.named')" '$ARGS.named' + ;; -*) - usage ;; + *) + usage + ;; esac diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 2d1710b..9075fa4 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; use clap::{Parser, Subcommand}; use cosmrs::{tendermint::chain::Id as ChainId, AccountId}; use figment::{providers::Serialized, Figment}; +use quartz_common::enclave::types::Fmspc; use serde::{Deserialize, Serialize}; use tracing::metadata::LevelFilter; @@ -73,6 +74,7 @@ pub enum Command { #[command(subcommand)] enclave_command: EnclaveCommand, }, + /// Build, deploy, perform handshake, and run quartz app while listening for changes Dev(DevArgs), } @@ -190,6 +192,21 @@ pub struct EnclaveStartArgs { #[arg(long)] pub unsafe_trust_latest: bool, + /// FMSPC (Family-Model-Stepping-Platform-Custom SKU); required if `MOCK_SGX` is not set + #[arg(long)] + #[serde(skip_serializing_if = "Option::is_none")] + pub fmspc: Option, + + /// Address of the TcbInfo contract + #[arg(long)] + #[serde(skip_serializing_if = "Option::is_none")] + pub tcbinfo_contract: Option, + + /// Address of the DCAP verifier contract + #[arg(long)] + #[serde(skip_serializing_if = "Option::is_none")] + pub dcap_verifier_contract: Option, + /// Whether to target release or dev #[arg(long)] #[serde(skip_serializing_if = "is_false")] @@ -211,6 +228,21 @@ pub struct DevArgs { #[command(flatten)] pub enclave_build: EnclaveBuildArgs, + + /// FMSPC (Family-Model-Stepping-Platform-Custom SKU); required if `MOCK_SGX` is not set + #[arg(long)] + #[serde(skip_serializing_if = "Option::is_none")] + pub fmspc: Option, + + /// Address of the TcbInfo contract + #[arg(long)] + #[serde(skip_serializing_if = "Option::is_none")] + pub tcbinfo_contract: Option, + + /// Address of the DCAP verifier contract + #[arg(long)] + #[serde(skip_serializing_if = "Option::is_none")] + pub dcap_verifier_contract: Option, } pub trait ToFigment { diff --git a/cli/src/handler/contract_deploy.rs b/cli/src/handler/contract_deploy.rs index 9ad8d67..1b6d1f7 100644 --- a/cli/src/handler/contract_deploy.rs +++ b/cli/src/handler/contract_deploy.rs @@ -91,13 +91,13 @@ async fn deploy( }; info!("🚀 Communicating with Relay to Instantiate..."); - let raw_init_msg = RelayMessage::Instantiate - .run_relay(config.enclave_rpc(), config.mock_sgx) - .await?; + let init_msg = RelayMessage::Instantiate { + init_msg: args.init_msg, + } + .run_relay(config.enclave_rpc()) + .await?; info!("🚀 Instantiating {}", args.label); - let mut init_msg = args.init_msg; - init_msg["quartz"] = json!(raw_init_msg); let init_output: WasmdTxResponse = serde_json::from_str(&wasmd_client.init( &config.chain_id, @@ -119,5 +119,3 @@ async fn deploy( Ok((code_id, contract_addr.to_owned())) } - -//RES=$($CMD tx wasm instantiate "$CODE_ID" "$INSTANTIATE_MSG" --from "$USER_ADDR" --label $LABEL $TXFLAG -y --no-admin --output json) diff --git a/cli/src/handler/dev.rs b/cli/src/handler/dev.rs index c84a19c..196b7da 100644 --- a/cli/src/handler/dev.rs +++ b/cli/src/handler/dev.rs @@ -171,6 +171,9 @@ fn spawn_enclave_start(args: &DevRequest, config: &Config) -> Result<(), Error> // In separate process, launch the enclave let enclave_start = EnclaveStartRequest { unsafe_trust_latest: args.unsafe_trust_latest, + fmspc: args.fmspc.clone(), + tcbinfo_contract: args.tcbinfo_contract.clone(), + dcap_verifier_contract: args.dcap_verifier_contract.clone(), }; let config_cpy = config.clone(); diff --git a/cli/src/handler/enclave_start.rs b/cli/src/handler/enclave_start.rs index 42db6fb..0081085 100644 --- a/cli/src/handler/enclave_start.rs +++ b/cli/src/handler/enclave_start.rs @@ -3,6 +3,8 @@ use std::{fs, path::Path}; use async_trait::async_trait; use cargo_metadata::MetadataCommand; use color_eyre::owo_colors::OwoColorize; +use cosmrs::AccountId; +use quartz_common::enclave::types::Fmspc; use tokio::process::{Child, Command}; use tracing::{debug, info}; @@ -50,6 +52,24 @@ impl Handler for EnclaveStartRequest { .await?; handle_process(enclave_child).await?; } else { + let Some(fmspc) = self.fmspc else { + return Err(Error::GenericErr( + "FMSPC is required if MOCK_SGX isn't set".to_string(), + )); + }; + + let Some(tcbinfo_contract) = self.tcbinfo_contract else { + return Err(Error::GenericErr( + "tcbinfo_contract is required if MOCK_SGX isn't set".to_string(), + )); + }; + + let Some(dcap_verifier_contract) = self.dcap_verifier_contract else { + return Err(Error::GenericErr( + "dcap_verifier_contract is required if MOCK_SGX isn't set".to_string(), + )); + }; + let enclave_dir = fs::canonicalize(config.app_dir.join("enclave"))?; // gramine private key @@ -62,6 +82,9 @@ impl Handler for EnclaveStartRequest { &trusted_hash.to_string(), quartz_dir_canon, &enclave_dir, + fmspc, + tcbinfo_contract, + dcap_verifier_contract, ) .await?; @@ -155,6 +178,9 @@ async fn gramine_manifest( trusted_hash: &str, quartz_dir: &Path, enclave_dir: &Path, + fmspc: Fmspc, + tcbinfo_contract: AccountId, + dcap_verifier_contract: AccountId, ) -> Result<(), Error> { let host = target_lexicon::HOST; let arch_libdir = format!( @@ -172,12 +198,18 @@ async fn gramine_manifest( .arg("-Dlog_level=error") .arg(format!("-Dhome={}", home_dir)) .arg(format!("-Darch_libdir={}", arch_libdir)) - .arg("-Dra_type=epid") + .arg("-Dra_type=dcap") .arg(format!("-Dra_client_spid={}", ra_client_spid)) .arg("-Dra_client_linkable=1") .arg(format!("-Dquartz_dir={}", quartz_dir.display())) .arg(format!("-Dtrusted_height={}", trusted_height)) .arg(format!("-Dtrusted_hash={}", trusted_hash)) + .arg(format!("-Dfmspc={}", hex::encode(fmspc))) + .arg(format!("-Dtcbinfo_contract={}", tcbinfo_contract)) + .arg(format!( + "-Ddcap_verifier_contract={}", + dcap_verifier_contract + )) .arg("quartz.manifest.template") .arg("quartz.manifest") .current_dir(enclave_dir) diff --git a/cli/src/handler/handshake.rs b/cli/src/handler/handshake.rs index bcc868a..68f57fa 100644 --- a/cli/src/handler/handshake.rs +++ b/cli/src/handler/handshake.rs @@ -57,8 +57,8 @@ async fn handshake(args: HandshakeRequest, config: Config) -> Result Result Result { + pub async fn run_relay(self, enclave_rpc: String) -> Result { // Query the gRPC quartz enclave service let mut qc_client = CoreClient::connect(enclave_rpc) .await .map_err(|e| Error::GenericErr(e.to_string()))?; let attested_msg = match self { - RelayMessage::Instantiate => qc_client + RelayMessage::Instantiate { mut init_msg } => qc_client .instantiate(tonic::Request::new(InstantiateRequest {})) .await - .map_err(|e| Error::GenericErr(e.to_string()))? - .get_ref() - .message - .clone(), + .map_err(|e| Error::GenericErr(e.to_string())) + .map(|res| serde_json::from_str::(&res.into_inner().message))? + .map(|msg| { + init_msg["quartz"] = msg; + init_msg.to_string() + })?, RelayMessage::SessionCreate => qc_client .session_create(tonic::Request::new(SessionCreateRequest {})) .await - .map_err(|e| Error::GenericErr(e.to_string()))? - .get_ref() - .message - .clone(), - RelayMessage::SessionSetPubKey(proof) => qc_client + .map_err(|e| Error::GenericErr(e.to_string())) + .map(|res| serde_json::from_str::(&res.into_inner().message))? + .map(|msg| json!({ "quartz": {"session_create": msg}}).to_string())?, + RelayMessage::SessionSetPubKey { proof } => qc_client .session_set_pub_key(SessionSetPubKeyRequest { - message: proof.to_string(), + message: serde_json::to_string(&proof)?, }) .await - .map_err(|e| Error::GenericErr(e.to_string()))? - .get_ref() - .message - .clone(), + .map_err(|e| Error::GenericErr(e.to_string())) + .map(|res| serde_json::from_str::(&res.into_inner().message))? + .map(|msg| json!({ "quartz": {"session_set_pub_key": msg}}).to_string())?, }; - - let mut msg_json: serde_json::Value = serde_json::from_str(&attested_msg)?; - let quote = msg_json["quote"].take(); - - if mock_sgx { - let attestation: RawMockAttestation = serde_json::from_value(quote)?; - - self.create_attested_msg(msg_json, attestation) - } else { - let attestation: RawEpidAttestation = create_epid_attestation("e).await?.into(); - - self.create_attested_msg(msg_json, attestation) - } - } - - fn create_attested_msg( - &self, - msg_json: serde_json::Value, - attestation: RA, - ) -> Result { - match self { - RelayMessage::Instantiate => { - let msg: RawCoreInstantiate = serde_json::from_value(msg_json)?; - let query_result: RawAttested = - RawAttested { msg, attestation }; - Ok(json!(query_result)) - } - RelayMessage::SessionCreate => { - let msg: RawSessionCreate = serde_json::from_value(msg_json)?; - let query_result: RawExecuteMsg = - RawExecuteMsg::RawSessionCreate(RawAttested { msg, attestation }); - Ok(json!({ "quartz": query_result })) - } - RelayMessage::SessionSetPubKey(_) => { - let msg: RawSessionSetPubKey = serde_json::from_value(msg_json)?; - let query_result: RawExecuteMsg = - RawExecuteMsg::RawSessionSetPubKey(RawAttested { msg, attestation }); - Ok(json!({ "quartz": query_result })) - } - } + serde_json::from_str(&attested_msg).map_err(Into::into) } } - -async fn create_epid_attestation(quote: &serde_json::Value) -> Result { - let quote_str = quote - .as_str() - .ok_or_else(|| Error::GenericErr("quote is not a string".to_string()))?; - let quote = decode(quote_str).map_err(|e| Error::GenericErr(e.to_string()))?; - - let (report, report_sig) = run_docker_command("e).await?; - - let report_json: ReportBody = serde_json::from_str(&report)?; - let report_sig = report_sig.replace('\n', ""); - - let ias_report = IASReport { - report: report_json, - report_sig: Binary::from_base64(&report_sig) - .map_err(|e| Error::GenericErr(e.to_string()))?, - }; - - Ok(EpidAttestation::new(ias_report)) -} - -async fn run_docker_command(quote: &[u8]) -> Result<(String, String), Error> { - let dir = tempfile::tempdir()?; - let ias_api_key: &str = "669244b3e6364b5888289a11d2a1726d"; - let ra_client_spid: &str = "51CAF5A48B450D624AEFE3286D314894"; - let quote_file_path = dir.path().join("test.quote"); - let datareport_file_path = dir.path().join("datareport"); - let datareportsig_file_path = dir.path().join("datareportsig"); - - let mut quote_file = File::create(quote_file_path.clone()).await?; - quote_file.write_all(quote).await?; - - let status = Command::new("docker") - .arg("run") - .arg("--rm") - .arg("-it") - .arg("-v") - .arg("/tmp:/tmp:rw") - .arg("gramineproject/gramine:1.7-jammy") - .arg(format!( - "gramine-sgx-ias-request report -g \"{}\" -k \"{}\" -q \"{}\" -r \"{}\" -s \"{}\" > /dev/null 2>&1", - ra_client_spid, ias_api_key, quote_file_path.display(), datareport_file_path.display(), datareportsig_file_path.display() - )) - .status() - .await - .map_err(|e| Error::GenericErr(e.to_string()))?; - - if !status.success() { - return Err(Error::GenericErr( - "Failed to run docker command".to_string(), - )); - } - - let report = fs::read_to_string(datareport_file_path) - .await - .map_err(|e| Error::GenericErr(e.to_string()))?; - - let reportsig = fs::read_to_string(datareportsig_file_path) - .await - .map_err(|e| Error::GenericErr(e.to_string()))? - .replace('\r', ""); - - Ok((report, reportsig)) -} diff --git a/cli/src/request.rs b/cli/src/request.rs index 301fafc..60ad6c1 100644 --- a/cli/src/request.rs +++ b/cli/src/request.rs @@ -48,6 +48,9 @@ impl TryFrom for Request { label: args.contract_deploy.label, contract_manifest: args.contract_deploy.contract_manifest, release: args.enclave_build.release, + fmspc: args.fmspc, + tcbinfo_contract: args.tcbinfo_contract, + dcap_verifier_contract: args.dcap_verifier_contract, } .into()), } @@ -98,6 +101,9 @@ impl TryFrom for Request { EnclaveCommand::Build(_) => Ok(EnclaveBuildRequest {}.into()), EnclaveCommand::Start(args) => Ok(EnclaveStartRequest { unsafe_trust_latest: args.unsafe_trust_latest, + fmspc: args.fmspc, + tcbinfo_contract: args.tcbinfo_contract, + dcap_verifier_contract: args.dcap_verifier_contract, } .into()), } diff --git a/cli/src/request/dev.rs b/cli/src/request/dev.rs index aebd547..c4f493a 100644 --- a/cli/src/request/dev.rs +++ b/cli/src/request/dev.rs @@ -1,5 +1,8 @@ use std::path::PathBuf; +use cosmrs::AccountId; +use quartz_common::enclave::types::Fmspc; + use crate::request::Request; #[derive(Clone, Debug)] @@ -10,6 +13,9 @@ pub struct DevRequest { pub label: String, pub contract_manifest: PathBuf, pub release: bool, + pub fmspc: Option, + pub tcbinfo_contract: Option, + pub dcap_verifier_contract: Option, } impl From for Request { diff --git a/cli/src/request/enclave_start.rs b/cli/src/request/enclave_start.rs index f165c44..0c2f7fe 100644 --- a/cli/src/request/enclave_start.rs +++ b/cli/src/request/enclave_start.rs @@ -1,3 +1,5 @@ +use cosmrs::AccountId; +use quartz_common::enclave::types::Fmspc; use tendermint::{block::Height, Hash}; use tracing::debug; @@ -9,6 +11,9 @@ use crate::{ #[derive(Clone, Debug)] pub struct EnclaveStartRequest { pub unsafe_trust_latest: bool, + pub fmspc: Option, + pub tcbinfo_contract: Option, + pub dcap_verifier_contract: Option, } impl From for Request { diff --git a/core/quartz/Cargo.toml b/core/quartz/Cargo.toml index d685665..75ac6f4 100644 --- a/core/quartz/Cargo.toml +++ b/core/quartz/Cargo.toml @@ -12,8 +12,6 @@ readme = "README.md" [features] mock-sgx = ["quartz-cw/mock-sgx"] - - [dependencies] # external anyhow.workspace = true @@ -26,12 +24,17 @@ futures-util.workspace = true hex.workspace = true k256.workspace = true rand.workspace = true +reqwest = { workspace = true, features = ["blocking"] } serde.workspace = true serde_json.workspace = true thiserror.workspace = true tonic.workspace = true tokio.workspace = true tower.workspace = true +urlencoding.workspace = true + +# mobilecoin +mc-sgx-dcap-sys-types.workspace = true # cosmos cosmrs.workspace = true diff --git a/core/quartz/README.md b/core/quartz/README.md index 59920a9..da09c9e 100644 --- a/core/quartz/README.md +++ b/core/quartz/README.md @@ -11,7 +11,7 @@ gramine-manifest \ -Dlog_level="error" \ -Dhome=${HOME} \ -Darch_libdir="/lib/$(gcc -dumpmachine)" \ - -Dra_type="epid" \ + -Dra_type="dcap" \ -Dra_client_spid="51CAF5A48B450D624AEFE3286D314894" \ -Dra_client_linkable=1 \ -Dquartz_dir="$(pwd)" \ diff --git a/core/quartz/src/attestor.rs b/core/quartz/src/attestor.rs index b28e213..e26627f 100644 --- a/core/quartz/src/attestor.rs +++ b/core/quartz/src/attestor.rs @@ -1,26 +1,37 @@ use std::{ + error::Error, fs::{read, File}, - io::{Error as IoError, Write}, + io::{Error as IoError, ErrorKind, Write}, }; +use mc_sgx_dcap_sys_types::sgx_ql_qve_collateral_t; use quartz_cw::{ - msg::execute::attested::HasUserData, + msg::{ + execute::attested::{ + Attestation, DcapAttestation, EpidAttestation, HasUserData, MockAttestation, + RawDcapAttestation, RawEpidAttestation, RawMockAttestation, + }, + HasDomainType, + }, state::{MrEnclave, UserData}, }; +use quartz_tee_ra::intel_sgx::dcap::{Collateral, Quote3Error}; +use reqwest::blocking::Client; +use serde::Serialize; -#[cfg(not(feature = "mock-sgx"))] -pub type DefaultAttestor = EpidAttestor; - -#[cfg(feature = "mock-sgx")] -pub type DefaultAttestor = MockAttestor; +use crate::types::Fmspc; /// The trait defines the interface for generating attestations from within an enclave. pub trait Attestor: Send + Sync + 'static { type Error: ToString; + type Attestation: Attestation; + type RawAttestation: HasDomainType + Serialize; fn quote(&self, user_data: impl HasUserData) -> Result, Self::Error>; fn mr_enclave(&self) -> Result; + + fn attestation(&self, user_data: impl HasUserData) -> Result; } /// An `Attestor` for generating EPID attestations for Gramine based enclaves. @@ -29,6 +40,8 @@ pub struct EpidAttestor; impl Attestor for EpidAttestor { type Error = IoError; + type Attestation = EpidAttestation; + type RawAttestation = RawEpidAttestation; fn quote(&self, user_data: impl HasUserData) -> Result, Self::Error> { let user_data = user_data.user_data(); @@ -44,14 +57,22 @@ impl Attestor for EpidAttestor { .try_into() .expect("hardcoded array size")) } + + fn attestation(&self, _user_data: impl HasUserData) -> Result { + unimplemented!() + } } /// An `Attestor` for generating DCAP attestations for Gramine based enclaves. -#[derive(Clone, PartialEq, Debug, Default)] -pub struct DcapAttestor; +#[derive(Clone, PartialEq, Debug)] +pub struct DcapAttestor { + pub fmspc: Fmspc, +} impl Attestor for DcapAttestor { type Error = IoError; + type Attestation = DcapAttestation; + type RawAttestation = RawDcapAttestation; fn quote(&self, user_data: impl HasUserData) -> Result, Self::Error> { let user_data = user_data.user_data(); @@ -67,6 +88,98 @@ impl Attestor for DcapAttestor { .try_into() .expect("hardcoded array size")) } + + fn attestation(&self, user_data: impl HasUserData) -> Result { + fn pccs_query_pck() -> Result<(Vec, String), Box> { + let url = "https://127.0.0.1:8081/sgx/certification/v4/pckcrl?ca=processor"; + + let client = Client::builder() + .danger_accept_invalid_certs(true) // FIXME(hu55a1n1): required? + .build()?; + let response = client.get(url).send()?; + + // Parse relevant headers + let pck_crl_issuer_chain = response + .headers() + .get("SGX-PCK-CRL-Issuer-Chain") + .ok_or("Missing PCK-Issuer-Chain header")? + .to_str()? + .to_string(); + + let pck_crl = response.bytes()?; + + Ok((pck_crl.to_vec(), pck_crl_issuer_chain)) + } + + fn collateral( + tcb_info: &str, + pck_crl: Vec, + pck_crl_issuer_chain: String, + ) -> Collateral { + let mut sgx_collateral = sgx_ql_qve_collateral_t::default(); + + // SAFETY: Version is a union which is inherently unsafe + #[allow(unsafe_code)] + let version = unsafe { sgx_collateral.__bindgen_anon_1.__bindgen_anon_1.as_mut() }; + version.major_version = 3; + version.minor_version = 1; + + let mut root_crl = + include_bytes!("../../../cosmwasm/packages/quartz-tee-ra/data/root_crl.der") + .to_vec(); + root_crl.push(0); + sgx_collateral.root_ca_crl = root_crl.as_ptr() as _; + sgx_collateral.root_ca_crl_size = root_crl.len() as u32; + + let mut pck_crl = hex::decode(pck_crl).unwrap(); + pck_crl.push(0); + sgx_collateral.pck_crl = pck_crl.as_ptr() as _; + sgx_collateral.pck_crl_size = pck_crl.len() as u32; + + let pck_crl_issuer_chain = urlencoding::decode(&pck_crl_issuer_chain).unwrap(); + // pck_crl_issuer_chain.push(0); + sgx_collateral.pck_crl_issuer_chain = pck_crl_issuer_chain.as_ptr() as _; + sgx_collateral.pck_crl_issuer_chain_size = pck_crl_issuer_chain.len() as u32; + + let root_cert = + include_str!("../../../cosmwasm/packages/quartz-tee-ra/data/root_ca.pem"); + let tcb_cert = + include_str!("../../../cosmwasm/packages/quartz-tee-ra/data/tcb_signer.pem"); + let mut tcb_chain = [tcb_cert, root_cert].join("\n").as_bytes().to_vec(); + tcb_chain.push(0); + sgx_collateral.tcb_info_issuer_chain = tcb_chain.as_ptr() as _; + sgx_collateral.tcb_info_issuer_chain_size = tcb_chain.len() as u32; + + sgx_collateral.tcb_info = tcb_info.as_ptr() as _; + sgx_collateral.tcb_info_size = tcb_info.len() as u32; + + // For live data the QE identity uses the same chain as the TCB info + sgx_collateral.qe_identity_issuer_chain = tcb_chain.as_ptr() as _; + sgx_collateral.qe_identity_issuer_chain_size = tcb_chain.len() as u32; + + const QE_IDENTITY_JSON: &str = + include_str!("../../../cosmwasm/packages/quartz-tee-ra/data/qe_identity.json"); + sgx_collateral.qe_identity = QE_IDENTITY_JSON.as_ptr() as _; + sgx_collateral.qe_identity_size = QE_IDENTITY_JSON.len() as u32; + + Collateral::try_from(&sgx_collateral).expect("Failed to parse collateral") + } + + let quote = self.quote(user_data)?; + + let collateral = { + let (pck_crl, pck_crl_issuer_chain) = + pccs_query_pck().map_err(|e| IoError::new(ErrorKind::Other, e.to_string()))?; + collateral(&self.fmspc.to_string(), pck_crl, pck_crl_issuer_chain) + }; + + Ok(DcapAttestation::new( + quote + .try_into() + .map_err(|e: Quote3Error| IoError::other(e.to_string()))?, + collateral, + )) + } } /// A mock `Attestor` that creates a quote consisting of just the user report data. (only meant for @@ -76,6 +189,8 @@ pub struct MockAttestor; impl Attestor for MockAttestor { type Error = String; + type Attestation = MockAttestation; + type RawAttestation = RawMockAttestation; fn quote(&self, user_data: impl HasUserData) -> Result, Self::Error> { let user_data = user_data.user_data(); @@ -85,6 +200,10 @@ impl Attestor for MockAttestor { fn mr_enclave(&self) -> Result { Ok(Default::default()) } + + fn attestation(&self, user_data: impl HasUserData) -> Result { + Ok(MockAttestation(user_data.user_data())) + } } struct NullUserData; diff --git a/core/quartz/src/lib.rs b/core/quartz/src/lib.rs index 8093bc5..7561b30 100644 --- a/core/quartz/src/lib.rs +++ b/core/quartz/src/lib.rs @@ -1,5 +1,5 @@ #![doc = include_str!("../README.md")] -#![forbid(unsafe_code)] +// #![forbid(unsafe_code)] #![warn( clippy::checked_conversions, clippy::panic, diff --git a/core/quartz/src/server.rs b/core/quartz/src/server.rs index 8324635..bd3620e 100644 --- a/core/quartz/src/server.rs +++ b/core/quartz/src/server.rs @@ -13,7 +13,10 @@ use futures_util::StreamExt; use k256::ecdsa::SigningKey; use quartz_cw::{ msg::{ - execute::{session_create::SessionCreate, session_set_pub_key::SessionSetPubKey}, + execute::{ + attested::Attested, session_create::SessionCreate, + session_set_pub_key::SessionSetPubKey, + }, instantiate::CoreInstantiate, }, state::{Config, LightClientOpts, Nonce, Session}, @@ -49,7 +52,7 @@ use tonic::{ use tower::Service; use crate::{ - attestor::{Attestor, DefaultAttestor}, + attestor::Attestor, error::QuartzError, types::{InstantiateResponse, SessionCreateResponse, SessionSetPubKeyResponse}, }; @@ -96,12 +99,15 @@ pub struct QuartzServer { } impl QuartzServer { - pub fn new( + pub fn new( config: Config, sk: Arc>>, - attestor: DefaultAttestor, + attestor: A, ws_config: WsListenerConfig, - ) -> Self { + ) -> Self + where + A: Attestor + Clone, + { let core_service = CoreServer::new(CoreService::new(config, sk.clone(), attestor.clone())); Self { @@ -200,16 +206,19 @@ where &self, _request: Request, ) -> TonicResult> { - let core_instantiate_msg = CoreInstantiate::new(self.config.clone()); + let msg = CoreInstantiate::new(self.config.clone()); - let quote = self + let attestation = self .attestor - .quote(core_instantiate_msg) + .attestation(msg.clone()) .map_err(|e| Status::internal(e.to_string()))?; + let attested_msg = Attested::new(msg, attestation); - let response = InstantiateResponse::new(self.config.clone(), quote); + let response: InstantiateResponse = + InstantiateResponse::new(attested_msg); Ok(Response::new(response.into())) } + async fn session_create( &self, _request: Request, @@ -217,15 +226,16 @@ where // FIXME(hu55a1n1) - disallow calling more than once let mut nonce = self.nonce.lock().unwrap(); *nonce = rand::thread_rng().gen::(); + let msg = SessionCreate::new(*nonce); - let session_create_msg = SessionCreate::new(*nonce); - - let quote = self + let attestation = self .attestor - .quote(session_create_msg) + .attestation(msg.clone()) .map_err(|e| Status::internal(e.to_string()))?; + let attested_msg = Attested::new(msg, attestation); - let response = SessionCreateResponse::new(*nonce, quote); + let response: SessionCreateResponse = + SessionCreateResponse::new(attested_msg); Ok(Response::new(response.into())) } @@ -253,14 +263,16 @@ where *self.sk.lock().unwrap() = Some(sk.clone()); let pk = sk.verifying_key(); - let session_set_pub_key_msg = SessionSetPubKey::new(*nonce, *pk); + let msg = SessionSetPubKey::new(*nonce, *pk); - let quote = self + let attestation = self .attestor - .quote(session_set_pub_key_msg) + .attestation(msg.clone()) .map_err(|e| Status::internal(e.to_string()))?; + let attested_msg = Attested::new(msg, attestation); - let response = SessionSetPubKeyResponse::new(*nonce, *pk, quote); + let response: SessionSetPubKeyResponse = + SessionSetPubKeyResponse::new(attested_msg); Ok(Response::new(response.into())) } } diff --git a/core/quartz/src/types.rs b/core/quartz/src/types.rs index 2d9ce27..ef24a1b 100644 --- a/core/quartz/src/types.rs +++ b/core/quartz/src/types.rs @@ -1,8 +1,18 @@ -use cosmwasm_std::{HexBinary, StdError}; -use k256::ecdsa::VerifyingKey; -use quartz_cw::{ - error::Error as QuartzCwError, - state::{Config, Nonce, RawConfig}, +use std::{ + fmt::{Display, Formatter}, + marker::PhantomData, + str::FromStr, +}; + +use hex::FromHexError; +use quartz_cw::msg::{ + execute::{ + attested::{Attested, RawAttested}, + session_create::{RawSessionCreate, SessionCreate}, + session_set_pub_key::{RawSessionSetPubKey, SessionSetPubKey}, + }, + instantiate::{CoreInstantiate, RawCoreInstantiate}, + HasDomainType, }; use quartz_proto::quartz::{ InstantiateResponse as RawInstantiateResponse, @@ -12,41 +22,29 @@ use quartz_proto::quartz::{ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq)] -pub struct InstantiateResponse { - message: InstantiateResponseMsg, +pub struct InstantiateResponse { + message: Attested, + _phantom: PhantomData, } -impl InstantiateResponse { - pub fn new(config: Config, quote: Vec) -> Self { +impl InstantiateResponse { + pub fn new(message: Attested) -> Self { Self { - message: InstantiateResponseMsg { config, quote }, + message, + _phantom: Default::default(), } } - - pub fn quote(&self) -> &[u8] { - &self.message.quote - } - - pub fn into_message(self) -> InstantiateResponseMsg { + pub fn into_message(self) -> Attested { self.message } } -impl TryFrom for InstantiateResponse { - type Error = StdError; - - fn try_from(value: RawInstantiateResponse) -> Result { - let raw_message: RawInstantiateResponseMsg = serde_json::from_str(&value.message) - .map_err(|e| StdError::parse_err("RawInstantiateResponseMsg", e))?; - Ok(Self { - message: raw_message.try_into()?, - }) - } -} - -impl From for RawInstantiateResponse { - fn from(value: InstantiateResponse) -> Self { - let raw_message: RawInstantiateResponseMsg = value.message.into(); +impl From> for RawInstantiateResponse +where + RA: HasDomainType + Serialize, +{ + fn from(value: InstantiateResponse) -> Self { + let raw_message: RawAttested = value.message.into(); Self { message: serde_json::to_string(&raw_message).expect("infallible serializer"), } @@ -54,79 +52,30 @@ impl From for RawInstantiateResponse { } #[derive(Clone, Debug, PartialEq)] -pub struct InstantiateResponseMsg { - config: Config, - quote: Vec, +pub struct SessionCreateResponse { + message: Attested, + _phantom: PhantomData, } -impl InstantiateResponseMsg { - pub fn into_tuple(self) -> (Config, Vec) { - (self.config, self.quote) - } -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct RawInstantiateResponseMsg { - config: RawConfig, - quote: HexBinary, -} - -impl TryFrom for InstantiateResponseMsg { - type Error = StdError; - - fn try_from(value: RawInstantiateResponseMsg) -> Result { - Ok(Self { - config: value.config.try_into()?, - quote: value.quote.into(), - }) - } -} - -impl From for RawInstantiateResponseMsg { - fn from(value: InstantiateResponseMsg) -> Self { +impl SessionCreateResponse { + pub fn new(message: Attested) -> Self { Self { - config: value.config.into(), - quote: value.quote.into(), - } - } -} - -#[derive(Clone, Debug, PartialEq)] -pub struct SessionCreateResponse { - message: SessionCreateResponseMsg, -} - -impl SessionCreateResponse { - pub fn new(nonce: Nonce, quote: Vec) -> Self { - Self { - message: SessionCreateResponseMsg { nonce, quote }, + message, + _phantom: Default::default(), } } - pub fn quote(&self) -> &[u8] { - &self.message.quote - } - - pub fn into_message(self) -> SessionCreateResponseMsg { + pub fn into_message(self) -> Attested { self.message } } -impl TryFrom for SessionCreateResponse { - type Error = StdError; - - fn try_from(value: RawSessionCreateResponse) -> Result { - let raw_message: RawSessionCreateResponseMsg = serde_json::from_str(&value.message) - .map_err(|e| StdError::parse_err("RawSessionCreateResponseMsg", e))?; - Ok(Self { - message: raw_message.try_into()?, - }) - } -} - -impl From for RawSessionCreateResponse { - fn from(value: SessionCreateResponse) -> Self { - let raw_message: RawSessionCreateResponseMsg = value.message.into(); +impl From> for RawSessionCreateResponse +where + RA: HasDomainType + Serialize, +{ + fn from(value: SessionCreateResponse) -> Self { + let raw_message: RawAttested = value.message.into(); Self { message: serde_json::to_string(&raw_message).expect("infallible serializer"), } @@ -134,130 +83,67 @@ impl From for RawSessionCreateResponse { } #[derive(Clone, Debug, PartialEq)] -pub struct SessionCreateResponseMsg { - nonce: Nonce, - quote: Vec, +pub struct SessionSetPubKeyResponse { + message: Attested, + _phantom: PhantomData, } -impl SessionCreateResponseMsg { - pub fn into_tuple(self) -> (Nonce, Vec) { - (self.nonce, self.quote) - } -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct RawSessionCreateResponseMsg { - nonce: HexBinary, - quote: HexBinary, -} - -impl TryFrom for SessionCreateResponseMsg { - type Error = StdError; - - fn try_from(value: RawSessionCreateResponseMsg) -> Result { - Ok(Self { - nonce: value.nonce.to_array()?, - quote: value.quote.into(), - }) - } -} - -impl From for RawSessionCreateResponseMsg { - fn from(value: SessionCreateResponseMsg) -> Self { +impl SessionSetPubKeyResponse { + pub fn new(message: Attested) -> Self { Self { - nonce: value.nonce.into(), - quote: value.quote.into(), - } - } -} - -#[derive(Clone, Debug, PartialEq)] -pub struct SessionSetPubKeyResponse { - message: SessionSetPubKeyResponseMsg, -} - -impl SessionSetPubKeyResponse { - pub fn new(nonce: Nonce, pub_key: VerifyingKey, quote: Vec) -> Self { - Self { - message: SessionSetPubKeyResponseMsg { - nonce, - pub_key, - quote, - }, + message, + _phantom: Default::default(), } } - pub fn quote(&self) -> &[u8] { - &self.message.quote - } - - pub fn into_message(self) -> SessionSetPubKeyResponseMsg { + pub fn into_message(self) -> Attested { self.message } } -impl TryFrom for SessionSetPubKeyResponse { - type Error = StdError; - - fn try_from(value: RawSessionSetPubKeyResponse) -> Result { - let raw_message: RawSessionSetPubKeyResponseMsg = serde_json::from_str(&value.message) - .map_err(|e| StdError::parse_err("RawSessionSetPubKeyResponseMsg", e))?; - Ok(Self { - message: raw_message.try_into()?, - }) - } -} - -impl From for RawSessionSetPubKeyResponse { - fn from(value: SessionSetPubKeyResponse) -> Self { - let raw_message: RawSessionSetPubKeyResponseMsg = value.message.into(); +impl From> for RawSessionSetPubKeyResponse +where + RA: HasDomainType + Serialize, +{ + fn from(value: SessionSetPubKeyResponse) -> Self { + let raw_message: RawAttested = value.message.into(); Self { message: serde_json::to_string(&raw_message).expect("infallible serializer"), } } } -#[derive(Clone, Debug, PartialEq)] -pub struct SessionSetPubKeyResponseMsg { - nonce: Nonce, - pub_key: VerifyingKey, - quote: Vec, -} +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct Fmspc(pub [u8; 6]); -impl SessionSetPubKeyResponseMsg { - pub fn into_tuple(self) -> (VerifyingKey, Vec) { - (self.pub_key, self.quote) +impl AsRef<[u8]> for Fmspc { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() } } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct RawSessionSetPubKeyResponseMsg { - nonce: HexBinary, - pub_key: HexBinary, - quote: HexBinary, -} +impl FromStr for Fmspc { + type Err = FromHexError; -impl TryFrom for SessionSetPubKeyResponseMsg { - type Error = StdError; - - fn try_from(value: RawSessionSetPubKeyResponseMsg) -> Result { - let pub_key = VerifyingKey::from_sec1_bytes(&value.pub_key) - .map_err(QuartzCwError::from) - .map_err(|e| StdError::generic_err(e.to_string()))?; - Ok(Self { - nonce: value.nonce.to_array()?, - pub_key, - quote: value.quote.into(), - }) + fn from_str(s: &str) -> Result { + let bytes = hex::decode(s)?; + let fmspc: [u8; 6] = bytes + .try_into() + .map_err(|_| FromHexError::InvalidStringLength)?; + Ok(Self(fmspc)) } } -impl From for RawSessionSetPubKeyResponseMsg { - fn from(value: SessionSetPubKeyResponseMsg) -> Self { - Self { - nonce: value.nonce.into(), - pub_key: value.pub_key.to_sec1_bytes().into_vec().into(), - quote: value.quote.into(), - } +impl TryFrom for Fmspc { + type Error = FromHexError; + + fn try_from(value: String) -> Result { + value.as_str().parse() + } +} + +impl Display for Fmspc { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", hex::encode(self)) } } diff --git a/cosmwasm/packages/quartz-cw/Cargo.toml b/cosmwasm/packages/quartz-cw/Cargo.toml index 0e4c276..f9de7a1 100644 --- a/cosmwasm/packages/quartz-cw/Cargo.toml +++ b/cosmwasm/packages/quartz-cw/Cargo.toml @@ -13,16 +13,18 @@ readme = "README.md" default = [] mock-sgx = [] std = ["k256/std", "serde/std", "serde_json/std", "sha2/std", "cosmwasm-std/std"] +library = [] [dependencies] # external +ciborium.workspace = true +hex.workspace = true k256.workspace = true serde.workspace = true serde_json.workspace = true serde_with.workspace = true sha2.workspace = true thiserror.workspace = true -hex.workspace = true # cosmos cw-storage-plus.workspace = true @@ -30,8 +32,9 @@ cosmwasm-schema.workspace = true cosmwasm-std.workspace = true # quartz +quartz-dcap-verifier-msgs.workspace = true quartz-tee-ra.workspace = true -tcbinfo.workspace = true +tcbinfo-msgs.workspace = true [dev-dependencies] serde_json.workspace = true diff --git a/cosmwasm/packages/quartz-cw/src/error.rs b/cosmwasm/packages/quartz-cw/src/error.rs index bb78fb1..453b3e1 100644 --- a/cosmwasm/packages/quartz-cw/src/error.rs +++ b/cosmwasm/packages/quartz-cw/src/error.rs @@ -17,6 +17,8 @@ pub enum Error { InvalidFmspc(String), #[error("TCB Info query error: {0}")] TcbInfoQueryError(String), + #[error("DCAP verification query error: {0}")] + DcapVerificationQueryError(String), } impl From for Error { diff --git a/cosmwasm/packages/quartz-cw/src/handler/execute/attested.rs b/cosmwasm/packages/quartz-cw/src/handler/execute/attested.rs index a68ce66..0add5a0 100644 --- a/cosmwasm/packages/quartz-cw/src/handler/execute/attested.rs +++ b/cosmwasm/packages/quartz-cw/src/handler/execute/attested.rs @@ -1,28 +1,46 @@ +use ciborium::{from_reader as from_cbor_slice, into_writer as into_cbor, Value as CborValue}; use cosmwasm_std::{ - from_json, to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, QueryRequest, Response, - WasmQuery, + to_json_binary, Deps, DepsMut, Env, MessageInfo, QueryRequest, Response, StdResult, WasmQuery, }; +use quartz_dcap_verifier_msgs::QueryMsg as DcapVerifierQueryMsg; use quartz_tee_ra::{ - intel_sgx::dcap::{Collateral, TrustedMrEnclaveIdentity}, - verify_dcap_attestation, verify_epid_attestation, Error as RaVerificationError, + intel_sgx::dcap::{Collateral, TrustedIdentity, TrustedMrEnclaveIdentity}, + verify_epid_attestation, Error as RaVerificationError, }; -use tcbinfo::msg::{GetTcbInfoResponse, QueryMsg as TcbInfoQueryMsg}; +use serde::{de::DeserializeOwned, Serialize}; +use tcbinfo_msgs::{GetTcbInfoResponse, QueryMsg as TcbInfoQueryMsg}; use crate::{ error::Error, handler::Handler, msg::execute::attested::{ Attestation, Attested, AttestedMsgSansHandler, DcapAttestation, EpidAttestation, - HasUserData, MockAttestation, + HasUserData, MockAttestation, Quote, }, state::CONFIG, }; -pub fn query_tcbinfo(deps: Deps<'_>, fmspc: String) -> Result { - let config = CONFIG.load(deps.storage).map_err(Error::Std)?; - let tcbinfo_addr = config - .tcb_info() - .expect("TcbInfo contract address is required for DCAP"); +fn query_contract( + deps: Deps<'_>, + contract_addr: String, + query_msg: impl Serialize, +) -> StdResult { + let request = QueryRequest::Wasm(WasmQuery::Smart { + contract_addr, + msg: to_json_binary(&query_msg)?, + }); + + deps.querier.query(&request) +} + +fn query_tcbinfo(deps: Deps<'_>, fmspc: String) -> Result { + let tcbinfo_addr = { + let config = CONFIG.load(deps.storage).map_err(Error::Std)?; + config + .tcbinfo_contract() + .expect("TcbInfo contract address is required for DCAP") + .to_string() + }; let fmspc_bytes = hex::decode(&fmspc).map_err(|_| Error::InvalidFmspc("Invalid FMSPC format".to_string()))?; @@ -32,16 +50,40 @@ pub fn query_tcbinfo(deps: Deps<'_>, fmspc: String) -> Result { let query_msg = TcbInfoQueryMsg::GetTcbInfo { fmspc }; - let request = QueryRequest::Wasm(WasmQuery::Smart { - contract_addr: tcbinfo_addr, - msg: to_json_binary(&query_msg).map_err(Error::Std)?, - }); - - deps.querier - .query(&request) + query_contract(deps, tcbinfo_addr, &query_msg) .map_err(|err| Error::TcbInfoQueryError(err.to_string())) } +fn to_cbor_vec(value: &T) -> Vec { + let mut buffer = Vec::new(); + into_cbor(&value, &mut buffer).expect("Serialization failed"); + buffer +} + +fn query_dcap_verifier( + deps: Deps<'_>, + quote: Quote, + mr_enclave: impl Into, + updated_collateral: Collateral, +) -> Result<(), Error> { + let query_msg = DcapVerifierQueryMsg::VerifyDcapAttestation { + quote: quote.as_ref().to_vec().into(), + collateral: to_cbor_vec(&updated_collateral).into(), + identities: Some(to_cbor_vec(&[mr_enclave.into()])), + }; + + let dcap_verifier_contract = { + let config = CONFIG.load(deps.storage).map_err(Error::Std)?; + config + .dcap_verifier_contract() + .expect("verifier_contract address is required for DCAP") + .to_string() + }; + + query_contract(deps, dcap_verifier_contract, &query_msg) + .map_err(|err| Error::DcapVerificationQueryError(err.to_string())) +} + impl Handler for EpidAttestation { fn handle( self, @@ -63,42 +105,48 @@ impl Handler for EpidAttestation { impl Handler for DcapAttestation { fn handle(self, deps: DepsMut<'_>, _env: &Env, _info: &MessageInfo) -> Result { let (quote, collateral) = self.clone().into_tuple(); - let mr_enclave = TrustedMrEnclaveIdentity::new(self.mr_enclave().into(), [""; 0], [""; 0]); + let mr_enclave = TrustedMrEnclaveIdentity::new( + self.mr_enclave().into(), + [""; 0], + ["INTEL-SA-00334", "INTEL-SA-00615"], + ); // Retrieve the FMSPC from the collateral let fmspc_hex = collateral.tcb_info().to_string(); // Query the tcbinfo contract with the FMSPC retrieved and validated - let tcb_info_query = query_tcbinfo(deps.as_ref(), fmspc_hex)?; - let tcb_info_response: GetTcbInfoResponse = from_json(tcb_info_query)?; + let tcb_info_response = query_tcbinfo(deps.as_ref(), fmspc_hex)?; // Serialize the existing collateral - let mut collateral_json: serde_json::Value = - serde_json::to_value(&collateral).map_err(|e| { + let collateral_serialized = to_cbor_vec(&collateral); + let mut collateral_value: CborValue = from_cbor_slice(collateral_serialized.as_slice()) + .map_err(|e| { Error::TcbInfoQueryError(format!("Failed to serialize collateral: {}", e)) })?; // Update the tcb_info in the serialized data - collateral_json["tcb_info"] = tcb_info_response.tcb_info; + fn try_get_tcb_info(collateral_value: &mut CborValue) -> Option<&mut CborValue> { + if let CborValue::Map(map) = collateral_value { + return map + .iter_mut() + .find(|(k, _)| k == &CborValue::Text("tcb_info".to_string())) + .map(|(_, v)| v); + } + None + } + + let tcb_info_value = try_get_tcb_info(&mut collateral_value).expect("infallible serde"); + *tcb_info_value = CborValue::Text(tcb_info_response.tcb_info.to_string()); // Deserialize back into a Collateral - let updated_collateral: Collateral = - serde_json::from_value(collateral_json).map_err(|e| { + let collateral_serialized = to_cbor_vec(&collateral_value); + let updated_collateral: Collateral = from_cbor_slice(collateral_serialized.as_slice()) + .map_err(|e| { Error::TcbInfoQueryError(format!("Failed to deserialize updated collateral: {}", e)) })?; - // attestation handler MUST verify that the user_data and mr_enclave match the config/msg - let verification_output = - verify_dcap_attestation(quote, updated_collateral, &[mr_enclave.into()]); - - // attestation handler MUST verify that the user_data and mr_enclave match the config/msg - if verification_output.is_success().into() { - Ok(Response::default()) - } else { - Err(Error::RaVerification(RaVerificationError::Dcap( - verification_output, - ))) - } + query_dcap_verifier(deps.as_ref(), quote, mr_enclave, updated_collateral) + .map(|_| Response::default()) } } diff --git a/cosmwasm/packages/quartz-cw/src/msg.rs b/cosmwasm/packages/quartz-cw/src/msg.rs index 4b440f8..6b3f223 100644 --- a/cosmwasm/packages/quartz-cw/src/msg.rs +++ b/cosmwasm/packages/quartz-cw/src/msg.rs @@ -5,7 +5,8 @@ pub mod query; use cosmwasm_std::StdError; pub use execute::{Execute as ExecuteMsg, RawExecute as RawExecuteMsg}; pub use instantiate::{Instantiate as InstantiateMsg, RawInstantiate as RawInstantiateMsg}; +use serde::Serialize; -pub trait HasDomainType: From { +pub trait HasDomainType: From + Serialize { type DomainType: TryFrom; } diff --git a/cosmwasm/packages/quartz-cw/src/msg/execute/attested.rs b/cosmwasm/packages/quartz-cw/src/msg/execute/attested.rs index 41ea583..dabcc2f 100644 --- a/cosmwasm/packages/quartz-cw/src/msg/execute/attested.rs +++ b/cosmwasm/packages/quartz-cw/src/msg/execute/attested.rs @@ -13,9 +13,9 @@ use serde::Serialize; pub type Quote = Quote3>; #[cfg(not(feature = "mock-sgx"))] -pub type DefaultAttestation = EpidAttestation; +pub type DefaultAttestation = DcapAttestation; #[cfg(not(feature = "mock-sgx"))] -pub type RawDefaultAttestation = RawEpidAttestation; +pub type RawDefaultAttestation = RawDcapAttestation; #[cfg(feature = "mock-sgx")] pub type DefaultAttestation = MockAttestation; @@ -178,8 +178,8 @@ impl DcapAttestation { #[cw_serde] pub struct RawDcapAttestation { - quote: HexBinary, - collateral: serde_json::Value, + pub quote: HexBinary, + pub collateral: HexBinary, } impl TryFrom for DcapAttestation { @@ -187,10 +187,11 @@ impl TryFrom for DcapAttestation { fn try_from(value: RawDcapAttestation) -> Result { let quote_bytes: Vec = value.quote.into(); + let collateral_bytes: Vec = value.collateral.into(); let quote = quote_bytes .try_into() .map_err(|e: Quote3Error| StdError::parse_err("Quote", e.to_string()))?; - let collateral = serde_json::from_value(value.collateral) + let collateral = ciborium::from_reader(collateral_bytes.as_slice()) .map_err(|e| StdError::parse_err("Collateral", e.to_string()))?; Ok(Self { quote, collateral }) @@ -199,11 +200,13 @@ impl TryFrom for DcapAttestation { impl From for RawDcapAttestation { fn from(value: DcapAttestation) -> Self { + let mut collateral_serialized = Vec::new(); + ciborium::into_writer(&value.collateral, &mut collateral_serialized) + .expect("infallible serializer"); + Self { quote: value.quote.as_ref().to_vec().into(), - collateral: serde_json::to_vec(&value.collateral) - .expect("infallible serializer") - .into(), + collateral: collateral_serialized.into(), } } } @@ -282,7 +285,7 @@ pub struct AttestedMsgSansHandler(pub T); #[cw_serde] pub struct RawAttestedMsgSansHandler(pub T); -impl HasDomainType for RawAttestedMsgSansHandler { +impl HasDomainType for RawAttestedMsgSansHandler { type DomainType = AttestedMsgSansHandler; } diff --git a/cosmwasm/packages/quartz-cw/src/msg/execute/session_create.rs b/cosmwasm/packages/quartz-cw/src/msg/execute/session_create.rs index 99aa545..e834653 100644 --- a/cosmwasm/packages/quartz-cw/src/msg/execute/session_create.rs +++ b/cosmwasm/packages/quartz-cw/src/msg/execute/session_create.rs @@ -1,5 +1,6 @@ use cosmwasm_schema::cw_serde; use cosmwasm_std::{HexBinary, StdError}; +use sha2::{Digest, Sha256}; use crate::{ msg::{execute::attested::HasUserData, HasDomainType}, @@ -49,8 +50,15 @@ impl HasDomainType for RawSessionCreate { impl HasUserData for SessionCreate { fn user_data(&self) -> UserData { + let mut hasher = Sha256::new(); + hasher.update( + serde_json::to_string(&RawSessionCreate::from(self.clone())) + .expect("infallible serializer"), + ); + let digest: [u8; 32] = hasher.finalize().into(); + let mut user_data = [0u8; 64]; - user_data[0..32].copy_from_slice(&self.nonce); + user_data[0..32].copy_from_slice(&digest); user_data } } diff --git a/cosmwasm/packages/quartz-cw/src/msg/execute/session_set_pub_key.rs b/cosmwasm/packages/quartz-cw/src/msg/execute/session_set_pub_key.rs index 6325212..321829a 100644 --- a/cosmwasm/packages/quartz-cw/src/msg/execute/session_set_pub_key.rs +++ b/cosmwasm/packages/quartz-cw/src/msg/execute/session_set_pub_key.rs @@ -65,8 +65,10 @@ impl HasDomainType for RawSessionSetPubKey { impl HasUserData for SessionSetPubKey { fn user_data(&self) -> UserData { let mut hasher = Sha256::new(); - hasher.update(self.nonce); - hasher.update(self.pub_key.to_sec1_bytes()); + hasher.update( + serde_json::to_string(&RawSessionSetPubKey::from(self.clone())) + .expect("infallible serializer"), + ); let digest: [u8; 32] = hasher.finalize().into(); let mut user_data = [0u8; 64]; diff --git a/cosmwasm/packages/quartz-cw/src/msg/instantiate.rs b/cosmwasm/packages/quartz-cw/src/msg/instantiate.rs index 3c69df4..79398ca 100644 --- a/cosmwasm/packages/quartz-cw/src/msg/instantiate.rs +++ b/cosmwasm/packages/quartz-cw/src/msg/instantiate.rs @@ -91,7 +91,7 @@ impl HasUserData for CoreInstantiate { fn user_data(&self) -> UserData { let mut hasher = Sha256::new(); hasher.update( - serde_json::to_string(&RawConfig::from(self.config.clone())) + serde_json::to_string(&RawCoreInstantiate::from(self.clone())) .expect("infallible serializer"), ); let digest: [u8; 32] = hasher.finalize().into(); diff --git a/cosmwasm/packages/quartz-cw/src/state.rs b/cosmwasm/packages/quartz-cw/src/state.rs index dff604a..75065af 100644 --- a/cosmwasm/packages/quartz-cw/src/state.rs +++ b/cosmwasm/packages/quartz-cw/src/state.rs @@ -18,6 +18,7 @@ pub struct Config { epoch_duration: Duration, light_client_opts: LightClientOpts, tcbinfo_contract: Option, + dcap_verifier_contract: Option, } impl Config { @@ -26,12 +27,14 @@ impl Config { epoch_duration: Duration, light_client_opts: LightClientOpts, tcbinfo_contract: Option, + dcap_verifier_contract: Option, ) -> Self { Self { mr_enclave, epoch_duration, light_client_opts, tcbinfo_contract, + dcap_verifier_contract, } } @@ -42,10 +45,6 @@ impl Config { pub fn mr_enclave(&self) -> MrEnclave { self.mr_enclave } - - pub fn tcbinfo_contract(&self) -> Option<&str> { - self.tcbinfo_contract.as_deref() - } } #[cw_serde] @@ -54,6 +53,7 @@ pub struct RawConfig { epoch_duration: Duration, light_client_opts: RawLightClientOpts, tcbinfo_contract: Option, + dcap_verifier_contract: Option, } impl RawConfig { @@ -61,8 +61,12 @@ impl RawConfig { self.mr_enclave.as_slice() } - pub fn tcb_info(&self) -> Option { - self.tcbinfo_contract.clone().map(|c| c.to_string()) + pub fn tcbinfo_contract(&self) -> Option<&str> { + self.tcbinfo_contract.as_deref() + } + + pub fn dcap_verifier_contract(&self) -> Option<&str> { + self.dcap_verifier_contract.as_deref() } } @@ -78,6 +82,7 @@ impl TryFrom for Config { .try_into() .map_err(|e| StdError::parse_err("light_client_opts", e))?, tcbinfo_contract: value.tcbinfo_contract, + dcap_verifier_contract: value.dcap_verifier_contract, }) } } @@ -89,6 +94,7 @@ impl From for RawConfig { epoch_duration: value.epoch_duration, light_client_opts: value.light_client_opts.into(), tcbinfo_contract: value.tcbinfo_contract, + dcap_verifier_contract: value.dcap_verifier_contract, } } } diff --git a/cosmwasm/packages/quartz-dcap-verifier/Cargo.toml b/cosmwasm/packages/quartz-dcap-verifier/Cargo.toml new file mode 100644 index 0000000..1666a38 --- /dev/null +++ b/cosmwasm/packages/quartz-dcap-verifier/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "quartz-dcap-verifier" +version = "0.1.0" +edition = "2021" + +exclude = [ + # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. + "contract.wasm", + "hash.txt", +] + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +# use library feature to disable all instantiate/execute/query exports +library = [] + +[package.metadata.scripts] +optimize = """docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/rust-optimizer:0.14.0 +""" + +[dependencies] +# external +ciborium.workspace = true + +# cosmos +cosmwasm-schema.workspace = true +cosmwasm-std.workspace = true + +# quartz +quartz-dcap-verifier-msgs.workspace = true +quartz-tee-ra.workspace = true + +# patch indirect deps +getrandom = { version = "0.2.15", features = ["js"] } + +[dev-dependencies] diff --git a/cosmwasm/packages/quartz-dcap-verifier/README.md b/cosmwasm/packages/quartz-dcap-verifier/README.md new file mode 100644 index 0000000..9ac8a14 --- /dev/null +++ b/cosmwasm/packages/quartz-dcap-verifier/README.md @@ -0,0 +1,13 @@ +# CosmWasm smart contract to verify DCAP attestations + +## Testing instructions +``` +wasmd query wasm contract-state smart "$CONTRACT" '{ + "verify_dcap_attestation": { + "quote": { /* ... */ }, + "collateral": { /* ... */ }, + "mrenclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb", + "user_data": "9113b0be77ed5d0d68680ec77206b8d587ed40679b71321ccdd5405e4d54a6820000000000000000000000000000000000000000000000000000000000000000" + } +}' +``` \ No newline at end of file diff --git a/cosmwasm/packages/quartz-dcap-verifier/msgs/Cargo.toml b/cosmwasm/packages/quartz-dcap-verifier/msgs/Cargo.toml new file mode 100644 index 0000000..a1916d0 --- /dev/null +++ b/cosmwasm/packages/quartz-dcap-verifier/msgs/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "quartz-dcap-verifier-msgs" +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +# cosmos +cosmwasm-schema.workspace = true +cosmwasm-std.workspace = true diff --git a/cosmwasm/packages/quartz-dcap-verifier/msgs/src/lib.rs b/cosmwasm/packages/quartz-dcap-verifier/msgs/src/lib.rs new file mode 100644 index 0000000..5fa822c --- /dev/null +++ b/cosmwasm/packages/quartz-dcap-verifier/msgs/src/lib.rs @@ -0,0 +1,20 @@ +use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::HexBinary; + +#[cw_serde] +pub struct InstantiateMsg; + +#[cw_serde] +pub enum ExecuteMsg {} + +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + /// Verify a DCAP attestation + #[returns(())] + VerifyDcapAttestation { + quote: HexBinary, + collateral: HexBinary, + identities: Option>, + }, +} diff --git a/cosmwasm/packages/quartz-dcap-verifier/src/bin/dcap_verifier_schema.rs b/cosmwasm/packages/quartz-dcap-verifier/src/bin/dcap_verifier_schema.rs new file mode 100644 index 0000000..88864ff --- /dev/null +++ b/cosmwasm/packages/quartz-dcap-verifier/src/bin/dcap_verifier_schema.rs @@ -0,0 +1,10 @@ +use cosmwasm_schema::write_api; +use quartz_dcap_verifier_msgs::{ExecuteMsg, InstantiateMsg, QueryMsg}; + +fn main() { + write_api! { + instantiate: InstantiateMsg, + execute: ExecuteMsg, + query: QueryMsg, + } +} diff --git a/cosmwasm/packages/quartz-dcap-verifier/src/contract.rs b/cosmwasm/packages/quartz-dcap-verifier/src/contract.rs new file mode 100644 index 0000000..9118ba3 --- /dev/null +++ b/cosmwasm/packages/quartz-dcap-verifier/src/contract.rs @@ -0,0 +1,65 @@ +#[cfg(not(feature = "library"))] +use cosmwasm_std::entry_point; +use cosmwasm_std::{ + to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError, StdResult, +}; +use quartz_dcap_verifier_msgs::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use quartz_tee_ra::{ + intel_sgx::dcap::{Collateral, Quote3, TrustedIdentity}, + verify_dcap_attestation, Error, +}; + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn instantiate( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: InstantiateMsg, +) -> Result { + Ok(Response::default()) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn execute( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: ExecuteMsg, +) -> StdResult { + unimplemented!() +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + match msg { + QueryMsg::VerifyDcapAttestation { + quote, + collateral, + identities, + } => { + let quote = Quote3::>::try_from(Vec::::from(quote)) + .map_err(|e| StdError::generic_err(format!("Quote parse error: {e}")))?; + let collateral: Collateral = ciborium::from_reader(collateral.as_slice()) + .map_err(|e| StdError::generic_err(format!("Collateral deserialize error: {e}")))?; + let identities: Vec = if let Some(identities) = identities { + ciborium::from_reader(identities.as_slice()) + .map_err(|e| StdError::generic_err(format!("Identities parse error: {e}")))? + } else { + vec![] + }; + + // attestation handler MUST verify that the user_data and mr_enclave match the config/msg + let verification_output = + verify_dcap_attestation(quote, collateral, identities.as_slice()); + + // attestation handler MUST verify that the user_data and mr_enclave match the config/msg + if verification_output.is_success().into() { + to_json_binary(&()) + } else { + Err(StdError::generic_err( + Error::Dcap(verification_output).to_string(), + )) + } + } + } +} diff --git a/cosmwasm/packages/quartz-dcap-verifier/src/lib.rs b/cosmwasm/packages/quartz-dcap-verifier/src/lib.rs new file mode 100644 index 0000000..c3ee4c1 --- /dev/null +++ b/cosmwasm/packages/quartz-dcap-verifier/src/lib.rs @@ -0,0 +1,10 @@ +#![deny( + warnings, + trivial_casts, + trivial_numeric_casts, + unused_import_braces, + unused_qualifications +)] +#![forbid(unsafe_code)] + +pub mod contract; diff --git a/cosmwasm/packages/quartz-tee-ra/Cargo.toml b/cosmwasm/packages/quartz-tee-ra/Cargo.toml index 9aaba50..b9aeeb3 100644 --- a/cosmwasm/packages/quartz-tee-ra/Cargo.toml +++ b/cosmwasm/packages/quartz-tee-ra/Cargo.toml @@ -12,7 +12,6 @@ readme = "README.md" [dependencies] # external der.workspace = true -displaydoc.workspace = true hex-literal.workspace = true num-bigint.workspace = true serde.workspace = true @@ -21,13 +20,10 @@ sha2.workspace = true thiserror.workspace = true x509-cert.workspace = true x509-parser.workspace = true -zeroize.workspace = true # mobilecoin mc-attestation-verifier.workspace = true -mc-sgx-core-types.workspace = true mc-sgx-dcap-types.workspace = true -mc-sgx-dcap-sys-types.workspace = true # cosmos cosmwasm-schema.workspace = true @@ -35,3 +31,6 @@ cosmwasm-std.workspace = true [dev-dependencies] hex = "0.4.3" +mc-sgx-dcap-types.workspace = true +mc-sgx-core-types.workspace = true +mc-sgx-dcap-sys-types.workspace = true diff --git a/cosmwasm/packages/quartz-tee-ra/src/intel_sgx/dcap/certificate_chain.rs b/cosmwasm/packages/quartz-tee-ra/src/intel_sgx/dcap/certificate_chain.rs index a70a50a..631e896 100644 --- a/cosmwasm/packages/quartz-tee-ra/src/intel_sgx/dcap/certificate_chain.rs +++ b/cosmwasm/packages/quartz-tee-ra/src/intel_sgx/dcap/certificate_chain.rs @@ -1,7 +1,7 @@ -use der::{pem::LineEnding, DateTime, EncodePem}; +use der::{DateTime, Encode}; use mc_attestation_verifier::{CertificateChainVerifier, CertificateChainVerifierError}; use x509_cert::{crl::CertificateList, Certificate}; -use x509_parser::{parse_x509_certificate, pem::parse_x509_pem}; +use x509_parser::parse_x509_certificate; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)] pub struct TlsCertificateChainVerifier; @@ -22,18 +22,13 @@ impl CertificateChainVerifier for TlsCertificateChainVerifier { ) -> Result<(), CertificateChainVerifierError> { let enc_certs = certificate_chain .into_iter() - .map(|cert| cert.to_pem(LineEnding::LF)) + .map(|cert| cert.to_der()) .collect::, _>>() .map_err(|_| CertificateChainVerifierError::GeneralCertificateError)?; - let pem_chain = enc_certs + let cert_chain = enc_certs .iter() - .map(|enc_cert| parse_x509_pem(enc_cert.as_ref())) - .collect::, _>>() - .map_err(|_| CertificateChainVerifierError::GeneralCertificateError)?; - let cert_chain = pem_chain - .iter() - .map(|pem| parse_x509_certificate(&pem.1.contents)) + .map(|der| parse_x509_certificate(der)) .collect::, _>>() .map_err(|_| CertificateChainVerifierError::GeneralCertificateError)?; // Skip applying the Certificate Revocation List entirely diff --git a/cosmwasm/packages/tcbinfo/Cargo.toml b/cosmwasm/packages/tcbinfo/Cargo.toml index 82c1dc3..0063577 100644 --- a/cosmwasm/packages/tcbinfo/Cargo.toml +++ b/cosmwasm/packages/tcbinfo/Cargo.toml @@ -1,25 +1,17 @@ [package] name = "tcbinfo" -version = "0.1.0" -authors = ["quinine"] -edition = "2021" +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] crate-type = ["cdylib", "rlib"] -[profile.release] -opt-level = 3 -debug = false -rpath = false -lto = true -debug-assertions = false -codegen-units = 1 -panic = 'abort' -incremental = false -overflow-checks = true - [features] # use library feature to disable all instantiate/execute/query exports library = [] @@ -32,25 +24,31 @@ optimize = """docker run --rm -v "$(pwd)":/code \ """ [dependencies] -cosmwasm-schema = "2.0.1" -cosmwasm-std = { version = "2.0.1", default-features = false, features = [ - "cosmwasm_1_3", - # Enable this if you only deploy to chains that have CosmWasm 1.4 or higher - # "cosmwasm_1_4", -] } -cw-storage-plus = "2.0.0" -cw2 = "2.0.0" -schemars = "0.8.16" -serde = { version = "1.0.197", default-features = false, features = ["derive"] } -thiserror = { version = "1.0.58" } -x509-cert = { version = "0.2.5", default-features = false, features = ["pem"] } -getrandom ={ version = "0.2.5", default-features = false, features = ["js"]} -der = { version = "0.7.9" } -quartz-tee-ra = { path = "../quartz-tee-ra" } -mc-attestation-verifier = { git = "https://github.com/informalsystems/attestation", default-features = false } -p256 = { version = "0.13.2", default-features = false } -serde_json = { version = "1.0", default-features = false } -hex = { version = "0.4.3", default-features = false, features = ["serde"] } +# external +der.workspace = true +hex.workspace = true +p256.workspace = true +schemars.workspace = true +serde.workspace = true +serde_json.workspace = true +thiserror.workspace = true +x509-cert.workspace = true + +# mobilecoin +mc-attestation-verifier.workspace = true + +# cosmos +cosmwasm-schema.workspace = true +cosmwasm-std.workspace = true +cw2.workspace = true +cw-storage-plus.workspace = true + +# quartz +quartz-tee-ra.workspace = true +tcbinfo-msgs.workspace = true + +# patch indirect deps +getrandom = { version = "0.2.15", features = ["js"] } [dev-dependencies] cw-multi-test = "2.0.0" diff --git a/cosmwasm/packages/tcbinfo/msgs/Cargo.toml b/cosmwasm/packages/tcbinfo/msgs/Cargo.toml new file mode 100644 index 0000000..a083959 --- /dev/null +++ b/cosmwasm/packages/tcbinfo/msgs/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "tcbinfo-msgs" +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +# external + +# cosmos +cosmwasm-schema.workspace = true diff --git a/cosmwasm/packages/tcbinfo/src/msg.rs b/cosmwasm/packages/tcbinfo/msgs/src/lib.rs similarity index 91% rename from cosmwasm/packages/tcbinfo/src/msg.rs rename to cosmwasm/packages/tcbinfo/msgs/src/lib.rs index b721f7b..db4a551 100644 --- a/cosmwasm/packages/tcbinfo/src/msg.rs +++ b/cosmwasm/packages/tcbinfo/msgs/src/lib.rs @@ -21,5 +21,5 @@ pub enum QueryMsg { #[cw_serde] pub struct GetTcbInfoResponse { - pub tcb_info: serde_json::Value, + pub tcb_info: String, } diff --git a/cosmwasm/packages/tcbinfo/src/bin/schema.rs b/cosmwasm/packages/tcbinfo/src/bin/tcbinfo_schema.rs similarity index 73% rename from cosmwasm/packages/tcbinfo/src/bin/schema.rs rename to cosmwasm/packages/tcbinfo/src/bin/tcbinfo_schema.rs index 06cc957..82800ac 100644 --- a/cosmwasm/packages/tcbinfo/src/bin/schema.rs +++ b/cosmwasm/packages/tcbinfo/src/bin/tcbinfo_schema.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::write_api; -use tcbinfo::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use tcbinfo_msgs::{ExecuteMsg, InstantiateMsg, QueryMsg}; fn main() { write_api! { diff --git a/cosmwasm/packages/tcbinfo/src/contract.rs b/cosmwasm/packages/tcbinfo/src/contract.rs index 9e07d3c..143001e 100644 --- a/cosmwasm/packages/tcbinfo/src/contract.rs +++ b/cosmwasm/packages/tcbinfo/src/contract.rs @@ -1,19 +1,17 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; -use cosmwasm_std::{ - to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError, StdResult, -}; +use cosmwasm_std::{to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult}; use cw2::set_contract_version; use der::{DateTime, DecodePem}; use mc_attestation_verifier::{CertificateChainVerifier, SignedTcbInfo}; use p256::ecdsa::VerifyingKey; use quartz_tee_ra::intel_sgx::dcap::certificate_chain::TlsCertificateChainVerifier; use serde_json::Value; +use tcbinfo_msgs::{ExecuteMsg, GetTcbInfoResponse, InstantiateMsg, QueryMsg}; use x509_cert::Certificate; use crate::{ error::ContractError, - msg::{ExecuteMsg, GetTcbInfoResponse, InstantiateMsg, QueryMsg}, state::{TcbInfo, DATABASE, ROOT_CERTIFICATE}, }; // version info for migration info @@ -147,11 +145,8 @@ pub mod query { .try_into() .expect("invalid fmspc"); let tcb_info = DATABASE.load(deps.storage, key)?; - let tcb_info_response = serde_json::from_str(&tcb_info.info).map_err(|_| { - StdError::parse_err(tcb_info.info, "Could not prarse on-chain TcbInfo as JSON") - })?; Ok(GetTcbInfoResponse { - tcb_info: tcb_info_response, + tcb_info: tcb_info.info, }) } } @@ -160,7 +155,7 @@ pub mod query { mod tests { use cosmwasm_std::{ coins, - testing::{mock_dependencies, mock_env, mock_info}, + testing::{message_info, mock_dependencies, mock_env}, }; use super::*; @@ -172,7 +167,10 @@ mod tests { #[test] fn verify_init_and_exec() { let time = "2024-07-11T15:19:13Z"; - let info = mock_info("creator", &coins(1000, "earth")); + let deps = mock_dependencies(); + let creator = deps.api.addr_make("creator"); + + let info = message_info(&creator, &coins(1000, "earth")); let init_msg = InstantiateMsg { root_cert: ROOT_CA.to_string(), }; @@ -185,7 +183,7 @@ mod tests { certificate: TCB_SIGNER.to_string(), time: Some(time.to_string()), }; - let info = mock_info("creator", &coins(1000, "earth")); + let info = message_info(&creator, &coins(1000, "earth")); let exec = execute(deps.as_mut(), mock_env(), info, exec_msg); assert!(exec.is_ok()); let query = query( diff --git a/cosmwasm/packages/tcbinfo/src/helpers.rs b/cosmwasm/packages/tcbinfo/src/helpers.rs index dedbecf..bbe2316 100644 --- a/cosmwasm/packages/tcbinfo/src/helpers.rs +++ b/cosmwasm/packages/tcbinfo/src/helpers.rs @@ -4,8 +4,7 @@ use cosmwasm_std::{ }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; - -use crate::msg::{ExecuteMsg, GetTcbInfoResponse, QueryMsg}; +use tcbinfo_msgs::{ExecuteMsg, GetTcbInfoResponse, QueryMsg}; const FMSPC: &str = "00606a000000"; diff --git a/cosmwasm/packages/tcbinfo/src/integration_tests.rs b/cosmwasm/packages/tcbinfo/src/integration_tests.rs index d2e6a53..c47f026 100644 --- a/cosmwasm/packages/tcbinfo/src/integration_tests.rs +++ b/cosmwasm/packages/tcbinfo/src/integration_tests.rs @@ -2,8 +2,9 @@ mod tests { use cosmwasm_std::{testing::MockApi, Addr, Coin, Empty, Uint128}; use cw_multi_test::{App, AppBuilder, Contract, ContractWrapper, Executor}; + use tcbinfo_msgs::InstantiateMsg; - use crate::{helpers::CwTemplateContract, msg::InstantiateMsg}; + use crate::helpers::CwTemplateContract; pub fn contract_template() -> Box> { let contract = ContractWrapper::new( @@ -67,8 +68,9 @@ mod tests { } mod add_tcbinfo { + use tcbinfo_msgs::ExecuteMsg; + use super::*; - use crate::msg::ExecuteMsg; #[test] fn add_tcbinfo() { diff --git a/cosmwasm/packages/tcbinfo/src/lib.rs b/cosmwasm/packages/tcbinfo/src/lib.rs index e51d701..038b68b 100644 --- a/cosmwasm/packages/tcbinfo/src/lib.rs +++ b/cosmwasm/packages/tcbinfo/src/lib.rs @@ -2,6 +2,5 @@ pub mod contract; mod error; pub mod helpers; pub mod integration_tests; -pub mod msg; pub mod state; pub use crate::error::ContractError; diff --git a/utils/cycles-sync/Cargo.toml b/utils/cycles-sync/Cargo.toml index 7d93b3b..8347a90 100644 --- a/utils/cycles-sync/Cargo.toml +++ b/utils/cycles-sync/Cargo.toml @@ -26,7 +26,7 @@ tokio.workspace = true tracing.workspace = true tracing-subscriber.workspace = true uuid.workspace = true -anyhow ={ version = "*"} +anyhow = { version = "*" } # cosmos cosmrs.workspace = true diff --git a/utils/print-fmspc/Cargo.toml b/utils/print-fmspc/Cargo.toml new file mode 100644 index 0000000..2bb122e --- /dev/null +++ b/utils/print-fmspc/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "print-fmspc" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +readme.workspace = true +repository.workspace = true +authors.workspace = true + +[dependencies] +dcap-qvl = "0.1.0" +hex.workspace = true +serde_json.workspace = true +tokio.workspace = true diff --git a/utils/print-fmspc/src/main.rs b/utils/print-fmspc/src/main.rs new file mode 100644 index 0000000..047ae21 --- /dev/null +++ b/utils/print-fmspc/src/main.rs @@ -0,0 +1,20 @@ +use dcap_qvl::collateral::get_collateral; + +const DEFAULT_PCCS_URL: &str = "https://localhost:8081/sgx/certification/v4/"; + +#[tokio::main] +async fn main() { + let pccs_url = std::env::var("PCCS_URL").unwrap_or_else(|_| DEFAULT_PCCS_URL.to_string()); + let quote = { + let quote_hex = std::env::var("QUOTE").expect("QUOTE is not found"); + hex::decode(quote_hex).expect("QUOTE is not valid hex") + }; + + let collateral = get_collateral(&pccs_url, "e, std::time::Duration::from_secs(10)) + .await + .expect("failed to get collateral"); + let tcb_info: serde_json::Value = + serde_json::from_str(&collateral.tcb_info).expect("Retrieved Tcbinfo is not valid JSON"); + + eprintln!("{}", tcb_info["fmspc"]); +}