Skip to content

Commit 50daea5

Browse files
committed
Add printing of all slots, tokens and objects on selected token
1 parent 7b3b06d commit 50daea5

File tree

2 files changed

+153
-6
lines changed

2 files changed

+153
-6
lines changed

crates/extensions/tedge-p11-server/src/pkcs11/mod.rs

Lines changed: 137 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use cryptoki::object::ObjectClass;
2626
use cryptoki::object::ObjectHandle;
2727
use cryptoki::session::Session;
2828
use cryptoki::session::UserType;
29+
use cryptoki::slot::SlotInfo;
2930
use cryptoki::slot::TokenInfo;
3031
use rsa::pkcs1::EncodeRsaPublicKey;
3132
use rustls::sign::Signer;
@@ -35,6 +36,7 @@ use rustls::SignatureScheme;
3536
use serde::Deserialize;
3637
use serde::Serialize;
3738
use tracing::debug;
39+
use tracing::error;
3840
use tracing::trace;
3941
use tracing::warn;
4042

@@ -181,8 +183,8 @@ impl Cryptoki {
181183
self.open_session(uri, CryptokiSessionType::ReadOnly)
182184
}
183185

184-
fn open_session_rw<'a>(&'a self, uri: Option<&'a str>) -> anyhow::Result<CryptokiSession<'a>> {
185-
self.open_session(uri, CryptokiSessionType::ReadWrite)
186+
fn _open_session_rw<'a>(&'a self, uri: Option<&'a str>) -> anyhow::Result<CryptokiSession<'a>> {
187+
self.open_session(uri, CryptokiSessionType::_ReadWrite)
186188
}
187189

188190
fn open_session<'a>(
@@ -203,6 +205,9 @@ impl Cryptoki {
203205
Err(e) => e.into_inner(),
204206
};
205207

208+
debug!(slots = ?get_all_slots_info(&context));
209+
debug!(tokens = ?get_all_token_info(&context));
210+
206211
let slots_with_tokens = context.get_slots_with_token()?;
207212
let tokens: Result<Vec<_>, _> = slots_with_tokens
208213
.iter()
@@ -232,18 +237,40 @@ impl Cryptoki {
232237

233238
let session = match session_type {
234239
CryptokiSessionType::ReadOnly => context.open_ro_session(slot)?,
235-
CryptokiSessionType::ReadWrite => context.open_rw_session(slot)?,
240+
CryptokiSessionType::_ReadWrite => context.open_rw_session(slot)?,
236241
};
237242

238243
session.login(UserType::User, Some(&self.config.pin))?;
239244
let session_info = session.get_session_info()?;
240245
debug!(?session_info, "Opened a readonly session");
241246

242-
Ok(CryptokiSession {
247+
let session = CryptokiSession {
243248
session,
244249
token_info,
245250
uri_attributes,
246-
})
251+
};
252+
253+
let template = [];
254+
let objects = session.session.find_objects(&template);
255+
match objects {
256+
Err(err) => {
257+
error!(?template, ?err, "failed to find objects");
258+
}
259+
Ok(objects) => {
260+
let objects = objects
261+
.into_iter()
262+
.flat_map(|o| {
263+
let uri = session.export_object_uri(o).inspect_err(
264+
|err| error!(?err, object = ?o, "failed to read properties of object"),
265+
);
266+
uri.map(|u| (o, u)).ok()
267+
})
268+
.collect::<Vec<_>>();
269+
trace!(?objects, "Objects found in the token");
270+
}
271+
}
272+
273+
Ok(session)
247274
}
248275

249276
fn request_uri<'a>(
@@ -268,6 +295,45 @@ impl Cryptoki {
268295
}
269296
}
270297

298+
fn get_all_slots_info(cryptoki: &Pkcs11) -> Vec<SlotInfo> {
299+
let slots = match cryptoki.get_all_slots() {
300+
Ok(slots) => slots,
301+
Err(err) => {
302+
error!(?err, "failed to get slots");
303+
return vec![];
304+
}
305+
};
306+
slots
307+
.into_iter()
308+
.flat_map(|s| {
309+
cryptoki
310+
.get_slot_info(s)
311+
.inspect_err(|err| error!(slot = ?s, ?err, "failed to read slot info from slot"))
312+
.ok()
313+
})
314+
.collect::<Vec<_>>()
315+
}
316+
317+
fn get_all_token_info(cryptoki: &Pkcs11) -> Vec<TokenInfo> {
318+
let slots = match cryptoki.get_slots_with_token() {
319+
Ok(slots) => slots,
320+
Err(err) => {
321+
error!(?err, "failed to get slots");
322+
return vec![];
323+
}
324+
};
325+
326+
slots
327+
.into_iter()
328+
.flat_map(|s| {
329+
cryptoki
330+
.get_token_info(s)
331+
.inspect_err(|err| error!(slot = ?s, ?err, "failed to read token info from slot"))
332+
.ok()
333+
})
334+
.collect::<Vec<_>>()
335+
}
336+
271337
/// A cryptoki session opened with a token.
272338
struct CryptokiSession<'a> {
273339
session: Session,
@@ -278,7 +344,7 @@ struct CryptokiSession<'a> {
278344
#[derive(Debug, Clone, Copy)]
279345
enum CryptokiSessionType {
280346
ReadOnly,
281-
ReadWrite,
347+
_ReadWrite,
282348
}
283349

