Keystore 2.0: Add super encryption infrastructure.

Add super_key.rs a runtime key database for credential based keys and
the relevant metadata fields to the database.

Also in this patch:
* Add DateTime type to represent database wall clock time.
* Move creation time to key metadata.
* Add KeyType field to the keyentry table to accommodate super keys
  and attestation keys.

Test: keystore2_test
Bug: 173545997
Change-Id: I670898174fb0223bf1c910051dfd7ead80b2c1a9
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 03523ff..0c49340 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -44,11 +44,16 @@
 //! from the database module these functions take permission check
 //! callbacks.
 
+#![allow(dead_code)]
+
 use crate::db_utils::{self, SqlField};
 use crate::error::{Error as KsError, ResponseCode};
+use crate::impl_metadata; // This is in db_utils.rs
 use crate::key_parameter::{KeyParameter, Tag};
 use crate::permission::KeyPermSet;
 use crate::utils::get_current_time_in_seconds;
+use anyhow::{anyhow, Context, Result};
+use std::{convert::TryFrom, convert::TryInto, time::SystemTimeError};
 
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     HardwareAuthToken::HardwareAuthToken, HardwareAuthenticatorType::HardwareAuthenticatorType,
@@ -57,24 +62,258 @@
 use android_system_keystore2::aidl::android::system::keystore2::{
     Domain::Domain, KeyDescriptor::KeyDescriptor,
 };
-use anyhow::{anyhow, Context, Result};
 
 use lazy_static::lazy_static;
 #[cfg(not(test))]
 use rand::prelude::random;
 use rusqlite::{
-    params, types::FromSql, types::FromSqlResult, types::ToSqlOutput, types::Value,
-    types::ValueRef, Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior,
-    NO_PARAMS,
+    params,
+    types::FromSql,
+    types::FromSqlResult,
+    types::ToSqlOutput,
+    types::{FromSqlError, Value, ValueRef},
+    Connection, OptionalExtension, ToSql, Transaction, TransactionBehavior, NO_PARAMS,
 };
 use std::{
-    collections::HashSet,
+    collections::{HashMap, HashSet},
     path::Path,
     sync::{Condvar, Mutex},
+    time::{Duration, SystemTime},
 };
 #[cfg(test)]
 use tests::random;
 
