1use std::sync::{Arc, Mutex};
30
31use anyhow::Result;
32use cryptoki::context::Pkcs11;
33use cryptoki::error::RvError;
34use cryptoki::object::{Attribute, ObjectClass, ObjectHandle};
35use cryptoki::session::{Session, UserType};
36use cryptoki::slot::Slot;
37use openpgp_x509_sequoia::types::PgpKeyType;
38use sequoia_openpgp::packet::key::{PublicParts, SecretParts, UnspecifiedRole};
39use sequoia_openpgp::packet::Key;
40use sequoia_openpgp::parse::stream::DecryptorBuilder;
41use sequoia_openpgp::parse::Parse;
42use sequoia_openpgp::policy::NullPolicy;
43use sequoia_openpgp::types::Timestamp;
44use sequoia_openpgp::{Cert, Fingerprint};
45
46pub(crate) mod decryptor;
47pub(crate) mod signer;
48mod upload;
49mod util;
50
51pub struct Op11 {
53 pkcs11: Pkcs11,
54}
55
56impl Op11 {
57 pub fn open(module: &str) -> Result<Self> {
59 let mut pkcs11 = Pkcs11::new(module)?;
60
61 let res = pkcs11.initialize(cryptoki::context::CInitializeArgs::OsThreads);
62 match res {
63 Err(cryptoki::error::Error::Pkcs11(RvError::CryptokiAlreadyInitialized)) => {
64 }
73 Err(e) => return Err(e.into()),
74 Ok(()) => {}
75 }
76
77 Ok(Op11 { pkcs11 })
78 }
79
80 pub fn slot(&mut self, serial_number: &str) -> Result<Op11Slot> {
82 for slot in self.pkcs11.get_all_slots()? {
83 if let Ok(ti) = self.pkcs11.get_token_info(slot) {
84 if serial_number == ti.serial_number() {
85 log::debug!("token info: {:#?}", ti);
86
87 return Ok(Op11Slot {
88 slot,
89 pkcs11: &self.pkcs11,
90 });
91 }
92 }
93 }
94
95 Err(anyhow::anyhow!("No slot found for '{serial_number}'"))
96 }
97
98 pub fn slots(&mut self) -> Result<Vec<Op11Slot>> {
100 Ok(self
101 .pkcs11
102 .get_slots_with_initialized_token()?
103 .into_iter()
104 .map(|slot| Op11Slot {
105 slot,
106 pkcs11: &self.pkcs11,
107 })
108 .collect())
109 }
110
111 pub fn pkcs11(&self) -> &Pkcs11 {
113 &self.pkcs11
114 }
115}
116
117pub struct Op11Slot<'a> {
119 slot: Slot,
120 pkcs11: &'a Pkcs11,
121}
122
123impl Op11Slot<'_> {
124 pub fn open_rw_session(self) -> Result<Op11Session> {
125 let session = self.pkcs11.open_rw_session(self.slot)?;
126 Ok(Op11Session { session })
127 }
128
129 pub fn open_ro_session(self) -> Result<Op11Session> {
130 let session = self.pkcs11.open_ro_session(self.slot)?;
131 Ok(Op11Session { session })
132 }
133
134 pub fn serial(&self) -> Result<String> {
135 if let Ok(ti) = self.pkcs11.get_token_info(self.slot) {
136 return Ok(ti.serial_number().to_string());
137 }
138
139 Err(anyhow::anyhow!("Couldn't get serial number"))
140 }
141}
142
143pub struct Op11Session {
145 session: Session,
146}
147
148impl Op11Session {
149 pub fn login(&self, pin: &str) -> Result<()> {
151 self.session.login(UserType::User, Some(pin))?;
152 Ok(())
153 }
154
155 pub fn login_so(&self, pin: &str) -> Result<()> {
157 self.session.login(UserType::So, Some(pin))?;
158 Ok(())
159 }
160
161 pub fn logout(&self) -> Result<()> {
163 self.session.logout()?;
164 Ok(())
165 }
166
167 pub fn key(
171 &self,
172 id: &[u8],
173 pkt: PgpKeyType,
174 cert: Option<Cert>,
175 ) -> Result<Key<PublicParts, UnspecifiedRole>> {
176 let x509cert = util::x509_cert(&self.session, id)?;
177
178 if let Some(c) = cert {
180 return openpgp_x509_sequoia::find_key_by_x509cert(&x509cert, &c);
181 }
182
183 let x509_cert = x509_certificate::rfc5280::Certificate::from(x509cert.clone());
184
185 let x509_creation_time = if let x509_certificate::asn1time::Time::UtcTime(utc) =
186 x509_cert.tbs_certificate.validity.not_before.clone()
187 {
188 Timestamp::from(utc.timestamp() as u32).into()
189 } else {
190 return Err(anyhow::anyhow!(
191 "Unexpected enum variant for validity.not_before"
192 ));
193 };
194
195 let extension_subkey_fp =
197 openpgp_x509_sequoia::experimental::extension_fingerprint(&x509_cert)?;
198
199 let extension_kdf_kek: Option<[u8; 4]> =
201 openpgp_x509_sequoia::experimental::extension_kdf_kek(&x509_cert)?;
202
203 let fp = if let Some(fp) = extension_subkey_fp {
206 fp
207 } else {
208 let serial = x509_cert.tbs_certificate.serial_number.as_slice();
209 let serial = &serial[serial.len() - 20..]; Fingerprint::from_bytes(serial)
211 };
212
213 let k4 = if let Ok(rsa_pub) = x509cert.rsa_public_key_data() {
214 util::get_rsa_as_pgp(rsa_pub, x509_creation_time)?
217 } else {
218 let pki = x509_cert.tbs_certificate.subject_public_key_info;
223
224 util::get_ecc_as_pgp(pkt, pki, x509_creation_time, &fp, extension_kdf_kek)?
225 };
226
227 if k4.fingerprint() != fp {
229 return Err(anyhow::anyhow!(
230 "Couldn't find matching key for Fingerprint {:?}",
231 fp
232 ));
233 }
234
235 Ok(k4.into())
236 }
237
238 pub fn keypair(self, id: &[u8], pkt: PgpKeyType, cert: Option<Cert>) -> Result<Op11KeyPair> {
242 let key = self.key(id, pkt, cert)?;
244
245 let priv_key_template = match pkt {
246 PgpKeyType::Sign | PgpKeyType::Auth => {
247 vec![
248 Attribute::Token(true),
249 Attribute::Private(true),
250 Attribute::Sign(true),
251 Attribute::Id(id.to_vec()),
252 Attribute::Class(ObjectClass::PRIVATE_KEY),
253 ]
254 }
255 PgpKeyType::Encrypt => {
256 vec![
257 Attribute::Token(true),
258 Attribute::Private(true),
259 Attribute::Decrypt(true), Attribute::Id(id.to_vec()),
261 Attribute::Class(ObjectClass::PRIVATE_KEY),
262 ]
263 }
264 };
265
266 let priv_key_handle = self.session.find_objects(&priv_key_template)?;
267
268 if priv_key_handle.len() == 1 {
269 Ok(Op11KeyPair::new(
270 key,
271 priv_key_handle[0],
272 Arc::new(Mutex::new(self.session)),
273 ))
274 } else {
275 Err(anyhow::anyhow!(
276 "Unexpected number of private keys found: {}",
277 priv_key_handle.len()
278 ))
279 }
280 }
281
282 pub fn decrypt(
286 self,
287 id: &[u8],
288 input: &mut (dyn std::io::Read + Send + Sync),
289 output: &mut (dyn std::io::Write + Send + Sync),
290 cert: Option<Cert>,
291 ) -> Result<()> {
292 let op11kp = self.keypair(id, PgpKeyType::Encrypt, cert)?;
293
294 let policy = &NullPolicy::new();
296 let mut decryptor =
297 DecryptorBuilder::from_reader(input)?.with_policy(policy, None, op11kp)?;
298
299 std::io::copy(&mut decryptor, output)?;
301
302 Ok(())
303 }
304
305 pub fn sign(
309 self,
310 id: &[u8],
311 input: &mut (dyn std::io::Read + Send + Sync),
312 output: &mut (dyn std::io::Write + Send + Sync),
313 cert: Option<Cert>,
314 ) -> Result<()> {
315 let op11kp = self.keypair(id, PgpKeyType::Sign, cert)?;
316
317 signer::sign_on_card(op11kp, input, output)
318 }
319
320 pub fn upload_key(
335 &self,
336 id: &[u8],
337 key: &Key<SecretParts, UnspecifiedRole>,
338 common_name: &str,
339 ) -> Result<()> {
340 let priv_key = self.upload_private(id, key)?;
341
342 let pub_key_info = Self::upload_gen_pki(key)?;
343 self.upload_pki(&pub_key_info)?;
344
345 let tbs_cert = openpgp_x509_sequoia::generate_x509(&pub_key_info, key, common_name, &[]);
347
348 let cert = self.upload_self_sign_x509(priv_key, tbs_cert, pub_key_info.algorithm())?;
350
351 let serial = key.fingerprint().as_bytes().to_vec();
353 self.upload_cert(cert, common_name, serial, id)?;
354
355 Ok(())
356 }
357
358 pub fn session(&self) -> &Session {
360 &self.session
361 }
362}
363
364pub struct Op11KeyPair {
369 pub public: Key<PublicParts, UnspecifiedRole>,
370 pub private: ObjectHandle,
371 pub session: Arc<Mutex<Session>>,
372}
373
374impl Op11KeyPair {
375 pub fn new(
376 public: Key<PublicParts, UnspecifiedRole>,
377 private: ObjectHandle,
378 session: Arc<Mutex<Session>>,
379 ) -> Self {
380 Self {
381 public,
382 private,
383 session,
384 }
385 }
386}