284350
impl CryptokiSession<'_> {
@@ -442,6 +508,41 @@ impl CryptokiSession<'_> {
442508

443509
Ok(pubkey_pem)
444510
}
511+
512+
fn export_object_uri(&self, object: ObjectHandle) -> anyhow::Result<String> {
513+
let template = &[AttributeType::Id, AttributeType::Label];
514+
let attrs = self.session.get_attributes(object, template)?.into_iter();
515+
516+
let mut key_uri = export_session_uri(&self.token_info);
517+
518+
for attr in attrs {
519+
match attr {
520+
Attribute::Id(id) => {
521+
key_uri.push(';');
522+
key_uri.push_str("id=");
523+
// from RFC section 2.3: Note that the value of the "id" attribute SHOULD NOT be encoded as UTF-8 because it can
524+
// contain non-textual data, instead it SHOULD be entirely percent-encoded
525+
for byte in &id {
526+
key_uri.push_str(percent_encoding::percent_encode_byte(*byte));
527+
}
528+
}
529+
Attribute::Label(label) => {
530+
let label = std::str::from_utf8(&label).context("label should be utf-8")?;
531+
key_uri.push(';');
532+
key_uri.push_str("object=");
533+
let label = uri::percent_encode(label);
534+
key_uri.push_str(&label);
535+
}
536+
other => warn!(asked = ?template, got= ?other, "Got invalid attribute"),
537+
}
538+
}
539+
540+
// omit the "type" attribute since its not relevant when used as device.key_uri, which is intended use for this produced value
541+
542+
anyhow::ensure!(key_uri.starts_with("pkcs11:"));
543+
544+
Ok(key_uri)
545+
}
445546
}
446547

447548
#[derive(Debug)]
@@ -687,6 +788,36 @@ fn get_ec_mechanism(session: &Session, key: ObjectHandle) -> anyhow::Result<SigS
687788
}
688789
}
689790

791+
/// Generates PKCS11 URI of the selected token.
792+
///
793+
/// The generated URI attempts to be similar to URIs generated by gnutls. Notably, "slot-description", "slot-id", and
794+
/// "slot-manufacturer" attributes are missing from gnutls URIs, perhaps for portability (URI points to the same thing
795+
/// even if token is reinserted into a different slot).
796+
fn export_session_uri(token_info: &TokenInfo) -> String {
797+
let mut uri = String::from("pkcs11:");
798+
799+
uri.push_str("model=");
800+
let model = uri::percent_encode(token_info.model());
801+
uri.push_str(&model);
802+
803+
uri.push(';');
804+
uri.push_str("manufacturer=");
805+
let manufacturer = uri::percent_encode(token_info.manufacturer_id());
806+
uri.push_str(&manufacturer);
807+
808+
uri.push(';');
809+
uri.push_str("serial=");
810+
let serial = uri::percent_encode(token_info.serial_number());
811+
uri.push_str(&serial);
812+
813+
uri.push(';');
814+
uri.push_str("token=");
815+
let token = uri::percent_encode(token_info.label());
816+
uri.push_str(&token);
817+
818+
uri
819+
}
820+
690821
#[cfg(test)]
691822
mod tests {
692823
use super::*;

crates/extensions/tedge-p11-server/src/pkcs11/uri.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,22 @@ impl<'a> Pkcs11Uri<'a> {
8585
}
8686
}
8787

88+
const PKCS11_ASCII_SET: &percent_encoding::AsciiSet =
89+
&percent_encoding::NON_ALPHANUMERIC.remove(b'-');
90+
91+
/// Percent-encode PKCS11 attribute values.
92+
///
93+
/// In contrast to more general URL percent-encoding, some characters like `-` don't need to be
94+
/// percent-encoded in PKCS11 URIs[1], so we don't encode them. Note that if we did, encoding these
95+
/// characters that don't have to be encoded is not a mistake, as any URI parser would eagerly
96+
/// decode all percent-encode sequences, the difference is just better/worse readability for the
97+
/// user.
98+
///
99+
/// [1]: https://www.rfc-editor.org/rfc/rfc7512.html#section-2.3
100+
pub fn percent_encode(input: &str) -> String {
101+
percent_encoding::utf8_percent_encode(input, PKCS11_ASCII_SET).to_string()
102+
}
103+
88104
#[cfg(test)]
89105
mod tests {
90106
use super::*;

0 commit comments

Comments
 (0)