+impl_metadata!(
+    /// A set of metadata for key entries.
+    #[derive(Debug, Default, Eq, PartialEq)]
+    pub struct KeyMetaData;
+    /// A metadata entry for key entries.
+    #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
+    pub enum KeyMetaEntry {
+        /// If present, indicates that the sensitive part of key
+        /// is encrypted with another key or a key derived from a password.
+        EncryptedBy(EncryptedBy) with accessor encrypted_by,
+        /// If the blob is password encrypted this field is set to the
+        /// salt used for the key derivation.
+        Salt(Vec<u8>) with accessor salt,
+        /// If the blob is encrypted, this field is set to the initialization vector.
+        Iv(Vec<u8>) with accessor iv,
+        /// If the blob is encrypted, this field holds the AEAD TAG.
+        AeadTag(Vec<u8>) with accessor aead_tag,
+        /// Creation date of a the key entry.
+        CreationDate(DateTime) with accessor creation_date,
+        /// Expiration date for attestation keys.
+        AttestationExpirationDate(DateTime) with accessor attestation_expiration_date,
+        //  --- ADD NEW META DATA FIELDS HERE ---
+        // For backwards compatibility add new entries only to
+        // end of this list and above this comment.
+    };
+);
+
+impl KeyMetaData {
+    fn load_from_db(key_id: i64, tx: &Transaction) -> Result<Self> {
+        let mut stmt = tx
+            .prepare(
+                "SELECT tag, data from persistent.keymetadata
+                    WHERE keyentryid = ?;",
+            )
+            .context("In KeyMetaData::load_from_db: prepare statement failed.")?;
+
+        let mut metadata: HashMap<i64, KeyMetaEntry> = Default::default();
+
+        let mut rows =
+            stmt.query(params![key_id]).context("In KeyMetaData::load_from_db: query failed.")?;
+        db_utils::with_rows_extract_all(&mut rows, |row| {
+            let db_tag: i64 = row.get(0).context("Failed to read tag.")?;
+            metadata.insert(
+                db_tag,
+                KeyMetaEntry::new_from_sql(db_tag, &SqlField::new(1, &row))
+                    .context("Failed to read KeyMetaEntry.")?,
+            );
+            Ok(())
+        })
+        .context("In KeyMetaData::load_from_db.")?;
+
+        Ok(Self { data: metadata })
+    }
+
+    fn store_in_db(&self, key_id: i64, tx: &Transaction) -> Result<()> {
+        let mut stmt = tx
+            .prepare(
+                "INSERT into persistent.keymetadata (keyentryid, tag, data)
+                    VALUES (?, ?, ?);",
+            )
+            .context("In KeyMetaData::store_in_db: Failed to prepare statement.")?;
+
+        let iter = self.data.iter();
+        for (tag, entry) in iter {
+            stmt.insert(params![key_id, tag, entry,]).with_context(|| {
+                format!("In KeyMetaData::store_in_db: Failed to insert {:?}", entry)
+            })?;
+        }
+        Ok(())
+    }
+}
+
+/// Indicates the type of the keyentry.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
+pub enum KeyType {
+    /// This is a client key type. These keys are created or imported through the Keystore 2.0
+    /// AIDL interface android.system.keystore2.
+    Client,
+    /// This is a super key type. These keys are created by keystore itself and used to encrypt
+    /// other key blobs to provide LSKF binding.
+    Super,
+    /// This is an attestation key. These keys are created by the remote provisioning mechanism.
+    Attestation,
+}
+
+impl ToSql for KeyType {
+    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
+        Ok(ToSqlOutput::Owned(Value::Integer(match self {
+            KeyType::Client => 0,
+            KeyType::Super => 1,
+            KeyType::Attestation => 2,
+        })))
+    }
+}
+
+impl FromSql for KeyType {
+    fn column_result(value: ValueRef) -> FromSqlResult<Self> {
+        match i64::column_result(value)? {
+            0 => Ok(KeyType::Client),
+            1 => Ok(KeyType::Super),
+            2 => Ok(KeyType::Attestation),
+            v => Err(FromSqlError::OutOfRange(v)),
+        }
+    }
+}
+
+/// Indicates how the sensitive part of this key blob is encrypted.
+#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
+pub enum EncryptedBy {
+    /// The keyblob is encrypted by a user password.
+    /// In the database this variant is represented as NULL.
+    Password,
+    /// The keyblob is encrypted by another key with wrapped key id.
+    /// In the database this variant is represented as non NULL value
+    /// that is convertible to i64, typically NUMERIC.
+    KeyId(i64),
+}
+
+impl ToSql for EncryptedBy {
+    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
+        match self {
+            Self::Password => Ok(ToSqlOutput::Owned(Value::Null)),
+            Self::KeyId(id) => id.to_sql(),
+        }
+    }
+}
+
+impl FromSql for EncryptedBy {
+    fn column_result(value: ValueRef) -> FromSqlResult<Self> {
+        match value {
+            ValueRef::Null => Ok(Self::Password),
+            _ => Ok(Self::KeyId(i64::column_result(value)?)),
+        }
+    }
+}
+
+/// A database representation of wall clock time. DateTime stores unix epoch time as
+/// i64 in milliseconds.
+#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
+pub struct DateTime(i64);
+
+/// Error type returned when creating DateTime or converting it from and to
+/// SystemTime.
+#[derive(thiserror::Error, Debug)]
+pub enum DateTimeError {
+    /// This is returned when SystemTime and Duration computations fail.
+    #[error(transparent)]
+    SystemTimeError(#[from] SystemTimeError),
+
+    /// This is returned when type conversions fail.
+    #[error(transparent)]
+    TypeConversion(#[from] std::num::TryFromIntError),
+
+    /// This is returned when checked time arithmetic failed.
+    #[error("Time arithmetic failed.")]
+    TimeArithmetic,
+}
+
+impl DateTime {
+    /// Constructs a new DateTime object denoting the current time. This may fail during
+    /// conversion to unix epoch time and during conversion to the internal i64 representation.
+    pub fn now() -> Result<Self, DateTimeError> {
+        Ok(Self(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
+    }
+
+    /// Constructs a new DateTime object from milliseconds.
+    pub fn from_millis_epoch(millis: i64) -> Self {
+        Self(millis)
+    }
+
+    /// Returns unix epoch time in milliseconds.
+    pub fn to_millis_epoch(&self) -> i64 {
+        self.0
+    }
+
+    /// Returns unix epoch time in seconds.
+    pub fn to_secs_epoch(&self) -> i64 {
+        self.0 / 1000
+    }
+}
+
+impl ToSql for DateTime {
+    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput> {
+        Ok(ToSqlOutput::Owned(Value::Integer(self.0)))
+    }
+}
+
+impl FromSql for DateTime {
+    fn column_result(value: ValueRef) -> FromSqlResult<Self> {
+        Ok(Self(i64::column_result(value)?))
+    }
+}
+
+impl TryInto<SystemTime> for DateTime {
+    type Error = DateTimeError;
+
+    fn try_into(self) -> Result<SystemTime, Self::Error> {
+        // We want to construct a SystemTime representation equivalent to self, denoting
+        // a point in time THEN, but we cannot set the time directly. We can only construct
+        // a SystemTime denoting NOW, and we can get the duration between EPOCH and NOW,
+        // and between EPOCH and THEN. With this common reference we can construct the
+        // duration between NOW and THEN which we can add to our SystemTime representation
+        // of NOW to get a SystemTime representation of THEN.
+        // Durations can only be positive, thus the if statement below.
+        let now = SystemTime::now();
+        let now_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
+        let then_epoch = Duration::from_millis(self.0.try_into()?);
+        Ok(if now_epoch > then_epoch {
+            // then = now - (now_epoch - then_epoch)
+            now_epoch
+                .checked_sub(then_epoch)
+                .and_then(|d| now.checked_sub(d))
+                .ok_or(DateTimeError::TimeArithmetic)?
+        } else {
+            // then = now + (then_epoch - now_epoch)
+            then_epoch
+                .checked_sub(now_epoch)
+                .and_then(|d| now.checked_add(d))
+                .ok_or(DateTimeError::TimeArithmetic)?
+        })
+    }
+}
+
+impl TryFrom<SystemTime> for DateTime {
+    type Error = DateTimeError;
+
+    fn try_from(t: SystemTime) -> Result<Self, Self::Error> {
+        Ok(Self(t.duration_since(SystemTime::UNIX_EPOCH)?.as_millis().try_into()?))
+    }
+}
+
 /// Keys have a KeyMint blob component and optional public certificate and
 /// certificate chain components.
 /// KeyEntryLoadBits is a bitmap that indicates to `KeystoreDB::load_key_entry`
@@ -169,7 +408,7 @@
 /// An entry has a unique `id` by which it can be found in the database.
 /// It has a security level field, key parameters, and three optional fields
 /// for the KeyMint blob, public certificate and a public certificate chain.
-#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
+#[derive(Debug, Default, Eq, PartialEq)]
 pub struct KeyEntry {
     id: i64,
     km_blob: Option<Vec<u8>>,
@@ -177,6 +416,7 @@
     cert_chain: Option<Vec<u8>>,
     sec_level: SecurityLevel,
     parameters: Vec<KeyParameter>,
+    metadata: KeyMetaData,
 }
 
 impl KeyEntry {
@@ -220,14 +460,18 @@
     pub fn into_key_parameters(self) -> Vec<KeyParameter> {
         self.parameters
     }
+    /// Exposes the key metadata of this key entry.
+    pub fn metadata(&self) -> &KeyMetaData {
+        &self.metadata
+    }
 }
 
 /// Indicates the sub component of a key entry for persistent storage.
 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
 pub struct SubComponentType(u32);
 impl SubComponentType {
-    /// Persistent identifier for a KeyMint blob.
-    pub const KM_BLOB: SubComponentType = Self(0);
+    /// Persistent identifier for a key blob.
+    pub const KEY_BLOB: SubComponentType = Self(0);
     /// Persistent identifier for a certificate blob.
     pub const CERT: SubComponentType = Self(1);
     /// Persistent identifier for a certificate chain blob.
@@ -346,7 +590,7 @@
         conn.execute(
             "CREATE TABLE IF NOT EXISTS persistent.keyentry (
                      id INTEGER UNIQUE,
-                     creation_date DATETIME,
+                     key_type INTEGER,
                      domain INTEGER,
                      namespace INTEGER,
                      alias BLOB);",
@@ -383,6 +627,15 @@
         .context("Failed to initialize \"keyparameter\" table.")?;
 
         conn.execute(
+            "CREATE TABLE IF NOT EXISTS persistent.keymetadata (
+                     keyentryid INTEGER,
+                     tag INTEGER,
+                     data ANY);",
+            NO_PARAMS,
+        )
+        .context("Failed to initialize \"keymetadata\" table.")?;
+
+        conn.execute(
             "CREATE TABLE IF NOT EXISTS persistent.grant (
                     id INTEGER UNIQUE,
                     grantee INTEGER,
@@ -439,6 +692,84 @@
         Ok(conn)
     }
 
+    /// Atomically loads a key entry and associated metadata or creates it using the
+    /// callback create_new_key callback. The callback is called during a database
+    /// transaction. This means that implementers should be mindful about using
+    /// blocking operations such as IPC or grabbing mutexes.
+    pub fn get_or_create_key_with<F>(
+        &mut self,
+        domain: Domain,
+        namespace: i64,
+        alias: &str,
+        create_new_key: F,
+    ) -> Result<(KeyIdGuard, KeyEntry)>
+    where
+        F: FnOnce() -> Result<(Vec<u8>, KeyMetaData)>,
+    {
+        let tx = self
+            .conn
+            .transaction_with_behavior(TransactionBehavior::Immediate)
+            .context("In get_or_create_key_with: Failed to initialize transaction.")?;
+
+        let id = {
+            let mut stmt = tx
+                .prepare(
+                    "SELECT id FROM persistent.keyentry
+                    WHERE
+                    key_type = ?
+                    AND domain = ?
+                    AND namespace = ?
+                    AND alias = ?;",
+                )
+                .context("In get_or_create_key_with: Failed to select from keyentry table.")?;
+            let mut rows = stmt
+                .query(params![KeyType::Super, domain.0, namespace, alias])
+                .context("In get_or_create_key_with: Failed to query from keyentry table.")?;
+
+            db_utils::with_rows_extract_one(&mut rows, |row| {
+                Ok(match row {
+                    Some(r) => r.get(0).context("Failed to unpack id.")?,
+                    None => None,
+                })
+            })
+            .context("In get_or_create_key_with.")?
+        };
+
+        let (id, entry) = match id {
+            Some(id) => (
+                id,
+                Self::load_key_components(&tx, KeyEntryLoadBits::KM, id)
+                    .context("In get_or_create_key_with.")?,
+            ),
+
+            None => {
+                let id = Self::insert_with_retry(|id| {
+                    tx.execute(
+                        "INSERT into persistent.keyentry
+                        (id, key_type, domain, namespace, alias)
+                        VALUES(?, ?, ?, ?, ?);",
+                        params![id, KeyType::Super, domain.0, namespace, alias],
+                    )
+                })
+                .context("In get_or_create_key_with.")?;
+
+                let (blob, metadata) = create_new_key().context("In get_or_create_key_with.")?;
+                Self::insert_blob_internal(
+                    &tx,
+                    id,
+                    SubComponentType::KEY_BLOB,
+                    &blob,
+                    SecurityLevel::SOFTWARE,
+                )
+                .context("In get_of_create_key_with.")?;
+                metadata.store_in_db(id, &tx).context("In get_or_create_key_with.")?;
+                (id, KeyEntry { id, km_blob: Some(blob), metadata, ..Default::default() })
+            }
+        };
+        tx.commit().context("In get_or_create_key_with: Failed to commit transaction.")?;
+        Ok((KEY_ID_LOCK.get(id), entry))
+    }
+
     /// Creates a new key entry and allocates a new randomized id for the new key.
     /// The key id gets associated with a domain and namespace but not with an alias.
     /// To complete key generation `rebind_alias` should be called after all of the
@@ -456,9 +787,10 @@
         Ok(KEY_ID_LOCK.get(
             Self::insert_with_retry(|id| {
                 self.conn.execute(
-                    "INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias)
-                     VALUES(?, datetime('now'), ?, ?, NULL);",
-                    params![id, domain.0 as u32, namespace],
+                    "INSERT into persistent.keyentry
+                     (id, key_type, domain, namespace, alias)
+                     VALUES(?, ?, ?, ?, NULL);",
+                    params![id, KeyType::Client, domain.0 as u32, namespace],
                 )
             })
             .context("In create_key_entry")?,
@@ -470,7 +802,7 @@
     /// Each key can have one of each sub component type associated. If more
     /// are added only the most recent can be retrieved, and superseded blobs
     /// will get garbage collected. The security level field of components
-    /// other than `SubComponentType::KM_BLOB` are ignored.
+    /// other than `SubComponentType::KEY_BLOB` are ignored.
     pub fn insert_blob(
         &mut self,
         key_id: &KeyIdGuard,
@@ -478,13 +810,30 @@
         blob: &[u8],
         sec_level: SecurityLevel,
     ) -> Result<()> {
-        self.conn
-            .execute(
-                "INSERT into persistent.blobentry (subcomponent_type, keyentryid, blob, sec_level)
-                    VALUES (?, ?, ?, ?);",
-                params![sc_type, key_id.0, blob, sec_level.0],
-            )
-            .context("Failed to insert blob.")?;
+        let tx = self
+            .conn
+            .transaction_with_behavior(TransactionBehavior::Immediate)
+            .context("In insert_blob: Failed to initialize transaction.")?;
+
+        Self::insert_blob_internal(&tx, key_id.0, sc_type, blob, sec_level)
+            .context("In insert_blob.")?;
+
+        tx.commit().context("In insert_blob: Failed to commit transaction.")
+    }
+
+    fn insert_blob_internal(
+        tx: &Transaction,
+        key_id: i64,
+        sc_type: SubComponentType,
+        blob: &[u8],
+        sec_level: SecurityLevel,
+    ) -> Result<()> {
+        tx.execute(
+            "INSERT into persistent.blobentry (subcomponent_type, keyentryid, blob, sec_level)
+                VALUES (?, ?, ?, ?);",
+            params![sc_type, key_id, blob, sec_level.0],
+        )
+        .context("In insert_blob_internal: Failed to insert blob.")?;
         Ok(())
     }
 
@@ -522,6 +871,20 @@
         Ok(())
     }
 
+    /// Insert a set of key entry specific metadata into the database.
+    pub fn insert_key_metadata(
+        &mut self,
+        key_id: &KeyIdGuard,
+        metadata: &KeyMetaData,
+    ) -> Result<()> {
+        let tx = self
+            .conn
+            .transaction_with_behavior(TransactionBehavior::Immediate)
+            .context("In insert_key_metadata: Failed to initialize transaction.")?;
+        metadata.store_in_db(key_id.0, &tx).context("In insert_key_metadata")?;
+        tx.commit().context("In insert_key_metadata: Failed to commit transaction")
+    }
+
     /// Updates the alias column of the given key id `newid` with the given alias,
     /// and atomically, removes the alias, domain, and namespace from another row
     /// with the same alias-domain-namespace tuple if such row exits.
@@ -576,7 +939,7 @@
     // Helper function loading the key_id given the key descriptor
     // tuple comprising domain, namespace, and alias.
     // Requires a valid transaction.
-    fn load_key_entry_id(key: &KeyDescriptor, tx: &Transaction) -> Result<i64> {
+    fn load_key_entry_id(tx: &Transaction, key: &KeyDescriptor, key_type: KeyType) -> Result<i64> {
         let alias = key
             .alias
             .as_ref()
@@ -586,13 +949,14 @@
             .prepare(
                 "SELECT id FROM persistent.keyentry
                     WHERE
-                    domain = ?
+                    key_type =  ?
+                    AND domain = ?
                     AND namespace = ?
                     AND alias = ?;",
             )
             .context("In load_key_entry_id: Failed to select from keyentry table.")?;
         let mut rows = stmt
-            .query(params![key.domain.0 as u32, key.nspace, alias])
+            .query(params![key_type, key.domain.0 as u32, key.nspace, alias])
             .context("In load_key_entry_id: Failed to read from keyentry table.")?;
         db_utils::with_rows_extract_one(&mut rows, |row| {
             row.map_or_else(|| Err(KsError::Rc(ResponseCode::KEY_NOT_FOUND)), Ok)?
@@ -618,6 +982,7 @@
     fn load_access_tuple(
         tx: &Transaction,
         key: KeyDescriptor,
+        key_type: KeyType,
         caller_uid: u32,
     ) -> Result<(i64, KeyDescriptor, Option<KeyPermSet>)> {
         match key.domain {
@@ -632,7 +997,7 @@
                 if access_key.domain == Domain::APP {
                     access_key.nspace = caller_uid as i64;
                 }
-                let key_id = Self::load_key_entry_id(&access_key, &tx)
+                let key_id = Self::load_key_entry_id(&tx, &access_key, key_type)
                     .with_context(|| format!("With key.domain = {:?}.", access_key.domain))?;
 
                 Ok((key_id, access_key, None))
@@ -719,7 +1084,7 @@
             let sub_type: SubComponentType =
                 row.get(2).context("Failed to extract subcomponent_type.")?;
             match (sub_type, load_bits.load_public()) {
-                (SubComponentType::KM_BLOB, _) => {
+                (SubComponentType::KEY_BLOB, _) => {
                     sec_level =
                         SecurityLevel(row.get(1).context("Failed to extract security level.")?);
                     if load_bits.load_km() {
@@ -778,6 +1143,7 @@
     pub fn load_key_entry(
         &mut self,
         key: KeyDescriptor,
+        key_type: KeyType,
         load_bits: KeyEntryLoadBits,
         caller_uid: u32,
         check_permission: impl FnOnce(&KeyDescriptor, Option<KeyPermSet>) -> Result<()>,
@@ -797,7 +1163,8 @@
 
         // Load the key_id and complete the access control tuple.
         let (key_id, access_key_descriptor, access_vector) =
-            Self::load_access_tuple(&tx, key, caller_uid).context("In load_key_entry.")?;
+            Self::load_access_tuple(&tx, key, key_type, caller_uid)
+                .context("In load_key_entry.")?;
 
         // Perform access control. It is vital that we return here if the permission is denied.
         // So do not touch that '?' at the end.
@@ -837,6 +1204,7 @@
                             nspace: key_id,
                             ..Default::default()
                         },
+                        key_type,
                         caller_uid,
                     )
                     .context("In load_key_entry. (deferred key lock)")?;
@@ -847,27 +1215,37 @@
             Some(key_id_guard) => (key_id_guard, tx),
         };
 
-        let (sec_level, km_blob, cert_blob, cert_chain_blob) =
-            Self::load_blob_components(key_id_guard.id(), load_bits, &tx)
-                .context("In load_key_entry.")?;
-
-        let parameters =
-            Self::load_key_parameters(key_id_guard.id(), &tx).context("In load_key_entry.")?;
+        let key_entry = Self::load_key_components(&tx, load_bits, key_id_guard.id())
+            .context("In load_key_entry.")?;
 
         tx.commit().context("In load_key_entry: Failed to commit transaction.")?;
 
-        let key_id = key_id_guard.id();
-        Ok((
-            key_id_guard,
-            KeyEntry {
-                id: key_id,
-                km_blob,
-                cert: cert_blob,
-                cert_chain: cert_chain_blob,
-                sec_level,
-                parameters,
-            },
-        ))
+        Ok((key_id_guard, key_entry))
+    }
+
+    fn load_key_components(
+        tx: &Transaction,
+        load_bits: KeyEntryLoadBits,
+        key_id: i64,
+    ) -> Result<KeyEntry> {
+        let metadata = KeyMetaData::load_from_db(key_id, &tx).context("In load_key_components.")?;
+
+        let (sec_level, km_blob, cert_blob, cert_chain_blob) =
+            Self::load_blob_components(key_id, load_bits, &tx)
+                .context("In load_key_components.")?;
+
+        let parameters =
+            Self::load_key_parameters(key_id, &tx).context("In load_key_components.")?;
+
+        Ok(KeyEntry {
+            id: key_id,
+            km_blob,
+            cert: cert_blob,
+            cert_chain: cert_chain_blob,
+            sec_level,
+            parameters,
+            metadata,
+        })
     }
 
     /// Returns a list of KeyDescriptors in the selected domain/namespace.
@@ -928,7 +1306,7 @@
         // But even if we load the access tuple by grant here, the permission
         // check denies the attempt to create a grant by grant descriptor.
         let (key_id, access_key_descriptor, _) =
-            Self::load_access_tuple(&tx, key, caller_uid).context("In grant")?;
+            Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid).context("In grant")?;
 
         // Perform access control. It is vital that we return here if the permission
         // was denied. So do not touch that '?' at the end of the line.
@@ -988,7 +1366,8 @@
         // Load the key_id and complete the access control tuple.
         // We ignore the access vector here because grants cannot be granted.
         let (key_id, access_key_descriptor, _) =
-            Self::load_access_tuple(&tx, key, caller_uid).context("In ungrant.")?;
+            Self::load_access_tuple(&tx, key, KeyType::Client, caller_uid)
+                .context("In ungrant.")?;
 
         // Perform access control. We must return here if the permission
         // was denied. So do not touch the '?' at the end of this line.
@@ -1072,6 +1451,7 @@
     use std::sync::atomic::{AtomicU8, Ordering};
     use std::sync::Arc;
     use std::thread;
+    use std::time::SystemTime;
 
     fn new_test_db() -> Result<KeystoreDB> {
         let conn = KeystoreDB::make_connection("file::memory:", "file::memory:")?;
@@ -1080,6 +1460,30 @@
         Ok(KeystoreDB { conn })
     }
 
+    #[test]
+    fn datetime() -> Result<()> {
+        let conn = Connection::open_in_memory()?;
+        conn.execute("CREATE TABLE test (ts DATETIME);", NO_PARAMS)?;
+        let now = SystemTime::now();
+        let duration = Duration::from_secs(1000);
+        let then = now.checked_sub(duration).unwrap();
+        let soon = now.checked_add(duration).unwrap();
+        conn.execute(
+            "INSERT INTO test (ts) VALUES (?), (?), (?);",
+            params![DateTime::try_from(now)?, DateTime::try_from(then)?, DateTime::try_from(soon)?],
+        )?;
+        let mut stmt = conn.prepare("SELECT ts FROM test ORDER BY ts ASC;")?;
+        let mut rows = stmt.query(NO_PARAMS)?;
+        assert_eq!(DateTime::try_from(then)?, rows.next()?.unwrap().get(0)?);
+        assert_eq!(DateTime::try_from(now)?, rows.next()?.unwrap().get(0)?);
+        assert_eq!(DateTime::try_from(soon)?, rows.next()?.unwrap().get(0)?);
+        assert!(rows.next()?.is_none());
+        assert!(DateTime::try_from(then)? < DateTime::try_from(now)?);
+        assert!(DateTime::try_from(then)? < DateTime::try_from(soon)?);
+        assert!(DateTime::try_from(now)? < DateTime::try_from(soon)?);
+        Ok(())
+    }
+
     // Ensure that we're using the "injected" random function, not the real one.
     #[test]
     fn test_mocked_random() {
@@ -1103,11 +1507,12 @@
             .prepare("SELECT name from persistent.sqlite_master WHERE type='table' ORDER BY name;")?
             .query_map(params![], |row| row.get(0))?
             .collect::<rusqlite::Result<Vec<String>>>()?;
-        assert_eq!(tables.len(), 4);
+        assert_eq!(tables.len(), 5);
         assert_eq!(tables[0], "blobentry");
         assert_eq!(tables[1], "grant");
         assert_eq!(tables[2], "keyentry");
-        assert_eq!(tables[3], "keyparameter");
+        assert_eq!(tables[3], "keymetadata");
+        assert_eq!(tables[4], "keyparameter");
         let tables = db
             .conn
             .prepare("SELECT name from perboot.sqlite_master WHERE type='table' ORDER BY name;")?
@@ -1307,8 +1712,8 @@
 
         let mut db = new_test_db()?;
         db.conn.execute(
-            "INSERT INTO persistent.keyentry (id, creation_date, domain, namespace, alias)
-                VALUES (1, '1980', 0, 15, 'key'), (2, '1980', 2, 7, 'yek');",
+            "INSERT INTO persistent.keyentry (id, key_type, domain, namespace, alias)
+                VALUES (1, 0, 0, 15, 'key'), (2, 0, 2, 7, 'yek');",
             NO_PARAMS,
         )?;
         let app_key = KeyDescriptor {
@@ -1448,7 +1853,7 @@
         Ok(())
     }
 
-    static TEST_KM_BLOB: &[u8] = b"my test blob";
+    static TEST_KEY_BLOB: &[u8] = b"my test blob";
     static TEST_CERT_BLOB: &[u8] = b"my test cert";
     static TEST_CERT_CHAIN_BLOB: &[u8] = b"my test cert_chain";
 
@@ -1457,8 +1862,8 @@
         let mut db = new_test_db()?;
         db.insert_blob(
             &KEY_ID_LOCK.get(1),
-            SubComponentType::KM_BLOB,
-            TEST_KM_BLOB,
+            SubComponentType::KEY_BLOB,
+            TEST_KEY_BLOB,
             SecurityLevel::SOFTWARE,
         )?;
         db.insert_blob(
@@ -1483,7 +1888,7 @@
                 Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?))
             })?;
         let r = rows.next().unwrap().unwrap();
-        assert_eq!(r, (SubComponentType::KM_BLOB, 1, TEST_KM_BLOB.to_vec(), 0));
+        assert_eq!(r, (SubComponentType::KEY_BLOB, 1, TEST_KEY_BLOB.to_vec(), 0));
         let r = rows.next().unwrap().unwrap();
         assert_eq!(r, (SubComponentType::CERT, 1, TEST_CERT_BLOB.to_vec(), 1));
         let r = rows.next().unwrap().unwrap();
@@ -1507,21 +1912,12 @@
                 alias: Some(TEST_ALIAS.to_string()),
                 blob: None,
             },
+            KeyType::Client,
             KeyEntryLoadBits::BOTH,
             1,
             |_k, _av| Ok(()),
         )?;
-        assert_eq!(
-            key_entry,
-            KeyEntry {
-                id: key_id,
-                km_blob: Some(TEST_KM_BLOB.to_vec()),
-                cert: Some(TEST_CERT_BLOB.to_vec()),
-                cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
-                sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
-                parameters: make_test_params(),
-            }
-        );
+        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id));
         Ok(())
     }
 
@@ -1538,21 +1934,12 @@
                 alias: Some(TEST_ALIAS.to_string()),
                 blob: None,
             },
+            KeyType::Client,
             KeyEntryLoadBits::BOTH,
             1,
             |_k, _av| Ok(()),
         )?;
-        assert_eq!(
-            key_entry,
-            KeyEntry {
-                id: key_id,
-                km_blob: Some(TEST_KM_BLOB.to_vec()),
-                cert: Some(TEST_CERT_BLOB.to_vec()),
-                cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
-                sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
-                parameters: make_test_params(),
-            }
-        );
+        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id));
         Ok(())
     }
 
