Skip to content

Commit b3ce209

Browse files
committed
fix cert renew incompat for tedge-p11-server 1.6.1
If tedge-p11-server is too old, use previous method to renew only existing certificates. With tedge-p11-server 1.6.1, we could only renew existing certificates. In later versions, where an ability to export the PEM of public keys was added and we could use this to generate CSRs without existing certificate, this new method replaced the previous approach, but this introduced the incompatibility (since tedge-p11-server 1.6.1 didn't support it). So now we revert to the older method if server is too old. Signed-off-by: Marcel Guzik <[email protected]>
1 parent 96afee0 commit b3ce209

File tree

6 files changed

+42
-4
lines changed

6 files changed

+42
-4
lines changed

crates/common/certificate/src/lib.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ pub enum KeyKind {
155155
}
156156

157157
impl KeyKind {
158-
pub fn from_cryptoki_and_existing_cert(
158+
fn from_cryptoki_and_existing_cert(
159159
cryptoki_config: CryptokiConfig,
160160
current_cert: &Utf8Path,
161161
) -> Result<Self, CertificateError> {
@@ -193,9 +193,29 @@ impl KeyKind {
193193
}))
194194
}
195195

196-
pub fn from_cryptoki(cryptoki_config: CryptokiConfig) -> Result<Self, CertificateError> {
196+
pub fn from_cryptoki(
197+
cryptoki_config: CryptokiConfig,
198+
current_cert: Option<&Utf8Path>,
199+
) -> Result<Self, CertificateError> {
197200
let cryptoki = tedge_p11_server::tedge_p11_service(cryptoki_config.clone())?;
198-
let pubkey_pem = cryptoki.get_public_key_pem(None)?;
201+
202+
let pubkey_pem = cryptoki.get_public_key_pem(None);
203+
let pubkey_pem = match pubkey_pem {
204+
Ok(p) => p,
205+
Err(err) => {
206+
let e = format!("{err:#}");
207+
if e.contains("Failed to parse the received frame") {
208+
// server doesn't understand the request, too old, fallback to the older method of just resigning existing certificate
209+
let Some(current_cert) = current_cert else {
210+
return Err(CertificateError::Other(
211+
anyhow::anyhow!("tedge-p11-server can only renew existing certificates but there's no existing certificate; upgrade tedge-p11-server or generate a self-signed certificate first")));
212+
};
213+
return Self::from_cryptoki_and_existing_cert(cryptoki_config, current_cert);
214+
}
215+
return Err(err.into());
216+
}
217+
};
218+
199219
let public_key = pem::parse(&pubkey_pem).unwrap();
200220
let public_key_raw = public_key.into_contents();
201221

crates/core/tedge/src/cli/certificate/c8y/download.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ impl DownloadCertCmd {
8585
create_device_csr(
8686
common_name.clone(),
8787
self.key.clone(),
88+
None,
8889
self.csr_path.clone(),
8990
self.csr_template.clone(),
9091
)

crates/core/tedge/src/cli/certificate/c8y/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ pub use upload::UploadCertCmd;
1818
async fn create_device_csr(
1919
common_name: String,
2020
key: super::create_csr::Key,
21+
current_cert: Option<Utf8PathBuf>,
2122
csr_path: Utf8PathBuf,
2223
csr_template: CsrTemplate,
2324
) -> Result<(), CertError> {
2425
let create_cmd = CreateCsrCmd {
2526
id: common_name,
2627
csr_path: csr_path.clone(),
2728
key,
29+
current_cert,
2830
user: "tedge".to_string(),
2931
group: "tedge".to_string(),
3032
csr_template,

crates/core/tedge/src/cli/certificate/c8y/renew.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ impl RenewCertCmd {
8484
create_device_csr(
8585
common_name,
8686
self.key.clone(),
87+
Some(self.cert_path.clone()),
8788
self.csr_path.clone(),
8889
self.csr_template.clone(),
8990
)

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,11 @@ impl BuildCommand for TEdgeCertCli {
197197
config.device_key_path(cloud.as_ref())?.to_owned(),
198198
));
199199
debug!(?key);
200+
let current_cert = config
201+
.device_cert_path(cloud.as_ref())
202+
.map(|c| c.to_owned())
203+
.ok();
204+
debug!(?current_cert);
200205

201206
let cmd = CreateCsrCmd {
202207
id: get_device_id(id, config, &cloud)?,
@@ -207,6 +212,7 @@ impl BuildCommand for TEdgeCertCli {
207212
} else {
208213
config.device_csr_path(cloud.as_ref())?.to_owned()
209214
},
215+
current_cert,
210216
user: user.to_owned(),
211217
group: group.to_owned(),
212218
csr_template,

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ pub struct CreateCsrCmd {
2424
/// The path where the device CSR will be stored
2525
pub csr_path: Utf8PathBuf,
2626

27+
/// Path to current certificate, if it exists
28+
pub current_cert: Option<Utf8PathBuf>,
29+
2730
/// The owner of the private key
2831
pub user: String,
2932
pub group: String,
@@ -63,7 +66,10 @@ impl CreateCsrCmd {
6366
.await
6467
.map_err(|e| CertError::IoError(e).key_context(key_path.clone()))?,
6568

66-
Key::Cryptoki(config) => KeyKind::from_cryptoki(config.clone())?,
69+
Key::Cryptoki(config) => KeyKind::from_cryptoki(
70+
config.clone(),
71+
self.current_cert.as_ref().map(|p| p.as_path()),
72+
)?,
6773
};
6874
debug!(?previous_key);
6975

@@ -111,6 +117,7 @@ mod tests {
111117
user: "mosquitto".to_string(),
112118
group: "mosquitto".to_string(),
113119
csr_template: CsrTemplate::default(),
120+
current_cert: None,
114121
};
115122

116123
assert_matches!(cmd.create_certificate_signing_request().await, Ok(()));
@@ -154,6 +161,7 @@ mod tests {
154161
user: "mosquitto".to_string(),
155162
group: "mosquitto".to_string(),
156163
csr_template: CsrTemplate::default(),
164+
current_cert: None,
157165
};
158166

159167
// create csr using existing private key and device_id from public cert

0 commit comments

Comments
 (0)