openpgp_card/ocard/
data.rs

1// SPDX-FileCopyrightText: 2021-2023 Heiko Schaefer <heiko@schaefer.name>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! OpenPGP card data objects (DO)
5
6use std::convert::{TryFrom, TryInto};
7use std::fmt::{Display, Formatter, Write};
8
9use chrono::{DateTime, Utc};
10
11use crate::ocard::algorithm::AlgorithmAttributes;
12use crate::ocard::tags::Tags;
13use crate::ocard::tlv::length::tlv_encode_length;
14use crate::ocard::tlv::Tlv;
15use crate::ocard::KeyType;
16use crate::Error;
17
18mod algo_attrs;
19mod algo_info;
20mod application_id;
21mod cardholder;
22mod extended_cap;
23mod extended_length_info;
24mod fingerprint;
25mod historical;
26mod kdf_do;
27mod key_generation_times;
28mod pw_status;
29
30/// Application Related Data [Spec section 4.4.3.1]
31///
32/// The "application related data" DO contains a set of DOs.
33/// This struct offers read access to these DOs.
34///
35/// (Note: when any of the information in this DO changes on the card, you
36/// need to re-read ApplicationRelatedData from the card to receive the
37/// new values!)
38pub struct ApplicationRelatedData(pub(crate) Tlv);
39
40impl ApplicationRelatedData {
41    /// Get application identifier (AID), ISO 7816-4
42    pub fn application_id(&self) -> Result<ApplicationIdentifier, Error> {
43        let aid = self.0.find(Tags::ApplicationIdentifier);
44
45        if let Some(aid) = aid {
46            Ok(ApplicationIdentifier::try_from(&aid.serialize()[..])?)
47        } else {
48            Err(Error::NotFound("Couldn't get Application ID.".to_string()))
49        }
50    }
51
52    /// Get historical bytes
53    pub fn historical_bytes(&self) -> Result<HistoricalBytes, Error> {
54        let hist = self.0.find(Tags::HistoricalBytes);
55
56        if let Some(hist) = hist {
57            log::trace!("Historical bytes: {:x?}", hist);
58            (hist.serialize().as_slice()).try_into()
59        } else {
60            Err(Error::NotFound(
61                "Failed to get historical bytes.".to_string(),
62            ))
63        }
64    }
65
66    /// Get extended length information (ISO 7816-4), which
67    /// contains maximum number of bytes for command and response.
68    pub fn extended_length_information(&self) -> Result<Option<ExtendedLengthInfo>, Error> {
69        let eli = self.0.find(Tags::ExtendedLengthInformation);
70
71        log::trace!("Extended length information: {:x?}", eli);
72
73        if let Some(eli) = eli {
74            // The card has returned extended length information
75            Ok(Some((&eli.serialize()[..]).try_into()?))
76        } else {
77            // The card didn't return this (optional) DO. That is ok.
78            Ok(None)
79        }
80    }
81
82    // fn general_feature_management() -> Option<bool> {
83    //     // FIXME
84    //     unimplemented!()
85    // }
86
87    // fn discretionary_data_objects() {
88    //     // FIXME
89    //     unimplemented!()
90    // }
91
92    /// Get extended Capabilities
93    pub fn extended_capabilities(&self) -> Result<ExtendedCapabilities, Error> {
94        let app_id = self.application_id()?;
95        let version = app_id.version();
96
97        // get from cached "application related data"
98        let ecap = self.0.find(Tags::ExtendedCapabilities);
99
100        if let Some(ecap) = ecap {
101            Ok(ExtendedCapabilities::try_from((
102                &ecap.serialize()[..],
103                version,
104            ))?)
105        } else {
106            Err(Error::NotFound(
107                "Failed to get extended capabilities.".to_string(),
108            ))
109        }
110    }
111
112    /// Get algorithm attributes (for each key type)
113    pub fn algorithm_attributes(&self, key_type: KeyType) -> Result<AlgorithmAttributes, Error> {
114        let aa = self.0.find(key_type.algorithm_tag());
115
116        if let Some(aa) = aa {
117            AlgorithmAttributes::try_from(&aa.serialize()[..])
118        } else {
119            Err(Error::NotFound(format!(
120                "Failed to get algorithm attributes for {key_type:?}."
121            )))
122        }
123    }
124
125    /// Get PW status Bytes
126    pub fn pw_status_bytes(&self) -> Result<PWStatusBytes, Error> {
127        let psb = self.0.find(Tags::PWStatusBytes);
128
129        if let Some(psb) = psb {
130            let pws = (&psb.serialize()[..]).try_into()?;
131
132            log::trace!("PW Status: {:x?}", pws);
133
134            Ok(pws)
135        } else {
136            Err(Error::NotFound(
137                "Failed to get PW status Bytes.".to_string(),
138            ))
139        }
140    }
141
142    /// Fingerprint, per key type.
143    /// Zero bytes indicate a not defined private key.
144    pub fn fingerprints(&self) -> Result<KeySet<Fingerprint>, Error> {
145        let fp = self.0.find(Tags::Fingerprints);
146
147        if let Some(fp) = fp {
148            let fp: KeySet<Fingerprint> = (&fp.serialize()[..]).try_into()?;
149
150            log::trace!("Fp: {:x?}", fp);
151
152            Ok(fp)
153        } else {
154            Err(Error::NotFound("Failed to get fingerprints.".into()))
155        }
156    }
157
158    pub fn ca_fingerprints(&self) -> Result<[Option<Fingerprint>; 3], Error> {
159        let fp = self.0.find(Tags::CaFingerprints);
160
161        if let Some(fp) = fp {
162            // FIXME: using a KeySet is a weird hack
163            let fp: KeySet<Fingerprint> = (&fp.serialize()[..]).try_into()?;
164
165            let fp = [fp.signature, fp.decryption, fp.authentication];
166
167            log::trace!("CA Fp: {:x?}", fp);
168
169            Ok(fp)
170        } else {
171            Err(Error::NotFound("Failed to get CA fingerprints.".into()))
172        }
173    }
174
175    /// Generation dates/times of key pairs
176    pub fn key_generation_times(&self) -> Result<KeySet<KeyGenerationTime>, Error> {
177        let kg = self.0.find(Tags::GenerationTimes);
178
179        if let Some(kg) = kg {
180            let kg: KeySet<KeyGenerationTime> = (&kg.serialize()[..]).try_into()?;
181
182            log::trace!("Key generation: {:x?}", kg);
183
184            Ok(kg)
185        } else {
186            Err(Error::NotFound(
187                "Failed to get key generation times.".to_string(),
188            ))
189        }
190    }
191
192    pub fn key_information(&self) -> Result<Option<KeyInformation>, Error> {
193        let ki = self.0.find(Tags::KeyInformation);
194
195        // TODO: return an error in .into(), if the format of the value is bad
196
197        Ok(ki.map(|v| v.serialize().into()))
198    }
199
200    pub fn uif_pso_cds(&self) -> Result<Option<UserInteractionFlag>, Error> {
201        let uif = self.0.find(Tags::UifSig);
202
203        match uif {
204            None => Ok(None),
205            Some(v) => Ok(Some(v.serialize().try_into()?)),
206        }
207    }
208
209    pub fn uif_pso_dec(&self) -> Result<Option<UserInteractionFlag>, Error> {
210        let uif = self.0.find(Tags::UifDec);
211
212        match uif {
213            None => Ok(None),
214            Some(v) => Ok(Some(v.serialize().try_into()?)),
215        }
216    }
217
218    pub fn uif_pso_aut(&self) -> Result<Option<UserInteractionFlag>, Error> {
219        let uif = self.0.find(Tags::UifAuth);
220
221        match uif {
222            None => Ok(None),
223            Some(v) => Ok(Some(v.serialize().try_into()?)),
224        }
225    }
226
227    /// Get Attestation key fingerprint.
228    pub fn attestation_key_fingerprint(&self) -> Result<Option<Fingerprint>, Error> {
229        match self.0.find(Tags::FingerprintAttestation) {
230            None => Ok(None),
231            Some(data) => {
232                // FIXME: move conversion logic to Fingerprint
233                if data.serialize().iter().any(|&b| b != 0) {
234                    Ok(Some(Fingerprint::try_from(data.serialize().as_slice())?))
235                } else {
236                    Ok(None)
237                }
238            }
239        }
240    }
241
242    /// Get Attestation key algorithm attributes.
243    pub fn attestation_key_algorithm_attributes(
244        &mut self,
245    ) -> Result<Option<AlgorithmAttributes>, Error> {
246        match self.0.find(Tags::AlgorithmAttributesAttestation) {
247            None => Ok(None),
248            Some(data) => Ok(Some(AlgorithmAttributes::try_from(
249                data.serialize().as_slice(),
250            )?)),
251        }
252    }
253
254    /// Get Attestation key generation time.
255    pub fn attestation_key_generation_time(&self) -> Result<Option<KeyGenerationTime>, Error> {
256        match self.0.find(Tags::GenerationTimeAttestation) {
257            None => Ok(None),
258            Some(data) => {
259                // FIXME: move conversion logic to KeyGenerationTime
260                match &data.serialize()[..] {
261                    [a, b, c, d] => {
262                        // Generation time of key, binary. 4 bytes, Big Endian.
263                        // Value shall be seconds since Jan 1, 1970. Default value is 00000000 (not specified).
264                        match u32::from_be_bytes([*a, *b, *c, *d]) {
265                            0 => Ok(None),
266                            kgt => Ok(Some(kgt.into())),
267                        }
268                    }
269                    data => Err(Error::ParseError(format!(
270                        "attestation_key_generation_time unexpected length {}",
271                        data.len()
272                    ))),
273                }
274            }
275        }
276    }
277
278    pub fn uif_attestation(&self) -> Result<Option<UserInteractionFlag>, Error> {
279        let uif = self.0.find(Tags::UifAttestation);
280
281        match uif {
282            None => Ok(None),
283            Some(v) => Ok(Some(v.serialize().try_into()?)),
284        }
285    }
286}
287
288/// Security support template [Spec page 24]
289#[derive(Debug)]
290pub struct SecuritySupportTemplate {
291    // Digital signature counter [3 bytes]
292    // (counts usage of Compute Digital Signature command)
293    pub(crate) dsc: u32,
294}
295
296impl SecuritySupportTemplate {
297    pub fn signature_count(&self) -> u32 {
298        self.dsc
299    }
300}
301
302/// An OpenPGP key generation Time [Spec page 24]
303#[derive(Clone, Copy, Eq, PartialEq, Debug)]
304pub struct KeyGenerationTime(u32);
305
306impl KeyGenerationTime {
307    pub fn get(&self) -> u32 {
308        self.0
309    }
310}
311
312impl Display for KeyGenerationTime {
313    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
314        write!(f, "{}", DateTime::<Utc>::from(self))
315    }
316}
317
318/// User Interaction Flag [Spec page 24]
319#[derive(Clone, Copy, Eq, PartialEq, Debug)]
320pub struct UserInteractionFlag([u8; 2]);
321
322impl TryFrom<Vec<u8>> for UserInteractionFlag {
323    type Error = Error;
324
325    fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
326        match &v[..] {
327            [a, b] => Ok(UserInteractionFlag([*a, *b])),
328            _ => Err(Error::ParseError(format!("Can't get UIF from {v:x?}"))),
329        }
330    }
331}
332
333impl UserInteractionFlag {
334    pub fn touch_policy(&self) -> TouchPolicy {
335        self.0[0].into()
336    }
337
338    pub fn set_touch_policy(&mut self, tm: TouchPolicy) {
339        self.0[0] = tm.into();
340    }
341
342    pub fn features(&self) -> Features {
343        self.0[1].into()
344    }
345
346    pub(crate) fn as_bytes(&self) -> &[u8] {
347        &self.0[..]
348    }
349}
350
351impl Display for UserInteractionFlag {
352    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
353        write!(
354            f,
355            "Touch policy: {} [Features: {}]",
356            self.touch_policy(),
357            self.features()
358        )
359    }
360}
361
362/// User interaction setting: is a 'touch' needed to perform an operation on the card?
363/// This setting is used in 4.4.3.6 User Interaction Flag (UIF)
364///
365/// See spec pg 24 and <https://github.com/Yubico/yubikey-manager/blob/main/ykman/openpgp.py>
366///
367/// Touch policies were introduced in YubiKey Version 4.2.0 with modes ON, OFF and FIXED.
368/// YubiKey Version >= 5.2.1 added support for modes CACHED and CACHED_FIXED.
369#[derive(Debug, Eq, PartialEq, Clone, Copy)]
370pub enum TouchPolicy {
371    Off,
372    On,
373    Fixed,
374    Cached,
375    CachedFixed,
376    Unknown(u8),
377}
378
379impl TouchPolicy {
380    /// Returns "true" if this TouchPolicy (probably) requires touch confirmation.
381    ///
382    /// Note: When the Policy is set to `Cached` or `CachedFixed`, there is no way to be sure if a
383    /// previous touch confirmation is still valid (touch confirmations are valid for 15s, in
384    /// Cached mode)
385    pub fn touch_required(&self) -> bool {
386        !matches!(self, Self::Off)
387    }
388}
389
390impl Display for TouchPolicy {
391    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
392        match self {
393            TouchPolicy::Off => write!(f, "Off"),
394            TouchPolicy::On => write!(f, "On"),
395            TouchPolicy::Fixed => write!(f, "Fixed"),
396            TouchPolicy::Cached => write!(f, "Cached"),
397            TouchPolicy::CachedFixed => write!(f, "CachedFixed"),
398            TouchPolicy::Unknown(i) => write!(f, "Unknown({i})"),
399        }
400    }
401}
402
403impl From<TouchPolicy> for u8 {
404    fn from(tm: TouchPolicy) -> Self {
405        match tm {
406            TouchPolicy::Off => 0,
407            TouchPolicy::On => 1,
408            TouchPolicy::Fixed => 2,
409            TouchPolicy::Cached => 3,
410            TouchPolicy::CachedFixed => 4,
411            TouchPolicy::Unknown(i) => i,
412        }
413    }
414}
415
416impl From<u8> for TouchPolicy {
417    fn from(i: u8) -> Self {
418        match i {
419            0 => TouchPolicy::Off,
420            1 => TouchPolicy::On,
421            2 => TouchPolicy::Fixed,
422            3 => TouchPolicy::Cached,
423            4 => TouchPolicy::CachedFixed,
424            _ => TouchPolicy::Unknown(i),
425        }
426    }
427}
428
429/// Features of "additional hardware for user interaction" [Spec section 4.1.3.2].
430/// (Settings for these features are contained in [`UserInteractionFlag`])
431pub struct Features(u8);
432
433impl From<u8> for Features {
434    fn from(i: u8) -> Self {
435        Features(i)
436    }
437}
438
439impl Display for Features {
440    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
441        let mut ft = vec![];
442
443        if self.0 & 0x80 != 0 {
444            ft.push("Display")
445        }
446        if self.0 & 0x40 != 0 {
447            ft.push("Biometric input sensor")
448        }
449        if self.0 & 0x20 != 0 {
450            ft.push("Button")
451        }
452        if self.0 & 0x10 != 0 {
453            ft.push("Keypad")
454        }
455        if self.0 & 0x8 != 0 {
456            ft.push("LED")
457        }
458        if self.0 & 0x4 != 0 {
459            ft.push("Loudspeaker")
460        }
461        if self.0 & 0x2 != 0 {
462            ft.push("Microphone")
463        }
464        if self.0 & 0x1 != 0 {
465            ft.push("Touchscreen")
466        }
467
468        write!(f, "{}", ft.join(", "))
469    }
470}
471
472/// Key Information [Spec section 4.4.3.8]
473pub struct KeyInformation(Vec<u8>);
474
475impl From<Vec<u8>> for KeyInformation {
476    fn from(v: Vec<u8>) -> Self {
477        KeyInformation(v)
478    }
479}
480
481impl KeyInformation {
482    /// How many "additional" keys do we have information for?
483    pub fn num_additional(&self) -> usize {
484        (self.0.len() - 6) / 2
485    }
486
487    fn get_ref(&self, n: usize) -> u8 {
488        self.0[n * 2]
489    }
490    fn get_status(&self, n: usize) -> KeyStatus {
491        self.0[n * 2 + 1].into()
492    }
493
494    pub fn sig_ref(&self) -> u8 {
495        self.get_ref(0)
496    }
497    pub fn sig_status(&self) -> KeyStatus {
498        self.get_status(0)
499    }
500
501    pub fn dec_ref(&self) -> u8 {
502        self.get_ref(1)
503    }
504    pub fn dec_status(&self) -> KeyStatus {
505        self.get_status(1)
506    }
507
508    pub fn aut_ref(&self) -> u8 {
509        self.get_ref(2)
510    }
511    pub fn aut_status(&self) -> KeyStatus {
512        self.get_status(2)
513    }
514
515    pub fn additional_ref(&self, num: usize) -> u8 {
516        self.get_ref(3 + num)
517    }
518    pub fn additional_status(&self, num: usize) -> KeyStatus {
519        self.get_status(3 + num)
520    }
521}
522
523impl Display for KeyInformation {
524    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
525        writeln!(
526            f,
527            "signature key      (#{}): {}",
528            self.sig_ref(),
529            self.sig_status()
530        )?;
531        writeln!(
532            f,
533            "decryption key     (#{}): {}",
534            self.dec_ref(),
535            self.dec_status()
536        )?;
537        writeln!(
538            f,
539            "authentication key (#{}): {}",
540            self.aut_ref(),
541            self.aut_status()
542        )?;
543
544        for i in 0..self.num_additional() {
545            writeln!(
546                f,
547                "additional key {}   (#{}): {}",
548                i,
549                self.additional_ref(i),
550                self.additional_status(i)
551            )?;
552        }
553
554        Ok(())
555    }
556}
557
558/// KeyStatus is contained in [`KeyInformation`].
559/// It encodes if key material on a card was imported or generated on the card.
560#[derive(Debug, PartialEq, Eq, Clone, Copy)]
561pub enum KeyStatus {
562    NotPresent,
563    Generated,
564    Imported,
565    Unknown(u8),
566}
567
568impl From<u8> for KeyStatus {
569    fn from(i: u8) -> Self {
570        match i {
571            0 => KeyStatus::NotPresent,
572            1 => KeyStatus::Generated,
573            2 => KeyStatus::Imported,
574            _ => KeyStatus::Unknown(i),
575        }
576    }
577}
578
579impl Display for KeyStatus {
580    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
581        match self {
582            KeyStatus::NotPresent => write!(f, "not present"),
583            KeyStatus::Generated => write!(f, "generated"),
584            KeyStatus::Imported => write!(f, "imported"),
585            KeyStatus::Unknown(i) => write!(f, "unknown status ({i})"),
586        }
587    }
588}
589
590/// Application Identifier (AID) [Spec section 4.2.1]
591#[derive(Debug, Copy, Clone, Eq, PartialEq)]
592pub struct ApplicationIdentifier {
593    application: u8,
594    version: u16,
595    manufacturer: u16,
596    serial: u32,
597}
598
599impl Display for ApplicationIdentifier {
600    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
601        write!(
602            f,
603            "D276000124 {:02X} {:04X} {:04X} {:08X} 0000",
604            self.application, self.version, self.manufacturer, self.serial
605        )
606    }
607}
608
609/// Historical Bytes [Spec chapter 6]
610#[derive(Debug, Clone, Copy, PartialEq, Eq)]
611pub struct HistoricalBytes {
612    /// category indicator byte
613    cib: u8,
614
615    /// Card service data (31)
616    csd: Option<CardServiceData>,
617
618    /// Card Capabilities (73)
619    cc: Option<CardCapabilities>,
620
621    /// status indicator byte (o-card 3.4.1, pg 44)
622    sib: u8,
623}
624
625/// Card Capabilities [Spec chapter 6 (Historical Bytes)]
626#[derive(Debug, Clone, Copy, PartialEq, Eq)]
627pub struct CardCapabilities {
628    command_chaining: bool,
629    extended_lc_le: bool,
630    extended_length_information: bool,
631}
632
633impl Display for CardCapabilities {
634    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
635        if self.command_chaining {
636            writeln!(f, "- command chaining")?;
637        }
638        if self.extended_lc_le {
639            writeln!(f, "- extended Lc and Le fields")?;
640        }
641        if self.extended_length_information {
642            writeln!(f, "- extended Length Information")?;
643        }
644
645        Ok(())
646    }
647}
648
649/// Card service data [Spec chapter 6 (Historical Bytes)]
650#[derive(Debug, Clone, Copy, PartialEq, Eq)]
651pub struct CardServiceData {
652    select_by_full_df_name: bool, // Application Selection by full DF name (AID)
653    select_by_partial_df_name: bool, // Application Selection by partial DF name
654    dos_available_in_ef_dir: bool,
655    dos_available_in_ef_atr_info: bool, // should be true if extended length supported
656    access_services: [bool; 3],         // should be '010' if extended length supported
657    mf: bool,
658}
659
660impl Display for CardServiceData {
661    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
662        if self.select_by_full_df_name {
663            writeln!(f, "- Application Selection by full DF name")?;
664        }
665        if self.select_by_partial_df_name {
666            writeln!(f, "- Application Selection by partial DF name")?;
667        }
668        if self.dos_available_in_ef_dir {
669            writeln!(f, "- DOs available in EF.DIR")?;
670        }
671        if self.dos_available_in_ef_atr_info {
672            writeln!(f, "- DOs available in EF.ATR/INFO")?;
673        }
674
675        write!(
676            f,
677            "- EF.DIR and EF.ATR/INFO access services by the GET DATA command (BER-TLV): "
678        )?;
679        for a in self.access_services {
680            if a {
681                write!(f, "1")?;
682            } else {
683                write!(f, "0")?;
684            }
685        }
686        writeln!(f)?;
687
688        if self.mf {
689            writeln!(f, "- Card with MF")?;
690        }
691
692        Ok(())
693    }
694}
695
696/// Extended Capabilities [Spec section 4.4.3.7]
697#[derive(Debug, Eq, Clone, Copy, PartialEq)]
698pub struct ExtendedCapabilities {
699    secure_messaging: bool,
700    get_challenge: bool,
701    key_import: bool,
702    pw_status_change: bool,
703    private_use_dos: bool,
704    algo_attrs_changeable: bool,
705    aes: bool,
706    kdf_do: bool,
707
708    sm_algo: u8,
709    max_len_challenge: u16,
710    max_len_cardholder_cert: u16,
711
712    max_cmd_len: Option<u16>,  // v2
713    max_resp_len: Option<u16>, // v2
714
715    max_len_special_do: Option<u16>,          // v3
716    pin_block_2_format_support: Option<bool>, // v3
717    mse_command_support: Option<bool>,        // v3
718}
719
720impl Display for ExtendedCapabilities {
721    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
722        if self.secure_messaging {
723            writeln!(f, "- secure messaging")?;
724        }
725        if self.get_challenge {
726            writeln!(f, "- get challenge")?;
727        }
728        if self.key_import {
729            writeln!(f, "- key import")?;
730        }
731        if self.pw_status_change {
732            writeln!(f, "- PW Status changeable")?;
733        }
734        if self.private_use_dos {
735            writeln!(f, "- private use DOs")?;
736        }
737        if self.algo_attrs_changeable {
738            writeln!(f, "- algorithm attributes changeable")?;
739        }
740        if self.aes {
741            writeln!(f, "- PSO:DEC/ENC with AES")?;
742        }
743        if self.kdf_do {
744            writeln!(f, "- KDF-DO")?;
745        }
746        if self.sm_algo != 0 {
747            writeln!(f, "- secure messaging algorithm: {:#02X}", self.sm_algo)?;
748        }
749
750        if self.max_len_challenge != 0 {
751            writeln!(
752                f,
753                "- maximum length of challenge: {}",
754                self.max_len_challenge
755            )?;
756        }
757        writeln!(
758            f,
759            "- maximum length cardholder certificates: {}",
760            self.max_len_cardholder_cert
761        )?;
762
763        // v2
764        if let Some(max_cmd_len) = self.max_cmd_len {
765            writeln!(f, "- maximum command length: {max_cmd_len}")?;
766        }
767        if let Some(max_resp_len) = self.max_resp_len {
768            writeln!(f, "- maximum response length: {max_resp_len}")?;
769        }
770
771        // v3
772        if let Some(max_len_special_do) = self.max_len_special_do {
773            writeln!(f, "- maximum length for special DOs: {max_len_special_do}")?;
774        }
775        if self.pin_block_2_format_support == Some(true) {
776            writeln!(f, "- PIN block 2 format supported")?;
777        }
778        if self.mse_command_support == Some(true) {
779            writeln!(f, "- MSE command (for DEC and AUT) supported")?;
780        }
781
782        Ok(())
783    }
784}
785
786/// Extended length information [Spec section 4.1.3.1]
787#[derive(Debug, Eq, Clone, Copy, PartialEq)]
788pub struct ExtendedLengthInfo {
789    max_command_bytes: u16,
790    max_response_bytes: u16,
791}
792
793impl Display for ExtendedLengthInfo {
794    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
795        writeln!(f, "- max command length: {}", self.max_command_bytes)?;
796        writeln!(f, "- max response length: {}", self.max_response_bytes)?;
797        Ok(())
798    }
799}
800
801/// Cardholder Related Data [Spec page 22]
802#[derive(Debug, PartialEq, Eq)]
803pub struct CardholderRelatedData {
804    name: Option<Vec<u8>>,
805    lang: Option<Vec<Lang>>,
806    sex: Option<Sex>,
807}
808
809impl Display for CardholderRelatedData {
810    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
811        if let Some(name) = &self.name {
812            writeln!(f, "Name: {}", Self::latin1_to_string(name))?;
813        }
814        if let Some(sex) = self.sex {
815            writeln!(f, "Sex: {sex}")?;
816        }
817        if let Some(lang) = &self.lang {
818            for (n, l) in lang.iter().enumerate() {
819                writeln!(f, "Lang {}: {}", n + 1, l)?;
820            }
821        }
822        Ok(())
823    }
824}
825
826/// Sex [Spec section 4.4.3.5].
827/// The Sex setting is accessible via [`CardholderRelatedData`].
828///
829/// Encoded in accordance with <https://en.wikipedia.org/wiki/ISO/IEC_5218>
830#[derive(Debug, PartialEq, Eq, Clone, Copy)]
831pub enum Sex {
832    NotKnown,
833    Male,
834    Female,
835    NotApplicable,
836    UndefinedValue(u8), // ISO 5218 doesn't define this value
837}
838
839impl Display for Sex {
840    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
841        match self {
842            Self::NotKnown => write!(f, "Not known"),
843            Self::Male => write!(f, "Male"),
844            Self::Female => write!(f, "Female"),
845            Self::NotApplicable => write!(f, "Not applicable"),
846            Self::UndefinedValue(v) => write!(f, "Undefined value {v:x?}"),
847        }
848    }
849}
850
851impl From<&Sex> for u8 {
852    fn from(sex: &Sex) -> u8 {
853        match sex {
854            Sex::NotKnown => 0x30,
855            Sex::Male => 0x31,
856            Sex::Female => 0x32,
857            Sex::NotApplicable => 0x39,
858            Sex::UndefinedValue(v) => *v,
859        }
860    }
861}
862
863impl From<u8> for Sex {
864    fn from(s: u8) -> Self {
865        match s {
866            0x30 => Self::NotKnown,
867            0x31 => Self::Male,
868            0x32 => Self::Female,
869            0x39 => Self::NotApplicable,
870            v => Self::UndefinedValue(v),
871        }
872    }
873}
874
875/// Individual language for Language Preferences [Spec section 4.4.3.4].
876/// Language preferences are accessible via [`CardholderRelatedData`].
877///
878/// Encoded according to <https://en.wikipedia.org/wiki/ISO_639-1>
879#[derive(Debug, PartialEq, Eq, Clone, Copy)]
880pub enum Lang {
881    Value([u8; 2]),
882    Invalid(u8),
883}
884
885impl Display for Lang {
886    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
887        match self {
888            Self::Value(v) => {
889                write!(f, "{}{}", v[0] as char, v[1] as char)
890            }
891            Self::Invalid(v) => {
892                write!(f, "{v:x?}")
893            }
894        }
895    }
896}
897
898impl From<(char, char)> for Lang {
899    fn from(c: (char, char)) -> Self {
900        Lang::Value([c.0 as u8, c.1 as u8])
901    }
902}
903
904impl From<[char; 2]> for Lang {
905    fn from(c: [char; 2]) -> Self {
906        Lang::Value([c[0] as u8, c[1] as u8])
907    }
908}
909
910impl From<Lang> for Vec<u8> {
911    fn from(lang: Lang) -> Self {
912        match lang {
913            Lang::Value(v) => vec![v[0], v[1]],
914            Lang::Invalid(v) => vec![v],
915        }
916    }
917}
918
919impl From<&[u8; 1]> for Lang {
920    fn from(data: &[u8; 1]) -> Self {
921        Lang::Invalid(data[0])
922    }
923}
924
925impl From<&[u8; 2]> for Lang {
926    fn from(data: &[u8; 2]) -> Self {
927        Lang::Value([data[0], data[1]])
928    }
929}
930
931/// PW status Bytes [Spec page 23]
932#[derive(Debug, PartialEq, Eq)]
933pub struct PWStatusBytes {
934    pub(crate) pw1_cds_valid_once: bool,
935    pub(crate) pw1_pin_block: bool,
936    pub(crate) pw1_len_format: u8,
937    pub(crate) rc_len: u8,
938    pub(crate) pw3_pin_block: bool,
939    pub(crate) pw3_len_format: u8,
940    pub(crate) err_count_pw1: u8,
941    pub(crate) err_count_rst: u8,
942    pub(crate) err_count_pw3: u8,
943}
944
945impl PWStatusBytes {
946    /// Set format of PW1:
947    /// `false` for UTF-8 or derived password,
948    /// `true` for PIN block format 2.
949    pub fn set_pw1_pin_block(&mut self, val: bool) {
950        self.pw1_pin_block = val;
951    }
952
953    /// Set format of PW3:
954    /// `false` for UTF-8 or derived password,
955    /// `true` for PIN block format 2.
956    pub fn set_pw3_pin_block(&mut self, val: bool) {
957        self.pw3_pin_block = val;
958    }
959
960    /// Is PW1 (no. 81) only valid for one PSO:CDS command?
961    pub fn pw1_cds_valid_once(&self) -> bool {
962        self.pw1_cds_valid_once
963    }
964
965    /// Configure if PW1 (no. 81) is only valid for one PSO:CDS command.
966    pub fn set_pw1_cds_valid_once(&mut self, val: bool) {
967        self.pw1_cds_valid_once = val;
968    }
969
970    /// Max length of PW1
971    pub fn pw1_max_len(&self) -> u8 {
972        self.pw1_len_format & 0x7f
973    }
974
975    /// Max length of Resetting Code (RC) for PW1
976    pub fn rc_max_len(&self) -> u8 {
977        self.rc_len
978    }
979
980    /// Max length of PW3
981    pub fn pw3_max_len(&self) -> u8 {
982        self.pw3_len_format & 0x7f
983    }
984
985    /// Error counter of PW1 (if 0, then PW1 is blocked).
986    pub fn err_count_pw1(&self) -> u8 {
987        self.err_count_pw1
988    }
989
990    /// Error counter of Resetting Code (RC) (if 0, then RC is blocked).
991    pub fn err_count_rc(&self) -> u8 {
992        self.err_count_rst
993    }
994
995    /// Error counter of PW3 (if 0, then PW3 is blocked).
996    pub fn err_count_pw3(&self) -> u8 {
997        self.err_count_pw3
998    }
999}
1000
1001/// OpenPGP Fingerprint for a key slot [Spec page 23]
1002#[derive(Clone, Eq, PartialEq)]
1003pub struct Fingerprint([u8; 20]);
1004
1005impl Fingerprint {
1006    pub fn to_hex(&self) -> String {
1007        self.0.map(|byte| format!("{:02x}", byte)).join("")
1008    }
1009
1010    pub fn to_spaced_hex(&self) -> String {
1011        let mut fp = String::new();
1012
1013        for i in 0..20 {
1014            let _ = write!(&mut fp, "{:02x}", self.0[i]);
1015
1016            if i < 19 && (i % 2 == 1) {
1017                fp.push(' ');
1018            }
1019            if i == 9 {
1020                fp.push(' ');
1021            }
1022        }
1023
1024        fp
1025    }
1026}
1027
1028// KDF DO
1029
1030#[derive(Debug, Clone)]
1031pub struct KdfDo {
1032    // 81 01 KDF algorithm byte:
1033    // 00 = NONE (not used)
1034    // 03 = KDF_ITERSALTED_S2K
1035    kdf_algo: u8,
1036
1037    // 82 01 Hash algorithm byte:
1038    // 08 = SHA256
1039    // 0A = SHA512
1040    hash_algo: Option<u8>,
1041
1042    // 83 04 Iteration count (long integer)
1043    iter_count: Option<u32>,
1044
1045    // 84 xx Salt bytes for User password (PW1)
1046    salt_pw1: Option<Vec<u8>>,
1047
1048    // 85 xx Salt bytes for Resetting Code of PW1
1049    salt_rc: Option<Vec<u8>>,
1050
1051    // 86 xx Salt bytes for Admin password (PW3)
1052    salt_pw3: Option<Vec<u8>>,
1053
1054    // 87 xx Initial password hash for User-PW
1055    initial_hash_pw1: Option<Vec<u8>>,
1056
1057    // 88 xx Initial password hash for Admin-PW
1058    initial_hash_pw3: Option<Vec<u8>>,
1059}
1060
1061impl KdfDo {
1062    pub(crate) fn serialize(&self) -> Vec<u8> {
1063        // FIXME: encode as tlv, then serialize?
1064
1065        // FIXME: check that lengths of salts and initials fits in u16?
1066
1067        let mut ser = vec![];
1068
1069        ser.push(0x81);
1070        ser.push(0x01);
1071        ser.push(self.kdf_algo);
1072
1073        if let Some(hash_algo) = self.hash_algo {
1074            ser.push(0x82);
1075            ser.push(0x01);
1076            ser.push(hash_algo);
1077        }
1078
1079        if let Some(iter_count) = self.iter_count {
1080            ser.push(0x83);
1081            ser.push(0x04);
1082            ser.extend_from_slice(&iter_count.to_be_bytes());
1083        }
1084
1085        if let Some(salt_pw1) = &self.salt_pw1 {
1086            ser.push(0x84);
1087            ser.extend_from_slice(&tlv_encode_length(salt_pw1.len() as u16));
1088            ser.extend_from_slice(salt_pw1);
1089        }
1090
1091        if let Some(salt_rc) = &self.salt_rc {
1092            ser.push(0x85);
1093            ser.extend_from_slice(&tlv_encode_length(salt_rc.len() as u16));
1094            ser.extend_from_slice(salt_rc);
1095        }
1096
1097        if let Some(salt_pw3) = &self.salt_pw3 {
1098            ser.push(0x86);
1099            ser.extend_from_slice(&tlv_encode_length(salt_pw3.len() as u16));
1100            ser.extend_from_slice(salt_pw3);
1101        }
1102
1103        if let Some(initial_hash_pw1) = &self.initial_hash_pw1 {
1104            ser.push(0x87);
1105            ser.extend_from_slice(&tlv_encode_length(initial_hash_pw1.len() as u16));
1106            ser.extend_from_slice(initial_hash_pw1);
1107        }
1108        if let Some(initial_hash_pw3) = &self.initial_hash_pw3 {
1109            ser.push(0x88);
1110            ser.extend_from_slice(&tlv_encode_length(initial_hash_pw3.len() as u16));
1111            ser.extend_from_slice(initial_hash_pw3);
1112        }
1113        ser
1114    }
1115
1116    pub fn iter_salted(
1117        hash_algo: u8,
1118        salt_pw1: Vec<u8>,
1119        salt_rc: Vec<u8>,
1120        salt_pw3: Vec<u8>,
1121    ) -> Result<Self, Error> {
1122        const PW1_INITIAL: &str = "123456";
1123        const PW3_INITIAL: &str = "12345678";
1124
1125        const ITER_COUNT: u32 = 0x03000000;
1126
1127        // 08 = SHA256
1128        // 0A = SHA512
1129        if hash_algo != 0x08 && hash_algo != 0x0a {
1130            return Err(Error::UnsupportedAlgo(
1131                "Unsupported hash algorithm".to_string(),
1132            ));
1133        }
1134
1135        let kdf_algo = 0x03; // KDF_ITERSALTED_S2K
1136        let hash_algo = Some(hash_algo);
1137        let iter_count = Some(ITER_COUNT);
1138
1139        let salt_pw1 = Some(salt_pw1);
1140        let salt_rc = Some(salt_rc);
1141        let salt_pw3 = Some(salt_pw3);
1142
1143        let initial_hash_pw1 = Some(crate::ocard::kdf::itersalt(
1144            PW1_INITIAL,
1145            hash_algo,
1146            iter_count,
1147            salt_pw1.as_deref(),
1148        )?);
1149
1150        let initial_hash_pw3 = Some(crate::ocard::kdf::itersalt(
1151            PW3_INITIAL,
1152            hash_algo,
1153            iter_count,
1154            salt_pw3.as_deref(),
1155        )?);
1156
1157        Ok(Self {
1158            kdf_algo,
1159            hash_algo,
1160            iter_count,
1161            salt_pw1,
1162            salt_rc,
1163            salt_pw3,
1164            initial_hash_pw1,
1165            initial_hash_pw3,
1166        })
1167    }
1168}
1169
1170/// Helper fn for nom parsing
1171pub(crate) fn complete<O>(result: nom::IResult<&[u8], O>) -> Result<O, Error> {
1172    let (rem, output) = result.map_err(|_err| Error::ParseError("Parsing failed".to_string()))?;
1173    if rem.is_empty() {
1174        Ok(output)
1175    } else {
1176        Err(Error::ParseError(format!(
1177            "Parsing incomplete, trailing data: {rem:x?}"
1178        )))
1179    }
1180}
1181
1182/// A KeySet binds together a triple of information about each Key slot on a card
1183#[derive(Clone, Debug, Eq, PartialEq)]
1184pub struct KeySet<T> {
1185    signature: Option<T>,
1186    decryption: Option<T>,
1187    authentication: Option<T>,
1188}
1189
1190impl<T> From<(Option<T>, Option<T>, Option<T>)> for KeySet<T> {
1191    fn from(tuple: (Option<T>, Option<T>, Option<T>)) -> Self {
1192        Self {
1193            signature: tuple.0,
1194            decryption: tuple.1,
1195            authentication: tuple.2,
1196        }
1197    }
1198}
1199
1200impl<T> KeySet<T> {
1201    pub fn signature(&self) -> Option<&T> {
1202        self.signature.as_ref()
1203    }
1204
1205    pub fn decryption(&self) -> Option<&T> {
1206        self.decryption.as_ref()
1207    }
1208
1209    pub fn authentication(&self) -> Option<&T> {
1210        self.authentication.as_ref()
1211    }
1212}