feat(dcap): make DCAP RA default (#150)

Co-authored-by: hu55a1n1 <sufialhussaini@gmail.com>
This commit is contained in:
dusterbloom 2024-09-25 21:14:06 +02:00 committed by GitHub
parent 69c1f63114
commit 391b7bc84a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
67 changed files with 1500 additions and 1146 deletions

455
Cargo.lock generated
View file

@ -335,6 +335,12 @@ dependencies = [
"syn 2.0.77", "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]] [[package]]
name = "async-priority-channel" name = "async-priority-channel"
version = "0.2.0" version = "0.2.0"
@ -571,6 +577,18 @@ version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 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]] [[package]]
name = "blake2" name = "blake2"
version = "0.10.6" version = "0.10.6"
@ -643,6 +661,12 @@ version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "byte-slice-cast"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c"
[[package]] [[package]]
name = "bytemuck" name = "bytemuck"
version = "1.18.0" version = "1.18.0"
@ -777,6 +801,33 @@ dependencies = [
"serde", "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]] [[package]]
name = "cipher" name = "cipher"
version = "0.4.4" version = "0.4.4"
@ -1395,6 +1446,35 @@ version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" 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]] [[package]]
name = "der" name = "der"
version = "0.7.9" version = "0.7.9"
@ -1705,6 +1785,18 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" 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]] [[package]]
name = "env_filter" name = "env_filter"
version = "0.1.2" version = "0.1.2"
@ -1888,6 +1980,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.30" version = "0.3.30"
@ -2401,6 +2499,16 @@ version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" 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]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.12.3" version = "0.12.3"
@ -2453,6 +2561,51 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" 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]] [[package]]
name = "hkdf" name = "hkdf"
version = "0.12.4" version = "0.12.4"
@ -2480,6 +2633,17 @@ dependencies = [
"windows-sys 0.52.0", "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]] [[package]]
name = "http" name = "http"
version = "0.2.12" version = "0.2.12"
@ -2628,7 +2792,7 @@ dependencies = [
"tokio", "tokio",
"tokio-rustls 0.26.0", "tokio-rustls 0.26.0",
"tower-service", "tower-service",
"webpki-roots", "webpki-roots 0.26.5",
] ]
[[package]] [[package]]
@ -2687,6 +2851,16 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 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]] [[package]]
name = "idna" name = "idna"
version = "0.5.0" version = "0.5.0"
@ -2732,6 +2906,17 @@ dependencies = [
"tracing", "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]] [[package]]
name = "indenter" name = "indenter"
version = "0.3.3" version = "0.3.3"
@ -2816,6 +3001,18 @@ dependencies = [
"cfg-if", "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]] [[package]]
name = "ipnet" name = "ipnet"
version = "2.10.0" version = "2.10.0"
@ -3039,6 +3236,12 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.4.14" version = "0.4.14"
@ -3118,6 +3321,21 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 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]] [[package]]
name = "matchers" name = "matchers"
version = "0.1.0" version = "0.1.0"
@ -3607,6 +3825,32 @@ dependencies = [
"sha2 0.10.8", "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]] [[package]]
name = "parking" name = "parking"
version = "2.2.1" version = "2.2.1"
@ -3720,6 +3964,16 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3aeb8f54c078314c2065ee649a7241f46b9d8e418e1a9581ba0546657d7aa3a" 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]] [[package]]
name = "pem-rfc7468" name = "pem-rfc7468"
version = "0.7.0" version = "0.7.0"
@ -3938,6 +4192,25 @@ dependencies = [
"elliptic-curve", "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]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.86" version = "1.0.86"
@ -4138,20 +4411,42 @@ dependencies = [
name = "quartz-cw" name = "quartz-cw"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ciborium",
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw-storage-plus", "cw-storage-plus",
"hex", "hex",
"k256", "k256",
"quartz-dcap-verifier-msgs",
"quartz-tee-ra", "quartz-tee-ra",
"serde", "serde",
"serde_json", "serde_json",
"serde_with", "serde_with",
"sha2 0.10.8", "sha2 0.10.8",
"tcbinfo", "tcbinfo-msgs",
"thiserror", "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]] [[package]]
name = "quartz-enclave" name = "quartz-enclave"
version = "0.1.0" version = "0.1.0"
@ -4167,11 +4462,13 @@ dependencies = [
"futures-util", "futures-util",
"hex", "hex",
"k256", "k256",
"mc-sgx-dcap-sys-types",
"mtcs", "mtcs",
"quartz-cw", "quartz-cw",
"quartz-proto", "quartz-proto",
"quartz-tee-ra", "quartz-tee-ra",
"rand", "rand",
"reqwest 0.12.7",
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.10.8", "sha2 0.10.8",
@ -4183,6 +4480,7 @@ dependencies = [
"tokio", "tokio",
"tonic", "tonic",
"tower 0.5.1", "tower 0.5.1",
"urlencoding",
] ]
[[package]] [[package]]
@ -4201,7 +4499,6 @@ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"der", "der",
"displaydoc",
"hex", "hex",
"hex-literal", "hex-literal",
"mc-attestation-verifier", "mc-attestation-verifier",
@ -4215,9 +4512,14 @@ dependencies = [
"thiserror", "thiserror",
"x509-cert", "x509-cert",
"x509-parser", "x509-parser",
"zeroize",
] ]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]] [[package]]
name = "quinn" name = "quinn"
version = "0.11.5" version = "0.11.5"
@ -4244,7 +4546,7 @@ checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6"
dependencies = [ dependencies = [
"bytes", "bytes",
"rand", "rand",
"ring", "ring 0.17.8",
"rustc-hash", "rustc-hash",
"rustls 0.23.13", "rustls 0.23.13",
"slab", "slab",
@ -4275,6 +4577,12 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]] [[package]]
name = "radix_trie" name = "radix_trie"
version = "0.2.1" version = "0.2.1"
@ -4425,6 +4733,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2 0.3.26", "h2 0.3.26",
"hickory-resolver",
"http 0.2.12", "http 0.2.12",
"http-body 0.4.6", "http-body 0.4.6",
"hyper 0.14.30", "hyper 0.14.30",
@ -4451,6 +4760,7 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
"webpki-roots 0.25.4",
"winreg", "winreg",
] ]
@ -4462,6 +4772,7 @@ checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bytes", "bytes",
"futures-channel",
"futures-core", "futures-core",
"futures-util", "futures-util",
"http 1.1.0", "http 1.1.0",
@ -4492,10 +4803,20 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
"webpki-roots", "webpki-roots 0.26.5",
"windows-registry", "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]] [[package]]
name = "rfc6979" name = "rfc6979"
version = "0.4.0" version = "0.4.0"
@ -4534,6 +4855,21 @@ dependencies = [
"syn 2.0.77", "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]] [[package]]
name = "ring" name = "ring"
version = "0.17.8" version = "0.17.8"
@ -4544,8 +4880,8 @@ dependencies = [
"cfg-if", "cfg-if",
"getrandom", "getrandom",
"libc", "libc",
"spin", "spin 0.9.8",
"untrusted", "untrusted 0.9.0",
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
@ -4608,7 +4944,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
dependencies = [ dependencies = [
"log", "log",
"ring", "ring 0.17.8",
"rustls-webpki 0.101.7", "rustls-webpki 0.101.7",
"sct", "sct",
] ]
@ -4620,7 +4956,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432"
dependencies = [ dependencies = [
"log", "log",
"ring", "ring 0.17.8",
"rustls-pki-types", "rustls-pki-types",
"rustls-webpki 0.102.8", "rustls-webpki 0.102.8",
"subtle", "subtle",
@ -4634,7 +4970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"ring", "ring 0.17.8",
"rustls-pki-types", "rustls-pki-types",
"rustls-webpki 0.102.8", "rustls-webpki 0.102.8",
"subtle", "subtle",
@ -4697,8 +5033,8 @@ version = "0.101.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
dependencies = [ dependencies = [
"ring", "ring 0.17.8",
"untrusted", "untrusted 0.9.0",
] ]
[[package]] [[package]]
@ -4707,9 +5043,9 @@ version = "0.102.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
dependencies = [ dependencies = [
"ring", "ring 0.17.8",
"rustls-pki-types", "rustls-pki-types",
"untrusted", "untrusted 0.9.0",
] ]
[[package]] [[package]]
@ -4743,6 +5079,31 @@ dependencies = [
"regex", "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]] [[package]]
name = "schannel" name = "schannel"
version = "0.1.24" version = "0.1.24"
@ -4788,8 +5149,8 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
dependencies = [ dependencies = [
"ring", "ring 0.17.8",
"untrusted", "untrusted 0.9.0",
] ]
[[package]] [[package]]
@ -4871,7 +5232,7 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
dependencies = [ dependencies = [
"half", "half 1.8.3",
"serde", "serde",
] ]
@ -4903,6 +5264,7 @@ version = "1.0.128"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
dependencies = [ dependencies = [
"indexmap 2.5.0",
"itoa", "itoa",
"memchr", "memchr",
"ryu", "ryu",
@ -5102,6 +5464,12 @@ dependencies = [
"windows-sys 0.52.0", "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]] [[package]]
name = "spin" name = "spin"
version = "0.9.8" version = "0.9.8"
@ -5226,6 +5594,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]] [[package]]
name = "target-lexicon" name = "target-lexicon"
version = "0.12.16" version = "0.12.16"
@ -5250,10 +5624,18 @@ dependencies = [
"schemars", "schemars",
"serde", "serde",
"serde_json", "serde_json",
"tcbinfo-msgs",
"thiserror", "thiserror",
"x509-cert", "x509-cert",
] ]
[[package]]
name = "tcbinfo-msgs"
version = "0.1.0"
dependencies = [
"cosmwasm-schema",
]
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.10.1" version = "3.10.1"
@ -5976,6 +6358,12 @@ dependencies = [
"subtle", "subtle",
] ]
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]] [[package]]
name = "untrusted" name = "untrusted"
version = "0.9.0" version = "0.9.0"
@ -5989,10 +6377,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
dependencies = [ dependencies = [
"form_urlencoded", "form_urlencoded",
"idna", "idna 0.5.0",
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]] [[package]]
name = "utf-8" name = "utf-8"
version = "0.7.6" version = "0.7.6"
@ -6203,6 +6597,12 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "webpki-roots"
version = "0.25.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
[[package]] [[package]]
name = "webpki-roots" name = "webpki-roots"
version = "0.26.5" version = "0.26.5"
@ -6224,6 +6624,12 @@ dependencies = [
"winsafe", "winsafe",
] ]
[[package]]
name = "widestring"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@ -6511,6 +6917,15 @@ version = "0.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
[[package]] [[package]]
name = "x509-cert" name = "x509-cert"
version = "0.2.5" version = "0.2.5"
@ -6534,7 +6949,7 @@ dependencies = [
"lazy_static", "lazy_static",
"nom", "nom",
"oid-registry", "oid-registry",
"ring", "ring 0.17.8",
"rusticata-macros", "rusticata-macros",
"thiserror", "thiserror",
"time", "time",

View file

@ -25,7 +25,8 @@ authors = ["Informal Systems <hello@informal.systems>"]
anyhow = { version = "1.0.86", features = ["std", "backtrace"] } anyhow = { version = "1.0.86", features = ["std", "backtrace"] }
async-trait = { version = "0.1.79", default-features = false } async-trait = { version = "0.1.79", default-features = false }
bip32 = { version = "0.5.1", default-features = false, features = ["alloc", "secp256k1", "bip39"] } 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"] } clap = { version = "4.1.8", default-features = false, features = ["derive", "std"] }
color-eyre = { version = "0.6.2", default-features = false } color-eyre = { version = "0.6.2", default-features = false }
der = { version = "0.7.9", 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 } hex-literal = { version = "0.4.1", default-features = false }
k256 = { version = "0.13.2", default-features = false, features = ["ecdsa", "alloc"] } k256 = { version = "0.13.2", default-features = false, features = ["ecdsa", "alloc"] }
num-bigint = { version = "0.4.4", default-features = false } 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 } prost = { version = "0.13.1", default-features = false }
rand = { version = "0.8.5", default-features = false, features = ["getrandom"] } rand = { version = "0.8.5", default-features = false, features = ["getrandom"] }
rand_core = { version = "0.6", default-features = false, features = ["std"] } rand_core = { version = "0.6", default-features = false, features = ["std"] }
reqwest = { version = "0.12.2", default-features = false, features = ["json", "rustls-tls"] } 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 = { version = "1.0.203", default-features = false, features = ["derive"] }
serde_json = { version = "1.0.94", default-features = false, features = ["alloc"] } serde_json = { version = "1.0.94", default-features = false, features = ["alloc"] }
serde_with = { version = "3.4.0", default-features = false, features = ["hex", "macros"] } 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" } tower = { version = "0.5.0" }
tracing = { version = "0.1.39", default-features = false } tracing = { version = "0.1.39", default-features = false }
tracing-subscriber = { version = "0.3.17", default-features = false, features = ["fmt"] } 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"] } uuid = { version = "1.4.1", default-features = false, features = ["serde"] }
x509-cert = { version = "0.2.5", default-features = false } 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 } zeroize = { version = "1.7.0", default-features = false }
# cosmos # 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 } cosmrs = { version = "=0.17.0", default-features = false }
cosmwasm-schema = { version = "2.1.1", 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 } 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"] } ics23 = { version = "0.12.0", default-features = false, features = ["host-functions"] }
tendermint = { version = "=0.38.1", default-features = false } tendermint = { version = "=0.38.1", default-features = false }
tendermint-light-client = { version = "=0.38.1", default-features = false, features = ["rust-crypto"] } 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 # quartz
cw-proof = { path = "core/light-client-proofs/cw-proof", default-features = false } 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-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-enclave = { path = "core/quartz", default-features = false }
quartz-proto = { path = "core/quartz-proto", default-features = false } quartz-proto = { path = "core/quartz-proto", default-features = false }
quartz-tee-ra = { path = "cosmwasm/packages/quartz-tee-ra", 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-prover = { path = "utils/tm-prover", default-features = false }
tm-stateless-verifier = { path = "core/light-client-proofs/tm-stateless-verifier", 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 } 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 # quartz apps
cw-tee-mtcs = { path = "apps/mtcs/contracts/cw-tee-mtcs", default-features = false } 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 = { 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] [profile.release]
opt-level = 3 opt-level = "z"
debug = false debug = false
rpath = false rpath = false
lto = true lto = true

View file

@ -280,6 +280,33 @@ dependencies = [
"serde", "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]] [[package]]
name = "const-oid" name = "const-oid"
version = "0.9.6" version = "0.9.6"
@ -407,6 +434,12 @@ version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]] [[package]]
name = "crypto-bigint" name = "crypto-bigint"
version = "0.5.5" version = "0.5.5"
@ -841,6 +874,16 @@ dependencies = [
"subtle", "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]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.13.2" version = "0.13.2"
@ -1205,20 +1248,30 @@ dependencies = [
name = "quartz-cw" name = "quartz-cw"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ciborium",
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw-storage-plus", "cw-storage-plus",
"hex", "hex",
"k256", "k256",
"quartz-dcap-verifier-msgs",
"quartz-tee-ra", "quartz-tee-ra",
"serde", "serde",
"serde_json", "serde_json",
"serde_with", "serde_with",
"sha2", "sha2",
"tcbinfo", "tcbinfo-msgs",
"thiserror", "thiserror",
] ]
[[package]]
name = "quartz-dcap-verifier-msgs"
version = "0.1.0"
dependencies = [
"cosmwasm-schema",
"cosmwasm-std",
]
[[package]] [[package]]
name = "quartz-tee-ra" name = "quartz-tee-ra"
version = "0.1.0" version = "0.1.0"
@ -1226,11 +1279,8 @@ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"der", "der",
"displaydoc",
"hex-literal", "hex-literal",
"mc-attestation-verifier", "mc-attestation-verifier",
"mc-sgx-core-types",
"mc-sgx-dcap-sys-types",
"mc-sgx-dcap-types", "mc-sgx-dcap-types",
"num-bigint", "num-bigint",
"serde", "serde",
@ -1239,7 +1289,6 @@ dependencies = [
"thiserror", "thiserror",
"x509-cert", "x509-cert",
"x509-parser", "x509-parser",
"zeroize",
] ]
[[package]] [[package]]
@ -1568,24 +1617,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "tcbinfo" name = "tcbinfo-msgs"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmwasm-schema", "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]] [[package]]

