Skip to main content

signstar_yubihsm2/object/
capability.rs

1//! YubiHSM2 object capabilities.
2
3use std::{collections::BTreeSet, fmt::Display, hash::Hash};
4
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7use strum::{AsRefStr, Display, EnumIter, EnumString, IntoEnumIterator, IntoStaticStr};
8
9/// A capability of an object stored on a YubiHSM2.
10#[derive(
11    AsRefStr,
12    Clone,
13    Copy,
14    Debug,
15    Display,
16    EnumIter,
17    EnumString,
18    Eq,
19    Hash,
20    IntoStaticStr,
21    Ord,
22    PartialEq,
23    PartialOrd,
24)]
25#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
26#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
27#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
28#[strum(serialize_all = "kebab-case")]
29pub enum Capability {
30    /// Replace authentication key objects.
31    ///
32    /// Applicable for authentication key objects.
33    ChangeAuthenticationKey,
34
35    /// Create OTP AEAD.
36    ///
37    /// Applicable for authentication and OTP AEAD key objects.
38    CreateOtpAead,
39
40    /// Decrypt data using AES CBC mode.
41    ///
42    /// Applicable for authentication and symmetric key objects.
43    DecryptCbc,
44
45    /// Decrypt data using AES ECB mode.
46    ///
47    /// Applicable for authentication and symmetric key objects.
48    DecryptEcb,
49
50    /// Decrypt data using RSA-OAEP.
51    ///
52    /// Applicable for authentication and asymmetric key objects.
53    DecryptOaep,
54
55    /// Decrypt OTP.
56    ///
57    /// Applicable for authentication and OTP AEAD key objects.
58    DecryptOtp,
59
60    /// Decrypt data using RSA-PKCS1v1.5.
61    ///
62    /// Applicable for authentication and asymmetric key objects.
63    DecryptPkcs,
64
65    /// Delete asymmetric key objects.
66    ///
67    /// Applicable for authentication key objects.
68    DeleteAsymmetricKey,
69
70    /// Delete authentication key objects.
71    ///
72    /// Applicable for authentication key objects.
73    DeleteAuthenticationKey,
74
75    /// Delete HMAC key objects.
76    ///
77    /// Applicable for authentication key objects.
78    DeleteHmacKey,
79
80    /// Delete opaque objects.
81    ///
82    /// Applicable for authentication key objects.
83    DeleteOpaque,
84
85    /// Delete OTP AEAD key objects.
86    ///
87    /// Applicable for authentication key objects.
88    DeleteOtpAeadKey,
89
90    /// Delete RSA public wrap key.
91    ///
92    /// Applicable for authentication and wrap key objects.
93    DeletePublicWrapKey,
94
95    /// Delete AES key.
96    ///
97    /// Applicable for authentication key objects.
98    DeleteSymmetricKey,
99
100    /// Delete template objects.
101    ///
102    /// Applicable for authentication key objects.
103    DeleteTemplate,
104
105    /// Delete wrap key objects.
106    ///
107    /// Applicable for authentication key objects.
108    DeleteWrapKey,
109
110    /// Perform ECDH.
111    ///
112    /// Applicable for authentication and asymmetric key objects.
113    DeriveEcdh,
114
115    /// Encrypt data using AES CBC mode.
116    ///
117    /// Applicable for authentication and symmetric key objects.
118    EncryptCbc,
119
120    /// Encrypt data using AES ECB mode.
121    ///
122    /// Applicable for authentication and symmetric key objects.
123    EncryptEcb,
124
125    /// The object can be exported under wrap (encrypted).
126    ///
127    /// Applicable for all objects.
128    ExportableUnderWrap,
129
130    /// Export other objects under wrap.
131    ///
132    /// Applicable for authentication and wrap key objects.
133    ///
134    /// # Note
135    ///
136    /// Both the authentication key used for export *and* the wrapping key need to be capable of
137    /// export.
138    ExportWrapped,
139
140    /// Generate asymmetric key objects.
141    ///
142    /// Applicable for authentication key objects.
143    GenerateAsymmetricKey,
144
145    /// Generate HMAC key objects.
146    ///
147    /// Applicable for authentication key objects.
148    GenerateHmacKey,
149
150    /// Generate OTP AEAD key objects.
151    ///
152    /// Applicable for authentication key objects.
153    GenerateOtpAeadKey,
154
155    /// Generate AES key.
156    ///
157    /// Applicable for authentication key objects.
158    GenerateSymmetricKey,
159
160    /// Generate wrap key objects.
161    ///
162    /// Applicable for authentication key objects.
163    GenerateWrapKey,
164
165    /// Read the log store.
166    ///
167    /// Applicable for authentication key objects.
168    GetLogEntries,
169
170    /// Read opaque objects.
171    ///
172    /// Applicable for authentication key objects.
173    GetOpaque,
174
175    /// Read device-global options.
176    ///
177    /// Applicable for authentication key objects.
178    GetOption,
179
180    /// Extract random bytes.
181    ///
182    /// Applicable for authentication key objects.
183    GetPseudoRandom,
184
185    /// Read template objects.
186    ///
187    /// Applicable for authentication key objects.
188    GetTemplate,
189
190    /// Import wrapped objects.
191    ///
192    /// Applicable for authentication and wrap key objects.
193    ///
194    /// # Note
195    ///
196    /// Both the authentication key used for import *and* the wrapping key need to be capable of
197    /// import.
198    ImportWrapped,
199
200    /// Write asymmetric key objects.
201    ///
202    /// Applicable for authentication key objects.
203    PutAsymmetricKey,
204
205    /// Write authentications key objects.
206    ///
207    /// Applicable for authentication key objects.
208    PutAuthenticationKey,
209
210    /// Write HMAC key objects.
211    ///
212    /// Applicable for authentication key objects.
213    PutHmacKey,
214
215    /// Write opaque objects.
216    ///
217    /// Applicable for authentication key objects.
218    PutOpaque,
219
220    /// Write OTP AEAD key objects.
221    ///
222    /// Applicable for authentication key objects.
223    PutOtpAeadKey,
224
225    /// Write RSA public wrap key.
226    ///
227    /// Applicable for authentication and wrap key objects.
228    PutPublicWrapKey,
229
230    /// Import AES key.
231    ///
232    /// Applicable for authentication key objects.
233    PutSymmetricKey,
234
235    /// Write template objects.
236    ///
237    /// Applicable for authentication key objects.
238    PutTemplate,
239
240    /// Write wrap key objects.
241    ///
242    /// Applicable for authentication key objects.
243    PutWrapKey,
244
245    /// Create OTP AEAD from random data.
246    ///
247    /// Applicable for authentication and OTP AEAD key objects.
248    RandomizeOtpAead,
249
250    /// Perform a factory reset on the device.
251    ///
252    /// Applicable for authentication key objects.
253    ResetDevice,
254
255    /// Rewrap AEADs from one OTP AEAD key to another.
256    ///
257    /// Applicable for authentication and OTP AEAD key objects.
258    RewrapFromOtpAeadKey,
259
260    /// Rewrap AEADs to one OTP AEAD key from another.
261    ///
262    /// Applicable for authentication and OTP AEAD key objects.
263    RewrapToOtpAeadKey,
264
265    /// Write device-global options.
266    ///
267    /// Applicable for authentication key objects.
268    SetOption,
269
270    /// Attest properties of asymmetric key objects.
271    ///
272    /// Applicable for authentication and asymmetric key objects.
273    SignAttestationCertificate,
274
275    /// Compute digital signatures using ECDSA.
276    ///
277    /// Applicable for authentication and asymmetric key objects.
278    SignEcdsa,
279
280    /// Compute digital signatures using [EdDSA].
281    ///
282    /// Applicable for authentication and asymmetric key objects.
283    ///
284    /// [EdDSA]: https://en.wikipedia.org/wiki/EdDSA
285    SignEddsa,
286
287    /// Compute HMAC of data.
288    ///
289    /// Applicable for authentication and HMAC key objects.
290    SignHmac,
291
292    /// Compute digital signatures using RSA-PKCS1v1.5.
293    ///
294    /// Applicable for authentication and asymmetric key objects.
295    SignPkcs,
296
297    /// Compute digital signatures using RSA-PSS.
298    ///
299    /// Applicable for authentication and asymmetric key objects.
300    SignPss,
301
302    /// Sign SSH certificates.
303    ///
304    /// Applicable for authentication and asymmetric key objects.
305    SignSshCertificate,
306
307    /// Unwrap user-provided data.
308    ///
309    /// Applicable for authentication and wrap key objects.
310    UnwrapData,
311
312    /// Verify HMAC of data.
313    ///
314    /// Applicable for authentication and HMAC key objects.
315    VerifyHmac,
316
317    /// Wrap user-provided data.
318    ///
319    /// Applicable for authentication and wrap key objects.
320    WrapData,
321}
322
323impl From<&Capability> for yubihsm::Capability {
324    fn from(value: &Capability) -> Self {
325        match *value {
326            Capability::ChangeAuthenticationKey => yubihsm::Capability::CHANGE_AUTHENTICATION_KEY,
327            Capability::CreateOtpAead => yubihsm::Capability::CREATE_OTP_AEAD,
328            Capability::DecryptCbc => yubihsm::Capability::UNKNOWN_CAPABILITY_52,
329            Capability::DecryptEcb => yubihsm::Capability::UNKNOWN_CAPABILITY_50,
330            Capability::DecryptOaep => yubihsm::Capability::DECRYPT_OAEP,
331            Capability::DecryptOtp => yubihsm::Capability::DECRYPT_OTP,
332            Capability::DecryptPkcs => yubihsm::Capability::DECRYPT_PKCS,
333            Capability::DeleteAsymmetricKey => yubihsm::Capability::DELETE_ASYMMETRIC_KEY,
334            Capability::DeleteAuthenticationKey => yubihsm::Capability::DELETE_AUTHENTICATION_KEY,
335            Capability::DeleteHmacKey => yubihsm::Capability::DELETE_HMAC_KEY,
336            Capability::DeleteOpaque => yubihsm::Capability::DELETE_OPAQUE,
337            Capability::DeleteOtpAeadKey => yubihsm::Capability::DELETE_OTP_AEAD_KEY,
338            Capability::DeletePublicWrapKey => yubihsm::Capability::UNKNOWN_CAPABILITY_55,
339            Capability::DeleteSymmetricKey => yubihsm::Capability::UNKNOWN_CAPABILITY_49,
340            Capability::DeleteTemplate => yubihsm::Capability::DELETE_TEMPLATE,
341            Capability::DeleteWrapKey => yubihsm::Capability::DELETE_WRAP_KEY,
342            Capability::DeriveEcdh => yubihsm::Capability::DERIVE_ECDH,
343            Capability::EncryptCbc => yubihsm::Capability::UNKNOWN_CAPABILITY_53,
344            Capability::EncryptEcb => yubihsm::Capability::UNKNOWN_CAPABILITY_51,
345            Capability::ExportableUnderWrap => yubihsm::Capability::EXPORTABLE_UNDER_WRAP,
346            Capability::ExportWrapped => yubihsm::Capability::EXPORT_WRAPPED,
347            Capability::GenerateAsymmetricKey => yubihsm::Capability::GENERATE_ASYMMETRIC_KEY,
348            Capability::GenerateHmacKey => yubihsm::Capability::GENERATE_HMAC_KEY,
349            Capability::GenerateOtpAeadKey => yubihsm::Capability::GENERATE_OTP_AEAD_KEY,
350            Capability::GenerateSymmetricKey => yubihsm::Capability::UNKNOWN_CAPABILITY_48,
351            Capability::GenerateWrapKey => yubihsm::Capability::GENERATE_WRAP_KEY,
352            Capability::GetOpaque => yubihsm::Capability::GET_OPAQUE,
353            Capability::GetOption => yubihsm::Capability::GET_OPTION,
354            Capability::GetPseudoRandom => yubihsm::Capability::GET_PSEUDO_RANDOM,
355            Capability::GetLogEntries => yubihsm::Capability::GET_LOG_ENTRIES,
356            Capability::GetTemplate => yubihsm::Capability::GET_TEMPLATE,
357            Capability::ImportWrapped => yubihsm::Capability::IMPORT_WRAPPED,
358            Capability::PutAsymmetricKey => yubihsm::Capability::PUT_ASYMMETRIC_KEY,
359            Capability::PutAuthenticationKey => yubihsm::Capability::PUT_AUTHENTICATION_KEY,
360            Capability::PutHmacKey => yubihsm::Capability::PUT_HMAC_KEY,
361            Capability::PutOpaque => yubihsm::Capability::PUT_OPAQUE,
362            Capability::PutOtpAeadKey => yubihsm::Capability::PUT_OTP_AEAD_KEY,
363            Capability::PutPublicWrapKey => yubihsm::Capability::UNKNOWN_CAPABILITY_51,
364            Capability::PutSymmetricKey => yubihsm::Capability::UNKNOWN_CAPABILITY_47,
365            Capability::PutTemplate => yubihsm::Capability::PUT_TEMPLATE,
366            Capability::PutWrapKey => yubihsm::Capability::PUT_WRAP_KEY,
367            Capability::RandomizeOtpAead => yubihsm::Capability::RANDOMIZE_OTP_AEAD,
368            Capability::RewrapFromOtpAeadKey => yubihsm::Capability::REWRAP_FROM_OTP_AEAD_KEY,
369            Capability::RewrapToOtpAeadKey => yubihsm::Capability::REWRAP_TO_OTP_AEAD_KEY,
370            Capability::ResetDevice => yubihsm::Capability::RESET_DEVICE,
371            Capability::SetOption => yubihsm::Capability::PUT_OPTION,
372            Capability::SignAttestationCertificate => {
373                yubihsm::Capability::SIGN_ATTESTATION_CERTIFICATE
374            }
375            Capability::SignEcdsa => yubihsm::Capability::SIGN_ECDSA,
376            Capability::SignEddsa => yubihsm::Capability::SIGN_EDDSA,
377            Capability::SignHmac => yubihsm::Capability::SIGN_HMAC,
378            Capability::SignPkcs => yubihsm::Capability::SIGN_PKCS,
379            Capability::SignPss => yubihsm::Capability::SIGN_PSS,
380            Capability::SignSshCertificate => yubihsm::Capability::SIGN_SSH_CERTIFICATE,
381            Capability::UnwrapData => yubihsm::Capability::UNWRAP_DATA,
382            Capability::VerifyHmac => yubihsm::Capability::VERIFY_HMAC,
383            Capability::WrapData => yubihsm::Capability::WRAP_DATA,
384        }
385    }
386}
387
388/// A set of capabilities of an object on a YubiHSM2.
389#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
390#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
391pub struct Capabilities(BTreeSet<Capability>);
392
393impl Display for Capabilities {
394    /// Formats a [`Capabilities`] as a string.
395    ///
396    /// Here, the capabilities in `self` are represented as a comma-separated list (e.g.
397    /// `change-authentication-key, create-otp-aead, decrypt-cbc` or
398    /// `change-authentication-key`).
399    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
400        write!(
401            f,
402            "{}",
403            self.0
404                .iter()
405                .map(|capability| capability.as_ref())
406                .collect::<Vec<_>>()
407                .join(", ")
408        )
409    }
410}
411
412impl From<[u8; 8]> for Capabilities {
413    fn from(bytes: [u8; 8]) -> Self {
414        let numeric = u64::from_be_bytes(bytes);
415        let value = yubihsm::Capability::from_bits_retain(numeric);
416        Self(
417            Capability::iter()
418                .filter(|capability| value.contains(capability.into()))
419                .collect(),
420        )
421    }
422}
423
424impl From<yubihsm::Capability> for Capabilities {
425    fn from(value: yubihsm::Capability) -> Self {
426        let lookup = [
427            (
428                yubihsm::Capability::CHANGE_AUTHENTICATION_KEY,
429                Capability::ChangeAuthenticationKey,
430            ),
431            (
432                yubihsm::Capability::CREATE_OTP_AEAD,
433                Capability::CreateOtpAead,
434            ),
435            // NOTE: This capability is not yet understood by the underlying library.
436            (
437                yubihsm::Capability::UNKNOWN_CAPABILITY_52,
438                Capability::DecryptCbc,
439            ),
440            // NOTE: This capability is not yet understood by the underlying library.
441            (
442                yubihsm::Capability::UNKNOWN_CAPABILITY_50,
443                Capability::DecryptEcb,
444            ),
445            (yubihsm::Capability::DECRYPT_OAEP, Capability::DecryptOaep),
446            (yubihsm::Capability::DECRYPT_OTP, Capability::DecryptOtp),
447            (yubihsm::Capability::DECRYPT_PKCS, Capability::DecryptPkcs),
448            (
449                yubihsm::Capability::DELETE_ASYMMETRIC_KEY,
450                Capability::DeleteAsymmetricKey,
451            ),
452            (
453                yubihsm::Capability::DELETE_AUTHENTICATION_KEY,
454                Capability::DeleteAuthenticationKey,
455            ),
456            (
457                yubihsm::Capability::DELETE_HMAC_KEY,
458                Capability::DeleteHmacKey,
459            ),
460            (yubihsm::Capability::DELETE_OPAQUE, Capability::DeleteOpaque),
461            (
462                yubihsm::Capability::DELETE_OTP_AEAD_KEY,
463                Capability::DeleteOtpAeadKey,
464            ),
465            // NOTE: This capability is not yet understood by the underlying library.
466            (
467                yubihsm::Capability::UNKNOWN_CAPABILITY_55,
468                Capability::DeletePublicWrapKey,
469            ),
470            // NOTE: This capability is not yet understood by the underlying library.
471            (
472                yubihsm::Capability::UNKNOWN_CAPABILITY_49,
473                Capability::DeleteSymmetricKey,
474            ),
475            (
476                yubihsm::Capability::DELETE_TEMPLATE,
477                Capability::DeleteTemplate,
478            ),
479            (
480                yubihsm::Capability::DELETE_WRAP_KEY,
481                Capability::DeleteWrapKey,
482            ),
483            (yubihsm::Capability::DERIVE_ECDH, Capability::DeriveEcdh),
484            // NOTE: This capability is not yet understood by the underlying library.
485            (
486                yubihsm::Capability::UNKNOWN_CAPABILITY_53,
487                Capability::EncryptCbc,
488            ),
489            // NOTE: This capability is not yet understood by the underlying library.
490            (
491                yubihsm::Capability::UNKNOWN_CAPABILITY_51,
492                Capability::EncryptEcb,
493            ),
494            (
495                yubihsm::Capability::EXPORTABLE_UNDER_WRAP,
496                Capability::ExportableUnderWrap,
497            ),
498            (
499                yubihsm::Capability::EXPORT_WRAPPED,
500                Capability::ExportWrapped,
501            ),
502            (
503                yubihsm::Capability::GENERATE_ASYMMETRIC_KEY,
504                Capability::GenerateAsymmetricKey,
505            ),
506            (
507                yubihsm::Capability::GENERATE_HMAC_KEY,
508                Capability::GenerateHmacKey,
509            ),
510            (
511                yubihsm::Capability::GENERATE_OTP_AEAD_KEY,
512                Capability::GenerateOtpAeadKey,
513            ),
514            // NOTE: This capability is not yet understood by the underlying library.
515            (
516                yubihsm::Capability::UNKNOWN_CAPABILITY_48,
517                Capability::GenerateSymmetricKey,
518            ),
519            (
520                yubihsm::Capability::GENERATE_WRAP_KEY,
521                Capability::GenerateWrapKey,
522            ),
523            (yubihsm::Capability::GET_OPAQUE, Capability::GetOpaque),
524            (yubihsm::Capability::GET_OPTION, Capability::GetOption),
525            (
526                yubihsm::Capability::GET_PSEUDO_RANDOM,
527                Capability::GetPseudoRandom,
528            ),
529            (
530                yubihsm::Capability::GET_LOG_ENTRIES,
531                Capability::GetLogEntries,
532            ),
533            (yubihsm::Capability::GET_TEMPLATE, Capability::GetTemplate),
534            (
535                yubihsm::Capability::IMPORT_WRAPPED,
536                Capability::ImportWrapped,
537            ),
538            (
539                yubihsm::Capability::PUT_ASYMMETRIC_KEY,
540                Capability::PutAsymmetricKey,
541            ),
542            (
543                yubihsm::Capability::PUT_AUTHENTICATION_KEY,
544                Capability::PutAuthenticationKey,
545            ),
546            (yubihsm::Capability::PUT_HMAC_KEY, Capability::PutHmacKey),
547            (yubihsm::Capability::PUT_OPAQUE, Capability::PutOpaque),
548            (
549                yubihsm::Capability::PUT_OTP_AEAD_KEY,
550                Capability::PutOtpAeadKey,
551            ),
552            // NOTE: This capability is not yet understood by the underlying library.
553            (
554                yubihsm::Capability::UNKNOWN_CAPABILITY_54,
555                Capability::PutPublicWrapKey,
556            ),
557            // NOTE: This capability is not yet understood by the underlying library.
558            (
559                yubihsm::Capability::UNKNOWN_CAPABILITY_47,
560                Capability::PutSymmetricKey,
561            ),
562            (yubihsm::Capability::PUT_TEMPLATE, Capability::PutTemplate),
563            (yubihsm::Capability::PUT_WRAP_KEY, Capability::PutWrapKey),
564            (
565                yubihsm::Capability::RANDOMIZE_OTP_AEAD,
566                Capability::RandomizeOtpAead,
567            ),
568            (
569                yubihsm::Capability::REWRAP_FROM_OTP_AEAD_KEY,
570                Capability::RewrapFromOtpAeadKey,
571            ),
572            (
573                yubihsm::Capability::REWRAP_TO_OTP_AEAD_KEY,
574                Capability::RewrapToOtpAeadKey,
575            ),
576            (yubihsm::Capability::RESET_DEVICE, Capability::ResetDevice),
577            (yubihsm::Capability::PUT_OPTION, Capability::SetOption),
578            (
579                yubihsm::Capability::SIGN_ATTESTATION_CERTIFICATE,
580                Capability::SignAttestationCertificate,
581            ),
582            (yubihsm::Capability::SIGN_ECDSA, Capability::SignEcdsa),
583            (yubihsm::Capability::SIGN_EDDSA, Capability::SignEddsa),
584            (yubihsm::Capability::SIGN_HMAC, Capability::SignHmac),
585            (yubihsm::Capability::SIGN_PKCS, Capability::SignPkcs),
586            (yubihsm::Capability::SIGN_PSS, Capability::SignPss),
587            (
588                yubihsm::Capability::SIGN_SSH_CERTIFICATE,
589                Capability::SignSshCertificate,
590            ),
591            (yubihsm::Capability::UNWRAP_DATA, Capability::UnwrapData),
592            (yubihsm::Capability::VERIFY_HMAC, Capability::VerifyHmac),
593            (yubihsm::Capability::WRAP_DATA, Capability::WrapData),
594        ];
595
596        Self(BTreeSet::from_iter(lookup.iter().filter_map(
597            |(yubi_cap, cap)| {
598                if value.contains(*yubi_cap) {
599                    Some(*cap)
600                } else {
601                    None
602                }
603            },
604        )))
605    }
606}
607
608impl From<&Capabilities> for [u8; 8] {
609    fn from(value: &Capabilities) -> Self {
610        yubihsm::Capability::from(value).bits().to_be_bytes()
611    }
612}
613
614impl From<&Capabilities> for yubihsm::Capability {
615    fn from(value: &Capabilities) -> Self {
616        value
617            .0
618            .iter()
619            .map(yubihsm::Capability::from)
620            .fold(yubihsm::Capability::empty(), |acc, c| acc | c)
621    }
622}
623
624impl From<&[Capability]> for Capabilities {
625    fn from(value: &[Capability]) -> Self {
626        Self(value.iter().copied().collect())
627    }
628}
629
630#[cfg(test)]
631mod tests {
632    use rstest::rstest;
633
634    use super::*;
635
636    /// Ensures that [`Capabilities::to_string`] works as expected.
637    #[test]
638    fn capabilities_to_string() {
639        let capability_list = vec![Capability::ChangeAuthenticationKey];
640        let capabilities = Capabilities::from(capability_list.as_slice());
641        assert_eq!("change-authentication-key", capabilities.to_string());
642
643        let capability_list = vec![
644            Capability::ChangeAuthenticationKey,
645            Capability::CreateOtpAead,
646        ];
647        let capabilities = Capabilities::from(capability_list.as_slice());
648        assert_eq!(
649            "change-authentication-key, create-otp-aead",
650            capabilities.to_string()
651        );
652    }
653
654    /// Ensures that [`Capabilities`] are created correctly from [`yubihsm::Capabilities`].
655    #[rstest]
656    #[case::change_authentication_key(
657        yubihsm::Capability::CHANGE_AUTHENTICATION_KEY,
658        Capabilities(BTreeSet::from_iter([Capability::ChangeAuthenticationKey])),
659    )]
660    #[case::create_otp_aead(
661        yubihsm::Capability::CREATE_OTP_AEAD,
662        Capabilities(BTreeSet::from_iter([Capability::CreateOtpAead])),
663    )]
664    // NOTE: This capability is not yet understood by the underlying library.
665    #[case::decrypt_cbc(
666        yubihsm::Capability::UNKNOWN_CAPABILITY_52,
667        Capabilities(BTreeSet::from_iter([Capability::DecryptCbc])),
668    )]
669    // NOTE: This capability is not yet understood by the underlying library.
670    #[case::decrypt_ecb(
671        yubihsm::Capability::UNKNOWN_CAPABILITY_50,
672        Capabilities(BTreeSet::from_iter([Capability::DecryptEcb])),
673    )]
674    #[case::decrypt_oaep(
675        yubihsm::Capability::DECRYPT_OAEP,
676        Capabilities(BTreeSet::from_iter([Capability::DecryptOaep])),
677    )]
678    #[case::decrypt_otp(
679        yubihsm::Capability::DECRYPT_OTP,
680        Capabilities(BTreeSet::from_iter([Capability::DecryptOtp])),
681    )]
682    #[case::decrypt_pkcs(
683        yubihsm::Capability::DECRYPT_PKCS,
684        Capabilities(BTreeSet::from_iter([Capability::DecryptPkcs])),
685    )]
686    #[case::delete_asymmetric_key(
687        yubihsm::Capability::DELETE_ASYMMETRIC_KEY,
688        Capabilities(BTreeSet::from_iter([Capability::DeleteAsymmetricKey])),
689    )]
690    #[case::delete_authentication_key(
691        yubihsm::Capability::DELETE_AUTHENTICATION_KEY,
692        Capabilities(BTreeSet::from_iter([Capability::DeleteAuthenticationKey])),
693    )]
694    #[case::delete_hmac_key(
695        yubihsm::Capability::DELETE_HMAC_KEY,
696        Capabilities(BTreeSet::from_iter([Capability::DeleteHmacKey])),
697    )]
698    #[case::delete_opaque(
699        yubihsm::Capability::DELETE_OPAQUE,
700        Capabilities(BTreeSet::from_iter([Capability::DeleteOpaque])),
701    )]
702    #[case::delete_otp_aead_key(
703        yubihsm::Capability::DELETE_OTP_AEAD_KEY,
704        Capabilities(BTreeSet::from_iter([Capability::DeleteOtpAeadKey])),
705    )]
706    // NOTE: This capability is not yet understood by the underlying library.
707    #[case::delete_public_wrap_key(
708        yubihsm::Capability::UNKNOWN_CAPABILITY_55,
709        Capabilities(BTreeSet::from_iter([Capability::DeletePublicWrapKey])),
710    )]
711    // NOTE: This capability is not yet understood by the underlying library.
712    #[case::delete_symmetric_key(
713        yubihsm::Capability::UNKNOWN_CAPABILITY_49,
714        Capabilities(BTreeSet::from_iter([Capability::DeleteSymmetricKey])),
715    )]
716    #[case::delete_template(
717        yubihsm::Capability::DELETE_TEMPLATE,
718        Capabilities(BTreeSet::from_iter([Capability::DeleteTemplate])),
719    )]
720    #[case::delete_wrap_key(
721        yubihsm::Capability::DELETE_WRAP_KEY,
722        Capabilities(BTreeSet::from_iter([Capability::DeleteWrapKey])),
723    )]
724    #[case::derive_ecdh(
725        yubihsm::Capability::DERIVE_ECDH,
726        Capabilities(BTreeSet::from_iter([Capability::DeriveEcdh])),
727    )]
728    // NOTE: This capability is not yet understood by the underlying library.
729    #[case::encrypt_cbc(
730        yubihsm::Capability::UNKNOWN_CAPABILITY_53,
731        Capabilities(BTreeSet::from_iter([Capability::EncryptCbc])),
732    )]
733    // NOTE: This capability is not yet understood by the underlying library.
734    #[case::encrypt_ecb(
735        yubihsm::Capability::UNKNOWN_CAPABILITY_51,
736        Capabilities(BTreeSet::from_iter([Capability::EncryptEcb])),
737    )]
738    #[case::exportable_under_wrap(
739        yubihsm::Capability::EXPORTABLE_UNDER_WRAP,
740        Capabilities(BTreeSet::from_iter([Capability::ExportableUnderWrap])),
741    )]
742    #[case::export_wrapped(
743        yubihsm::Capability::EXPORT_WRAPPED,
744        Capabilities(BTreeSet::from_iter([Capability::ExportWrapped])),
745    )]
746    #[case::generate_asymmetric_key(
747        yubihsm::Capability::GENERATE_ASYMMETRIC_KEY,
748        Capabilities(BTreeSet::from_iter([Capability::GenerateAsymmetricKey])),
749    )]
750    #[case::generate_hmac_key(
751        yubihsm::Capability::GENERATE_HMAC_KEY,
752        Capabilities(BTreeSet::from_iter([Capability::GenerateHmacKey])),
753    )]
754    #[case::generate_otp_aead_key(
755        yubihsm::Capability::GENERATE_OTP_AEAD_KEY,
756        Capabilities(BTreeSet::from_iter([Capability::GenerateOtpAeadKey])),
757    )]
758    // NOTE: This capability is not yet understood by the underlying library.
759    #[case::generate_symmetric_key(
760        yubihsm::Capability::UNKNOWN_CAPABILITY_48,
761        Capabilities(BTreeSet::from_iter([Capability::GenerateSymmetricKey])),
762    )]
763    #[case::generate_wrap_key(
764        yubihsm::Capability::GENERATE_WRAP_KEY,
765        Capabilities(BTreeSet::from_iter([Capability::GenerateWrapKey])),
766    )]
767    #[case::get_opaque(
768        yubihsm::Capability::GET_OPAQUE,
769        Capabilities(BTreeSet::from_iter([Capability::GetOpaque])),
770    )]
771    #[case::get_option(
772        yubihsm::Capability::GET_OPTION,
773        Capabilities(BTreeSet::from_iter([Capability::GetOption])),
774    )]
775    #[case::get_pseudo_random(
776        yubihsm::Capability::GET_PSEUDO_RANDOM,
777        Capabilities(BTreeSet::from_iter([Capability::GetPseudoRandom])),
778    )]
779    #[case::get_log_entries(
780        yubihsm::Capability::GET_LOG_ENTRIES,
781        Capabilities(BTreeSet::from_iter([Capability::GetLogEntries])),
782    )]
783    #[case::get_template(
784        yubihsm::Capability::GET_TEMPLATE,
785        Capabilities(BTreeSet::from_iter([Capability::GetTemplate])),
786    )]
787    #[case::import_wrapped(
788        yubihsm::Capability::IMPORT_WRAPPED,
789        Capabilities(BTreeSet::from_iter([Capability::ImportWrapped])),
790    )]
791    #[case::put_asymmetric_key(
792        yubihsm::Capability::PUT_ASYMMETRIC_KEY,
793        Capabilities(BTreeSet::from_iter([Capability::PutAsymmetricKey])),
794    )]
795    #[case::put_authentication_key(
796        yubihsm::Capability::PUT_AUTHENTICATION_KEY,
797        Capabilities(BTreeSet::from_iter([Capability::PutAuthenticationKey])),
798    )]
799    #[case::put_hmac_key(
800        yubihsm::Capability::PUT_HMAC_KEY,
801        Capabilities(BTreeSet::from_iter([Capability::PutHmacKey])),
802    )]
803    #[case::put_opaque(
804        yubihsm::Capability::PUT_OPAQUE,
805        Capabilities(BTreeSet::from_iter([Capability::PutOpaque])),
806    )]
807    #[case::put_otp_aead_key(
808        yubihsm::Capability::PUT_OTP_AEAD_KEY,
809        Capabilities(BTreeSet::from_iter([Capability::PutOtpAeadKey])),
810    )]
811    // NOTE: This capability is not yet understood by the underlying library.
812    #[case::put_public_wrap_key(
813        yubihsm::Capability::UNKNOWN_CAPABILITY_54,
814        Capabilities(BTreeSet::from_iter([Capability::PutPublicWrapKey])),
815    )]
816    // NOTE: This capability is not yet understood by the underlying library.
817    #[case::put_symmetric_key(
818        yubihsm::Capability::UNKNOWN_CAPABILITY_47,
819        Capabilities(BTreeSet::from_iter([Capability::PutSymmetricKey])),
820    )]
821    #[case::put_template(
822        yubihsm::Capability::PUT_TEMPLATE,
823        Capabilities(BTreeSet::from_iter([Capability::PutTemplate])),
824    )]
825    #[case::put_wrap_key(
826        yubihsm::Capability::PUT_WRAP_KEY,
827        Capabilities(BTreeSet::from_iter([Capability::PutWrapKey])),
828    )]
829    #[case::randomize_otp_aead(
830        yubihsm::Capability::RANDOMIZE_OTP_AEAD,
831        Capabilities(BTreeSet::from_iter([Capability::RandomizeOtpAead])),
832    )]
833    #[case::rewrap_from_otp_aead_key(
834        yubihsm::Capability::REWRAP_FROM_OTP_AEAD_KEY,
835        Capabilities(BTreeSet::from_iter([Capability::RewrapFromOtpAeadKey])),
836    )]
837    #[case::rewrap_to_otp_aead_key(
838        yubihsm::Capability::REWRAP_TO_OTP_AEAD_KEY,
839        Capabilities(BTreeSet::from_iter([Capability::RewrapToOtpAeadKey])),
840    )]
841    #[case::reset_device(
842        yubihsm::Capability::RESET_DEVICE,
843        Capabilities(BTreeSet::from_iter([Capability::ResetDevice])),
844    )]
845    #[case::put_option(
846        yubihsm::Capability::PUT_OPTION,
847        Capabilities(BTreeSet::from_iter([Capability::SetOption])),
848    )]
849    #[case::sign_attestation_certificate(
850        yubihsm::Capability::SIGN_ATTESTATION_CERTIFICATE,
851        Capabilities(BTreeSet::from_iter([Capability::SignAttestationCertificate])),
852    )]
853    #[case::sign_ecdsa(
854        yubihsm::Capability::SIGN_ECDSA,
855        Capabilities(BTreeSet::from_iter([Capability::SignEcdsa])),
856    )]
857    #[case::sign_eddsa(
858        yubihsm::Capability::SIGN_EDDSA,
859        Capabilities(BTreeSet::from_iter([Capability::SignEddsa])),
860    )]
861    #[case::sign_hmac(
862        yubihsm::Capability::SIGN_HMAC,
863        Capabilities(BTreeSet::from_iter([Capability::SignHmac])),
864    )]
865    #[case::sign_pkcs(
866        yubihsm::Capability::SIGN_PKCS,
867        Capabilities(BTreeSet::from_iter([Capability::SignPkcs])),
868    )]
869    #[case::sign_pss(
870        yubihsm::Capability::SIGN_PSS,
871        Capabilities(BTreeSet::from_iter([Capability::SignPss])),
872    )]
873    #[case::sign_ssh_certificate(
874        yubihsm::Capability::SIGN_SSH_CERTIFICATE,
875        Capabilities(BTreeSet::from_iter([Capability::SignSshCertificate])),
876    )]
877    #[case::unwrap_data(
878        yubihsm::Capability::UNWRAP_DATA,
879        Capabilities(BTreeSet::from_iter([Capability::UnwrapData])),
880    )]
881    #[case::verify_hmac(
882        yubihsm::Capability::VERIFY_HMAC,
883        Capabilities(BTreeSet::from_iter([Capability::VerifyHmac])),
884    )]
885    #[case::wrap_data(
886        yubihsm::Capability::WRAP_DATA,
887        Capabilities(BTreeSet::from_iter([Capability::WrapData])),
888    )]
889    fn capabilities_from_yubihsm_capability(
890        #[case] yubi_cap: yubihsm::Capability,
891        #[case] cap: Capabilities,
892    ) {
893        assert_eq!(Capabilities::from(yubi_cap), cap);
894    }
895}