Skip to main content

kryoptic_lib/object/
factory.rs

1// Copyright 2023-2026 Simo Sorce
2// See LICENSE.txt file for terms
3
4use std::collections::HashMap;
5use std::fmt::Debug;
6use std::sync::LazyLock;
7
8use crate::attribute::{AttrType, Attribute};
9use crate::error::{Error, Result};
10use crate::mechanism::{Mechanism, Mechanisms};
11use crate::misc::{sizeof, void_ptr};
12use crate::pkcs11::*;
13
14#[cfg(feature = "nssdb")]
15use crate::pkcs11::vendor::nss::*;
16
17use super::certs::{TrustObject, X509Factory};
18use super::key::{
19    GenericSecretKeyFactory, GenericSecretKeyMechanism, KeyFactory,
20    PubKeyFactory, SecretKeyFactory,
21};
22use super::Object;
23
24#[cfg(feature = "nssdb")]
25use super::certs::NSSTrustObject;
26
27use bitflags::bitflags;
28
29/// Helper to map errors to CKR_TEMPLATE_INCOMPLETE
30pub fn incomplete(e: Error) -> Error {
31    if e.attr_not_found() {
32        Error::ck_rv(CKR_TEMPLATE_INCOMPLETE)
33    } else {
34        e
35    }
36}
37
38bitflags! {
39    /// A bitflag set that defines attribute properties and behaviors
40    #[derive(Debug, Clone, Copy)]
41    pub struct OAFlags: u32 {
42        /// the attribute is ignored and not copied from a template
43        const Ignored              = 0x00000001;
44
45        /// The attribute is sensitive and will not be returned by a call
46        /// unless specifically authorized (like a key secret value)
47        const Sensitive            = 0x00000002;
48
49        /// The attribute has a default value that can be set when it is
50        /// required on object creation but not provided by a template
51        const Defval               = 0x00000004;
52
53        /// The attribute must be provided in the template on object
54        /// creation or the operation will fail
55        const RequiredOnCreate     = 0x00000008;
56
57        /// The attribute must be provided in the template on key
58        /// generation or the operation will fail
59        const RequiredOnGenerate   = 0x00000010;
60
61        /// The attribute is always required or the operation will fail,
62        /// however combined with Defval it means it will be generated
63        /// automatically when absent from the template and will not
64        /// cause the operation to fail
65        const AlwaysRequired       = 0x00000020;
66
67        /// The attribute can only be set in a template for create
68        /// (import) operations, if set for any other operation (copy,
69        /// generate, wrap, derive) it will cause a failure
70        const SettableOnlyOnCreate = 0x00000080;
71
72        /// This attribute can never be set in a template, if set the
73        /// operation will fail (they are only ever set by internal
74        /// functions)
75        const NeverSettable        = 0x00000100;
76
77        /// The attribute cannot be changed once set (enforced from
78        /// changing via C_SetAttibuteValue or via C_CopyObject
79        const Unchangeable         = 0x00000400;
80
81        /// The attribute can only be changed from `True` to `False`
82        const ChangeToFalse        = 0x00000C00;
83
84        /// The attribute can only be changed from `False` to `True`
85        const ChangeToTrue         = 0x00001400;
86
87        /// The attribute can be changed only during a Copy Operation
88        const ChangeOnCopy         = 0x00002400;
89
90        /// The attribute is ephemeral and should not be stored on
91        /// permanent storage
92        const Ephemeral            = 0x00008000;
93    }
94}
95
96/// This object is used to list the attribute that are allowed for specific
97/// object types and also can define what if any their default value is and
98/// what operation can be done on this object by applications.
99
100#[derive(Debug, Clone)]
101pub struct ObjectAttr {
102    /// The reference attribute, may contain a default value
103    pub(crate) attribute: Attribute,
104    /// The flags that define the attribute properties for the object
105    /// class this ObjectAttr is applied to
106    flags: OAFlags,
107}
108
109impl ObjectAttr {
110    /// Creates a new ObjectAttr
111    pub fn new(a: Attribute, f: OAFlags) -> ObjectAttr {
112        ObjectAttr {
113            attribute: a,
114            flags: f,
115        }
116    }
117
118    /// Gets the internal attribute id (type)
119    pub fn get_type(&self) -> CK_ULONG {
120        self.attribute.get_type()
121    }
122
123    /// Check if a specific flag is present on the ObjectAttr
124    pub fn is(&self, val: OAFlags) -> bool {
125        if val.is_empty() {
126            return false;
127        }
128        self.flags.contains(val)
129    }
130
131    /// Checks if the ObjectAttr has a default value
132    pub fn has_default(&self) -> bool {
133        self.flags.contains(OAFlags::Defval)
134    }
135}
136
137/// Helper to quickly instantiate an ObjectAttr element
138#[macro_export]
139macro_rules! attr_element {
140    ($id:expr; $flags:expr; $from_type:expr; val $defval:expr) => {
141        $crate::object::factory::ObjectAttr::new(
142            $from_type($id, $defval),
143            $flags,
144        )
145    };
146}
147pub use attr_element;
148
149/// This trait must be implemented by any mechanisms that defines an
150/// object type, like key object of a specific type. The ObjectFactory
151/// is responsible for defining what are the allowed attributes for the
152/// specific object/key type, and any special behaviors for object
153/// creation/import or other manipulation.
154
155#[derive(Debug)]
156pub struct ObjectFactoryData {
157    /// Class of the object created by the factory
158    class: CK_OBJECT_CLASS,
159    /// List of valid attributes and their properties for this factory
160    attributes: Vec<ObjectAttr>,
161    /// List of attributes considered sensitive
162    sensitive: Vec<CK_ATTRIBUTE_TYPE>,
163    /// List of attributes that should never be saved in token storage
164    ephemeral: Vec<CK_ATTRIBUTE_TYPE>,
165    /// Flag that indicates this factory data has been finalized and cannot
166    /// be further modified
167    finalized: bool,
168}
169
170impl ObjectFactoryData {
171    pub fn new(class: CK_OBJECT_CLASS) -> ObjectFactoryData {
172        ObjectFactoryData {
173            class: class,
174            attributes: Vec::new(),
175            sensitive: Vec::new(),
176            ephemeral: Vec::new(),
177            finalized: false,
178        }
179    }
180
181    /// Return the class of the object created by the factory
182    pub fn get_class(&self) -> CK_OBJECT_CLASS {
183        self.class
184    }
185
186    /// Returns a reference to factory valid attributes and their properties
187    pub fn get_attributes(&self) -> &Vec<ObjectAttr> {
188        &self.attributes
189    }
190
191    /// Returns a mutable reference to factory valid attributes and
192    /// their properties
193    ///
194    /// This method panics if it is called after the factory data has
195    /// been finalized.
196    pub fn get_attributes_mut(&mut self) -> &mut Vec<ObjectAttr> {
197        if self.finalized {
198            panic!("Attempted modification after finalization");
199        }
200        &mut self.attributes
201    }
202
203    /// Get the list of sensitive attributes
204    ///
205    /// Empty until the factory data is finalized
206    pub fn get_sensitive(&self) -> &Vec<CK_ATTRIBUTE_TYPE> {
207        &self.sensitive
208    }
209
210    /// Get the list of ephemeral attributes
211    ///
212    /// Empty until the factory data is finalized
213    pub fn get_ephemeral(&self) -> &Vec<CK_ATTRIBUTE_TYPE> {
214        &self.ephemeral
215    }
216
217    /// Finalizes the factory data and populates the sensitive
218    /// and ephemeral lists
219    pub fn finalize(&mut self) {
220        for a in &self.attributes {
221            if a.is(OAFlags::Sensitive) {
222                self.sensitive.push(a.get_type());
223            }
224            if a.is(OAFlags::Ephemeral) {
225                self.ephemeral.push(a.get_type());
226            }
227        }
228        self.finalized = true;
229    }
230}
231
232/// This is a common trait to define common methods all objects implement
233/// and common attributes all objects posses
234///
235/// [Common attributes](https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/pkcs11-spec-v3.1-os.html#_Toc111203203)
236/// and
237/// [Storage Objects](https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/pkcs11-spec-v3.1-os.html#_Toc111203216)
238/// (Version 3.1)
239
240pub trait ObjectFactory: Debug + Send + Sync {
241    /// Creates a new object from the template
242    ///
243    /// Mechanism implementations that can create objects must implement
244    /// this function, the default implementation returns a general error.
245    fn create(&self, _template: &[CK_ATTRIBUTE]) -> Result<Object> {
246        return Err(CKR_GENERAL_ERROR)?;
247    }
248
249    /// Creates a new Built-In object from the template
250    ///
251    /// Implemented only by mechanism that provide built-in objects
252    fn builtin_create(&self, _id: CK_ULONG) -> Result<Object> {
253        return Err(CKR_GENERAL_ERROR)?;
254    }
255
256    /// Creates a copy of the object
257    ///
258    /// Uses the default_copy() internal method by default.
259    fn copy(&self, obj: &Object, template: &[CK_ATTRIBUTE]) -> Result<Object> {
260        self.default_copy(obj, template)
261    }
262
263    /// Adds the common object attributes defined in spec
264    fn add_common_object_attrs(&mut self) {
265        let attrs = self.get_data_mut().get_attributes_mut();
266        attrs.push(attr_element!(
267            CKA_CLASS; OAFlags::RequiredOnCreate;
268            Attribute::from_ulong; val 0));
269        attrs.push(attr_element!(
270            CKA_UNIQUE_ID; OAFlags::NeverSettable | OAFlags::Unchangeable;
271            Attribute::from_string; val String::new()));
272    }
273
274    /// Adds the storage object attributes defined in the spec
275    fn add_common_storage_attrs(&mut self, private: bool) {
276        self.add_common_object_attrs();
277        let attrs = self.get_data_mut().get_attributes_mut();
278        attrs.push(attr_element!(
279            CKA_TOKEN; OAFlags::Defval | OAFlags::ChangeOnCopy;
280            Attribute::from_bool; val false));
281        attrs.push(attr_element!(
282            CKA_PRIVATE; OAFlags::Defval | OAFlags::ChangeOnCopy;
283            Attribute::from_bool; val private));
284        attrs.push(attr_element!(
285            CKA_MODIFIABLE; OAFlags::Defval | OAFlags::ChangeOnCopy;
286            Attribute::from_bool; val true));
287        attrs.push(attr_element!(
288            CKA_LABEL; OAFlags::empty(); Attribute::from_string;
289            val String::new()));
290        attrs.push(attr_element!(
291            CKA_COPYABLE; OAFlags::Defval | OAFlags::ChangeToFalse;
292            Attribute::from_bool; val true));
293        attrs.push(attr_element!(
294            CKA_DESTROYABLE; OAFlags::Defval; Attribute::from_bool;
295            val true));
296    }
297
298    /// This function implements the creation/import/derivation of any object
299    /// type and encodes common rules to interpret the list of ObjectAttr for
300    /// the object.
301    ///
302    /// The unacceptable_flags argument defines what attributes can't be
303    /// manipulated by the calling function when their flag matches one of
304    /// the flags specified in this argument.
305    ///
306    /// The required_flags argument defines what attributes must be provided
307    /// in the template by the calling function when their flag matches one of
308    /// the flags specified in this argument.
309    ///
310    /// This function should not be overridden by specialized factories.
311
312    fn internal_object_create(
313        &self,
314        template: &[CK_ATTRIBUTE],
315        unacceptable_flags: OAFlags,
316        required_flags: OAFlags,
317    ) -> Result<Object> {
318        let data = self.get_data();
319        let mut obj = Object::new(data.get_class());
320
321        let attributes = data.get_attributes();
322        for ck_attr in template {
323            match attributes.iter().find(|a| a.get_type() == ck_attr.type_) {
324                Some(attr) => {
325                    if attr.is(unacceptable_flags) {
326                        return Err(CKR_ATTRIBUTE_TYPE_INVALID)?;
327                    }
328                    /* duplicate? */
329                    match obj.get_attr(ck_attr.type_) {
330                        Some(oa) => {
331                            if oa.get_type() != CKA_CLASS
332                                || (oa.get_type() == CKA_CLASS
333                                    && ck_attr.to_ulong()? != oa.to_ulong()?)
334                            {
335                                return Err(CKR_TEMPLATE_INCONSISTENT)?;
336                            }
337                        }
338                        None => (),
339                    }
340                    if !attr.is(OAFlags::Ignored) {
341                        obj.attributes.push(Attribute::from_ck_attr(ck_attr)?);
342                    }
343                }
344                None => {
345                    return Err(CKR_ATTRIBUTE_VALUE_INVALID)?;
346                }
347            }
348        }
349        for attr in attributes {
350            match obj.get_attr(attr.get_type()) {
351                Some(_) => (),
352                None => {
353                    if attr.has_default() {
354                        obj.attributes.push(attr.attribute.clone());
355                    } else if attr.is(required_flags)
356                        || attr.is(OAFlags::AlwaysRequired)
357                    {
358                        return Err(CKR_TEMPLATE_INCOMPLETE)?;
359                    }
360                }
361            }
362        }
363        Ok(obj)
364    }
365
366    fn default_object_create(
367        &self,
368        template: &[CK_ATTRIBUTE],
369    ) -> Result<Object> {
370        let mut obj = self.internal_object_create(
371            template,
372            OAFlags::NeverSettable,
373            OAFlags::RequiredOnCreate,
374        )?;
375        obj.generate_unique();
376        Ok(obj)
377    }
378
379    /// Adds an attribute to an object using the default value defined
380    /// for the attribute type in the factory
381    #[allow(dead_code)]
382    fn set_attribute_default(
383        &self,
384        attr: CK_ATTRIBUTE_TYPE,
385        obj: &mut Object,
386    ) -> Result<()> {
387        let attributes = self.get_data().get_attributes();
388        match attributes.iter().find(|a| a.get_type() == attr) {
389            Some(defattr) => {
390                if defattr.has_default() {
391                    obj.set_attr(defattr.attribute.clone())?;
392                }
393            }
394            None => (),
395        }
396        Ok(())
397    }
398
399    /// Helper to copy objects that respects the semantics and restrictions
400    /// defined in the PKCS#11 specification.
401    fn default_copy(
402        &self,
403        origin: &Object,
404        template: &[CK_ATTRIBUTE],
405    ) -> Result<Object> {
406        let attributes = self.get_data().get_attributes();
407        for ck_attr in template {
408            match attributes.iter().find(|a| a.get_type() == ck_attr.type_) {
409                Some(attr) => {
410                    if attr.is(OAFlags::Unchangeable) {
411                        if attr
412                            .is(OAFlags::ChangeToFalse | OAFlags::ChangeToTrue)
413                        {
414                            let val =
415                                match origin.get_attr_as_bool(ck_attr.type_) {
416                                    Ok(a) => a,
417                                    Err(_) => false,
418                                };
419                            if val && !attr.is(OAFlags::ChangeToFalse) {
420                                return Err(CKR_ATTRIBUTE_READ_ONLY)?;
421                            }
422                            if !val && !attr.is(OAFlags::ChangeToTrue) {
423                                return Err(CKR_ATTRIBUTE_READ_ONLY)?;
424                            }
425                        }
426                        if !attr.is(OAFlags::ChangeOnCopy) {
427                            return Err(CKR_ATTRIBUTE_READ_ONLY)?;
428                        }
429                    }
430                }
431                None => return Err(CKR_TEMPLATE_INCONSISTENT)?,
432            }
433        }
434
435        let mut obj = origin.blind_copy()?;
436        for ck_attr in template {
437            let _ = obj.set_attr(Attribute::from_ck_attr(ck_attr)?)?;
438        }
439
440        /* special attrs handling */
441        match obj.get_attr_as_bool(CKA_EXTRACTABLE) {
442            Ok(e) => {
443                let mut val = !e;
444                match obj.get_attr_as_bool(CKA_NEVER_EXTRACTABLE) {
445                    Ok(ne) => val &= ne,
446                    Err(_) => match origin.get_attr_as_bool(CKA_EXTRACTABLE) {
447                        Ok(oe) => val &= !oe,
448                        Err(_) => val = false,
449                    },
450                }
451                let _ = obj.set_attr(Attribute::from_bool(
452                    CKA_NEVER_EXTRACTABLE,
453                    val,
454                ))?;
455            }
456            Err(_) => (),
457        }
458        match obj.get_attr_as_bool(CKA_SENSITIVE) {
459            Ok(b) => {
460                let mut val = b;
461                match origin.get_attr_as_bool(CKA_ALWAYS_SENSITIVE) {
462                    Ok(ob) => val &= ob,
463                    Err(_) => match origin.get_attr_as_bool(CKA_SENSITIVE) {
464                        Ok(os) => val &= os,
465                        Err(_) => val = false,
466                    },
467                }
468                let _ = obj.set_attr(Attribute::from_bool(
469                    CKA_ALWAYS_SENSITIVE,
470                    val,
471                ))?;
472            }
473            Err(_) => (),
474        }
475
476        Ok(obj)
477    }
478
479    /// Helper function to check if the attributes specified in the template
480    /// can be modified according to the PKCS#11 rules for the specific object.
481    /// If an attribute provided in the template cannot be changed an
482    /// appropriate error is returned.
483    fn check_set_attributes(&self, template: &[CK_ATTRIBUTE]) -> Result<()> {
484        let attrs = self.get_data().get_attributes();
485        for ck_attr in template {
486            match attrs.iter().find(|a| a.get_type() == ck_attr.type_) {
487                None => return Err(CKR_ATTRIBUTE_TYPE_INVALID)?,
488                Some(attr) => {
489                    if attr.is(OAFlags::NeverSettable) {
490                        return Err(CKR_ACTION_PROHIBITED)?;
491                    }
492                    if attr.is(OAFlags::Unchangeable) {
493                        if attr.attribute.get_attrtype() == AttrType::BoolType {
494                            let val = ck_attr.to_bool()?;
495                            if val {
496                                if !attr.is(OAFlags::ChangeToTrue) {
497                                    return Err(CKR_ATTRIBUTE_READ_ONLY)?;
498                                }
499                            } else {
500                                if !attr.is(OAFlags::ChangeToFalse) {
501                                    return Err(CKR_ATTRIBUTE_READ_ONLY)?;
502                                }
503                            }
504                        } else {
505                            return Err(CKR_ATTRIBUTE_READ_ONLY)?;
506                        }
507                    }
508                }
509            }
510        }
511        Ok(())
512    }
513
514    /// Helper function to change the attributes of an existing object.
515    /// This helpers performs the necessary checks required to permit
516    /// object modification in accordance to the PKCS#11 specification
517    /// and returns an error if any check fails before any attribute is
518    /// modified.
519    fn set_object_attributes(
520        &self,
521        obj: &mut Object,
522        template: &[CK_ATTRIBUTE],
523    ) -> Result<()> {
524        if !obj.is_modifiable() {
525            return Err(CKR_ACTION_PROHIBITED)?;
526        }
527
528        /* first check that all attributes can be changed */
529        self.check_set_attributes(template)?;
530
531        /* if checks clear out, apply changes */
532        for ck_attr in template {
533            obj.set_attr(Attribute::from_ck_attr(ck_attr)?)?;
534        }
535
536        Ok(())
537    }
538
539    /// Helper method to get a reference to the ObjectFactoryData
540    fn get_data(&self) -> &ObjectFactoryData;
541
542    /// Helper method to get a mutable reference to the ObjectFactoryData
543    fn get_data_mut(&mut self) -> &mut ObjectFactoryData;
544
545    /// Helper to access traits that are only available for objects of
546    /// type Key, other types of objects should not implement this method.
547    fn as_key_factory(&self) -> Result<&dyn KeyFactory> {
548        Err(CKR_GENERAL_ERROR)?
549    }
550
551    /// Helper to access traits that are only available for objects of
552    /// class CKO_PUPBLIC_KEY. Other key type factories should not
553
554    /// implement this method.
555    fn as_public_key_factory(&self) -> Result<&dyn PubKeyFactory> {
556        Err(CKR_GENERAL_ERROR)?
557    }
558
559    /// Helper to access traits that are only available for objects of
560    /// class CKO_SECRET_KEY. Other key type factories should not
561    /// implement this method.
562    fn as_secret_key_factory(&self) -> Result<&dyn SecretKeyFactory> {
563        Err(CKR_GENERAL_ERROR)?
564    }
565}
566
567/// This is a specialized factory for objects of class CKO_DATA
568///
569/// [Data Objects](https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/pkcs11-spec-v3.1-os.html#_Toc111203218)
570/// (Version 3.1)
571
572#[derive(Debug)]
573struct DataFactory {
574    data: ObjectFactoryData,
575}
576
577impl DataFactory {
578    /// Initializes a new DataFactory object
579    fn new() -> DataFactory {
580        let mut factory: DataFactory = DataFactory {
581            data: ObjectFactoryData::new(CKO_DATA),
582        };
583
584        factory.add_common_storage_attrs(false);
585
586        let attributes = factory.data.get_attributes_mut();
587
588        attributes.push(attr_element!(
589            CKA_APPLICATION; OAFlags::Defval; Attribute::from_string;
590            val String::new()));
591        attributes.push(attr_element!(
592            CKA_OBJECT_ID; OAFlags::empty(); Attribute::from_bytes;
593            val Vec::new()));
594        attributes.push(attr_element!(
595            CKA_VALUE; OAFlags::Defval; Attribute::from_bytes;
596            val Vec::new()));
597
598        factory.data.finalize();
599
600        factory
601    }
602}
603
604impl ObjectFactory for DataFactory {
605    /// Creates a new Data Object from the template
606    ///
607    /// Uses `key_create()`
608    fn create(&self, template: &[CK_ATTRIBUTE]) -> Result<Object> {
609        self.default_object_create(template)
610    }
611
612    fn copy(
613        &self,
614        origin: &Object,
615        template: &[CK_ATTRIBUTE],
616    ) -> Result<Object> {
617        self.default_copy(origin, template)
618    }
619
620    fn get_data(&self) -> &ObjectFactoryData {
621        &self.data
622    }
623
624    fn get_data_mut(&mut self) -> &mut ObjectFactoryData {
625        &mut self.data
626    }
627}
628
629/// This is a specialized factory for objects of class CKO_PROFILE
630
631#[cfg(feature = "profiles")]
632#[derive(Debug)]
633pub struct ProfileFactory {
634    data: ObjectFactoryData,
635}
636
637#[cfg(feature = "profiles")]
638impl ProfileFactory {
639    /// Initializes a new ProfileFactory object
640    fn new() -> ProfileFactory {
641        let mut factory: ProfileFactory = ProfileFactory {
642            data: ObjectFactoryData::new(CKO_PROFILE),
643        };
644
645        factory.add_common_object_attrs();
646
647        let attributes = factory.data.get_attributes_mut();
648
649        attributes.push(attr_element!(
650            CKA_PROFILE_ID; OAFlags::RequiredOnCreate; Attribute::from_ulong;
651            val CK_UNAVAILABLE_INFORMATION));
652
653        factory.data.finalize();
654
655        factory
656    }
657}
658
659#[cfg(feature = "profiles")]
660impl ObjectFactory for ProfileFactory {
661    fn create(&self, _template: &[CK_ATTRIBUTE]) -> Result<Object> {
662        Err(CKR_TEMPLATE_INCOMPLETE)?
663    }
664
665    fn builtin_create(&self, profile_id: CK_PROFILE_ID) -> Result<Object> {
666        let mut pid = profile_id;
667        let attr = CK_ATTRIBUTE {
668            type_: CKA_PROFILE_ID,
669            pValue: void_ptr!(&mut pid),
670            ulValueLen: sizeof!(CK_PROFILE_ID),
671        };
672        let mut obj = self.internal_object_create(
673            &[attr],
674            OAFlags::empty(),
675            OAFlags::RequiredOnCreate,
676        )?;
677        obj.generate_stable_unique(profile_id);
678        Ok(obj)
679    }
680
681    fn copy(
682        &self,
683        _origin: &Object,
684        _template: &[CK_ATTRIBUTE],
685    ) -> Result<Object> {
686        Err(CKR_ACTION_PROHIBITED)?
687    }
688
689    fn get_data(&self) -> &ObjectFactoryData {
690        &self.data
691    }
692
693    fn get_data_mut(&mut self) -> &mut ObjectFactoryData {
694        &mut self.data
695    }
696}
697
698/// This is a specialized factory for objects of class CKO_MECHANISM
699
700#[derive(Debug)]
701pub struct MechanismFactory {
702    data: ObjectFactoryData,
703}
704
705impl MechanismFactory {
706    /// Initializes a new MechanismFactory object
707    fn new() -> MechanismFactory {
708        let mut factory: MechanismFactory = MechanismFactory {
709            data: ObjectFactoryData::new(CKO_MECHANISM),
710        };
711
712        factory.add_common_object_attrs();
713
714        let attributes = factory.data.get_attributes_mut();
715
716        attributes.push(attr_element!(
717            CKA_MECHANISM_TYPE; OAFlags::RequiredOnCreate; Attribute::from_ulong;
718            val CK_UNAVAILABLE_INFORMATION));
719
720        factory.data.finalize();
721
722        factory
723    }
724}
725
726impl ObjectFactory for MechanismFactory {
727    fn create(&self, _template: &[CK_ATTRIBUTE]) -> Result<Object> {
728        Err(CKR_TEMPLATE_INCOMPLETE)?
729    }
730
731    fn builtin_create(
732        &self,
733        mechanism_type: CK_MECHANISM_TYPE,
734    ) -> Result<Object> {
735        let mut mt = mechanism_type;
736        let attr = CK_ATTRIBUTE {
737            type_: CKA_MECHANISM_TYPE,
738            pValue: void_ptr!(&mut mt),
739            ulValueLen: sizeof!(CK_MECHANISM_TYPE),
740        };
741        let mut obj = self.internal_object_create(
742            &[attr],
743            OAFlags::empty(),
744            OAFlags::RequiredOnCreate,
745        )?;
746        obj.generate_stable_unique(mechanism_type);
747        Ok(obj)
748    }
749
750    fn copy(
751        &self,
752        _origin: &Object,
753        _template: &[CK_ATTRIBUTE],
754    ) -> Result<Object> {
755        Err(CKR_ACTION_PROHIBITED)?
756    }
757
758    fn get_data(&self) -> &ObjectFactoryData {
759        &self.data
760    }
761
762    fn get_data_mut(&mut self) -> &mut ObjectFactoryData {
763        &mut self.data
764    }
765}
766
767/// Structure that defines an Object Type
768///
769/// Holds a Class type and the underlying type.
770///
771/// For object classes that have no underlying type `type_` is set to 0.
772#[derive(Debug, Eq, Hash, PartialEq)]
773pub struct ObjectType {
774    class: CK_ULONG,
775    type_: CK_ULONG,
776}
777
778impl ObjectType {
779    /// Initializes and returns a new ObjectType
780    pub fn new(class: CK_ULONG, type_: CK_ULONG) -> ObjectType {
781        ObjectType {
782            class: class,
783            type_: type_,
784        }
785    }
786}
787
788/// This structure holds all of the registered object factories for
789/// the implemented object types.
790///
791/// It provides accessors to find and retrieve object factories, and
792/// to add object factories at token initialization.
793
794#[derive(Debug)]
795pub struct ObjectFactories {
796    factories: HashMap<ObjectType, &'static Box<dyn ObjectFactory>>,
797}
798
799impl ObjectFactories {
800    /// Crates a new Object Factory registry
801    pub fn new() -> ObjectFactories {
802        ObjectFactories {
803            factories: HashMap::new(),
804        }
805    }
806
807    /// Adds a factory to the registry
808    pub fn add_factory(
809        &mut self,
810        otype: ObjectType,
811        templ: &'static Box<dyn ObjectFactory>,
812    ) {
813        self.factories.insert(otype, templ);
814    }
815
816    /// Retrieves a factory for the specified object type from the registry
817    pub fn get_factory(
818        &self,
819        otype: ObjectType,
820    ) -> Result<&Box<dyn ObjectFactory>> {
821        match self.factories.get(&otype) {
822            Some(b) => Ok(b),
823            None => Err(CKR_ATTRIBUTE_VALUE_INVALID)?,
824        }
825    }
826
827    /// Crates a new object using the appropriate factory based on the
828    /// data in the template.
829    pub fn create(&self, template: &[CK_ATTRIBUTE]) -> Result<Object> {
830        let class = match template.iter().find(|a| a.type_ == CKA_CLASS) {
831            Some(c) => c.to_ulong()?,
832            None => return Err(CKR_TEMPLATE_INCOMPLETE)?,
833        };
834        let type_ = match class {
835            CKO_DATA | CKO_TRUST | CKO_PROFILE | CKO_MECHANISM => 0,
836            #[cfg(feature = "nssdb")]
837            CKO_NSS_TRUST => 0,
838            CKO_CERTIFICATE => {
839                match template.iter().find(|a| a.type_ == CKA_CERTIFICATE_TYPE)
840                {
841                    Some(c) => c.to_ulong()?,
842                    None => return Err(CKR_TEMPLATE_INCOMPLETE)?,
843                }
844            }
845            CKO_PUBLIC_KEY => {
846                match template.iter().find(|a| a.type_ == CKA_KEY_TYPE) {
847                    Some(k) => k.to_ulong()?,
848                    None => return Err(CKR_TEMPLATE_INCOMPLETE)?,
849                }
850            }
851            CKO_PRIVATE_KEY => {
852                match template.iter().find(|a| a.type_ == CKA_KEY_TYPE) {
853                    Some(k) => k.to_ulong()?,
854                    None => return Err(CKR_TEMPLATE_INCOMPLETE)?,
855                }
856            }
857            CKO_SECRET_KEY | CKO_OTP_KEY => {
858                match template.iter().find(|a| a.type_ == CKA_KEY_TYPE) {
859                    Some(k) => k.to_ulong()?,
860                    None => return Err(CKR_TEMPLATE_INCOMPLETE)?,
861                }
862            }
863            /* TODO:
864             * CKO_HW_FEATURE, CKO_DOMAIN_PARAMETERS,
865             * CKO_VENDOR_DEFINED.
866             * Builtin objects cannot be created so they always return
867             * this error. Unsupported objects alaso return the same.
868             */
869            _ => return Err(CKR_TEMPLATE_INCONSISTENT)?,
870        };
871        self.get_factory(ObjectType::new(class, type_))?
872            .create(template)
873    }
874
875    /// Returns the object factory associated to the specified object
876    pub fn get_object_factory(
877        &self,
878        obj: &Object,
879    ) -> Result<&Box<dyn ObjectFactory>> {
880        let class = obj.get_attr_as_ulong(CKA_CLASS)?;
881        let type_ = match class {
882            CKO_CERTIFICATE => obj.get_attr_as_ulong(CKA_CERTIFICATE_TYPE)?,
883            CKO_PUBLIC_KEY | CKO_PRIVATE_KEY | CKO_SECRET_KEY | CKO_OTP_KEY => {
884                obj.get_attr_as_ulong(CKA_KEY_TYPE)?
885            }
886            _ => 0,
887        };
888        self.get_factory(ObjectType::new(class, type_))
889    }
890
891    fn get_template_attribute(
892        oa: &Attribute,
893        ck_attr: &mut CK_ATTRIBUTE,
894        result: &mut CK_RV,
895    ) -> Result<()> {
896        let stored_attrs = oa.to_template()?;
897        let stored_count = stored_attrs.len();
898        let ck_attr_size = std::mem::size_of::<CK_ATTRIBUTE>();
899        let expected_len = CK_ULONG::try_from(stored_count * ck_attr_size)?;
900
901        // 1. Size Inquiry (ck_attr.pValue.is_null())
902        if ck_attr.pValue.is_null() {
903            ck_attr.ulValueLen = expected_len;
904            return Ok(());
905        }
906
907        // 2. Validation
908        let val_len = usize::try_from(ck_attr.ulValueLen)?;
909        if val_len % ck_attr_size != 0 {
910            ck_attr.ulValueLen = CK_UNAVAILABLE_INFORMATION;
911            if *result == CKR_OK {
912                *result = CKR_TEMPLATE_INCONSISTENT;
913            }
914            return Ok(());
915        }
916
917        let app_count = val_len / ck_attr_size;
918        if app_count != stored_count {
919            ck_attr.ulValueLen = CK_UNAVAILABLE_INFORMATION;
920            if *result == CKR_OK {
921                *result = CKR_TEMPLATE_INCONSISTENT;
922            }
923            return Ok(());
924        }
925
926        if app_count == 0 {
927            ck_attr.ulValueLen = 0;
928            return Ok(());
929        }
930
931        let app_attrs: &mut [CK_ATTRIBUTE] = unsafe {
932            std::slice::from_raw_parts_mut(
933                ck_attr.pValue as *mut CK_ATTRIBUTE,
934                app_count,
935            )
936        };
937
938        let unavail_count = app_attrs
939            .iter()
940            .filter(|a| a.type_ == CK_UNAVAILABLE_INFORMATION)
941            .count();
942
943        if unavail_count != 0 && unavail_count != app_count {
944            ck_attr.ulValueLen = CK_UNAVAILABLE_INFORMATION;
945            if *result == CKR_OK {
946                *result = CKR_TEMPLATE_INCONSISTENT;
947            }
948            return Ok(());
949        }
950
951        // 3. Field Discovery Mode (all types == CK_UNAVAILABLE_INFORMATION)
952        if unavail_count == app_count {
953            if app_attrs
954                .iter()
955                .any(|a| !a.pValue.is_null() || a.ulValueLen != 0)
956            {
957                ck_attr.ulValueLen = CK_UNAVAILABLE_INFORMATION;
958                if *result == CKR_OK {
959                    *result = CKR_TEMPLATE_INCONSISTENT;
960                }
961                return Ok(());
962            }
963
964            for i in 0..app_count {
965                app_attrs[i].type_ = stored_attrs[i].get_type();
966                app_attrs[i].ulValueLen =
967                    CK_ULONG::try_from(stored_attrs[i].get_value().len())?;
968                app_attrs[i].pValue = std::ptr::null_mut();
969            }
970            ck_attr.ulValueLen = expected_len;
971            return Ok(());
972        }
973
974        // 4. Value Retrieval Mode (all types specified)
975        for (idx, a) in app_attrs.iter().enumerate() {
976            if app_attrs[idx + 1..]
977                .iter()
978                .any(|other| other.type_ == a.type_)
979            {
980                ck_attr.ulValueLen = CK_UNAVAILABLE_INFORMATION;
981                if *result == CKR_OK {
982                    *result = CKR_TEMPLATE_INCONSISTENT;
983                }
984                return Ok(());
985            }
986        }
987
988        for inner in app_attrs.iter_mut() {
989            match stored_attrs.iter().find(|sa| sa.get_type() == inner.type_) {
990                Some(sa) => {
991                    let attr_val = sa.get_value();
992                    let attr_len = CK_ULONG::try_from(attr_val.len())?;
993                    if inner.pValue.is_null() {
994                        inner.ulValueLen = attr_len;
995                    } else if inner.ulValueLen == CK_UNAVAILABLE_INFORMATION {
996                        if *result == CKR_OK {
997                            *result = CKR_TEMPLATE_INCONSISTENT;
998                        }
999                    } else if inner.ulValueLen < attr_len {
1000                        inner.ulValueLen = CK_UNAVAILABLE_INFORMATION;
1001                        if *result == CKR_OK {
1002                            *result = CKR_BUFFER_TOO_SMALL;
1003                        }
1004                    } else {
1005                        inner.ulValueLen = attr_len;
1006                        unsafe {
1007                            std::ptr::copy_nonoverlapping(
1008                                attr_val.as_ptr(),
1009                                inner.pValue as *mut u8,
1010                                attr_val.len(),
1011                            );
1012                        }
1013                    }
1014                }
1015                None => {
1016                    inner.ulValueLen = CK_UNAVAILABLE_INFORMATION;
1017                    if *result == CKR_OK {
1018                        *result = CKR_TEMPLATE_INCONSISTENT;
1019                    }
1020                }
1021            }
1022        }
1023
1024        ck_attr.ulValueLen = expected_len;
1025        Ok(())
1026    }
1027
1028    /// Helper to check if the template includes invalid or sensitive
1029    /// attributes related to the specified object. This is done by
1030    /// sourcing the object factory related to the provide object and
1031    /// then using object type specific attribute lists.
1032    pub fn check_sensitive(
1033        &self,
1034        obj: &Object,
1035        template: &[CK_ATTRIBUTE],
1036    ) -> Result<()> {
1037        let objtype_attrs =
1038            self.get_object_factory(obj)?.get_data().get_attributes();
1039        for ck_attr in template {
1040            match objtype_attrs.iter().find(|a| a.get_type() == ck_attr.type_) {
1041                None => return Err(CKR_ATTRIBUTE_TYPE_INVALID)?,
1042                Some(attr) => {
1043                    if attr.is(OAFlags::Sensitive) {
1044                        return Err(CKR_ATTRIBUTE_SENSITIVE)?;
1045                    }
1046                }
1047            }
1048        }
1049        Ok(())
1050    }
1051
1052    /// Fills the template with the specified attributes from the provided
1053    /// object. Ensures the attribute are valid and can be returned. If the
1054    /// object is not extractable and a sensitive attribute is requested an
1055    /// appropriate error is returned and the template is not filled, except
1056    /// for setting the ulValueLen of the forbidden attributes appropriately
1057    /// as required by the PKCS#11 specification.
1058    pub fn get_object_attributes(
1059        &self,
1060        obj: &Object,
1061        template: &mut [CK_ATTRIBUTE],
1062    ) -> Result<()> {
1063        let sensitive = obj.is_sensitive() || !obj.is_extractable();
1064        let mut result = CKR_OK;
1065
1066        let factory_attrs =
1067            self.get_object_factory(obj)?.get_data().get_attributes();
1068        let obj_attrs = obj.get_attributes();
1069
1070        for ck_attr in template.iter_mut() {
1071            let valid: bool;
1072
1073            /* check if this attribute is valid/allowed */
1074            match factory_attrs.iter().find(|a| a.get_type() == ck_attr.type_) {
1075                Some(fa) => {
1076                    if sensitive && fa.is(OAFlags::Sensitive) {
1077                        ck_attr.ulValueLen = CK_UNAVAILABLE_INFORMATION;
1078                        if result == CKR_OK {
1079                            result = CKR_ATTRIBUTE_SENSITIVE;
1080                        }
1081                        valid = false;
1082                    } else {
1083                        valid = true;
1084                    }
1085                }
1086                None => {
1087                    /* This attribute is not valid for given object type */
1088                    ck_attr.ulValueLen = CK_UNAVAILABLE_INFORMATION;
1089                    if result == CKR_OK {
1090                        result = CKR_ATTRIBUTE_TYPE_INVALID;
1091                    }
1092                    valid = false;
1093                }
1094            }
1095
1096            if !valid {
1097                /* The attribute value can't be returned, it is either sesntive
1098                 * or the attribute type is invalid for this object class.
1099                 * Continue to the next one skipping the code that copies the
1100                 * values in the template */
1101                continue;
1102            }
1103
1104            match obj_attrs.iter().find(|a| a.get_type() == ck_attr.type_) {
1105                Some(oa) => {
1106                    if oa.get_attrtype() == AttrType::TemplateType {
1107                        Self::get_template_attribute(oa, ck_attr, &mut result)?;
1108                        continue;
1109                    }
1110                    let attr_val = oa.get_value();
1111                    let attr_len = CK_ULONG::try_from(attr_val.len())?;
1112                    if ck_attr.pValue.is_null() {
1113                        ck_attr.ulValueLen = attr_len;
1114                    } else if ck_attr.ulValueLen == CK_UNAVAILABLE_INFORMATION {
1115                        if result == CKR_OK {
1116                            result = CKR_TEMPLATE_INCONSISTENT;
1117                        }
1118                    } else {
1119                        if ck_attr.ulValueLen < attr_len {
1120                            ck_attr.ulValueLen = CK_UNAVAILABLE_INFORMATION;
1121                            if result == CKR_OK {
1122                                result = CKR_BUFFER_TOO_SMALL;
1123                            }
1124                        } else {
1125                            ck_attr.ulValueLen = attr_len;
1126                            unsafe {
1127                                std::ptr::copy_nonoverlapping(
1128                                    attr_val.as_ptr(),
1129                                    ck_attr.pValue as *mut _,
1130                                    attr_val.len(),
1131                                );
1132                            }
1133                        }
1134                    }
1135                }
1136                None => {
1137                    /* This attribute is not available on given object */
1138                    ck_attr.ulValueLen = CK_UNAVAILABLE_INFORMATION;
1139                    if result == CKR_OK {
1140                        result = CKR_ATTRIBUTE_TYPE_INVALID;
1141                    }
1142                }
1143            }
1144        }
1145        if result == CKR_OK {
1146            Ok(())
1147        } else {
1148            Err(result)?
1149        }
1150    }
1151
1152    /// Uses an object type specific copy operation to return a copy
1153    /// of the provided object
1154    pub fn copy(
1155        &self,
1156        obj: &Object,
1157        template: &[CK_ATTRIBUTE],
1158    ) -> Result<Object> {
1159        if !obj.is_copyable() {
1160            return Err(CKR_ACTION_PROHIBITED)?;
1161        }
1162        self.get_object_factory(obj)?.copy(obj, template)
1163    }
1164
1165    /// Finds the appropriate object factory to operate on the object
1166    /// defined by the template
1167    pub fn get_obj_factory_from_key_template(
1168        &self,
1169        template: &[CK_ATTRIBUTE],
1170    ) -> Result<&Box<dyn ObjectFactory>> {
1171        let class = match template.iter().position(|x| x.type_ == CKA_CLASS) {
1172            Some(idx) => template[idx].to_ulong()?,
1173            None => return Err(CKR_TEMPLATE_INCONSISTENT)?,
1174        };
1175        let key_type =
1176            match template.iter().position(|x| x.type_ == CKA_KEY_TYPE) {
1177                Some(idx) => template[idx].to_ulong()?,
1178                None => return Err(CKR_TEMPLATE_INCONSISTENT)?,
1179            };
1180        self.get_factory(ObjectType::new(class, key_type))
1181    }
1182
1183    /// Finds the appropriate object factory for the derivation template
1184    /// provided and attempts a key derivation operation.
1185    pub fn derive_key_from_template(
1186        &self,
1187        key: &Object,
1188        template: &[CK_ATTRIBUTE],
1189    ) -> Result<Object> {
1190        let factory = self.get_obj_factory_from_key_template(template)?;
1191        factory.as_key_factory()?.key_derive(template, key)
1192    }
1193}
1194
1195/// The static Data Object factory
1196static DATA_OBJECT_FACTORY: LazyLock<Box<dyn ObjectFactory>> =
1197    LazyLock::new(|| Box::new(DataFactory::new()));
1198
1199/// The static X509 Certificate factory
1200static X509_CERT_FACTORY: LazyLock<Box<dyn ObjectFactory>> =
1201    LazyLock::new(|| Box::new(X509Factory::new()));
1202
1203/// The static Trust Object factory
1204static TRUST_OBJECT_FACTORY: LazyLock<Box<dyn ObjectFactory>> =
1205    LazyLock::new(|| Box::new(TrustObject::new()));
1206
1207/// The static NSS Trust Object factory
1208#[cfg(feature = "nssdb")]
1209static NSS_TRUST_OBJECT_FACTORY: LazyLock<Box<dyn ObjectFactory>> =
1210    LazyLock::new(|| Box::new(NSSTrustObject::new()));
1211
1212/// The static Profile Object factory
1213#[cfg(feature = "profiles")]
1214static PROFILE_FACTORY: LazyLock<Box<dyn ObjectFactory>> =
1215    LazyLock::new(|| Box::new(ProfileFactory::new()));
1216
1217/// The static Mechanism Object factory
1218static MECHANISM_FACTORY: LazyLock<Box<dyn ObjectFactory>> =
1219    LazyLock::new(|| Box::new(MechanismFactory::new()));
1220
1221/// Object that holds Mechanisms for Generic Secrets
1222static GENERIC_SECRET: LazyLock<Box<dyn Mechanism>> = LazyLock::new(|| {
1223    Box::new(GenericSecretKeyMechanism::new(CKK_GENERIC_SECRET))
1224});
1225
1226/// The static Generic Secret factory
1227pub(crate) static GENERIC_SECRET_FACTORY: LazyLock<Box<dyn ObjectFactory>> =
1228    LazyLock::new(|| Box::new(GenericSecretKeyFactory::new()));
1229
1230/// Registers mechanisms and key factories for Data Objects, X509
1231/// Certificates and Generic Secret Keys
1232pub fn register(mechs: &mut Mechanisms, ot: &mut ObjectFactories) {
1233    mechs.add_mechanism(CKM_GENERIC_SECRET_KEY_GEN, &(*GENERIC_SECRET));
1234
1235    ot.add_factory(ObjectType::new(CKO_DATA, 0), &(*DATA_OBJECT_FACTORY));
1236    ot.add_factory(
1237        ObjectType::new(CKO_CERTIFICATE, CKC_X_509),
1238        &(*X509_CERT_FACTORY),
1239    );
1240    ot.add_factory(
1241        ObjectType::new(CKO_SECRET_KEY, CKK_GENERIC_SECRET),
1242        &(*GENERIC_SECRET_FACTORY),
1243    );
1244    ot.add_factory(ObjectType::new(CKO_TRUST, 0), &(*TRUST_OBJECT_FACTORY));
1245    #[cfg(feature = "nssdb")]
1246    ot.add_factory(
1247        ObjectType::new(CKO_NSS_TRUST, 0),
1248        &(*NSS_TRUST_OBJECT_FACTORY),
1249    );
1250    #[cfg(feature = "profiles")]
1251    ot.add_factory(ObjectType::new(CKO_PROFILE, 0), &(*PROFILE_FACTORY));
1252    ot.add_factory(ObjectType::new(CKO_MECHANISM, 0), &(*MECHANISM_FACTORY));
1253}
1254
1255#[cfg(test)]
1256mod tests {
1257    use super::*;
1258    use crate::attribute::serialize_template;
1259
1260    #[test]
1261    fn test_get_template_attribute_lifecycle() {
1262        let mut of = ObjectFactories::new();
1263        of.add_factory(
1264            ObjectType::new(CKO_SECRET_KEY, CKK_GENERIC_SECRET),
1265            &(*GENERIC_SECRET_FACTORY),
1266        );
1267
1268        let mut obj = Object::new(CKO_SECRET_KEY);
1269        obj.set_attr(Attribute::from_ulong(CKA_KEY_TYPE, CKK_GENERIC_SECRET))
1270            .unwrap();
1271        obj.set_attr(Attribute::from_bool(CKA_EXTRACTABLE, true))
1272            .unwrap();
1273        obj.set_attr(Attribute::from_bool(CKA_SENSITIVE, false))
1274            .unwrap();
1275
1276        let inner_attrs = vec![
1277            Attribute::from_bool(CKA_ENCRYPT, true),
1278            Attribute::from_ulong(CKA_VALUE_LEN, 32),
1279        ];
1280        let serialized = serialize_template(&inner_attrs).unwrap();
1281        obj.set_attr(Attribute::from_template_bytes(
1282            CKA_DERIVE_TEMPLATE,
1283            serialized,
1284        ))
1285        .unwrap();
1286
1287        let ck_attr_size = std::mem::size_of::<CK_ATTRIBUTE>();
1288
1289        // 1. Size Inquiry
1290        let mut query = [CK_ATTRIBUTE {
1291            type_: CKA_DERIVE_TEMPLATE,
1292            pValue: std::ptr::null_mut(),
1293            ulValueLen: 0,
1294        }];
1295        assert!(of.get_object_attributes(&obj, &mut query).is_ok());
1296        assert_eq!(query[0].ulValueLen, (2 * ck_attr_size) as CK_ULONG);
1297
1298        // 2. Discovery Mode
1299        let mut disc_attrs = [
1300            CK_ATTRIBUTE {
1301                type_: CK_UNAVAILABLE_INFORMATION,
1302                pValue: std::ptr::null_mut(),
1303                ulValueLen: 0,
1304            },
1305            CK_ATTRIBUTE {
1306                type_: CK_UNAVAILABLE_INFORMATION,
1307                pValue: std::ptr::null_mut(),
1308                ulValueLen: 0,
1309            },
1310        ];
1311        let mut query = [CK_ATTRIBUTE {
1312            type_: CKA_DERIVE_TEMPLATE,
1313            pValue: disc_attrs.as_mut_ptr() as *mut std::ffi::c_void,
1314            ulValueLen: (2 * ck_attr_size) as CK_ULONG,
1315        }];
1316        assert!(of.get_object_attributes(&obj, &mut query).is_ok());
1317        assert_eq!(disc_attrs[0].type_, CKA_ENCRYPT);
1318        assert_eq!(disc_attrs[0].ulValueLen, 1);
1319        assert!(disc_attrs[0].pValue.is_null());
1320        assert_eq!(disc_attrs[1].type_, CKA_VALUE_LEN);
1321        assert_eq!(disc_attrs[1].ulValueLen, sizeof!(CK_ULONG));
1322        assert!(disc_attrs[1].pValue.is_null());
1323
1324        // 3. Discovery with non-null pValue -> CKR_TEMPLATE_INCONSISTENT
1325        let mut dummy = 0u8;
1326        disc_attrs[0].pValue = &mut dummy as *mut _ as *mut std::ffi::c_void;
1327        disc_attrs[0].type_ = CK_UNAVAILABLE_INFORMATION;
1328        disc_attrs[1].type_ = CK_UNAVAILABLE_INFORMATION;
1329        let mut query = [CK_ATTRIBUTE {
1330            type_: CKA_DERIVE_TEMPLATE,
1331            pValue: disc_attrs.as_mut_ptr() as *mut std::ffi::c_void,
1332            ulValueLen: (2 * ck_attr_size) as CK_ULONG,
1333        }];
1334        assert_eq!(
1335            of.get_object_attributes(&obj, &mut query).unwrap_err().rv(),
1336            CKR_TEMPLATE_INCONSISTENT
1337        );
1338
1339        // 4. Mixed types -> CKR_TEMPLATE_INCONSISTENT
1340        disc_attrs[0].pValue = std::ptr::null_mut();
1341        disc_attrs[0].type_ = CKA_ENCRYPT;
1342        disc_attrs[1].type_ = CK_UNAVAILABLE_INFORMATION;
1343        let mut query = [CK_ATTRIBUTE {
1344            type_: CKA_DERIVE_TEMPLATE,
1345            pValue: disc_attrs.as_mut_ptr() as *mut std::ffi::c_void,
1346            ulValueLen: (2 * ck_attr_size) as CK_ULONG,
1347        }];
1348        assert_eq!(
1349            of.get_object_attributes(&obj, &mut query).unwrap_err().rv(),
1350            CKR_TEMPLATE_INCONSISTENT
1351        );
1352
1353        // 5. Value Retrieval Mode
1354        let mut enc_val: CK_BBOOL = CK_FALSE;
1355        let mut vlen_val: CK_ULONG = 0;
1356        let mut val_attrs = [
1357            CK_ATTRIBUTE {
1358                type_: CKA_ENCRYPT,
1359                pValue: &mut enc_val as *mut _ as *mut std::ffi::c_void,
1360                ulValueLen: sizeof!(CK_BBOOL),
1361            },
1362            CK_ATTRIBUTE {
1363                type_: CKA_VALUE_LEN,
1364                pValue: &mut vlen_val as *mut _ as *mut std::ffi::c_void,
1365                ulValueLen: sizeof!(CK_ULONG),
1366            },
1367        ];
1368        let mut query = [CK_ATTRIBUTE {
1369            type_: CKA_DERIVE_TEMPLATE,
1370            pValue: val_attrs.as_mut_ptr() as *mut std::ffi::c_void,
1371            ulValueLen: (2 * ck_attr_size) as CK_ULONG,
1372        }];
1373        assert!(of.get_object_attributes(&obj, &mut query).is_ok());
1374        assert_eq!(enc_val, CK_TRUE);
1375        assert_eq!(vlen_val, 32);
1376
1377        // 6. Buffer too small
1378        val_attrs[0].ulValueLen = 0;
1379        let mut query = [CK_ATTRIBUTE {
1380            type_: CKA_DERIVE_TEMPLATE,
1381            pValue: val_attrs.as_mut_ptr() as *mut std::ffi::c_void,
1382            ulValueLen: (2 * ck_attr_size) as CK_ULONG,
1383        }];
1384        assert_eq!(
1385            of.get_object_attributes(&obj, &mut query).unwrap_err().rv(),
1386            CKR_BUFFER_TOO_SMALL
1387        );
1388        assert_eq!(val_attrs[0].ulValueLen, CK_UNAVAILABLE_INFORMATION);
1389    }
1390}