@@ -1564,21 +1951,12 @@
             .0;
         let (_key_guard, key_entry) = db.load_key_entry(
             KeyDescriptor { domain: Domain::KEY_ID, nspace: key_id, alias: None, blob: None },
+            KeyType::Client,
             KeyEntryLoadBits::BOTH,
             1,
             |_k, _av| Ok(()),
         )?;
-        assert_eq!(
-            key_entry,
-            KeyEntry {
-                id: key_id,
-                km_blob: Some(TEST_KM_BLOB.to_vec()),
-                cert: Some(TEST_CERT_BLOB.to_vec()),
-                cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
-                sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
-                parameters: make_test_params(),
-            }
-        );
+        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id));
 
         Ok(())
     }
@@ -1606,23 +1984,13 @@
         debug_dump_grant_table(&mut db)?;
 
         let (_key_guard, key_entry) =
-            db.load_key_entry(granted_key, KeyEntryLoadBits::BOTH, 2, |k, av| {
+            db.load_key_entry(granted_key, KeyType::Client, KeyEntryLoadBits::BOTH, 2, |k, av| {
                 assert_eq!(Domain::GRANT, k.domain);
                 assert!(av.unwrap().includes(KeyPerm::use_()));
                 Ok(())
             })?;
 
-        assert_eq!(
-            key_entry,
-            KeyEntry {
-                id: key_id,
-                km_blob: Some(TEST_KM_BLOB.to_vec()),
-                cert: Some(TEST_CERT_BLOB.to_vec()),
-                cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
-                sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
-                parameters: make_test_params(),
-            }
-        );
+        assert_eq!(key_entry, make_test_key_entry_test_vector(key_id));
         Ok(())
     }
 
@@ -1644,21 +2012,12 @@
                     alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
                     blob: None,
                 },
