1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
// Apparently bitflags isn't clippy-safe
#![cfg_attr(clippy, allow(clippy::redundant_field_names, clippy::suspicious_arithmetic_impl))]

use std::fmt;

use serde::de::{self, Deserialize, Deserializer, Visitor};
use serde::ser::{Serialize, Serializer};

bitflags! {
    /// Object attributes specifying which operations are allowed to be performed
    ///
    /// <https://developers.yubico.com/YubiHSM2/Concepts/Capability.html>
    pub struct Capability: u64 {
        /// asymmetric_decrypt_ecdh: perform ECDH operation
        const ASYMMETRIC_DECRYPT_ECDH = 0x800;

        /// asymmetric_decrypt_oaep: perform RSA-OAEP decryption
        const ASYMMETRIC_DECRYPT_OAEP = 0x400;

        /// asymmetric_decrypt_pkcs: perform RSA-PKCS1v1.5 decryption
        const ASYMMETRIC_DECRYPT_PKCS = 0x200;

        /// asymmetric_gen: generate asymmetric objects
        const ASYMMETRIC_GEN = 0x10;

        /// asymmetric_sign_ecdsa: compute ECDSA digital signature
        const ASYMMETRIC_SIGN_ECDSA = 0x80;

        /// asymmetric_sign_eddsa: compute EdDSA (i.e. Ed25519) digital signature
        const ASYMMETRIC_SIGN_EDDSA = 0x100;

        /// asymmetric_sign_pkcs: compute RSA-PKCS1v1.5 digital signature
        const ASYMMETRIC_SIGN_PKCS = 0x20;

        /// asymmetric_sign_pss: compute RSA-PSS digital signature
        const ASYMMETRIC_SIGN_PSS = 0x40;

        /// attest: create attestation (i.e. X.509 certificate) about an asymmetric object
        const ATTEST = 0x4_0000_0000;

        /// audit: read the log store
        const AUDIT = 0x100_0000;

        /// delete_asymmetric: delete asymmetric key objects
        const DELETE_ASYMMETRIC = 0x200_0000_0000;

        /// delete_auth_key: delete AuthKey objects
        const DELETE_AUTHKEY = 0x100_0000_0000;

        /// delete_hmac_key: delete HMACKey objects
        const DELETE_HMACKEY = 0x800_0000_0000;

        /// delete_opaque: delete opaque objects
        const DELETE_OPAQUE = 0x80_0000_0000;

        /// delete_otp_aead_key: delete OTPAEADKey objects
        const DELETE_OTP_AEAD_KEY = 0x2000_0000_0000;

        /// delete_template: delete template objects
        const DELETE_TEMPLATE = 0x1000_0000_0000;

        /// delete_wrap_key: delete WrapKey objects
        const DELETE_WRAPKEY = 0x400_0000_0000;

        /// export_under_wrap: mark an object as exportable under keywrap
        const EXPORT_UNDER_WRAP = 0x1_0000;

        /// export_wrapped: export objects under keywrap
        const EXPORT_WRAPPED = 0x1000;

        /// generate_otp_aead_key: generate OTPAEADKey objects
        const GENERATE_OTP_AEAD_KEY = 0x10_0000_0000;

        /// generate_wrapkey: generate wrapkey objects
        const GENERATE_WRAPKEY = 0x8000;

        /// get_opaque: read opaque objects
        const GET_OPAQUE = 0x1;

        /// get_option: read device-global options
        const GET_OPTION = 0x4_0000;

        /// get_randomness: extract random bytes
        const GET_RANDOMNESS = 0x8_0000;

        /// get_template: read template objects
        const GET_TEMPLATE = 0x400_0000;

        /// hmackey_generate: generate HMACKey objects
        const HMACKEY_GENERATE = 0x20_0000;

        /// hmac_data: compute HMAC for data
        const HMAC_DATA = 0x40_0000;

        /// hmac_verify: verify HMAC for data
        const HMAC_VERIFY = 0x80_0000;

        /// import_wrapped: import keywrapped objects
        const IMPORT_WRAPPED = 0x2000;

        /// otp_aead_create: create an OTP AEAD
        const OTP_AEAD_CREATE = 0x4000_0000;

        /// otp_aead_random: create an OTP AEAD from random data
        const OTP_AEAD_RANDOM = 0x8000_0000;

        /// otp_aead_rewrap_from: rewrap AEADs from one OTPAEADKey Object to another
        const OTP_AEAD_REWRAP_FROM = 0x1_0000_0000;

        /// otp_aead_rewrap_to: rewrap AEADs to one OTPAEADKey Object from another
        const OTP_AEAD_REWRAP_TO = 0x2_0000_0000;

        /// otp_decrypt: decrypt OTP
        const OTP_DECRYPT = 0x2000_0000;

        /// put_asymmetric_key: write asymmetric objects
        const PUT_ASYMMETRIC =  0x8;

        /// put_auth_key: write AuthKey objects
        const PUT_AUTHKEY = 0x4;

        /// put_hmac_key: write HMACKey objects
        const PUT_HMACKEY = 0x10_0000;

        /// put_opaque: Write Opaque Objects
        const PUT_OPAQUE = 0x2;

        /// put_option: write device-global options
        const PUT_OPTION = 0x2_0000;

        /// put_otp_aead_key: write OTPAEADKey objects
        const PUT_OTP_AEAD_KEY = 0x8_0000_0000;

        /// put_template: write template objects
        const PUT_TEMPLATE = 0x800_0000;

        /// put_wrapkey: write WrapKey objects
        const PUT_WRAPKEY = 0x4000;

        /// reset: factory reset the device
        const RESET = 0x1000_0000;

        /// ssh_certify: sign SSH certificates
        const SSH_CERTIFY = 0x200_0000;

        /// unwrap_data: unwrap user-provided data
        const UNWRAP_DATA = 0x40_0000_0000;

        /// wrap_data: wrap user-provided data
        const WRAP_DATA = 0x20_0000_0000;

        /// Unknown Capability (Bit 46)
        const CAP46 = 0x4000_0000_0000;

        /// Unknown Capability (Bit 47)
        const CAP47 = 0x8000_0000_0000;

        /// Unknown Capability (Bit 48)
        const CAP48 = 0x1_0000_0000_0000;

        /// Unknown Capability (Bit 49)
        const CAP49 = 0x2_0000_0000_0000;

        /// Unknown Capability (Bit 50)
        const CAP50 = 0x4_0000_0000_0000;

        /// Unknown Capability (Bit 51)
        const CAP51 = 0x8_0000_0000_0000;

        /// Unknown Capability (Bit 52)
        const CAP52 = 0x10_0000_0000_0000;

        /// Unknown Capability (Bit 53)
        const CAP53 = 0x20_0000_0000_0000;

        /// Unknown Capability (Bit 54)
        const CAP54 = 0x40_0000_0000_0000;

        /// Unknown Capability (Bit 55)
        const CAP55 = 0x80_0000_0000_0000;

        /// Unknown Capability (Bit 56)
        const CAP56 = 0x100_0000_0000_0000;

        /// Unknown Capability (Bit 57)
        const CAP57 = 0x200_0000_0000_0000;

        /// Unknown Capability (Bit 58)
        const CAP58 = 0x400_0000_0000_0000;

        /// Unknown Capability (Bit 59)
        const CAP59 = 0x800_0000_0000_0000;

        /// Unknown Capability (Bit 60)
        const CAP60 = 0x1000_0000_0000_0000;

        /// Unknown Capability (Bit 61)
        const CAP61 = 0x2000_0000_0000_0000;

        /// Unknown Capability (Bit 62)
        const CAP62 = 0x4000_0000_0000_0000;

        /// Unknown Capability (Bit 63)
        const CAP63 = 0x8000_0000_0000_0000;
    }
}

impl Default for Capability {
    fn default() -> Self {
        Capability::empty()
    }
}

impl Serialize for Capability {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_u64(self.bits())
    }
}

impl<'de> Deserialize<'de> for Capability {
    fn deserialize<D>(deserializer: D) -> Result<Capability, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct CapabilityVisitor;

        impl<'de> Visitor<'de> for CapabilityVisitor {
            type Value = Capability;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("8-bytes containing capability bitflags")
            }

            fn visit_u64<E>(self, value: u64) -> Result<Capability, E>
            where
                E: de::Error,
            {
                Capability::from_bits(value).ok_or_else(|| E::custom("invalid capability bitflags"))
            }
        }

        deserializer.deserialize_u64(CapabilityVisitor)
    }
}