View file

@ -13,7 +13,7 @@ path = "bin/schema.rs"
crate-type = ["cdylib", "rlib"] crate-type = ["cdylib", "rlib"]
[profile.release] [profile.release]
opt-level = 3 opt-level = "z"
debug = false debug = false
rpath = false rpath = false
lto = true lto = true
@ -38,7 +38,7 @@ thiserror = { version = "1.0.49" }
# cosmwasm # cosmwasm
cosmwasm-schema = { version = "2.1.1", 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 } cw-storage-plus = { version = "2.0.0", default-features = false }
cw20-base = { version = "2.0.0", features = ["library"] } cw20-base = { version = "2.0.0", features = ["library"] }
cw20 = "2.0.0" cw20 = "2.0.0"

View file

@ -5,8 +5,7 @@
// unused_import_braces, // unused_import_braces,
// unused_qualifications // unused_qualifications
// )] // )]
// #![forbid(unsafe_code)] #![forbid(unsafe_code)]
pub mod contract; pub mod contract;
mod error; mod error;
pub mod msg; pub mod msg;

File diff suppressed because one or more lines are too long

View file

@ -4,17 +4,6 @@ version = "0.1.0"
edition = "2021" edition = "2021"
authors = ["Informal Systems <hello@informal.systems>"] authors = ["Informal Systems <hello@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] [features]
mock-sgx = ["quartz-common/mock-sgx-cw", "quartz-common/mock-sgx-enclave"] mock-sgx = ["quartz-common/mock-sgx-cw", "quartz-common/mock-sgx-enclave"]

View file

@ -22,6 +22,9 @@ loader.env.QUARTZ_PORT = { passthrough = true }
loader.argv = ["enclave", loader.argv = ["enclave",
"--chain-id", "testing", "--chain-id", "testing",
"--fmspc", "{{ fmspc }}",
"--tcbinfo-contract", "{{ tcbinfo_contract }}",
"--dcap-verifier-contract", "{{ dcap_verifier_contract }}",
"--trusted-height", "{{ trusted_height }}", "--trusted-height", "{{ trusted_height }}",
"--trusted-hash", "{{ trusted_hash }}"] "--trusted-hash", "{{ trusted_hash }}"]

View file

@ -3,6 +3,7 @@ use std::net::SocketAddr;
use clap::Parser; use clap::Parser;
use color_eyre::eyre::{eyre, Result}; use color_eyre::eyre::{eyre, Result};
use cosmrs::AccountId; use cosmrs::AccountId;
use quartz_common::enclave::types::Fmspc;
use tendermint::Hash; use tendermint::Hash;
use tendermint_light_client::types::{Height, TrustThreshold}; use tendermint_light_client::types::{Height, TrustThreshold};
@ -27,10 +28,18 @@ pub struct Cli {
#[clap(long)] #[clap(long)]
pub chain_id: String, pub chain_id: String,
/// FMSPC (Family-Model-Stepping-Platform-Custom SKU)
#[clap(long)]
pub fmspc: Option<Fmspc>,
/// TcbInfo contract address /// TcbInfo contract address
#[clap(long)] #[clap(long)]
pub tcbinfo_contract: Option<AccountId>, pub tcbinfo_contract: Option<AccountId>,
/// DCAP verifier contract address
#[clap(long)]
pub dcap_verifier_contract: Option<AccountId>,
/// Height of the trusted header (AKA root-of-trust) /// Height of the trusted header (AKA root-of-trust)
#[clap(long)] #[clap(long)]
pub trusted_height: Height, pub trusted_height: Height,

View file

@ -29,7 +29,7 @@ use mtcs_server::MtcsService;
use quartz_common::{ use quartz_common::{
contract::state::{Config, LightClientOpts}, contract::state::{Config, LightClientOpts},
enclave::{ enclave::{
attestor::{Attestor, DefaultAttestor}, attestor::{self, Attestor},
server::{QuartzServer, WsListenerConfig}, server::{QuartzServer, WsListenerConfig},
}, },
}; };
@ -53,13 +53,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
args.max_block_lag, 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( let config: Config = Config::new(
attestor.mr_enclave()?, attestor.mr_enclave()?,
Duration::from_secs(30 * 24 * 60), Duration::from_secs(30 * 24 * 60),
light_client_opts, light_client_opts,
args.tcbinfo_contract.map(|c| c.to_string()), args.tcbinfo_contract.map(|c| c.to_string()),
args.dcap_verifier_contract.map(|c| c.to_string()),
); );
let ws_config = WsListenerConfig { let ws_config = WsListenerConfig {

View file

@ -41,6 +41,7 @@ impl<A: Attestor> IntoServer for MtcsService<A> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MtcsService<A> { pub struct MtcsService<A> {
#[allow(dead_code)]
config: Config, // TODO: this config is not used anywhere config: Config, // TODO: this config is not used anywhere
sk: Arc<Mutex<Option<SigningKey>>>, sk: Arc<Mutex<Option<SigningKey>>>,
attestor: A, attestor: A,
@ -107,12 +108,16 @@ where
let msg = SubmitSetoffsMsg { setoffs_enc }; let msg = SubmitSetoffsMsg { setoffs_enc };
println!("setoff_msg: {:?}", msg); println!("setoff_msg: {:?}", msg);
let attestation = self let attestation = self
.attestor .attestor
.quote(msg.clone()) .attestation(msg.clone())
.map_err(|e| Status::internal(e.to_string()))?; .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(); let message = serde_json::to_string(&attested_msg).unwrap();
Ok(Response::new(RunClearingResponse { message })) 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<HexBinary, i64>,
// debtor_pk: VerifyingKey,
// creditor_pk: VerifyingKey,
// ) -> Vec<RawCipherText> {
// 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( fn decrypt_obligation(
sk: &SigningKey, sk: &SigningKey,
ciphertext: &RawCipherText, ciphertext: &RawCipherText,

View file

@ -280,6 +280,33 @@ dependencies = [
"serde", "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]] [[package]]
name = "const-oid" name = "const-oid"
version = "0.9.6" version = "0.9.6"
@ -407,6 +434,12 @@ version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]] [[package]]
name = "crypto-bigint" name = "crypto-bigint"
version = "0.5.5" version = "0.5.5"
@ -500,51 +533,6 @@ dependencies = [
"thiserror", "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]] [[package]]
name = "darling" name = "darling"
version = "0.20.10" version = "0.20.10"
@ -820,6 +808,16 @@ dependencies = [
"subtle", "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]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.13.2" version = "0.13.2"
@ -1184,20 +1182,30 @@ dependencies = [
name = "quartz-cw" name = "quartz-cw"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ciborium",
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw-storage-plus", "cw-storage-plus",
"hex", "hex",
"k256", "k256",
"quartz-dcap-verifier-msgs",
"quartz-tee-ra", "quartz-tee-ra",
"serde", "serde",
"serde_json", "serde_json",
"serde_with", "serde_with",
"sha2", "sha2",
"tcbinfo", "tcbinfo-msgs",
"thiserror", "thiserror",
] ]
[[package]]
name = "quartz-dcap-verifier-msgs"
version = "0.1.0"
dependencies = [
"cosmwasm-schema",
"cosmwasm-std",
]
[[package]] [[package]]
name = "quartz-tee-ra" name = "quartz-tee-ra"
version = "0.1.0" version = "0.1.0"
@ -1205,11 +1213,8 @@ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"der", "der",
"displaydoc",
"hex-literal", "hex-literal",
"mc-attestation-verifier", "mc-attestation-verifier",
"mc-sgx-core-types",
"mc-sgx-dcap-sys-types",
"mc-sgx-dcap-types", "mc-sgx-dcap-types",
"num-bigint", "num-bigint",
"serde", "serde",
@ -1218,7 +1223,6 @@ dependencies = [
"thiserror", "thiserror",
"x509-cert", "x509-cert",
"x509-parser", "x509-parser",
"zeroize",
] ]
[[package]] [[package]]
@ -1547,24 +1551,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "tcbinfo" name = "tcbinfo-msgs"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmwasm-schema", "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]] [[package]]
@ -1627,11 +1617,8 @@ dependencies = [
"cw-multi-test", "cw-multi-test",
"cw-storage-plus", "cw-storage-plus",
"cw-utils", "cw-utils",
"cw2",
"cw20-base",
"getrandom", "getrandom",
"quartz-common", "quartz-common",
"serde",
"serde_json", "serde_json",
"sha2", "sha2",
"thiserror", "thiserror",

View file

@ -13,7 +13,7 @@ path = "bin/schema.rs"
crate-type = ["cdylib", "rlib"] crate-type = ["cdylib", "rlib"]
[profile.release] [profile.release]
opt-level = 3 opt-level = "z"
debug = false debug = false
rpath = false rpath = false
lto = true lto = true
@ -23,7 +23,6 @@ panic = 'abort'
incremental = false incremental = false
overflow-checks = true overflow-checks = true
[features] [features]
mock-sgx = ["quartz-common/mock-sgx-cw"] mock-sgx = ["quartz-common/mock-sgx-cw"]
library = [] library = []
@ -31,24 +30,20 @@ library = []
[dependencies] [dependencies]
# external # external
sha2 = "0.10.8" sha2 = "0.10.8"
serde_json = { version = "1.0.122", default-features = false, features = ["alloc"] } serde_json = { version = "1.0.122", default-features = false }
serde = { version = "1.0.204", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.63" } thiserror = { version = "1.0.63" }
# cosmwasm # 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 } 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 } 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 } cw-utils = { version = "2.0.0", default-features = false }
# quartz # quartz
# quartz-common = { git = "ssh://git@github.com/informalsystems/cycles-quartz.git", features=["contract"]} quartz-common = { path = "../../../core/quartz-common", default-features = false, features = ["contract"] }
quartz-common = { path = "../../../core/quartz-common", features=["contract"]}
# patch indirect deps # patch indirect deps
getrandom = { version = "0.2.15", default-features = false, features = ["js"] } getrandom = { version = "0.2.15", features = ["js"] }
[dev-dependencies] [dev-dependencies]
cw-multi-test = { version = "2.1.0", default-features = false } cw-multi-test = { version = "2.1.0", default-features = false }

View file

@ -1,5 +1,4 @@
use cosmwasm_std::StdError; use cosmwasm_std::StdError;
use cw20_base::ContractError as Cw20ContractError;
use cw_utils::PaymentError; use cw_utils::PaymentError;
use quartz_common::contract::error::Error as QuartzError; use quartz_common::contract::error::Error as QuartzError;
use thiserror::Error; use thiserror::Error;
@ -21,19 +20,10 @@ pub enum ContractError {
#[error("Invalid length")] #[error("Invalid length")]
BadLength, BadLength,
#[error("Cw20 error: {0}")]
Cw20(Cw20ContractError),
#[error("Payment error: {0}")] #[error("Payment error: {0}")]
CwUtil(PaymentError), CwUtil(PaymentError),
} }
impl From<Cw20ContractError> for ContractError {
fn from(e: Cw20ContractError) -> Self {
Self::Cw20(e)
}
}
impl From<PaymentError> for ContractError { impl From<PaymentError> for ContractError {
fn from(e: PaymentError) -> Self { fn from(e: PaymentError) -> Self {
Self::CwUtil(e) Self::CwUtil(e)

View file

@ -23,7 +23,7 @@ pub enum QueryMsg {
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
pub enum ExecuteMsg<RA = RawDefaultAttestation> { pub enum ExecuteMsg<RA = RawDefaultAttestation> {
// quartz initialization // quartz initialization
Quartz(QuartzExecuteMsg), Quartz(QuartzExecuteMsg<RA>),
// User msgs // User msgs
// clear text // clear text

View file

@ -530,6 +530,33 @@ dependencies = [
"serde", "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]] [[package]]
name = "cipher" name = "cipher"
version = "0.4.4" version = "0.4.4"
@ -926,51 +953,6 @@ dependencies = [
"thiserror", "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]] [[package]]
name = "darling" name = "darling"
version = "0.20.10" version = "0.20.10"
@ -1410,9 +1392,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-io",
"futures-macro", "futures-macro",
"futures-sink", "futures-sink",
"futures-task", "futures-task",
"memchr",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
"slab", "slab",
@ -1513,6 +1497,16 @@ version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" 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]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.12.3" version = "0.12.3"
@ -2677,20 +2671,30 @@ dependencies = [
name = "quartz-cw" name = "quartz-cw"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ciborium",
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"cw-storage-plus", "cw-storage-plus",
"hex", "hex",
"k256", "k256",
"quartz-dcap-verifier-msgs",
"quartz-tee-ra", "quartz-tee-ra",
"serde", "serde",
"serde_json", "serde_json",
"serde_with", "serde_with",
"sha2 0.10.8", "sha2 0.10.8",
"tcbinfo", "tcbinfo-msgs",
"thiserror", "thiserror",
] ]
[[package]]
name = "quartz-dcap-verifier-msgs"
version = "0.1.0"
dependencies = [
"cosmwasm-schema",
"cosmwasm-std",
]
[[package]] [[package]]
name = "quartz-enclave" name = "quartz-enclave"
version = "0.1.0" version = "0.1.0"
@ -2706,11 +2710,13 @@ dependencies = [
"futures-util", "futures-util",
"hex", "hex",
"k256", "k256",
"mc-sgx-dcap-sys-types",
"mtcs", "mtcs",
"quartz-cw", "quartz-cw",
"quartz-proto", "quartz-proto",
"quartz-tee-ra", "quartz-tee-ra",
"rand", "rand",
"reqwest 0.12.7",
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.10.8", "sha2 0.10.8",
@ -2722,6 +2728,7 @@ dependencies = [
"tokio", "tokio",
"tonic", "tonic",
"tower 0.5.1", "tower 0.5.1",
"urlencoding",
] ]
[[package]] [[package]]
@ -2740,11 +2747,8 @@ dependencies = [
"cosmwasm-schema", "cosmwasm-schema",
"cosmwasm-std", "cosmwasm-std",
"der", "der",
"displaydoc",
"hex-literal", "hex-literal",
"mc-attestation-verifier", "mc-attestation-verifier",
"mc-sgx-core-types",
"mc-sgx-dcap-sys-types",
"mc-sgx-dcap-types", "mc-sgx-dcap-types",
"num-bigint", "num-bigint",
"serde", "serde",
@ -2753,7 +2757,6 @@ dependencies = [
"thiserror", "thiserror",
"x509-cert", "x509-cert",
"x509-parser", "x509-parser",
"zeroize",
] ]
[[package]] [[package]]
@ -2966,6 +2969,7 @@ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bytes", "bytes",
"encoding_rs", "encoding_rs",
"futures-channel",
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2 0.4.6", "h2 0.4.6",
@ -3339,7 +3343,7 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
dependencies = [ dependencies = [
"half", "half 1.8.3",
"serde", "serde",
] ]
@ -3672,24 +3676,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "tcbinfo" name = "tcbinfo-msgs"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cosmwasm-schema", "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]] [[package]]
@ -4277,11 +4267,8 @@ dependencies = [
"cosmwasm-std", "cosmwasm-std",
"cw-storage-plus", "cw-storage-plus",
"cw-utils", "cw-utils",
"cw2",
"cw20-base",
"getrandom", "getrandom",
"quartz-common", "quartz-common",
"serde",
"serde_json", "serde_json",
"sha2 0.10.8", "sha2 0.10.8",
"thiserror", "thiserror",
@ -4374,6 +4361,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]] [[package]]
name = "utf-8" name = "utf-8"
version = "0.7.6" version = "0.7.6"

View file

@ -22,6 +22,9 @@ loader.env.QUARTZ_PORT = { passthrough = true }
loader.argv = ["quartz-app-transfers-enclave", loader.argv = ["quartz-app-transfers-enclave",
"--chain-id", "testing", "--chain-id", "testing",
"--fmspc", "{{ fmspc }}",
"--tcbinfo-contract", "{{ tcbinfo_contract }}",
"--dcap-verifier-contract", "{{ dcap_verifier_contract }}",
"--rpc-addr", "0.0.0.0:11090", "--rpc-addr", "0.0.0.0:11090",
"--trusted-height", "{{ trusted_height }}", "--trusted-height", "{{ trusted_height }}",
"--trusted-hash", "{{ trusted_hash }}"] "--trusted-hash", "{{ trusted_hash }}"]

View file

@ -3,6 +3,7 @@ use std::{env, net::SocketAddr};
use clap::Parser; use clap::Parser;
use color_eyre::eyre::{eyre, Result}; use color_eyre::eyre::{eyre, Result};
use cosmrs::AccountId; use cosmrs::AccountId;
use quartz_common::enclave::types::Fmspc;
use tendermint::Hash; use tendermint::Hash;
use tendermint_light_client::types::{Height, TrustThreshold}; use tendermint_light_client::types::{Height, TrustThreshold};
@ -27,10 +28,18 @@ pub struct Cli {
#[clap(long)] #[clap(long)]
pub chain_id: String, pub chain_id: String,
/// FMSPC (Family-Model-Stepping-Platform-Custom SKU)
#[clap(long)]
pub fmspc: Option<Fmspc>,
/// TcbInfo contract address /// TcbInfo contract address
#[clap(long)] #[clap(long)]
pub tcbinfo_contract: Option<AccountId>, pub tcbinfo_contract: Option<AccountId>,
/// DCAP verifier contract address
#[clap(long)]
pub dcap_verifier_contract: Option<AccountId>,
/// Height of the trusted header (AKA root-of-trust) /// Height of the trusted header (AKA root-of-trust)
#[clap(long)] #[clap(long)]
pub trusted_height: Height, pub trusted_height: Height,

View file

@ -28,7 +28,7 @@ use cli::Cli;
use quartz_common::{ use quartz_common::{
contract::state::{Config, LightClientOpts}, contract::state::{Config, LightClientOpts},
enclave::{ enclave::{
attestor::{Attestor, DefaultAttestor}, attestor::{self, Attestor},
server::{QuartzServer, WsListenerConfig}, server::{QuartzServer, WsListenerConfig},
}, },
}; };
@ -53,13 +53,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
args.max_block_lag, 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( let config = Config::new(
attestor.mr_enclave()?, attestor.mr_enclave()?,
Duration::from_secs(30 * 24 * 60), Duration::from_secs(30 * 24 * 60),
light_client_opts, light_client_opts,
args.tcbinfo_contract.map(|c| c.to_string()), args.tcbinfo_contract.map(|c| c.to_string()),
args.dcap_verifier_contract.map(|c| c.to_string()),
); );
let ws_config = WsListenerConfig { let ws_config = WsListenerConfig {

View file

@ -23,12 +23,6 @@ pub struct QueryResponse {
#[prost(string, tag = "1")] #[prost(string, tag = "1")]
pub message: ::prost::alloc::string::String, 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. /// Generated client implementations.
pub mod settlement_client { pub mod settlement_client {
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] #![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<T> {
inner: tonic::client::Grpc<T>,
}
impl EventListenerClient<tonic::transport::Channel> {
/// Attempt to create a new client by connecting to a given endpoint.
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
impl<T> EventListenerClient<T>
where
T: tonic::client::GrpcService<tonic::body::BoxBody>,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + 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<F>(
inner: T,
interceptor: F,
) -> EventListenerClient<InterceptedService<T, F>>
where
F: tonic::service::Interceptor,
T::ResponseBody: Default,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
>,
>,
<T as tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
>>::Error: Into<StdError> + 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<super::ListenRequest>,
) -> std::result::Result<tonic::Response<super::ListenResponse>, 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. /// Generated server implementations.
pub mod settlement_server { pub mod settlement_server {
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] #![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"; 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<super::ListenRequest>,
) -> std::result::Result<tonic::Response<super::ListenResponse>, tonic::Status>;
}
#[derive(Debug)]
pub struct EventListenerServer<T: EventListener> {
inner: Arc<T>,
accept_compression_encodings: EnabledCompressionEncodings,
send_compression_encodings: EnabledCompressionEncodings,
max_decoding_message_size: Option<usize>,
max_encoding_message_size: Option<usize>,
}
impl<T: EventListener> EventListenerServer<T> {
pub fn new(inner: T) -> Self {
Self::from_arc(Arc::new(inner))
}
pub fn from_arc(inner: Arc<T>) -> 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<F>(
inner: T,
interceptor: F,
) -> InterceptedService<Self, F>
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<T, B> tonic::codegen::Service<http::Request<B>> for EventListenerServer<T>
where
T: EventListener,
B: Body + Send + 'static,
B::Error: Into<StdError> + Send + 'static,
{
type Response = http::Response<tonic::body::BoxBody>;
type Error = std::convert::Infallible;
type Future = BoxFuture<Self::Response, Self::Error>;
fn poll_ready(
&mut self,
_cx: &mut Context<'_>,
) -> Poll<std::result::Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: http::Request<B>) -> Self::Future {
match req.uri().path() {
"/transfers.EventListener/Listen" => {
#[allow(non_camel_case_types)]
struct ListenSvc<T: EventListener>(pub Arc<T>);
impl<
T: EventListener,
> tonic::server::UnaryService<super::ListenRequest>
for ListenSvc<T> {
type Response = super::ListenResponse;
type Future = BoxFuture<
tonic::Response<Self::Response>,
tonic::Status,
>;
fn call(
&mut self,
request: tonic::Request<super::ListenRequest>,
) -> Self::Future {
let inner = Arc::clone(&self.0);
let fut = async move {
<T as EventListener>::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<T: EventListener> Clone for EventListenerServer<T> {
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<T: EventListener> tonic::server::NamedService for EventListenerServer<T> {
const NAME: &'static str = "transfers.EventListener";
}
}

View file

@ -102,12 +102,6 @@ pub struct StatusResponseMessage {
encrypted_bal: HexBinary, encrypted_bal: HexBinary,
} }
#[derive(Clone, Debug, Serialize, Deserialize)]
struct AttestedMsg<M> {
msg: M,
quote: Vec<u8>,
}
impl<A> TransfersService<A> impl<A> TransfersService<A>
where where
A: Attestor, A: Attestor,
@ -238,13 +232,15 @@ where
}; };
// Attest to message // Attest to message
let attestation: HexBinary = self let attestation = self
.attestor .attestor
.quote(msg.clone()) .attestation(msg.clone())
.map_err(|e| Status::internal(e.to_string()))? .map_err(|e| Status::internal(e.to_string()))?;
.into();
let attested_msg = RawAttested { msg, attestation }; let attested_msg = RawAttested {
msg,
attestation: A::RawAttestation::from(attestation),
};
let message = let message =
serde_json::to_string(&attested_msg).map_err(|e| Status::internal(e.to_string()))?; serde_json::to_string(&attested_msg).map_err(|e| Status::internal(e.to_string()))?;
@ -300,13 +296,15 @@ where
}; };
// Attest to message // Attest to message
let attestation: HexBinary = self let attestation = self
.attestor .attestor
.quote(msg.clone()) .attestation(msg.clone())
.map_err(|e| Status::internal(e.to_string()))? .map_err(|e| Status::internal(e.to_string()))?;
.into();
let attested_msg = RawAttested { msg, attestation }; let attested_msg = RawAttested {
msg,
attestation: A::RawAttestation::from(attestation),
};
let message = let message =
serde_json::to_string(&attested_msg).map_err(|e| Status::internal(e.to_string()))?; serde_json::to_string(&attested_msg).map_err(|e| Status::internal(e.to_string()))?;

View file

@ -50,9 +50,8 @@ cosmwasm-std.workspace = true
tendermint.workspace = true tendermint.workspace = true
tendermint-light-client.workspace = true tendermint-light-client.workspace = true
tendermint-rpc = { workspace = true, features = ["websocket-client", "http-client"] } tendermint-rpc = { workspace = true, features = ["websocket-client", "http-client"] }
tm-prover = { workspace = true } tm-prover = { workspace = true }
quartz-common = { workspace = true, features=["contract", "proto"]} quartz-common = { workspace = true, features = ["full"] }
quartz-tee-ra = { workspace = true } quartz-tee-ra = { workspace = true }
wasmd-client.workspace = true wasmd-client.workspace = true
tempfile.workspace = true tempfile.workspace = true

View file

@ -10,11 +10,6 @@ usage() {
DIR_QUARTZ=$(git rev-parse --show-toplevel) DIR_QUARTZ=$(git rev-parse --show-toplevel)
DIR_PROTO="$DIR_QUARTZ/core/quartz-proto/proto" 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="$1"
REQUEST_MSG=${2:-"{}"} REQUEST_MSG=${2:-"{}"}
@ -22,9 +17,6 @@ REQUEST_MSG=${2:-"{}"}
# Use the QUARTZ_PORT environment variable if set, otherwise default to 11090 # Use the QUARTZ_PORT environment variable if set, otherwise default to 11090
QUARTZ_PORT="${QUARTZ_PORT:-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 # 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') 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') QUOTE=$(echo "$ATTESTED_MSG" | jq -c '.quote')
MSG=$(echo "$ATTESTED_MSG" | jq 'del(.quote)') MSG=$(echo "$ATTESTED_MSG" | jq 'del(.quote)')
if [ "$MOCK_SGX" ]; then if [ "$MOCK_SGX" ]; then
case "$REQUEST" in case "$REQUEST" in
"Instantiate") "Instantiate")
jq -nc --argjson msg "$MSG" --argjson "attestation" "$QUOTE" '$ARGS.named' jq -nc --argjson msg "$MSG" --argjson "attestation" "$QUOTE" '$ARGS.named'
@ -52,34 +42,21 @@ if [ "$MOCK_SGX" ]; then
exit 0 exit 0
fi 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 case "$REQUEST" in
"Instantiate") "Instantiate")
jq -nc --argjson msg "$MSG" --argjson "attestation" \ jq -nc --argjson msg "$MSG" --argjson "attestation" \
"$(jq -nc --argjson report "$(jq -nc --argjson report "$REPORT" --arg reportsig "$REPORTSIG" '$ARGS.named')" '$ARGS.named')" \ "$(jq -nc --argjson collateral "$COLLATERAL" '$ARGS.named')" \
'$ARGS.named' ;; '$ARGS.named'
;;
"SessionCreate" | "SessionSetPubKey") "SessionCreate" | "SessionSetPubKey")
REQUEST_KEY=$(echo "$REQUEST" | perl -pe 's/([A-Z])/_\L$1/g;s/^_//') 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 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')" \ "$(jq -nc --argjson collateral "$COLLATERAL" '$ARGS.named')" \
'$ARGS.named')" '$ARGS.named')" '$ARGS.named' ;; '$ARGS.named')" '$ARGS.named')" '$ARGS.named'
;;
*) *)
usage ;; usage
;;
esac esac

View file

@ -3,6 +3,7 @@ use std::path::PathBuf;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use cosmrs::{tendermint::chain::Id as ChainId, AccountId}; use cosmrs::{tendermint::chain::Id as ChainId, AccountId};
use figment::{providers::Serialized, Figment}; use figment::{providers::Serialized, Figment};
use quartz_common::enclave::types::Fmspc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::metadata::LevelFilter; use tracing::metadata::LevelFilter;
@ -73,6 +74,7 @@ pub enum Command {
#[command(subcommand)] #[command(subcommand)]
enclave_command: EnclaveCommand, enclave_command: EnclaveCommand,
}, },
/// Build, deploy, perform handshake, and run quartz app while listening for changes /// Build, deploy, perform handshake, and run quartz app while listening for changes
Dev(DevArgs), Dev(DevArgs),
} }
@ -190,6 +192,21 @@ pub struct EnclaveStartArgs {
#[arg(long)] #[arg(long)]
pub unsafe_trust_latest: bool, 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<Fmspc>,
/// Address of the TcbInfo contract
#[arg(long)]
#[serde(skip_serializing_if = "Option::is_none")]
pub tcbinfo_contract: Option<AccountId>,
/// Address of the DCAP verifier contract
#[arg(long)]
#[serde(skip_serializing_if = "Option::is_none")]
pub dcap_verifier_contract: Option<AccountId>,
/// Whether to target release or dev /// Whether to target release or dev
#[arg(long)] #[arg(long)]
#[serde(skip_serializing_if = "is_false")] #[serde(skip_serializing_if = "is_false")]
@ -211,6 +228,21 @@ pub struct DevArgs {
#[command(flatten)] #[command(flatten)]
pub enclave_build: EnclaveBuildArgs, 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<Fmspc>,
/// Address of the TcbInfo contract
#[arg(long)]
#[serde(skip_serializing_if = "Option::is_none")]
pub tcbinfo_contract: Option<AccountId>,
/// Address of the DCAP verifier contract
#[arg(long)]
#[serde(skip_serializing_if = "Option::is_none")]
pub dcap_verifier_contract: Option<AccountId>,
} }
pub trait ToFigment { pub trait ToFigment {

View file

@ -91,13 +91,13 @@ async fn deploy(
}; };
info!("🚀 Communicating with Relay to Instantiate..."); info!("🚀 Communicating with Relay to Instantiate...");
let raw_init_msg = RelayMessage::Instantiate let init_msg = RelayMessage::Instantiate {
.run_relay(config.enclave_rpc(), config.mock_sgx) init_msg: args.init_msg,
}
.run_relay(config.enclave_rpc())
.await?; .await?;
info!("🚀 Instantiating {}", args.label); 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( let init_output: WasmdTxResponse = serde_json::from_str(&wasmd_client.init(
&config.chain_id, &config.chain_id,
@ -119,5 +119,3 @@ async fn deploy(
Ok((code_id, contract_addr.to_owned())) 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)

View file

@ -171,6 +171,9 @@ fn spawn_enclave_start(args: &DevRequest, config: &Config) -> Result<(), Error>
// In separate process, launch the enclave // In separate process, launch the enclave
let enclave_start = EnclaveStartRequest { let enclave_start = EnclaveStartRequest {
unsafe_trust_latest: args.unsafe_trust_latest, 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(); let config_cpy = config.clone();

View file

@ -3,6 +3,8 @@ use std::{fs, path::Path};
use async_trait::async_trait; use async_trait::async_trait;
use cargo_metadata::MetadataCommand; use cargo_metadata::MetadataCommand;
use color_eyre::owo_colors::OwoColorize; use color_eyre::owo_colors::OwoColorize;
use cosmrs::AccountId;
use quartz_common::enclave::types::Fmspc;
use tokio::process::{Child, Command}; use tokio::process::{Child, Command};
use tracing::{debug, info}; use tracing::{debug, info};
@ -50,6 +52,24 @@ impl Handler for EnclaveStartRequest {
.await?; .await?;
handle_process(enclave_child).await?; handle_process(enclave_child).await?;
} else { } 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"))?; let enclave_dir = fs::canonicalize(config.app_dir.join("enclave"))?;
// gramine private key // gramine private key
@ -62,6 +82,9 @@ impl Handler for EnclaveStartRequest {
&trusted_hash.to_string(), &trusted_hash.to_string(),
quartz_dir_canon, quartz_dir_canon,
&enclave_dir, &enclave_dir,
fmspc,
tcbinfo_contract,
dcap_verifier_contract,
) )
.await?; .await?;
@ -155,6 +178,9 @@ async fn gramine_manifest(
trusted_hash: &str, trusted_hash: &str,
quartz_dir: &Path, quartz_dir: &Path,
enclave_dir: &Path, enclave_dir: &Path,
fmspc: Fmspc,
tcbinfo_contract: AccountId,
dcap_verifier_contract: AccountId,
) -> Result<(), Error> { ) -> Result<(), Error> {
let host = target_lexicon::HOST; let host = target_lexicon::HOST;
let arch_libdir = format!( let arch_libdir = format!(
@ -172,12 +198,18 @@ async fn gramine_manifest(
.arg("-Dlog_level=error") .arg("-Dlog_level=error")
.arg(format!("-Dhome={}", home_dir)) .arg(format!("-Dhome={}", home_dir))
.arg(format!("-Darch_libdir={}", arch_libdir)) .arg(format!("-Darch_libdir={}", arch_libdir))
.arg("-Dra_type=epid") .arg("-Dra_type=dcap")
.arg(format!("-Dra_client_spid={}", ra_client_spid)) .arg(format!("-Dra_client_spid={}", ra_client_spid))
.arg("-Dra_client_linkable=1") .arg("-Dra_client_linkable=1")
.arg(format!("-Dquartz_dir={}", quartz_dir.display())) .arg(format!("-Dquartz_dir={}", quartz_dir.display()))
.arg(format!("-Dtrusted_height={}", trusted_height)) .arg(format!("-Dtrusted_height={}", trusted_height))
.arg(format!("-Dtrusted_hash={}", trusted_hash)) .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.template")
.arg("quartz.manifest") .arg("quartz.manifest")
.current_dir(enclave_dir) .current_dir(enclave_dir)

View file

@ -57,8 +57,8 @@ async fn handshake(args: HandshakeRequest, config: Config) -> Result<String, any
info!("Running SessionCreate"); info!("Running SessionCreate");
let res = RelayMessage::SessionCreate let res: serde_json::Value = RelayMessage::SessionCreate
.run_relay(config.enclave_rpc(), config.mock_sgx) .run_relay(config.enclave_rpc())
.await?; .await?;
let output: WasmdTxResponse = serde_json::from_str( let output: WasmdTxResponse = serde_json::from_str(
@ -101,8 +101,10 @@ async fn handshake(args: HandshakeRequest, config: Config) -> Result<String, any
// Execute SessionSetPubKey on enclave // Execute SessionSetPubKey on enclave
info!("Running SessionSetPubKey"); info!("Running SessionSetPubKey");
let res = RelayMessage::SessionSetPubKey(serde_json::to_string(&proof_output)?) let res: serde_json::Value = RelayMessage::SessionSetPubKey {
.run_relay(config.enclave_rpc(), config.mock_sgx) proof: proof_output,
}
.run_relay(config.enclave_rpc())
.await?; .await?;
// Submit SessionSetPubKey to contract // Submit SessionSetPubKey to contract

View file

@ -1,175 +1,50 @@
use cosmwasm_std::Binary; use quartz_common::proto::{
use hex::decode;
use quartz_common::{
contract::msg::{
execute::{
attested::{EpidAttestation, RawAttested, RawEpidAttestation, RawMockAttestation},
session_create::RawSessionCreate,
session_set_pub_key::RawSessionSetPubKey,
},
instantiate::RawCoreInstantiate,
RawExecuteMsg,
},
proto::{
core_client::CoreClient, InstantiateRequest, SessionCreateRequest, SessionSetPubKeyRequest, core_client::CoreClient, InstantiateRequest, SessionCreateRequest, SessionSetPubKeyRequest,
},
};
use quartz_tee_ra::{intel_sgx::epid::types::ReportBody, IASReport};
use serde_json::json;
use tokio::{
fs::{self, File},
io::AsyncWriteExt,
process::Command,
}; };
use serde_json::{json, Value as JsonValue};
use tm_prover::config::ProofOutput;
use crate::error::Error; use crate::error::Error;
#[derive(Debug)] #[derive(Debug)]
pub enum RelayMessage { pub enum RelayMessage {
Instantiate, Instantiate { init_msg: JsonValue },
SessionCreate, SessionCreate,
SessionSetPubKey(String), SessionSetPubKey { proof: ProofOutput },
} }
impl RelayMessage { impl RelayMessage {
pub async fn run_relay( pub async fn run_relay(self, enclave_rpc: String) -> Result<JsonValue, Error> {
&self,
enclave_rpc: String,
mock_sgx: bool,
) -> Result<serde_json::Value, Error> {
// Query the gRPC quartz enclave service // Query the gRPC quartz enclave service
let mut qc_client = CoreClient::connect(enclave_rpc) let mut qc_client = CoreClient::connect(enclave_rpc)
.await .await
.map_err(|e| Error::GenericErr(e.to_string()))?; .map_err(|e| Error::GenericErr(e.to_string()))?;
let attested_msg = match self { let attested_msg = match self {
RelayMessage::Instantiate => qc_client RelayMessage::Instantiate { mut init_msg } => qc_client
.instantiate(tonic::Request::new(InstantiateRequest {})) .instantiate(tonic::Request::new(InstantiateRequest {}))
.await .await
.map_err(|e| Error::GenericErr(e.to_string()))? .map_err(|e| Error::GenericErr(e.to_string()))
.get_ref() .map(|res| serde_json::from_str::<JsonValue>(&res.into_inner().message))?
.message .map(|msg| {
.clone(), init_msg["quartz"] = msg;
init_msg.to_string()
})?,
RelayMessage::SessionCreate => qc_client RelayMessage::SessionCreate => qc_client
.session_create(tonic::Request::new(SessionCreateRequest {})) .session_create(tonic::Request::new(SessionCreateRequest {}))
.await .await
.map_err(|e| Error::GenericErr(e.to_string()))? .map_err(|e| Error::GenericErr(e.to_string()))
.get_ref() .map(|res| serde_json::from_str::<JsonValue>(&res.into_inner().message))?
.message .map(|msg| json!({ "quartz": {"session_create": msg}}).to_string())?,
.clone(), RelayMessage::SessionSetPubKey { proof } => qc_client
RelayMessage::SessionSetPubKey(proof) => qc_client
.session_set_pub_key(SessionSetPubKeyRequest { .session_set_pub_key(SessionSetPubKeyRequest {
message: proof.to_string(), message: serde_json::to_string(&proof)?,
}) })
.await .await
.map_err(|e| Error::GenericErr(e.to_string()))? .map_err(|e| Error::GenericErr(e.to_string()))
.get_ref() .map(|res| serde_json::from_str::<JsonValue>(&res.into_inner().message))?
.message .map(|msg| json!({ "quartz": {"session_set_pub_key": msg}}).to_string())?,
.clone(),
}; };
serde_json::from_str(&attested_msg).map_err(Into::into)
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(&quote).await?.into();
self.create_attested_msg(msg_json, attestation)
} }
} }
fn create_attested_msg<RA: serde::Serialize>(
&self,
msg_json: serde_json::Value,
attestation: RA,
) -> Result<serde_json::Value, Error> {
match self {
RelayMessage::Instantiate => {
let msg: RawCoreInstantiate = serde_json::from_value(msg_json)?;
let query_result: RawAttested<RawCoreInstantiate, RA> =
RawAttested { msg, attestation };
Ok(json!(query_result))
}
RelayMessage::SessionCreate => {
let msg: RawSessionCreate = serde_json::from_value(msg_json)?;
let query_result: RawExecuteMsg<RA> =
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<RA> =
RawExecuteMsg::RawSessionSetPubKey(RawAttested { msg, attestation });
Ok(json!({ "quartz": query_result }))
}
}
}
}
async fn create_epid_attestation(quote: &serde_json::Value) -> Result<EpidAttestation, Error> {
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(&quote).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))
}

View file

@ -48,6 +48,9 @@ impl TryFrom<Command> for Request {
label: args.contract_deploy.label, label: args.contract_deploy.label,
contract_manifest: args.contract_deploy.contract_manifest, contract_manifest: args.contract_deploy.contract_manifest,
release: args.enclave_build.release, release: args.enclave_build.release,
fmspc: args.fmspc,
tcbinfo_contract: args.tcbinfo_contract,
dcap_verifier_contract: args.dcap_verifier_contract,
} }
.into()), .into()),
} }
@ -98,6 +101,9 @@ impl TryFrom<EnclaveCommand> for Request {
EnclaveCommand::Build(_) => Ok(EnclaveBuildRequest {}.into()), EnclaveCommand::Build(_) => Ok(EnclaveBuildRequest {}.into()),
EnclaveCommand::Start(args) => Ok(EnclaveStartRequest { EnclaveCommand::Start(args) => Ok(EnclaveStartRequest {
unsafe_trust_latest: args.unsafe_trust_latest, unsafe_trust_latest: args.unsafe_trust_latest,
fmspc: args.fmspc,
tcbinfo_contract: args.tcbinfo_contract,
dcap_verifier_contract: args.dcap_verifier_contract,
} }
.into()), .into()),
} }

View file

@ -1,5 +1,8 @@
use std::path::PathBuf; use std::path::PathBuf;
use cosmrs::AccountId;
use quartz_common::enclave::types::Fmspc;
use crate::request::Request; use crate::request::Request;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -10,6 +13,9 @@ pub struct DevRequest {
pub label: String, pub label: String,
pub contract_manifest: PathBuf, pub contract_manifest: PathBuf,
pub release: bool, pub release: bool,
pub fmspc: Option<Fmspc>,
pub tcbinfo_contract: Option<AccountId>,
pub dcap_verifier_contract: Option<AccountId>,
} }
impl From<DevRequest> for Request { impl From<DevRequest> for Request {

View file

@ -1,3 +1,5 @@
use cosmrs::AccountId;
use quartz_common::enclave::types::Fmspc;
use tendermint::{block::Height, Hash}; use tendermint::{block::Height, Hash};
use tracing::debug; use tracing::debug;
@ -9,6 +11,9 @@ use crate::{
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct EnclaveStartRequest { pub struct EnclaveStartRequest {
pub unsafe_trust_latest: bool, pub unsafe_trust_latest: bool,
pub fmspc: Option<Fmspc>,
pub tcbinfo_contract: Option<AccountId>,
pub dcap_verifier_contract: Option<AccountId>,
} }
impl From<EnclaveStartRequest> for Request { impl From<EnclaveStartRequest> for Request {

View file

@ -12,8 +12,6 @@ readme = "README.md"
[features] [features]
mock-sgx = ["quartz-cw/mock-sgx"] mock-sgx = ["quartz-cw/mock-sgx"]
[dependencies] [dependencies]
# external # external
anyhow.workspace = true anyhow.workspace = true
@ -26,12 +24,17 @@ futures-util.workspace = true
hex.workspace = true hex.workspace = true
k256.workspace = true k256.workspace = true
rand.workspace = true rand.workspace = true
reqwest = { workspace = true, features = ["blocking"] }
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
thiserror.workspace = true thiserror.workspace = true
tonic.workspace = true tonic.workspace = true
tokio.workspace = true tokio.workspace = true
tower.workspace = true tower.workspace = true
urlencoding.workspace = true
# mobilecoin
mc-sgx-dcap-sys-types.workspace = true
# cosmos # cosmos
cosmrs.workspace = true cosmrs.workspace = true

View file

@ -11,7 +11,7 @@ gramine-manifest \
-Dlog_level="error" \ -Dlog_level="error" \
-Dhome=${HOME} \ -Dhome=${HOME} \
-Darch_libdir="/lib/$(gcc -dumpmachine)" \ -Darch_libdir="/lib/$(gcc -dumpmachine)" \
-Dra_type="epid" \ -Dra_type="dcap" \
-Dra_client_spid="51CAF5A48B450D624AEFE3286D314894" \ -Dra_client_spid="51CAF5A48B450D624AEFE3286D314894" \
-Dra_client_linkable=1 \ -Dra_client_linkable=1 \
-Dquartz_dir="$(pwd)" \ -Dquartz_dir="$(pwd)" \

View file

@ -1,26 +1,37 @@
use std::{ use std::{
error::Error,
fs::{read, File}, 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::{ use quartz_cw::{
msg::execute::attested::HasUserData, msg::{
execute::attested::{
Attestation, DcapAttestation, EpidAttestation, HasUserData, MockAttestation,
RawDcapAttestation, RawEpidAttestation, RawMockAttestation,
},
HasDomainType,
},
state::{MrEnclave, UserData}, state::{MrEnclave, UserData},
}; };
use quartz_tee_ra::intel_sgx::dcap::{Collateral, Quote3Error};
use reqwest::blocking::Client;
use serde::Serialize;
#[cfg(not(feature = "mock-sgx"))] use crate::types::Fmspc;
pub type DefaultAttestor = EpidAttestor;
#[cfg(feature = "mock-sgx")]
pub type DefaultAttestor = MockAttestor;
/// The trait defines the interface for generating attestations from within an enclave. /// The trait defines the interface for generating attestations from within an enclave.
pub trait Attestor: Send + Sync + 'static { pub trait Attestor: Send + Sync + 'static {
type Error: ToString; type Error: ToString;
type Attestation: Attestation;
type RawAttestation: HasDomainType<DomainType = Self::Attestation> + Serialize;
fn quote(&self, user_data: impl HasUserData) -> Result<Vec<u8>, Self::Error>; fn quote(&self, user_data: impl HasUserData) -> Result<Vec<u8>, Self::Error>;
fn mr_enclave(&self) -> Result<MrEnclave, Self::Error>; fn mr_enclave(&self) -> Result<MrEnclave, Self::Error>;
fn attestation(&self, user_data: impl HasUserData) -> Result<Self::Attestation, Self::Error>;
} }
/// An `Attestor` for generating EPID attestations for Gramine based enclaves. /// An `Attestor` for generating EPID attestations for Gramine based enclaves.
@ -29,6 +40,8 @@ pub struct EpidAttestor;
impl Attestor for EpidAttestor { impl Attestor for EpidAttestor {
type Error = IoError; type Error = IoError;
type Attestation = EpidAttestation;
type RawAttestation = RawEpidAttestation;
fn quote(&self, user_data: impl HasUserData) -> Result<Vec<u8>, Self::Error> { fn quote(&self, user_data: impl HasUserData) -> Result<Vec<u8>, Self::Error> {
let user_data = user_data.user_data(); let user_data = user_data.user_data();
@ -44,14 +57,22 @@ impl Attestor for EpidAttestor {
.try_into() .try_into()
.expect("hardcoded array size")) .expect("hardcoded array size"))
} }
fn attestation(&self, _user_data: impl HasUserData) -> Result<Self::Attestation, Self::Error> {
unimplemented!()
}
} }
/// An `Attestor` for generating DCAP attestations for Gramine based enclaves. /// An `Attestor` for generating DCAP attestations for Gramine based enclaves.
#[derive(Clone, PartialEq, Debug, Default)] #[derive(Clone, PartialEq, Debug)]
pub struct DcapAttestor; pub struct DcapAttestor {
pub fmspc: Fmspc,
}
impl Attestor for DcapAttestor { impl Attestor for DcapAttestor {
type Error = IoError; type Error = IoError;
type Attestation = DcapAttestation;
type RawAttestation = RawDcapAttestation;
fn quote(&self, user_data: impl HasUserData) -> Result<Vec<u8>, Self::Error> { fn quote(&self, user_data: impl HasUserData) -> Result<Vec<u8>, Self::Error> {
let user_data = user_data.user_data(); let user_data = user_data.user_data();
@ -67,6 +88,98 @@ impl Attestor for DcapAttestor {
.try_into() .try_into()
.expect("hardcoded array size")) .expect("hardcoded array size"))
} }
fn attestation(&self, user_data: impl HasUserData) -> Result<Self::Attestation, Self::Error> {
fn pccs_query_pck() -> Result<(Vec<u8>, String), Box<dyn Error>> {
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<u8>,
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 /// 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 { impl Attestor for MockAttestor {
type Error = String; type Error = String;
type Attestation = MockAttestation;
type RawAttestation = RawMockAttestation;
fn quote(&self, user_data: impl HasUserData) -> Result<Vec<u8>, Self::Error> { fn quote(&self, user_data: impl HasUserData) -> Result<Vec<u8>, Self::Error> {
let user_data = user_data.user_data(); let user_data = user_data.user_data();
@ -85,6 +200,10 @@ impl Attestor for MockAttestor {
fn mr_enclave(&self) -> Result<MrEnclave, Self::Error> { fn mr_enclave(&self) -> Result<MrEnclave, Self::Error> {
Ok(Default::default()) Ok(Default::default())
} }
fn attestation(&self, user_data: impl HasUserData) -> Result<Self::Attestation, Self::Error> {
Ok(MockAttestation(user_data.user_data()))
}
} }
struct NullUserData; struct NullUserData;

View file

@ -1,5 +1,5 @@
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![forbid(unsafe_code)] // #![forbid(unsafe_code)]
#![warn( #![warn(
clippy::checked_conversions, clippy::checked_conversions,
clippy::panic, clippy::panic,

View file

@ -13,7 +13,10 @@ use futures_util::StreamExt;
use k256::ecdsa::SigningKey; use k256::ecdsa::SigningKey;
use quartz_cw::{ use quartz_cw::{
msg::{ msg::{
execute::{session_create::SessionCreate, session_set_pub_key::SessionSetPubKey}, execute::{
attested::Attested, session_create::SessionCreate,
session_set_pub_key::SessionSetPubKey,
},
instantiate::CoreInstantiate, instantiate::CoreInstantiate,
}, },
state::{Config, LightClientOpts, Nonce, Session}, state::{Config, LightClientOpts, Nonce, Session},
@ -49,7 +52,7 @@ use tonic::{
use tower::Service; use tower::Service;
use crate::{ use crate::{
attestor::{Attestor, DefaultAttestor}, attestor::Attestor,
error::QuartzError, error::QuartzError,
types::{InstantiateResponse, SessionCreateResponse, SessionSetPubKeyResponse}, types::{InstantiateResponse, SessionCreateResponse, SessionSetPubKeyResponse},
}; };
@ -96,12 +99,15 @@ pub struct QuartzServer {
} }
impl QuartzServer { impl QuartzServer {
pub fn new( pub fn new<A>(
config: Config, config: Config,
sk: Arc<Mutex<Option<SigningKey>>>, sk: Arc<Mutex<Option<SigningKey>>>,
attestor: DefaultAttestor, attestor: A,
ws_config: WsListenerConfig, ws_config: WsListenerConfig,
) -> Self { ) -> Self
where
A: Attestor + Clone,
{
let core_service = CoreServer::new(CoreService::new(config, sk.clone(), attestor.clone())); let core_service = CoreServer::new(CoreService::new(config, sk.clone(), attestor.clone()));
Self { Self {
@ -200,16 +206,19 @@ where
&self, &self,
_request: Request<RawInstantiateRequest>, _request: Request<RawInstantiateRequest>,
) -> TonicResult<Response<RawInstantiateResponse>> { ) -> TonicResult<Response<RawInstantiateResponse>> {
let core_instantiate_msg = CoreInstantiate::new(self.config.clone()); let msg = CoreInstantiate::new(self.config.clone());
let quote = self let attestation = self
.attestor .attestor
.quote(core_instantiate_msg) .attestation(msg.clone())
.map_err(|e| Status::internal(e.to_string()))?; .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<A::Attestation, A::RawAttestation> =
InstantiateResponse::new(attested_msg);
Ok(Response::new(response.into())) Ok(Response::new(response.into()))
} }
async fn session_create( async fn session_create(
&self, &self,
_request: Request<RawSessionCreateRequest>, _request: Request<RawSessionCreateRequest>,
@ -217,15 +226,16 @@ where
// FIXME(hu55a1n1) - disallow calling more than once // FIXME(hu55a1n1) - disallow calling more than once
let mut nonce = self.nonce.lock().unwrap(); let mut nonce = self.nonce.lock().unwrap();
*nonce = rand::thread_rng().gen::<Nonce>(); *nonce = rand::thread_rng().gen::<Nonce>();
let msg = SessionCreate::new(*nonce);
let session_create_msg = SessionCreate::new(*nonce); let attestation = self
let quote = self
.attestor .attestor
.quote(session_create_msg) .attestation(msg.clone())
.map_err(|e| Status::internal(e.to_string()))?; .map_err(|e| Status::internal(e.to_string()))?;
let attested_msg = Attested::new(msg, attestation);
let response = SessionCreateResponse::new(*nonce, quote); let response: SessionCreateResponse<A::Attestation, A::RawAttestation> =
SessionCreateResponse::new(attested_msg);
Ok(Response::new(response.into())) Ok(Response::new(response.into()))
} }
@ -253,14 +263,16 @@ where
*self.sk.lock().unwrap() = Some(sk.clone()); *self.sk.lock().unwrap() = Some(sk.clone());
let pk = sk.verifying_key(); 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 .attestor
.quote(session_set_pub_key_msg) .attestation(msg.clone())
.map_err(|e| Status::internal(e.to_string()))?; .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<A::Attestation, A::RawAttestation> =
SessionSetPubKeyResponse::new(attested_msg);
Ok(Response::new(response.into())) Ok(Response::new(response.into()))
} }
} }

View file

@ -1,8 +1,18 @@
use cosmwasm_std::{HexBinary, StdError}; use std::{
use k256::ecdsa::VerifyingKey; fmt::{Display, Formatter},
use quartz_cw::{ marker::PhantomData,
error::Error as QuartzCwError, str::FromStr,
state::{Config, Nonce, RawConfig}, };
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::{ use quartz_proto::quartz::{
InstantiateResponse as RawInstantiateResponse, InstantiateResponse as RawInstantiateResponse,
@ -12,41 +22,29 @@ use quartz_proto::quartz::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct InstantiateResponse { pub struct InstantiateResponse<A, RA> {
message: InstantiateResponseMsg, message: Attested<CoreInstantiate, A>,
_phantom: PhantomData<RA>,
} }
impl InstantiateResponse { impl<A, RA> InstantiateResponse<A, RA> {
pub fn new(config: Config, quote: Vec<u8>) -> Self { pub fn new(message: Attested<CoreInstantiate, A>) -> Self {
Self { Self {
message: InstantiateResponseMsg { config, quote }, message,
_phantom: Default::default(),
} }
} }
pub fn into_message(self) -> Attested<CoreInstantiate, A> {
pub fn quote(&self) -> &[u8] {
&self.message.quote
}
pub fn into_message(self) -> InstantiateResponseMsg {
self.message self.message
} }
} }
impl TryFrom<RawInstantiateResponse> for InstantiateResponse { impl<A, RA> From<InstantiateResponse<A, RA>> for RawInstantiateResponse
type Error = StdError; where
RA: HasDomainType<DomainType = A> + Serialize,
fn try_from(value: RawInstantiateResponse) -> Result<Self, Self::Error> { {
let raw_message: RawInstantiateResponseMsg = serde_json::from_str(&value.message) fn from(value: InstantiateResponse<A, RA>) -> Self {
.map_err(|e| StdError::parse_err("RawInstantiateResponseMsg", e))?; let raw_message: RawAttested<RawCoreInstantiate, RA> = value.message.into();
Ok(Self {
message: raw_message.try_into()?,
})
}
}
impl From<InstantiateResponse> for RawInstantiateResponse {
fn from(value: InstantiateResponse) -> Self {
let raw_message: RawInstantiateResponseMsg = value.message.into();
Self { Self {
message: serde_json::to_string(&raw_message).expect("infallible serializer"), message: serde_json::to_string(&raw_message).expect("infallible serializer"),
} }
@ -54,79 +52,30 @@ impl From<InstantiateResponse> for RawInstantiateResponse {
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct InstantiateResponseMsg { pub struct SessionCreateResponse<A, RA> {
config: Config, message: Attested<SessionCreate, A>,
quote: Vec<u8>, _phantom: PhantomData<RA>,
} }
impl InstantiateResponseMsg { impl<A, RA> SessionCreateResponse<A, RA> {
pub fn into_tuple(self) -> (Config, Vec<u8>) { pub fn new(message: Attested<SessionCreate, A>) -> Self {
(self.config, self.quote)
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RawInstantiateResponseMsg {
config: RawConfig,
quote: HexBinary,
}
impl TryFrom<RawInstantiateResponseMsg> for InstantiateResponseMsg {
type Error = StdError;
fn try_from(value: RawInstantiateResponseMsg) -> Result<Self, Self::Error> {
Ok(Self {
config: value.config.try_into()?,
quote: value.quote.into(),
})
}
}
impl From<InstantiateResponseMsg> for RawInstantiateResponseMsg {
fn from(value: InstantiateResponseMsg) -> Self {
Self { Self {
config: value.config.into(), message,
quote: value.quote.into(), _phantom: Default::default(),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct SessionCreateResponse {
message: SessionCreateResponseMsg,
}
impl SessionCreateResponse {
pub fn new(nonce: Nonce, quote: Vec<u8>) -> Self {
Self {
message: SessionCreateResponseMsg { nonce, quote },
} }
} }
pub fn quote(&self) -> &[u8] { pub fn into_message(self) -> Attested<SessionCreate, A> {
&self.message.quote
}
pub fn into_message(self) -> SessionCreateResponseMsg {
self.message self.message
} }
} }
impl TryFrom<RawSessionCreateResponse> for SessionCreateResponse { impl<A, RA> From<SessionCreateResponse<A, RA>> for RawSessionCreateResponse
type Error = StdError; where
RA: HasDomainType<DomainType = A> + Serialize,
fn try_from(value: RawSessionCreateResponse) -> Result<Self, Self::Error> { {
let raw_message: RawSessionCreateResponseMsg = serde_json::from_str(&value.message) fn from(value: SessionCreateResponse<A, RA>) -> Self {
.map_err(|e| StdError::parse_err("RawSessionCreateResponseMsg", e))?; let raw_message: RawAttested<RawSessionCreate, RA> = value.message.into();
Ok(Self {
message: raw_message.try_into()?,
})
}
}
impl From<SessionCreateResponse> for RawSessionCreateResponse {
fn from(value: SessionCreateResponse) -> Self {
let raw_message: RawSessionCreateResponseMsg = value.message.into();
Self { Self {
message: serde_json::to_string(&raw_message).expect("infallible serializer"), message: serde_json::to_string(&raw_message).expect("infallible serializer"),
} }
@ -134,130 +83,67 @@ impl From<SessionCreateResponse> for RawSessionCreateResponse {
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct SessionCreateResponseMsg { pub struct SessionSetPubKeyResponse<A, RA> {
nonce: Nonce, message: Attested<SessionSetPubKey, A>,
quote: Vec<u8>, _phantom: PhantomData<RA>,
} }
impl SessionCreateResponseMsg { impl<A, RA> SessionSetPubKeyResponse<A, RA> {
pub fn into_tuple(self) -> (Nonce, Vec<u8>) { pub fn new(message: Attested<SessionSetPubKey, A>) -> Self {
(self.nonce, self.quote)
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RawSessionCreateResponseMsg {
nonce: HexBinary,
quote: HexBinary,
}
impl TryFrom<RawSessionCreateResponseMsg> for SessionCreateResponseMsg {
type Error = StdError;
fn try_from(value: RawSessionCreateResponseMsg) -> Result<Self, Self::Error> {
Ok(Self {
nonce: value.nonce.to_array()?,
quote: value.quote.into(),
})
}
}
impl From<SessionCreateResponseMsg> for RawSessionCreateResponseMsg {
fn from(value: SessionCreateResponseMsg) -> Self {
Self { Self {
nonce: value.nonce.into(), message,
quote: value.quote.into(), _phantom: Default::default(),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct SessionSetPubKeyResponse {
message: SessionSetPubKeyResponseMsg,
}
impl SessionSetPubKeyResponse {
pub fn new(nonce: Nonce, pub_key: VerifyingKey, quote: Vec<u8>) -> Self {
Self {
message: SessionSetPubKeyResponseMsg {
nonce,
pub_key,
quote,
},
} }
} }
pub fn quote(&self) -> &[u8] { pub fn into_message(self) -> Attested<SessionSetPubKey, A> {
&self.message.quote
}
pub fn into_message(self) -> SessionSetPubKeyResponseMsg {
self.message self.message
} }
} }
impl TryFrom<RawSessionSetPubKeyResponse> for SessionSetPubKeyResponse { impl<A, RA> From<SessionSetPubKeyResponse<A, RA>> for RawSessionSetPubKeyResponse
type Error = StdError; where
RA: HasDomainType<DomainType = A> + Serialize,
fn try_from(value: RawSessionSetPubKeyResponse) -> Result<Self, Self::Error> { {
let raw_message: RawSessionSetPubKeyResponseMsg = serde_json::from_str(&value.message) fn from(value: SessionSetPubKeyResponse<A, RA>) -> Self {
.map_err(|e| StdError::parse_err("RawSessionSetPubKeyResponseMsg", e))?; let raw_message: RawAttested<RawSessionSetPubKey, RA> = value.message.into();
Ok(Self {
message: raw_message.try_into()?,
})
}
}
impl From<SessionSetPubKeyResponse> for RawSessionSetPubKeyResponse {
fn from(value: SessionSetPubKeyResponse) -> Self {
let raw_message: RawSessionSetPubKeyResponseMsg = value.message.into();
Self { Self {
message: serde_json::to_string(&raw_message).expect("infallible serializer"), message: serde_json::to_string(&raw_message).expect("infallible serializer"),
} }
} }
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct SessionSetPubKeyResponseMsg { pub struct Fmspc(pub [u8; 6]);
nonce: Nonce,
pub_key: VerifyingKey,
quote: Vec<u8>,
}
impl SessionSetPubKeyResponseMsg { impl AsRef<[u8]> for Fmspc {
pub fn into_tuple(self) -> (VerifyingKey, Vec<u8>) { fn as_ref(&self) -> &[u8] {
(self.pub_key, self.quote) self.0.as_ref()
} }
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] impl FromStr for Fmspc {
pub struct RawSessionSetPubKeyResponseMsg { type Err = FromHexError;
nonce: HexBinary,
pub_key: HexBinary,
quote: HexBinary,
}
impl TryFrom<RawSessionSetPubKeyResponseMsg> for SessionSetPubKeyResponseMsg { fn from_str(s: &str) -> Result<Self, Self::Err> {
type Error = StdError; let bytes = hex::decode(s)?;
let fmspc: [u8; 6] = bytes
fn try_from(value: RawSessionSetPubKeyResponseMsg) -> Result<Self, Self::Error> { .try_into()
let pub_key = VerifyingKey::from_sec1_bytes(&value.pub_key) .map_err(|_| FromHexError::InvalidStringLength)?;
.map_err(QuartzCwError::from) Ok(Self(fmspc))
.map_err(|e| StdError::generic_err(e.to_string()))?;
Ok(Self {
nonce: value.nonce.to_array()?,
pub_key,
quote: value.quote.into(),
})
} }
} }
impl From<SessionSetPubKeyResponseMsg> for RawSessionSetPubKeyResponseMsg { impl TryFrom<String> for Fmspc {
fn from(value: SessionSetPubKeyResponseMsg) -> Self { type Error = FromHexError;
Self {
nonce: value.nonce.into(), fn try_from(value: String) -> Result<Self, Self::Error> {
pub_key: value.pub_key.to_sec1_bytes().into_vec().into(), value.as_str().parse()
quote: value.quote.into(),
} }
} }
impl Display for Fmspc {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", hex::encode(self))
}
} }

View file

@ -13,16 +13,18 @@ readme = "README.md"
default = [] default = []
mock-sgx = [] mock-sgx = []
std = ["k256/std", "serde/std", "serde_json/std", "sha2/std", "cosmwasm-std/std"] std = ["k256/std", "serde/std", "serde_json/std", "sha2/std", "cosmwasm-std/std"]
library = []
[dependencies] [dependencies]
# external # external
ciborium.workspace = true
hex.workspace = true
k256.workspace = true k256.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
serde_with.workspace = true serde_with.workspace = true
sha2.workspace = true sha2.workspace = true
thiserror.workspace = true thiserror.workspace = true
hex.workspace = true
# cosmos # cosmos
cw-storage-plus.workspace = true cw-storage-plus.workspace = true
@ -30,8 +32,9 @@ cosmwasm-schema.workspace = true
cosmwasm-std.workspace = true cosmwasm-std.workspace = true
# quartz # quartz
quartz-dcap-verifier-msgs.workspace = true
quartz-tee-ra.workspace = true quartz-tee-ra.workspace = true
tcbinfo.workspace = true tcbinfo-msgs.workspace = true
[dev-dependencies] [dev-dependencies]
serde_json.workspace = true serde_json.workspace = true

View file

@ -17,6 +17,8 @@ pub enum Error {
InvalidFmspc(String), InvalidFmspc(String),
#[error("TCB Info query error: {0}")] #[error("TCB Info query error: {0}")]
TcbInfoQueryError(String), TcbInfoQueryError(String),
#[error("DCAP verification query error: {0}")]
DcapVerificationQueryError(String),
} }
impl From<K256Error> for Error { impl From<K256Error> for Error {

View file

@ -1,28 +1,46 @@
use ciborium::{from_reader as from_cbor_slice, into_writer as into_cbor, Value as CborValue};
use cosmwasm_std::{ use cosmwasm_std::{
from_json, to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, QueryRequest, Response, to_json_binary, Deps, DepsMut, Env, MessageInfo, QueryRequest, Response, StdResult, WasmQuery,
WasmQuery,
}; };
use quartz_dcap_verifier_msgs::QueryMsg as DcapVerifierQueryMsg;
use quartz_tee_ra::{ use quartz_tee_ra::{
intel_sgx::dcap::{Collateral, TrustedMrEnclaveIdentity}, intel_sgx::dcap::{Collateral, TrustedIdentity, TrustedMrEnclaveIdentity},
verify_dcap_attestation, verify_epid_attestation, Error as RaVerificationError, 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::{ use crate::{
error::Error, error::Error,
handler::Handler, handler::Handler,
msg::execute::attested::{ msg::execute::attested::{
Attestation, Attested, AttestedMsgSansHandler, DcapAttestation, EpidAttestation, Attestation, Attested, AttestedMsgSansHandler, DcapAttestation, EpidAttestation,
HasUserData, MockAttestation, HasUserData, MockAttestation, Quote,
}, },
state::CONFIG, state::CONFIG,
}; };
pub fn query_tcbinfo(deps: Deps<'_>, fmspc: String) -> Result<Binary, Error> { fn query_contract<T: DeserializeOwned>(
deps: Deps<'_>,
contract_addr: String,
query_msg: impl Serialize,
) -> StdResult<T> {
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<GetTcbInfoResponse, Error> {
let tcbinfo_addr = {
let config = CONFIG.load(deps.storage).map_err(Error::Std)?; let config = CONFIG.load(deps.storage).map_err(Error::Std)?;
let tcbinfo_addr = config config
.tcb_info() .tcbinfo_contract()
.expect("TcbInfo contract address is required for DCAP"); .expect("TcbInfo contract address is required for DCAP")
.to_string()
};
let fmspc_bytes = let fmspc_bytes =
hex::decode(&fmspc).map_err(|_| Error::InvalidFmspc("Invalid FMSPC format".to_string()))?; 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<Binary, Error> {
let query_msg = TcbInfoQueryMsg::GetTcbInfo { fmspc }; let query_msg = TcbInfoQueryMsg::GetTcbInfo { fmspc };
let request = QueryRequest::Wasm(WasmQuery::Smart { query_contract(deps, tcbinfo_addr, &query_msg)
contract_addr: tcbinfo_addr,
msg: to_json_binary(&query_msg).map_err(Error::Std)?,
});
deps.querier
.query(&request)
.map_err(|err| Error::TcbInfoQueryError(err.to_string())) .map_err(|err| Error::TcbInfoQueryError(err.to_string()))
} }
fn to_cbor_vec<T: Serialize>(value: &T) -> Vec<u8> {
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<TrustedIdentity>,
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 { impl Handler for EpidAttestation {
fn handle( fn handle(
self, self,
@ -63,42 +105,48 @@ impl Handler for EpidAttestation {
impl Handler for DcapAttestation { impl Handler for DcapAttestation {
fn handle(self, deps: DepsMut<'_>, _env: &Env, _info: &MessageInfo) -> Result<Response, Error> { fn handle(self, deps: DepsMut<'_>, _env: &Env, _info: &MessageInfo) -> Result<Response, Error> {
let (quote, collateral) = self.clone().into_tuple(); 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 // Retrieve the FMSPC from the collateral
let fmspc_hex = collateral.tcb_info().to_string(); let fmspc_hex = collateral.tcb_info().to_string();
// Query the tcbinfo contract with the FMSPC retrieved and validated // 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 = query_tcbinfo(deps.as_ref(), fmspc_hex)?;
let tcb_info_response: GetTcbInfoResponse = from_json(tcb_info_query)?;
// Serialize the existing collateral // Serialize the existing collateral
let mut collateral_json: serde_json::Value = let collateral_serialized = to_cbor_vec(&collateral);
serde_json::to_value(&collateral).map_err(|e| { let mut collateral_value: CborValue = from_cbor_slice(collateral_serialized.as_slice())
.map_err(|e| {
Error::TcbInfoQueryError(format!("Failed to serialize collateral: {}", e)) Error::TcbInfoQueryError(format!("Failed to serialize collateral: {}", e))
})?; })?;
// Update the tcb_info in the serialized data // 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 // Deserialize back into a Collateral
let updated_collateral: Collateral = let collateral_serialized = to_cbor_vec(&collateral_value);
serde_json::from_value(collateral_json).map_err(|e| { let updated_collateral: Collateral = from_cbor_slice(collateral_serialized.as_slice())
.map_err(|e| {
Error::TcbInfoQueryError(format!("Failed to deserialize updated collateral: {}", 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 query_dcap_verifier(deps.as_ref(), quote, mr_enclave, updated_collateral)
let verification_output = .map(|_| Response::default())
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,
)))
}
} }
} }

View file

@ -5,7 +5,8 @@ pub mod query;
use cosmwasm_std::StdError; use cosmwasm_std::StdError;
pub use execute::{Execute as ExecuteMsg, RawExecute as RawExecuteMsg}; pub use execute::{Execute as ExecuteMsg, RawExecute as RawExecuteMsg};
pub use instantiate::{Instantiate as InstantiateMsg, RawInstantiate as RawInstantiateMsg}; pub use instantiate::{Instantiate as InstantiateMsg, RawInstantiate as RawInstantiateMsg};
use serde::Serialize;
pub trait HasDomainType: From<Self::DomainType> { pub trait HasDomainType: From<Self::DomainType> + Serialize {
type DomainType: TryFrom<Self, Error = StdError>; type DomainType: TryFrom<Self, Error = StdError>;
} }

View file

@ -13,9 +13,9 @@ use serde::Serialize;
pub type Quote = Quote3<Vec<u8>>; pub type Quote = Quote3<Vec<u8>>;
#[cfg(not(feature = "mock-sgx"))] #[cfg(not(feature = "mock-sgx"))]
pub type DefaultAttestation = EpidAttestation; pub type DefaultAttestation = DcapAttestation;
#[cfg(not(feature = "mock-sgx"))] #[cfg(not(feature = "mock-sgx"))]
pub type RawDefaultAttestation = RawEpidAttestation; pub type RawDefaultAttestation = RawDcapAttestation;
#[cfg(feature = "mock-sgx")] #[cfg(feature = "mock-sgx")]
pub type DefaultAttestation = MockAttestation; pub type DefaultAttestation = MockAttestation;
@ -178,8 +178,8 @@ impl DcapAttestation {
#[cw_serde] #[cw_serde]
pub struct RawDcapAttestation { pub struct RawDcapAttestation {
quote: HexBinary, pub quote: HexBinary,
collateral: serde_json::Value, pub collateral: HexBinary,
} }
impl TryFrom<RawDcapAttestation> for DcapAttestation { impl TryFrom<RawDcapAttestation> for DcapAttestation {
@ -187,10 +187,11 @@ impl TryFrom<RawDcapAttestation> for DcapAttestation {
fn try_from(value: RawDcapAttestation) -> Result<Self, Self::Error> { fn try_from(value: RawDcapAttestation) -> Result<Self, Self::Error> {
let quote_bytes: Vec<u8> = value.quote.into(); let quote_bytes: Vec<u8> = value.quote.into();
let collateral_bytes: Vec<u8> = value.collateral.into();
let quote = quote_bytes let quote = quote_bytes
.try_into() .try_into()
.map_err(|e: Quote3Error| StdError::parse_err("Quote", e.to_string()))?; .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()))?; .map_err(|e| StdError::parse_err("Collateral", e.to_string()))?;
Ok(Self { quote, collateral }) Ok(Self { quote, collateral })
@ -199,11 +200,13 @@ impl TryFrom<RawDcapAttestation> for DcapAttestation {
impl From<DcapAttestation> for RawDcapAttestation { impl From<DcapAttestation> for RawDcapAttestation {
fn from(value: DcapAttestation) -> Self { fn from(value: DcapAttestation) -> Self {
let mut collateral_serialized = Vec::new();
ciborium::into_writer(&value.collateral, &mut collateral_serialized)
.expect("infallible serializer");
Self { Self {
quote: value.quote.as_ref().to_vec().into(), quote: value.quote.as_ref().to_vec().into(),
collateral: serde_json::to_vec(&value.collateral) collateral: collateral_serialized.into(),
.expect("infallible serializer")
.into(),
} }
} }
} }
@ -282,7 +285,7 @@ pub struct AttestedMsgSansHandler<T>(pub T);
#[cw_serde] #[cw_serde]
pub struct RawAttestedMsgSansHandler<T>(pub T); pub struct RawAttestedMsgSansHandler<T>(pub T);
impl<T> HasDomainType for RawAttestedMsgSansHandler<T> { impl<T: Serialize> HasDomainType for RawAttestedMsgSansHandler<T> {
type DomainType = AttestedMsgSansHandler<T>; type DomainType = AttestedMsgSansHandler<T>;
} }

View file

@ -1,5 +1,6 @@
use cosmwasm_schema::cw_serde; use cosmwasm_schema::cw_serde;
use cosmwasm_std::{HexBinary, StdError}; use cosmwasm_std::{HexBinary, StdError};
use sha2::{Digest, Sha256};
use crate::{ use crate::{
msg::{execute::attested::HasUserData, HasDomainType}, msg::{execute::attested::HasUserData, HasDomainType},
@ -49,8 +50,15 @@ impl HasDomainType for RawSessionCreate {
impl HasUserData for SessionCreate { impl HasUserData for SessionCreate {
fn user_data(&self) -> UserData { 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]; 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 user_data
} }
} }

View file

@ -65,8 +65,10 @@ impl HasDomainType for RawSessionSetPubKey {
impl HasUserData for SessionSetPubKey { impl HasUserData for SessionSetPubKey {
fn user_data(&self) -> UserData { fn user_data(&self) -> UserData {
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
hasher.update(self.nonce); hasher.update(
hasher.update(self.pub_key.to_sec1_bytes()); serde_json::to_string(&RawSessionSetPubKey::from(self.clone()))
.expect("infallible serializer"),
);
let digest: [u8; 32] = hasher.finalize().into(); let digest: [u8; 32] = hasher.finalize().into();
let mut user_data = [0u8; 64]; let mut user_data = [0u8; 64];

View file

@ -91,7 +91,7 @@ impl HasUserData for CoreInstantiate {
fn user_data(&self) -> UserData { fn user_data(&self) -> UserData {
let mut hasher = Sha256::new(); let mut hasher = Sha256::new();
hasher.update( hasher.update(
serde_json::to_string(&RawConfig::from(self.config.clone())) serde_json::to_string(&RawCoreInstantiate::from(self.clone()))
.expect("infallible serializer"), .expect("infallible serializer"),
); );
let digest: [u8; 32] = hasher.finalize().into(); let digest: [u8; 32] = hasher.finalize().into();

View file

@ -18,6 +18,7 @@ pub struct Config {
epoch_duration: Duration, epoch_duration: Duration,
light_client_opts: LightClientOpts, light_client_opts: LightClientOpts,
tcbinfo_contract: Option<String>, tcbinfo_contract: Option<String>,
dcap_verifier_contract: Option<String>,
} }
impl Config { impl Config {
@ -26,12 +27,14 @@ impl Config {
epoch_duration: Duration, epoch_duration: Duration,
light_client_opts: LightClientOpts, light_client_opts: LightClientOpts,
tcbinfo_contract: Option<String>, tcbinfo_contract: Option<String>,
dcap_verifier_contract: Option<String>,
) -> Self { ) -> Self {
Self { Self {
mr_enclave, mr_enclave,
epoch_duration, epoch_duration,
light_client_opts, light_client_opts,
tcbinfo_contract, tcbinfo_contract,
dcap_verifier_contract,
} }
} }
@ -42,10 +45,6 @@ impl Config {
pub fn mr_enclave(&self) -> MrEnclave { pub fn mr_enclave(&self) -> MrEnclave {
self.mr_enclave self.mr_enclave
} }
pub fn tcbinfo_contract(&self) -> Option<&str> {
self.tcbinfo_contract.as_deref()
}
} }
#[cw_serde] #[cw_serde]
@ -54,6 +53,7 @@ pub struct RawConfig {
epoch_duration: Duration, epoch_duration: Duration,
light_client_opts: RawLightClientOpts, light_client_opts: RawLightClientOpts,
tcbinfo_contract: Option<String>, tcbinfo_contract: Option<String>,
dcap_verifier_contract: Option<String>,
} }
impl RawConfig { impl RawConfig {
@ -61,8 +61,12 @@ impl RawConfig {
self.mr_enclave.as_slice() self.mr_enclave.as_slice()
} }
pub fn tcb_info(&self) -> Option<String> { pub fn tcbinfo_contract(&self) -> Option<&str> {
self.tcbinfo_contract.clone().map(|c| c.to_string()) 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<RawConfig> for Config {
.try_into() .try_into()
.map_err(|e| StdError::parse_err("light_client_opts", e))?, .map_err(|e| StdError::parse_err("light_client_opts", e))?,
tcbinfo_contract: value.tcbinfo_contract, tcbinfo_contract: value.tcbinfo_contract,
dcap_verifier_contract: value.dcap_verifier_contract,
}) })
} }
} }
@ -89,6 +94,7 @@ impl From<Config> for RawConfig {
epoch_duration: value.epoch_duration, epoch_duration: value.epoch_duration,
light_client_opts: value.light_client_opts.into(), light_client_opts: value.light_client_opts.into(),
tcbinfo_contract: value.tcbinfo_contract, tcbinfo_contract: value.tcbinfo_contract,
dcap_verifier_contract: value.dcap_verifier_contract,
} }
} }
} }

View file

@ -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]

View file

@ -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"
}
}'
```

View file

@ -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

View file

@ -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<Vec<u8>>,
},
}

View file

@ -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,
}
}

View file

@ -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<Response, StdError> {
Ok(Response::default())
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
_msg: ExecuteMsg,
) -> StdResult<Response> {
unimplemented!()
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::VerifyDcapAttestation {
quote,
collateral,
identities,
} => {
let quote = Quote3::<Vec<u8>>::try_from(Vec::<u8>::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<TrustedIdentity> = 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(),
))
}
}
}
}

View file

@ -0,0 +1,10 @@
#![deny(
warnings,
trivial_casts,
trivial_numeric_casts,
unused_import_braces,
unused_qualifications
)]
#![forbid(unsafe_code)]
pub mod contract;

View file

@ -12,7 +12,6 @@ readme = "README.md"
[dependencies] [dependencies]
# external # external
der.workspace = true der.workspace = true
displaydoc.workspace = true
hex-literal.workspace = true hex-literal.workspace = true
num-bigint.workspace = true num-bigint.workspace = true
serde.workspace = true serde.workspace = true
@ -21,13 +20,10 @@ sha2.workspace = true
thiserror.workspace = true thiserror.workspace = true
x509-cert.workspace = true x509-cert.workspace = true
x509-parser.workspace = true x509-parser.workspace = true
zeroize.workspace = true
# mobilecoin # mobilecoin
mc-attestation-verifier.workspace = true mc-attestation-verifier.workspace = true
mc-sgx-core-types.workspace = true
mc-sgx-dcap-types.workspace = true mc-sgx-dcap-types.workspace = true
mc-sgx-dcap-sys-types.workspace = true
# cosmos # cosmos
cosmwasm-schema.workspace = true cosmwasm-schema.workspace = true
@ -35,3 +31,6 @@ cosmwasm-std.workspace = true
[dev-dependencies] [dev-dependencies]
hex = "0.4.3" hex = "0.4.3"
mc-sgx-dcap-types.workspace = true
mc-sgx-core-types.workspace = true
mc-sgx-dcap-sys-types.workspace = true

View file

@ -1,7 +1,7 @@
use der::{pem::LineEnding, DateTime, EncodePem}; use der::{DateTime, Encode};
use mc_attestation_verifier::{CertificateChainVerifier, CertificateChainVerifierError}; use mc_attestation_verifier::{CertificateChainVerifier, CertificateChainVerifierError};
use x509_cert::{crl::CertificateList, Certificate}; 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)] #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
pub struct TlsCertificateChainVerifier; pub struct TlsCertificateChainVerifier;
@ -22,18 +22,13 @@ impl CertificateChainVerifier for TlsCertificateChainVerifier {
) -> Result<(), CertificateChainVerifierError> { ) -> Result<(), CertificateChainVerifierError> {
let enc_certs = certificate_chain let enc_certs = certificate_chain
.into_iter() .into_iter()
.map(|cert| cert.to_pem(LineEnding::LF)) .map(|cert| cert.to_der())
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.map_err(|_| CertificateChainVerifierError::GeneralCertificateError)?; .map_err(|_| CertificateChainVerifierError::GeneralCertificateError)?;
let pem_chain = enc_certs let cert_chain = enc_certs
.iter() .iter()
.map(|enc_cert| parse_x509_pem(enc_cert.as_ref())) .map(|der| parse_x509_certificate(der))
.collect::<Result<Vec<_>, _>>()
.map_err(|_| CertificateChainVerifierError::GeneralCertificateError)?;
let cert_chain = pem_chain
.iter()
.map(|pem| parse_x509_certificate(&pem.1.contents))
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
.map_err(|_| CertificateChainVerifierError::GeneralCertificateError)?; .map_err(|_| CertificateChainVerifierError::GeneralCertificateError)?;
// Skip applying the Certificate Revocation List entirely // Skip applying the Certificate Revocation List entirely

View file

@ -1,25 +1,17 @@
[package] [package]
name = "tcbinfo" name = "tcbinfo"
version = "0.1.0" version.workspace = true
authors = ["quinine"] authors.workspace = true
edition = "2021" 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 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib] [lib]
crate-type = ["cdylib", "rlib"] 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] [features]
# use library feature to disable all instantiate/execute/query exports # use library feature to disable all instantiate/execute/query exports
library = [] library = []
@ -32,25 +24,31 @@ optimize = """docker run --rm -v "$(pwd)":/code \
""" """
[dependencies] [dependencies]
cosmwasm-schema = "2.0.1" # external
cosmwasm-std = { version = "2.0.1", default-features = false, features = [ der.workspace = true
"cosmwasm_1_3", hex.workspace = true
# Enable this if you only deploy to chains that have CosmWasm 1.4 or higher p256.workspace = true
# "cosmwasm_1_4", schemars.workspace = true
] } serde.workspace = true
cw-storage-plus = "2.0.0" serde_json.workspace = true
cw2 = "2.0.0" thiserror.workspace = true
schemars = "0.8.16" x509-cert.workspace = true
serde = { version = "1.0.197", default-features = false, features = ["derive"] }
thiserror = { version = "1.0.58" } # mobilecoin
x509-cert = { version = "0.2.5", default-features = false, features = ["pem"] } mc-attestation-verifier.workspace = true
getrandom ={ version = "0.2.5", default-features = false, features = ["js"]}
der = { version = "0.7.9" } # cosmos
quartz-tee-ra = { path = "../quartz-tee-ra" } cosmwasm-schema.workspace = true
mc-attestation-verifier = { git = "https://github.com/informalsystems/attestation", default-features = false } cosmwasm-std.workspace = true
p256 = { version = "0.13.2", default-features = false } cw2.workspace = true
serde_json = { version = "1.0", default-features = false } cw-storage-plus.workspace = true
hex = { version = "0.4.3", default-features = false, features = ["serde"] }
# quartz
quartz-tee-ra.workspace = true
tcbinfo-msgs.workspace = true
# patch indirect deps
getrandom = { version = "0.2.15", features = ["js"] }
[dev-dependencies] [dev-dependencies]
cw-multi-test = "2.0.0" cw-multi-test = "2.0.0"

View file

@ -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

View file

@ -21,5 +21,5 @@ pub enum QueryMsg {
#[cw_serde] #[cw_serde]
pub struct GetTcbInfoResponse { pub struct GetTcbInfoResponse {
pub tcb_info: serde_json::Value, pub tcb_info: String,
} }

View file

@ -1,5 +1,5 @@
use cosmwasm_schema::write_api; use cosmwasm_schema::write_api;
use tcbinfo::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; use tcbinfo_msgs::{ExecuteMsg, InstantiateMsg, QueryMsg};
fn main() { fn main() {
write_api! { write_api! {

View file

@ -1,19 +1,17 @@
#[cfg(not(feature = "library"))] #[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point; use cosmwasm_std::entry_point;
use cosmwasm_std::{ use cosmwasm_std::{to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult};
to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError, StdResult,
};
use cw2::set_contract_version; use cw2::set_contract_version;
use der::{DateTime, DecodePem}; use der::{DateTime, DecodePem};
use mc_attestation_verifier::{CertificateChainVerifier, SignedTcbInfo}; use mc_attestation_verifier::{CertificateChainVerifier, SignedTcbInfo};
use p256::ecdsa::VerifyingKey; use p256::ecdsa::VerifyingKey;
use quartz_tee_ra::intel_sgx::dcap::certificate_chain::TlsCertificateChainVerifier; use quartz_tee_ra::intel_sgx::dcap::certificate_chain::TlsCertificateChainVerifier;
use serde_json::Value; use serde_json::Value;
use tcbinfo_msgs::{ExecuteMsg, GetTcbInfoResponse, InstantiateMsg, QueryMsg};
use x509_cert::Certificate; use x509_cert::Certificate;
use crate::{ use crate::{
error::ContractError, error::ContractError,
msg::{ExecuteMsg, GetTcbInfoResponse, InstantiateMsg, QueryMsg},
state::{TcbInfo, DATABASE, ROOT_CERTIFICATE}, state::{TcbInfo, DATABASE, ROOT_CERTIFICATE},
}; };
// version info for migration info // version info for migration info
@ -147,11 +145,8 @@ pub mod query {
.try_into() .try_into()
.expect("invalid fmspc"); .expect("invalid fmspc");
let tcb_info = DATABASE.load(deps.storage, key)?; 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 { Ok(GetTcbInfoResponse {
tcb_info: tcb_info_response, tcb_info: tcb_info.info,
}) })
} }
} }
@ -160,7 +155,7 @@ pub mod query {
mod tests { mod tests {
use cosmwasm_std::{ use cosmwasm_std::{
coins, coins,
testing::{mock_dependencies, mock_env, mock_info}, testing::{message_info, mock_dependencies, mock_env},
}; };
use super::*; use super::*;
@ -172,7 +167,10 @@ mod tests {
#[test] #[test]
fn verify_init_and_exec() { fn verify_init_and_exec() {
let time = "2024-07-11T15:19:13Z"; 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 { let init_msg = InstantiateMsg {
root_cert: ROOT_CA.to_string(), root_cert: ROOT_CA.to_string(),
}; };
@ -185,7 +183,7 @@ mod tests {
certificate: TCB_SIGNER.to_string(), certificate: TCB_SIGNER.to_string(),
time: Some(time.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); let exec = execute(deps.as_mut(), mock_env(), info, exec_msg);
assert!(exec.is_ok()); assert!(exec.is_ok());
let query = query( let query = query(

View file

@ -4,8 +4,7 @@ use cosmwasm_std::{
}; };
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tcbinfo_msgs::{ExecuteMsg, GetTcbInfoResponse, QueryMsg};
use crate::msg::{ExecuteMsg, GetTcbInfoResponse, QueryMsg};
const FMSPC: &str = "00606a000000"; const FMSPC: &str = "00606a000000";

View file

@ -2,8 +2,9 @@
mod tests { mod tests {
use cosmwasm_std::{testing::MockApi, Addr, Coin, Empty, Uint128}; use cosmwasm_std::{testing::MockApi, Addr, Coin, Empty, Uint128};
use cw_multi_test::{App, AppBuilder, Contract, ContractWrapper, Executor}; 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<dyn Contract<Empty>> { pub fn contract_template() -> Box<dyn Contract<Empty>> {
let contract = ContractWrapper::new( let contract = ContractWrapper::new(
@ -67,8 +68,9 @@ mod tests {
} }
mod add_tcbinfo { mod add_tcbinfo {
use tcbinfo_msgs::ExecuteMsg;
use super::*; use super::*;
use crate::msg::ExecuteMsg;
#[test] #[test]
fn add_tcbinfo() { fn add_tcbinfo() {

View file

@ -2,6 +2,5 @@ pub mod contract;
mod error; mod error;
pub mod helpers; pub mod helpers;
pub mod integration_tests; pub mod integration_tests;
pub mod msg;
pub mod state; pub mod state;
pub use crate::error::ContractError; pub use crate::error::ContractError;

View file

@ -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

View file

@ -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, &quote, 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"]);
}