|
@@ -6,11 +6,16 @@ use std::{
|
|
|
raw::c_char,
|
|
|
unix::fs::PermissionsExt,
|
|
|
},
|
|
|
- ffi::CStr, path::{Path},
|
|
|
+ ffi::CStr,
|
|
|
+ path::Path,
|
|
|
fs::{File, OpenOptions},
|
|
|
sync::{Arc, Mutex},
|
|
|
};
|
|
|
-use openssl::{bn::BigNum, hash::Hasher, nid::Nid};
|
|
|
+use openssl::{
|
|
|
+ bn::BigNum,
|
|
|
+ hash::Hasher,
|
|
|
+ nid::Nid,
|
|
|
+};
|
|
|
use tss_esapi_sys::{TSS2_RC, TPMT_TK_HASHCHECK };
|
|
|
use tss_esapi::{
|
|
|
Context,
|
|
@@ -38,6 +43,8 @@ use tss_esapi::{
|
|
|
HashcheckTicket,
|
|
|
Ticket,
|
|
|
SignatureScheme,
|
|
|
+ RsaDecryptionScheme,
|
|
|
+ Data,
|
|
|
},
|
|
|
attributes::{
|
|
|
object::ObjectAttributes,
|
|
@@ -45,7 +52,7 @@ use tss_esapi::{
|
|
|
handles::KeyHandle,
|
|
|
};
|
|
|
|
|
|
-const COOKIE_LEN: usize = RSA_SIG_LEN;
|
|
|
+const COOKIE_LEN: usize = RSA_KEY_BYTES;
|
|
|
|
|
|
struct Cookie([u8; COOKIE_LEN]);
|
|
|
|
|
@@ -108,6 +115,11 @@ pub(crate) struct TpmCredStore {
|
|
|
}
|
|
|
|
|
|
impl TpmCredStore {
|
|
|
+ /// The public exponent to use for generated RSA keys.
|
|
|
+ const RSA_EXPONENT: u32 = 65537; // 2**16 + 1
|
|
|
+
|
|
|
+ const RSA_KEY_BITS: RsaKeyBits = RsaKeyBits::Rsa3072;
|
|
|
+
|
|
|
pub(crate) fn new<P: AsRef<Path>>(
|
|
|
mut context: Context, cookie_path: P
|
|
|
) -> Result<TpmCredStore> {
|
|
@@ -128,7 +140,6 @@ impl TpmCredStore {
|
|
|
}
|
|
|
|
|
|
fn gen_node_creds(&self) -> Result<TpmCreds> {
|
|
|
- const RSA_EXPONENT: u32 = 65537; // 2**16 + 1
|
|
|
let template = {
|
|
|
let object_attributes = ObjectAttributes::builder()
|
|
|
.with_fixed_tpm(true)
|
|
@@ -146,8 +157,8 @@ impl TpmCredStore {
|
|
|
let parameters = PublicRsaParameters::new(
|
|
|
SymmetricDefinitionObject::Null,
|
|
|
RsaScheme::Null,
|
|
|
- RsaKeyBits::Rsa3072,
|
|
|
- RsaExponent::try_from(RSA_EXPONENT).map_err(Error::from)?,
|
|
|
+ TpmCredStore::RSA_KEY_BITS,
|
|
|
+ RsaExponent::try_from(TpmCredStore::RSA_EXPONENT).map_err(Error::from)?,
|
|
|
);
|
|
|
let unique = PublicKeyRsa::try_from(self.cookie.as_slice())
|
|
|
.map_err(|e| Error::Message(e.to_string()))?;
|
|
@@ -307,7 +318,7 @@ impl Signer for TpmCreds {
|
|
|
};
|
|
|
let buf = match sig {
|
|
|
tss_esapi::structures::Signature::RsaSsa(inner) => {
|
|
|
- let mut buf = [0u8; RSA_SIG_LEN];
|
|
|
+ let mut buf = [0u8; RSA_KEY_BYTES];
|
|
|
let slice: &[u8] = inner.signature();
|
|
|
buf.as_mut_slice().write_all(slice).map_err(Error::from)?;
|
|
|
buf
|
|
@@ -320,8 +331,16 @@ impl Signer for TpmCreds {
|
|
|
}
|
|
|
|
|
|
impl Decrypter for TpmCreds {
|
|
|
- fn decrypt(&self, _slice: &[u8]) -> Result<Vec<u8>> {
|
|
|
- unimplemented!()
|
|
|
+ fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
|
|
|
+ let cipher_text = PublicKeyRsa::try_from(slice).map_err(|e| Error::Message(e.to_string()))?;
|
|
|
+ let in_scheme = RsaDecryptionScheme::RsaEs;
|
|
|
+ let empty = [0u8; 0];
|
|
|
+ let label = Data::try_from(empty.as_slice()).map_err(|e| Error::Message(e.to_string()))?;
|
|
|
+ let plain_text = {
|
|
|
+ let mut lock = self.context.lock().map_err(|e| Error::Message(e.to_string()))?;
|
|
|
+ lock.rsa_decrypt(self.handle, cipher_text, in_scheme, label)?
|
|
|
+ };
|
|
|
+ Ok(Vec::from(plain_text.value()))
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -413,6 +432,7 @@ mod test {
|
|
|
PublicEccParameters,
|
|
|
},
|
|
|
};
|
|
|
+ use ctor::ctor;
|
|
|
|
|
|
trait ContextExt {
|
|
|
fn for_test() -> Result<Context>;
|
|
@@ -425,6 +445,11 @@ mod test {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ #[ctor]
|
|
|
+ fn ctor() {
|
|
|
+ env_logger::init();
|
|
|
+ }
|
|
|
+
|
|
|
/// Displays the message associated with a TSS2 return code.
|
|
|
//#[test]
|
|
|
fn print_error_message() {
|
|
@@ -558,18 +583,33 @@ mod test {
|
|
|
assert_eq(MessageDigest::sha3_512(), Nid::sha3_512());
|
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
- fn tpm_sign_verify() -> Result<()> {
|
|
|
- env_logger::init();
|
|
|
+ fn test_store() -> Result<TpmCredStore> {
|
|
|
let dir = TempDir::new("btnode").map_err(Error::from)?;
|
|
|
let cookie_path = dir.path().join("cookie.bin");
|
|
|
let store = TpmCredStore::new(Context::for_test()?, &cookie_path)?;
|
|
|
+ dir.close()?;
|
|
|
+ Ok(store)
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn tpm_sign_verify() -> Result<()> {
|
|
|
+ let store = test_store()?;
|
|
|
let handle = store.gen_node_creds()?;
|
|
|
let data: [u8; 1024] = rand_array()?;
|
|
|
let parts = [data.as_slice()];
|
|
|
let sig = handle.sign(parts.into_iter())?;
|
|
|
assert!(handle.verify(parts.into_iter(), sig.as_slice())?);
|
|
|
- dir.close()?;
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn tpm_encrypt_decrypt() -> Result<()> {
|
|
|
+ let store = test_store()?;
|
|
|
+ let handle = store.gen_node_creds()?;
|
|
|
+ let expected: [u8; RSA_KEY_BYTES / 2] = rand_array()?;
|
|
|
+ let ct = handle.encrypt(expected.as_slice())?;
|
|
|
+ let actual = handle.decrypt(&ct)?;
|
|
|
+ assert_eq!(expected.as_slice(), actual);
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
@@ -578,4 +618,16 @@ mod test {
|
|
|
fn hashcheck_null() {
|
|
|
HashcheckTicket::null();
|
|
|
}
|
|
|
+
|
|
|
+ /// Checks that the value of `TpmCredStore::RSA_KEY_BITS` matches the value of `RSA_KEY_BYTES`.
|
|
|
+ #[test]
|
|
|
+ fn rsa_key_bits_and_key_bytes_compatible() {
|
|
|
+ let bytes = match TpmCredStore::RSA_KEY_BITS {
|
|
|
+ RsaKeyBits::Rsa1024 => 128,
|
|
|
+ RsaKeyBits::Rsa2048 => 256,
|
|
|
+ RsaKeyBits::Rsa3072 => 384,
|
|
|
+ RsaKeyBits::Rsa4096 => 512,
|
|
|
+ };
|
|
|
+ assert_eq!(RSA_KEY_BYTES, bytes)
|
|
|
+ }
|
|
|
}
|