Skip to content

Commit 9b21b16

Browse files
committed
WIP: Create credentials
Signed-off-by: Arthur Gautier <[email protected]>
1 parent 7e73a1e commit 9b21b16

File tree

7 files changed

+526
-2
lines changed

7 files changed

+526
-2
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@ p192 = { git = "https://github.com/RustCrypto/elliptic-curves.git" }
77
p224 = { git = "https://github.com/RustCrypto/elliptic-curves.git" }
88
sm2 = { git = "https://github.com/RustCrypto/elliptic-curves.git" }
99

10+
# https://github.com/RustCrypto/KDFs/pull/108
11+
kbkdf = { git = "https://github.com/TheBestTvarynka/KDFs.git", branch = "feat/kbkdf" }
12+
concat-kdf = { git = "https://github.com/RustCrypto/KDFs.git" }
13+
14+
cfb-mode = { git = "https://github.com/RustCrypto/block-modes.git" }

tss-esapi/Cargo.toml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@ regex = "1.3.9"
3535
zeroize = { version = "1.5.7", features = ["zeroize_derive"] }
3636
tss-esapi-sys = { path = "../tss-esapi-sys", version = "0.5.0" }
3737
x509-cert = { version = "0.3.0-pre.0", optional = true }
38+
aes = { version = "0.9.0-pre.2", optional = true }
39+
cfb-mode = { version = "0.9.0-pre", optional = true }
3840
ecdsa = { version = "0.17.0-pre.9", features = ["der", "hazmat", "arithmetic", "verifying"], optional = true }
3941
elliptic-curve = { version = "0.14.0-rc.1", optional = true, features = ["alloc", "pkcs8"] }
42+
hmac = { version = "0.13.0-pre.4", optional = true }
4043
p192 = { version = "0.14.0-pre", optional = true }
4144
p224 = { version = "0.14.0-pre", optional = true }
4245
p256 = { version = "0.14.0-pre.2", optional = true }
@@ -48,16 +51,21 @@ sha2 = { version = "0.11.0-pre.4", optional = true }
4851
sha3 = { version = "0.11.0-pre.4", optional = true }
4952
sm2 = { version = "0.14.0-pre", optional = true }
5053
sm3 = { version = "0.5.0-pre.4", optional = true }
54+
kbkdf = { version = "0.1.0", optional = true }
55+
concat-kdf = { version = "0.2.0-pre", optional = true }
5156
digest = "0.11.0-pre.9"
5257
signature = { version = "2.3.0-pre.4", features = ["std"], optional = true}
5358
cfg-if = "1.0.0"
5459
strum = { version = "0.26.3", optional = true }
5560
strum_macros = { version = "0.26.4", optional = true }
5661
paste = "1.0.14"
5762
getrandom = "0.2.11"
63+
rand = "0.8"
5864

