sequoia_keystore_openpgp_card/
lib.rs

1use std::collections::HashMap;
2use std::collections::hash_map::Entry;
3use std::path::Path;
4use std::sync::Arc;
5use std::sync::Weak;
6use std::time::Duration;
7use std::time::SystemTime;
8
9use futures::lock::Mutex;
10
11use card_backend_pcsc;
12
13use openpgp_card::ocard::crypto::Cryptogram;
14use openpgp_card::ocard::data::KeyStatus;
15use openpgp_card::ocard::KeyType;
16use openpgp_card::ocard::Transaction;
17
18use sequoia_openpgp as openpgp;
19use openpgp::Cert;
20use openpgp::Fingerprint;
21use openpgp::Result;
22use openpgp::crypto::mem::Protected;
23use openpgp::crypto::ecdh;
24use openpgp::crypto::mpi;
25use openpgp::crypto::Password;
26use openpgp::crypto::SessionKey;
27use openpgp::packet;
28use openpgp::types::Curve;
29use openpgp::types::HashAlgorithm;
30use openpgp::types::PublicKeyAlgorithm;
31
32use sequoia_keystore_backend as backend;
33use backend::Error;
34use backend::ImportStatus;
35use backend::PasswordSource;
36use backend::Protection;
37use backend::utils::Directory;
38
39mod certd;
40
41// XXX: openpgp-card-sequoia is deprecated.  We've copied what we
42// need, but we should fork it.
43#[cfg(test)]
44mod privkey;
45
46#[derive(Clone)]
47pub struct Backend {
48    inner: Arc<Mutex<BackendInternal>>,
49}
50
51struct BackendInternal {
52    home: Directory,
53
54    // False if the backend is disabled.
55    enabled: bool,
56
57    // OpenPGP cards don't store the OpenPGP key data structures nor
58    // do they (always) have all the information required to
59    // reconstruct them (in particular, it's missing the ECC algorithm
60    // parameters).  Since looking up a key by subkey means doing a
61    // full scan, we cache the results.
62    certd: Arc<certd::CertD>,
63
64    // One device per OpenPGP card.
65    // XXX: Make this a HashMap keyed on the card id.
66    devices: Vec<Device>,
67
68    last_scan: Option<SystemTime>,
69}
70
71/// A Device exposes the (usable) keys managed by a particular
72/// OpenPGP Card.
73///
74/// A key is usable if we have the OpenPGP data structure.  If we
75/// don't have the OpenPGP key, we ignore the key.
76#[derive(Clone)]
77pub struct Device {
78    // "application identifier".
79    id: String,
80    inner: Arc<Mutex<DeviceInternal>>
81}
82
83impl Device {
84    /// Creates a new `WeakDevice` from this `Device`.
85    fn downgrade(&self) -> WeakDevice {
86        WeakDevice {
87            id: self.id.clone(),
88            inner: Arc::downgrade(&self.inner),
89        }
90    }
91}
92
93/// A `Device`, but with a weak reference to the data.
94///
95/// Before you use this, you need to upgrade this to a `Device`.
96#[derive(Clone)]
97pub struct WeakDevice {
98    id: String,
99    inner: Weak<Mutex<DeviceInternal>>,
100}
101
102impl WeakDevice {
103    /// Upgrades the `WeakDevice` to a `Device`, if possible.
104    fn upgrade(&self) -> Option<Device> {
105        Some(Device {
106            id: self.id.clone(),
107            inner: self.inner.upgrade()?,
108        })
109    }
110}
111
112struct DeviceInternal {
113    /// The "application identifier".
114    ///
115    /// This is of the form `FFFE:43233446`.  It identifies both a
116    /// card and the OpenPGP application.
117    id: String,
118
119    /// The opened card.
120    ///
121    /// The card is open in shared mode so that other applications can
122    /// use it.
123    card: openpgp_card::Card<openpgp_card::state::Open>,
124
125    /// Whether the card has a pinpad.
126    pinpad: bool,
127
128    /// A map from id (fingerprint) to key.
129    keys: HashMap<Fingerprint, Key>,
130}
131
132#[derive(Clone)]
133pub struct Key {
134    // The fingerprint is also the id.
135    fpr: Fingerprint,
136    inner: Arc<Mutex<KeyInternal>>,
137}
138
139/// A secret key.
140struct KeyInternal {
141    device: WeakDevice,
142
143    fingerprint: Fingerprint,
144    public_key: packet::Key<packet::key::PublicParts,
145                            packet::key::UnspecifiedRole>,
146
147    /// The cached password.
148    ///
149    /// OpenPGP cards can have up to three passwords: an admin
150    /// password, a user password, and an optional signing password.
151    /// The user password unlocks the decryption and authentication
152    /// slots.  If configured, the signing password unlocks the
153    /// signing slot.  Otherwise, the user password unlocks the
154    /// signing slot.
155    ///
156    /// We simplify things by having a per-slot password.  This means
157    /// that occasionally we'll ask for a password even though we know
158    /// it (e.g., we've cached the password for the decryption key,
159    /// and we're trying to use the authentication key), but that's
160    /// not a big deal.
161    password: Option<Password>,
162
163    /// The key's slot.
164    slot: openpgp_card::ocard::KeyType,
165}
166
167impl Backend {
168    /// Initializes an openpgp card backend.
169    ///
170    /// `home` is the directory where the backend will look for its
171    /// configuration, e.g., `$HOME/.sq/keystore/openpgp-card`.
172    ///
173    /// If `default` is true, this backend uses the cards managed by
174    /// PCSC.  Otherwise, the backend is disabled.
175    pub async fn init<P: AsRef<Path>>(home: P, default: bool)
176        -> Result<Self>
177    {
178        log::trace!("Backend::init");
179
180        let home = Directory::from(home.as_ref());
181
182        let certd = Arc::new(certd::CertD::new()?);
183
184        Ok(Backend {
185            inner: Arc::new(Mutex::new(BackendInternal {
186                home,
187                enabled: default,
188                certd,
189                devices: vec![],
190                last_scan: None,
191            }))
192        })
193    }
194
195    /// Initializes an ephemeral OpenPGP card backend.
196    ///
197    /// This is primarily useful for testing.
198    pub async fn init_ephemeral() -> Result<Self> {
199        log::trace!("Backend::init_ephemeral");
200
201        let home = Directory::ephemeral()?;
202        // XXX: default should be false, not true
203        Self::init(home, true).await
204    }
205}
206
207impl BackendInternal {
208    async fn scan_internal(&mut self, force: bool) -> Result<()> {
209        log::trace!("Backend::scan");
210
211        if ! self.enabled {
212            log::debug!("OpenPGP Card backend is disabled");
213            return Ok(());
214        }
215
216        if ! force {
217            // Don't scan too often.  Rate limit it to once every few seconds.
218            if let Some(last_scan) = self.last_scan {
219                if let Ok(duration) = SystemTime::now().duration_since(last_scan) {
220                    if duration < Duration::new(3, 0) {
221                        return Ok(())
222                    }
223                }
224            }
225        }
226
227        let certd = Arc::clone(&self.certd);
228
229        let card_backends = match card_backend_pcsc::PcscBackend::cards(None) {
230            Ok(card_backends) => card_backends.collect(),
231            Err(err) => {
232                log::debug!("Listing openpgp cards using PC/SC: {}", err);
233                Vec::new()
234            }
235        };
236
237        // XXX: Remove keys and devices that are not longer available.
238
239        for card_backend in card_backends.into_iter() {
240            let card_backend = match card_backend {
241                Ok(card_backend) => card_backend,
242                Err(err) => {
243                    log::debug!("Opening openpgp card backend: {}", err);
244                    continue;
245                }
246            };
247
248            let mut card = match openpgp_card::Card::new(card_backend) {
249                Ok(card) => card,
250                Err(err) => {
251                    log::debug!("Opening openpgp card: {}", err);
252                    continue;
253                }
254            };
255
256            let mut tx = match card.transaction() {
257                Ok(tx) => tx,
258                Err(err) => {
259                    log::debug!("Starting transaction on openpgp card: {}", err);
260                    continue;
261                }
262            };
263
264            // The device's identifier.
265            let id = match tx.application_identifier() {
266                Ok(id) => id,
267                Err(err) => {
268                    log::debug!("Getting application id from openpgp card: {}", err);
269                    continue;
270                }
271            };
272            let id = id.ident();
273
274            // Gather information about the keys.
275            let keyinfo = match tx.key_information() {
276                Ok(keyinfo) => keyinfo,
277                Err(err) => {
278                    log::debug!("Getting key information from openpgp card: {}", err);
279                    continue;
280                }
281            };
282
283            let present = if let Some(keyinfo) = keyinfo {
284                [
285                    keyinfo.sig_status() != KeyStatus::NotPresent,
286                    keyinfo.dec_status() != KeyStatus::NotPresent,
287                    keyinfo.aut_status() != KeyStatus::NotPresent
288                ]
289            } else {
290                [false, false, false]
291            };
292
293            let fprs = match tx.fingerprints() {
294                Ok(tx) => tx,
295                Err(err) => {
296                    log::debug!("Getting fingerprints from openpgp card: {}", err);
297                    continue;
298                }
299            };
300
301            let pinpad = tx.feature_pinpad_verify();
302
303            drop(tx);
304
305            // See if we already know about this device.
306            let mut device = None;
307            for d in self.devices.iter_mut() {
308                if d.id == id {
309                    device = Some(d);
310                }
311            }
312
313            let device = if let Some(device) = device {
314                // Already known.
315                device
316            } else {
317                // Create a new device.
318                let device = Device {
319                    id: id.clone(),
320                    inner: Arc::new(Mutex::new(DeviceInternal {
321                        id: id.clone(),
322                        keys: HashMap::new(),
323                        card: card,
324                        pinpad,
325                    })),
326                };
327
328                self.devices.push(device);
329
330                self.devices.last_mut().unwrap()
331            };
332
333            let mut device_internal = device.inner.lock().await;
334
335            let fprs = &[
336                (fprs.signature(), KeyType::Signing),
337                (fprs.decryption(), KeyType::Decryption),
338                (fprs.authentication(), KeyType::Authentication),
339            ][..];
340
341            for ((fpr, slot), present) in fprs.into_iter().zip(present.into_iter()) {
342                let Some(fpr) = fpr else { continue };
343                // Convert from an
344                // openpgp_card::ocard::data::Fingerprint to a
345                // sequoia_openpgp::Fingerprint.
346                let fpr = Fingerprint::from_bytes(4, fpr.as_bytes())?;
347                log::trace!("{}: {}present",
348                            fpr, if present { "" } else { "NOT " });
349
350                match device_internal.keys.entry(fpr.clone()) {
351                    Entry::Occupied(_oe) => {
352                        // Already have it.
353                    }
354                    Entry::Vacant(ve) => {
355                        // Need to add it.
356                        log::debug!("Found key {}", fpr);
357
358                        if let Some(pk) = certd.find_one(&fpr).await {
359                            let key = Key {
360                                fpr: fpr.clone(),
361                                inner: Arc::new(Mutex::new(KeyInternal {
362                                    device: device.downgrade(),
363                                    fingerprint: fpr,
364                                    // XXX
365                                    public_key: pk,
366                                    password: None,
367                                    slot: slot.clone(),
368                                })),
369                            };
370
371                            ve.insert(key);
372                        } else {
373                            log::debug!("Ignoring {}: no public key available",
374                                        fpr);
375                        }
376                    }
377                }
378            }
379        }
380
381        self.last_scan = Some(SystemTime::now());
382
383        Ok(())
384    }
385}
386
387#[async_trait::async_trait]
388impl backend::Backend for Backend {
389    fn id(&self) -> String {
390        "openpgp-card".into()
391    }
392
393    async fn scan(&mut self) -> Result<()> {
394        let mut backend = self.inner.lock().await;
395        backend.scan_internal(false).await
396    }
397
398    async fn list<'a>(&'a self)
399        -> Box<dyn Iterator<Item=Box<dyn backend::DeviceHandle + Send + Sync + 'a>>
400               + Send + Sync + 'a>
401    {
402        log::trace!("Backend::list");
403
404        let mut backend = self.inner.lock().await;
405
406        if let Err(err) = backend.scan_internal(false).await {
407            log::debug!("Scanning OpenPGP Cards: {}", err);
408        }
409
410        Box::new(
411            backend.devices.iter()
412                .map(|device| {
413                    Box::new(device.clone())
414                        as Box<dyn backend::DeviceHandle + Send + Sync>
415                })
416                .collect::<Vec<_>>()
417                .into_iter())
418    }
419
420    async fn find_device<'a>(&self, id: &str)
421        -> Result<Box<dyn backend::DeviceHandle + Send + Sync + 'a>>
422    {
423        log::trace!("Backend::find_device");
424
425        let mut backend = self.inner.lock().await;
426
427        // The first time through we look for the key without
428        // scanning.  If we don't find it, then we rescan.
429        for scan in [false, true] {
430            if scan {
431                log::trace!("Rescanning");
432                if let Err(err) = backend.scan_internal(true).await {
433                    log::debug!("Scanning OpenPGP Cards: {}", err);
434                }
435            }
436
437            for device in backend.devices.iter() {
438                if device.id == id {
439                    return Ok(Box::new(device.clone())
440                              as Box<dyn backend::DeviceHandle + Send + Sync>);
441                }
442            }
443        }
444
445        Err(Error::NotFound(id.into()).into())
446    }
447
448    async fn find_key<'a>(&self, id: &str)
449        -> Result<Box<dyn backend::KeyHandle + Send + Sync + 'a>>
450    {
451        log::trace!("Backend::find_key");
452
453        let mut backend = self.inner.lock().await;
454
455        // The first time through we look for the key without
456        // scanning.  If we don't find it, then we rescan.
457        for scan in [false, true] {
458            if scan {
459                log::trace!("Rescanning");
460                if let Err(err) = backend.scan_internal(true).await {
461                    log::debug!("Scanning OpenPGP Cards: {}", err);
462                }
463            }
464
465            for device in backend.devices.iter() {
466                let device = device.inner.lock().await;
467
468                for (key_id, key) in device.keys.iter() {
469                    if &key_id.to_string() == id {
470                        return Ok(Box::new(key.clone())
471                                  as Box<dyn backend::KeyHandle + Send + Sync>);
472                    }
473                }
474            }
475        }
476
477        Err(Error::NotFound(id.into()).into())
478    }
479
480    async fn import<'a>(&self, _cert: Cert)
481        -> Result<Vec<(ImportStatus,
482                       Box<dyn backend::KeyHandle + Send + Sync + 'a>)>>
483    {
484        log::trace!("Backend::import");
485
486        Err(Error::ExternalImportRequired(Some(
487            "To import a key into an OpenPGP Card, use something like: \
488             oct admin --card ABCD:01234567 import key.priv".into())).into())
489    }
490}
491
492#[async_trait::async_trait]
493impl backend::DeviceHandle for Device {
494    fn id(&self) -> String {
495        log::trace!("Device::id");
496
497        self.id.clone()
498    }
499
500    async fn available(&self) -> bool {
501        log::trace!("Device::available");
502
503        // XXX: Right now, we only support plugged-in cards.  Change
504        // this when we support registering OpenPGP cards.
505        true
506    }
507
508    async fn configured(&self) -> bool {
509        log::trace!("Device::configured");
510
511        // XXX: Right now, we only support plugged-in cards.  Change
512        // this when we support registering OpenPGP cards.
513        true
514    }
515
516    async fn registered(&self) -> bool {
517        log::trace!("Device::registered");
518
519
520        // XXX: Right now, we only support plugged-in cards.  Change
521        // this when we support registering OpenPGP cards.
522        true
523    }
524
525    async fn lock(&mut self) -> Result<()> {
526        log::trace!("Device::lock");
527
528        // We manage passwords at the slot level.
529        let device = self.inner.lock().await;
530        for key in device.keys.values() {
531            let mut key_internal = key.inner.lock().await;
532            key_internal.password = None;
533        }
534
535        Ok(())
536    }
537
538    async fn list<'a>(&'a self)
539        -> Box<dyn Iterator<Item=Box<dyn backend::KeyHandle + Send + Sync + 'a>>
540               + Send + Sync + 'a>
541    {
542        log::trace!("Device::list");
543
544        let device = self.inner.lock().await;
545        let keys = device.keys.values()
546            .map(|key| {
547                Box::new(key.clone())
548                    as Box<dyn backend::KeyHandle + Send + Sync>
549            })
550            .collect::<Vec<_>>();
551
552        Box::new(keys.into_iter())
553    }
554}
555
556#[async_trait::async_trait]
557impl backend::KeyHandle for Key {
558    fn id(&self) -> String {
559        log::trace!("Key::id");
560
561        self.fpr.to_string()
562    }
563
564    fn fingerprint(&self) -> Fingerprint {
565        log::trace!("Key::fingerprint");
566
567        self.fpr.clone()
568    }
569
570    async fn device<'a>(&self)
571        -> Box<dyn backend::DeviceHandle + Send + Sync + 'a>
572    {
573        log::trace!("Key::device");
574
575        let key_internal = self.inner.lock().await;
576
577        // Get the device that the key is on.
578        let device = match key_internal.device.upgrade() {
579            Some(device) => device,
580            None => panic!("Device disappeared"),
581        };
582
583        Box::new(device)
584    }
585
586    /// Returns whether the key is available.
587    ///
588    /// A key managed by an OpenPGP card is considered to *not* be
589    /// available if:
590    ///
591    /// - It is not present
592    /// - The smartcard is not inserted.
593    async fn available(&self) -> bool {
594        log::trace!("Key::available");
595
596        // XXX: Right now, we only support plugged-in cards.  Change
597        // this when we support registering OpenPGP cards.
598        true
599    }
600
601    async fn locked(&self) -> Protection {
602        log::trace!("Key::locked");
603
604        // We pessimistically consider a slot to be locked if we
605        // haven't cached a password for the slot.  On some cards, we
606        // could use [`Card::check_user_verified`], but on other cards
607        // that increase the pin's error count, which is a bit of a
608        // disaster.
609        //
610        // [`Card::check_user_verified`]: https://docs.rs/openpgp-card/latest/openpgp_card/struct.Card.html#method.check_user_verified
611
612        // Due to the locking order requirements, in order to get the
613        // device, we have to drop the lock on the key.  We copy what
614        // we need from the key, and then get the device.
615        let key_internal = self.inner.lock().await;
616        let slot = key_internal.slot;
617
618        let slot_str = || {
619            match slot {
620                KeyType::Signing => "signing".to_string(),
621                KeyType::Decryption => "decryption".to_string(),
622                KeyType::Authentication => "authentication".to_string(),
623                s => format!("{:?}", s),
624            }
625        };
626
627        if key_internal.password.is_some() {
628            return Protection::Unlocked;
629        }
630
631        // Get the device that the key is on.
632        let device = match key_internal.device.upgrade() {
633            Some(device) => device,
634            None => {
635                return Protection::ExternalOther(
636                    Some("Card disappeared".into()));
637            }
638        };
639        // Now we drop the lock on key and take the lock on device.
640        drop(key_internal);
641        let mut device_internal = device.inner.lock().await;
642
643        if device_internal.pinpad {
644            return Protection::ExternalPassword(None);
645        }
646
647        let mut tx = match device_internal.card.transaction() {
648            Ok(tx) => tx,
649            Err(err) => {
650                log::debug!("Starting transaction on openpgp card: {}", err);
651                return Protection::ExternalOther(Some(
652                    "Communication with card failed".into()));
653            }
654        };
655
656        match tx.user_interaction_flag(slot) {
657            Ok(uif) => {
658                if let Some(uif) = uif {
659                    if uif.touch_policy().touch_required() {
660                        // If user interaction is required, the user
661                        // needs to enter the password *first*, and
662                        // *then* interact with the device.  There
663                        // *are* cases where just a touch is required,
664                        // but according to "We pessimistically
665                        // consider a slot to be locked if we haven't
666                        // cached a password for the slot", this is
667                        // not the case here: we need a password and
668                        // *then* an interaction, so we return
669                        // Password with a hint.
670                        return Protection::Password(Some(
671                            format!("Enter PIN and touch the OpenPGP card \
672                                     to unlock the {} key", slot_str())))
673                    }
674                }
675            }
676            Err(err) => {
677                log::debug!("Getting user interaction flags: {}", err);
678            }
679        }
680
681        Protection::Password(Some(
682            format!("Enter PIN to unlock the {} key", slot_str())))
683    }
684
685    async fn password_source(&self) -> PasswordSource {
686        log::trace!("Key::password_source");
687
688        // Due to the locking order requirements, in order to get the
689        // device, we have to drop the lock on the key.
690        let key_internal = self.inner.lock().await;
691
692        // Get the device that the key is on.
693        let device = match key_internal.device.upgrade() {
694            Some(device) => device,
695            None => {
696                // We don't have a way to return an error.
697                return PasswordSource::ExternalSideEffect;
698            }
699        };
700        // Now we drop the lock on key and take the lock on device.
701        drop(key_internal);
702        let mut device_internal = device.inner.lock().await;
703        // Retake the key lock.
704        let key_internal = self.inner.lock().await;
705
706        if device_internal.pinpad {
707            // XXX: Is ExternalOnDemand more accurate?
708            return PasswordSource::ExternalSideEffect;
709        }
710
711        let mut tx = match device_internal.card.transaction() {
712            Ok(tx) => tx,
713            Err(err) => {
714                log::debug!("Starting transaction on openpgp card: {}", err);
715                // We don't have a way to return an error.
716                return PasswordSource::ExternalSideEffect;
717            }
718        };
719
720        match tx.user_interaction_flag(key_internal.slot) {
721            Ok(uif) => {
722                if let Some(uif) = uif {
723                    if uif.touch_policy().touch_required() {
724                        return PasswordSource::InlineWithConfirmation;
725                    }
726                }
727            }
728            Err(err) => {
729                log::debug!("Getting user interaction flags: {}", err);
730            }
731        }
732
733        PasswordSource::Inline
734    }
735
736    async fn decryption_capable(&self) -> bool {
737        log::trace!("Key::decryption_capable");
738
739        let key_internal = self.inner.lock().await;
740        match key_internal.slot {
741            KeyType::Signing => false,
742            KeyType::Decryption => true,
743            KeyType::Authentication => false,
744            _ => false,
745        }
746    }
747
748    async fn signing_capable(&self) -> bool {
749        log::trace!("Key::signing_capable");
750
751        let key_internal = self.inner.lock().await;
752        match key_internal.slot {
753            KeyType::Signing => true,
754            KeyType::Decryption => false,
755            KeyType::Authentication => true,
756            _ => false,
757        }
758    }
759
760    async fn unlock(&mut self, password: Option<&Password>) -> Result<()> {
761        log::trace!("Key::unlock");
762
763        // Due to the locking order requirements, in order to get the
764        // device, we have to drop the lock on the key.
765        let key_internal = self.inner.lock().await;
766
767        if key_internal.password.is_some() {
768            return Err(Error::AlreadyUnlocked(
769                "Key is already unlocked".into()).into());
770        }
771
772        // Get the device that the key is on.
773        let device = match key_internal.device.upgrade() {
774            Some(device) => device,
775            None => {
776                return Err(anyhow::anyhow!("Card disappeared"));
777            }
778        };
779        // Now we drop the lock on key and take the lock on device.
780        drop(key_internal);
781        let mut device_internal = device.inner.lock().await;
782        // Retake the key lock.
783        let mut key_internal = self.inner.lock().await;
784
785        // Prompt the user for the password.
786
787        let pinpad = device_internal.pinpad;
788
789        let mut tx = match device_internal.card.transaction() {
790            Ok(tx) => tx,
791            Err(err) => {
792                log::debug!("Starting transaction on openpgp card: {}", err);
793                // XXX: Turn it into a real error.
794                return Err(err.into());
795            }
796        };
797
798        if let Some(password) = password {
799            // The user supplied a password.
800
801            if pinpad {
802                // We can't use the password: we need to use the pin
803                // pad.
804                return Err(Error::NoInlinePassword(None).into());
805            }
806
807            let p = password.map(|p| String::from_utf8(p.to_vec()))?;
808
809            if key_internal.slot == KeyType::Signing {
810                tx.verify_user_signing_pin(p.into())?;
811            } else {
812                tx.verify_user_pin(p.into())?;
813            }
814            key_internal.password = Some(password.clone());
815        } else {
816            // The user didn't supply a password.  This means we are
817            // supposed to unlock the slot using the pin pad.
818
819            if ! pinpad {
820                return Err(Error::NoExternalPassword(
821                    Some("Cannot prompt user for password".into())).into());
822            }
823
824            fn cb() {}
825            if key_internal.slot == KeyType::Signing {
826                tx.verify_user_signing_pinpad(&cb)?;
827            } else {
828                tx.verify_user_pinpad(&cb)?;
829            }
830        }
831
832        Ok(())
833    }
834
835    async fn lock(&mut self) -> Result<()> {
836        log::trace!("Key::lock");
837
838        let mut key_internal = self.inner.lock().await;
839
840        key_internal.password = None;
841
842        // XXX: We should also lock the slot.  Currently the
843        // openpgp-card library doesn't (appear to) support that.
844
845        Ok(())
846    }
847
848    async fn public_key(&self)
849        -> packet::Key<packet::key::PublicParts,
850                       packet::key::UnspecifiedRole>
851    {
852        log::trace!("Key::public_key");
853
854        let key = self.inner.lock().await;
855        key.public_key.clone()
856    }
857
858    // XXX: Use plaintext_len.
859    async fn decrypt_ciphertext(&mut self,
860                                ciphertext: &mpi::Ciphertext,
861                                _plaintext_len: Option<usize>)
862        -> Result<SessionKey>
863    {
864        log::trace!("Key::decrypt_ciphertext");
865
866        // Due to the locking order requirements, in order to get the
867        // device, we have to drop the lock on the key.  We copy what
868        // we need from the key, and then get the device.
869        let key_internal = self.inner.lock().await;
870
871        // Copy what we need.
872        let public_key = key_internal.public_key.clone();
873        let password = key_internal.password.clone();
874
875        // Get the device that the key is on.
876        let device = match key_internal.device.upgrade() {
877            Some(device) => device,
878            None => {
879                return Err(anyhow::anyhow!("Card disappeared"));
880            }
881        };
882        // Now we drop the lock on key and take the lock on device.
883        drop(key_internal);
884        let mut device_internal = device.inner.lock().await;
885
886        let mut tx = match device_internal.card.transaction() {
887            Ok(tx) => tx,
888            Err(err) => {
889                log::debug!("Starting transaction on openpgp card: {}", err);
890                // XXX: Turn it into a real error.
891                return Err(err.into());
892            }
893        };
894
895        // The rest of this function is derived from
896        // openpgp-card-sequoia's [CardDecryptor::decrypt].
897        //
898        // [CardDecryptor::decrypt]: https://gitlab.com/openpgp-card/openpgp-card/-/blob/fa3e2e5c/openpgp-card-sequoia/src/decryptor.rs
899        //
900        // The file has the following copyright notice:
901        //
902        // SPDX-FileCopyrightText: 2021-2022 Heiko Schaefer <heiko@schaefer.name>
903        // SPDX-License-Identifier: MIT OR Apache-2.0
904
905        let unlock = || -> Result<()> {
906            if let Some(password) = password {
907                let password = password.map(|p| String::from_utf8(p.to_vec()))?;
908                tx.verify_user_pin(password.into())?;
909            }
910
911            Ok(())
912        };
913
914        // Delegate a decryption operation to the OpenPGP card.
915        //
916        // This fn prepares the data structures that openpgp-card needs to
917        // perform the decryption operation.
918        //
919        // (7.2.11 PSO: DECIPHER)
920        match (ciphertext, public_key.mpis()) {
921            (mpi::Ciphertext::RSA { c: ct }, mpi::PublicKey::RSA { .. }) => {
922                let dm = Cryptogram::RSA(ct.value());
923
924                unlock()?;
925                let dec = tx.card().decipher(dm)?;
926
927                let sk = SessionKey::from(&dec[..]);
928                Ok(sk)
929            }
930            (mpi::Ciphertext::ECDH { ref e, .. }, mpi::PublicKey::ECDH { ref curve, .. }) => {
931                let dm = if curve == &Curve::Cv25519 {
932                    assert_eq!(
933                        e.value()[0],
934                        0x40,
935                        "Unexpected shape of decrypted Cv25519 data"
936                    );
937
938                    // Ephemeral key without header byte 0x40
939                    Cryptogram::ECDH(&e.value()[1..])
940                } else {
941                    // NIST curves: ephemeral key with header byte
942                    Cryptogram::ECDH(e.value())
943                };
944
945                // Decryption operation on the card
946                unlock()?;
947                let mut dec = tx.card().decipher(dm)?;
948
949                // Specifically handle return value format like Gnuk's
950                // (Gnuk returns a leading '0x04' byte and
951                // an additional 32 trailing bytes)
952                if curve == &Curve::NistP256 && dec.len() == 65 {
953                    assert_eq!(dec[0], 0x04, "Unexpected shape of decrypted NistP256 data");
954
955                    // see Gnuk src/call-ec.c:82
956                    dec = dec[1..33].to_vec();
957                }
958
959                #[allow(non_snake_case)]
960                let S: Protected = dec.into();
961
962                Ok(ecdh::decrypt_unwrap(&public_key, &S, ciphertext, None /* XXX */)?)
963            }
964
965            (ciphertext, public) => Err(anyhow::anyhow!(
966                "Unsupported combination of ciphertext {:?} \
967                 and public key {:?} ",
968                ciphertext,
969                public
970            )),
971        }
972    }
973
974    async fn sign(&mut self, hash_algo: HashAlgorithm, digest: &[u8])
975        -> Result<(PublicKeyAlgorithm, mpi::Signature)>
976    {
977        log::trace!("Key::sign");
978
979        // Due to the locking order requirements, in order to get the
980        // device, we have to drop the lock on the key.  We copy what
981        // we need from the key, and then get the device.
982        let key_internal = self.inner.lock().await;
983
984        // Copy what we need.
985        let public_key = key_internal.public_key.clone();
986        let password = key_internal.password.clone();
987        let slot = key_internal.slot;
988
989        // Get the device that the key is on.
990        let device = match key_internal.device.upgrade() {
991            Some(device) => device,
992            None => {
993                return Err(anyhow::anyhow!("Card disappeared"));
994            }
995        };
996        // Now we drop the lock on key and take the lock on device.
997        drop(key_internal);
998        let mut device_internal = device.inner.lock().await;
999
1000        let mut tx = match device_internal.card.transaction() {
1001            Ok(tx) => tx,
1002            Err(err) => {
1003                log::debug!("Starting transaction on openpgp card: {}", err);
1004                // XXX: Turn it into a real error.
1005                return Err(err.into());
1006            }
1007        };
1008
1009        let unlock = || -> Result<()> {
1010            if let Some(password) = password {
1011                log::trace!("Unlocking key with password");
1012                let password = password.map(|p| String::from_utf8(p.to_vec()))?;
1013                tx.verify_user_signing_pin(password.into())?;
1014                log::trace!("Successfully unlocked slot");
1015            } else {
1016                log::debug!("Not unlocking slot; no password cached");
1017            }
1018
1019            Ok(())
1020        };
1021
1022        // The rest of this function is derived from
1023        // openpgp-card-sequoia's [CardSigner::sign].
1024        //
1025        // [CardDecryptor::decrypt]: https://gitlab.com/openpgp-card/openpgp-card/-/blob/fa3e2e5c/openpgp-card-sequoia/src/signer.rs
1026        //
1027        // The file has the following copyright notice:
1028        //
1029        // SPDX-FileCopyrightText: 2021-2022 Heiko Schaefer <heiko@schaefer.name>
1030        // SPDX-License-Identifier: MIT OR Apache-2.0
1031
1032        let sig_fn = if slot == KeyType::Signing {
1033            Transaction::signature_for_hash
1034        } else {
1035            Transaction::authenticate_for_hash
1036        };
1037        // Delegate a signing (or auth) operation to the OpenPGP card.
1038        //
1039        // This fn prepares the data structures that openpgp-card needs to
1040        // perform the signing operation.
1041        //
1042        // (7.2.10 PSO: COMPUTE DIGITAL SIGNATURE)
1043        // or (7.2.13 INTERNAL AUTHENTICATE)
1044        use openpgp_card::ocard::crypto::Hash;
1045        let sig = match (public_key.pk_algo(), public_key.mpis()) {
1046            #[allow(deprecated)]
1047            (PublicKeyAlgorithm::RSASign, mpi::PublicKey::RSA { .. })
1048            | (PublicKeyAlgorithm::RSAEncryptSign, mpi::PublicKey::RSA { .. }) => {
1049                let hash = match hash_algo {
1050                    sequoia_openpgp::types::HashAlgorithm::SHA256 => Hash::SHA256(
1051                        digest
1052                            .try_into()
1053                            .map_err(|_| anyhow::anyhow!("invalid slice length"))?,
1054                    ),
1055                    sequoia_openpgp::types::HashAlgorithm::SHA384 => Hash::SHA384(
1056                        digest
1057                            .try_into()
1058                            .map_err(|_| anyhow::anyhow!("invalid slice length"))?,
1059                    ),
1060                    sequoia_openpgp::types::HashAlgorithm::SHA512 => Hash::SHA512(
1061                        digest
1062                            .try_into()
1063                            .map_err(|_| anyhow::anyhow!("invalid slice length"))?,
1064                    ),
1065                    _ => {
1066                        return Err(anyhow::anyhow!(
1067                            "Unsupported hash algorithm for RSA {:?}",
1068                            hash_algo
1069                        ));
1070                    }
1071                };
1072                unlock()?;
1073                let sig = sig_fn(tx.card(), hash)?;
1074                let mpi = mpi::MPI::new(&sig[..]);
1075                mpi::Signature::RSA { s: mpi }
1076            }
1077            (PublicKeyAlgorithm::EdDSA, mpi::PublicKey::EdDSA { .. }) => {
1078                let hash = Hash::EdDSA(digest);
1079                unlock()?;
1080                let sig = sig_fn(tx.card(), hash)?;
1081                let r = mpi::MPI::new(&sig[..32]);
1082                let s = mpi::MPI::new(&sig[32..]);
1083                mpi::Signature::EdDSA { r, s }
1084            }
1085            (PublicKeyAlgorithm::ECDSA, mpi::PublicKey::ECDSA { curve, .. }) => {
1086                let hash = match curve {
1087                    Curve::NistP256 => Hash::ECDSA(&digest[..32]),
1088                    Curve::NistP384 => Hash::ECDSA(&digest[..48]),
1089                    Curve::NistP521 => Hash::ECDSA(&digest[..64]),
1090                    _ => Hash::ECDSA(digest),
1091                };
1092                unlock()?;
1093                let sig = sig_fn(tx.card(), hash)?;
1094                let len_2 = sig.len() / 2;
1095                let r = mpi::MPI::new(&sig[..len_2]);
1096                let s = mpi::MPI::new(&sig[len_2..]);
1097                mpi::Signature::ECDSA { r, s }
1098            }
1099            // FIXME: implement NIST etc
1100            (pk_algo, _) => return Err(anyhow::anyhow!(
1101                "Unsupported combination of algorithm {:?} and pubkey {:?}",
1102                pk_algo,
1103                public_key
1104            )),
1105        };
1106
1107        log::trace!("Returned a {} signature", public_key.pk_algo());
1108        Ok((public_key.pk_algo(), sig))
1109    }
1110
1111    async fn export(&mut self)
1112        -> Result<openpgp::packet::Key<
1113            openpgp::packet::key::SecretParts,
1114            openpgp::packet::key::UnspecifiedRole>>
1115    {
1116        Err(Error::OperationNotSupported(
1117            "Keys cannot be exported from OpenPGP cards.".into()).into())
1118    }
1119
1120    async fn change_password(&mut self, password: Option<&Password>)
1121        -> Result<()>
1122    {
1123        log::trace!("KeyHandle::change_password({}, {})",
1124                    self.fingerprint(),
1125                    if let Some(password) = password {
1126                        if password.map(|p| p.is_empty()) {
1127                            "clear password"
1128                        } else {
1129                            "set password"
1130                        }
1131                    } else {
1132                        "ask for password"
1133                    });
1134
1135        Err(Error::OperationNotSupported(
1136            "Use an external tool to manage OpenPGP cards.".into()).into())
1137    }
1138
1139    async fn delete_secret_key_material(&mut self)
1140        -> Result<()>
1141    {
1142        log::trace!("KeyHandle::delete_secret_key_material");
1143
1144        Err(Error::OperationNotSupported(
1145            "Use an external tool to manage OpenPGP cards.".into()).into())
1146    }
1147}
1148
1149#[cfg(test)]
1150mod tests {
1151    use super::*;
1152
1153    use openpgp::KeyHandle;
1154    use openpgp::cert::amalgamation::key::ValidKeyAmalgamation;
1155    use openpgp::parse::Parse;
1156    use openpgp::policy::StandardPolicy;
1157    use openpgp::serialize::Serialize;
1158
1159    const P: &StandardPolicy = &StandardPolicy::new();
1160
1161    use backend::test_framework;
1162
1163    use backend::Backend as _;
1164
1165    /// This is the ID and PINs for the opcard-rs virtual smart card.
1166    const TEST_CARD_ID: &str = "0000:00000000";
1167    const TEST_CARD_ADMIN_PIN: &str = "12345678";
1168    const TEST_CARD_USER_PIN: &str = "123456";
1169
1170    fn get_test_card() -> Option<openpgp_card::Card<openpgp_card::state::Open>>
1171    {
1172        let card_backends = match card_backend_pcsc::PcscBackend::cards(None) {
1173            Ok(card_backends) => card_backends.collect(),
1174            Err(err) => {
1175                log::debug!("Listing openpgp cards using PC/SC: {}", err);
1176                Vec::new()
1177            }
1178        };
1179
1180        let mut test_card = None;
1181        for card_backend in card_backends.into_iter() {
1182            let card_backend = match card_backend {
1183                Ok(card_backend) => card_backend,
1184                Err(err) => {
1185                    log::debug!("Opening openpgp card backend: {}", err);
1186                    continue;
1187                }
1188            };
1189
1190            let mut card = match openpgp_card::Card::new(card_backend) {
1191                Ok(card) => card,
1192                Err(err) => {
1193                    log::debug!("Opening openpgp card: {}", err);
1194                    continue;
1195                }
1196            };
1197
1198            let tx = match card.transaction() {
1199                Ok(tx) => tx,
1200                Err(err) => {
1201                    log::debug!("Starting transaction on openpgp card: {}", err);
1202                    continue;
1203                }
1204            };
1205
1206            let id = match tx.application_identifier() {
1207                Ok(id) => id,
1208                Err(err) => {
1209                    log::debug!("Getting application id from openpgp card: {}", err);
1210                    continue;
1211                }
1212            };
1213            let id = id.ident();
1214
1215            if id == TEST_CARD_ID {
1216                drop(tx);
1217                test_card = Some(card);
1218                break;
1219            } else {
1220                eprintln!("Found card {}", id);
1221            }
1222        }
1223
1224        test_card
1225    }
1226
1227    fn preinit() -> bool {
1228        // Don't run the tests if the test card is not available.
1229        get_test_card().is_some()
1230    }
1231
1232    async fn init_backend() -> Backend {
1233        let backend = Backend::init_ephemeral().await.expect("can init backend");
1234
1235        let mut card = if let Some(card) = get_test_card() {
1236            card
1237        } else {
1238            panic!("Test card ({}) not available", TEST_CARD_ID);
1239        };
1240
1241        // Reset the card so that it is empty.
1242        let mut tx = card.transaction().expect("can start a transaction");
1243        tx.factory_reset().expect("can factory reset");
1244
1245        backend
1246    }
1247
1248    async fn import_cert(backend: &mut Backend, cert: &Cert) {
1249        let vc = cert.with_policy(P, None).expect("valid cert");
1250
1251        eprintln!("Importing cert {}'s subkeys", cert.fingerprint());
1252        for ka in vc.keys().subkeys() {
1253            eprintln!("  - {}, secret: {}, key flags: {:?}",
1254                      ka.key().fingerprint(), ka.key().has_secret(), ka.key_flags());
1255        }
1256
1257        let signing_key
1258            = vc.keys().subkeys().for_signing().secret().next();
1259        let auth_key
1260            = vc.keys().subkeys().for_authentication().secret().next();
1261        let encryption_key
1262            = vc.keys().subkeys().for_transport_encryption().secret().next();
1263
1264        assert!(signing_key.is_some()
1265                || auth_key.is_some()
1266                || encryption_key.is_some(),
1267                "Expect at least one subkey with secret key material");
1268
1269        let mut card = if let Some(card) = get_test_card() {
1270            card
1271        } else {
1272            panic!("Test card ({}) not available", TEST_CARD_ID);
1273        };
1274
1275        let mut tx = card.transaction().expect("can start a transaction");
1276
1277        tx.verify_admin_pin(TEST_CARD_ADMIN_PIN.to_string().into())
1278            .expect("can use admin pin");
1279
1280        let mut admin = tx.to_admin_card(None)
1281            .expect("can access admin functionality");
1282
1283        // Import the keys.
1284        let mut import_key = |key: Option<ValidKeyAmalgamation<_, _, ()>>, slot: KeyType| {
1285            if let Some(key) = key {
1286                eprintln!("Importing key {} to {:?} slot",
1287                          key.key().fingerprint(), slot);
1288
1289                assert!(key.key().has_unencrypted_secret());
1290                let key = Box::new(privkey::SequoiaKey::new(key.into(), None));
1291                //let key = openpgp_card_sequoia::util::vka_as_uploadable_key(
1292                //    key.into(), None);
1293                admin.import_key(key, slot)
1294                    .expect("can import key");
1295            } else {
1296                eprintln!("No {:?} key to import", slot);
1297            }
1298        };
1299
1300        import_key(signing_key, KeyType::Signing);
1301        import_key(auth_key, KeyType::Authentication);
1302        import_key(encryption_key, KeyType::Decryption);
1303
1304        // And insert the certificate into our local certd so that we
1305        // can find the OpenPGP keys.
1306        backend.inner.lock().await.certd.certd().insert(
1307            &cert.fingerprint().to_string(),
1308            (), false,
1309            |(), disk| {
1310                let cert_;
1311                let cert = if let Some(disk) = disk {
1312                    // Merge.
1313                    let disk = Cert::from_bytes(disk).expect("valid cert");
1314                    cert_ = cert.clone().merge_public(disk).expect("can merge");
1315                    &cert_
1316                } else {
1317                    // New.
1318                    cert
1319                };
1320
1321                let mut bytes = Vec::new();
1322                cert.serialize(&mut bytes).expect("can serialize to a vec");
1323                Ok(bytes.into())
1324            })
1325            .expect("inserted");
1326    }
1327
1328    sequoia_keystore_backend::generate_tests!(
1329        preinit,
1330        true, // Serialize tests.
1331        Backend, init_backend,
1332        import_cert,
1333        false, // Can import encrypted secret key material.
1334        Some(1), // Supported key sets.
1335        Some(TEST_CARD_USER_PIN), // Default password.
1336        false, // Can export.
1337        false, // Can change password.
1338        false // Can delete secret key material.
1339    );
1340}