openpgp_card/ocard/
mod.rs

1// SPDX-FileCopyrightText: 2021-2024 Heiko Schaefer <heiko@schaefer.name>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Low-level access to an OpenPGP card application
5
6use std::convert::{TryFrom, TryInto};
7
8use card_backend::{CardBackend, CardCaps, CardTransaction, PinType, SmartcardError};
9use secrecy::{ExposeSecret, SecretVec};
10
11use crate::ocard::algorithm::{AlgorithmAttributes, AlgorithmInformation};
12use crate::ocard::apdu::command::Command;
13use crate::ocard::apdu::response::RawResponse;
14use crate::ocard::crypto::{CardUploadableKey, Cryptogram, Hash, PublicKeyMaterial};
15use crate::ocard::data::{
16    ApplicationIdentifier, ApplicationRelatedData, CardholderRelatedData, ExtendedCapabilities,
17    ExtendedLengthInfo, Fingerprint, HistoricalBytes, KdfDo, KeyGenerationTime, Lang,
18    PWStatusBytes, SecuritySupportTemplate, Sex, UserInteractionFlag,
19};
20use crate::ocard::tags::{ShortTag, Tags};
21use crate::ocard::tlv::value::Value;
22use crate::ocard::tlv::Tlv;
23use crate::Error;
24
25pub mod algorithm;
26pub(crate) mod apdu;
27mod commands;
28pub mod crypto;
29pub mod data;
30pub mod kdf;
31mod keys;
32pub(crate) mod oid;
33pub(crate) mod tags;
34pub(crate) mod tlv;
35
36pub(crate) const OPENPGP_APPLICATION: &[u8] = &[0xD2, 0x76, 0x00, 0x01, 0x24, 0x01];
37
38/// Identify a Key slot on an OpenPGP card
39#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
40pub enum KeyType {
41    Signing,
42    Decryption,
43    Authentication,
44
45    /// Attestation is a Yubico proprietary key slot
46    Attestation,
47}
48
49impl KeyType {
50    /// Get C1/C2/C3/DA values for this KeyTypes, to use as Tag
51    pub(crate) fn algorithm_tag(&self) -> ShortTag {
52        match self {
53            Self::Signing => Tags::AlgorithmAttributesSignature,
54            Self::Decryption => Tags::AlgorithmAttributesDecryption,
55            Self::Authentication => Tags::AlgorithmAttributesAuthentication,
56            Self::Attestation => Tags::AlgorithmAttributesAttestation,
57        }
58        .into()
59    }
60
61    /// Get C7/C8/C9/DB values for this KeyTypes, to use as Tag.
62    ///
63    /// (NOTE: these Tags are only used for "PUT DO", but GETting
64    /// fingerprint information from the card uses the combined Tag C5)
65    fn fingerprint_put_tag(&self) -> ShortTag {
66        match self {
67            Self::Signing => Tags::FingerprintSignature,
68            Self::Decryption => Tags::FingerprintDecryption,
69            Self::Authentication => Tags::FingerprintAuthentication,
70            Self::Attestation => Tags::FingerprintAttestation,
71        }
72        .into()
73    }
74
75    /// Get CE/CF/D0/DD values for this KeyTypes, to use as Tag.
76    ///
77    /// (NOTE: these Tags are only used for "PUT DO", but GETting
78    /// timestamp information from the card uses the combined Tag CD)
79    fn timestamp_put_tag(&self) -> ShortTag {
80        match self {
81            Self::Signing => Tags::GenerationTimeSignature,
82            Self::Decryption => Tags::GenerationTimeDecryption,
83            Self::Authentication => Tags::GenerationTimeAuthentication,
84            Self::Attestation => Tags::GenerationTimeAttestation,
85        }
86        .into()
87    }
88}
89
90/// A struct to cache immutable information of a card.
91/// Some of the data is stored during [`OpenPGP::new`].
92/// Other information can optionally be cached later (e.g. `ai`)
93#[derive(Debug)]
94struct CardImmutable {
95    aid: ApplicationIdentifier,
96    ec: ExtendedCapabilities,
97    hb: Option<HistoricalBytes>,     // new in v2.0
98    eli: Option<ExtendedLengthInfo>, // new in v3.0
99
100    // First `Option` layer encodes if this cache field has been initialized,
101    // if `Some`, then the second `Option` layer encodes if the field exists on the card.
102    ai: Option<Option<AlgorithmInformation>>, // new in v3.4
103}
104
105/// An OpenPGP card object (backed by a CardBackend implementation).
106///
107/// Most users will probably want to use the `PcscCard` backend from the `card-backend-pcsc` crate.
108///
109/// Users of this crate can keep a long-lived [`OpenPGP`] object, including in long-running programs.
110/// All operations must be performed on a [`Transaction`] (which must be short-lived).
111pub struct OpenPGP {
112    /// A connection to the smart card
113    card: Box<dyn CardBackend + Send + Sync>,
114
115    /// Capabilites of the card, determined from hints by the Backend,
116    /// as well as the Application Related Data
117    card_caps: Option<CardCaps>,
118
119    /// A cache data structure for information that is immutable on OpenPGP cards.
120    /// Some of the information gets initialized when connecting to the card.
121    /// Other information may be cached on first read.
122    immutable: Option<CardImmutable>,
123}
124
125impl OpenPGP {
126    /// Turn a [`CardBackend`] into a [`OpenPGP`] object:
127    ///
128    /// The OpenPGP application is `SELECT`ed, and the card capabilities
129    /// of the card are retrieved from the "Application Related Data".
130    pub fn new<B>(backend: B) -> Result<Self, Error>
131    where
132        B: Into<Box<dyn CardBackend + Send + Sync>>,
133    {
134        let card: Box<dyn CardBackend + Send + Sync> = backend.into();
135
136        let mut op = Self {
137            card,
138            card_caps: None,
139            immutable: None,
140        };
141
142        let (caps, imm) = {
143            let mut tx = op.transaction()?;
144            tx.select()?;
145
146            // Init card_caps
147            let ard = tx.application_related_data()?;
148
149            // Determine chaining/extended length support from card
150            // metadata and cache this information in the CardTransaction
151            // implementation (as a CardCaps)
152            let mut ext_support = false;
153            let mut chaining_support = false;
154
155            if let Ok(hist) = ard.historical_bytes() {
156                if let Some(cc) = hist.card_capabilities() {
157                    chaining_support = cc.command_chaining();
158                    ext_support = cc.extended_lc_le();
159                }
160            }
161
162            let ext_cap = ard.extended_capabilities()?;
163
164            // Get max command/response byte sizes from card
165            let (max_cmd_bytes, max_rsp_bytes) = if let Ok(Some(eli)) =
166                ard.extended_length_information()
167            {
168                // In card 3.x, max lengths come from ExtendedLengthInfo
169                (eli.max_command_bytes(), eli.max_response_bytes())
170            } else if let (Some(cmd), Some(rsp)) = (ext_cap.max_cmd_len(), ext_cap.max_resp_len()) {
171                // In card 2.x, max lengths come from ExtendedCapabilities
172                (cmd, rsp)
173            } else {
174                // Fallback: use 255 if we have no information from the card
175                (255, 255)
176            };
177
178            let pw_status = ard.pw_status_bytes()?;
179            let pw1_max = pw_status.pw1_max_len();
180            let pw3_max = pw_status.pw3_max_len();
181
182            let caps = CardCaps::new(
183                ext_support,
184                chaining_support,
185                max_cmd_bytes,
186                max_rsp_bytes,
187                pw1_max,
188                pw3_max,
189            );
190
191            let imm = CardImmutable {
192                aid: ard.application_id()?,
193                ec: ard.extended_capabilities()?,
194                hb: Some(ard.historical_bytes()?),
195                eli: ard.extended_length_information()?,
196                ai: None, // FIXME: initialize elsewhere?
197            };
198
199            drop(tx);
200
201            // General mechanism to ask the backend for amendments to
202            // the CardCaps (e.g. to change support for "extended length")
203            //
204            // Also see https://blog.apdu.fr/posts/2011/05/extended-apdu-status-per-reader/
205            let caps = op.card.limit_card_caps(caps);
206
207            (caps, imm)
208        };
209
210        log::trace!("set card_caps to: {:x?}", caps);
211        op.card_caps = Some(caps);
212
213        log::trace!("set immutable card state to: {:x?}", imm);
214        op.immutable = Some(imm);
215
216        Ok(op)
217    }
218
219    /// Get the internal `CardBackend`.
220    ///
221    /// This is useful to perform operations on the card with a different crate,
222    /// e.g. `yubikey-management`.
223    pub fn into_card(self) -> Box<dyn CardBackend + Send + Sync> {
224        self.card
225    }
226
227    /// Start a transaction on the underlying CardBackend.
228    /// The resulting [Transaction] object allows performing commands on the card.
229    ///
230    /// Note: Transactions on the Card cannot be long running.
231    /// They may be reset by the smart card subsystem within seconds, when idle.
232    pub fn transaction(&mut self) -> Result<Transaction, Error> {
233        let card_caps = &mut self.card_caps;
234        let immutable = &mut self.immutable; // FIXME: unwrap
235
236        let tx = self.card.transaction(Some(OPENPGP_APPLICATION))?;
237
238        if tx.was_reset() {
239            // FIXME: Signal state invalidation to the library user?
240            // (E.g.: PIN verifications may have been lost.)
241        }
242
243        Ok(Transaction {
244            tx,
245            card_caps,
246            immutable,
247        })
248    }
249}
250
251/// To perform commands on a [`OpenPGP`], a [`Transaction`] must be started.
252/// This struct offers low-level access to OpenPGP card functionality.
253///
254/// On backends that support transactions, operations are grouped together in transaction, while
255/// an object of this type lives.
256///
257/// A [`Transaction`] on typical underlying card subsystems must be short lived.
258/// (Typically, smart cards can't be kept open for longer than a few seconds,
259/// before they are automatically closed.)
260pub struct Transaction<'a> {
261    tx: Box<dyn CardTransaction + Send + Sync + 'a>,
262    card_caps: &'a Option<CardCaps>,
263    immutable: &'a mut Option<CardImmutable>,
264}
265
266impl Transaction<'_> {
267    pub(crate) fn tx(&mut self) -> &mut dyn CardTransaction {
268        self.tx.as_mut()
269    }
270
271    pub(crate) fn send_command(
272        &mut self,
273        cmd: Command,
274        expect_reply: bool,
275    ) -> Result<RawResponse, Error> {
276        apdu::send_command(&mut *self.tx, cmd, *self.card_caps, expect_reply)
277    }
278
279    // SELECT
280
281    /// Select the OpenPGP card application
282    pub fn select(&mut self) -> Result<Vec<u8>, Error> {
283        log::info!("OpenPgpTransaction: select");
284
285        self.send_command(commands::select_openpgp()?, false)?
286            .try_into()
287    }
288
289    // TERMINATE DF
290
291    /// 7.2.16 TERMINATE DF
292    pub fn terminate_df(&mut self) -> Result<(), Error> {
293        log::info!("OpenPgpTransaction: terminate_df");
294
295        self.send_command(commands::terminate_df()?, false)?;
296        Ok(())
297    }
298
299    // ACTIVATE FILE
300
301    /// 7.2.17 ACTIVATE FILE
302    pub fn activate_file(&mut self) -> Result<(), Error> {
303        log::info!("OpenPgpTransaction: activate_file");
304
305        self.send_command(commands::activate_file()?, false)?;
306        Ok(())
307    }
308
309    // --- pinpad ---
310
311    /// Does the reader support FEATURE_VERIFY_PIN_DIRECT?
312    pub fn feature_pinpad_verify(&self) -> bool {
313        self.tx.feature_pinpad_verify()
314    }
315
316    /// Does the reader support FEATURE_MODIFY_PIN_DIRECT?
317    pub fn feature_pinpad_modify(&self) -> bool {
318        self.tx.feature_pinpad_modify()
319    }
320
321    // --- get data ---
322
323    /// Get the "application related data" from the card.
324    ///
325    /// (This data should probably be cached in a higher layer. Some parts of
326    /// it are needed regularly, and it does not usually change during
327    /// normal use of a card.)
328    pub fn application_related_data(&mut self) -> Result<ApplicationRelatedData, Error> {
329        log::info!("OpenPgpTransaction: application_related_data");
330
331        let resp = self.send_command(commands::application_related_data()?, true)?;
332        let value = Value::from(resp.data()?, true)?;
333
334        log::trace!(" ARD value: {:02x?}", value);
335
336        Ok(ApplicationRelatedData(Tlv::new(
337            Tags::ApplicationRelatedData,
338            value,
339        )))
340    }
341
342    // -- cached card data --
343
344    /// Get read access to cached immutable card information
345    fn card_immutable(&self) -> Result<&CardImmutable, Error> {
346        if let Some(imm) = &self.immutable {
347            Ok(imm)
348        } else {
349            // We expect that self.immutable has been initialized here
350            Err(Error::InternalError(
351                "Unexpected state of immutable cache".to_string(),
352            ))
353        }
354    }
355
356    /// Application Identifier.
357    ///
358    /// This function returns data that is cached during initialization.
359    /// Calling it doesn't require sending a command to the card.
360    pub fn application_identifier(&self) -> Result<ApplicationIdentifier, Error> {
361        Ok(self.card_immutable()?.aid)
362    }
363
364    /// Extended capabilities.
365    ///
366    /// This function returns data that is cached during initialization.
367    /// Calling it doesn't require sending a command to the card.
368    pub fn extended_capabilities(&self) -> Result<ExtendedCapabilities, Error> {
369        Ok(self.card_immutable()?.ec)
370    }
371
372    /// Historical Bytes (if available).
373    ///
374    /// This function returns data that is cached during initialization.
375    /// Calling it doesn't require sending a command to the card.
376    pub fn historical_bytes(&self) -> Result<Option<HistoricalBytes>, Error> {
377        Ok(self.card_immutable()?.hb)
378    }
379
380    /// Extended length info (if available).
381    ///
382    /// This function returns data that is cached during initialization.
383    /// Calling it doesn't require sending a command to the card.
384    pub fn extended_length_info(&self) -> Result<Option<ExtendedLengthInfo>, Error> {
385        Ok(self.card_immutable()?.eli)
386    }
387
388    #[allow(dead_code)]
389    pub(crate) fn algorithm_information_cached(
390        &mut self,
391    ) -> Result<Option<AlgorithmInformation>, Error> {
392        // FIXME: merge this fn with the regular/public `algorithm_information()` fn?
393
394        // We expect that self.immutable has been initialized here
395        match &self.immutable {
396            Some(ci) => {
397                // We have a cached copy of the data and return it
398                if let Some(ai) = &ci.ai {
399                    return Ok(ai.clone());
400                }
401            }
402            None => {
403                return Err(Error::InternalError(
404                    "Unexpected state of immutable cache".to_string(),
405                ))
406            }
407        }
408
409        // Cached AlgorithmInformation is unset in self.immutable, initialize it now
410        let ai = self.algorithm_information()?;
411
412        match self.immutable {
413            Some(ci) => {
414                ci.ai = Some(ai.clone());
415                Ok(ai)
416            }
417            None => Err(Error::InternalError(
418                "Unexpected state of immutable cache".to_string(),
419            )),
420        }
421    }
422
423    // --- login data (5e) ---
424
425    /// Get URL (5f50)
426    pub fn url(&mut self) -> Result<Vec<u8>, Error> {
427        log::info!("OpenPgpTransaction: url");
428
429        self.send_command(commands::url()?, true)?.try_into()
430    }
431
432    /// Get Login Data (5e)
433    pub fn login_data(&mut self) -> Result<Vec<u8>, Error> {
434        log::info!("OpenPgpTransaction: login_data");
435
436        self.send_command(commands::login_data()?, true)?.try_into()
437    }
438
439    /// Get cardholder related data (65)
440    pub fn cardholder_related_data(&mut self) -> Result<CardholderRelatedData, Error> {
441        log::info!("OpenPgpTransaction: cardholder_related_data");
442
443        let resp = self.send_command(commands::cardholder_related_data()?, true)?;
444
445        resp.data()?.try_into()
446    }
447
448    /// Get security support template (7a)
449    pub fn security_support_template(&mut self) -> Result<SecuritySupportTemplate, Error> {
450        log::info!("OpenPgpTransaction: security_support_template");
451
452        let resp = self.send_command(commands::security_support_template()?, true)?;
453
454        let tlv = Tlv::try_from(resp.data()?)?;
455
456        let dst = tlv.find(Tags::DigitalSignatureCounter).ok_or_else(|| {
457            Error::NotFound("Couldn't get DigitalSignatureCounter DO".to_string())
458        })?;
459
460        if let Value::S(data) = dst {
461            let data = match &data[..] {
462                // the signature counter should be a three byte value
463                [a, b, c] => [0, *a, *b, *c],
464                _ => {
465                    return Err(Error::ParseError(format!(
466                        "Unexpected length {} for DigitalSignatureCounter DO",
467                        data.len()
468                    )))
469                }
470            };
471
472            let dsc: u32 = u32::from_be_bytes(data);
473            Ok(SecuritySupportTemplate { dsc })
474        } else {
475            Err(Error::NotFound(
476                "Failed to process SecuritySupportTemplate".to_string(),
477            ))
478        }
479    }
480
481    /// Get cardholder certificate (each for AUT, DEC and SIG).
482    ///
483    /// Call select_data() before calling this fn to select a particular
484    /// certificate (if the card supports multiple certificates).
485    ///
486    /// According to the OpenPGP card specification:
487    ///
488    /// The cardholder certificate DOs are designed to store a certificate (e. g. X.509)
489    /// for the keys in the card. They can be used to identify the card in a client-server
490    /// authentication, where specific non-OpenPGP-certificates are needed, for S-MIME and
491    /// other x.509 related functions.
492    ///
493    /// (See <https://support.nitrokey.com/t/nitrokey-pro-and-pkcs-11-support-on-linux/160/4>
494    /// for some discussion of the `cardholder certificate` OpenPGP card feature)
495    #[allow(dead_code)]
496    pub fn cardholder_certificate(&mut self) -> Result<Vec<u8>, Error> {
497        log::info!("OpenPgpTransaction: cardholder_certificate");
498
499        self.send_command(commands::cardholder_certificate()?, true)?
500            .try_into()
501    }
502
503    /// Call "GET NEXT DATA" for the DO cardholder certificate.
504    ///
505    /// Cardholder certificate data for multiple slots can be read from the card by first calling
506    /// cardholder_certificate(), followed by up to two calls to  next_cardholder_certificate().
507    pub fn next_cardholder_certificate(&mut self) -> Result<Vec<u8>, Error> {
508        log::info!("OpenPgpTransaction: next_cardholder_certificate");
509
510        self.send_command(commands::get_next_cardholder_certificate()?, true)?
511            .try_into()
512    }
513
514    /// Get "KDF-DO" (announced in Extended Capabilities)
515    pub fn kdf_do(&mut self) -> Result<KdfDo, Error> {
516        log::info!("OpenPgpTransaction: kdf_do");
517
518        let kdf_do = self
519            .send_command(commands::kdf_do()?, true)?
520            .data()?
521            .try_into()?;
522
523        log::trace!(" KDF DO value: {:02x?}", kdf_do);
524
525        Ok(kdf_do)
526    }
527
528    /// Get "Algorithm Information"
529    pub fn algorithm_information(&mut self) -> Result<Option<AlgorithmInformation>, Error> {
530        log::info!("OpenPgpTransaction: algorithm_information");
531
532        let resp = self.send_command(commands::algo_info()?, true)?;
533
534        let ai = resp.data()?.try_into()?;
535        Ok(Some(ai))
536    }
537
538    /// Get "Attestation Certificate (Yubico)"
539    pub fn attestation_certificate(&mut self) -> Result<Vec<u8>, Error> {
540        log::info!("OpenPgpTransaction: attestation_certificate");
541
542        self.send_command(commands::attestation_certificate()?, true)?
543            .try_into()
544    }
545
546    /// Firmware Version (YubiKey specific (?))
547    pub fn firmware_version(&mut self) -> Result<Vec<u8>, Error> {
548        log::info!("OpenPgpTransaction: firmware_version");
549
550        self.send_command(commands::firmware_version()?, true)?
551            .try_into()
552    }
553
554    /// Set identity (Nitrokey Start specific (?)).
555    /// [see:
556    /// <https://docs.nitrokey.com/start/linux/multiple-identities.html>
557    /// <https://github.com/Nitrokey/nitrokey-start-firmware/pull/33/>]
558    pub fn set_identity(&mut self, id: u8) -> Result<Vec<u8>, Error> {
559        log::info!("OpenPgpTransaction: set_identity");
560
561        let resp = self.send_command(commands::set_identity(id)?, false);
562
563        // Apparently it's normal to get "NotTransacted" from pcsclite when
564        // the identity switch was successful.
565        if let Err(Error::Smartcard(SmartcardError::NotTransacted)) = resp {
566            Ok(vec![])
567        } else {
568            resp?.try_into()
569        }
570    }
571
572    /// SELECT DATA ("select a DO in the current template").
573    ///
574    /// This command currently only applies to
575    /// [`cardholder_certificate`](Transaction::cardholder_certificate) and
576    /// [`set_cardholder_certificate`](Transaction::set_cardholder_certificate)
577    /// in OpenPGP card.
578    ///
579    /// (This library leaves it up to consumers to decide on a strategy for dealing with this
580    /// issue. Possible strategies include:
581    /// - asking the card for its [`Transaction::firmware_version`]
582    ///   and using the workaround if version <=5.4.3
583    /// - trying this command first without the workaround, then with workaround if the card
584    ///   returns [`StatusBytes::IncorrectParametersCommandDataField`]
585    /// - for read operations: using [`Transaction::next_cardholder_certificate`]
586    ///   instead of SELECT DATA)
587    pub fn select_data(&mut self, num: u8, tag: &[u8]) -> Result<(), Error> {
588        log::info!("OpenPgpTransaction: select_data");
589
590        let tlv = Tlv::new(
591            Tags::GeneralReference,
592            Value::C(vec![Tlv::new(Tags::TagList, Value::S(tag.to_vec()))]),
593        );
594
595        let mut data = tlv.serialize();
596
597        // YubiKey 5 up to (and including) firmware version 5.4.3 need a workaround
598        // for this command.
599        //
600        // When sending the SELECT DATA command as defined in the card spec, without enabling the
601        // workaround, bad YubiKey firmware versions (<= 5.4.3) return
602        // `StatusBytes::IncorrectParametersCommandDataField`
603        //
604        // FIXME: caching for `firmware_version`?
605        if let Ok(version) = self.firmware_version() {
606            if version.len() == 3
607                && version[0] == 5
608                && (version[1] < 4 || (version[1] == 4 && version[2] <= 3))
609            {
610                // Workaround for YubiKey 5.
611                // This hack is needed <= 5.4.3 according to ykman sources
612                // (see _select_certificate() in ykman/openpgp.py).
613
614                // Catch blatant misuse: tags are 1-2 bytes long
615                if data.len() > 255 {
616                    return Err(Error::InternalError(format!(
617                        "select_data: exceedingly long data: {}",
618                        data.len()
619                    )));
620                }
621
622                data.insert(0, data.len() as u8);
623            }
624        }
625
626        let cmd = commands::select_data(num, data)?;
627
628        // Possible response data (Control Parameter = CP) don't need to be evaluated by the
629        // application (See "7.2.5 SELECT DATA")
630        self.send_command(cmd, true)?.check_ok()?;
631
632        Ok(())
633    }
634
635    // --- optional private DOs (0101 - 0104) ---
636
637    /// Get data from "private use" DO.
638    ///
639    /// `num` must be between 1 and 4.
640    pub fn private_use_do(&mut self, num: u8) -> Result<Vec<u8>, Error> {
641        log::info!("OpenPgpTransaction: private_use_do");
642
643        let tag = match num {
644            1 => Tags::PrivateUse1,
645            2 => Tags::PrivateUse2,
646            3 => Tags::PrivateUse3,
647            4 => Tags::PrivateUse4,
648            _ => {
649                return Err(Error::UnsupportedFeature(format!(
650                    "Illegal Private Use DO num '{}'",
651                    num,
652                )))
653            }
654        };
655
656        let cmd = commands::get_data(tag)?;
657        self.send_command(cmd, true)?.try_into()
658    }
659
660    // ----------
661
662    /// Reset all state on this OpenPGP card.
663    ///
664    /// Note: the "factory reset" operation is not directly offered by the
665    /// card spec. It is implemented as a series of OpenPGP card commands:
666    /// - send 4 bad requests to verify pw1,
667    /// - send 4 bad requests to verify pw3,
668    /// - terminate_df,
669    /// - activate_file.
670    ///
671    /// With most cards, this sequence of operations causes the card
672    /// to revert to a "blank" state.
673    ///
674    /// (However, e.g. vanilla Gnuk doesn't support this functionality.
675    /// Gnuk needs to be built with the `--enable-factory-reset`
676    /// option to the `configure` script to enable this functionality).
677    pub fn factory_reset(&mut self) -> Result<(), Error> {
678        log::info!("OpenPgpTransaction: factory_reset");
679
680        let mut bad_pw_len = 8;
681
682        // In KDF mode, the "bad password" we try must have the correct length for the KDF hash
683        // algorithm. Otherwise, the PIN retry counter doesn't decrement, and don't lock the card
684        // (which means we don't get to do a reset).
685        if let Ok(kdf_do) = self.kdf_do() {
686            if kdf_do.hash_algo() == Some(0x08) {
687                bad_pw_len = 0x20;
688            } else if kdf_do.hash_algo() == Some(0x0a) {
689                bad_pw_len = 0x40;
690            }
691        }
692
693        let bad_pw: Vec<_> = std::iter::repeat(0x40).take(bad_pw_len).collect();
694
695        // send 4 bad requests to verify pw1
696        for _ in 0..4 {
697            let resp = self.verify_pw1_sign(bad_pw.clone().into());
698
699            if !(matches!(
700                resp,
701                Err(Error::CardStatus(StatusBytes::SecurityStatusNotSatisfied))
702                    | Err(Error::CardStatus(StatusBytes::AuthenticationMethodBlocked))
703                    | Err(Error::CardStatus(
704                        StatusBytes::ExecutionErrorNonVolatileMemoryUnchanged
705                    ))
706                    | Err(Error::CardStatus(StatusBytes::PasswordNotChecked(_)))
707                    | Err(Error::CardStatus(StatusBytes::ConditionOfUseNotSatisfied))
708            )) {
709                return Err(Error::InternalError(
710                    "Unexpected status for reset, at pw1.".into(),
711                ));
712            }
713        }
714
715        // send 4 bad requests to verify pw3
716        for _ in 0..4 {
717            let resp = self.verify_pw3(bad_pw.clone().into());
718
719            if !(matches!(
720                resp,
721                Err(Error::CardStatus(StatusBytes::SecurityStatusNotSatisfied))
722                    | Err(Error::CardStatus(StatusBytes::AuthenticationMethodBlocked))
723                    | Err(Error::CardStatus(
724                        StatusBytes::ExecutionErrorNonVolatileMemoryUnchanged
725                    ))
726                    | Err(Error::CardStatus(StatusBytes::PasswordNotChecked(_)))
727                    | Err(Error::CardStatus(StatusBytes::ConditionOfUseNotSatisfied))
728            )) {
729                return Err(Error::InternalError(
730                    "Unexpected status for reset, at pw3.".into(),
731                ));
732            }
733        }
734
735        self.terminate_df()?;
736        self.activate_file()?;
737
738        Ok(())
739    }
740
741    // --- verify/modify ---
742
743    /// Verify pw1 (user) for signing operation (mode 81).
744    ///
745    /// Depending on the PW1 status byte (see Extended Capabilities) this
746    /// access condition is only valid for one PSO:CDS command or remains
747    /// valid for several attempts.
748    pub fn verify_pw1_sign(&mut self, pin: SecretVec<u8>) -> Result<(), Error> {
749        log::info!("OpenPgpTransaction: verify_pw1_sign");
750
751        let cmd = commands::verify_pw1_81(pin)?;
752
753        self.send_command(cmd, false)?.try_into()
754    }
755
756    /// Verify pw1 (user) for signing operation (mode 81) using a
757    /// pinpad on the card reader. If no usable pinpad is found, an error
758    /// is returned.
759    ///
760    /// Depending on the PW1 status byte (see Extended Capabilities) this
761    /// access condition is only valid for one PSO:CDS command or remains
762    /// valid for several attempts.
763    pub fn verify_pw1_sign_pinpad(&mut self) -> Result<(), Error> {
764        log::info!("OpenPgpTransaction: verify_pw1_sign_pinpad");
765
766        let cc = *self.card_caps;
767
768        let res = self.tx().pinpad_verify(PinType::Sign, &cc)?;
769        RawResponse::try_from(res)?.try_into()
770    }
771
772    /// Check the current access of PW1 for signing (mode 81).
773    ///
774    /// If verification is not required, an empty Ok Response is returned.
775    ///
776    /// (Note:
777    /// - some cards don't correctly implement this feature, e.g. YubiKey 5
778    /// - some cards that don't support this instruction may decrease the pin's error count,
779    ///   eventually requiring the user to reset the pin)
780    pub fn check_pw1_sign(&mut self) -> Result<(), Error> {
781        log::info!("OpenPgpTransaction: check_pw1_sign");
782
783        let verify = commands::verify_pw1_81(vec![].into())?;
784        self.send_command(verify, false)?.try_into()
785    }
786
787    /// Verify PW1 (user).
788    /// (For operations except signing, mode 82).
789    pub fn verify_pw1_user(&mut self, pin: SecretVec<u8>) -> Result<(), Error> {
790        log::info!("OpenPgpTransaction: verify_pw1_user");
791
792        let verify = commands::verify_pw1_82(pin)?;
793        self.send_command(verify, false)?.try_into()
794    }
795
796    /// Verify PW1 (user) for operations except signing (mode 82),
797    /// using a pinpad on the card reader. If no usable pinpad is found,
798    /// an error is returned.
799    pub fn verify_pw1_user_pinpad(&mut self) -> Result<(), Error> {
800        log::info!("OpenPgpTransaction: verify_pw1_user_pinpad");
801
802        let cc = *self.card_caps;
803
804        let res = self.tx().pinpad_verify(PinType::User, &cc)?;
805        RawResponse::try_from(res)?.try_into()
806    }
807
808    /// Check the current access of PW1.
809    /// (For operations except signing, mode 82).
810    ///
811    /// If verification is not required, an empty Ok Response is returned.
812    ///
813    /// (Note:
814    /// - some cards don't correctly implement this feature, e.g. YubiKey 5
815    /// - some cards that don't support this instruction may decrease the pin's error count,
816    ///   eventually requiring the user to reset the pin)
817    pub fn check_pw1_user(&mut self) -> Result<(), Error> {
818        log::info!("OpenPgpTransaction: check_pw1_user");
819
820        let verify = commands::verify_pw1_82(vec![].into())?;
821        self.send_command(verify, false)?.try_into()
822    }
823
824    /// Verify PW3 (admin).
825    pub fn verify_pw3(&mut self, pin: SecretVec<u8>) -> Result<(), Error> {
826        log::info!("OpenPgpTransaction: verify_pw3");
827
828        let verify = commands::verify_pw3(pin)?;
829        self.send_command(verify, false)?.try_into()
830    }
831
832    /// Verify PW3 (admin) using a pinpad on the card reader. If no usable
833    /// pinpad is found, an error is returned.
834    pub fn verify_pw3_pinpad(&mut self) -> Result<(), Error> {
835        log::info!("OpenPgpTransaction: verify_pw3_pinpad");
836
837        let cc = *self.card_caps;
838
839        let res = self.tx().pinpad_verify(PinType::Admin, &cc)?;
840        RawResponse::try_from(res)?.try_into()
841    }
842
843    /// Check the current access of PW3 (admin).
844    ///
845    /// If verification is not required, an empty Ok Response is returned.
846    ///
847    /// (Note:
848    /// - some cards don't correctly implement this feature, e.g. YubiKey 5
849    /// - some cards that don't support this instruction may decrease the pin's error count,
850    ///   eventually requiring the user to factory reset the card)
851    pub fn check_pw3(&mut self) -> Result<(), Error> {
852        log::info!("OpenPgpTransaction: check_pw3");
853
854        let verify = commands::verify_pw3(vec![].into())?;
855        self.send_command(verify, false)?.try_into()
856    }
857
858    /// Change the value of PW1 (user password).
859    ///
860    /// The current value of PW1 must be presented in `old` for authorization.
861    pub fn change_pw1(&mut self, old: SecretVec<u8>, new: SecretVec<u8>) -> Result<(), Error> {
862        log::info!("OpenPgpTransaction: change_pw1");
863
864        let mut data = vec![];
865        data.extend(old.expose_secret());
866        data.extend(new.expose_secret());
867
868        let change = commands::change_pw1(data.into())?;
869        self.send_command(change, false)?.try_into()
870    }
871
872    /// Change the value of PW1 (0x81) using a pinpad on the
873    /// card reader. If no usable pinpad is found, an error is returned.
874    pub fn change_pw1_pinpad(&mut self) -> Result<(), Error> {
875        log::info!("OpenPgpTransaction: change_pw1_pinpad");
876
877        let cc = *self.card_caps;
878
879        // Note: for change PW, only 0x81 and 0x83 are used!
880        // 0x82 is implicitly the same as 0x81.
881        let res = self.tx().pinpad_modify(PinType::Sign, &cc)?;
882        RawResponse::try_from(res)?.try_into()
883    }
884
885    /// Change the value of PW3 (admin password).
886    ///
887    /// The current value of PW3 must be presented in `old` for authorization.
888    pub fn change_pw3(&mut self, old: SecretVec<u8>, new: SecretVec<u8>) -> Result<(), Error> {
889        log::info!("OpenPgpTransaction: change_pw3");
890
891        let mut data = vec![];
892        data.extend(old.expose_secret());
893        data.extend(new.expose_secret());
894
895        let change = commands::change_pw3(data.into())?;
896        self.send_command(change, false)?.try_into()
897    }
898
899    /// Change the value of PW3 (admin password) using a pinpad on the
900    /// card reader. If no usable pinpad is found, an error is returned.
901    pub fn change_pw3_pinpad(&mut self) -> Result<(), Error> {
902        log::info!("OpenPgpTransaction: change_pw3_pinpad");
903
904        let cc = *self.card_caps;
905
906        let res = self.tx().pinpad_modify(PinType::Admin, &cc)?;
907        RawResponse::try_from(res)?.try_into()
908    }
909
910    /// Reset the error counter for PW1 (user password) and set a new value
911    /// for PW1.
912    ///
913    /// For authorization, either:
914    /// - PW3 must have been verified previously,
915    /// - secure messaging must be currently used,
916    /// - the resetting_code must be presented.
917    pub fn reset_retry_counter_pw1(
918        &mut self,
919        new_pw1: SecretVec<u8>,
920        resetting_code: Option<SecretVec<u8>>,
921    ) -> Result<(), Error> {
922        log::info!("OpenPgpTransaction: reset_retry_counter_pw1");
923
924        let cmd = commands::reset_retry_counter_pw1(resetting_code, new_pw1)?;
925        self.send_command(cmd, false)?.try_into()
926    }
927
928    // --- decrypt ---
929
930    /// Decrypt the ciphertext in `dm`, on the card.
931    ///
932    /// (This is a wrapper around the low-level pso_decipher
933    /// operation, it builds the required `data` field from `dm`)
934    pub fn decipher(&mut self, dm: Cryptogram) -> Result<Vec<u8>, Error> {
935        match dm {
936            Cryptogram::RSA(message) => {
937                // "Padding indicator byte (00) for RSA" (pg. 69)
938                let mut data = vec![0x0];
939                data.extend_from_slice(message);
940
941                // Call the card to decrypt `data`
942                self.pso_decipher(data)
943            }
944            Cryptogram::ECDH(eph) => {
945                // "In case of ECDH the card supports a partial decrypt
946                // only. The input is a cipher DO with the following data:"
947                // A6 xx Cipher DO
948                //  -> 7F49 xx Public Key DO
949                //    -> 86 xx External Public Key
950
951                // External Public Key
952                let epk = Tlv::new(Tags::ExternalPublicKey, Value::S(eph.to_vec()));
953
954                // Public Key DO
955                let pkdo = Tlv::new(Tags::PublicKey, Value::C(vec![epk]));
956
957                // Cipher DO
958                let cdo = Tlv::new(Tags::Cipher, Value::C(vec![pkdo]));
959
960                self.pso_decipher(cdo.serialize())
961            }
962        }
963    }
964
965    /// Run decryption operation on the smartcard (low level operation)
966    /// (7.2.11 PSO: DECIPHER)
967    ///
968    /// (consider using the [`Self::decipher`] method if you don't want to create
969    /// the data field manually)
970    pub fn pso_decipher(&mut self, data: Vec<u8>) -> Result<Vec<u8>, Error> {
971        log::info!("OpenPgpTransaction: pso_decipher");
972
973        // The OpenPGP card is already connected and PW1 82 has been verified
974        let dec_cmd = commands::decryption(data)?;
975        let resp = self.send_command(dec_cmd, true)?;
976
977        Ok(resp.data()?.to_vec())
978    }
979
980    /// Set the key to be used for the pso_decipher and the internal_authenticate commands.
981    ///
982    /// Valid until next reset of of the card or the next call to `select`
983    /// The only keys that can be configured by this command are the `Decryption` and `Authentication` keys.
984    ///
985    /// The following first sets the *Authentication* key to be used for [`Self::pso_decipher`]
986    /// and then sets the *Decryption* key to be used for [`Self::internal_authenticate`].
987    ///
988    /// ```no_run
989    /// # use openpgp_card::ocard::{KeyType, Transaction};
990    /// # let mut tx: Transaction<'static> = panic!();
991    /// tx.manage_security_environment(KeyType::Decryption, KeyType::Authentication)?;
992    /// tx.manage_security_environment(KeyType::Authentication, KeyType::Decryption)?;
993    /// # Result::<(), openpgp_card::Error>::Ok(())
994    /// ```
995    pub fn manage_security_environment(
996        &mut self,
997        for_operation: KeyType,
998        key_ref: KeyType,
999    ) -> Result<(), Error> {
1000        log::info!("OpenPgpTransaction: manage_security_environment");
1001
1002        if !matches!(for_operation, KeyType::Authentication | KeyType::Decryption)
1003            || !matches!(key_ref, KeyType::Authentication | KeyType::Decryption)
1004        {
1005            return Err(Error::UnsupportedAlgo("Only Decryption and Authentication keys can be manipulated by manage_security_environment".to_string()));
1006        }
1007
1008        let cmd = commands::manage_security_environment(for_operation, key_ref)?;
1009        let resp = self.send_command(cmd, false)?;
1010        resp.check_ok()?;
1011        Ok(())
1012    }
1013
1014    // --- sign ---
1015
1016    /// Sign `hash`, on the card.
1017    ///
1018    /// This is a wrapper around the low-level
1019    /// pso_compute_digital_signature operation.
1020    /// It builds the required `data` field from `hash`.
1021    ///
1022    /// For RSA, this means a "DigestInfo" data structure is generated.
1023    /// (see 7.2.10.2 DigestInfo for RSA).
1024    ///
1025    /// With ECC the hash data is processed as is, using
1026    /// [`Self::pso_compute_digital_signature`].
1027    pub fn signature_for_hash(&mut self, hash: Hash) -> Result<Vec<u8>, Error> {
1028        self.pso_compute_digital_signature(digestinfo(hash)?)
1029    }
1030
1031    /// Run signing operation on the smartcard (low level operation)
1032    /// (7.2.10 PSO: COMPUTE DIGITAL SIGNATURE)
1033    ///
1034    /// (consider using the [`Self::signature_for_hash`] method if you don't
1035    /// want to create the data field manually)
1036    pub fn pso_compute_digital_signature(&mut self, data: Vec<u8>) -> Result<Vec<u8>, Error> {
1037        log::info!("OpenPgpTransaction: pso_compute_digital_signature");
1038
1039        let cds_cmd = commands::signature(data)?;
1040        let resp = self.send_command(cds_cmd, true)?;
1041
1042        Ok(resp.data().map(|d| d.to_vec())?)
1043    }
1044
1045    // --- internal authenticate ---
1046
1047    /// Auth-sign `hash`, on the card.
1048    ///
1049    /// This is a wrapper around the low-level
1050    /// internal_authenticate operation.
1051    /// It builds the required `data` field from `hash`.
1052    ///
1053    /// For RSA, this means a "DigestInfo" data structure is generated.
1054    /// (see 7.2.10.2 DigestInfo for RSA).
1055    ///
1056    /// With ECC the hash data is processed as is.
1057    pub fn authenticate_for_hash(&mut self, hash: Hash) -> Result<Vec<u8>, Error> {
1058        self.internal_authenticate(digestinfo(hash)?)
1059    }
1060
1061    /// Run signing operation on the smartcard (low level operation)
1062    /// (7.2.13 INTERNAL AUTHENTICATE)
1063    ///
1064    /// (consider using the `authenticate_for_hash()` method if you don't
1065    /// want to create the data field manually)
1066    pub fn internal_authenticate(&mut self, data: Vec<u8>) -> Result<Vec<u8>, Error> {
1067        log::info!("OpenPgpTransaction: internal_authenticate");
1068
1069        let ia_cmd = commands::internal_authenticate(data)?;
1070        let resp = self.send_command(ia_cmd, true)?;
1071
1072        Ok(resp.data().map(|d| d.to_vec())?)
1073    }
1074
1075    // --- PUT DO ---
1076
1077    /// Set data of "private use" DO.
1078    ///
1079    /// `num` must be between 1 and 4.
1080    ///
1081    /// Access condition:
1082    /// - 1/3 need PW1 (82)
1083    /// - 2/4 need PW3
1084    pub fn set_private_use_do(&mut self, num: u8, data: Vec<u8>) -> Result<(), Error> {
1085        log::info!("OpenPgpTransaction: set_private_use_do");
1086
1087        let tag = match num {
1088            1 => Tags::PrivateUse1,
1089            2 => Tags::PrivateUse2,
1090            3 => Tags::PrivateUse3,
1091            4 => Tags::PrivateUse4,
1092            _ => {
1093                return Err(Error::UnsupportedFeature(format!(
1094                    "Illegal Private Use DO num '{}'",
1095                    num,
1096                )))
1097            }
1098        };
1099
1100        let cmd = commands::put_data(tag, data)?;
1101        self.send_command(cmd, true)?.try_into()
1102    }
1103
1104    pub fn set_login(&mut self, login: &[u8]) -> Result<(), Error> {
1105        log::info!("OpenPgpTransaction: set_login");
1106
1107        let cmd = commands::put_login_data(login.to_vec())?;
1108        self.send_command(cmd, false)?.try_into()
1109    }
1110
1111    pub fn set_name(&mut self, name: &[u8]) -> Result<(), Error> {
1112        log::info!("OpenPgpTransaction: set_name");
1113
1114        let cmd = commands::put_name(name.to_vec())?;
1115        self.send_command(cmd, false)?.try_into()
1116    }
1117
1118    pub fn set_lang(&mut self, lang: &[Lang]) -> Result<(), Error> {
1119        log::info!("OpenPgpTransaction: set_lang");
1120
1121        let bytes: Vec<_> = lang.iter().flat_map(|&l| Vec::<u8>::from(l)).collect();
1122
1123        let cmd = commands::put_lang(bytes)?;
1124        self.send_command(cmd, false)?.try_into()
1125    }
1126
1127    pub fn set_sex(&mut self, sex: Sex) -> Result<(), Error> {
1128        log::info!("OpenPgpTransaction: set_sex");
1129
1130        let cmd = commands::put_sex((&sex).into())?;
1131        self.send_command(cmd, false)?.try_into()
1132    }
1133
1134    pub fn set_url(&mut self, url: &[u8]) -> Result<(), Error> {
1135        log::info!("OpenPgpTransaction: set_url");
1136
1137        let cmd = commands::put_url(url.to_vec())?;
1138        self.send_command(cmd, false)?.try_into()
1139    }
1140
1141    /// Set cardholder certificate (for AUT, DEC or SIG).
1142    ///
1143    /// Call select_data() before calling this fn to select a particular
1144    /// certificate (if the card supports multiple certificates).
1145    pub fn set_cardholder_certificate(&mut self, data: Vec<u8>) -> Result<(), Error> {
1146        log::info!("OpenPgpTransaction: set_cardholder_certificate");
1147
1148        let cmd = commands::put_cardholder_certificate(data)?;
1149        self.send_command(cmd, false)?.try_into()
1150    }
1151
1152    /// Set algorithm attributes for a key slot (4.4.3.9 Algorithm Attributes)
1153    ///
1154    /// Note: `algorithm_attributes` needs to precisely specify the
1155    /// RSA bit-size of e (if applicable), and import format, with values
1156    /// that the current card supports.
1157    pub fn set_algorithm_attributes(
1158        &mut self,
1159        key_type: KeyType,
1160        algorithm_attributes: &AlgorithmAttributes,
1161    ) -> Result<(), Error> {
1162        log::info!("OpenPgpTransaction: set_algorithm_attributes");
1163
1164        // Don't set algorithm if the feature is not available?
1165        let ecap = self.extended_capabilities()?;
1166        if !ecap.algo_attrs_changeable() {
1167            // Don't change the algorithm attributes, if the card doesn't support change
1168            // FIXME: Compare current and requested setting and return an error, if they differ?
1169
1170            return Ok(());
1171        }
1172
1173        // Command to PUT the algorithm attributes
1174        let cmd = commands::put_data(
1175            key_type.algorithm_tag(),
1176            algorithm_attributes.to_data_object()?,
1177        )?;
1178
1179        self.send_command(cmd, false)?.try_into()
1180    }
1181
1182    /// Set PW Status Bytes.
1183    ///
1184    /// If `long` is false, send 1 byte to the card, otherwise 4.
1185    /// According to the spec, length information should not be changed.
1186    ///
1187    /// So, effectively, with 'long == false' the setting `pw1_cds_multi`
1188    /// can be changed.
1189    /// With 'long == true', the settings `pw1_pin_block` and `pw3_pin_block`
1190    /// can also be changed.
1191    ///
1192    /// (See OpenPGP card spec, pg. 28)
1193    pub fn set_pw_status_bytes(
1194        &mut self,
1195        pw_status: &PWStatusBytes,
1196        long: bool,
1197    ) -> Result<(), Error> {
1198        log::info!("OpenPgpTransaction: set_pw_status_bytes");
1199
1200        let data = pw_status.serialize_for_put(long);
1201
1202        let cmd = commands::put_pw_status(data)?;
1203        self.send_command(cmd, false)?.try_into()
1204    }
1205
1206    pub fn set_fingerprint(&mut self, fp: Fingerprint, key_type: KeyType) -> Result<(), Error> {
1207        log::info!("OpenPgpTransaction: set_fingerprint");
1208
1209        let cmd = commands::put_data(key_type.fingerprint_put_tag(), fp.as_bytes().to_vec())?;
1210
1211        self.send_command(cmd, false)?.try_into()
1212    }
1213
1214    pub fn set_ca_fingerprint_1(&mut self, fp: Fingerprint) -> Result<(), Error> {
1215        log::info!("OpenPgpTransaction: set_ca_fingerprint_1");
1216
1217        let cmd = commands::put_data(Tags::CaFingerprint1, fp.as_bytes().to_vec())?;
1218        self.send_command(cmd, false)?.try_into()
1219    }
1220
1221    pub fn set_ca_fingerprint_2(&mut self, fp: Fingerprint) -> Result<(), Error> {
1222        log::info!("OpenPgpTransaction: set_ca_fingerprint_2");
1223
1224        let cmd = commands::put_data(Tags::CaFingerprint2, fp.as_bytes().to_vec())?;
1225        self.send_command(cmd, false)?.try_into()
1226    }
1227
1228    pub fn set_ca_fingerprint_3(&mut self, fp: Fingerprint) -> Result<(), Error> {
1229        log::info!("OpenPgpTransaction: set_ca_fingerprint_3");
1230
1231        let cmd = commands::put_data(Tags::CaFingerprint3, fp.as_bytes().to_vec())?;
1232        self.send_command(cmd, false)?.try_into()
1233    }
1234
1235    pub fn set_creation_time(
1236        &mut self,
1237        time: KeyGenerationTime,
1238        key_type: KeyType,
1239    ) -> Result<(), Error> {
1240        log::info!("OpenPgpTransaction: set_creation_time");
1241
1242        // Timestamp update
1243        let time_value: Vec<u8> = time.get().to_be_bytes().to_vec();
1244
1245        let cmd = commands::put_data(key_type.timestamp_put_tag(), time_value)?;
1246
1247        self.send_command(cmd, false)?.try_into()
1248    }
1249
1250    // FIXME: optional DO SM-Key-ENC
1251
1252    // FIXME: optional DO SM-Key-MAC
1253
1254    /// Set resetting code
1255    /// (4.3.4 Resetting Code)
1256    pub fn set_resetting_code(&mut self, resetting_code: SecretVec<u8>) -> Result<(), Error> {
1257        log::info!("OpenPgpTransaction: set_resetting_code");
1258
1259        let cmd = commands::put_data(Tags::ResettingCode, resetting_code)?;
1260        self.send_command(cmd, false)?.try_into()
1261    }
1262
1263    /// Set AES key for symmetric decryption/encryption operations.
1264    ///
1265    /// Optional DO (announced in Extended Capabilities) for
1266    /// PSO:ENC/DEC with AES (32 bytes dec. in case of
1267    /// AES256, 16 bytes dec. in case of AES128).
1268    pub fn set_pso_enc_dec_key(&mut self, key: &[u8]) -> Result<(), Error> {
1269        log::info!("OpenPgpTransaction: set_pso_enc_dec_key");
1270
1271        let cmd = commands::put_data(Tags::PsoEncDecKey, key.to_vec())?;
1272        self.send_command(cmd, false)?.try_into()
1273    }
1274
1275    /// Set UIF for PSO:CDS
1276    pub fn set_uif_pso_cds(&mut self, uif: &UserInteractionFlag) -> Result<(), Error> {
1277        log::info!("OpenPgpTransaction: set_uif_pso_cds");
1278
1279        let cmd = commands::put_data(Tags::UifSig, uif.as_bytes().to_vec())?;
1280        self.send_command(cmd, false)?.try_into()
1281    }
1282
1283    /// Set UIF for PSO:DEC
1284    pub fn set_uif_pso_dec(&mut self, uif: &UserInteractionFlag) -> Result<(), Error> {
1285        log::info!("OpenPgpTransaction: set_uif_pso_dec");
1286
1287        let cmd = commands::put_data(Tags::UifDec, uif.as_bytes().to_vec())?;
1288        self.send_command(cmd, false)?.try_into()
1289    }
1290
1291    /// Set UIF for PSO:AUT
1292    pub fn set_uif_pso_aut(&mut self, uif: &UserInteractionFlag) -> Result<(), Error> {
1293        log::info!("OpenPgpTransaction: set_uif_pso_aut");
1294
1295        let cmd = commands::put_data(Tags::UifAuth, uif.as_bytes().to_vec())?;
1296        self.send_command(cmd, false)?.try_into()
1297    }
1298
1299    /// Set UIF for Attestation key
1300    ///
1301    /// (Caution: Setting the touch policy of the Attestation slot on YubiKey 5 devices
1302    /// to a variation of "Fixed" is permanent for the lifetime of the hardware device!
1303    ///
1304    /// It can't be undone with a factory reset!
1305    ///
1306    /// However, a "fixed" attestation key touch policy can be cleared by overwriting the
1307    /// attestation key.
1308    ///
1309    /// Related/relevant: Overwriting the original Yubico CA attestation key is also permanent.
1310    /// It can't be restored with a factory reset either.)
1311    pub fn set_uif_attestation(&mut self, uif: &UserInteractionFlag) -> Result<(), Error> {
1312        log::info!("OpenPgpTransaction: set_uif_attestation");
1313
1314        let cmd = commands::put_data(Tags::UifAttestation, uif.as_bytes().to_vec())?;
1315        self.send_command(cmd, false)?.try_into()
1316    }
1317
1318    /// Generate Attestation (Yubico)
1319    pub fn generate_attestation(&mut self, key_type: KeyType) -> Result<(), Error> {
1320        log::info!("OpenPgpTransaction: generate_attestation");
1321
1322        let key = match key_type {
1323            KeyType::Signing => 0x01,
1324            KeyType::Decryption => 0x02,
1325            KeyType::Authentication => 0x03,
1326            _ => return Err(Error::InternalError("Unexpected KeyType".to_string())),
1327        };
1328
1329        let cmd = commands::generate_attestation(key)?;
1330        self.send_command(cmd, false)?.try_into()
1331    }
1332
1333    // FIXME: Attestation key algo attr, FP, CA-FP, creation time
1334
1335    // FIXME: SM keys (ENC and MAC) with Tags D1 and D2
1336
1337    /// Set KDF DO attributes
1338    pub fn set_kdf_do(&mut self, kdf_do: &KdfDo) -> Result<(), Error> {
1339        log::info!("OpenPgpTransaction: set_kdf_do");
1340
1341        let cmd = commands::put_data(Tags::KdfDo, kdf_do.serialize())?;
1342        self.send_command(cmd, false)?.try_into()
1343    }
1344
1345    // FIXME: certificate used with secure messaging
1346
1347    // FIXME: Attestation Certificate (Yubico)
1348
1349    // -----------------
1350
1351    /// Import an existing private key to the card.
1352    /// (This implicitly sets the algorithm attributes, fingerprint and timestamp)
1353    pub fn key_import(
1354        &mut self,
1355        key: Box<dyn CardUploadableKey>,
1356        key_type: KeyType,
1357    ) -> Result<(), Error> {
1358        keys::key_import(self, key, key_type)
1359    }
1360
1361    /// Generate a key on the card.
1362    /// (7.2.14 GENERATE ASYMMETRIC KEY PAIR)
1363    pub fn generate_key(
1364        &mut self,
1365        fp_from_pub: fn(
1366            &PublicKeyMaterial,
1367            KeyGenerationTime,
1368            KeyType,
1369        ) -> Result<Fingerprint, Error>,
1370        key_type: KeyType,
1371    ) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> {
1372        // get current (possibly updated) state of algorithm_attributes
1373        let ard = self.application_related_data()?; // no caching, here!
1374        let cur_algo = ard.algorithm_attributes(key_type)?;
1375
1376        keys::gen_key_set_metadata(self, fp_from_pub, &cur_algo, key_type)
1377    }
1378
1379    /// Get public key material from the card.
1380    ///
1381    /// Note: this fn returns a set of raw public key data (not an
1382    /// OpenPGP data structure).
1383    ///
1384    /// Note also that the information from the card is insufficient to
1385    /// reconstruct a pre-existing OpenPGP public key that corresponds to
1386    /// the private key on the card.
1387    pub fn public_key(&mut self, key_type: KeyType) -> Result<PublicKeyMaterial, Error> {
1388        keys::public_key(self, key_type)
1389    }
1390}
1391
1392fn digestinfo(hash: Hash) -> Result<Vec<u8>, Error> {
1393    match hash {
1394        Hash::SHA1(_) | Hash::SHA256(_) | Hash::SHA384(_) | Hash::SHA512(_) => {
1395            let tlv = Tlv::new(
1396                Tags::Sequence,
1397                Value::C(vec![
1398                    Tlv::new(
1399                        Tags::Sequence,
1400                        Value::C(vec![
1401                            Tlv::new(
1402                                Tags::ObjectIdentifier,
1403                                // unwrapping is ok, for SHA*
1404                                Value::S(hash.oid()?.to_vec()),
1405                            ),
1406                            Tlv::new(Tags::Null, Value::S(vec![])),
1407                        ]),
1408                    ),
1409                    Tlv::new(Tags::OctetString, Value::S(hash.digest().to_vec())),
1410                ]),
1411            );
1412
1413            Ok(tlv.serialize())
1414        }
1415        Hash::EdDSA(d) => Ok(d.to_vec()),
1416        Hash::ECDSA(d) => Ok(d.to_vec()),
1417    }
1418}
1419
1420/// OpenPGP card "Status Bytes" (ok statuses and errors)
1421#[derive(thiserror::Error, Debug, PartialEq, Eq, Copy, Clone)]
1422#[non_exhaustive]
1423pub enum StatusBytes {
1424    #[error("Command correct")]
1425    Ok,
1426
1427    #[error("Command correct, [{0}] bytes available in response")]
1428    OkBytesAvailable(u8),
1429
1430    #[error("Selected file or DO in termination state")]
1431    TerminationState,
1432
1433    #[error("Password not checked, {0} allowed retries")]
1434    PasswordNotChecked(u8),
1435
1436    #[error("Execution error with non-volatile memory unchanged")]
1437    ExecutionErrorNonVolatileMemoryUnchanged,
1438
1439    #[error("Triggering by the card {0}")]
1440    TriggeringByCard(u8),
1441
1442    #[error("Memory failure")]
1443    MemoryFailure,
1444
1445    #[error("Security-related issues (reserved for UIF in this application)")]
1446    SecurityRelatedIssues,
1447
1448    #[error("Wrong length (Lc and/or Le)")]
1449    WrongLength,
1450
1451    #[error("Logical channel not supported")]
1452    LogicalChannelNotSupported,
1453
1454    #[error("Secure messaging not supported")]
1455    SecureMessagingNotSupported,
1456
1457    #[error("Last command of the chain expected")]
1458    LastCommandOfChainExpected,
1459
1460    #[error("Command chaining not supported")]
1461    CommandChainingNotSupported,
1462
1463    #[error("Security status not satisfied")]
1464    SecurityStatusNotSatisfied,
1465
1466    #[error("Authentication method blocked")]
1467    AuthenticationMethodBlocked,
1468
1469    #[error("Condition of use not satisfied")]
1470    ConditionOfUseNotSatisfied,
1471
1472    #[error("Expected secure messaging DOs missing (e. g. SM-key)")]
1473    ExpectedSecureMessagingDOsMissing,
1474
1475    #[error("SM data objects incorrect (e. g. wrong TLV-structure in command data)")]
1476    SMDataObjectsIncorrect,
1477
1478    #[error("Incorrect parameters in the command data field")]
1479    IncorrectParametersCommandDataField,
1480
1481    #[error("File or application not found")]
1482    FileOrApplicationNotFound,
1483
1484    #[error("Referenced data, reference data or DO not found")]
1485    ReferencedDataNotFound,
1486
1487    #[error("Wrong parameters P1-P2")]
1488    WrongParametersP1P2,
1489
1490    #[error("Instruction code (INS) not supported or invalid")]
1491    INSNotSupported,
1492
1493    #[error("Class (CLA) not supported")]
1494    CLANotSupported,
1495
1496    #[error("No precise diagnosis")]
1497    NoPreciseDiagnosis,
1498
1499    #[error("Unknown OpenPGP card status: [{0:x}, {1:x}]")]
1500    UnknownStatus(u8, u8),
1501}
1502
1503impl From<(u8, u8)> for StatusBytes {
1504    fn from(status: (u8, u8)) -> Self {
1505        match (status.0, status.1) {
1506            (0x90, 0x00) => StatusBytes::Ok,
1507            (0x61, bytes) => StatusBytes::OkBytesAvailable(bytes),
1508
1509            (0x62, 0x85) => StatusBytes::TerminationState,
1510            (0x63, 0xC0..=0xCF) => StatusBytes::PasswordNotChecked(status.1 & 0xf),
1511            (0x64, 0x00) => StatusBytes::ExecutionErrorNonVolatileMemoryUnchanged,
1512            (0x64, 0x02..=0x80) => StatusBytes::TriggeringByCard(status.1),
1513            (0x65, 0x01) => StatusBytes::MemoryFailure,
1514            (0x66, 0x00) => StatusBytes::SecurityRelatedIssues,
1515            (0x67, 0x00) => StatusBytes::WrongLength,
1516            (0x68, 0x81) => StatusBytes::LogicalChannelNotSupported,
1517            (0x68, 0x82) => StatusBytes::SecureMessagingNotSupported,
1518            (0x68, 0x83) => StatusBytes::LastCommandOfChainExpected,
1519            (0x68, 0x84) => StatusBytes::CommandChainingNotSupported,
1520            (0x69, 0x82) => StatusBytes::SecurityStatusNotSatisfied,
1521            (0x69, 0x83) => StatusBytes::AuthenticationMethodBlocked,
1522            (0x69, 0x85) => StatusBytes::ConditionOfUseNotSatisfied,
1523            (0x69, 0x87) => StatusBytes::ExpectedSecureMessagingDOsMissing,
1524            (0x69, 0x88) => StatusBytes::SMDataObjectsIncorrect,
1525            (0x6A, 0x80) => StatusBytes::IncorrectParametersCommandDataField,
1526            (0x6A, 0x82) => StatusBytes::FileOrApplicationNotFound,
1527            (0x6A, 0x88) => StatusBytes::ReferencedDataNotFound,
1528            (0x6B, 0x00) => StatusBytes::WrongParametersP1P2,
1529            (0x6D, 0x00) => StatusBytes::INSNotSupported,
1530            (0x6E, 0x00) => StatusBytes::CLANotSupported,
1531            (0x6F, 0x00) => StatusBytes::NoPreciseDiagnosis,
1532            _ => StatusBytes::UnknownStatus(status.0, status.1),
1533        }
1534    }
1535}