sequoia_gpg_agent/
cardinfo.rs1use std::str::FromStr;
6
7use sequoia_openpgp as openpgp;
8use openpgp::Fingerprint;
9
10use sequoia_ipc as ipc;
11use ipc::Keygrip;
12
13use crate::Result;
14
15#[derive(thiserror::Error, Debug)]
17#[non_exhaustive]
18pub enum Error {
19 #[error("Error parsing card info data: {0}")]
20 ParseError(String),
21}
22
23#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct CardInfo {
28 raw: Vec<(String, String)>,
29}
30
31impl CardInfo {
32 pub fn raw(&self) -> impl Iterator<Item=&(String, String)> {
39 self.raw.iter()
40 }
41
42 pub fn keys<'a>(&'a self) -> impl Iterator<Item=Fingerprint> + 'a {
44 self.raw()
45 .filter_map(|(keyword, value)| {
46 if keyword == "KEY-FPR" {
47 if let Some(fpr) = value.split(" ").nth(1) {
48 return Fingerprint::from_str(fpr).ok();
49 }
50 }
51
52 None
53 })
54 }
55
56 pub fn keys_keygrips<'a>(&'a self) -> impl Iterator<Item=Keygrip> + 'a {
58 self.raw()
59 .filter_map(|(keyword, value)| {
60 if keyword == "KEYPAIRINFO" {
61 if let Some(fpr) = value.split(" ").nth(0) {
62 return Keygrip::from_str(fpr).ok();
63 }
64 }
65
66 None
67 })
68 }
69
70 pub(crate) fn parse(raw: Vec<(String, String)>) -> Result<Self> {
95 Ok(Self {
96 raw,
97 })
98 }
99}
100
101#[cfg(test)]
102mod test {
103 use super::*;
104
105 #[test]
106 fn parse_cardinfo() -> Result<()> {
107 let lines = &[
108 ("KDF", "�%01%00"),
109 ("SIG-COUNTER", "793"),
110 ("CHV-STATUS", "+1+127+127+127+3+0+3"),
111 ("KEY-TIME", "3 1428399828"),
112 ("KEY-TIME", "2 1428399800"),
113 ("KEY-TIME", "1 1428399766"),
114 ("KEY-FPR", "3 2DC50AB55BE2F3B04C2D2CF8A3506AFB820ABD08"),
115 ("KEY-FPR", "2 50E6D924308DBF223CFB510AC2B819056C652598"),
116 ("KEY-FPR", "1 C03FA6411B03AE12576461187223B56678E02528"),
117 ("DISP-SEX", "9"),
118 ("MANUFACTURER", "6 Yubico"),
119 ("EXTCAP", "gc=1+ki=1+fc=1+pd=1+mcl3=2048+aac=1+sm=0+si=5+dec=0+bt=1+kdf=1"),
120 ("APPTYPE", "openpgp"),
121 ("SERIALNO", "D2760001240103040006181329630000"),
122 ("READER", "1050:0407:X:0"),
123 ("KEYPAIRINFO", "9483454871CC1239D4C2A1416F2742D39A14DB14 OPENPGP.3"),
124 ("KEYPAIRINFO", "9873FD355DE470DDC151CD9919AC9785C3C2FDDE OPENPGP.2"),
125 ("KEYPAIRINFO", "BE2FE8C8793141322AC30E3EAFD1E4F9D8DACCC4 OPENPGP.1"),
126 ][..];
127
128 let info = CardInfo::parse(
129 lines.into_iter()
130 .map(|(k, m)| {
131 (k.to_string(), m.to_string())
132 })
133 .collect::<Vec<_>>())
134 .expect("valid");
135
136 let fprs = info.keys().collect::<Vec<Fingerprint>>();
137 assert_eq!(fprs.len(), 3);
138 assert_eq!(
139 fprs[0],
140 "2DC50AB55BE2F3B04C2D2CF8A3506AFB820ABD08".parse::<Fingerprint>().expect("ok"));
141 assert_eq!(
142 fprs[1],
143 "50E6D924308DBF223CFB510AC2B819056C652598".parse::<Fingerprint>().expect("ok"));
144 assert_eq!(
145 fprs[2],
146 "C03FA6411B03AE12576461187223B56678E02528".parse::<Fingerprint>().expect("ok"));
147
148 let keygrips = info.keys_keygrips().collect::<Vec<Keygrip>>();
149 assert_eq!(keygrips.len(), 3);
150 assert_eq!(
151 keygrips[0],
152 "9483454871CC1239D4C2A1416F2742D39A14DB14".parse::<Keygrip>().expect("ok"));
153 assert_eq!(
154 keygrips[1],
155 "9873FD355DE470DDC151CD9919AC9785C3C2FDDE".parse::<Keygrip>().expect("ok"));
156 assert_eq!(
157 keygrips[2],
158 "BE2FE8C8793141322AC30E3EAFD1E4F9D8DACCC4".parse::<Keygrip>().expect("ok"));
159
160 Ok(())
161 }
162}