diff --git a/Cargo.toml b/Cargo.toml index 814067ec..0912401b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ serde_json = "1.0.104" serial_test = "3.1.1" simplelog = { version = "0.12.2", default-features = false, optional = true } toml = { version = "0.9", default-features = false, features = ["display", "parse", "serde"] } -uuid = { version = "1.4.1", features = ["v4"] } +uuid = { version = "1.4.1", features = ["v4", "v8"] } ossl.workspace = true [dev-dependencies] diff --git a/src/aes.rs b/src/aes.rs index 3d26dd7e..3c400e47 100644 --- a/src/aes.rs +++ b/src/aes.rs @@ -93,14 +93,16 @@ pub(crate) fn check_key_len(len: usize) -> Result<()> { /// methods for generic manipulation of AES key objects (generation, derivation, wrapping ...) /// -#[derive(Debug, Default)] +#[derive(Debug)] pub struct AesKeyFactory { data: ObjectFactoryData, } impl AesKeyFactory { fn new() -> AesKeyFactory { - let mut factory: AesKeyFactory = Default::default(); + let mut factory: AesKeyFactory = AesKeyFactory { + data: ObjectFactoryData::new(CKO_SECRET_KEY), + }; factory.add_common_secret_key_attrs(); diff --git a/src/ec/ecdsa.rs b/src/ec/ecdsa.rs index caffb816..e80f48eb 100644 --- a/src/ec/ecdsa.rs +++ b/src/ec/ecdsa.rs @@ -110,7 +110,7 @@ pub fn register(mechs: &mut Mechanisms, ot: &mut ObjectFactories) { } /// The ECDSA Public-Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct ECDSAPubFactory { data: ObjectFactoryData, } @@ -118,7 +118,9 @@ pub struct ECDSAPubFactory { impl ECDSAPubFactory { /// Initializes a new ECDSA Public-Key factory pub fn new() -> ECDSAPubFactory { - let mut factory: ECDSAPubFactory = Default::default(); + let mut factory: ECDSAPubFactory = ECDSAPubFactory { + data: ObjectFactoryData::new(CKO_PUBLIC_KEY), + }; factory.add_common_public_key_attrs(); @@ -221,7 +223,7 @@ impl PubKeyFactory for ECDSAPubFactory { } /// The ECDSA Private-Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct ECDSAPrivFactory { data: ObjectFactoryData, } @@ -229,7 +231,9 @@ pub struct ECDSAPrivFactory { impl ECDSAPrivFactory { /// Initializes a new ECDSA Private-Key factory pub fn new() -> ECDSAPrivFactory { - let mut factory: ECDSAPrivFactory = Default::default(); + let mut factory: ECDSAPrivFactory = ECDSAPrivFactory { + data: ObjectFactoryData::new(CKO_PRIVATE_KEY), + }; factory.add_common_private_key_attrs(); diff --git a/src/ec/eddsa.rs b/src/ec/eddsa.rs index 8c0e4ff5..3b11cfeb 100644 --- a/src/ec/eddsa.rs +++ b/src/ec/eddsa.rs @@ -91,7 +91,7 @@ pub fn register(mechs: &mut Mechanisms, ot: &mut ObjectFactories) { } /// The EdDSA-Edwards Public-Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct EDDSAPubFactory { data: ObjectFactoryData, } @@ -99,7 +99,9 @@ pub struct EDDSAPubFactory { impl EDDSAPubFactory { /// Initializes a new EdDSA Public-Key factory pub fn new() -> EDDSAPubFactory { - let mut factory: EDDSAPubFactory = Default::default(); + let mut factory: EDDSAPubFactory = EDDSAPubFactory { + data: ObjectFactoryData::new(CKO_PUBLIC_KEY), + }; factory.add_common_public_key_attrs(); @@ -198,7 +200,7 @@ impl PubKeyFactory for EDDSAPubFactory { } /// The EdDSA Private-Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct EDDSAPrivFactory { data: ObjectFactoryData, } @@ -206,7 +208,9 @@ pub struct EDDSAPrivFactory { impl EDDSAPrivFactory { /// Initializes a new EdDSA Private-Key factory pub fn new() -> EDDSAPrivFactory { - let mut factory: EDDSAPrivFactory = Default::default(); + let mut factory: EDDSAPrivFactory = EDDSAPrivFactory { + data: ObjectFactoryData::new(CKO_PRIVATE_KEY), + }; factory.add_common_private_key_attrs(); diff --git a/src/ec/montgomery.rs b/src/ec/montgomery.rs index 3af375fd..ecbc9deb 100644 --- a/src/ec/montgomery.rs +++ b/src/ec/montgomery.rs @@ -85,7 +85,7 @@ pub fn register(mechs: &mut Mechanisms, ot: &mut ObjectFactories) { } /// The EC-Montgomery Public-Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct ECMontgomeryPubFactory { data: ObjectFactoryData, } @@ -93,7 +93,9 @@ pub struct ECMontgomeryPubFactory { impl ECMontgomeryPubFactory { /// Initializes a new EC-Montgomery Public-Key factory pub fn new() -> ECMontgomeryPubFactory { - let mut factory: ECMontgomeryPubFactory = Default::default(); + let mut factory: ECMontgomeryPubFactory = ECMontgomeryPubFactory { + data: ObjectFactoryData::new(CKO_PUBLIC_KEY), + }; factory.add_common_public_key_attrs(); @@ -192,7 +194,7 @@ impl PubKeyFactory for ECMontgomeryPubFactory { } /// The EC-Montgomery Private-Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct ECMontgomeryPrivFactory { data: ObjectFactoryData, } @@ -200,7 +202,9 @@ pub struct ECMontgomeryPrivFactory { impl ECMontgomeryPrivFactory { /// Initializes a new EC-Montgomery Private-Key factory pub fn new() -> ECMontgomeryPrivFactory { - let mut factory: ECMontgomeryPrivFactory = Default::default(); + let mut factory: ECMontgomeryPrivFactory = ECMontgomeryPrivFactory { + data: ObjectFactoryData::new(CKO_PRIVATE_KEY), + }; factory.add_common_private_key_attrs(); diff --git a/src/ffdh.rs b/src/ffdh.rs index 1a189ef0..f6a6a534 100644 --- a/src/ffdh.rs +++ b/src/ffdh.rs @@ -104,7 +104,7 @@ fn ffdh_public_key_info( } /// The FFDH Public-Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct FFDHPubFactory { data: ObjectFactoryData, } @@ -112,7 +112,9 @@ pub struct FFDHPubFactory { impl FFDHPubFactory { /// Initializes a new FFDH Public-Key factory pub fn new() -> FFDHPubFactory { - let mut factory: FFDHPubFactory = Default::default(); + let mut factory: FFDHPubFactory = FFDHPubFactory { + data: ObjectFactoryData::new(CKO_PUBLIC_KEY), + }; factory.add_common_public_key_attrs(); @@ -164,7 +166,7 @@ impl CommonKeyFactory for FFDHPubFactory {} impl PubKeyFactory for FFDHPubFactory {} /// The FFDH Private-Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct FFDHPrivFactory { data: ObjectFactoryData, } @@ -172,7 +174,9 @@ pub struct FFDHPrivFactory { impl FFDHPrivFactory { /// Initializes a new FFDH Private-Key factory pub fn new() -> FFDHPrivFactory { - let mut factory: FFDHPrivFactory = Default::default(); + let mut factory: FFDHPrivFactory = FFDHPrivFactory { + data: ObjectFactoryData::new(CKO_PRIVATE_KEY), + }; factory.add_common_private_key_attrs(); diff --git a/src/fips/indicators.rs b/src/fips/indicators.rs index b76a873a..7b3ac35f 100644 --- a/src/fips/indicators.rs +++ b/src/fips/indicators.rs @@ -24,7 +24,7 @@ use crate::Token; pub const KRF_FIPS: CK_ULONG = 1; /// The Validation Object factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct ValidationFactory { data: ObjectFactoryData, } @@ -32,7 +32,9 @@ pub struct ValidationFactory { impl ValidationFactory { /// Initializes the validation object factory fn new() -> ValidationFactory { - let mut factory: ValidationFactory = Default::default(); + let mut factory: ValidationFactory = ValidationFactory { + data: ObjectFactoryData::new(CKO_VALIDATION), + }; factory.add_common_storage_attrs(false); @@ -112,13 +114,12 @@ pub(crate) static VALIDATION_FACTORY: LazyLock> = /// /// This is generally done only once at token initialization pub fn insert_fips_validation(token: &mut Token) -> Result<()> { - let mut obj = Object::new(); + let mut obj = Object::new(CKO_VALIDATION); obj.set_attr(Attribute::from_bool(CKA_TOKEN, false))?; obj.set_attr(Attribute::from_bool(CKA_DESTROYABLE, false))?; obj.set_attr(Attribute::from_bool(CKA_MODIFIABLE, false))?; obj.set_attr(Attribute::from_bool(CKA_PRIVATE, false))?; obj.set_attr(Attribute::from_bool(CKA_SENSITIVE, false))?; - obj.set_attr(Attribute::from_ulong(CKA_CLASS, CKO_VALIDATION))?; obj.set_attr(Attribute::from_ulong( CKA_VALIDATION_TYPE, CKV_TYPE_SOFTWARE, @@ -161,8 +162,8 @@ pub fn insert_fips_validation(token: &mut Token) -> Result<()> { String::from(""), ))?; - /* generate a unique id */ - obj.generate_unique(); + /* generate a unique but stable id */ + obj.generate_stable_unique(1); /* invalid session handle will prevent it from being removed when * session objects are cleared on session closings */ diff --git a/src/fips/kats.rs b/src/fips/kats.rs index 4bc83523..02097f37 100644 --- a/src/fips/kats.rs +++ b/src/fips/kats.rs @@ -64,8 +64,7 @@ pub static HMAC_SELFTEST: LazyLock = LazyLock::new(|| { }); fn secret_key_object(secret: Vec) -> Result { - let mut key = Object::new(); - key.set_attr(Attribute::from_ulong(CKA_CLASS, CKO_SECRET_KEY))?; + let mut key = Object::new(CKO_SECRET_KEY); key.set_attr(Attribute::from_ulong(CKA_KEY_TYPE, CKK_GENERIC_SECRET))?; key.set_attr(Attribute::from_ulong( CKA_VALUE_LEN, diff --git a/src/mldsa.rs b/src/mldsa.rs index 0dc6d54e..dfebb5ae 100644 --- a/src/mldsa.rs +++ b/src/mldsa.rs @@ -148,7 +148,7 @@ fn mldsa_pub_check_import(obj: &Object) -> Result<()> { } /// The ML-DSA Public Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct MlDsaPubFactory { data: ObjectFactoryData, } @@ -156,7 +156,9 @@ pub struct MlDsaPubFactory { impl MlDsaPubFactory { /// Initializes a ML-DSA Public Key Factory pub fn new() -> MlDsaPubFactory { - let mut factory: MlDsaPubFactory = Default::default(); + let mut factory: MlDsaPubFactory = MlDsaPubFactory { + data: ObjectFactoryData::new(CKO_PUBLIC_KEY), + }; factory.add_common_public_key_attrs(); @@ -278,7 +280,7 @@ fn mldsa_priv_check_import(obj: &mut Object) -> Result<()> { } /// The ML-DSA Private Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct MlDsaPrivFactory { data: ObjectFactoryData, } @@ -286,7 +288,9 @@ pub struct MlDsaPrivFactory { impl MlDsaPrivFactory { /// Initializes a ML-DSA Private Key Factory pub fn new() -> MlDsaPrivFactory { - let mut factory: MlDsaPrivFactory = Default::default(); + let mut factory: MlDsaPrivFactory = MlDsaPrivFactory { + data: ObjectFactoryData::new(CKO_PRIVATE_KEY), + }; factory.add_common_private_key_attrs(); diff --git a/src/mlkem.rs b/src/mlkem.rs index 2af14081..d2a482cc 100644 --- a/src/mlkem.rs +++ b/src/mlkem.rs @@ -141,7 +141,7 @@ fn mlkem_pub_check_import(obj: &Object) -> Result<()> { } /// The ML-KEM Public Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct MlKemPubFactory { data: ObjectFactoryData, } @@ -149,7 +149,9 @@ pub struct MlKemPubFactory { impl MlKemPubFactory { /// Initializes a ML-KEM Public Key Factory pub fn new() -> MlKemPubFactory { - let mut factory: MlKemPubFactory = Default::default(); + let mut factory: MlKemPubFactory = MlKemPubFactory { + data: ObjectFactoryData::new(CKO_PUBLIC_KEY), + }; factory.add_common_public_key_attrs(); @@ -271,7 +273,7 @@ fn mlkem_priv_check_import(obj: &mut Object) -> Result<()> { } /// The ML-KEM Private Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct MlKemPrivFactory { data: ObjectFactoryData, } @@ -279,7 +281,9 @@ pub struct MlKemPrivFactory { impl MlKemPrivFactory { /// Initializes a ML-KEM Private Key Factory pub fn new() -> MlKemPrivFactory { - let mut factory: MlKemPrivFactory = Default::default(); + let mut factory: MlKemPrivFactory = MlKemPrivFactory { + data: ObjectFactoryData::new(CKO_PRIVATE_KEY), + }; factory.add_common_private_key_attrs(); diff --git a/src/object.rs b/src/object.rs index 0cc2cb9e..b4dcc34c 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,4 +1,3 @@ -// Copyright 2023 Simo Sorce // See LICENSE.txt file for terms //! This module defines the core representation of PKCS#11 objects (`Object`) @@ -86,6 +85,9 @@ pub struct Object { /// Set to CK_INVALID_HANDLE when the object is not tied to /// a session or is new session: CK_SESSION_HANDLE, + /// All objects have a class so we keep it here in order to access it + /// directly in some internal functions + class: CK_OBJECT_CLASS, /// The object attributes as vector of [Attribute] values attributes: Vec, /// Flag to indicate if the object needs to be zeroized when it is @@ -106,11 +108,12 @@ impl Drop for Object { impl Object { /// Creates a new empty Object - pub fn new() -> Object { + pub fn new(class: CK_OBJECT_CLASS) -> Object { Object { handle: CK_INVALID_HANDLE, session: CK_INVALID_HANDLE, - attributes: Vec::new(), + class: class, + attributes: vec![Attribute::from_ulong(CKA_CLASS, class)], zeroize: false, } } @@ -135,10 +138,33 @@ impl Object { } } + /// Generates the internal per object unique id using a stable input + pub fn generate_stable_unique(&mut self, stable_id: CK_ULONG) { + if !self + .attributes + .iter() + .any(|r| r.get_type() == CKA_UNIQUE_ID) + { + let class = match self.get_attr_as_ulong(CKA_CLASS) { + Ok(c) => c, + Err(_) => CK_UNAVAILABLE_INFORMATION, + }; + let mut buf = [0u8; 16]; + buf[..8].copy_from_slice(b"kyroptic"); + let val = (class & 0xFFFFFFFF) as u32; + buf[8..12].copy_from_slice(&val.to_be_bytes()); + let val = (stable_id & 0xFFFFFFFF) as u32; + buf[12..16].copy_from_slice(&val.to_be_bytes()); + let uuid = Uuid::new_v8(buf).to_string(); + self.attributes + .push(Attribute::from_string(CKA_UNIQUE_ID, uuid)); + } + } + /// Allow for a full copy of all attributes but regenerates the /// unique id pub fn blind_copy(&self) -> Result { - let mut obj = Object::new(); + let mut obj = Object::new(self.class); obj.generate_unique(); for attr in &self.attributes { if attr.get_type() == CKA_UNIQUE_ID { @@ -170,17 +196,50 @@ impl Object { self.session } + /// Gets the object's class + pub fn get_class(&self) -> CK_OBJECT_CLASS { + self.class + } + create_bool_checker! {make is_token; from CKA_TOKEN; def false} create_bool_checker! {make is_private; from CKA_PRIVATE; def true} - create_bool_checker! {make is_sensitive; from CKA_SENSITIVE; def true} create_bool_checker! {make is_always_sensitive; from CKA_ALWAYS_SENSITIVE; def true} create_bool_checker! {make is_copyable; from CKA_COPYABLE; def true} create_bool_checker! {make is_modifiable; from CKA_MODIFIABLE; def true} create_bool_checker! {make is_destroyable; from CKA_DESTROYABLE; def false} - create_bool_checker! {make is_extractable; from CKA_EXTRACTABLE; def false} create_bool_checker! {make is_never_extractable; from CKA_NEVER_EXTRACTABLE; def false} create_bool_checker! {make always_auth; from CKA_ALWAYS_AUTHENTICATE; def false} + /// Report is the object is sensitive with a sensible default + pub fn is_sensitive(&self) -> bool { + match self.class { + CKO_PRIVATE_KEY | CKO_SECRET_KEY => { + for a in &self.attributes { + if a.get_type() == CKA_SENSITIVE { + return a.to_bool().unwrap_or(true); + } + } + true + } + _ => false, + } + } + + /// Report is the object is extractable with a sensible default + pub fn is_extractable(&self) -> bool { + match self.class { + CKO_PRIVATE_KEY | CKO_SECRET_KEY => { + for a in &self.attributes { + if a.get_type() == CKA_EXTRACTABLE { + return a.to_bool().unwrap_or(false); + } + } + false + } + _ => true, + } + } + /// Get an attribute from the object by attribute id pub fn get_attr(&self, ck_type: CK_ULONG) -> Option<&Attribute> { self.attributes.iter().find(|r| r.get_type() == ck_type) @@ -189,6 +248,9 @@ impl Object { /// Sets or Replaces an attribute on the object pub fn set_attr(&mut self, a: Attribute) -> Result<()> { let atype = a.get_type(); + if atype == CKA_CLASS { + self.class = a.to_ulong()?; + } match self.attributes.iter().position(|r| r.get_type() == atype) { Some(idx) => self.attributes[idx] = a, None => self.attributes.push(a), @@ -435,8 +497,10 @@ pub(crate) use attr_element; /// specific object/key type, and any special behaviors for object /// creation/import or other manipulation. -#[derive(Debug, Default)] +#[derive(Debug)] pub struct ObjectFactoryData { + /// Class of the object created by the factory + class: CK_OBJECT_CLASS, /// List of valid attributes and their properties for this factory attributes: Vec, /// List of attributes considered sensitive @@ -449,6 +513,21 @@ pub struct ObjectFactoryData { } impl ObjectFactoryData { + pub fn new(class: CK_OBJECT_CLASS) -> ObjectFactoryData { + ObjectFactoryData { + class: class, + attributes: Vec::new(), + sensitive: Vec::new(), + ephemeral: Vec::new(), + finalized: false, + } + } + + /// Return the class of the object created by the factory + pub fn get_class(&self) -> CK_OBJECT_CLASS { + self.class + } + /// Returns a reference to factory valid attributes and their properties pub fn get_attributes(&self) -> &Vec { &self.attributes @@ -570,22 +649,19 @@ pub trait ObjectFactory: Debug + Send + Sync { // default key attributes on CreateObject obj.set_attr(Attribute::from_bool(CKA_LOCAL, false))?; - match obj.get_attr_as_ulong(CKA_CLASS) { - Ok(c) => match c { - CKO_PRIVATE_KEY | CKO_SECRET_KEY => { - // default key attributes on CreateObject for PRIVATE/SECRET keys - obj.set_attr(Attribute::from_bool( - CKA_ALWAYS_SENSITIVE, - false, - ))?; - obj.set_attr(Attribute::from_bool( - CKA_NEVER_EXTRACTABLE, - false, - ))?; - } - _ => (), - }, - Err(_) => (), + match obj.get_class() { + CKO_PRIVATE_KEY | CKO_SECRET_KEY => { + // default key attributes on CreateObject for PRIVATE/SECRET keys + obj.set_attr(Attribute::from_bool( + CKA_ALWAYS_SENSITIVE, + false, + ))?; + obj.set_attr(Attribute::from_bool( + CKA_NEVER_EXTRACTABLE, + false, + ))?; + } + _ => (), } Ok(obj) } @@ -706,9 +782,10 @@ pub trait ObjectFactory: Debug + Send + Sync { unacceptable_flags: OAFlags, required_flags: OAFlags, ) -> Result { - let attributes = self.get_data().get_attributes(); - let mut obj = Object::new(); + let data = self.get_data(); + let mut obj = Object::new(data.get_class()); + let attributes = data.get_attributes(); for ck_attr in template { match attributes.iter().find(|a| a.get_type() == ck_attr.type_) { Some(attr) => { @@ -719,7 +796,11 @@ pub trait ObjectFactory: Debug + Send + Sync { } /* duplicate? */ match obj.get_attr(ck_attr.type_) { - Some(_) => return Err(CKR_TEMPLATE_INCONSISTENT)?, + Some(a) => { + if a.get_type() != CKA_CLASS { + return Err(CKR_TEMPLATE_INCONSISTENT)?; + } + } None => (), } if !attr.is(OAFlags::Ignored) { @@ -953,7 +1034,7 @@ pub trait ObjectFactory: Debug + Send + Sync { /// [Data Objects](https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/pkcs11-spec-v3.1-os.html#_Toc111203218) /// (Version 3.1) -#[derive(Debug, Default)] +#[derive(Debug)] struct DataFactory { data: ObjectFactoryData, } @@ -961,7 +1042,9 @@ struct DataFactory { impl DataFactory { /// Initializes a new DataFactory object fn new() -> DataFactory { - let mut factory: DataFactory = Default::default(); + let mut factory: DataFactory = DataFactory { + data: ObjectFactoryData::new(CKO_DATA), + }; factory.add_common_storage_attrs(false); @@ -1082,7 +1165,7 @@ pub trait CertFactory: ObjectFactory { /// [X.509 public key certificate objects](https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/pkcs11-spec-v3.1-os.html#_Toc111203224) /// (Version 3.1) -#[derive(Debug, Default)] +#[derive(Debug)] struct X509Factory { data: ObjectFactoryData, } @@ -1090,7 +1173,9 @@ struct X509Factory { impl X509Factory { /// Initializes a new X509Factory object fn new() -> X509Factory { - let mut factory: X509Factory = Default::default(); + let mut factory: X509Factory = X509Factory { + data: ObjectFactoryData::new(CKO_CERTIFICATE), + }; factory.add_common_certificate_attrs(); @@ -1204,7 +1289,7 @@ impl CertFactory for X509Factory {} /// /// [Trust objects](https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.2/pkcs11-spec-v3.2.html#_Toc195693091) /// (Version 3.2) -#[derive(Debug, Default)] +#[derive(Debug)] struct TrustObject { data: ObjectFactoryData, } @@ -1212,7 +1297,9 @@ struct TrustObject { impl TrustObject { /// Initializes a new TrustObject factory fn new() -> TrustObject { - let mut factory: TrustObject = Default::default(); + let mut factory: TrustObject = TrustObject { + data: ObjectFactoryData::new(CKO_TRUST), + }; // CKO_TRUST is a storage object. // Spec: if CKA_PRIVATE is not set, it defaults to CK_FALSE. @@ -1333,7 +1420,7 @@ impl ObjectFactory for TrustObject { /// NSS Trust objects are vendor defined and are used in NSS DBs /// to store trust information about certificates. #[cfg(feature = "nssdb")] -#[derive(Debug, Default)] +#[derive(Debug)] struct NSSTrustObject { data: ObjectFactoryData, } @@ -1342,7 +1429,9 @@ struct NSSTrustObject { impl NSSTrustObject { /// Initializes a new NSSTrustObject factory fn new() -> NSSTrustObject { - let mut factory: NSSTrustObject = Default::default(); + let mut factory: NSSTrustObject = NSSTrustObject { + data: ObjectFactoryData::new(CKO_NSS_TRUST), + }; factory.add_common_storage_attrs(false); let attrs = factory.data.get_attributes_mut(); @@ -1752,16 +1841,19 @@ pub trait SecretKeyFactory: CommonKeyFactory { /// [Generic secret key](https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/pkcs11-spec-v3.1-os.html#_Toc111203468) /// (Version 3.1) -#[derive(Debug, Default)] +#[derive(Debug)] pub struct GenericSecretKeyFactory { - keysize: usize, data: ObjectFactoryData, + keysize: usize, } impl GenericSecretKeyFactory { /// Initializes a new GenericSecretKeyFactory object pub fn new() -> GenericSecretKeyFactory { - let mut factory: GenericSecretKeyFactory = Default::default(); + let mut factory: GenericSecretKeyFactory = GenericSecretKeyFactory { + data: ObjectFactoryData::new(CKO_SECRET_KEY), + keysize: 0, + }; factory.add_common_secret_key_attrs(); diff --git a/src/pbkdf2.rs b/src/pbkdf2.rs index 41047fb7..c40e581e 100644 --- a/src/pbkdf2.rs +++ b/src/pbkdf2.rs @@ -51,9 +51,8 @@ impl PBKDF2Mechanism { /// This is needed because the underlying PBKDF2 implementation (native or /// OpenSSL) expects a key object as input for the PRF (HMAC). fn mock_password_object(&self, key: Vec) -> Result { - let mut obj = Object::new(); + let mut obj = Object::new(CKO_SECRET_KEY); obj.set_zeroize(); - obj.set_attr(Attribute::from_ulong(CKA_CLASS, CKO_SECRET_KEY))?; obj.set_attr(Attribute::from_ulong(CKA_KEY_TYPE, CKK_GENERIC_SECRET))?; obj.set_attr(Attribute::from_ulong( CKA_VALUE_LEN, diff --git a/src/rsa.rs b/src/rsa.rs index 9effb86a..e740e72a 100644 --- a/src/rsa.rs +++ b/src/rsa.rs @@ -195,7 +195,7 @@ fn rsa_check_public_key_info(obj: &mut Object) -> Result<()> { } /// The RSA Public-Key Factory. -#[derive(Debug, Default)] +#[derive(Debug)] pub struct RSAPubFactory { data: ObjectFactoryData, } @@ -206,7 +206,9 @@ impl RSAPubFactory { /// Sets up common public key attributes and RSA-specific required attributes /// like CKA_MODULUS and CKA_PUBLIC_EXPONENT. pub fn new() -> RSAPubFactory { - let mut factory: RSAPubFactory = Default::default(); + let mut factory: RSAPubFactory = RSAPubFactory { + data: ObjectFactoryData::new(CKO_PUBLIC_KEY), + }; factory.add_common_public_key_attrs(); @@ -344,7 +346,7 @@ impl RSAPrivateKey<'_> { } /// The RSA Private-Key Factory. -#[derive(Debug, Default)] +#[derive(Debug)] pub struct RSAPrivFactory { data: ObjectFactoryData, } @@ -356,7 +358,9 @@ impl RSAPrivFactory { /// attributes (CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, CKA_PRIME_1, etc.). /// Sets CKA_PRIVATE defaults appropriately. pub fn new() -> RSAPrivFactory { - let mut factory: RSAPrivFactory = Default::default(); + let mut factory: RSAPrivFactory = RSAPrivFactory { + data: ObjectFactoryData::new(CKO_PRIVATE_KEY), + }; factory.add_common_private_key_attrs(); diff --git a/src/slhdsa.rs b/src/slhdsa.rs index 14568f5b..146505c7 100644 --- a/src/slhdsa.rs +++ b/src/slhdsa.rs @@ -170,7 +170,7 @@ fn slhdsa_pub_check_import(obj: &Object) -> Result<()> { } /// The SLH-DSA Public Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct SlhDsaPubFactory { data: ObjectFactoryData, } @@ -178,7 +178,9 @@ pub struct SlhDsaPubFactory { impl SlhDsaPubFactory { /// Initializes a SLH-DSA Public Key Factory pub fn new() -> SlhDsaPubFactory { - let mut factory: SlhDsaPubFactory = Default::default(); + let mut factory: SlhDsaPubFactory = SlhDsaPubFactory { + data: ObjectFactoryData::new(CKO_PUBLIC_KEY), + }; factory.add_common_public_key_attrs(); @@ -286,7 +288,7 @@ fn slhdsa_priv_check_import(obj: &Object) -> Result<()> { } /// The SLH-DSA Private Key Factory -#[derive(Debug, Default)] +#[derive(Debug)] pub struct SlhDsaPrivFactory { data: ObjectFactoryData, } @@ -294,7 +296,9 @@ pub struct SlhDsaPrivFactory { impl SlhDsaPrivFactory { /// Initializes a SLH-DSA Private Key Factory pub fn new() -> SlhDsaPrivFactory { - let mut factory: SlhDsaPrivFactory = Default::default(); + let mut factory: SlhDsaPrivFactory = SlhDsaPrivFactory { + data: ObjectFactoryData::new(CKO_PRIVATE_KEY), + }; factory.add_common_private_key_attrs(); diff --git a/src/storage/nssdb/mod.rs b/src/storage/nssdb/mod.rs index 0fba3ba9..5af0e79c 100644 --- a/src/storage/nssdb/mod.rs +++ b/src/storage/nssdb/mod.rs @@ -505,7 +505,7 @@ impl NSSStorage { mut rows: Rows, attrs: &[CK_ATTRIBUTE], ) -> Result { - let mut obj = Object::new(); + let mut obj = Object::new(CK_UNAVAILABLE_INFORMATION); let (cols, offset) = if attrs.len() == 0 { (Cow::Borrowed(&self.cols), 1) @@ -577,6 +577,9 @@ impl NSSStorage { }; obj.set_attr(attr)?; } + if obj.get_class() == CK_UNAVAILABLE_INFORMATION { + return Err(CKR_GENERAL_ERROR)?; + } } /* ensure only one row was returned */ diff --git a/src/storage/sqlite.rs b/src/storage/sqlite.rs index 51ec56e6..da54f1b7 100644 --- a/src/storage/sqlite.rs +++ b/src/storage/sqlite.rs @@ -181,8 +181,20 @@ impl SqliteStorage { row.get::<_, u32>(1).map_err(bad_storage)? as CK_ULONG; let val = row.get_ref(2).map_err(bad_storage)?; if objid != id { + /* ensure current last object is valid before moving on */ + match objects.last_mut() { + Some(obj) => { + if obj.get_class() == CK_UNAVAILABLE_INFORMATION { + return Err(CKR_GENERAL_ERROR)?; + } + } + _ => (), + } + /* init a new object to populate */ + objects.push(Object::new(CK_UNAVAILABLE_INFORMATION)); + + /* mark the object id currently being processed */ objid = id; - objects.push(Object::new()); } match objects.last_mut() { Some(obj) => { diff --git a/src/tests/json_objects.rs b/src/tests/json_objects.rs index aef50d81..7042db66 100644 --- a/src/tests/json_objects.rs +++ b/src/tests/json_objects.rs @@ -140,7 +140,7 @@ impl JsonObjects { } } for jo in &self.objects { - let mut obj = Object::new(); + let mut obj = Object::new(CK_UNAVAILABLE_INFORMATION); for (key, val) in &jo.attributes { let (id, atype) = AttrType::attr_name_to_id_type(key)?; let attr = match atype { @@ -206,6 +206,9 @@ impl JsonObjects { obj.set_attr(attr)?; } + if obj.get_class() == CK_UNAVAILABLE_INFORMATION { + return Err(CKR_GENERAL_ERROR)?; + } store.store_obj(obj)?; } Ok(()) diff --git a/src/tests/mechs.rs b/src/tests/mechs.rs index c6e50be5..9740eb32 100644 --- a/src/tests/mechs.rs +++ b/src/tests/mechs.rs @@ -138,3 +138,66 @@ fn test_deny_mechs() { testtokn.finalize(); } + +#[test] +#[parallel] +fn test_mechanism_objects() { + let mut testtokn = TestToken::initialized("test_mechanism_objects", None); + let session = testtokn.get_session(true); + + let mut tmpl = make_attr_template(&[(CKA_CLASS, CKO_MECHANISM)], &[], &[]); + + let ret = fn_find_objects_init( + session, + tmpl.as_mut_ptr(), + tmpl.len() as CK_ULONG, + ); + assert_eq!(ret, CKR_OK); + + let mut handles = Vec::::with_capacity(64); + let mut count = 64; + while count == 64 { + let mut ph = [CK_INVALID_HANDLE; 64]; + let ret = fn_find_objects(session, ph.as_mut_ptr(), 64, &mut count); + assert_eq!(ret, CKR_OK); + if count > 0 { + handles.extend_from_slice(&ph[..count as usize]); + } + } + + let ret = fn_find_objects_final(session); + assert_eq!(ret, CKR_OK); + + assert!(handles.len() > 0, "No mechanism objects found"); + + for mech_type in [ + CKM_RSA_PKCS_KEY_PAIR_GEN, + CKM_SHA256, + CKM_GENERIC_SECRET_KEY_GEN, + ] { + let mut search_tmpl = make_attr_template( + &[(CKA_CLASS, CKO_MECHANISM), (CKA_MECHANISM_TYPE, mech_type)], + &[], + &[], + ); + + let ret = fn_find_objects_init( + session, + search_tmpl.as_mut_ptr(), + search_tmpl.len() as CK_ULONG, + ); + assert_eq!(ret, CKR_OK); + + let mut found_handle = CK_INVALID_HANDLE; + let mut found_count = 0; + let ret = + fn_find_objects(session, &mut found_handle, 1, &mut found_count); + assert_eq!(ret, CKR_OK); + assert_eq!(found_count, 1); + + let ret = fn_find_objects_final(session); + assert_eq!(ret, CKR_OK); + } + + testtokn.finalize(); +} diff --git a/src/tests/tls.rs b/src/tests/tls.rs index e041f9b8..d9559ab9 100644 --- a/src/tests/tls.rs +++ b/src/tests/tls.rs @@ -95,9 +95,7 @@ fn test_tlsprf_vectors() { let name = v.4; /* mock key */ - let mut key = object::Object::new(); - key.set_attr(Attribute::from_ulong(CKA_CLASS, CKO_SECRET_KEY)) - .unwrap(); + let mut key = object::Object::new(CKO_SECRET_KEY); key.set_attr(Attribute::from_ulong(CKA_KEY_TYPE, CKK_GENERIC_SECRET)) .unwrap(); key.set_attr(Attribute::from_bytes(CKA_VALUE, secret.clone())) diff --git a/src/token.rs b/src/token.rs index 609f7e0f..1a20bca4 100644 --- a/src/token.rs +++ b/src/token.rs @@ -177,11 +177,13 @@ impl Token { /// initialized or re-initialized. This function is meant to provision /// exclusively ephemeral data like internal session objects. fn token_internal_objects_init(&mut self) -> Result<()> { + // Add FIPS Validation objects #[cfg(feature = "fips")] if fips::token_init(self).is_err() { return Err(CKR_GENERAL_ERROR)?; } + // Add Profile Objects #[cfg(feature = "profiles")] { insert_profile_object(self, CKP_BASELINE_PROVIDER)?; @@ -193,6 +195,12 @@ impl Token { #[cfg(feature = "hkdf")] insert_profile_object(self, CKP_HKDF_TLS_TOKEN)?; } + + // Generate Mechanism Objects for each known Mechanism + for mech in self.get_mechs_list() { + insert_mechanism_object(self, mech)?; + } + Ok(()) } @@ -761,8 +769,7 @@ impl Token { /* First add internal session objects */ for (_, o) in &self.session_objects { - let builtin = o.get_attr_as_ulong(CKA_CLASS)? == CKO_PROFILE; - if !builtin && o.is_sensitive() { + if o.is_sensitive() { match self.facilities.factories.check_sensitive(o, template) { Err(_) => continue, Ok(()) => (), @@ -795,12 +802,32 @@ fn insert_profile_object( ) -> Result<()> { use crate::attribute::Attribute; - let mut obj = Object::new(); - obj.set_attr(Attribute::from_ulong(CKA_CLASS, CKO_PROFILE))?; + let mut obj = Object::new(CKO_PROFILE); obj.set_attr(Attribute::from_ulong(CKA_PROFILE_ID, profile_id))?; /* generate a unique id */ - obj.generate_unique(); + obj.generate_stable_unique(profile_id); + + /* invalid session handle will prevent it from being removed when + * session objects are cleared on session closings */ + let _ = token.insert_object(CK_INVALID_HANDLE, obj)?; + Ok(()) +} + +/// Synthesize a CKO_MECHANISM object + +/// These objects only have an attribute named CKA_MECHANISM_TYPE +pub fn insert_mechanism_object( + token: &mut Token, + mech_type: CK_MECHANISM_TYPE, +) -> Result<()> { + use crate::attribute::Attribute; + + let mut obj = Object::new(CKO_MECHANISM); + obj.set_attr(Attribute::from_ulong(CKA_MECHANISM_TYPE, mech_type))?; + + /* generate a unique id */ + obj.generate_stable_unique(mech_type); /* invalid session handle will prevent it from being removed when * session objects are cleared on session closings */