+                KeyType::Client,
                 KeyEntryLoadBits::BOTH,
                 33,
                 |_k, _av| Ok(()),
             )?;
-            assert_eq!(
-                key_entry,
-                KeyEntry {
-                    id: key_id,
-                    km_blob: Some(TEST_KM_BLOB.to_vec()),
-                    cert: Some(TEST_CERT_BLOB.to_vec()),
-                    cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
-                    sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
-                    parameters: make_test_params(),
-                }
-            );
+            assert_eq!(key_entry, make_test_key_entry_test_vector(key_id));
             let state = Arc::new(AtomicU8::new(1));
             let state2 = state.clone();
 
@@ -1680,6 +2039,7 @@
                             alias: Some(KEY_LOCK_TEST_ALIAS.to_string()),
                             blob: None,
                         },
+                        KeyType::Client,
                         KeyEntryLoadBits::BOTH,
                         33,
                         |_k, _av| Ok(()),
@@ -1771,7 +2131,13 @@
                 .into_iter()
                 .map(|d| {
                     let (_, entry) = db
-                        .load_key_entry(d, KeyEntryLoadBits::NONE, *namespace as u32, |_, _| Ok(()))
+                        .load_key_entry(
+                            d,
+                            KeyType::Client,
+                            KeyEntryLoadBits::NONE,
+                            *namespace as u32,
+                            |_, _| Ok(()),
+                        )
                         .unwrap();
                     entry.id()
                 })
