Keystore 2.0: Add new_from_tag_primitive_pair to key_parameters.rs
Test: keystore2_test
Bug: 159371296
Change-Id: If055b7b6f4649b65067c50e30b3d3a83e4bf7958
diff --git a/keystore2/src/key_parameter.rs b/keystore2/src/key_parameter.rs
index a19ba25..ac1164e 100644
--- a/keystore2/src/key_parameter.rs
+++ b/keystore2/src/key_parameter.rs
@@ -32,6 +32,8 @@
//! impl KeyParameterValue {
//! pub fn get_tag(&self) -> Tag;
//! pub fn new_from_sql(tag: Tag, data: &SqlField) -> Result<Self>;
+//! pub fn new_from_tag_primitive_pair<T: Into<Primitive>>(tag: Tag, v: T)
+//! -> Result<Self, PrimitiveError>;
//! fn to_sql(&self) -> SqlResult<ToSqlOutput>
//! }
//!
@@ -40,7 +42,7 @@
//! impl From<KmKeyParameter> for KeyParameterValue {}
//!
//! ## Implementation
-//! Each of the five functions is implemented as match statement over each key parameter variant.
+//! Each of the six functions is implemented as match statement over each key parameter variant.
//! We bootstrap these function as well as the KeyParameterValue enum itself from a single list
//! of key parameters, that needs to be kept in sync with the KeyMint AIDL specification.
//!
@@ -88,6 +90,8 @@
//! * The termination condition which has an empty in list.
//! * The public interface, which does not have @marker and calls itself with an empty out list.
+use std::convert::TryInto;
+
use crate::db_utils::SqlField;
use crate::error::Error as KeystoreError;
use crate::error::ResponseCode;
@@ -170,6 +174,117 @@
implement_associate_primitive_identity! {i64}
implement_associate_primitive_identity! {i32}
+/// This enum allows passing a primitive value to `KeyParameterValue::new_from_tag_primitive_pair`
+/// Usually, it is not necessary to use this type directly because the function uses
+/// `Into<Primitive>` as a trait bound.
+pub enum Primitive {
+ /// Wraps an i64.
+ I64(i64),
+ /// Wraps an i32.
+ I32(i32),
+ /// Wraps a Vec<u8>.
+ Vec(Vec<u8>),
+}
+
+impl From<i64> for Primitive {
+ fn from(v: i64) -> Self {
+ Self::I64(v)
+ }
+}
+impl From<i32> for Primitive {
+ fn from(v: i32) -> Self {
+ Self::I32(v)
+ }
+}
+impl From<Vec<u8>> for Primitive {
+ fn from(v: Vec<u8>) -> Self {
+ Self::Vec(v)
+ }
+}
+
+/// This error is returned by `KeyParameterValue::new_from_tag_primitive_pair`.
+#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum PrimitiveError {
+ /// Returned if this primitive is unsuitable for the given tag type.
+ #[error("Primitive does not match the expected tag type.")]
+ TypeMismatch,
+ /// Return if the tag type is unknown.
+ #[error("Unknown tag.")]
+ UnknownTag,
+}
+
+impl TryInto<i64> for Primitive {
+ type Error = PrimitiveError;
+
+ fn try_into(self) -> Result<i64, Self::Error> {
+ match self {
+ Self::I64(v) => Ok(v),
+ _ => Err(Self::Error::TypeMismatch),
+ }
+ }
+}
+impl TryInto<i32> for Primitive {
+ type Error = PrimitiveError;
+
+ fn try_into(self) -> Result<i32, Self::Error> {
+ match self {
+ Self::I32(v) => Ok(v),
+ _ => Err(Self::Error::TypeMismatch),
+ }
+ }
+}
+impl TryInto<Vec<u8>> for Primitive {
+ type Error = PrimitiveError;
+
+ fn try_into(self) -> Result<Vec<u8>, Self::Error> {
+ match self {
+ Self::Vec(v) => Ok(v),
+ _ => Err(Self::Error::TypeMismatch),
+ }
+ }
+}
+
+/// Expands the list of KeyParameterValue variants as follows:
+///
+/// Input:
+/// Invalid with tag INVALID and field Invalid,
+/// Algorithm(Algorithm) with tag ALGORITHM and field Algorithm,
+///
+/// Output:
+/// ```
+/// pub fn new_from_tag_primitive_pair<T: Into<Primitive>>(
+/// tag: Tag,
+/// v: T
+/// ) -> Result<KeyParameterValue, PrimitiveError> {
+/// let p: Primitive = v.into();
+/// Ok(match tag {
+/// Tag::INVALID => KeyParameterValue::Invalid,
+/// Tag::ALGORITHM => KeyParameterValue::Algorithm(
+/// <Algorithm>::from_primitive(p.try_into()?)
+/// ),
+/// _ => return Err(PrimitiveError::UnknownTag),
+/// })
+/// }
+/// ```
+macro_rules! implement_from_tag_primitive_pair {
+ ($enum_name:ident; $($vname:ident$(($vtype:ty))? $tag_name:ident),*) => {
+ /// Returns the an instance of $enum_name or an error if the given primitive does not match
+ /// the tag type or the tag is unknown.
+ pub fn new_from_tag_primitive_pair<T: Into<Primitive>>(
+ tag: Tag,
+ v: T
+ ) -> Result<$enum_name, PrimitiveError> {
+ let p: Primitive = v.into();
+ Ok(match tag {
+ $(Tag::$tag_name => $enum_name::$vname$((
+ <$vtype>::from_primitive(p.try_into()?)
+ ))?,)*
+ _ => return Err(PrimitiveError::UnknownTag),
+ })
+ }
+ };
+}
+
/// Expands the list of KeyParameterValue variants as follows:
///
/// Input:
@@ -534,6 +649,7 @@
impl $enum_name {
implement_new_from_sql!($enum_name; $($vname$(($vtype))? $tag_name),*);
implement_get_tag!($enum_name; $($vname$(($vtype))? $tag_name),*);
+ implement_from_tag_primitive_pair!($enum_name; $($vname$(($vtype))? $tag_name),*);
#[cfg(test)]
fn make_field_matches_tag_type_test_vector() -> Vec<KmKeyParameter> {