Skip to content

Commit 658d7d3

Browse files
committed
Remove same-key limitation for CSR generation using PKCS11
This PR removes a limitation for generating CSRs using PKCS11 private keys that they can only be generated for the same certificate that is already present. This unlocks two usecases that were previously impossible: - using `tedge cert renew` to install a new certificate when we already have a certificate but a different keypair is used (previously SubjectPublicKeyInfo was reused from previous cert so using different key didn't work) - using `tedge cert download c8y` when we don't yet have a certificate and register the device to C8y CA and download the initial certificate (previously some fields of CSR were reused from older cert so had no way to fill these fields without some certificate already being present) Signed-off-by: Marcel Guzik <[email protected]>
1 parent a246c68 commit 658d7d3

File tree

9 files changed

+178
-88
lines changed

9 files changed

+178
-88
lines changed

crates/common/certificate/src/lib.rs

Lines changed: 96 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use sha1::Digest;
77
use sha1::Sha1;
88
use std::path::Path;
99
use std::path::PathBuf;
10+
use tedge_p11_server::service::ChooseSchemeRequest;
1011
use tedge_p11_server::CryptokiConfig;
1112
use tedge_p11_server::CryptokiConfigDirect;
1213
use time::Duration;
@@ -199,44 +200,112 @@ impl KeyKind {
199200
#[instrument]
200201
pub fn from_cryptoki_and_public_key_pem(
201202
cryptoki_config: CryptokiConfig,
202-
private_key_label: String,
203-
public_key_pem: String,
204-
algorithm: SignatureAlgorithm,
205203
) -> Result<Self, CertificateError> {
206-
let public_key = pem::parse(public_key_pem).unwrap();
204+
let cryptoki = tedge_p11_server::tedge_p11_service(cryptoki_config.clone())?;
205+
let pubkey_pem = cryptoki.get_public_key_pem(None)?;
206+
let public_key = pem::parse(&pubkey_pem).unwrap();
207207
let public_key_raw = public_key.into_contents();
208-
trace!("pubkey raw: {public_key_raw:x?}");
209208

210-
// construct a URI that uses private key we just created to sign
211-
let mut cryptoki_config = cryptoki_config;
212-
let uri = match cryptoki_config {
213-
CryptokiConfig::Direct(CryptokiConfigDirect { ref mut uri, .. }) => uri,
214-
CryptokiConfig::SocketService { ref mut uri, .. } => uri,
215-
};
216-
// TODO: cleanup manual URI parsing
217-
let private_key_uri = match uri {
218-
Some(uri) if uri.contains("object=") => {
219-
let uri: String = uri
220-
.strip_prefix("pkcs11:")
221-
.unwrap_or("")
222-
.split(';')
223-
.filter(|a| !a.contains("object="))
224-
.collect();
225-
226-
format!("pkcs11:{uri};object={private_key_label}")
227-
}
228-
Some(uri) => format!("{uri};object={private_key_label}"),
229-
None => format!("pkcs11:object={private_key_label}"),
209+
let signature_algorithm = cryptoki.choose_scheme(ChooseSchemeRequest {
210+
offered: vec![
211+
tedge_p11_server::service::SignatureScheme(
212+
rustls::SignatureScheme::ECDSA_NISTP256_SHA256,
213+
),
214+
tedge_p11_server::service::SignatureScheme(
215+
rustls::SignatureScheme::ECDSA_NISTP384_SHA384,
216+
),
217+
tedge_p11_server::service::SignatureScheme(
218+
rustls::SignatureScheme::RSA_PKCS1_SHA256,
219+
),
220+
],
221+
uri: None,
222+
})?;
223+
let signature_algorithm = signature_algorithm
224+
.scheme
225+
.context("No supported scheme found")?
226+
.0;
227+
228+
let algorithm = match signature_algorithm {
229+
rustls::SignatureScheme::ECDSA_NISTP256_SHA256 => SignatureAlgorithm::EcdsaP256Sha256,
230+
rustls::SignatureScheme::ECDSA_NISTP384_SHA384 => SignatureAlgorithm::EcdsaP384Sha384,
231+
rustls::SignatureScheme::RSA_PKCS1_SHA256 => SignatureAlgorithm::RsaPkcs1Sha256,
232+
_ => return Err(anyhow::anyhow!("Unsupported signature scheme").into()),
230233
};
231-
*uri = Some(private_key_uri.into());
232-
debug!(?uri);
234+
trace!(?pubkey_pem, ?algorithm);
235+
// trace!("pubkey raw: {public_key_raw:x?}");
236+
237+
// // construct a URI that uses private key we just created to sign
238+
// let mut cryptoki_config = cryptoki_config;
239+
// let uri = match cryptoki_config {
240+
// CryptokiConfig::Direct(CryptokiConfigDirect { ref mut uri, .. }) => uri,
241+
// CryptokiConfig::SocketService { ref mut uri, .. } => uri,
242+
// };
243+
// // TODO: cleanup manual URI parsing
244+
// let private_key_uri = match uri {
245+
// Some(uri) if uri.contains("object=") => {
246+
// let uri: String = uri
247+
// .strip_prefix("pkcs11:")
248+
// .unwrap_or("")
249+
// .split(';')
250+
// .filter(|a| !a.contains("object="))
251+
// .collect();
252+
253+
// format!("pkcs11:{uri};object={private_key_label}")
254+
// }
255+
// Some(uri) => format!("{uri};object={private_key_label}"),
256+
// None => format!("pkcs11:object={private_key_label}"),
257+
// };
258+
// *uri = Some(private_key_uri.into());
259+
// debug!(?uri);
233260

234261
Ok(Self::ReuseRemote(RemoteKeyPair {
235262
cryptoki_config,
236263
public_key_raw,
237264
algorithm,
238265
}))
239266
}
267+
268+
// #[instrument]
269+
// pub fn from_cryptoki_and_public_key_pem(
270+
// cryptoki_config: CryptokiConfig,
271+
// private_key_label: String,
272+
// public_key_pem: String,
273+
// algorithm: SignatureAlgorithm,
274+
// ) -> Result<Self, CertificateError> {
275+
// let public_key = pem::parse(public_key_pem).unwrap();
276+
// let public_key_raw = public_key.into_contents();
277+
// trace!("pubkey raw: {public_key_raw:x?}");
278+
279+
// // construct a URI that uses private key we just created to sign
280+
// let mut cryptoki_config = cryptoki_config;
281+
// let uri = match cryptoki_config {
282+
// CryptokiConfig::Direct(CryptokiConfigDirect { ref mut uri, .. }) => uri,
283+
// CryptokiConfig::SocketService { ref mut uri, .. } => uri,
284+
// };
285+
// // TODO: cleanup manual URI parsing
286+
// let private_key_uri = match uri {
287+
// Some(uri) if uri.contains("object=") => {
288+
// let uri: String = uri
289+
// .strip_prefix("pkcs11:")
290+
// .unwrap_or("")
291+
// .split(';')
292+
// .filter(|a| !a.contains("object="))
293+
// .collect();
294+
295+
// format!("pkcs11:{uri};object={private_key_label}")
296+
// }
297+
// Some(uri) => format!("{uri};object={private_key_label}"),
298+
// None => format!("pkcs11:object={private_key_label}"),
299+
// };
300+
// *uri = Some(private_key_uri.into());
301+
// debug!(?uri);
302+
303+
// Ok(Self::ReuseRemote(RemoteKeyPair {
304+
// cryptoki_config,
305+
// public_key_raw,
306+
// algorithm,
307+
// }))
308+
// }
240309
}
241310

242311
/// A key pair using a remote private key.

crates/common/tedge_config/src/tedge_toml/tedge_config/mqtt_config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use camino::Utf8PathBuf;
1212
use certificate::parse_root_certificate::AuthPin;
1313
use certificate::CertificateError;
1414
use tedge_config_macros::all_or_nothing;
15+
use tracing::trace;
1516

1617
use super::CloudConfig;
1718
use super::TEdgeConfigReaderDevice;
@@ -226,6 +227,7 @@ impl TEdgeConfigReaderDevice {
226227
let uri = cloud
227228
.and_then(|c| c.key_uri().or(self.key_uri.or_none().cloned()))
228229
.or(self.key_uri.or_none().cloned());
230+
trace!(?uri);
229231
match cryptoki.mode {
230232
Cryptoki::Off => Ok(None),
231233
Cryptoki::Module => Ok(Some(CryptokiConfig::Direct(CryptokiConfigDirect {

crates/core/tedge/src/cli/certificate/create_csr.rs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,20 +78,7 @@ impl CreateCsrCmd {
7878
privkey_label,
7979
pubkey_pem,
8080
sigalg,
81-
} => {
82-
let current_cert = self.current_cert.clone();
83-
match current_cert {
84-
Some(current_cert) => {
85-
KeyKind::from_cryptoki_and_existing_cert(config.clone(), &current_cert)?
86-
}
87-
None => KeyKind::from_cryptoki_and_public_key_pem(
88-
config.clone(),
89-
privkey_label.clone().unwrap(),
90-
pubkey_pem.as_ref().unwrap().clone(),
91-
sigalg.expect("sigalg should be set when generating a new key"),
92-
)?,
93-
}
94-
}
81+
} => KeyKind::from_cryptoki_and_public_key_pem(config.clone())?,
9582
};
9683
debug!(?previous_key);
9784

crates/core/tedge/src/cli/certificate/create_key.rs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -90,28 +90,28 @@ impl Command for CreateKeyCmd {
9090

9191
eprintln!("New keypair was successfully created.");
9292

93-
// use returned public key to create a CSR
94-
let sigalg = match (self.r#type, self.curve) {
95-
(KeyType::Rsa, _) => certificate::SignatureAlgorithm::RsaPkcs1Sha256,
96-
(KeyType::Ec, EcCurve::P256) => certificate::SignatureAlgorithm::EcdsaP256Sha256,
97-
(KeyType::Ec, EcCurve::P384) => certificate::SignatureAlgorithm::EcdsaP384Sha384,
98-
};
99-
100-
let key = super::create_csr::Key::Cryptoki {
101-
config: self.cryptoki_config.clone(),
102-
privkey_label: Some(self.label.clone()),
103-
pubkey_pem: Some(pubkey_pem.clone()),
104-
sigalg: Some(sigalg),
105-
};
106-
107-
super::create_device_csr(
108-
self.device_id.clone(),
109-
key,
110-
None,
111-
self.csr_path.clone(),
112-
self.csr_template.clone(),
113-
)
114-
.await?;
93+
// // use returned public key to create a CSR
94+
// let sigalg = match (self.r#type, self.curve) {
95+
// (KeyType::Rsa, _) => certificate::SignatureAlgorithm::RsaPkcs1Sha256,
96+
// (KeyType::Ec, EcCurve::P256) => certificate::SignatureAlgorithm::EcdsaP256Sha256,
97+
// (KeyType::Ec, EcCurve::P384) => certificate::SignatureAlgorithm::EcdsaP384Sha384,
98+
// };
99+
100+
// let key = super::create_csr::Key::Cryptoki {
101+
// config: self.cryptoki_config.clone(),
102+
// privkey_label: Some(self.label.clone()),
103+
// pubkey_pem: Some(pubkey_pem.clone()),
104+
// sigalg: Some(sigalg),
105+
// };
106+
107+
// super::create_device_csr(
108+
// self.device_id.clone(),
109+
// key,
110+
// None,
111+
// self.csr_path.clone(),
112+
// self.csr_template.clone(),
113+
// )
114+
// .await?;
115115

116116
eprintln!("Public key:\n{pubkey_pem}\n");
117117

crates/core/tedge/src/main.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,7 @@ async fn main() -> anyhow::Result<()> {
6969
.context("failed to run tedge apt plugin")?
7070
}
7171
TEdgeOptMulticall::Tedge(TEdgeCli { cmd, common }) => {
72-
log_init(
73-
"tedge",
74-
&common.log_args.with_default_level(tracing::Level::WARN),
75-
&common.config_dir,
76-
)?;
72+
log_init("tedge", &common.log_args, &common.config_dir)?;
7773

7874
let tedge_config = tedge_config::TEdgeConfig::load(&common.config_dir).await?;
7975

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

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ use cryptoki::mechanism::MechanismType;
7979
use cryptoki::object::Attribute;
8080
use cryptoki::object::AttributeType;
8181
use cryptoki::object::KeyType;
82+
use cryptoki::object::ObjectClass;
8283
use cryptoki::object::ObjectHandle;
8384
use cryptoki::session::Session;
8485
use cryptoki::session::UserType;
@@ -239,7 +240,8 @@ impl Cryptoki {
239240
let session = self.open_session(&uri_attributes)?;
240241

241242
// get the signing key
242-
let key = Self::find_key_by_attributes(&uri_attributes, &session)?;
243+
let key =
244+
Self::find_key_by_attributes(&uri_attributes, &session, ObjectClass::PRIVATE_KEY)?;
243245
let key_type = session
244246
.get_attributes(key, &[AttributeType::KeyType])?
245247
.into_iter()
@@ -278,12 +280,14 @@ impl Cryptoki {
278280
session,
279281
key,
280282
sigscheme,
283+
secondary_schemes: Vec::new(),
281284
}
282285
}
283286
KeyType::RSA => Pkcs11Signer {
284287
session,
285288
key,
286289
sigscheme: SigScheme::RsaPssSha256,
290+
secondary_schemes: vec![SigScheme::RsaPkcs1Sha256],
287291
},
288292
_ => anyhow::bail!("unsupported key type"),
289293
};
@@ -305,20 +309,20 @@ impl Cryptoki {
305309
let uri_attributes = self.request_uri(uri)?;
306310
let session = self.open_session(&uri_attributes)?;
307311

308-
let key =
309-
Self::find_key_by_attributes(&uri_attributes, &session).context("object not found")?;
312+
let key = Self::find_key_by_attributes(&uri_attributes, &session, ObjectClass::PUBLIC_KEY)?;
310313

311314
export_public_key_pem(&session, key)
312315
}
313316

314317
fn find_key_by_attributes(
315318
uri: &uri::Pkcs11Uri,
316319
session: &Session,
320+
class: ObjectClass,
317321
) -> anyhow::Result<ObjectHandle> {
318322
let mut key_template = vec![
319323
Attribute::Token(true),
320-
Attribute::Private(true),
321-
Attribute::Sign(true),
324+
// Attribute::Sign(true),
325+
Attribute::Class(class),
322326
];
323327
if let Some(object) = &uri.object {
324328
key_template.push(Attribute::Label(object.as_bytes().to_vec()));
@@ -327,14 +331,14 @@ impl Cryptoki {
327331
key_template.push(Attribute::Id(id.clone()));
328332
}
329333

330-
trace!(?key_template, "Finding a key");
334+
trace!(?key_template, ?uri.object, "Finding a key");
331335

332336
let mut keys = session
333337
.find_objects(&key_template)
334338
.context("Failed to find private key objects")?
335339
.into_iter();
336340

337-
let key = keys.next().context("Failed to find a private key")?;
341+
let key = keys.next().context("Failed to find a key")?;
338342
if keys.len() > 0 {
339343
warn!(
340344
"Multiple keys were found. If the wrong one was chosen, please use a URI that uniquely identifies a key."
@@ -636,6 +640,8 @@ fn export_public_key_pem(session: &Session, key: ObjectHandle) -> anyhow::Result
636640
}
637641

638642
debug!("Can't use PublicKeyInfo, reconstructing pubkey from components");
643+
let attrs = session.get_attributes(key, &[AttributeType::EcPoint])?;
644+
let mut attrs = attrs.into_iter();
639645

640646
// Elliptic-Curve-Point-to-Octet-String from SEC 1: Elliptic Curve Cryptography (Version 2.0) section 2.3.3 (page 10)
641647
let ec_point = attrs.next().context("Failed to get pubkey EcPoint")?;
@@ -678,6 +684,7 @@ pub struct Pkcs11Signer {
678684
session: Pkcs11Session,
679685
key: ObjectHandle,
680686
pub sigscheme: SigScheme,
687+
pub secondary_schemes: Vec<SigScheme>,
681688
}
682689

683690
impl Pkcs11Signer {
@@ -812,10 +819,20 @@ impl SigningKey for Pkcs11Signer {
812819
let key_scheme = self.sigscheme.into();
813820
if offered.contains(&key_scheme) {
814821
debug!("Matching scheme: {key_scheme:?}");
815-
Some(Box::new(self.clone()))
816-
} else {
817-
None
822+
return Some(Box::new(self.clone()));
818823
}
824+
825+
for scheme in &self.secondary_schemes {
826+
let key_scheme = (*scheme).into();
827+
if offered.contains(&key_scheme) {
828+
debug!("Matching scheme: {key_scheme:?}");
829+
let mut signer = self.clone();
830+
signer.sigscheme = *scheme;
831+
return Some(Box::new(signer));
832+
}
833+
}
834+
835+
None
819836
}
820837

821838
fn algorithm(&self) -> SignatureAlgorithm {

0 commit comments

Comments
 (0)