Skip to content

oxidecomputer/vm-attest-proto

Repository files navigation

This repo hosts a prototype interface for interacting with a still notional API. This API is intended to extend our attestation architecture to:

  • capture some limited state describing the virtual machine
  • provide a mechanism for the VM to bind data to the attestation

This repo also provides a mock implementation of this interface to facility early prototyping and development.

API Consumer

The intended consumers of this interface are VM instances. We provide a mechanism for these instances to associate both a nonce and a user defined blob (aka "user data") with attestations produced by the Oxide platform RoT. The nonce is intended to be a value generated by an off-platform challenger as a means to prove freshness. This requires that nonce values are never reused. The user defined blob is intended to be the public part of an asymmetric cryptographic key generated by the instance.

API Provider

The other end of this API will be handled by the propolis process dedicated to the VM instance and operating on its behalf. propolis is responsible for receiving the nonce & user data. It will then combine this information with a set of data that describes the VMs configuration at the time it was launched. propolis will combine this data using a 32 byte digest as follows:

digest(vm_cfg | nonce | user_data)

vm_cfg is defined as the concatenation of all elements from the set describing the VMs configuration at launch. Our initial / v1 implementation is limited to:

  • UUID assigned to the VM instance by the oxide control plane on launch serialized as 16 bytes
  • sha256 digest of the disk image assigned to / used to boot the VM instance serialized as 32 bytes

Additional data may be included in vm_cfg as our implementation progresses.

Mock Impl

The mock implementation of this interface is intended to mimic the behavior we expect from propolis described in API Provider. This impl must be provided with the the vm_cfg data when it is instantiated. The test module that drives the mock impl uses static data from test-data/vm-instance-cfg.json.

propolis will itself call into the Oxide platform RoT to obtain attestations for its measurement log. Our mock of the API Provider uses the mock implementation of this RoT that we use elsewhere in testing. The test module again relies on static data found in:

These files are plain text specifications of the PKI and measurement log. Before they are useful to the Oxide platform mock impl they must be processed to generate keys and encodings of various structures.

build.rs

The build.rs file in this repo is responsible for generating data used by the mock impls in this repo and putting the generated data in a place the library can find it. This requires that the system building and running the tests in this repo have a few tools installed in advance. This integration is unfortunately ad-hoc executing external commands. This prevents us from using cargo to track these dependencies so they must be installed by hand (cargo install).

pki-playground

The pki-playground source is here: https://github.com/oxidecomputer/pki-playground. This tool interprets a textual description of a PKI hierarchy generating keys, certs, and certificate chains / pki paths per the spec. The mock implementation of the Oxide platform RoT consumes these artifacts using a generated key to sign attestations while producing the associated cert chain on demand for verification. Paths to these outputs are stored in a generated rust file config.rs that are consumed by the mock_impl.

attest-mock

The attest-mock source is here: https://github.com/oxidecomputer/dice-util/tree/main/attest-mock. This tool interprets textual descriptions of:

  • the measurement log produced by the Oxide platform RoT
  • the CoRIM documents used to appraise measurments from the log. The mock implementation of the Oxide platform RoT consumes the generated measurement log providing it to callers of its get_measurement_log function. Tests in the test module then use the generated CoRIM as reference measurements in the measurement log appraisal process. Again, paths to these outputs are stored in a generated rust file config.rs that are consumed by the mock_impl.

Tests

The majority of the code in this repo are tests. These tests are intended to:

  • exercise the mock impl of the trait as described in (Mock Impl)[#mock-impl)
  • demonstrate the steps necessary for a relying party to:

Exercising the mock impl requires that the caller generate a nonce and some blob of data to satisfy the API. The rest is just function calls. Verification and appraisal are more interesting:

Cert Chain Verification

The API Provider doesn't generate an attestation directly. Instead it associates the VM instance properties that it observes with an attestation produced by the Oxide platform RoT. The API Consumer must then verify the cert chain from the Oxide platform RoT. This is a process that Oxide implements in our Trust Quorum protocol and the tests in this repo rely on this implementation from https://github.com/oxidecomputer/dice-util/tree/main/verifier.

Attestation Verification

To verify an attestation produced by the (API Provider)[#api-provider] the resultant attestation the test code must first reconstruct the data signed by the underlying Oxide platform RoT. This requires that the test first reconstruct the digest computed by the (API Provider)[#api-provider]. To do so the test (acting as the challenger) must know the expected UUID and image digest in advance. The UUID is obtained by the some software that started the execution of the VM. This must be communicated to the challenger through some process outside of the Oxide system. Similarly the challenger is assumed to get the expected digest of the VM image through some build & publication process that is again, external to the Oxide system. We mock the reference data using same static data used to construct the (Mock Impl)[#mock-impl]: test-data/vm-instance-cfg.json.

The attestation returned to the API Consumer also includes the serialized measurement log from the Oxide platform RoT. This is obtained from the API Provider and is the same mock data produced by the build.rs. The final value signed by the Oxide platform RoT can then be reconstructed as:

digest(hubpack(log) | vm_cfg | nonce | user_data)

To verify this message the test uses the public key from the leaf cert in the cert chain produced by the get_cert_chain function implemented by the API Provider.

Appraisal

The definition of vm_cfg from API Provider requires the consumer know both the expected UUID and image digest in order to verify the attestation. If the verification is successful then both of these values have effectively been appraised. The remaining measurements from the Oxide platform RoT are appraised through a separate process.

The hubpack(log) value is reconstructed from the measurement log produced by the Oxide platform RoT and forwarded to the consumer via the get_measurement_logs function. Verifying the attestation guarantees that the log obtained from this function is the same one included in the attestation. Additional work is required to determine whether or not the software identified in the log is trustworthy.

As part of our software release process we generate reference integrity manifests for the relevant binaries. These manifests are used by the appraisal process to identify the software running on the system. The appraisal test relies on a reference integrity manifest generated by build.rs and described in attest-mock. The measurements from this manifest correspond to the mock values found in test-data/config.kdl and test-data/log.kdl

The measurement log from the Oxide platform RoT is a simple list of digests each representing the identity of a software component executed as part of the boot process. We obtain an additional measurement of early boot software from the cert chain produced by this RoT. These two collections of measurements are combined and the resultant set compared to the available reference integrity measurements. Any measurements from the log that cannot be found in the manifests known to the appraiser results in a failure. This test relies on the implementation from https://github.com/oxidecomputer/dice-util/blob/main/verifier/.

About

prototype interface for attesting to VM state

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages