From 1b35428edcf4aa53e53d8d73c954cd6b4eeb11f8 Mon Sep 17 00:00:00 2001 From: Hendrik Eeckhaut Date: Wed, 2 Apr 2025 15:31:21 +0200 Subject: [PATCH] Basic quote verification in Rust --- intel-tee-quote-verification-docker/readme.md | 16 - quote_verification/.gitignore | 1 + quote_verification/Cargo.lock | 718 ++++++++++++++++++ quote_verification/Cargo.toml | 12 + quote_verification/readme.md | 13 + quote_verification/src/main.rs | 185 +++++ readme.md | 17 + 7 files changed, 946 insertions(+), 16 deletions(-) create mode 100644 quote_verification/.gitignore create mode 100644 quote_verification/Cargo.lock create mode 100644 quote_verification/Cargo.toml create mode 100644 quote_verification/readme.md create mode 100644 quote_verification/src/main.rs create mode 100644 readme.md diff --git a/intel-tee-quote-verification-docker/readme.md b/intel-tee-quote-verification-docker/readme.md index dc1fcfe..d96b7a3 100644 --- a/intel-tee-quote-verification-docker/readme.md +++ b/intel-tee-quote-verification-docker/readme.md @@ -6,22 +6,6 @@ This repository contains code to verify SGX quotes for TLSNotary notary servers This Rust program leverages Intel's `tee-quote-verification` library to automatically fetch and validate Intel's certificates. Since this library is only supported on Linux systems, we use Docker to handle dependencies and ensure compatibility. -## Getting the Quote - -To retrieve the SGX quote from a notary server: - -1. Visit the info page of the notary server. -2. Copy the `rawQuote` field. -3. Decode the hex-encoded quote. - -You can perform these steps in a single command: - -```sh -curl https://notary.pse.dev/v0.1.0-alpha.9/info | jq -r '.quote.rawQuote' | xxd -r -p > quote.dat -``` - -This command fetches the `rawQuote`, decodes it from hex, and saves it as `quote.dat`. - ## Verifying the Quote The binary has native library dependencies. To simplify running the quote verifier, it can be built and executed within a Docker container. diff --git a/quote_verification/.gitignore b/quote_verification/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/quote_verification/.gitignore @@ -0,0 +1 @@ +/target diff --git a/quote_verification/Cargo.lock b/quote_verification/Cargo.lock new file mode 100644 index 0000000..cb8d735 --- /dev/null +++ b/quote_verification/Cargo.lock @@ -0,0 +1,718 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "asn1-rs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom 7.1.3", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "data-encoding" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom 7.1.3", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if", + "ryu", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "5.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b" +dependencies = [ + "lexical-core", + "memchr", + "version_check", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "pem" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" +dependencies = [ + "base64", + "serde", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "quote_test" +version = "0.1.0" +dependencies = [ + "hex", + "p256", + "pem", + "sgx-quote", + "sha2", + "x509-parser", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom 7.1.3", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sgx-quote" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1640577af7b81d10db340c4b31006b77972e3918f351eec4e65c389c8b58e21" +dependencies = [ + "nom 5.1.3", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "x509-parser" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom 7.1.3", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/quote_verification/Cargo.toml b/quote_verification/Cargo.toml new file mode 100644 index 0000000..2e5adfd --- /dev/null +++ b/quote_verification/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "quote_test" +version = "0.1.0" +edition = "2024" + +[dependencies] +hex = "0.4.3" +sgx-quote = "0.1.0" +sha2 = "0.10.8" +p256 = { version = "0.13", features = ["ecdsa"] } +x509-parser = "0.17.0" +pem = "3.0.5" diff --git a/quote_verification/readme.md b/quote_verification/readme.md new file mode 100644 index 0000000..ca34a8e --- /dev/null +++ b/quote_verification/readme.md @@ -0,0 +1,13 @@ +# SGX Quote Verification + +This repository contains code to verify SGX quotes for TLSNotary notary servers running in Intel SGX Trusted Execution Environments (TEEs). + +## Overview + +This Rust program parses the quote, prints the certificate chain and checks the signatures + +## Verifying the Quote + +```bash +cargo run -- ../test-input/quote_9.dat +``` \ No newline at end of file diff --git a/quote_verification/src/main.rs b/quote_verification/src/main.rs new file mode 100644 index 0000000..4d1267a --- /dev/null +++ b/quote_verification/src/main.rs @@ -0,0 +1,185 @@ +use p256::ecdsa::signature::Verifier; +use p256::ecdsa::{Signature as P256Signature, VerifyingKey}; +use pem::parse_many; +use sgx_quote::{Quote, Signature}; +use std::env; + +use sha2::{Digest, Sha256}; +use x509_parser::parse_x509_certificate; +use x509_parser::prelude::{FromDer, X509Certificate}; + +use x509_parser::extensions::ParsedExtension; + +fn main() { + let args: Vec = env::args().collect(); + if args.len() != 2 { + eprintln!("Usage: {} ", args[0]); + std::process::exit(1); + } + + let quote_path = &args[1]; + let quote_bytes = std::fs::read(quote_path).expect("Failed to read quote file"); + + let quote = Quote::parse("e_bytes).expect("Failed to parse quote file"); + + println!("== Quote Info =="); + println!("Version: {:?}", quote.header.version); + println!("MRENCLAVE: {}", hex::encode(quote.isv_report.mrenclave)); + println!("MRSIGNER : {}", hex::encode(quote.isv_report.mrsigner)); + println!("ISV_PROD_ID: {}", quote.isv_report.isv_prod_id); + println!("ISV_SVN : {}", u16::from_le(quote.isv_report.isv_svn)); + + match "e.signature { + Signature::EcdsaP256 { + attestation_key, + isv_report_signature, + qe_certification_data, + qe_report, + qe_report_signature, + .. + } => { + println!( + "ECDSA Attestation Key (pubkey): {}", + hex::encode(attestation_key) + ); + + if let sgx_quote::QeCertificationData::CertChain(cert_chain_bytes) = + qe_certification_data + { + let pems = parse_many(cert_chain_bytes).expect("Failed to parse PEM blocks"); + + for (i, pem_block) in pems.iter().enumerate() { + println!("\n=== Certificate {} ===", i + 1); + + if pem_block.tag() != "CERTIFICATE" { + println!("Skipping non-certificate block: {}", pem_block.tag()); + continue; + } + + match X509Certificate::from_der(pem_block.contents()) { + Ok((_, cert)) => { + println!("Subject: {}", cert.subject()); + println!("Issuer : {}", cert.issuer()); + println!( + "Valid : {} to {}", + cert.validity().not_before, + cert.validity().not_after + ); + println!("Serial : {:x}", cert.serial); + } + Err(e) => { + println!("Failed to parse certificate: {:?}", e); + } + } + } + + let certs: Vec> = pems + .iter() + .map(|pem| parse_x509_certificate(pem.contents()).unwrap().1) + .collect(); + for i in 0..certs.len() - 1 { + assert_eq!( + certs[i].tbs_certificate.issuer, + certs[i + 1].tbs_certificate.subject + ); + } + for ext in certs[0].extensions() { + println!("Custom OID: {}", &ext.oid); + // println!("Value: {}", hex::encode(&ext.value)); + println!("Critical: {}", &ext.critical); + if let ParsedExtension::UnsupportedExtension { oid } = &ext.parsed_extension() { + println!("Custom OID: {}", oid); + } + } + + //http://www.certificate.fyicenter.com/6827_Intel_SGX_Root_CA_Certificate-22650CD65A9D3489F383B49552BF501B392706AC.html + + //compare + let spki = certs[0].public_key(); + let pubkey_bytes = spki.subject_public_key.data.clone(); + + let _cert_vk = match VerifyingKey::from_sec1_bytes(pubkey_bytes.as_ref()) { + Ok(vk) => vk, + Err(_) => { + println!("Failed to parse cert public key as P-256"); + return; + } + }; + + // Pull attestation key from quote + let _quote_vk = match "e.signature { + Signature::EcdsaP256 { + attestation_key, .. + } => { + let mut sec1 = [0u8; 65]; + sec1[0] = 0x04; // uncompressed point prefix + sec1[1..].copy_from_slice(attestation_key); + VerifyingKey::from_sec1_bytes(&sec1).unwrap() + } + }; + + println!("QE"); + + // println!("Cert public key: {:?}", cert_vk.to_encoded_point(false)); + // println!("Quote key : {:?}", quote_vk.to_encoded_point(false)); + + //////////// + // 1. Check that QE report data matches hash(attestation_key) + let mut hasher = Sha256::new(); + hasher.update(attestation_key); + let hash = hasher.finalize(); + + assert_eq!(attestation_key.len(), 64); // This should pass + println!( + "Hash of attestation key: {} ({})", + hex::encode(hash), + attestation_key.len() + ); + println!( + "QE report data: {}", + hex::encode(&qe_report.report_data[..32]) + ); + + // Build full SEC1-encoded pubkey (0x04 || X || Y) + let mut sec1 = [0u8; 65]; + sec1[0] = 0x04; + sec1[1..].copy_from_slice(attestation_key); + let hash = Sha256::digest(sec1); + println!("Expected hash: {}", hex::encode(hash)); + + // 2. Extract cert public key + let spki = certs[0].public_key(); + let pubkey_bytes = spki.subject_public_key.data.clone(); + let cert_vk = VerifyingKey::from_sec1_bytes(pubkey_bytes.as_ref()).unwrap(); + let qe_report_sig = P256Signature::from_slice(qe_report_signature).unwrap(); + + // Use the `report_data` as the message that was signed by the cert + cert_vk + .verify(qe_report.signed_message(), &qe_report_sig) + .unwrap(); + println!("✅ QE report signature is valid!"); + + // Now build uncompressed SEC1-encoded point: 0x04 || X || Y and parse into a VerifyingKey + let mut sec1 = [0u8; 65]; + sec1[0] = 0x04; + sec1[1..].copy_from_slice(attestation_key); + // println!("Pubkey SEC1: {}", hex::encode(sec1)); + let pubkey = VerifyingKey::from_sec1_bytes(&sec1).unwrap(); + println!("Attestation pubkey: {:?}", &pubkey); + + // ISV + + let signature = P256Signature::from_slice(isv_report_signature).unwrap(); + println!("signature: {:?}", &signature); + + // Step 6: Verify the signature + pubkey.verify(quote.signed_message(), &signature).unwrap(); + + println!("✅ ECDSA signature is valid!"); + // qe_report_signature + } else { + println!("qe_certification_data is not a CertChain"); + } + } + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..671cd62 --- /dev/null +++ b/readme.md @@ -0,0 +1,17 @@ +This repository contains two approaches to verify SGX quotes from TLSNotary notary servers running in Intel SGX Trusted Execution Environments (TEEs): +1. `intel-tee-quote-verification-docker`: Uses Intel's `tee-quote-verification` library (uses Docker to handle the native dependencies) +2. `quote_verification`: Native Rust to parse and verify the quote + +## Getting the Quote + +To retrieve the SGX quote from a notary server: + +1. Visit the info page of the notary server. +2. Copy the `rawQuote` field. +3. Decode the hex-encoded quote. + +You can perform these steps in a single command: + +```sh +curl https://notary.pse.dev/v0.1.0-alpha.9/info | jq -r '.quote.rawQuote' | xxd -r -p > quote.dat +```