Skip to content

Commit 573d67e

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

File tree

7 files changed

+517
-1
lines changed

7 files changed

+517
-1
lines changed

Cargo.toml

+5
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

+9-1
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ 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+
cfb-mode = { version = "0.9.0-pre", optional = true }
3839
ecdsa = { version = "0.17.0-pre.9", features = ["der", "hazmat", "arithmetic", "verifying"], optional = true }
3940
elliptic-curve = { version = "0.14.0-rc.1", optional = true, features = ["alloc", "pkcs8"] }
41+
hmac = { version = "0.13.0-pre.4", optional = true }
4042
p192 = { version = "0.14.0-pre", optional = true }
4143
p224 = { version = "0.14.0-pre", optional = true }
4244
p256 = { version = "0.14.0-pre.2", optional = true }
@@ -48,16 +50,21 @@ sha2 = { version = "0.11.0-pre.4", optional = true }
4850
sha3 = { version = "0.11.0-pre.4", optional = true }
4951
sm2 = { version = "0.14.0-pre", optional = true }
5052
sm3 = { version = "0.5.0-pre.4", optional = true }
53+
kbkdf = { version = "0.1.0" }
54+
concat-kdf = { version = "0.2.0-pre" }
5155
digest = "0.11.0-pre.9"
5256
signature = { version = "2.3.0-pre.4", features = ["std"], optional = true}
5357
cfg-if = "1.0.0"
5458
strum = { version = "0.26.3", optional = true }
5559
strum_macros = { version = "0.26.4", optional = true }
5660
paste = "1.0.14"
5761
getrandom = "0.2.11"
62+
rand = "0.8"
63+
aes = "0.9.0-pre.2"
5864

