2.3 An Abstraction of the Trusted Computing Component
2.3.1 TCC interface
The primitives that constitute our TCC interface are depicted in Figure 2.2, also showing which code calls each primitive—and from what execution environment. The interface logically extends through different execution environments, namely: in the untrusted environment of the cloud provider, untrusted code is allowed to (call a primitive to) trigger an isolated execution; in the trusted environment of the cloud provider, code executing in isolation can make the TCC per- form a code identity attestation, for example; finally, the remote client can perform an attestation verification to make a trust decision.
A natural question is whether such an interface is complete, i.e., whether the code executed either using XMHF-TrustVisor or Intel SGX would look the same, or additional primitives are necessary. The answer is that the interface is almost complete. Two additional mechanisms, for exiting the execution environment and accepting memory, are required and can be easily imple- mented. At the user-level, both require a simple “return” from a function in XMHF-TrustVisor,
Chapter
Primitives Parameters
3 4 5 input output
3 3 3 execute code, input data output data
3 3 3 attest input and output data identities, nonce attestation
3 3 3 verify∗
remote attestation, code identity,
0/1 (false or true) input and output data identities,
nonce, certified TCC public key
3 auth put recipient code identity, plain text data encrypted data 3 auth get caller code identity, encrypted data plain text data
3 create cnt
service identifier
0
3 get cnt counter value
3 incr cnt counter value +1
3† 3† 3 get cert (none) TCC’s certificate
∗
implemented at the client †not used explicitly, but assumed in the model
Table 2.1: Primitives used in this thesis. The columns indicate: the name of the primitive, the input and output parameters, the chapter (and so the technique) where a specific primitive is used.
though a special instruction in SGX. Hence, simple wrappers can solve the issue. The implemen- tation of LaStGTin Chapter4will elaborate more on this. We do not include these implementa- tion details in the interface to simplify the description.
Our trusted execution primitives are detailed in Table2.1. The primitives do not include the enhancements that are presented in later chapters of this thesis.
Beginning from the “Chapter” columns, we highlight that the primitives execute, attest and verify are common throughout the techniques in this thesis; auth put and auth get are exclusively used to enable our technique (Chapter3) for executing large code bases; create cnt, get cnt and incr cnt are specifically required for secure and available passively replicated executions (Chap- ter5). We remark that get cert is explicitly used in Chapter5while the other techniques implicitly use it by assuming its functionality in their respective system models.
Next, we briefly describe each primitive and then present their implementations.
• execute makes the TCC execute a code over some input data and eventually returns a result as output. Both the code and the input data are provided as input parameters. The TCC is responsible to identify the input code by hashing its binary and to store the identity securely in an internal register. This identity is then used for code attestation.
We point out that the code to be executed is self-contained. This is a natural requirement since the execution environment is strongly isolated and the code cannot rely on untrusted code, which is outside the trusted computing base (TCB), so neither identified by the TCC nor verified
by the client. For example, although it would be tempting to enable system calls to the untrusted OS from the isolated environment, this would enlarge the attack surface with hundreds of system calls that are difficult to secure, making the system susceptible to Iago attacks [97] (i.e., system calls that return values crafted by a malicious kernel so to induce the running code to undertake an arbitrary computation). Hence, any service application executed on the TCC needs to be self- contained, i.e., with statically linked libraries and no OS dependencies.
• attest makes the TCC produce an attestation using the TCC’s private key over the identity of the code (say c), which is loaded and identified through the execute primitive. The attestation allows binding the identities (or integrity measurements) of the input and output data together with the identity of the code c, which is running on the TCC. The input data includes a client- provided nonce and it is received by the code through the execute primitive, while the output data is the result of the execution of c. The executing code c is responsible (and must be programmed) to compute the integrity measurements (i.e., hashes) of the input and output data before calling the attest primitive and supplying these measurements as parameters.
• verify is implemented at the client and accepts as input an attestation and the respective nonce, a certificate that vouches for the TCC’s public attestation key, and the execution param- eters such as the code identity and the measurements of the input and output data. In XMHF- TrustVisor, the TCC’s public attestation key belongs to the hypervisor; the key and the hypervisor identity are verified using a TPM attestation. The verification is successful and returns true if the TCC’s public key is certified by a trusted Certification Authority and the provided parameters are the intended ones. Otherwise, it returns false and the client can make the decision to reject the received results.
So far we have describe the basic primitives for trusted executions, that simply allow to exe- cute, attest and verify some code. We remark that our contribution in Chapter4only uses these primitives, though an enhanced version of execute that we describe later. Next, we extend this basic set with primitives for secure storage and trusted counters. The primitives for secure stor- age, also enhanced later, enable our contribution in Chapter3, while those for trusted counters enable our contribution in Chapter5.
• auth put and auth get provide functionality for identity-dependent secure storage using a secret key stored inside the TCC. The former (auth put) allows to protect some input data on the behalf of the currently running code. It requires the code running on the TCC to specify the identity of a recipient code that is allowed to retrieve the data when the recipient code will later execute on the TCC. Similarly, the latter (auth get) allows to validate some protected input data. It
requires the code running on the TCC to specify the identity of the previously executed code that originally put the data in secure storage. Notice that both primitives work with the identities of the sender and of the recipient code, so the data is bound to two identities. Also, the TCC directly computes the sender code identity in auth put and the recipient code identity in auth get, so the identity of the running code is always included by the TCC.
• create cnt, incr cnt and incr cnt provide functionality for trusted counter management. In particular, the TCC creates, stores and modifies pairs of (counter identifier cid, value), where the identifier depends on the running code’s identity (computed by the TCC) and defined as cid ← h(code identity||sid). Here the sid represents a service identifier. All the primitives thus accept a sid as input and finally return the last or the incremented counter value.
• get cert returns the public key (or the certificate) of the TCC. Such key enables a remote party to verify the attestations issued by the TCC. It should be signed such that the resulting trust anchor is a trusted root certification authority—possibly the manufacturer of the trusted hardware component.