5965
[dev-dependencies]
66+
aes = "0.9.0-pre.2"
6067
env_logger = "0.11.5"
68+
hex-literal = "0.4.1"
6169
serde_json = "^1.0.108"
6270
sha2 = { version = "0.11.0-pre.4", features = ["oid"] }
6371
tss-esapi = { path = ".", features = [
@@ -66,6 +74,7 @@ tss-esapi = { path = ".", features = [
6674
"abstraction",
6775
"rustcrypto-full",
6876
] }
77+
p256 = { version = "0.14.0-pre.2", features = ["ecdh"] }
6978
x509-cert = { version = "0.3.0-pre.0", features = ["builder"] }
7079

7180
[build-dependencies]
@@ -77,6 +86,6 @@ generate-bindings = ["tss-esapi-sys/generate-bindings"]
7786
abstraction = ["rustcrypto"]
7887
integration-tests = ["strum", "strum_macros"]
7988

80-
rustcrypto = ["ecdsa", "elliptic-curve", "signature", "x509-cert"]
81-
rustcrypto-full = ["rustcrypto", "p192", "p224", "p256", "p384", "p521", "rsa", "sha1", "sha2", "sha3", "sm2", "sm3"]
89+
rustcrypto = ["cfb-mode", "concat-kdf", "ecdsa", "elliptic-curve", "elliptic-curve/ecdh", "hmac", "kbkdf", "signature", "x509-cert"]
90+
rustcrypto-full = ["rustcrypto", "aes", "p192", "p224", "p256", "p384", "p521", "rsa", "sha1", "sha2", "sha3", "sm2", "sm3"]
8291

tss-esapi/src/utils/credential.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// Copyright 2019 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use aes::cipher::AsyncStreamCipher;
5+
use cfb_mode::cipher::BlockCipherEncrypt;
6+
use core::{
7+
marker::PhantomData,
8+
ops::{Add, Mul},
9+
};
10+
use digest::{
11+
array::ArraySize,
12+
consts::{B1, U8},
13+
crypto_common::{Iv, KeyIvInit, KeySizeUser},
14+
typenum::{
15+
operator_aliases::{Add1, Sum},
16+
Unsigned,
17+
},
18+
Digest, FixedOutputReset, KeyInit, Mac, OutputSizeUser,
19+
};
20+
use ecdsa::elliptic_curve::{
21+
ecdh::{EphemeralSecret, SharedSecret},
22+
sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint},
23+
AffinePoint, Curve, CurveArithmetic, FieldBytesSize, PublicKey,
24+
};
25+
use hmac::{EagerHash, Hmac};
26+
use rand::thread_rng;
27+
28+
use crate::{
29+
structures::{EncryptedSecret, IdObject, Name},
30+
utils::kdf::{self},
31+
};
32+
33+
// [`TpmHmac`] intends to code for the key expected for hmac
34+
// in the KDFa and KDFe derivations. There are no standard sizes for hmac keys really,
35+
// upstream RustCrypto considers it to be [BlockSize], but TPM specification
36+
// has a different opinion on the matter, and expect the key to the output
37+
// bit size of the hash algorithm used.
38+
//
39+
// See https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=202
40+
// section 24.5 HMAC:
41+
// bits the number of bits in the digest produced by ekNameAlg
42+
//
43+
// [BlockSize]: https://docs.rs/hmac/0.12.1/hmac/struct.HmacCore.html#impl-KeySizeUser-for-HmacCore%3CD%3E
44+
struct TpmHmac<H>(PhantomData<H>);
45+
46+
impl<H> KeySizeUser for TpmHmac<H>
47+
where
48+
H: OutputSizeUser,
49+
{
50+
type KeySize = H::OutputSize;
51+
}
52+
53+
pub fn make_credential_ecc<C, EkHash, EkCipher>(
54+
ek_public: PublicKey<C>,
55+
secret: &[u8],
56+
key_name: Name,
57+
) -> (IdObject, EncryptedSecret)
58+
where
59+
C: Curve + CurveArithmetic,
60+
61+
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
62+
FieldBytesSize<C>: ModulusSize,
63+
64+
<FieldBytesSize<C> as Add>::Output: Add<FieldBytesSize<C>>,
65+
Sum<FieldBytesSize<C>, FieldBytesSize<C>>: ArraySize,
66+
Sum<FieldBytesSize<C>, FieldBytesSize<C>>: Add<U8>,
67+
Sum<Sum<FieldBytesSize<C>, FieldBytesSize<C>>, U8>: Add<B1>,
68+
Add1<Sum<Sum<FieldBytesSize<C>, FieldBytesSize<C>>, U8>>: ArraySize,
69+
70+
EkHash: Digest + EagerHash + FixedOutputReset,
71+
<EkHash as OutputSizeUser>::OutputSize: Mul<U8>,
72+
<<EkHash as OutputSizeUser>::OutputSize as Mul<U8>>::Output: Unsigned,
73+
<<EkHash as EagerHash>::Core as OutputSizeUser>::OutputSize: ArraySize + Mul<U8>,
74+
<<<EkHash as EagerHash>::Core as OutputSizeUser>::OutputSize as Mul<U8>>::Output: Unsigned,
75+
76+
EkCipher: KeySizeUser + BlockCipherEncrypt + KeyInit,
77+
<EkCipher as KeySizeUser>::KeySize: Mul<U8>,
78+
<<EkCipher as KeySizeUser>::KeySize as Mul<U8>>::Output: ArraySize,
79+
{
80+
let mut rng = thread_rng();
81+
82+
// See Table 22 - Key Generation for the various labels used here after:
83+
// https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=183
84+
85+
// C.6.4. ECC Secret Sharing for Credentials
86+
// https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=311
87+
let local = EphemeralSecret::<C>::random(&mut rng);
88+
89+
let ecdh_secret: SharedSecret<C> = local.diffie_hellman(&ek_public);
90+
let local_public = local.public_key();
91+
drop(local);
92+
93+
let seed = kdf::kdfe::<kdf::Identity, EkHash, C, TpmHmac<EkHash>>(
94+
&ecdh_secret,
95+
&local_public,
96+
&ek_public,
97+
);
98+
drop(ecdh_secret);
99+
100+
// The local ECDH pair is used as "encrypted seed"
101+
let encrypted_seed = {
102+
let mut out = vec![];
103+
out.extend_from_slice(&FieldBytesSize::<C>::U16.to_be_bytes()[..]);
104+
out.extend_from_slice(&local_public.to_encoded_point(false).x().unwrap());
105+
out.extend_from_slice(&FieldBytesSize::<C>::U16.to_be_bytes()[..]);
106+
out.extend_from_slice(&local_public.to_encoded_point(false).y().unwrap());
107+
out
108+
};
109+
110+
// Prepare the sensitive data
111+
// this will be then encrypted using AES-CFB (size of the symmetric key depends on the EK).
112+
let mut sensitive_data = {
113+
let mut out = vec![];
114+
out.extend_from_slice(&u16::try_from(secret.len()).unwrap().to_be_bytes()[..]);
115+
out.extend_from_slice(secret);
116+
out
117+
};
118+
119+
// We'll now encrypt the sensitive data, and hmac the result of the encryption
120+
// https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=201
121+
// See 24.4 Symmetric Encryption
122+
let sym_key = kdf::kdfa::<EkHash, kdf::Storage, EkCipher>(&seed, key_name.value(), &[]);
123+
124+
// TODO(baloo): once the weak key detection merges
125+
// https://github.com/RustCrypto/traits/pull/1739
126+
// https://github.com/RustCrypto/block-ciphers/pull/465
127+
//
128+
// We should check for weak keys, and re-run all the steps above until we get a non-weak key
129+
// this is to be in compliance with TPM spec section 11.4.10.4:
130+
// https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=82
131+
132+
let iv: Iv<cfb_mode::Encryptor<EkCipher>> = Default::default();
133+
134+
cfb_mode::Encryptor::<EkCipher>::new(&sym_key.into(), &iv.into()).encrypt(&mut sensitive_data);
135+
136+
// See 24.5 HMAC
137+
let hmac_key = kdf::kdfa::<EkHash, kdf::Integrity, TpmHmac<EkHash>>(&seed, &[], &[]);
138+
let mut hmac = Hmac::<EkHash>::new_from_slice(&hmac_key).unwrap();
139+
hmac.update(&sensitive_data);
140+
hmac.update(key_name.value());
141+
let hmac = hmac.finalize();
142+
143+
// We'll now serialize the object and get everything through the door.
144+
let mut out = vec![];
145+
out.extend_from_slice(
146+
&u16::try_from(hmac.into_bytes().len())
147+
.unwrap()
148+
.to_be_bytes()[..],
149+
);
150+
out.extend_from_slice(&hmac.into_bytes());
151+
out.extend_from_slice(&sensitive_data);
152+
153+
(
154+
IdObject::from_bytes(&out).unwrap(),
155+
EncryptedSecret::from_bytes(&encrypted_seed).unwrap(),
156+
)
157+
}

0 commit comments

Comments
 (0)