5965
[dev-dependencies]
6066
env_logger = "0.11.5"
67+
hex-literal = "0.4.1"
6168
serde_json = "^1.0.108"
6269
sha2 = { version = "0.11.0-pre.4", features = ["oid"] }
6370
tss-esapi = { path = ".", features = [
@@ -66,6 +73,7 @@ tss-esapi = { path = ".", features = [
6673
"abstraction",
6774
"rustcrypto-full",
6875
] }
76+
p256 = { version = "0.14.0-pre.2", features = ["ecdh"] }
6977
x509-cert = { version = "0.3.0-pre.0", features = ["builder"] }
7078

7179
[build-dependencies]
@@ -77,6 +85,6 @@ generate-bindings = ["tss-esapi-sys/generate-bindings"]
7785
abstraction = ["rustcrypto"]
7886
integration-tests = ["strum", "strum_macros"]
7987

80-
rustcrypto = ["ecdsa", "elliptic-curve", "signature", "x509-cert"]
88+
rustcrypto = ["cfb-mode", "ecdsa", "elliptic-curve", "elliptic-curve/ecdh", "hmac", "signature", "x509-cert"]
8189
rustcrypto-full = ["rustcrypto", "p192", "p224", "p256", "p384", "p521", "rsa", "sha1", "sha2", "sha3", "sm2", "sm3"]
8290

tss-esapi/src/utils/credential.rs

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
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+
// TpmHmacKey intends to code for the key expected for hmac
34+
// in the KDFa 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+
struct TpmHmac<H>(PhantomData<H>);
43+
44+
impl<H> KeySizeUser for TpmHmac<H>
45+
where
46+
H: OutputSizeUser,
47+
{
48+
type KeySize = H::OutputSize;
49+
}
50+
51+
pub fn make_credential_ecc<C, EkHash, EkCipher>(
52+
ek_public: PublicKey<C>,
53+
secret: &[u8],
54+
key_name: Name,
55+
) -> (IdObject, EncryptedSecret)
56+
where
57+
C: Curve + CurveArithmetic,
58+
59+
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
60+
FieldBytesSize<C>: ModulusSize,
61+
62+
<FieldBytesSize<C> as Add>::Output: Add<FieldBytesSize<C>>,
63+
Sum<FieldBytesSize<C>, FieldBytesSize<C>>: ArraySize,
64+
Sum<FieldBytesSize<C>, FieldBytesSize<C>>: Add<U8>,
65+
Sum<Sum<FieldBytesSize<C>, FieldBytesSize<C>>, U8>: Add<B1>,
66+
Add1<Sum<Sum<FieldBytesSize<C>, FieldBytesSize<C>>, U8>>: ArraySize,
67+
68+
EkHash: Digest + EagerHash + FixedOutputReset,
69+
<EkHash as OutputSizeUser>::OutputSize: Mul<U8>,
70+
<<EkHash as OutputSizeUser>::OutputSize as Mul<U8>>::Output: Unsigned,
71+
<<EkHash as EagerHash>::Core as OutputSizeUser>::OutputSize: ArraySize + Mul<U8>,
72+
<<<EkHash as EagerHash>::Core as OutputSizeUser>::OutputSize as Mul<U8>>::Output: Unsigned,
73+
74+
EkCipher: KeySizeUser + BlockCipherEncrypt + KeyInit,
75+
<EkCipher as KeySizeUser>::KeySize: Mul<U8>,
76+
<<EkCipher as KeySizeUser>::KeySize as Mul<U8>>::Output: ArraySize,
77+
{
78+
let mut rng = thread_rng();
79+
80+
// See Table 22 - Key Generation for the various labels used here after:
81+
// https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=183
82+
83+
// C.6.4. ECC Secret Sharing for Credentials
84+
// https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=311
85+
let local = EphemeralSecret::<C>::random(&mut rng);
86+
87+
let ecdh_secret: SharedSecret<C> = local.diffie_hellman(&ek_public);
88+
let local_public = local.public_key();
89+
drop(local);
90+
91+
let seed = kdf::kdfe::<kdf::Identity, EkHash, C, TpmHmac<EkHash>>(
92+
&ecdh_secret,
93+
&local_public,
94+
&ek_public,
95+
);
96+
drop(ecdh_secret);
97+
98+
// The local ECDH pair is used as "encrypted seed"
99+
let encrypted_seed = {
100+
let mut out = vec![];
101+
out.extend_from_slice(&FieldBytesSize::<C>::U16.to_be_bytes()[..]);
102+
out.extend_from_slice(&local_public.to_encoded_point(false).x().unwrap());
103+
out.extend_from_slice(&FieldBytesSize::<C>::U16.to_be_bytes()[..]);
104+
out.extend_from_slice(&local_public.to_encoded_point(false).y().unwrap());
105+
out
106+
};
107+
108+
// Prepare the sensitive data
109+
// this will be then encrypted using AES-CFB (size of the symmetric key depends on the EK).
110+
let mut sensitive_data = {
111+
let mut out = vec![];
112+
out.extend_from_slice(&u16::try_from(secret.len()).unwrap().to_be_bytes()[..]);
113+
out.extend_from_slice(secret);
114+
out
115+
};
116+
117+
// We'll now encrypt the sensitive data, and hmac the result of the encryption
118+
// https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=201
119+
// See 24.4 Symmetric Encryption
120+
let sym_key = kdf::kdfa::<EkHash, kdf::Storage, EkCipher>(&seed, key_name.value(), &[]);
121+
122+
let iv: Iv<cfb_mode::Encryptor<EkCipher>> = Default::default();
123+
124+
cfb_mode::Encryptor::<EkCipher>::new(&sym_key.into(), &iv.into()).encrypt(&mut sensitive_data);
125+
126+
// See 24.5 HMAC
127+
let hmac_key = kdf::kdfa::<EkHash, kdf::Integrity, TpmHmac<EkHash>>(&seed, &[], &[]);
128+
let mut hmac = Hmac::<EkHash>::new_from_slice(&hmac_key).unwrap();
129+
hmac.update(&sensitive_data);
130+
hmac.update(key_name.value());
131+
let hmac = hmac.finalize();
132+
133+
// We'll now serialize the object and get everything through the door.
134+
let mut out = vec![];
135+
out.extend_from_slice(
136+
&u16::try_from(hmac.into_bytes().len())
137+
.unwrap()
138+
.to_be_bytes()[..],
139+
);
140+
out.extend_from_slice(&hmac.into_bytes());
141+
out.extend_from_slice(&sensitive_data);
142+
143+
(
144+
IdObject::from_bytes(&out).unwrap(),
145+
EncryptedSecret::from_bytes(&encrypted_seed).unwrap(),
146+
)
147+
}

0 commit comments

Comments
 (0)