Browse Source

Started implementing a TPM backed credentials store.

Matthew Carr 2 years ago
parent
commit
d0fc5d9a77

+ 0 - 17
crates/btnode/src/crypto/key_store.rs

@@ -1,17 +0,0 @@
-use super::*;
-
-pub(crate) trait KeyStore : std::fmt::Debug {
-    fn generate(&mut self, kind: AsymKeyKind) -> &KeyPair;
-    fn store<'a>(&'a mut self, pair: &KeyPair) -> Result<&'a KeyPair>;
-    fn duplicate(
-        &mut self, pair: &KeyPair, wrap_with: Option<&AsymKey<Public>>
-    ) -> Cryptotext<KeyPair>;
-    fn list<'a>(&'a self) -> Box<dyn Iterator<Item=&'a KeyPair>>; 
-    fn delete(&mut self, pair: &KeyPair) -> Result<()>;
-
-    fn sign(&self, pair: &KeyPair, data: &[u8]) -> Vec<u8>;
-    fn verify(&self, pair: &KeyPair, data: &[u8], sig: &[u8]) -> bool;
-
-    fn encrypt(&self, pair: &KeyPair, data: &[u8]) -> Vec<u8>;
-    fn decrypt(&self, pair: &KeyPair, data: &[u8]) -> Vec<u8>;
-}

+ 24 - 0
crates/btnode/src/crypto/mod.rs

@@ -3,6 +3,7 @@
 mod tpm;
 
 use super::*;
+
 use openssl::{
     error::ErrorStack,
     encrypt::{Encrypter, Decrypter},
@@ -43,6 +44,7 @@ pub(crate) enum Error {
     InvalidHashFormat,
     Message(String),
     Serde(serde_block_tree::Error),
+    Io(std::io::Error),
 }
 
 impl Display for Error {
@@ -56,6 +58,7 @@ impl Display for Error {
             Error::InvalidHashFormat => write!(f, "invalid format"),
             Error::Message(message) => f.write_str(message.as_str()),
             Error::Serde(serde_err) => serde_err.fmt(f),
+            Error::Io(io_err) => io_err.fmt(f),
         }
     }
 }
@@ -72,6 +75,12 @@ impl From<serde_block_tree::Error> for Error {
     }
 }
 
+impl From<std::io::Error> for Error {
+    fn from(error: std::io::Error) -> Error {
+        Error::Io(error)
+    }
+}
+
 pub(crate) type Result<T> = std::result::Result<T, Error>;
 
 /// A cryptographic hash.
@@ -543,6 +552,21 @@ pub(crate) trait Creds: CredsPriv + CredsPub {
     fn public(&self) -> &AsymKeyPub;
 }
 
