diff --git a/Cargo.bazel.lock b/Cargo.bazel.lock index 671cea3978b..b4af7c2ec3e 100644 --- a/Cargo.bazel.lock +++ b/Cargo.bazel.lock @@ -230,6 +230,7 @@ dependencies = [ "prost", "prost-build", "rand_core", + "regex", "rsa", "serde", "serde_json", diff --git a/Cargo.lock b/Cargo.lock index 27e5b69d129..39d18cf3d01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,9 +426,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "camino" @@ -701,18 +701,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.104.1" +version = "0.105.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "7e7c0d51205b863591dd1e7aaa0fb69c2ea7bed48ffa63d6c4a848b07a35a732" +checksum = "16d5521e2abca66bbb1ddeecbb6f6965c79160352ae1579b39f8c86183895c24" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.104.1" +version = "0.105.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "9ffb467cbc25543e4c20d2ad669bf8275598047b03c89652ad5fe2a0f47fc0e1" +checksum = "ef40a4338a47506e832ac3e53f7f1375bc59351f049a8379ff736dd02565bd95" dependencies = [ "bumpalo", "cranelift-bforest", @@ -731,33 +731,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.104.1" +version = "0.105.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "bc7e74aed5c2b91e38d090653506afbd2cd3be1ff70593e2aa6bb82b3c6b77ff" +checksum = "d24cd5d85985c070f73dfca07521d09086362d1590105ba44b0932bf33513b61" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.104.1" +version = "0.105.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "9ff2dd24cce0775566da85770cb48aa58fef901cf2bff30275b42e7dbe62cbd5" +checksum = "e0584c4363e3aa0a3c7cb98a778fbd5326a3709f117849a727da081d4051726c" [[package]] name = "cranelift-control" -version = "0.104.1" +version = "0.105.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "e8bcf4d5c73bbca309edf3af2839b5218e5c74cfbf22b0ac492af8a1d11120d9" +checksum = "f25ecede098c6553fdba362a8e4c9ecb8d40138363bff47f9712db75be7f0571" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.104.1" +version = "0.105.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "286754159b1a685475d6a0b4710832f950d6f4846a817002e2c23ff001321a65" +checksum = "6ea081a42f25dc4c5b248b87efdd87dcd3842a1050a37524ec5391e6172058cb" dependencies = [ "serde", "serde_derive", @@ -765,9 +765,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.104.1" +version = "0.105.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "67150a1fef9857caba710f8c0c8223d640f02c0e5d1ebbfc75ed62912599cb6b" +checksum = "9796e712f5af797e247784f7518e6b0a83a8907d73d51526982d86ecb3a58b68" dependencies = [ "cranelift-codegen", "log", @@ -777,15 +777,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.104.1" +version = "0.105.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "eb7ceea70d3e0d7f69df7657f99de902e32016731c5a8d2788c1df0215f00952" +checksum = "f4a66ccad5782f15c80e9dd5af0df4acfe6e3eee98e8f7354a2e5c8ec3104bdd" [[package]] name = "cranelift-native" -version = "0.104.1" +version = "0.105.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "707e5d9384ce4fa3c40af1abf4c3ec49857745cced5187593385f4a2c0b95445" +checksum = "285e80df1d9b79ded9775b285df68b920a277b84f88a7228d2f5bc31fcdc58eb" dependencies = [ "cranelift-codegen", "libc", @@ -794,9 +794,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.104.1" +version = "0.105.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "d4d957e3ff2a14c2f974a66c22bfcedcd2bd0272af8dce4236869c3942f5a471" +checksum = "4135b0ab01fd16aa8f8821196e9e2fe15953552ccaef8ba5153be0ced04ef757" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -1169,6 +1169,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + [[package]] name = "env_filter" version = "0.1.0" @@ -2323,6 +2332,7 @@ dependencies = [ "p256", "p384", "prost", + "regex", "rsa", "serde", "serde_json", @@ -5171,15 +5181,6 @@ version = "0.2.90" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" -[[package]] -name = "wasm-encoder" -version = "0.38.1" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f" -dependencies = [ - "leb128", -] - [[package]] name = "wasm-encoder" version = "0.41.1" @@ -5222,10 +5223,11 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.118.1" +version = "0.121.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9" +checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" dependencies = [ + "bitflags 2.4.1", "indexmap 2.1.0", "semver", ] @@ -5239,56 +5241,74 @@ dependencies = [ "indexmap-nostd", ] +[[package]] +name = "wasmprinter" +version = "0.2.80" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "60e73986a6b7fdfedb7c5bf9e7eb71135486507c8fbc4c0c42cffcb6532988b7" +dependencies = [ + "anyhow", + "wasmparser", +] + [[package]] name = "wasmtime" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "8acb6aa966be38f613954c3debe7ba6c7a02ffd0537432be438da0b038955cdf" +checksum = "8106d7d22d63d1bcb940e22dcc7b03e46f0fc8bfbaf2fd7b6cb8f448f9449774" dependencies = [ + "addr2line", "anyhow", "async-trait", "bincode", "bumpalo", "cfg-if", + "encoding_rs", "fxprof-processed-profile", + "gimli", "indexmap 2.1.0", + "ittapi", "libc", "log", "object", "once_cell", "paste", "rayon", + "rustix", "serde", "serde_derive", "serde_json", "target-lexicon", - "wasm-encoder 0.38.1", + "wasm-encoder", "wasmparser", "wasmtime-cache", "wasmtime-component-macro", + "wasmtime-component-util", "wasmtime-cranelift", "wasmtime-environ", "wasmtime-fiber", - "wasmtime-jit", + "wasmtime-jit-debug", + "wasmtime-jit-icache-coherence", "wasmtime-runtime", + "wasmtime-winch", "wat", "windows-sys 0.52.0", ] [[package]] name = "wasmtime-asm-macros" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "c1495ef4d46aec14f967b672e946e391dd8a14a443cda3d5e0779ff67fb6e28d" +checksum = "3b0cf02cea951ace34ee3b0e64b7f446c3519d1c95ad75bc5330f405e275ee8f" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "e2de1b065bdbaca3df9e7e9f70eb129e326a99d971b16d666acd798d98d47635" +checksum = "3249204a71d728d53fb3eea18afd0473f87e520445707a4d567ac4da0bb3eb5d" dependencies = [ "anyhow", "base64 0.21.7", @@ -5306,9 +5326,9 @@ dependencies = [ [[package]] name = "wasmtime-component-macro" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "2f19bcff82f81ba0273c0b68f3909977b0dd54489bc86c630d8aad43dca92f3f" +checksum = "7d3786c0531565ec6c9852c0e46299f06cb6e4b58d36e30f3c234cfa69bde376" dependencies = [ "anyhow", "proc-macro2", @@ -5321,15 +5341,15 @@ dependencies = [ [[package]] name = "wasmtime-component-util" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "8af072b7ad5ac5583e1f9e4737ebf88923de564fb5d4ace0ca9b4b720bdf95a1" +checksum = "81eae2ec98027ee0b3950da83bc320120a23087ac4d39b3d59201cb5ebf52777" [[package]] name = "wasmtime-cranelift" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "df08a8bd9a68732577bee05ac685e4c247238b5e79ad9c062e2dfb4d04dca132" +checksum = "595abdb067acdc812ab0f21d8d46d5aa4022392aa7c3e0632c20bff9ec49ffb4" dependencies = [ "anyhow", "cfg-if", @@ -5352,9 +5372,9 @@ dependencies = [ [[package]] name = "wasmtime-cranelift-shared" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "404201c9e669083f189f01337b3ed0aa0eb081157fb4e170bbfe193df9497771" +checksum = "e8c24c1fdea167b992d82ebe76471fd1cbe7b0b406bc72f9250f86353000134e" dependencies = [ "anyhow", "cranelift-codegen", @@ -5368,29 +5388,35 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "7e696b4911c9a69c3c2892ec05eb41bb15436d1a46d8830a755c40f5df47546a" +checksum = "3279d510005358141550d8a90a5fc989d7e81748e5759d582fe6bfdcbf074a04" dependencies = [ "anyhow", + "bincode", + "cpp_demangle 0.3.5", "cranelift-entity", "gimli", "indexmap 2.1.0", "log", "object", + "rustc-demangle", "serde", "serde_derive", "target-lexicon", "thiserror", + "wasm-encoder", "wasmparser", + "wasmprinter", + "wasmtime-component-util", "wasmtime-types", ] [[package]] name = "wasmtime-fiber" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "4a39681c1f6f54d1bf7efe5dc829f8d7fc0e2ca12c346fd7a3efbf726e9681d2" +checksum = "9b1df665f2117741d1265f5663b0d93068b18120c2c4b18b9faed49d00d92c31" dependencies = [ "anyhow", "cc", @@ -5401,38 +5427,11 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "wasmtime-jit" -version = "17.0.1" -source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "2c56519882d936c680bd191d58ac04cff071a470eca2dcc664adcd60f986a731" -dependencies = [ - "addr2line", - "anyhow", - "bincode", - "cfg-if", - "cpp_demangle 0.3.5", - "gimli", - "ittapi", - "log", - "object", - "rustc-demangle", - "rustix", - "serde", - "serde_derive", - "target-lexicon", - "wasmtime-environ", - "wasmtime-jit-debug", - "wasmtime-jit-icache-coherence", - "wasmtime-runtime", - "windows-sys 0.52.0", -] - [[package]] name = "wasmtime-jit-debug" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "babc65e64ab0dd4e1ce65624db64e24ed0fbdebb16148729173fa0da9f70e53c" +checksum = "63f307739370736e5b0cd2b45910ff96bcda6d5d68b2c4384bcedb0af4f3b321" dependencies = [ "object", "once_cell", @@ -5442,9 +5441,9 @@ dependencies = [ [[package]] name = "wasmtime-jit-icache-coherence" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "d7ec5b11c12d9acb09612e7ce04c4c8aea3e8dc79b2591ffdead986a5ce8ec49" +checksum = "866634605089b4632b32226b54aa3670d72e1849f9fc425c7e50b3749c2e6df3" dependencies = [ "cfg-if", "libc", @@ -5453,13 +5452,14 @@ dependencies = [ [[package]] name = "wasmtime-runtime" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "28e1c31bbdf67cb86f149bcead5193749f23f77c93c5244ec9ac8d192f90966c" +checksum = "e11185c88cadf595d228f5ae4ff9b4badbf9ca98dcb37b0310c36e31fa74867f" dependencies = [ "anyhow", "cc", "cfg-if", + "encoding_rs", "indexmap 2.1.0", "libc", "log", @@ -5470,7 +5470,7 @@ dependencies = [ "psm", "rustix", "sptr", - "wasm-encoder 0.38.1", + "wasm-encoder", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-fiber", @@ -5482,9 +5482,9 @@ dependencies = [ [[package]] name = "wasmtime-types" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "52e799cff634d30fd042db96b417d515e54f903b95f8c1e0ec60e8f604479485" +checksum = "f32377cbd827bee06fcb2f6bf97b0477fdcc86888bbe6db7b9cab8e644082e0a" dependencies = [ "cranelift-entity", "serde", @@ -5495,20 +5495,37 @@ dependencies = [ [[package]] name = "wasmtime-versioned-export-macros" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "e10fe166d4e4c95d5d80c5b47e1e12256af2099ac525ddb9a19b1aeb8896e5e1" +checksum = "4ab8d7566d206c42f8cf1d4ac90c5e40d3582e8eabad9b3b67e9e73c61fc47a1" dependencies = [ "proc-macro2", "quote", "syn 2.0.48", ] +[[package]] +name = "wasmtime-winch" +version = "18.0.3" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "ba5a97bfccc241d1769cef75eb16f472a893982704d5f3c9c71c431c1484344a" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "object", + "target-lexicon", + "wasmparser", + "wasmtime-cranelift-shared", + "wasmtime-environ", + "winch-codegen", +] + [[package]] name = "wasmtime-wit-bindgen" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "6bb3bc92c031cf4961135bffe055a69c1bd67c253dca20631478189bb05ec27b" +checksum = "faf2c76781a27e07802669f6f0e11eb4441546407eb65be60c3d862200988b92" dependencies = [ "anyhow", "heck", @@ -5518,9 +5535,9 @@ dependencies = [ [[package]] name = "wasmtime-wmemcheck" -version = "17.0.1" +version = "18.0.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" -checksum = "5da08ab734954e16f57be38423b90c25a0b13420e51cbd0a2e37b86a468a988c" +checksum = "3847d969bd203b8cd239f89581e52432a0f00b8c5c9bc917be2fccd7542c4f2f" [[package]] name = "wast" @@ -5532,7 +5549,7 @@ dependencies = [ "leb128", "memchr", "unicode-width", - "wasm-encoder 0.41.1", + "wasm-encoder", ] [[package]] @@ -5610,6 +5627,22 @@ version = "0.4.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winch-codegen" +version = "0.16.3" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "1e0bd4d6cac8d69525d475d0ce1e0801eb6f314d42e764a52bd497ed3cb9c371" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "regalloc2", + "smallvec", + "target-lexicon", + "wasmparser", + "wasmtime-environ", +] + [[package]] name = "windows-core" version = "0.52.0" diff --git a/FORCE_CI b/FORCE_CI index f04c001f3f7..64bb6b746dc 100644 --- a/FORCE_CI +++ b/FORCE_CI @@ -1 +1 @@ -29 +30 diff --git a/WORKSPACE b/WORKSPACE index ae09e3053a7..5bfc7531b22 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -183,6 +183,20 @@ load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_depende # https://bazelbuild.github.io/rules_foreign_cc/0.9.0/flatten.html#rules_foreign_cc_dependencies rules_foreign_cc_dependencies() +http_archive( + name = "rules_kotlin", + sha256 = "d9898c3250e0442436eeabde4e194c30d6c76a4a97f517b18cefdfd4e345725a", + url = "/~https://github.com/bazelbuild/rules_kotlin/releases/download/v1.9.1/rules_kotlin-v1.9.1.tar.gz", +) + +load("@rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories") + +kotlin_repositories() # if you want the default. Otherwise see custom kotlinc distribution below + +load("@rules_kotlin//kotlin:core.bzl", "kt_register_toolchains") + +kt_register_toolchains() # to use the default toolchain, otherwise see toolchains below + # C++ CBOR support. # https://android.googlesource.com/platform/external/libcppbor git_repository( @@ -285,7 +299,6 @@ rules_rust_dependencies() rust_register_toolchains( edition = "2021", versions = [ - # TODO(b/309612743) Can we automatically sync this with flake.nix? "1.76.0", "nightly/2023-11-15", ], @@ -378,6 +391,10 @@ crates_repository( features = ["getrandom"], version = "*", ), + "regex": crate.spec( + default_features = False, + version = "*", + ), "rsa": crate.spec( default_features = False, version = "0.9.6", diff --git a/cargo-bazel-lock.json b/cargo-bazel-lock.json index 9b6a030453b..746bf3b64ed 100644 --- a/cargo-bazel-lock.json +++ b/cargo-bazel-lock.json @@ -1,5 +1,5 @@ { - "checksum": "20905ca77634d11a6071cbe711d2fd7f7a7688bca9c5a4a45e7149bd539b060e", + "checksum": "ea906083db334fa545e6bddd74c9c9271f2cb3802f30aaed50f7eec83bedadb5", "crates": { "aho-corasick 1.1.2": { "name": "aho-corasick", @@ -1420,6 +1420,10 @@ "id": "rand_core 0.6.4", "target": "rand_core" }, + { + "id": "regex 1.10.3", + "target": "regex" + }, { "id": "rsa 0.9.6", "target": "rsa" @@ -7395,6 +7399,7 @@ "prost 0.12.3", "prost-build 0.12.3", "rand_core 0.6.4", + "regex 1.10.3", "rsa 0.9.6", "serde 1.0.197", "serde_json 1.0.114", diff --git a/cc/containers/sdk/encryption_key_handle.cc b/cc/containers/sdk/encryption_key_handle.cc index c28c5ffbeb9..3e6328a2bbe 100644 --- a/cc/containers/sdk/encryption_key_handle.cc +++ b/cc/containers/sdk/encryption_key_handle.cc @@ -44,4 +44,16 @@ InstanceEncryptionKeyHandle::GenerateRecipientContext( return RecipientContext::Deserialize(*session_keys); } +absl::StatusOr> +GroupEncryptionKeyHandle::GenerateRecipientContext( + absl::string_view serialized_encapsulated_public_key) { + absl::StatusOr session_keys = orchestrator_crypto_client_.DeriveSessionKeys( + KeyOrigin::GROUP, serialized_encapsulated_public_key); + if (!session_keys.ok()) { + return absl::InternalError("couldn't derive session keys"); + } + + return RecipientContext::Deserialize(*session_keys); +} + } // namespace oak::containers::sdk diff --git a/cc/containers/sdk/encryption_key_handle.h b/cc/containers/sdk/encryption_key_handle.h index a2513324c66..58ceabe89ef 100644 --- a/cc/containers/sdk/encryption_key_handle.h +++ b/cc/containers/sdk/encryption_key_handle.h @@ -37,6 +37,15 @@ class InstanceEncryptionKeyHandle : public ::oak::crypto::EncryptionKeyHandle { OrchestratorCryptoClient orchestrator_crypto_client_; }; +class GroupEncryptionKeyHandle : public ::oak::crypto::EncryptionKeyHandle { + public: + absl::StatusOr> GenerateRecipientContext( + absl::string_view serialized_encapsulated_public_key) override; + + private: + OrchestratorCryptoClient orchestrator_crypto_client_; +}; + } // namespace oak::containers::sdk #endif // THIRD_PARTY_OAK_CC_CONTAINERS_ENCRYPTION_KEY_HANDLE_H_ diff --git a/cc/transport/BUILD b/cc/transport/BUILD index 5f3b8eeb122..ce75129f9bc 100644 --- a/cc/transport/BUILD +++ b/cc/transport/BUILD @@ -36,6 +36,7 @@ cc_library( hdrs = ["grpc_streaming_transport.h"], deps = [ ":transport", + ":util", "//proto/crypto:crypto_cc_proto", "//proto/session:messages_cc_proto", "//proto/session:service_streaming_cc_grpc", @@ -48,6 +49,34 @@ cc_library( ], ) +cc_library( + name = "grpc_unary_transport", + hdrs = ["grpc_unary_transport.h"], + deps = [ + ":transport", + ":util", + "//proto/crypto:crypto_cc_proto", + "//proto/session:messages_cc_proto", + "//proto/session:service_unary_cc_grpc", + "//proto/session:service_unary_cc_proto", + "@com_github_grpc_grpc//:grpc++", + "@com_google_absl//absl/log", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + ], +) + +cc_library( + name = "util", + srcs = ["util.cc"], + hdrs = ["util.h"], + deps = [ + "@com_github_grpc_grpc//:grpc++", + "@com_google_absl//absl/status", + ], +) + cc_test( name = "grpc_streaming_transport_test", srcs = ["grpc_streaming_transport_test.cc"], @@ -64,3 +93,20 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "grpc_unary_transport_test", + srcs = ["grpc_unary_transport_test.cc"], + deps = [ + ":grpc_unary_transport", + "//proto/crypto:crypto_cc_proto", + "//proto/session:messages_cc_proto", + "//proto/session:service_unary_cc_grpc", + "//proto/session:service_unary_cc_proto", + "@com_github_grpc_grpc//:grpc++", + "@com_google_absl//absl/log", + "@com_google_absl//absl/log:absl_check", + "@com_google_absl//absl/status", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/cc/transport/grpc_streaming_transport.cc b/cc/transport/grpc_streaming_transport.cc index 4ae85dd7355..23d5e4f1d7e 100644 --- a/cc/transport/grpc_streaming_transport.cc +++ b/cc/transport/grpc_streaming_transport.cc @@ -23,6 +23,7 @@ #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +#include "cc/transport/util.h" #include "grpcpp/channel.h" #include "grpcpp/client_context.h" #include "grpcpp/create_channel.h" @@ -32,19 +33,12 @@ namespace oak::transport { -namespace { using ::oak::crypto::v1::EncryptedRequest; using ::oak::crypto::v1::EncryptedResponse; using ::oak::session::v1::EndorsedEvidence; using ::oak::session::v1::GetEndorsedEvidenceRequest; using ::oak::session::v1::RequestWrapper; using ::oak::session::v1::ResponseWrapper; -} // namespace - -absl::Status to_absl_status(const grpc::Status& grpc_status) { - return absl::Status(static_cast(grpc_status.error_code()), - grpc_status.error_message()); -} absl::StatusOr GrpcStreamingTransport::GetEndorsedEvidence() { // Create request. diff --git a/cc/transport/grpc_unary_transport.h b/cc/transport/grpc_unary_transport.h new file mode 100644 index 00000000000..6e614b49352 --- /dev/null +++ b/cc/transport/grpc_unary_transport.h @@ -0,0 +1,83 @@ +/* + * Copyright 2023 The Project Oak Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CC_TRANSPORT_GRPC_UNARY_TRANSPORT_H_ +#define CC_TRANSPORT_GRPC_UNARY_TRANSPORT_H_ + +#include "absl/log/log.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "cc/transport/transport.h" +#include "cc/transport/util.h" +#include "grpcpp/client_context.h" +#include "proto/crypto/crypto.pb.h" +#include "proto/session/messages.pb.h" +#include "proto/session/service_unary.pb.h" + +namespace oak::transport { + +// Transport class for communication with unary gRPC Oak service. Evidence +// must be collected from the enclave and verified prior to issuing any data +// requests. This template class can be used to communicate with any unary +// stubby Oak service that use a gRPC interface consistent with +// oak/proto/session/service_unary.proto. +template +class GrpcUnaryTransport : public ::oak::transport::TransportWrapper { + public: + explicit GrpcUnaryTransport(OakBackendStub* const client_stub) : client_stub_(client_stub) {} + + // Collects the enclave's evidence that needs to be verified by the client. + absl::StatusOr<::oak::session::v1::EndorsedEvidence> GetEndorsedEvidence() override { + ::grpc::ClientContext context; + ::oak::session::v1::GetEndorsedEvidenceRequest request; + ::oak::session::v1::GetEndorsedEvidenceResponse response; + + grpc::Status status = client_stub_->GetEndorsedEvidence(&context, request, &response); + if (!status.ok()) { + absl::Status absl_status = to_absl_status(status); + LOG(ERROR) << "Failed to fetch evidence with status: " << absl_status; + return absl_status; + } + + return response.endorsed_evidence(); + } + + // Takes an encrypted request and sends it to the enclave, returning the + // enclave's encrypted response. + absl::StatusOr<::oak::crypto::v1::EncryptedResponse> Invoke( + const ::oak::crypto::v1::EncryptedRequest& encrypted_request) override { + ::grpc::ClientContext context; + ::oak::session::v1::InvokeRequest request; + ::oak::session::v1::InvokeResponse response; + + *request.mutable_encrypted_request() = encrypted_request; + grpc::Status status = client_stub_->Invoke(&context, request, &response); + if (!status.ok()) { + absl::Status absl_status = to_absl_status(status); + LOG(ERROR) << "Failed to call invoke with status: " << absl_status; + return absl_status; + } + + return response.encrypted_response(); + } + + private: + OakBackendStub* client_stub_; +}; + +} // namespace oak::transport + +#endif // CC_TRANSPORT_GRPC_UNARY_TRANSPORT_H_ diff --git a/cc/transport/grpc_unary_transport_test.cc b/cc/transport/grpc_unary_transport_test.cc new file mode 100644 index 00000000000..491e7c1298c --- /dev/null +++ b/cc/transport/grpc_unary_transport_test.cc @@ -0,0 +1,101 @@ +/* + * Copyright 2023 The Project Oak Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cc/transport/grpc_unary_transport.h" + +#include +#include + +#include "absl/status/status.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "proto/crypto/crypto.pb.h" +#include "proto/session/messages.pb.h" +#include "proto/session/service_unary.pb.h" +#include "proto/session/service_unary_mock.grpc.pb.h" + +namespace oak::transport { +namespace { + +using ::oak::crypto::v1::AeadEncryptedMessage; +using ::oak::crypto::v1::EncryptedRequest; +using ::oak::crypto::v1::EncryptedResponse; +using ::oak::session::v1::EndorsedEvidence; +using ::oak::session::v1::GetEndorsedEvidenceRequest; +using ::oak::session::v1::GetEndorsedEvidenceResponse; +using ::oak::session::v1::InvokeRequest; +using ::oak::session::v1::InvokeResponse; +using ::oak::session::v1::MockUnarySessionStub; + +using ::testing::_; +using ::testing::DoAll; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::StrEq; + +TEST(StubbyUnaryTransportTest, KeyRetrievedAndInvokeCalledSuccess) { + auto mock_stub = std::make_unique(); + + // Test the get endorsed evidence method. + GetEndorsedEvidenceRequest empty_request; + GetEndorsedEvidenceResponse evidence_response; + std::string application_key = "001"; + *evidence_response.mutable_endorsed_evidence() + ->mutable_evidence() + ->mutable_application_keys() + ->mutable_encryption_public_key_certificate() = application_key; + + EXPECT_CALL(*mock_stub, GetEndorsedEvidence(_, _, _)) + .WillOnce(DoAll(SetArgPointee<2>(evidence_response), Return(grpc::Status::OK))); + + GrpcUnaryTransport unary_transport(mock_stub.get()); + + auto actual_endorsed_evidence = unary_transport.GetEndorsedEvidence(); + ASSERT_TRUE(actual_endorsed_evidence.ok()); + EXPECT_THAT( + actual_endorsed_evidence->evidence().application_keys().encryption_public_key_certificate(), + StrEq(application_key)); + + // Now we test the invoke method. + + const std::string request_ciphertext = "Some encrypted request."; + AeadEncryptedMessage request_aead_encrypted_message; + request_aead_encrypted_message.set_ciphertext(request_ciphertext); + EncryptedRequest encrypted_request; + *encrypted_request.mutable_encrypted_message() = request_aead_encrypted_message; + InvokeRequest invoke_request; + *invoke_request.mutable_encrypted_request() = encrypted_request; + + const std::string response_ciphertext = "Some encrypted response."; + AeadEncryptedMessage response_aead_encrypted_message; + response_aead_encrypted_message.set_ciphertext(response_ciphertext); + EncryptedResponse encrypted_response; + *encrypted_response.mutable_encrypted_message() = response_aead_encrypted_message; + InvokeResponse invoke_response; + *invoke_response.mutable_encrypted_response() = encrypted_response; + + EXPECT_CALL(*mock_stub, Invoke(_, _, _)) + .WillOnce(DoAll(SetArgPointee<2>(invoke_response), Return(::grpc::Status::OK))); + + auto actual_encrypted_response = unary_transport.Invoke(encrypted_request); + ASSERT_TRUE(actual_encrypted_response.ok()); + + EXPECT_THAT(actual_encrypted_response->encrypted_message().ciphertext(), + StrEq(response_ciphertext)); +} + +} // namespace +} // namespace oak::transport diff --git a/cc/transport/util.cc b/cc/transport/util.cc new file mode 100644 index 00000000000..7924d64cc43 --- /dev/null +++ b/cc/transport/util.cc @@ -0,0 +1,27 @@ +/* + * Copyright 2023 The Project Oak Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "absl/status/status.h" +#include "grpcpp/grpcpp.h" + +namespace oak::transport { + +absl::Status to_absl_status(const grpc::Status& grpc_status) { + return absl::Status(static_cast(grpc_status.error_code()), + grpc_status.error_message()); +} + +} // namespace oak::transport diff --git a/cc/transport/util.h b/cc/transport/util.h new file mode 100644 index 00000000000..c818404ea73 --- /dev/null +++ b/cc/transport/util.h @@ -0,0 +1,31 @@ +/* + * Copyright 2023 The Project Oak Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CC_TRANSPORT_UTIL_H_ +#define CC_TRANSPORT_UTIL_H_ + +#include "absl/status/status.h" +#include "grpcpp/grpcpp.h" + +namespace oak::transport { + +// Converts gRPC status to an absl status. The gRPC error status code is casted and the error +// message is copied. +absl::Status to_absl_status(const grpc::Status& grpc_status); + +} // namespace oak::transport + +#endif // CC_TRANSPORT_UTIL_H_ diff --git a/enclave_apps/oak_orchestrator/src/main.rs b/enclave_apps/oak_orchestrator/src/main.rs index c087dd44000..b9874fa993e 100644 --- a/enclave_apps/oak_orchestrator/src/main.rs +++ b/enclave_apps/oak_orchestrator/src/main.rs @@ -20,13 +20,66 @@ extern crate alloc; +use core::fmt::Write; + use oak_dice::evidence::Stage0DiceData; use oak_restricted_kernel_interface::{syscall, DERIVED_KEY_FD, DICE_DATA_FD}; use oak_restricted_kernel_orchestrator::AttestedApp; -use oak_restricted_kernel_sdk::{channel::FileDescriptorChannel, entrypoint}; +use oak_restricted_kernel_sdk::channel::FileDescriptorChannel; use zerocopy::{AsBytes, FromZeroes}; use zeroize::Zeroize; +struct OrchestratorLogger {} + +impl log::Log for OrchestratorLogger { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + writeln!( + oak_restricted_kernel_sdk::utils::Stderr {}, + "orchestrator {}: {}", + record.level(), + record.args() + ) + .unwrap(); + } + + fn flush(&self) { + oak_restricted_kernel_sdk::utils::Stderr::flush(); + } +} + +#[global_allocator] +static ALLOCATOR: oak_restricted_kernel_sdk::utils::heap::LockedGrowableHeap = + oak_restricted_kernel_sdk::utils::heap::LockedGrowableHeap::empty(); + +static LOGGER: OrchestratorLogger = OrchestratorLogger {}; + +// The orchestrator uses a custom logging implementation, hence the +// #[oak_restricted_kernel_sdk::entrypoint] is not used. The allocator, +// handlers, etc are declared explicitly. +#[no_mangle] +fn _start() -> ! { + oak_restricted_kernel_sdk::utils::log::set_logger(&LOGGER).expect("failed to set logger"); + oak_restricted_kernel_sdk::utils::log::set_max_level( + oak_restricted_kernel_sdk::utils::log::LevelFilter::Debug, + ); + entrypoint() +} + +#[alloc_error_handler] +fn out_of_memory(layout: ::core::alloc::Layout) -> ! { + panic!("error allocating memory in orchestrator: {:#?}", layout); +} + +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + log::error!("orchestrator PANIC: {}", info); + oak_restricted_kernel_interface::syscall::exit(-1); +} + fn read_stage0_dice_data() -> Stage0DiceData { let mut result = Stage0DiceData::new_zeroed(); let buffer = result.as_bytes_mut(); @@ -35,8 +88,7 @@ fn read_stage0_dice_data() -> Stage0DiceData { result } -#[entrypoint] -fn start() -> ! { +fn entrypoint() -> ! { let mut attested_app = { let stage0_dice_data = read_stage0_dice_data(); let channel = FileDescriptorChannel::default(); diff --git a/flake.nix b/flake.nix index 300f0203a70..08707c53b18 100644 --- a/flake.nix +++ b/flake.nix @@ -35,7 +35,17 @@ # Note that building a package via nix is not by itself a guarantee of # reproducibility; see https://reproducible.nixos.org. linux_kernel = pkgs.linuxManualConfig { + # To allow reproducibility, the following options need to be configured: + # - CONFIG_MODULE_SIG is not set + # - CONFIG_MODULE_SIG_ALL is not set + # - CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set configfile = ./oak_containers_kernel/configs/6.1.33/minimal.config; + # And also the following build variables. + # See https://docs.kernel.org/kbuild/reproducible-builds.html. + extraMakeFlags = [ + "KBUILD_BUILD_USER=user" + "KBUILD_BUILD_HOST=host" + ]; version = linux_kernel_version; src = linux_kernel_src; allowImportFromDerivation = true; diff --git a/java/src/main/java/com/google/oak/crypto/BUILD b/java/src/main/java/com/google/oak/crypto/BUILD index 508092089bf..dca11f8a58a 100644 --- a/java/src/main/java/com/google/oak/crypto/BUILD +++ b/java/src/main/java/com/google/oak/crypto/BUILD @@ -15,16 +15,17 @@ # load("@rules_java//java:defs.bzl", "java_library") +load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") package( default_visibility = ["//visibility:public"], licenses = ["notice"], ) -java_library( +kt_jvm_library( name = "decryption_result", srcs = [ - "DecryptionResult.java", + "DecryptionResult.kt", ], ) diff --git a/java/src/main/java/com/google/oak/crypto/DecryptionResult.java b/java/src/main/java/com/google/oak/crypto/DecryptionResult.kt similarity index 66% rename from java/src/main/java/com/google/oak/crypto/DecryptionResult.java rename to java/src/main/java/com/google/oak/crypto/DecryptionResult.kt index 6d0b2d1016c..1a9d7f3c87d 100644 --- a/java/src/main/java/com/google/oak/crypto/DecryptionResult.java +++ b/java/src/main/java/com/google/oak/crypto/DecryptionResult.kt @@ -16,12 +16,12 @@ package com.google.oak.crypto; -public final class DecryptionResult { - public final byte[] plaintext; - public final byte[] associatedData; - - public DecryptionResult(byte[] plaintext, byte[] associatedData) { - this.plaintext = plaintext; - this.associatedData = associatedData; - } -} +class DecryptionResult( + // This is needed because the Java code reference backing fields directly. + // By default, Kotlin properties generate getter/setter methods, and does not + // expose the backing fields directly. + @JvmField + val plaintext: ByteArray, + @JvmField + val associatedData: ByteArray, +) diff --git a/java/src/main/java/com/google/oak/verification/BUILD b/java/src/main/java/com/google/oak/verification/BUILD index bb84d699823..64694317a12 100644 --- a/java/src/main/java/com/google/oak/verification/BUILD +++ b/java/src/main/java/com/google/oak/verification/BUILD @@ -14,7 +14,8 @@ # limitations under the License. # -load("@rules_java//java:defs.bzl", "java_binary", "java_library") +load("@rules_java//java:defs.bzl", "java_binary") +load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") package( default_visibility = ["//visibility:public"], @@ -37,9 +38,12 @@ java_binary( ], ) -java_library( +kt_jvm_library( name = "verification", - srcs = glob(["*.java"]), + srcs = glob([ + "*.java", + "*.kt", + ]), deps = [ "@com_google_code_gson_gson", ], diff --git a/java/src/main/java/com/google/oak/verification/Failure.java b/java/src/main/java/com/google/oak/verification/Failure.kt similarity index 79% rename from java/src/main/java/com/google/oak/verification/Failure.java rename to java/src/main/java/com/google/oak/verification/Failure.kt index 4d71417e23f..063e225d7d9 100644 --- a/java/src/main/java/com/google/oak/verification/Failure.java +++ b/java/src/main/java/com/google/oak/verification/Failure.kt @@ -18,14 +18,4 @@ package com.google.oak.verification; /** Signals verification failure and provides a human-readable cause. */ -public class Failure { - public Failure(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - - private final String message; -} +data class Failure(val message: String) diff --git a/micro_rpc_tests/build.rs b/micro_rpc_tests/build.rs index 6a842f4ee29..8a3f51c87e4 100644 --- a/micro_rpc_tests/build.rs +++ b/micro_rpc_tests/build.rs @@ -18,7 +18,10 @@ fn main() { println!("cargo:rerun-if-env-changed=WORKSPACE_ROOT"); micro_rpc_build::compile( &[format!("{}micro_rpc_tests/proto/test_schema.proto", env!("WORKSPACE_ROOT"))], - &[format!("{}micro_rpc_tests/proto", env!("WORKSPACE_ROOT"))], + &[ + format!("{}micro_rpc_tests/proto", env!("WORKSPACE_ROOT")), + env!("WORKSPACE_ROOT").to_string(), + ], Default::default(), ); } diff --git a/micro_rpc_tests/proto/test_schema.proto b/micro_rpc_tests/proto/test_schema.proto index f6f0dbb50a0..3c7c368614d 100644 --- a/micro_rpc_tests/proto/test_schema.proto +++ b/micro_rpc_tests/proto/test_schema.proto @@ -22,6 +22,7 @@ import "google/protobuf/empty.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; import "google/protobuf/any.proto"; +import "proto/micro_rpc/options.proto"; message LookupDataRequest { bytes key = 1; @@ -37,15 +38,27 @@ message LogResponse {} service TestService { // method_id: 15 - rpc LookupData(LookupDataRequest) returns (LookupDataResponse); + rpc LookupData(LookupDataRequest) returns (LookupDataResponse) { + option (.oak.micro_rpc.method_id) = 15; + } // method_id: 16 - rpc Log(LogRequest) returns (LogResponse); + rpc Log(LogRequest) returns (LogResponse) { + option (.oak.micro_rpc.method_id) = 16; + } // method_id: 17 - rpc Empty(google.protobuf.Empty) returns (google.protobuf.Empty); + rpc Empty(google.protobuf.Empty) returns (google.protobuf.Empty) { + option (.oak.micro_rpc.method_id) = 17; + } // method_id: 18 - rpc Duration(google.protobuf.Duration) returns (google.protobuf.Duration); + rpc Duration(google.protobuf.Duration) returns (google.protobuf.Duration) { + option (.oak.micro_rpc.method_id) = 18; + } // method_id: 19 - rpc Timestamp(google.protobuf.Timestamp) returns (google.protobuf.Timestamp); + rpc Timestamp(google.protobuf.Timestamp) returns (google.protobuf.Timestamp) { + option (.oak.micro_rpc.method_id) = 19; + } // method_id: 20 - rpc Any(google.protobuf.Any) returns (google.protobuf.Any); + rpc Any(google.protobuf.Any) returns (google.protobuf.Any) { + option (.oak.micro_rpc.method_id) = 20; + } } diff --git a/oak_attestation/src/dice.rs b/oak_attestation/src/dice.rs index f8cc9b51278..4b6bdbe6751 100644 --- a/oak_attestation/src/dice.rs +++ b/oak_attestation/src/dice.rs @@ -96,6 +96,8 @@ impl DiceBuilder { additional_claims: Vec<(ClaimName, ciborium::Value)>, kem_public_key: &[u8], verifying_key: &VerifyingKey, + group_kem_public_key: Option<&[u8]>, + group_verifying_key: Option<&VerifyingKey>, ) -> anyhow::Result { // The last evidence layer contains the certificate for the current signing key. // Since the builder contains an existing signing key there must be at @@ -127,7 +129,7 @@ impl DiceBuilder { let signing_public_key_certificate = generate_signing_certificate( &self.signing_key, - issuer_id, + issuer_id.clone(), verifying_key, additional_claims, ) @@ -136,9 +138,44 @@ impl DiceBuilder { .to_vec() .map_err(anyhow::Error::msg)?; + // Generate group keys certificates as part of Key Provisioning. + let group_encryption_public_key_certificate = + if let Some(group_kem_public_key) = group_kem_public_key { + generate_kem_certificate( + &self.signing_key, + issuer_id.clone(), + group_kem_public_key, + vec![], + ) + .map_err(anyhow::Error::msg) + .context("couldn't generate encryption public key certificate")? + .to_vec() + .map_err(anyhow::Error::msg)? + } else { + vec![] + }; + + let group_signing_public_key_certificate = + if let Some(group_verifying_key) = group_verifying_key { + generate_signing_certificate( + &self.signing_key, + issuer_id.clone(), + group_verifying_key, + vec![], + ) + .map_err(anyhow::Error::msg) + .context("couldn't generate signing public key certificate")? + .to_vec() + .map_err(anyhow::Error::msg)? + } else { + vec![] + }; + evidence.application_keys = Some(ApplicationKeys { encryption_public_key_certificate, signing_public_key_certificate, + group_encryption_public_key_certificate, + group_signing_public_key_certificate, }); Ok(evidence) @@ -237,5 +274,10 @@ fn application_keys_to_proto( let signing_public_key_certificate = oak_dice::utils::cbor_encoded_bytes_to_vec(&value.signing_public_key_certificate[..]) .map_err(anyhow::Error::msg)?; - Ok(ApplicationKeys { encryption_public_key_certificate, signing_public_key_certificate }) + Ok(ApplicationKeys { + encryption_public_key_certificate, + signing_public_key_certificate, + group_encryption_public_key_certificate: vec![], + group_signing_public_key_certificate: vec![], + }) } diff --git a/oak_attestation_integration_tests/tests/verifier_tests.rs b/oak_attestation_integration_tests/tests/verifier_tests.rs index d6ea84c1641..efc3b7a3c4e 100644 --- a/oak_attestation_integration_tests/tests/verifier_tests.rs +++ b/oak_attestation_integration_tests/tests/verifier_tests.rs @@ -18,11 +18,11 @@ use oak_attestation::dice::evidence_to_proto; use oak_attestation_verification::verifier::{to_attestation_results, verify, verify_dice_chain}; use oak_proto_rust::oak::attestation::v1::{ attestation_results::Status, binary_reference_value, endorsements, - kernel_binary_reference_value, reference_values, ApplicationLayerReferenceValues, - BinaryReferenceValue, Endorsements, InsecureReferenceValues, KernelBinaryReferenceValue, - KernelLayerReferenceValues, OakRestrictedKernelEndorsements, + kernel_binary_reference_value, reference_values, text_reference_value, + ApplicationLayerReferenceValues, BinaryReferenceValue, Endorsements, InsecureReferenceValues, + KernelBinaryReferenceValue, KernelLayerReferenceValues, OakRestrictedKernelEndorsements, OakRestrictedKernelReferenceValues, ReferenceValues, RootLayerEndorsements, - RootLayerReferenceValues, SkipVerification, + RootLayerReferenceValues, SkipVerification, TextReferenceValue, }; use oak_restricted_kernel_sdk::attestation::EvidenceProvider; @@ -78,9 +78,13 @@ fn verify_mock_evidence() { SkipVerification {}, )), }), - kernel_image: Some(skip.clone()), - kernel_setup_data: Some(skip.clone()), - kernel_cmd_line: Some(skip.clone()), + kernel_image: None, + kernel_setup_data: None, + kernel_cmd_line: None, + kernel_cmd_line_regex: None, + kernel_cmd_line_text: Some(TextReferenceValue { + r#type: Some(text_reference_value::Type::Skip(SkipVerification {})), + }), init_ram_fs: Some(skip.clone()), memory_map: Some(skip.clone()), acpi: Some(skip.clone()), diff --git a/oak_attestation_verification/BUILD b/oak_attestation_verification/BUILD index 6ba4e60ebd6..062cda204cd 100644 --- a/oak_attestation_verification/BUILD +++ b/oak_attestation_verification/BUILD @@ -48,3 +48,34 @@ rust_library( "@oak_crates_index//:zerocopy", ], ) + +rust_library( + name = "oak_attestation_verification_with_regex", + srcs = glob(["src/**"]), + compile_data = [ + "//oak_attestation_verification/data:ask_milan.pem", + ], + crate_features = ["regex"], + deps = [ + "//oak_dice", + "//oak_proto_rust", + "//oak_sev_snp_attestation_report", + "@oak_crates_index//:anyhow", + "@oak_crates_index//:base64", + "@oak_crates_index//:coset", + "@oak_crates_index//:ecdsa", + "@oak_crates_index//:getrandom", + "@oak_crates_index//:hex", + "@oak_crates_index//:p256", + "@oak_crates_index//:p384", + "@oak_crates_index//:prost", + "@oak_crates_index//:regex", + "@oak_crates_index//:rsa", + "@oak_crates_index//:serde", + "@oak_crates_index//:serde_json", + "@oak_crates_index//:sha2", + "@oak_crates_index//:time", + "@oak_crates_index//:x509-cert", + "@oak_crates_index//:zerocopy", + ], +) diff --git a/oak_attestation_verification/Cargo.toml b/oak_attestation_verification/Cargo.toml index 1bc424248c8..d6ffee6bbdb 100644 --- a/oak_attestation_verification/Cargo.toml +++ b/oak_attestation_verification/Cargo.toml @@ -35,6 +35,7 @@ p384 = { version = "0.13.0", default-features = false, features = [ prost = { workspace = true, default-features = false, features = [ "prost-derive", ] } +regex = { version = "*", default-features = false, optional = true } rsa = { version = "0.9.6", default-features = false } serde = { version = "*", default-features = false, features = ["derive"] } serde_json = { version = "*", default-features = false, features = ["alloc"] } diff --git a/oak_attestation_verification/src/verifier.rs b/oak_attestation_verification/src/verifier.rs index 4ed0a865c73..c8f9dc0cd76 100644 --- a/oak_attestation_verification/src/verifier.rs +++ b/oak_attestation_verification/src/verifier.rs @@ -16,7 +16,7 @@ //! Provides verification based on evidence, endorsements and reference values. -use alloc::{format, vec::Vec}; +use alloc::{format, string::String, vec::Vec}; use anyhow::Context; use coset::{cbor::Value, cwt::ClaimsSet, CborSerializable, CoseKey, RegisteredLabelWithPrivate}; @@ -24,31 +24,35 @@ use ecdsa::{signature::Verifier, Signature}; use oak_dice::cert::{ cose_key_to_hpke_public_key, cose_key_to_verifying_key, get_public_key_from_claims_set, ACPI_MEASUREMENT_ID, CONTAINER_IMAGE_LAYER_ID, ENCLAVE_APPLICATION_LAYER_ID, - FINAL_LAYER_CONFIG_MEASUREMENT_ID, INITRD_MEASUREMENT_ID, KERNEL_LAYER_ID, - KERNEL_MEASUREMENT_ID, LAYER_2_CODE_MEASUREMENT_ID, LAYER_3_CODE_MEASUREMENT_ID, - MEMORY_MAP_MEASUREMENT_ID, SETUP_DATA_MEASUREMENT_ID, SHA2_256_ID, SYSTEM_IMAGE_LAYER_ID, + FINAL_LAYER_CONFIG_MEASUREMENT_ID, INITRD_MEASUREMENT_ID, KERNEL_COMMANDLINE_ID, + KERNEL_COMMANDLINE_MEASUREMENT_ID, KERNEL_LAYER_ID, KERNEL_MEASUREMENT_ID, + LAYER_2_CODE_MEASUREMENT_ID, LAYER_3_CODE_MEASUREMENT_ID, MEMORY_MAP_MEASUREMENT_ID, + SETUP_DATA_MEASUREMENT_ID, SHA2_256_ID, SYSTEM_IMAGE_LAYER_ID, }; use oak_proto_rust::oak::{ attestation::v1::{ attestation_results::Status, binary_reference_value, endorsements, extracted_evidence::EvidenceValues, kernel_binary_reference_value, reference_values, - root_layer_data::Report, AmdAttestationReport, AmdSevReferenceValues, ApplicationKeys, - ApplicationLayerData, ApplicationLayerEndorsements, ApplicationLayerReferenceValues, - AttestationResults, BinaryReferenceValue, CbData, CbEndorsements, CbReferenceValues, - ContainerLayerData, ContainerLayerEndorsements, ContainerLayerReferenceValues, - Endorsements, Evidence, ExtractedEvidence, FakeAttestationReport, InsecureReferenceValues, - IntelTdxAttestationReport, IntelTdxReferenceValues, KernelAttachment, - KernelBinaryReferenceValue, KernelLayerData, KernelLayerEndorsements, - KernelLayerReferenceValues, OakContainersData, OakContainersEndorsements, - OakContainersReferenceValues, OakRestrictedKernelData, OakRestrictedKernelEndorsements, - OakRestrictedKernelReferenceValues, ReferenceValues, RootLayerData, RootLayerEndorsements, - RootLayerEvidence, RootLayerReferenceValues, SystemLayerData, SystemLayerEndorsements, - SystemLayerReferenceValues, TcbVersion, TeePlatform, TransparentReleaseEndorsement, + root_layer_data::Report, text_reference_value, AmdAttestationReport, AmdSevReferenceValues, + ApplicationKeys, ApplicationLayerData, ApplicationLayerEndorsements, + ApplicationLayerReferenceValues, AttestationResults, BinaryReferenceValue, CbData, + CbEndorsements, CbReferenceValues, ContainerLayerData, ContainerLayerEndorsements, + ContainerLayerReferenceValues, Endorsements, Evidence, ExtractedEvidence, + FakeAttestationReport, InsecureReferenceValues, IntelTdxAttestationReport, + IntelTdxReferenceValues, KernelAttachment, KernelBinaryReferenceValue, KernelLayerData, + KernelLayerEndorsements, KernelLayerReferenceValues, OakContainersData, + OakContainersEndorsements, OakContainersReferenceValues, OakRestrictedKernelData, + OakRestrictedKernelEndorsements, OakRestrictedKernelReferenceValues, ReferenceValues, + RootLayerData, RootLayerEndorsements, RootLayerEvidence, RootLayerReferenceValues, + SystemLayerData, SystemLayerEndorsements, SystemLayerReferenceValues, TcbVersion, + TeePlatform, TextReferenceValue, TransparentReleaseEndorsement, }, HexDigest, RawDigest, }; use oak_sev_snp_attestation_report::AttestationReport; use prost::Message; +#[cfg(feature = "regex")] +use regex::Regex; use x509_cert::{ der::{Decode, DecodePem}, Certificate, @@ -514,7 +518,32 @@ fn verify_kernel_layer( ) .context("kernel failed verification")?; - // TODO: b/325979696 - Validate the kernel command-line using a regex. + if let Some(kernel_raw_cmd_line) = values.kernel_raw_cmd_line.as_ref() { + verify_text( + kernel_raw_cmd_line.as_str(), + reference_values + .kernel_cmd_line_text + .as_ref() + .context("no kernel command line text reference values")?, + ) + .context("kernel command line failed verification")?; + } else { + // Support missing kernel_raw_cmd_line but only if the corresponding reference + // value is set to skip. This is a temporary workaround until all clients are + // migrated. + anyhow::ensure!( + matches!( + reference_values + .kernel_cmd_line_text + .as_ref() + .expect("no kernel command line text reference values") + .r#type + .as_ref(), + Some(text_reference_value::Type::Skip(_)) + ), + "No kernel_raw_cmd_line provided" + ) + } verify_measurement_digest( values.init_ram_fs.as_ref().context("no initial RAM disk evidence value")?, @@ -732,6 +761,46 @@ fn verify_hex_digests(actual: &HexDigest, expected: &HexDigest) -> anyhow::Resul } } +fn verify_text(actual: &str, expected: &TextReferenceValue) -> anyhow::Result<()> { + match expected.r#type.as_ref() { + Some(text_reference_value::Type::Skip(_)) => Ok(()), + Some(text_reference_value::Type::Regex(regex)) => verify_regex(actual, regex), + Some(text_reference_value::Type::StringLiterals(string_literals)) => { + anyhow::ensure!(!string_literals.value.is_empty()); + for sl in string_literals.value.iter() { + if sl == actual { + return Ok(()); + } + } + Err(anyhow::anyhow!(format!( + "value doesn't match the reference value string literal: {actual}" + ))) + } + None => Err(anyhow::anyhow!("missing skip or value in the text reference value")), + } +} + +#[cfg(feature = "regex")] +fn verify_regex( + actual: &str, + regex: &oak_proto_rust::oak::attestation::v1::Regex, +) -> anyhow::Result<()> { + let re = Regex::new(regex.value.as_str()) + .map_err(|msg| anyhow::anyhow!("couldn't parse regex in the reference value: {msg}"))?; + Ok(anyhow::ensure!( + re.is_match(actual), + format!("value doesn't match the reference value regex: {actual}") + )) +} + +#[cfg(not(feature = "regex"))] +fn verify_regex( + _actual: &str, + _regex: &oak_proto_rust::oak::attestation::v1::Regex, +) -> anyhow::Result<()> { + Err(anyhow::anyhow!("verification of regex values not supported")) +} + struct ApplicationKeyValues { encryption_public_key: Vec, signing_public_key: Vec, @@ -907,7 +976,11 @@ fn extract_kernel_values(claims: &ClaimsSet) -> anyhow::Result let kernel_image = Some(value_to_raw_digest(extract_value(values, KERNEL_MEASUREMENT_ID)?)?); let kernel_setup_data = Some(value_to_raw_digest(extract_value(values, SETUP_DATA_MEASUREMENT_ID)?)?); - // TODO: b/325979696 - Extract raw kernel command-line. + let kernel_cmd_line = + Some(value_to_raw_digest(extract_value(values, KERNEL_COMMANDLINE_MEASUREMENT_ID)?)?); + let kernel_raw_cmd_line = extract_value(values, KERNEL_COMMANDLINE_ID) + .ok() + .map(|v| String::from(v.as_text().expect("kernel_raw_cmd_line found but is not a string"))); let init_ram_fs = Some(value_to_raw_digest(extract_value(values, INITRD_MEASUREMENT_ID)?)?); let memory_map = Some(value_to_raw_digest(extract_value(values, MEMORY_MAP_MEASUREMENT_ID)?)?); let acpi = Some(value_to_raw_digest(extract_value(values, ACPI_MEASUREMENT_ID)?)?); @@ -915,7 +988,8 @@ fn extract_kernel_values(claims: &ClaimsSet) -> anyhow::Result Ok(KernelLayerData { kernel_image, kernel_setup_data, - kernel_cmd_line: None, + kernel_cmd_line, + kernel_raw_cmd_line, init_ram_fs, memory_map, acpi, @@ -985,7 +1059,7 @@ fn extract_value(values: &[(Value, Value)], label_id: i64) -> anyhow::Result<&Va values .iter() .find_map(|(key, value)| if key == &target_key { Some(value) } else { None }) - .context("couldn't find measurement") + .context(format!("couldn't find measurement {label_id}")) } /// Extracts the individual digests from a value that represents a set of diff --git a/oak_attestation_verification/testdata/BUILD b/oak_attestation_verification/testdata/BUILD index 147c56779a5..0bc30c46ce4 100644 --- a/oak_attestation_verification/testdata/BUILD +++ b/oak_attestation_verification/testdata/BUILD @@ -42,6 +42,8 @@ exports_files([ "rekor_public_key.pem", "rk_evidence.binarypb", "rk_evidence.textproto", + "rk_evidence_20240312.binarypb", + "rk_evidence_20240312.textproto", "rk_vcek_milan.der", "rk_vcek_milan.pem", ]) diff --git a/oak_attestation_verification/testdata/fake_evidence.binarypb b/oak_attestation_verification/testdata/fake_evidence.binarypb index cd5a4cc9c87..a3571a16971 100644 Binary files a/oak_attestation_verification/testdata/fake_evidence.binarypb and b/oak_attestation_verification/testdata/fake_evidence.binarypb differ diff --git a/oak_attestation_verification/testdata/fake_evidence.textproto b/oak_attestation_verification/testdata/fake_evidence.textproto index 3a519fbb96a..774d51b4986 100644 --- a/oak_attestation_verification/testdata/fake_evidence.textproto +++ b/oak_attestation_verification/testdata/fake_evidence.textproto @@ -6,16 +6,16 @@ # serialized binary format. root_layer { platform: TEE_PLATFORM_NONE - remote_attestation_report: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000g{\374/\207\316\246\213\366\321\207ic\301Pr=\177\212\304\364\214\376\326\016l\212\375z?C.\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" - eca_public_key: "\247\001\002\002T\006\337\216\277\337<\3375\361\241S\236W\371\216pUN\323\016\003&\004\201\002 \001!X \302\202\323A\241\255o\253\274\322\360\316\023PX\227K\267\300\014\256\346\206\374\324V%\342\253\370\211\203\"X L\327\2775\263;\212\007w\246\207B\261\021yBu\375\303M\013\301\032\244\033\216)\375\276sn-" + remote_attestation_report: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\222~\301 \202\337>\3222\230\254\262:/\216\223&M\024`\027\205\255s}\215\025\006\244\201\324\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + eca_public_key: "\247\001\002\002Tmt\266\300\360\340\266}\213o\371$F\t\037O\257\324\000\000\003&\004\201\002 \001!X \363\324P\230\362%n\"\010\224\351\357\027N\014\253!\267\236\200\006J\021\316\033\200\246\205\251w9S\"X \014\210\336\203\017\345\3535\350\354|\016\356!\335Xn\311\366)\353p\374\371gz\005\034\350\\\333\007" } layers { - eca_certificate: "\204C\241\001&\241\004RAsymmetricECDSA256Y\001\340\245\001x(06df8ebfdf3cdf35f1a1539e57f98e70554ed30e\002x(83af874d80f9fe6d5c807e6e78d344b40bb74adc:\000GDWXf\247\001\002\002T\203\257\207M\200\371\376m\\\200~nx\323D\264\013\267J\334\003&\004\201\002 \001!X k\221\233\\_1\364\234\372\253\013*\000\177EO\373\275\377\207$\033)\007\001Y>z\213x\035\035\"X :Z\261%\003P\272f\333\017=\310\377\2278`3\r\3169\307Y\353\215\245\202\037!\260/T(:\000GDXB \000:\000GDZ\246:\000GD`\241:\000GDkX \324*\253\002\333\205\205\310\306E\305\233\277\316>\217&*\276\301W\003m\032\352\223u\2509[\244\006:\000GDa\241:\000GDkX \215c\241+\037t\"\023\367\360\222\\\226\tZx\363\\\371JL\221\274\'\221\236D\252\312\311\026\035:\000GDb\241:\000GDkX \177\204W\306\033>\013V\033|\314\322\r\004\216\225?\327|>|\177b\333@\'\014\257s\271C%:\000GDc\241:\000GDkX /\2762NP>\305I\243\264Z\030\177uI \225/\303Q^\272u\305*9\"\031\315\330\322\362:\000GDd\241:\000GDkX \001u>\274BEU\250\r5\255\252!\365\310\305\360\tH.\213\\\305\332\360I\274\033\277\376\274{:\000GDe\241:\000GDkX Z\200J\367\351\007t\222\332\302\342\333g\020\246\315\246\207\331]A\\rA\225\321\2051\010\"\261\260X@\010\362\023\n_G\247\205a\314\375\334/T\343\tgq\235\370\334\240A\221M\230s\305H\316\023<\254\235\330\202i\352x}\260\366\324\351\271\350K\304\322\332\020\014dv\373\352\002\363qA3\035\353\260" + eca_certificate: "\204C\241\001&\241\004RAsymmetricECDSA256Y\002~\245\001x(6d74b6c0f0e0b67d8b6ff92446091f4fafd40000\002x(d92b255c77f253471da4d90bfc4e8f0a87e7f1f1:\000GDWXf\247\001\002\002T\331+%\\w\362SG\035\244\331\013\374N\217\n\207\347\361\361\003&\004\201\002 \001!X 4\032h\244\355\216\335\221Raz~\006\320\353\037\370\353\016\245j#\235\016]\2422r\033wz\342\"X \321\253\240\326Tt\364N\332\277\353\036S\307\373-S\326u\016\351\252l\266\017~\304s\371\364K\277:\000GDXB \000:\000GDZ\247:\000GD`\241:\000GDkX \324*\253\002\333\205\205\310\306E\305\233\277\316>\217&*\276\301W\003m\032\352\223u\2509[\244\006:\000GDa\241:\000GDkX \215c\241+\037t\"\023\367\360\222\\\226\tZx\363\\\371JL\221\274\'\221\236D\252\312\311\026\035:\000GDlx\227console=ttyS0 panic=-1 earlycon=uart,io,0x3F8 brd.rd_nr=1 brd.rd_size=3072000 brd.max_part=1 ip=10.0.2.15:::255.255.255.0::eth0:off net.ifnames=0 quiet:\000GDb\241:\000GDkX \001\322\353\032\253L_\356\244\022!\004\201\234\300`\016\266\377lo;g\031\000\260\345\231\327\371\202A:\000GDc\241:\000GDkX \030\303M\214\3077\373W\t\251\232\313\007<\334^\330\244\004P?bl\352n\013\255\n@`\002\374:\000GDd\241:\000GDkX p\n\240\321:\377y\3747\240S\245r\261X\306\324b\002i i\370\203PI8\217\020\031\241\367:\000GDe\241:\000GDkX Z\200J\367\351\007t\222\332\302\342\333g\020\246\315\246\207\331]A\\rA\225\321\2051\010\"\261\260X@\001\260\342*=%\013[\334Z\262x%+\002\373\333\300\217+\227}\265.\245\373\273\251w\037Y\315\234\267\346\026\321z\240T\227v\264\257\226\367\327\232jX\204l>\t#\006\326P(\"~N\304\233" } layers { - eca_certificate: "\204C\241\001&\241\004RAsymmetricECDSA256X\377\245\001x(83af874d80f9fe6d5c807e6e78d344b40bb74adc\002x(ab1ec0a82d71e1c19aae5cccdf70750a503cf220:\000GDWXf\247\001\002\002T\253\036\300\250-q\341\301\232\256\\\314\337pu\nP<\362 \003&\004\201\002 \001!X \025Kh\353\314r\210\356\032w\276[\014{}\274\214\371TW+\302\311k\276\277k*H\004\227\264\"X \306LD\337z\031\325\312\254\037\301\327\037M\223\207+\243%\202O\203y\320H\272\027\257\341\326\233\301:\000GDXB \000:\000GD\\\241:\000GDf\241:\000GDkX \020\326\225B\n4\031\343\205Wh_h\306\217\034\255\037H>=\025\353m\267`\340\036Rv\307\351X@\035\257\200\304\343\207SL\211\372\371t\357J\244b$\310d<\242\254\356]\3616i?\215;`\357\2271\007#`\216\227\265|\2229\252\342\323IL\367k\322\206\325\345\274\377\331\0042gD\242\223\324" + eca_certificate: "\204C\241\001&\241\004RAsymmetricECDSA256X\377\245\001x(d92b255c77f253471da4d90bfc4e8f0a87e7f1f1\002x(30a05da52f6b4233d97498bfc83bf7548ad0a2fe:\000GDWXf\247\001\002\002T0\240]\245/kB3\331t\230\277\310;\367T\212\320\242\376\003&\004\201\002 \001!X \357p\r\017\037\262\252\352\362\276\025\362\216]\021F-\351\n\235b\365\362\314\216o\250\0320\n\277\212\"X \020\304A\272\335u5\254\200\363\333\371\003\272a8\377N\031s\357\303\232\215\0341\375\211\225\"\203\302:\000GDXB \000:\000GD\\\241:\000GDf\241:\000GDkX \322r\005f;L\206\267\027_\217;\266R\361\007\317\330w!\226u\033\272\027\2232\361\345(\273\027X@\022T\\\243\263D\033[S|\231\305\210\365\340e\314lM\021\3574k\336\377v/\301B\0341\004\"\230\311\312\301\243Z\216\365\002ZV\230\204-N\0055\274\220g\346%\243AS\323]\350\344}\266" } application_keys { - encryption_public_key_certificate: "\204C\241\001&\241\004RAsymmetricECDSA256Y\001\n\245\001x(ab1ec0a82d71e1c19aae5cccdf70750a503cf220\002x(383ca72f3f9b75c0af4245bdd6166f26f94e89fd:\000GDWXD\246\001\001\002T8<\247/?\233u\300\257BE\275\326\026o&\371N\211\375\0038\036\004\201\005 \004!X \271\261\342\026\366\341\352k4\217\0334\341\311\275x38\275\243\006\024|5e\311C\267r\376jQ:\000GDXB \000:\000GD^\242:\000GDh\241:\000GDkX P>\323\307\242=\3354U_\227?Q\255~<.\301[\362aSv{\377\211j\260\024\301l\200:\000GDi\241:\000GDkX \033\336\262\213\304\362\020\333\233B\2421`\370\027\307\005\357\371\210\334g\302\342\350\356O\216\345\223RzX@\3155\375\224\321_\335\264^\\Ta\007\364\244\004\232tX\310i\366e\317\020\020q\273\321\236\270\020\212)\025\026\230\316%\216\364E\275\".\336H0\272.g\223\226\303\343\303\323\337\215\222\323\036\266\254" - signing_public_key_certificate: "\204C\241\001&\241\004RAsymmetricECDSA256Y\001,\245\001x(ab1ec0a82d71e1c19aae5cccdf70750a503cf220\002x(055d633d8f1ae1e976c98e6bf89e522c477eb372:\000GDWXf\247\001\002\002T\005]c=\217\032\341\351v\311\216k\370\236R,G~\263r\003&\004\201\002 \001!X l\322s\365\311`7\303\221kD-VQ\000\363[\305=\361\257\230|\272\253MU{fh\315!\"X \266P\322\231\216\216g[\007\242\212\250\326\245\"\316mW\330R\204Cg|\333\2042\354<\223\020<:\000GDXB \000:\000GD^\242:\000GDh\241:\000GDkX P>\323\307\242=\3354U_\227?Q\255~<.\301[\362aSv{\377\211j\260\024\301l\200:\000GDi\241:\000GDkX \033\336\262\213\304\362\020\333\233B\2421`\370\027\307\005\357\371\210\334g\302\342\350\356O\216\345\223RzX@>\204&\330\216c\014\336U\313\374\303r\236\230@\342\312\322\242q`\241\3517\005\302\262C\321\354\320\346\373\203F\314\241\352R\021I\263<\273i\245\004\360\335\312\266Jz\355\301\254Uu:\000GDXB \000:\000GD^\242:\000GDh\241:\000GDkX s+\016=/_\210\301\2678\353\242*\271\024wl\010`\026H=4\003\nY\321xz}\342\302:\000GDi\241:\000GDkX \033\336\262\213\304\362\020\333\233B\2421`\370\027\307\005\357\371\210\334g\302\342\350\356O\216\345\223RzX@\357sBF\242`\332\363\222u:\241\260\032\277\000)\202\250\213\340\356\033p\237\211\247\020\001O\277u\014\320\030\256\360*U\302\323\217J\255\372~\177-X=\322\320=E \254-P(c\242\301.\316" } diff --git a/oak_attestation_verification/testdata/rk_evidence_20240312.binarypb b/oak_attestation_verification/testdata/rk_evidence_20240312.binarypb new file mode 100644 index 00000000000..6f590720410 Binary files /dev/null and b/oak_attestation_verification/testdata/rk_evidence_20240312.binarypb differ diff --git a/oak_attestation_verification/testdata/rk_evidence_20240312.textproto b/oak_attestation_verification/testdata/rk_evidence_20240312.textproto new file mode 100644 index 00000000000..aceac6da128 --- /dev/null +++ b/oak_attestation_verification/testdata/rk_evidence_20240312.textproto @@ -0,0 +1,20 @@ +# proto-file: proto/attestation/evidence.proto +# proto-message: oak.attestaton.v1.Evidence +# +# Valid real-world evidence for a Restricted Kernel chain, used for testing. +# Generated on 2024-03-12. `oc_evidence.binarypb` is the same instance in +# serialized binary format. ECA: Embedded Certification Authority +# +# The stage0 binary is measured in the attestation report. +root_layer { + platform: AMD_SEV_SNP + remote_attestation_report: "\002\000\000\000\000\000\000\000\000\000\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\003\000\000\000\000\000\024\321\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000w2\252D\223\000Db\2172\355\260\235\024\250\335\376\036\200\002\346\036x\347a\230\255\005}\005x#\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\366\337 T\243\207\363\370)\221A\226\010mY\222dk|\275\203Bp\304\333 \\\323hy\227~\340`\026\301\346\\\236\304S\3434\2415>\223:\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\3111\312\374\2427ynn\373\n\264W\226\014=\323P\304\216\230\007\256\306g%\316^my>\343\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\003\000\000\000\000\000\024\321\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\013\272\370\027|i\366~39}\203*\3533\270-d\256\351S\246#\001\351\017r\000r\232\313\351\222G\'wbZ*B\'\2553\322\336\303\366\024\215aAa\033\264\237d\315m\317\227Z>\267\300\003\000\000\000\000\000\024\321\0207\001\000\0207\001\000\003\000\000\000\000\000\024\321\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\310\274\324\320<\030\t+\017\2040\361\344\020\376\376\374\323\\\347\231\241\270\226\354U}\255\0062E\333\255\202eC\370\035{\02321\321<\314\266\020Z\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\232\355A\263Lm\2007m\237\0265Wu\322\277\371\305\343\204\302\007R\001eLq\305\344Ue\336\013FT\317<\263\373!\203\313\"}\311\301\252\235\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + eca_public_key: "\247\001\002\002T\256jOA}\026Vj\025\024\341\306\323\036K\3671\201\032\336\003&\004\201\002 \001!X \361v\376\347?\377\233\211\240\326Za\0369\335\202\r\005d\267\016\331\365\221\\\007w\0261$\264^\"X \314\345!\266e[\365\377R\034\036S\245 ^\353\322{\377]\212\367X\367\034;V\203y>\344\317" +} +layers { + eca_certificate: "\204C\241\001&\241\004RAsymmetricECDSA256Y\001\340\245\001x(ae6a4f417d16566a1514e1c6d31e4bf731811ade\002x(25c27a19fda31d66242035a30892ead3746e6920:\000GDWXf\247\001\002\002T%\302z\031\375\243\035f$ 5\243\010\222\352\323tni \003&\004\201\002 \001!X N\330n\007\260Wi\347Q\337\300.\336\264\234\216hL\213z\235\342E\0358\000\312\0378k)\'\"X \344\302\006i\255\257:|L\370\2555\326\307d_\261VSO6\315}z\336\312hc\\bT\210:\000GDXB \000:\000GDZ\246:\000GD`\241:\000GDkX \314\216\243\312j\305\340\247s\342[\037\017}\365j\356\340wB\033R\206\375\345BOc\005\007\373N:\000GDa\241:\000GDkX +\230Xm\231\005\246\005\302\225\327|a\350\317\322\002z\345\270\240N\357\251\001\2046\366\255\021B\227:\000GDb\241:\000GDkX L\320 \202\r\246c\006?A\205\312\024\247\350\003\315|\234\241H\274BEU\250\r5\255\252!\365\310\305\360\tH.\213\\\305\332\360I\274\033\277\376\274{:\000GDe\241:\000GDkX d\365U2r\207\242\024\024vh\036NM\330\r_u\253\234\'om\270\357\374U#m\272\231SX@d\016\\\353\314\230\267A\231\017\232\267\241A\037\322e\333\325\3222\210\322\244\360\322\212L\220\212\030\0073\265\211\032\356=\354\215\226\201e\247\334\230\334C}\014l\317H\336]b2\277YJ\004\217\036\357" +} +application_keys { + encryption_public_key_certificate: "\204C\241\001&\241\004RAsymmetricECDSA256X\351\245\001x(25c27a19fda31d66242035a30892ead3746e6920\002x(ba848bf3163adcebaa6a86e85593e64112bec8f7:\000GDWXD\246\001\001\002T\272\204\213\363\026:\334\353\252j\206\350U\223\346A\022\276\310\367\0038\036\004\201\005 \004!X \361u\235\355Wh\224\375\250\342\213~H\241>\240s\346Ns\250\351\247\346\256Z=\300U\323)\016:\000GDXB \000:\000GD[\242:\000GDf\241:\000GDkX \225\377$\246\2763\321\225\302\237O\342\256\342r\025\'\371X\244$T\247\3042$^\305\354\214T\235:\000GDi\241:\000GDk@X@d\365\367\267\333b\327yE\352\003\276\263>\r\031b\346\344`\242^\317\204B\313\256\371\303\263\020\034R\327`\356\007\311\200\324\375<\316\366\036\265 E\274\010$\'\256M-\277\016\362\013=Kf\023\342" + signing_public_key_certificate: "\204C\241\001&\241\004RAsymmetricECDSA256Y\001\013\245\001x(25c27a19fda31d66242035a30892ead3746e6920\002x(38d213454f2a0f4668c7816c35ac857c7f85a0e6:\000GDWXf\247\001\002\002T8\322\023EO*\017Fh\307\201l5\254\205|\177\205\240\346\003&\004\201\002 \001!X \215\315\337\177~\331}\254.\307`@#\020%G9=\361t\375v\202<\266\236\351\210QW\357\311\"X 8z\255\376\263Vd\320#>\027\177\237\335\377\315<\237\345\227\273\242\000\002&I\312G\2174n\004:\000GDXB \000:\000GD[\242:\000GDf\241:\000GDkX \225\377$\246\2763\321\225\302\237O\342\256\342r\025\'\371X\244$T\247\3042$^\305\354\214T\235:\000GDi\241:\000GDk@X@\215\323\254\332\321Z\177A\344\315Rr(\212\253E\0050-\367=\231\036\237\357\007*b\254\340\317O)\213\370]P\344\3261\356\311\333\007\264\201B\360!\276:\275>\027\007\254\027$\316\314\263\032\247$" +} diff --git a/oak_attestation_verification/tests/verifier_tests.rs b/oak_attestation_verification/tests/verifier_tests.rs index 72dfccc46c1..2e62f804146 100644 --- a/oak_attestation_verification/tests/verifier_tests.rs +++ b/oak_attestation_verification/tests/verifier_tests.rs @@ -14,7 +14,7 @@ // limitations under the License. // -use std::fs; +use std::{fs, string::String}; use oak_attestation_verification::{ util::convert_pem_to_raw, @@ -24,14 +24,15 @@ use oak_proto_rust::oak::{ attestation::v1::{ attestation_results::Status, binary_reference_value, extracted_evidence::EvidenceValues, kernel_binary_reference_value, reference_values, root_layer_data::Report, - AmdSevReferenceValues, ApplicationLayerEndorsements, ApplicationLayerReferenceValues, - BinaryReferenceValue, ContainerLayerEndorsements, ContainerLayerReferenceValues, Digests, - EndorsementReferenceValue, Endorsements, Evidence, InsecureReferenceValues, - KernelBinaryReferenceValue, KernelLayerEndorsements, KernelLayerReferenceValues, - OakContainersEndorsements, OakContainersReferenceValues, OakRestrictedKernelEndorsements, - OakRestrictedKernelReferenceValues, ReferenceValues, RootLayerEndorsements, - RootLayerReferenceValues, SkipVerification, SystemLayerEndorsements, - SystemLayerReferenceValues, TcbVersion, TransparentReleaseEndorsement, + text_reference_value, AmdSevReferenceValues, ApplicationLayerEndorsements, + ApplicationLayerReferenceValues, BinaryReferenceValue, ContainerLayerEndorsements, + ContainerLayerReferenceValues, Digests, EndorsementReferenceValue, Endorsements, Evidence, + InsecureReferenceValues, KernelBinaryReferenceValue, KernelLayerEndorsements, + KernelLayerReferenceValues, OakContainersEndorsements, OakContainersReferenceValues, + OakRestrictedKernelEndorsements, OakRestrictedKernelReferenceValues, ReferenceValues, + Regex, RootLayerEndorsements, RootLayerReferenceValues, SkipVerification, StringLiterals, + SystemLayerEndorsements, SystemLayerReferenceValues, TcbVersion, TextReferenceValue, + TransparentReleaseEndorsement, }, RawDigest, }; @@ -46,6 +47,7 @@ const ENDORSER_PUBLIC_KEY_PATH: &str = "testdata/oak-development.pem"; const REKOR_PUBLIC_KEY_PATH: &str = "testdata/rekor_public_key.pem"; const CONTAINERS_EVIDENCE_PATH: &str = "testdata/oc_evidence.binarypb"; const RK_EVIDENCE_PATH: &str = "testdata/rk_evidence.binarypb"; +const RK_OBSOLETE_EVIDENCE_PATH: &str = "testdata/rk_evidence_20240312.binarypb"; const FAKE_EVIDENCE_PATH: &str = "testdata/fake_evidence.binarypb"; // Pretend the tests run at this time: 1 Nov 2023, 9:00 UTC @@ -64,6 +66,13 @@ fn create_rk_evidence() -> Evidence { Evidence::decode(serialized.as_slice()).expect("could not decode evidence") } +// Creates a valid AMD SEV-SNP evidence instance for a restricted kernel +// application but with obsolete DICE data that is still used by some clients. +fn create_rk_obsolete_evidence() -> Evidence { + let serialized = fs::read(RK_OBSOLETE_EVIDENCE_PATH).expect("could not read evidence"); + Evidence::decode(serialized.as_slice()).expect("could not decode evidence") +} + // Creates a valid fake evidence instance. fn create_fake_evidence() -> Evidence { let serialized = fs::read(FAKE_EVIDENCE_PATH).expect("could not read fake evidence"); @@ -158,9 +167,17 @@ fn create_containers_reference_values() -> ReferenceValues { kernel: Some(KernelBinaryReferenceValue { r#type: Some(kernel_binary_reference_value::Type::Skip(SkipVerification {})), }), - kernel_image: Some(skip.clone()), - kernel_setup_data: Some(skip.clone()), - kernel_cmd_line: Some(skip.clone()), + kernel_setup_data: None, + kernel_image: None, + kernel_cmd_line: None, + kernel_cmd_line_regex: None, + kernel_cmd_line_text: Some(TextReferenceValue { + r#type: Some(text_reference_value::Type::StringLiterals(StringLiterals { + value: vec![String::from( + "console=ttyS0 panic=-1 earlycon=uart,io,0x3F8 brd.rd_nr=1 brd.rd_size=3072000 brd.max_part=1 ip=10.0.2.15:::255.255.255.0::eth0:off net.ifnames=0 quiet", + )], + })), + }), init_ram_fs: Some(skip.clone()), memory_map: Some(skip.clone()), acpi: Some(skip.clone()), @@ -198,9 +215,15 @@ fn create_rk_reference_values() -> ReferenceValues { kernel: Some(KernelBinaryReferenceValue { r#type: Some(kernel_binary_reference_value::Type::Skip(SkipVerification {})), }), - kernel_image: Some(skip.clone()), - kernel_setup_data: Some(skip.clone()), - kernel_cmd_line: Some(skip.clone()), + kernel_setup_data: None, + kernel_image: None, + kernel_cmd_line: None, + kernel_cmd_line_regex: None, + kernel_cmd_line_text: Some(TextReferenceValue { + r#type: Some(text_reference_value::Type::StringLiterals(StringLiterals { + value: vec![String::from("console=ttyS0")], + })), + }), init_ram_fs: Some(skip.clone()), memory_map: Some(skip.clone()), acpi: Some(skip.clone()), @@ -475,3 +498,127 @@ fn verify_fails_with_empty_args() { assert!(r.is_err()); assert!(p.status() == Status::GenericFailure); } + +#[test] +fn verify_fails_with_non_matching_command_line_reference_value_set() { + let evidence = create_rk_evidence(); + let endorsements = create_rk_endorsements(); + let mut reference_values = create_rk_reference_values(); + match reference_values.r#type.as_mut() { + Some(reference_values::Type::OakRestrictedKernel(rfs)) => { + rfs.kernel_layer.as_mut().unwrap().kernel_cmd_line_text = Some(TextReferenceValue { + r#type: Some(text_reference_value::Type::Regex(Regex { + value: String::from("this will fail"), + })), + }); + } + Some(_) => {} + None => {} + }; + + let r = verify(NOW_UTC_MILLIS, &evidence, &endorsements, &reference_values); + let p = to_attestation_results(&r); + + eprintln!("======================================"); + eprintln!("code={} reason={}", p.status as i32, p.reason); + eprintln!("======================================"); + assert!(r.is_err()); + assert!(p.status() == Status::GenericFailure); +} + +#[test] +#[cfg(not(feature = "regex"))] +fn verify_fails_with_matching_command_line_reference_value_regex_set_and_regex_disabled() { + let evidence = create_rk_evidence(); + let endorsements = create_rk_endorsements(); + let mut reference_values = create_rk_reference_values(); + match reference_values.r#type.as_mut() { + Some(reference_values::Type::OakRestrictedKernel(rfs)) => { + rfs.kernel_layer.as_mut().unwrap().kernel_cmd_line_text = Some(TextReferenceValue { + r#type: Some(text_reference_value::Type::Regex(Regex { + value: String::from("^console=[a-zA-Z0-9]+$"), + })), + }); + } + Some(_) => {} + None => {} + }; + + let r = verify(NOW_UTC_MILLIS, &evidence, &endorsements, &reference_values); + let p = to_attestation_results(&r); + + eprintln!("======================================"); + eprintln!("code={} reason={}", p.status as i32, p.reason); + eprintln!("======================================"); + assert!(r.is_err()); + assert!(p.status() == Status::GenericFailure); +} + +#[test] +#[cfg(feature = "regex")] +fn verify_succeeds_with_matching_command_line_reference_value_regex_set_and_regex_enabled() { + let evidence = create_rk_evidence(); + let endorsements = create_rk_endorsements(); + let mut reference_values = create_rk_reference_values(); + match reference_values.r#type.as_mut() { + Some(reference_values::Type::OakRestrictedKernel(rfs)) => { + rfs.kernel_layer.as_mut().unwrap().kernel_cmd_line_text = Some(TextReferenceValue { + r#type: Some(text_reference_value::Type::Regex(Regex { + value: String::from("^console=[a-zA-Z0-9]+$"), + })), + }); + } + Some(_) => {} + None => {} + }; + + let r = verify(NOW_UTC_MILLIS, &evidence, &endorsements, &reference_values); + let p = to_attestation_results(&r); + + eprintln!("======================================"); + eprintln!("code={} reason={}", p.status as i32, p.reason); + eprintln!("======================================"); + assert!(r.is_ok()); + assert!(p.status() == Status::Success); +} + +#[test] +fn verify_fails_with_command_line_reference_value_set_and_obsolete_evidence() { + let evidence = create_rk_obsolete_evidence(); + let endorsements = create_rk_endorsements(); + let reference_values = create_rk_reference_values(); + + let r = verify(NOW_UTC_MILLIS, &evidence, &endorsements, &reference_values); + let p = to_attestation_results(&r); + + eprintln!("======================================"); + eprintln!("code={} reason={}", p.status as i32, p.reason); + eprintln!("======================================"); + assert!(r.is_err()); + assert!(p.status() == Status::GenericFailure); +} + +#[test] +fn verify_succeeds_with_skip_command_line_reference_value_set_and_obsolete_evidence() { + let evidence = create_rk_obsolete_evidence(); + let endorsements = create_rk_endorsements(); + let mut reference_values = create_rk_reference_values(); + match reference_values.r#type.as_mut() { + Some(reference_values::Type::OakRestrictedKernel(rfs)) => { + rfs.kernel_layer.as_mut().unwrap().kernel_cmd_line_text = Some(TextReferenceValue { + r#type: Some(text_reference_value::Type::Skip(SkipVerification {})), + }); + } + Some(_) => {} + None => {} + }; + + let r = verify(NOW_UTC_MILLIS, &evidence, &endorsements, &reference_values); + let p = to_attestation_results(&r); + + eprintln!("======================================"); + eprintln!("code={} reason={}", p.status as i32, p.reason); + eprintln!("======================================"); + assert!(r.is_ok()); + assert!(p.status() == Status::Success); +} diff --git a/oak_containers_kernel/configs/6.1.33/minimal.config b/oak_containers_kernel/configs/6.1.33/minimal.config index 1860526e993..52b52eaf919 100644 --- a/oak_containers_kernel/configs/6.1.33/minimal.config +++ b/oak_containers_kernel/configs/6.1.33/minimal.config @@ -726,9 +726,9 @@ CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_ASM_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y -CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG is not set # CONFIG_MODULE_SIG_FORCE is not set -CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_ALL is not set # CONFIG_MODULE_SIG_SHA1 is not set # CONFIG_MODULE_SIG_SHA224 is not set CONFIG_MODULE_SIG_SHA256=y @@ -2805,7 +2805,7 @@ CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_INFO=y CONFIG_AS_HAS_NON_CONST_LEB128=y # CONFIG_DEBUG_INFO_NONE is not set -CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set # CONFIG_DEBUG_INFO_DWARF4 is not set # CONFIG_DEBUG_INFO_DWARF5 is not set # CONFIG_DEBUG_INFO_REDUCED is not set diff --git a/oak_containers_orchestrator/src/main.rs b/oak_containers_orchestrator/src/main.rs index bdf761a9af4..22961d67942 100644 --- a/oak_containers_orchestrator/src/main.rs +++ b/oak_containers_orchestrator/src/main.rs @@ -56,78 +56,89 @@ async fn main() -> anyhow::Result<()> { .map_err(|error| anyhow!("couldn't create client: {:?}", error))?, ); + // Get key provisioning role. + let key_provisioning_role = launcher_client + .get_key_provisioning_role() + .await + .map_err(|error| anyhow!("couldn't get key provisioning role: {:?}", error))?; + + // Generate application keys. + let (instance_keys, instance_public_keys) = generate_instance_keys(); + let (mut group_keys, group_public_keys) = + if key_provisioning_role == KeyProvisioningRole::Leader { + let (group_keys, group_public_keys) = instance_keys.generate_group_keys(); + (Some(Arc::new(group_keys)), Some(group_public_keys)) + } else { + (None, None) + }; + + // Load application. let container_bundle = launcher_client .get_container_bundle() .await .map_err(|error| anyhow!("couldn't get container bundle: {:?}", error))?; - let application_config = launcher_client .get_application_config() .await .map_err(|error| anyhow!("couldn't get application config: {:?}", error))?; + // Generate attestation evidence and send it to the Hostlib. let dice_builder = oak_containers_orchestrator::dice::load_stage1_dice_data()?; let additional_claims = oak_containers_orchestrator::dice::measure_container_and_config( &container_bundle, &application_config, ); - let (instance_keys, instance_public_keys) = generate_instance_keys(); - let evidence = dice_builder.add_application_keys( additional_claims, &instance_public_keys.encryption_public_key, &instance_public_keys.signing_public_key, + if let Some(ref group_public_keys) = group_public_keys { + Some(&group_public_keys.encryption_public_key) + } else { + None + }, + None, )?; launcher_client .send_attestation_evidence(evidence) .await .map_err(|error| anyhow!("couldn't send attestation evidence: {:?}", error))?; + // Request group keys. + if key_provisioning_role == KeyProvisioningRole::Follower { + let get_group_keys_response = launcher_client + .get_group_keys() + .await + .map_err(|error| anyhow!("couldn't get group keys: {:?}", error))?; + let provisioned_group_keys = instance_keys + .provide_group_keys(get_group_keys_response) + .context("couldn't provide group keys")?; + group_keys = Some(Arc::new(provisioned_group_keys)); + } + if let Some(path) = args.ipc_socket_path.parent() { tokio::fs::create_dir_all(path).await?; } - let key_provisioning_role = launcher_client - .get_key_provisioning_role() - .await - .map_err(|error| anyhow!("couldn't get key provisioning role: {:?}", error))?; - let group_keys = Arc::new(match key_provisioning_role { - KeyProvisioningRole::Unspecified => anyhow::bail!("unspecified key provisioning role"), - KeyProvisioningRole::Leader => { - // TODO(#4442): Sign group public keys in the enclave evidence. - let (group_keys, _) = instance_keys.generate_group_keys(); - group_keys - } - KeyProvisioningRole::Dependant => { - let get_group_keys_response = launcher_client - .get_group_keys() - .await - .map_err(|error| anyhow!("couldn't get group keys: {:?}", error))?; - instance_keys - .provide_group_keys(get_group_keys_response) - .context("couldn't provide group keys")? - } - }); - let _metrics = oak_containers_orchestrator::metrics::run(launcher_client.clone())?; + // Start application and gRPC servers. let user = nix::unistd::User::from_name(&args.runtime_user) .context(format!("error resolving user {}", args.runtime_user))? .context(format!("user `{}` not found", args.runtime_user))?; - let cancellation_token = CancellationToken::new(); tokio::try_join!( oak_containers_orchestrator::ipc_server::create( &args.ipc_socket_path, instance_keys, - group_keys.clone(), + group_keys.clone().context("group keys were not provisioned")?, application_config, launcher_client, cancellation_token.clone(), ), oak_containers_orchestrator::key_provisioning::create( &args.orchestrator_addr, - group_keys, + group_keys.context("group keys were not provisioned")?, cancellation_token.clone(), ), oak_containers_orchestrator::container_runtime::run( diff --git a/oak_dice/BUILD b/oak_dice/BUILD index 98633cfb186..a665d34b26e 100644 --- a/oak_dice/BUILD +++ b/oak_dice/BUILD @@ -24,6 +24,9 @@ package( rust_library( name = "oak_dice", srcs = glob(["src/**"]), + crate_features = [ + "no_std", + ], deps = [ "@oak_crates_index//:bitflags", "@oak_crates_index//:ciborium", diff --git a/oak_restricted_kernel_sdk/src/utils.rs b/oak_restricted_kernel_sdk/src/utils.rs index 7ee2b16a231..90a7667b307 100644 --- a/oak_restricted_kernel_sdk/src/utils.rs +++ b/oak_restricted_kernel_sdk/src/utils.rs @@ -23,12 +23,12 @@ pub use oak_core::*; pub use oak_enclave_runtime_support::heap; use oak_restricted_kernel_interface::syscall::{fsync, write}; -struct Stderr {} +pub struct Stderr {} impl Stderr { const STDERR_FD: i32 = 2; - fn flush() { + pub fn flush() { fsync(Self::STDERR_FD).unwrap(); } } diff --git a/proto/attestation/evidence.proto b/proto/attestation/evidence.proto index cf5e88beaf4..a54a52bc30e 100644 --- a/proto/attestation/evidence.proto +++ b/proto/attestation/evidence.proto @@ -84,6 +84,20 @@ message ApplicationKeys { // Represented as a CBOR/COSE/CWT ECA certificate. // bytes signing_public_key_certificate = 2; + + // Certificate signing the group encryption public key as part of Key + // Provisioning. + // + // Represented as a CBOR/COSE/CWT ECA certificate. + // + bytes group_encryption_public_key_certificate = 3; + + // Certificate signing the group signing public key as part of Key + // Provisioning. + // + // Represented as a CBOR/COSE/CWT ECA certificate. + // + bytes group_signing_public_key_certificate = 4; } // Attestation Evidence used by the client to the identity of firmware and diff --git a/proto/attestation/reference_value.proto b/proto/attestation/reference_value.proto index 10bf97fdd40..5fea9c4c331 100644 --- a/proto/attestation/reference_value.proto +++ b/proto/attestation/reference_value.proto @@ -19,8 +19,8 @@ syntax = "proto3"; package oak.attestation.v1; -import "proto/digest.proto"; import "proto/attestation/tcb_version.proto"; +import "proto/digest.proto"; option go_package = "proto/oak/attestation/v1"; option java_multiple_files = true; @@ -79,25 +79,56 @@ message FileReferenceValue { // Allowable digests for the file. Digests digests = 1; - // Absolute path to the file in question, or just the file name. Relative paths are - // not supported. + // Absolute path to the file in question, or just the file name. Relative + // paths are not supported. string path = 2; } -// Verifies that a particular string is equal to at least one of the specified ones. -// No checks are performed if this is empty. +// Verifies that a particular string is equal to at least one of the specified +// ones. No checks are performed if this is empty. message StringReferenceValue { + // Use TextReferenceValue instead. + option deprecated = true; + repeated string values = 1; } +message Regex { + string value = 1; +} + +// A match in at least onevalue is considered a success. At least one value must +// be specified, otherwise verification fails. +message StringLiterals { + repeated string value = 1; +} + +message RegexReferenceValue { + // Use TextReferenceValue instead. + option deprecated = true; + + oneof type { + SkipVerification skip = 1; + Regex regex = 2; + } +} + +message TextReferenceValue { + oneof type { + SkipVerification skip = 1; + Regex regex = 2; + StringLiterals string_literals = 3; + } +} + message RootLayerReferenceValues { // Switches between AMD SEV-SNP and Intel TDX based on TeePlatform value. // Verification is skipped when not running in a TEE. AmdSevReferenceValues amd_sev = 1; IntelTdxReferenceValues intel_tdx = 2; - // When insecure is set no verification of the TEE platform is performed. This can - // be used when not running in a TEE or when the client is agnostic about the - // platform and doesn't care about the hardware verification. + // When insecure is set no verification of the TEE platform is performed. This + // can be used when not running in a TEE or when the client is agnostic about + // the platform and doesn't care about the hardware verification. InsecureReferenceValues insecure = 3; } @@ -128,14 +159,15 @@ message KernelLayerReferenceValues { // Verifies the kernel based on endorsement. KernelBinaryReferenceValue kernel = 1; - // No longer used. Will be removed. - // TODO: b/325979696 - Validate the kernel command-line using a regex. - BinaryReferenceValue kernel_cmd_line = 2 [deprecated = true]; + // Validates the kernel command-line using either a string literal or a regex. + TextReferenceValue kernel_cmd_line_text = 9; - // Fields are deprecated and kept only for backwards compatibility. - // Remove ASAP. + // Fields are deprecated and kept only for backwards compatibility. They are + // not being used by the verifier. Remove ASAP. BinaryReferenceValue kernel_setup_data = 3 [deprecated = true]; BinaryReferenceValue kernel_image = 7 [deprecated = true]; + RegexReferenceValue kernel_cmd_line_regex = 8 [deprecated = true]; + BinaryReferenceValue kernel_cmd_line = 2 [deprecated = true]; // Verifies the stage1 binary if running as Oak Containers. BinaryReferenceValue init_ram_fs = 4; diff --git a/proto/attestation/tcb_version.proto b/proto/attestation/tcb_version.proto index 0b5f3024e80..359dbbe35ff 100644 --- a/proto/attestation/tcb_version.proto +++ b/proto/attestation/tcb_version.proto @@ -17,6 +17,10 @@ syntax = "proto3"; package oak.attestation.v1; +option go_package = "proto/oak/attestation/v1"; +option java_multiple_files = true; +option java_package = "com.google.oak.attestation.v1"; + // The versions of the components in the AMD SEV-SNP platform Trusted Compute // Base (TCB). message TcbVersion { diff --git a/proto/attestation/verification.proto b/proto/attestation/verification.proto index ea48ead7cb7..108163873cc 100644 --- a/proto/attestation/verification.proto +++ b/proto/attestation/verification.proto @@ -143,9 +143,15 @@ message KernelLayerData { // Measured digests of the command-line that was passed to the kernel // during startup. - // TODO: b/325979696 - Validate the kernel command-line using a regex. RawDigest kernel_cmd_line = 2 [deprecated = true]; + // Command-line that was passed to the kernel during startup. If absent, + // verification will only succeed with the corresponding reference value set + // to skip (for compatibility with the legacy version of the evidence + // producing code). Empty value corresponds to the kernel being run with an + // empty command line. + optional string kernel_raw_cmd_line = 7; + // Measured digests of the initial RAM disk. RawDigest init_ram_fs = 4; diff --git a/proto/containers/hostlib_key_provisioning.proto b/proto/containers/hostlib_key_provisioning.proto index 2b06cbfcb7d..a31f81a32ca 100644 --- a/proto/containers/hostlib_key_provisioning.proto +++ b/proto/containers/hostlib_key_provisioning.proto @@ -24,7 +24,7 @@ import "proto/key_provisioning/key_provisioning.proto"; enum KeyProvisioningRole { KEY_PROVISIONING_ROLE_UNSPECIFIED = 0; LEADER = 1; - DEPENDANT = 2; + FOLLOWER = 2; } message GetKeyProvisioningRoleResponse { @@ -40,11 +40,11 @@ service HostlibKeyProvisioning { // Get the enclave role for Key Provisioning. // Could be one of the following: // - Leader that generates group keys and distributes them. - // - Dependant that requests group keys from the leader. + // - Follower that requests group keys from the leader. rpc GetKeyProvisioningRole(google.protobuf.Empty) returns (GetKeyProvisioningRoleResponse) {} // Get enclave group keys to the enclave as part of Key Provisioning. - // This method is only called by the Dependant Orchestrator. + // This method is only called by the Follower Orchestrator. // // This method must be called after `oak.containers.Launcher.SendAttestationEvidence`, because // Hostlib needs to have the Attestation Evidence in order to request group keys from the leader. diff --git a/proto/oak_functions/BUILD b/proto/oak_functions/BUILD index e95489fc749..dda9e6fb446 100644 --- a/proto/oak_functions/BUILD +++ b/proto/oak_functions/BUILD @@ -42,6 +42,7 @@ proto_library( proto_library( name = "testing_proto", srcs = ["testing.proto"], + deps = ["//proto/micro_rpc:options_proto"], ) build_test( diff --git a/proto/oak_functions/sdk/oak_functions_wasm.proto b/proto/oak_functions/sdk/oak_functions_wasm.proto index f8ba90ef13e..d85561831b6 100644 --- a/proto/oak_functions/sdk/oak_functions_wasm.proto +++ b/proto/oak_functions/sdk/oak_functions_wasm.proto @@ -19,6 +19,7 @@ syntax = "proto3"; package oak.functions.wasm.v1; import "google/protobuf/wrappers.proto"; +import "proto/micro_rpc/options.proto"; // The standard API for Oak Functions, which is exposed to Wasm modules via micro RPC, and wrapped // by the Oak Functions SDK. @@ -30,7 +31,9 @@ service StdWasmApi { // This method is idempotent: multiple calls result in the same response. // // method_id: 0 - rpc ReadRequest(ReadRequestRequest) returns (ReadRequestResponse) {} + rpc ReadRequest(ReadRequestRequest) returns (ReadRequestResponse) { + option (.oak.micro_rpc.method_id) = 0; + } // Write a response for the client. // @@ -39,7 +42,9 @@ service StdWasmApi { // runtime sends an empty response to the client. // // method_id: 1 - rpc WriteResponse(WriteResponseRequest) returns (WriteResponseResponse) {} + rpc WriteResponse(WriteResponseRequest) returns (WriteResponseResponse) { + option (.oak.micro_rpc.method_id) = 1; + } // Writes a debug log message. // @@ -47,22 +52,30 @@ service StdWasmApi { // in debug mode. // // method_id: 2 - rpc Log(LogRequest) returns (LogResponse) {} + rpc Log(LogRequest) returns (LogResponse) { + option (.oak.micro_rpc.method_id) = 2; + } // Looks up an item from the in-memory key/value lookup store. // // method_id: 3 - rpc LookupData(LookupDataRequest) returns (LookupDataResponse) {} + rpc LookupData(LookupDataRequest) returns (LookupDataResponse) { + option (.oak.micro_rpc.method_id) = 3; + } // Looks up multiple items from the in-memory key/value lookup store. // // method_id: 4 - rpc LookupDataMulti(LookupDataMultiRequest) returns (LookupDataMultiResponse) {} + rpc LookupDataMulti(LookupDataMultiRequest) returns (LookupDataMultiResponse) { + option (.oak.micro_rpc.method_id) = 4; + } // Test method only. // // method_id: 128 - rpc Test(TestRequest) returns (TestResponse) {} + rpc Test(TestRequest) returns (TestResponse) { + option (.oak.micro_rpc.method_id) = 128; + } } message ReadRequestRequest {} diff --git a/proto/oak_functions/service/oak_functions.proto b/proto/oak_functions/service/oak_functions.proto index 812d752f50d..e574981dc28 100644 --- a/proto/oak_functions/service/oak_functions.proto +++ b/proto/oak_functions/service/oak_functions.proto @@ -20,17 +20,22 @@ package oak.functions; import "proto/crypto/crypto.proto"; import "proto/attestation/evidence.proto"; +import "proto/micro_rpc/options.proto"; service OakFunctions { // Initializes the service and remote attestation keys. // // method_id: 0 - rpc Initialize(InitializeRequest) returns (InitializeResponse); + rpc Initialize(InitializeRequest) returns (InitializeResponse) { + option (.oak.micro_rpc.method_id) = 0; + } // Handles an invocation coming from a client. // // method_id: 1 - rpc HandleUserRequest(InvokeRequest) returns (InvokeResponse); + rpc HandleUserRequest(InvokeRequest) returns (InvokeResponse) { + option (.oak.micro_rpc.method_id) = 1; + } // Extends the next lookup data by the given chunk of lookup data. Only // after the sender calls finishes building the next lookup data, the receiver replaces the @@ -38,25 +43,33 @@ service OakFunctions { // lookups. // // method_id: 2 - rpc ExtendNextLookupData(ExtendNextLookupDataRequest) returns (ExtendNextLookupDataResponse); + rpc ExtendNextLookupData(ExtendNextLookupDataRequest) returns (ExtendNextLookupDataResponse) { + option (.oak.micro_rpc.method_id) = 2; + } // Finishes building the next lookup data with the given chunk of lookup data. The receiver // replaces the current lookup data and the next lookup data will be served in lookups. // // method_id: 3 - rpc FinishNextLookupData(FinishNextLookupDataRequest) returns (FinishNextLookupDataResponse); + rpc FinishNextLookupData(FinishNextLookupDataRequest) returns (FinishNextLookupDataResponse) { + option (.oak.micro_rpc.method_id) = 3; + } // Aborts building the next lookup data.option // // method_id: 4 - rpc AbortNextLookupData(Empty) returns (AbortNextLookupDataResponse); + rpc AbortNextLookupData(Empty) returns (AbortNextLookupDataResponse) { + option (.oak.micro_rpc.method_id) = 4; + } // Streaming version combining `ExtendNextLookupData` and `FinishNextLookupData`. // // This is mainly for use with gRPC, as microRPC doesn't support streaming. // // method_id: 5 - rpc StreamLookupData(stream LookupDataChunk) returns (FinishNextLookupDataResponse); + rpc StreamLookupData(stream LookupDataChunk) returns (FinishNextLookupDataResponse) { + option (.oak.micro_rpc.method_id) = 5; + } // Reserves additional capacity for entries in the lookup table. // @@ -64,7 +77,9 @@ service OakFunctions { // number of memory allocations, but it's not mandatory to call this RPC. // // method_id: 6 - rpc Reserve(ReserveRequest) returns (ReserveResponse); + rpc Reserve(ReserveRequest) returns (ReserveResponse) { + option (.oak.micro_rpc.method_id) = 6; + } } message InitializeRequest { diff --git a/proto/session/BUILD b/proto/session/BUILD index b92faa7f5f6..c790d87e75c 100644 --- a/proto/session/BUILD +++ b/proto/session/BUILD @@ -75,6 +75,7 @@ cc_proto_library( cc_grpc_library( name = "service_unary_cc_grpc", srcs = [":service_unary_proto"], + generate_mocks = True, grpc_only = True, deps = [":service_unary_cc_proto"], ) diff --git a/stage0/src/sev.rs b/stage0/src/sev.rs index 9c9942c64df..94d31522eb3 100644 --- a/stage0/src/sev.rs +++ b/stage0/src/sev.rs @@ -19,6 +19,7 @@ use core::{ alloc::{AllocError, Allocator, Layout}, ops::{Deref, DerefMut}, ptr::NonNull, + sync::atomic::{AtomicUsize, Ordering}, }; use oak_core::sync::OnceCell; @@ -230,7 +231,7 @@ pub fn unshare_page(page: Page) { } tlb::flush_all(); // We have to revalidate the page again after un-sharing it. - if let Err(err) = page.pvalidate() { + if let Err(err) = page.pvalidate(&counters::VALIDATED_4K) { if err != InstructionError::ValidationStatusNotUpdated { panic!("shared page revalidation failed"); } @@ -256,12 +257,14 @@ impl ValidatablePageSize for Size2MiB { } trait Validate { - fn pvalidate(&self) -> Result<(), InstructionError>; + fn pvalidate(&self, counter: &AtomicUsize) -> Result<(), InstructionError>; } impl Validate for Page { - fn pvalidate(&self) -> Result<(), InstructionError> { - pvalidate(self.start_address().as_u64() as usize, S::SEV_PAGE_SIZE, Validation::Validated) + fn pvalidate(&self, counter: &AtomicUsize) -> Result<(), InstructionError> { + pvalidate(self.start_address().as_u64() as usize, S::SEV_PAGE_SIZE, Validation::Validated)?; + counter.fetch_add(1, Ordering::SeqCst); + Ok(()) } } @@ -285,6 +288,7 @@ fn pvalidate_range( memory: &mut MappedPage, encrypted: u64, flags: PageTableFlags, + success_counter: &AtomicUsize, mut f: F, ) -> Result<(), InstructionError> where @@ -324,7 +328,7 @@ where .iter() .zip(pages) .filter(|(entry, _)| !entry.is_unused()) - .map(|(entry, page)| (entry, page.pvalidate())) + .map(|(entry, page)| (entry, page.pvalidate(success_counter))) .map(|(entry, result)| result.or_else(|err| f(entry.addr(), err))) .find(|result| result.is_err()) { @@ -338,6 +342,23 @@ where Ok(()) } +pub mod counters { + use core::sync::atomic::AtomicUsize; + + /// Number of PVALIDATE invocations that did not change Validated state. + pub static ERROR_VALIDATION_STATUS_NOT_UPDATED: AtomicUsize = AtomicUsize::new(0); + + /// Number of FAIL_SIZEMISMATCH errors when invoking PVALIDATE on 2 MiB + /// pages. + pub static ERROR_FAIL_SIZE_MISMATCH: AtomicUsize = AtomicUsize::new(0); + + /// Number of successful PVALIDATE invocations on 2 MiB pages. + pub static VALIDATED_2M: AtomicUsize = AtomicUsize::new(0); + + /// Number of successful PVALIDATE invocations on 4 KiB pages. + pub static VALIDATED_4K: AtomicUsize = AtomicUsize::new(0); +} + trait Validatable4KiB { /// Validate a region of memory using 4 KiB pages. /// @@ -357,15 +378,23 @@ impl Validatable4KiB for PhysFrameRange { pt: &mut MappedPage, encrypted: u64, ) -> Result<(), InstructionError> { - pvalidate_range(self, pt, encrypted, PageTableFlags::empty(), |_addr, err| match err { - InstructionError::ValidationStatusNotUpdated => { - // We don't treat this as an error. It only happens if SEV-SNP is not enabled, - // or it is already validated. See the PVALIDATE instruction in - // for more details. - Ok(()) - } - other => Err(other), - }) + pvalidate_range( + self, + pt, + encrypted, + PageTableFlags::empty(), + &counters::VALIDATED_4K, + |_addr, err| match err { + InstructionError::ValidationStatusNotUpdated => { + // We don't treat this as an error. It only happens if SEV-SNP is not enabled, + // or it is already validated. See the PVALIDATE instruction in + // for more details. + counters::ERROR_VALIDATION_STATUS_NOT_UPDATED.fetch_add(1, Ordering::SeqCst); + Ok(()) + } + other => Err(other), + }, + ) } } @@ -393,26 +422,35 @@ impl Validatable2MiB for PhysFrameRange { pt: &mut MappedPage, encrypted: u64, ) -> Result<(), InstructionError> { - pvalidate_range(self, pd, encrypted, PageTableFlags::HUGE_PAGE, |addr, err| match err { - InstructionError::FailSizeMismatch => { - // 2MiB is no go, fail back to 4KiB pages. - // This will not panic as every address that is 2 MiB-aligned is by definition - // also 4 KiB-aligned. - let start = PhysFrame::::from_start_address(PhysAddr::new( - addr.as_u64() & !encrypted, - )) - .unwrap(); - let range = PhysFrame::range(start, start + 512); - range.pvalidate(pt, encrypted) - } - InstructionError::ValidationStatusNotUpdated => { - // We don't treat this as an error. It only happens if SEV-SNP is not enabled, - // or it is already validated. See the PVALIDATE instruction in - // for more details. - Ok(()) - } - other => Err(other), - }) + pvalidate_range( + self, + pd, + encrypted, + PageTableFlags::HUGE_PAGE, + &counters::VALIDATED_2M, + |addr, err| match err { + InstructionError::FailSizeMismatch => { + // 2MiB is no go, fail back to 4KiB pages. + // This will not panic as every address that is 2 MiB-aligned is by definition + // also 4 KiB-aligned. + counters::ERROR_FAIL_SIZE_MISMATCH.fetch_add(1, Ordering::SeqCst); + let start = PhysFrame::::from_start_address(PhysAddr::new( + addr.as_u64() & !encrypted, + )) + .unwrap(); + let range = PhysFrame::range(start, start + 512); + range.pvalidate(pt, encrypted) + } + InstructionError::ValidationStatusNotUpdated => { + // We don't treat this as an error. It only happens if SEV-SNP is not enabled, + // or it is already validated. See the PVALIDATE instruction in + // for more details. + counters::ERROR_VALIDATION_STATUS_NOT_UPDATED.fetch_add(1, Ordering::SeqCst); + Ok(()) + } + other => Err(other), + }, + ) } } @@ -487,6 +525,16 @@ pub fn validate_memory(e820_table: &[BootE820Entry], encrypted: u64) { page_tables.pdpt[1].set_unused(); tlb::flush_all(); log::info!("SEV-SNP memory validation complete."); + log::info!(" Validated using 2 MiB pages: {}", counters::VALIDATED_2M.load(Ordering::SeqCst)); + log::info!(" Validated using 4 KiB pages: {}", counters::VALIDATED_4K.load(Ordering::SeqCst)); + log::info!( + " Valid state not updated: {}", + counters::ERROR_VALIDATION_STATUS_NOT_UPDATED.load(Ordering::SeqCst) + ); + log::info!( + " RMP page size mismatch errors (fallback to 4K): {}", + counters::ERROR_FAIL_SIZE_MISMATCH.load(Ordering::SeqCst) + ); } /// Initializes the Guest Message encryptor using VMPCK0. diff --git a/stage0_bin/build.rs b/stage0_bin/build.rs index 58ee6bffb5b..e526062d6ab 100644 --- a/stage0_bin/build.rs +++ b/stage0_bin/build.rs @@ -21,9 +21,10 @@ fn main() { println!("cargo:rerun-if-changed=layout.ld"); println!("cargo:rustc-link-arg=--script=layout.ld"); + #[allow(clippy::if_same_then_else)] if env::var("PROFILE").unwrap() == "release" { - println!("cargo:rustc-link-arg=--defsym=BIOS_SIZE=256K"); + println!("cargo:rustc-link-arg=--defsym=BIOS_SIZE=2M"); } else { - println!("cargo:rustc-link-arg=--defsym=BIOS_SIZE=2048K"); + println!("cargo:rustc-link-arg=--defsym=BIOS_SIZE=2M"); } } diff --git a/testing/oak_echo_service/proto/oak_echo.proto b/testing/oak_echo_service/proto/oak_echo.proto index 6c33aa879bd..cabfedb8700 100644 --- a/testing/oak_echo_service/proto/oak_echo.proto +++ b/testing/oak_echo_service/proto/oak_echo.proto @@ -20,6 +20,7 @@ package oak.echo; import "google/protobuf/empty.proto"; import "proto/attestation/evidence.proto"; +import "proto/micro_rpc/options.proto"; message EchoRequest { bytes body = 1; @@ -35,8 +36,12 @@ message GetEvidenceResponse { service Echo { // method_id: 1988 - rpc Echo(EchoRequest) returns (EchoResponse); + rpc Echo(EchoRequest) returns (EchoResponse) { + option (.oak.micro_rpc.method_id) = 1988; + } // method_id: 1771 - rpc GetEvidence(google.protobuf.Empty) returns (GetEvidenceResponse); + rpc GetEvidence(google.protobuf.Empty) returns (GetEvidenceResponse) { + option (.oak.micro_rpc.method_id) = 1771; + } } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 0b3ff352fc0..70b9d7a246f 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -638,7 +638,14 @@ fn run_bazel_build() -> Step { name: "bazel build".to_string(), command: Cmd::new( "bazel", - ["build", "--", "//java/...:all", "//cc/...:all", "//proto/...:all"], + [ + "build", + "--", + "//java/...:all", + "//cc/...:all", + "//proto/...:all", + "//oak_proto_rust", + ], ), } } @@ -648,7 +655,7 @@ fn run_bazel_test() -> Step { name: "bazel test".to_string(), command: Cmd::new( "bazel", - ["test", "--", "//java/...:all", "//cc/...:all", "//proto/...:all"], + ["test", "--", "//java/...:all", "//cc/...:all", "//proto/...:all", "//oak_proto_rust"], ), } }