Skip to content

Commit 104587c

Browse files
authored
Merge pull request #497 from Firstyear/20240210-sealed-data-objects
Add sealed data object example
2 parents 523396a + 3121d19 commit 104587c

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// Copyright 2020 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
/*
5+
* This example demonstrates how to create a sealed data object. A sealed data object allows
6+
* a small amount of data to be encrypted (sealed) by the tpm. To decrypt (unseal) the object
7+
* requires the parent of the object to be loaded, and other policies in the TPM to be met such
8+
* as PCR state or a valid authValue.
9+
*/
10+
11+
use tss_esapi::{
12+
attributes::ObjectAttributesBuilder,
13+
interface_types::{
14+
algorithm::{HashingAlgorithm, PublicAlgorithm},
15+
resource_handles::Hierarchy,
16+
},
17+
structures::{
18+
CreatePrimaryKeyResult, Digest, KeyedHashScheme, PublicBuilder, PublicKeyedHashParameters,
19+
SensitiveData, SymmetricCipherParameters, SymmetricDefinitionObject,
20+
},
21+
Context, TctiNameConf,
22+
};
23+
24+
use std::convert::TryFrom;
25+
26+
fn main() {
27+
// Create a new TPM context. This reads from the environment variable `TPM2TOOLS_TCTI` or `TCTI`
28+
//
29+
// It's recommended you use `TCTI=device:/dev/tpmrm0` for the linux kernel
30+
// tpm resource manager.
31+
let mut context = Context::new(
32+
TctiNameConf::from_environment_variable()
33+
.expect("Failed to get TCTI / TPM2TOOLS_TCTI from environment. Try `export TCTI=device:/dev/tpmrm0`"),
34+
)
35+
.expect("Failed to create Context");
36+
37+
// This example won't go over the process to create a new parent. For more detail see `examples/hmac.rs`.
38+
39+
let primary = create_primary(&mut context);
40+
41+
// Sensitive data is the value we want to seal. It's maximum size is determined by
42+
// SensitiveData::MAX_SIZE. If the data you wish to seal is larger than this size you may
43+
// want to seal a symmetric key that encrypts the data instead.
44+
let sensitive_data = SensitiveData::try_from(vec![
45+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
46+
25, 26, 27, 28, 29, 30, 31,
47+
])
48+
.unwrap();
49+
50+
// A sealed data object is a specialised form of a HMAC key. There are strict requirements for
51+
// the object attributes and algorithms to signal to the TPM that this is a sealed data object.
52+
let object_attributes = ObjectAttributesBuilder::new()
53+
.with_fixed_tpm(true)
54+
.with_fixed_parent(true)
55+
.with_st_clear(true)
56+
// To access the sealed data we require user auth or policy. In this example we
57+
// set a null authValue.
58+
.with_user_with_auth(true)
59+
// Must be clear (not set). This is because the sensitive data is
60+
// input from an external source.
61+
// .with_sensitive_data_origin(true)
62+
// For sealed data, none of sign, decrypt or restricted can be set. This indicates
63+
// the created object is a sealed data object.
64+
// .with_decrypt(false)
65+
// .with_restricted(false)
66+
// .with_sign_encrypt(false)
67+
.build()
68+
.expect("Failed to build object attributes");
69+
70+
let key_pub = PublicBuilder::new()
71+
// A sealed data object is an HMAC key with a NULL hash scheme.
72+
.with_public_algorithm(PublicAlgorithm::KeyedHash)
73+
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
74+
.with_object_attributes(object_attributes)
75+
.with_keyed_hash_parameters(PublicKeyedHashParameters::new(KeyedHashScheme::Null))
76+
.with_keyed_hash_unique_identifier(Digest::default())
77+
.build()
78+
.unwrap();
79+
80+
let (enc_private, public) = context
81+
.execute_with_nullauth_session(|ctx| {
82+
// Create the sealed data object. The encrypted private component is now encrypted and
83+
// contains our data. Like any other TPM object, to load this we require the public
84+
// component as well. Both should be persisted for future use.
85+
ctx.create(
86+
primary.key_handle,
87+
key_pub,
88+
None,
89+
Some(sensitive_data.clone()),
90+
None,
91+
None,
92+
)
93+
.map(|key| (key.out_private, key.out_public))
94+
})
95+
.unwrap();
96+
97+
let unsealed = context
98+
.execute_with_nullauth_session(|ctx| {
99+
// When we wish to unseal the data, we must load this object like any other meeting
100+
// any policy or authValue requirements.
101+
let sealed_data_object = ctx
102+
.load(primary.key_handle, enc_private.clone(), public.clone())
103+
.unwrap();
104+
105+
ctx.unseal(sealed_data_object.into())
106+
})
107+
.unwrap();
108+
109+
// We can now assert that we correctly unsealed our data.
110+
println!("sensitive_data = {:?}", sensitive_data);
111+
println!("unsealed_data = {:?}", unsealed);
112+
assert_eq!(unsealed, sensitive_data);
113+
}
114+
115+
fn create_primary(context: &mut Context) -> CreatePrimaryKeyResult {
116+
let object_attributes = ObjectAttributesBuilder::new()
117+
.with_fixed_tpm(true)
118+
.with_fixed_parent(true)
119+
.with_st_clear(false)
120+
.with_sensitive_data_origin(true)
121+
.with_user_with_auth(true)
122+
.with_decrypt(true)
123+
.with_restricted(true)
124+
.build()
125+
.expect("Failed to build object attributes");
126+
127+
let primary_pub = PublicBuilder::new()
128+
.with_public_algorithm(PublicAlgorithm::SymCipher)
129+
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
130+
.with_object_attributes(object_attributes)
131+
.with_symmetric_cipher_parameters(SymmetricCipherParameters::new(
132+
SymmetricDefinitionObject::AES_128_CFB,
133+
))
134+
.with_symmetric_cipher_unique_identifier(Digest::default())
135+
.build()
136+
.unwrap();
137+
138+
context
139+
.execute_with_nullauth_session(|ctx| {
140+
ctx.create_primary(Hierarchy::Owner, primary_pub, None, None, None, None)
141+
})
142+
.unwrap()
143+
}

0 commit comments

Comments
 (0)