+/// A trait for types which store credentials.
+pub(crate) trait CredStore {
+    type CredHandle: Creds;
+
+    /// Returns the node credentials. If credentials haven't been generated, they are generated
+    /// stored and returned.
+    fn node_creds(&self) -> Result<&Self::CredHandle>;
+    /// Returns the root credentials. If no root credentials have been generated, or the provided
+    /// password is incorrect, then an error is returned.
+    fn root_creds(&self, password: &str) -> Result<&Self::CredHandle>;
+    /// Generates the root crednetials and protects them using the given password. If the root
+    /// credentials have already been generated then an error is returned.
+    fn gen_root_creds(&self, password: &str) -> Result<&Self::CredHandle>;
+}
+
 pub(crate) fn encrypt_block<C: Creds>(
     mut block: Block, principal: &Principal, creds: &C
 ) -> Result<Block> {

+ 71 - 29
crates/btnode/src/crypto/tpm.rs

@@ -1,10 +1,79 @@
+use super::{
+    Error,
+    Result,
+    rand_array,
+};
 
 use std::{
+    io::{Read, Write},
     os::raw::c_char,
-    ffi::CStr,
+    ffi::CStr, path::{Path},
+    fs::{OpenOptions}
 };
-use tss_esapi::constants::response_code::Tss2ResponseCode;
+use tss_esapi::{constants::response_code::Tss2ResponseCode};
 use tss_esapi_sys::TSS2_RC;
+    use core::str::FromStr;
+    use tss_esapi::{
+        Context,
+        constants::{
+            session_type::{SessionType},
+        },
+        tcti_ldr::{DeviceConfig, TctiNameConf, TabrmdConfig},
+        interface_types::{
+            resource_handles::{Hierarchy},
+            algorithm::{HashingAlgorithm},
+            ecc::{EccCurve},
+        },
+        structures::{
+            Digest,
+            EccPoint,
+            EccScheme,
+            KeyDerivationFunctionScheme,
+            HashScheme,
+            Public,
+            PublicEccParameters,
+            SymmetricDefinition,
+            SymmetricDefinitionObject,
+        },
+        attributes::{
+            object::{ObjectAttributes},
+        },
+    };
+
+
+const COOKIE_LEN: usize = 64;
+type Cookie = [u8; COOKIE_LEN];
+
+pub(crate) struct TpmCredStore {
+    context: Context,
+    cookie: Cookie,
+}
+
+impl TpmCredStore {
+    fn new<P: AsRef<Path>>(tpm_path: &str, cookie_path: P) -> Result<TpmCredStore> {
+        let config = TctiNameConf::Device(DeviceConfig::from_str(tpm_path).unwrap());
+        let context = Context::new(config)
+            .tss2_expect("Failed to create context");
+        let cookie = match OpenOptions::new().read(true).open(&cookie_path) {
+            Ok(mut file) => {
+                let mut cookie: Cookie = [0; COOKIE_LEN];
+                file.read_exact(cookie.as_mut_slice()).map_err(Error::from)?;
+                cookie
+            },
+            Err(other) => {
+                if std::io::ErrorKind::NotFound != other.kind() {
+                    return Err(Error::from(other));
+                }
+                let cookie: Cookie = rand_array()?;
+                let mut file = OpenOptions::new().write(true).create_new(true).open(&cookie_path)
+                    .map_err(Error::from)?;
+                file.write_all(cookie.as_slice()).map_err(Error::from)?;
+                cookie
+            }
+        };
+        Ok(TpmCredStore { context, cookie })
+    }
+}
 
 #[link(name = "tss2-rc")]
 extern {
@@ -66,33 +135,6 @@ impl<T> Tss2Expect<T> for tss_esapi::Result<T> {
 #[cfg(test)]
 mod test {
     use super::*;
-    use core::str::FromStr;
-    use tss_esapi::{
-        Context,
-        constants::{
-            session_type::{SessionType},
-        },
-        tcti_ldr::{DeviceConfig, TctiNameConf, TabrmdConfig},
-        interface_types::{
-            resource_handles::{Hierarchy},
-            algorithm::{HashingAlgorithm},
-            ecc::{EccCurve},
-        },
-        structures::{
-            Digest,
-            EccPoint,
-            EccScheme,
-            KeyDerivationFunctionScheme,
-            HashScheme,
-            Public,
-            PublicEccParameters,
-            SymmetricDefinition,
-            SymmetricDefinitionObject,
-        },
-        attributes::{
-            object::{ObjectAttributes},
-        },
-    };
 
     #[test]
     fn create_context() {

+ 11 - 12
crates/btnode/src/main.rs

@@ -2,6 +2,17 @@
 // TODO: Delete this prior to release.
 #![allow(dead_code)]
 
+#[cfg(test)]
+mod test_helpers;
+
+#[cfg(test)]
+mod serde_tests;
+
+use serde_block_tree::{self, read_from, write_to};
+use harness::Message;
+mod crypto;
+use crypto::{Hash, HashKind, Signature, SymKey, AsymKeyPub, Cryptotext};
+
 use std::{
     collections::HashMap,
     convert::TryFrom,
@@ -15,18 +26,6 @@ use serde::{Serialize, Deserialize};
 use serde_big_array::BigArray;
 use log::{info, error};
 
-use serde_block_tree::{self, read_from, write_to};
-use harness::Message;
-
-#[cfg(test)]
-mod test_helpers;
-
-#[cfg(test)]
-mod serde_tests;
-
-mod crypto;
-use crypto::{Hash, HashKind, Signature, SymKey, AsymKeyPub, Cryptotext};
-
 /// A Block tagged with its version number. When a block of a previous version is received over
 /// the network or read from the filesystem, it is upgraded to the current version before being
 /// processed.