yubihsm/
capability.rs

1//! Object attributes specifying which operations are allowed to be performed
2
3use bitflags::bitflags;
4use serde::{
5    de::{self, Deserialize, Deserializer, Visitor},
6    ser::{Serialize, Serializer},
7};
8use std::{
9    fmt::{self, Display},
10    str::{self, FromStr},
11};
12
13bitflags! {
14    /// Object attributes specifying which operations are allowed to be performed
15    ///
16    /// <https://developers.yubico.com/YubiHSM2/Concepts/Capability.html>
17    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
18    pub struct Capability: u64 {
19        /// `derive-ecdh`: perform ECDH operation
20        const DERIVE_ECDH = 0x800;
21
22        /// `decrypt-oaep`: perform RSA-OAEP decryption
23        const DECRYPT_OAEP = 0x400;
24
25        /// `decrypt-pkcs`: perform RSA-PKCS1v1.5 decryption
26        const DECRYPT_PKCS = 0x200;
27
28        /// `generate-asymmetric-key`: generate asymmetric objects
29        const GENERATE_ASYMMETRIC_KEY = 0x10;
30
31        /// `sign-ecdsa`: compute ECDSA digital signature
32        const SIGN_ECDSA = 0x80;
33
34        /// `sign-eddsa`: compute EdDSA (i.e. Ed25519) digital signature
35        const SIGN_EDDSA = 0x100;
36
37        /// `sign-pkcs`: compute RSA-PKCS1v1.5 digital signature
38        const SIGN_PKCS = 0x20;
39
40        /// `sign-pss`: compute RSA-PSS digital signature
41        const SIGN_PSS = 0x40;
42
43        /// `sign-attestation-certificate`: create attestation (i.e. X.509 certificate)
44        /// about an asymmetric object
45        const SIGN_ATTESTATION_CERTIFICATE = 0x4_0000_0000;
46
47        /// `get-log-entries`: read the log store
48        const GET_LOG_ENTRIES = 0x100_0000;
49
50        /// `delete-asymmetric-key`: delete asymmetric key objects
51        const DELETE_ASYMMETRIC_KEY = 0x200_0000_0000;
52
53        /// `delete-authentication-key`: delete authentication::Key objects
54        const DELETE_AUTHENTICATION_KEY = 0x100_0000_0000;
55
56        /// `delete-hmac-key`: delete HMACKey objects
57        const DELETE_HMAC_KEY = 0x800_0000_0000;
58
59        /// `delete-opaque`: delete opaque objects
60        const DELETE_OPAQUE = 0x80_0000_0000;
61
62        /// `delete-otp-aead-key`: delete Yubic OTP AEAD key objects
63        const DELETE_OTP_AEAD_KEY = 0x2000_0000_0000;
64
65        /// `delete-template`: delete template objects
66        const DELETE_TEMPLATE = 0x1000_0000_0000;
67
68        /// `delete-wrap-key`: delete WrapKey objects
69        const DELETE_WRAP_KEY = 0x400_0000_0000;
70
71        /// `exportable-under-wrap`: mark an object as exportable under keywrap
72        const EXPORTABLE_UNDER_WRAP = 0x1_0000;
73
74        /// `export-wrapped`: export objects under keywrap
75        const EXPORT_WRAPPED = 0x1000;
76
77        /// `generate-otp-aead-key`: generate Yubico OTP AEAD objects
78        const GENERATE_OTP_AEAD_KEY = 0x10_0000_0000;
79
80        /// `generate-wrap-key`: generate wrapkey objects
81        const GENERATE_WRAP_KEY = 0x8000;
82
83        /// `get-opaque`: read opaque objects
84        const GET_OPAQUE = 0x1;
85
86        /// `get-option`: read device-global options
87        const GET_OPTION = 0x4_0000;
88
89        /// `get-pseudo-random`: extract random bytes
90        const GET_PSEUDO_RANDOM = 0x8_0000;
91
92        /// `get-template`: read SSH template objects
93        const GET_TEMPLATE = 0x400_0000;
94
95        /// `generate-hmac-key`: generate HMAC key objects
96        const GENERATE_HMAC_KEY = 0x20_0000;
97
98        /// `sign-hmac`: compute HMAC for data
99        const SIGN_HMAC = 0x40_0000;
100
101        /// `verify-hmac`: verify HMAC for data
102        const VERIFY_HMAC = 0x80_0000;
103
104        /// `import-wrapped`: import keywrapped objects
105        const IMPORT_WRAPPED = 0x2000;
106
107        /// `create-otp-aead`: create an OTP AEAD
108        const CREATE_OTP_AEAD = 0x4000_0000;
109
110        /// `randomize-otp-aead`: create an OTP AEAD from random data
111        const RANDOMIZE_OTP_AEAD = 0x8000_0000;
112
113        /// `rewrap-from-otp-aead-key`: rewrap AEADs from an OTP AEAD key object to another
114        const REWRAP_FROM_OTP_AEAD_KEY = 0x1_0000_0000;
115
116        /// `rewrap-to-otp-aead-key`: rewrap AEADs to an OTP AEAD key object from another
117        const REWRAP_TO_OTP_AEAD_KEY = 0x2_0000_0000;
118
119        /// `decrypt-otp`: decrypt OTP
120        const DECRYPT_OTP = 0x2000_0000;
121
122        /// `put-asymmetric-key`: write asymmetric objects
123        const PUT_ASYMMETRIC_KEY =  0x8;
124
125        /// `put-authentication-key`: write authentication key objects
126        const PUT_AUTHENTICATION_KEY = 0x4;
127
128        /// `put-hmac-key`: write HMAC key objects
129        const PUT_HMAC_KEY = 0x10_0000;
130
131        /// `put-opaque`: Write Opaque Objects
132        const PUT_OPAQUE = 0x2;
133
134        /// `set-option`: write device-global options
135        const PUT_OPTION = 0x2_0000;
136
137        /// `put-otp-aead-key`: write OTP AEAD key objects
138        const PUT_OTP_AEAD_KEY = 0x8_0000_0000;
139
140        /// `put-template`: write template objects
141        const PUT_TEMPLATE = 0x800_0000;
142
143        /// `put-wrap-key`: write WrapKey objects
144        const PUT_WRAP_KEY = 0x4000;
145
146        /// `reset-device`: factory reset the device
147        const RESET_DEVICE = 0x1000_0000;
148
149        /// `sign-ssh-certificate`: sign SSH certificates
150        const SIGN_SSH_CERTIFICATE = 0x200_0000;
151
152        /// `unwrap-data`: unwrap user-provided data
153        const UNWRAP_DATA = 0x40_0000_0000;
154
155        /// `wrap-data`: wrap user-provided data
156        const WRAP_DATA = 0x20_0000_0000;
157
158        /// `change-authentication-key`: overwrite existing authentication key with new one
159        const CHANGE_AUTHENTICATION_KEY = 0x4000_0000_0000;
160
161        /// unknown capability: bit 47
162        const UNKNOWN_CAPABILITY_47 = 0x8000_0000_0000;
163
164        /// unknown capability: bit 48
165        const UNKNOWN_CAPABILITY_48 = 0x1_0000_0000_0000;
166
167        /// unknown capability: bit 49
168        const UNKNOWN_CAPABILITY_49 = 0x2_0000_0000_0000;
169
170        /// unknown capability: bit 50
171        const UNKNOWN_CAPABILITY_50 = 0x4_0000_0000_0000;
172
173        /// unknown capability: bit 51
174        const UNKNOWN_CAPABILITY_51 = 0x8_0000_0000_0000;
175
176        /// unknown capability: bit 52
177        const UNKNOWN_CAPABILITY_52 = 0x10_0000_0000_0000;
178
179        /// unknown capability: bit 53
180        const UNKNOWN_CAPABILITY_53 = 0x20_0000_0000_0000;
181
182        /// unknown capability: bit 54
183        const UNKNOWN_CAPABILITY_54 = 0x40_0000_0000_0000;
184
185        /// unknown capability: bit 55
186        const UNKNOWN_CAPABILITY_55 = 0x80_0000_0000_0000;
187
188        /// unknown capability: bit 56
189        const UNKNOWN_CAPABILITY_56 = 0x100_0000_0000_0000;
190
191        /// unknown capability: bit 57
192        const UNKNOWN_CAPABILITY_57 = 0x200_0000_0000_0000;
193
194        /// unknown capability: bit 58
195        const UNKNOWN_CAPABILITY_58 = 0x400_0000_0000_0000;
196
197        /// unknown capability: bit 59
198        const UNKNOWN_CAPABILITY_59 = 0x800_0000_0000_0000;
199
200        /// unknown capability: bit 60
201        const UNKNOWN_CAPABILITY_60 = 0x1000_0000_0000_0000;
202
203        /// unknown capability: bit 61
204        const UNKNOWN_CAPABILITY_61 = 0x2000_0000_0000_0000;
205
206        /// unknown capability: bit 62
207        const UNKNOWN_CAPABILITY_62 = 0x4000_0000_0000_0000;
208
209        /// unknown capability: bit 63
210        const UNKNOWN_CAPABILITY_63 = 0x8000_0000_0000_0000;
211    }
212}
213
214impl Default for Capability {
215    fn default() -> Self {
216        Capability::empty()
217    }
218}
219
220impl Display for Capability {
221    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222        let s = match *self {
223            Capability::DERIVE_ECDH => "derive-ecdh",
224            Capability::DECRYPT_OAEP => "decrypt-oaep",
225            Capability::DECRYPT_PKCS => "decrypt-pkcs",
226            Capability::GENERATE_ASYMMETRIC_KEY => "generate-asymmetric-key",
227            Capability::SIGN_ECDSA => "sign-ecdsa",
228            Capability::SIGN_EDDSA => "sign-eddsa",
229            Capability::SIGN_PKCS => "sign-pkcs",
230            Capability::SIGN_PSS => "sign-pss",
231            Capability::SIGN_ATTESTATION_CERTIFICATE => "sign-attestation-certificate",
232            Capability::GET_LOG_ENTRIES => "get-log-entries",
233            Capability::DELETE_ASYMMETRIC_KEY => "delete-asymmetric-key",
234            Capability::DELETE_AUTHENTICATION_KEY => "delete-authentication-key",
235            Capability::DELETE_HMAC_KEY => "delete-hmac-key",
236            Capability::DELETE_OPAQUE => "delete-opaque",
237            Capability::DELETE_OTP_AEAD_KEY => "delete-otp-aead-key",
238            Capability::DELETE_TEMPLATE => "delete-template",
239            Capability::DELETE_WRAP_KEY => "delete-wrap-key",
240            Capability::EXPORTABLE_UNDER_WRAP => "exportable-under-wrap",
241            Capability::EXPORT_WRAPPED => "export-wrapped",
242            Capability::GENERATE_OTP_AEAD_KEY => "generate-otp-aead-key",
243            Capability::GENERATE_WRAP_KEY => "generate-wrap-key",
244            Capability::GET_OPAQUE => "get-opaque",
245            Capability::GET_OPTION => "get-option",
246            Capability::GET_PSEUDO_RANDOM => "get-pseudo-random",
247            Capability::GET_TEMPLATE => "get-template",
248            Capability::GENERATE_HMAC_KEY => "generate-hmac-key",
249            Capability::SIGN_HMAC => "sign-hmac",
250            Capability::VERIFY_HMAC => "verify-hmac",
251            Capability::IMPORT_WRAPPED => "import-wrapped",
252            Capability::CREATE_OTP_AEAD => "create-otp-aead",
253            Capability::RANDOMIZE_OTP_AEAD => "randomize-otp-aead",
254            Capability::REWRAP_FROM_OTP_AEAD_KEY => "rewrap-from-otp-aead-key",
255            Capability::REWRAP_TO_OTP_AEAD_KEY => "rewrap-to-otp-aead-key",
256            Capability::DECRYPT_OTP => "decrypt-otp",
257            Capability::PUT_ASYMMETRIC_KEY => "put-asymmetric-key",
258            Capability::PUT_AUTHENTICATION_KEY => "put-authentication-key",
259            Capability::PUT_HMAC_KEY => "put-hmac-key",
260            Capability::PUT_OPAQUE => "put-opaque",
261            Capability::PUT_OPTION => "set-option",
262            Capability::PUT_OTP_AEAD_KEY => "put-otp-aead-key",
263            Capability::PUT_TEMPLATE => "put-template",
264            Capability::PUT_WRAP_KEY => "put-wrap-key",
265            Capability::RESET_DEVICE => "reset-device",
266            Capability::SIGN_SSH_CERTIFICATE => "sign-ssh-certificate",
267            Capability::UNWRAP_DATA => "unwrap-data",
268            Capability::WRAP_DATA => "wrap-data",
269            Capability::CHANGE_AUTHENTICATION_KEY => "change-authentication-key",
270            _ => return Err(fmt::Error), // we don't support displaying this capability yet
271        };
272
273        write!(f, "{s}")
274    }
275}
276
277impl FromStr for Capability {
278    type Err = ();
279
280    fn from_str(s: &str) -> Result<Capability, ()> {
281        Ok(match s {
282            "derive-ecdh" => Capability::DERIVE_ECDH,
283            "decrypt-oaep" => Capability::DECRYPT_OAEP,
284            "decrypt-pkcs" => Capability::DECRYPT_PKCS,
285            "generate-asymmetric-key" => Capability::GENERATE_ASYMMETRIC_KEY,
286            "sign-ecdsa" => Capability::SIGN_ECDSA,
287            "sign-eddsa" => Capability::SIGN_EDDSA,
288            "sign-pkcs" => Capability::SIGN_PKCS,
289            "sign-pss" => Capability::SIGN_PSS,
290            "sign-attestation-certificate" => Capability::SIGN_ATTESTATION_CERTIFICATE,
291            "get-log-entries" => Capability::GET_LOG_ENTRIES,
292            "delete-asymmetric-key" => Capability::DELETE_ASYMMETRIC_KEY,
293            "delete-authentication-key" => Capability::DELETE_AUTHENTICATION_KEY,
294            "delete-hmac-key" => Capability::DELETE_HMAC_KEY,
295            "delete-opaque" => Capability::DELETE_OPAQUE,
296            "delete-otp-aead-key" => Capability::DELETE_OTP_AEAD_KEY,
297            "delete-template" => Capability::DELETE_TEMPLATE,
298            "delete-wrap-key" => Capability::DELETE_WRAP_KEY,
299            "exportable-under-wrap" => Capability::EXPORTABLE_UNDER_WRAP,
300            "export-wrapped" => Capability::EXPORT_WRAPPED,
301            "generate-otp-aead-key" => Capability::GENERATE_OTP_AEAD_KEY,
302            "generate-wrap-key" => Capability::GENERATE_WRAP_KEY,
303            "get-opaque" => Capability::GET_OPAQUE,
304            "get-option" => Capability::GET_OPTION,
305            "get-pseudo-random" => Capability::GET_PSEUDO_RANDOM,
306            "get-template" => Capability::GET_TEMPLATE,
307            "generate-hmac-key" => Capability::GENERATE_HMAC_KEY,
308            "sign-hmac" => Capability::SIGN_HMAC,
309            "verify-hmac" => Capability::VERIFY_HMAC,
310            "import-wrapped" => Capability::IMPORT_WRAPPED,
311            "create-otp-aead" => Capability::CREATE_OTP_AEAD,
312            "randomize-otp-aead" => Capability::RANDOMIZE_OTP_AEAD,
313            "rewrap-from-otp-aead-key" => Capability::REWRAP_FROM_OTP_AEAD_KEY,
314            "rewrap-to-otp-aead-key" => Capability::REWRAP_TO_OTP_AEAD_KEY,
315            "decrypt-otp" => Capability::DECRYPT_OTP,
316            "put-asymmetric-key" => Capability::PUT_ASYMMETRIC_KEY,
317            "put-authentication-key" => Capability::PUT_AUTHENTICATION_KEY,
318            "put-hmac-key" => Capability::PUT_HMAC_KEY,
319            "put-opaque" => Capability::PUT_OPAQUE,
320            "set-option" => Capability::PUT_OPTION,
321            "put-otp-aead-key" => Capability::PUT_OTP_AEAD_KEY,
322            "put-template" => Capability::PUT_TEMPLATE,
323            "put-wrap-key" => Capability::PUT_WRAP_KEY,
324            "reset-device" => Capability::RESET_DEVICE,
325            "sign-ssh-certificate" => Capability::SIGN_SSH_CERTIFICATE,
326            "unwrap-data" => Capability::UNWRAP_DATA,
327            "wrap-data" => Capability::WRAP_DATA,
328            "change-authentication-key" => Capability::CHANGE_AUTHENTICATION_KEY,
329            _ => return Err(()),
330        })
331    }
332}
333
334impl Serialize for Capability {
335    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
336    where
337        S: Serializer,
338    {
339        serializer.serialize_u64(self.bits())
340    }
341}
342
343impl<'de> Deserialize<'de> for Capability {
344    fn deserialize<D>(deserializer: D) -> Result<Capability, D::Error>
345    where
346        D: Deserializer<'de>,
347    {
348        struct CapabilityVisitor;
349
350        impl<'de> Visitor<'de> for CapabilityVisitor {
351            type Value = Capability;
352
353            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
354                formatter.write_str("8-bytes containing capability bitflags")
355            }
356
357            fn visit_u64<E>(self, value: u64) -> Result<Capability, E>
358            where
359                E: de::Error,
360            {
361                Capability::from_bits(value).ok_or_else(|| E::custom("invalid capability bitflags"))
362            }
363        }
364
365        deserializer.deserialize_u64(CapabilityVisitor)
366    }
367}