@@ -1812,7 +2178,7 @@
     #[allow(dead_code)]
     struct KeyEntryRow {
         id: i64,
-        creation_date: String,
+        key_type: KeyType,
         domain: Option<Domain>,
         namespace: Option<i64>,
         alias: Option<String>,
@@ -1824,7 +2190,7 @@
             .query_map(NO_PARAMS, |row| {
                 Ok(KeyEntryRow {
                     id: row.get(0)?,
-                    creation_date: row.get(1)?,
+                    key_type: row.get(1)?,
                     domain: match row.get(2)? {
                         Some(i) => Some(Domain(i)),
                         None => None,
@@ -2068,8 +2434,8 @@
         let key_id = db.create_key_entry(domain, namespace)?;
         db.insert_blob(
             &key_id,
-            SubComponentType::KM_BLOB,
-            TEST_KM_BLOB,
+            SubComponentType::KEY_BLOB,
+            TEST_KEY_BLOB,
             SecurityLevel::TRUSTED_ENVIRONMENT,
         )?;
         db.insert_blob(
@@ -2085,24 +2451,48 @@
             SecurityLevel::TRUSTED_ENVIRONMENT,
         )?;
         db.insert_keyparameter(&key_id, &make_test_params())?;
+        let mut metadata = KeyMetaData::new();
+        metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
+        metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
+        metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
+        metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
+        db.insert_key_metadata(&key_id, &metadata)?;
         db.rebind_alias(&key_id, alias, domain, namespace)?;
         Ok(key_id)
     }
 
+    fn make_test_key_entry_test_vector(key_id: i64) -> KeyEntry {
+        let mut metadata = KeyMetaData::new();
+        metadata.add(KeyMetaEntry::EncryptedBy(EncryptedBy::Password));
+        metadata.add(KeyMetaEntry::Salt(vec![1, 2, 3]));
+        metadata.add(KeyMetaEntry::Iv(vec![2, 3, 1]));
+        metadata.add(KeyMetaEntry::AeadTag(vec![3, 1, 2]));
+
+        KeyEntry {
+            id: key_id,
+            km_blob: Some(TEST_KEY_BLOB.to_vec()),
+            cert: Some(TEST_CERT_BLOB.to_vec()),
+            cert_chain: Some(TEST_CERT_CHAIN_BLOB.to_vec()),
+            sec_level: SecurityLevel::TRUSTED_ENVIRONMENT,
+            parameters: make_test_params(),
+            metadata,
+        }
+    }
+
     fn debug_dump_keyentry_table(db: &mut KeystoreDB) -> Result<()> {
-        let mut stmt = db.conn.prepare(
-            "SELECT id, creation_date, domain, namespace, alias FROM persistent.keyentry;",
-        )?;
-        let rows = stmt.query_map::<(i64, i64, i32, i64, String), _, _>(NO_PARAMS, |row| {
+        let mut stmt = db
+            .conn
+            .prepare("SELECT id, key_type, domain, namespace, alias FROM persistent.keyentry;")?;
+        let rows = stmt.query_map::<(i64, KeyType, i32, i64, String), _, _>(NO_PARAMS, |row| {
             Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?, row.get(4)?))
         })?;
 
         println!("Key entry table rows:");
         for r in rows {
-            let (id, cdate, domain, namespace, alias) = r.unwrap();
+            let (id, key_type, domain, namespace, alias) = r.unwrap();
             println!(
-                "    id: {} Creation date: {} Domain: {} Namespace: {} Alias: {}",
-                id, cdate, domain, namespace, alias
+                "    id: {} KeyType: {:?} Domain: {} Namespace: {} Alias: {}",
+                id, key_type, domain, namespace, alias
             );
         }
         Ok(())