Skip to main content

openpgp_card/ocard/
mod.rs

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