Skip to content

Commit 43a8d11

Browse files
authored
Merge pull request #3833 from reubenmiller/test-p11-1.6-incompat-cert-renew
fix: Fix `tedge cert renew` incompatibility when using 1.6.1 `tedge-p11-server` and more recent `tedge`
2 parents 969dcee + b3ce209 commit 43a8d11

File tree

7 files changed

+102
-4
lines changed

7 files changed

+102
-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
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
*** Settings ***
2+
Documentation This test suite runs the tests with tedge-p11-server pinned to a fixed version to ensure that new
3+
... versions of thin-edge remain backwards compatible with tedge-p11-server's binary communication protocol. The
4+
... scope of this test is limited to tedge-p11-server's initial feature set and will generally not be expanded.
5+
6+
Resource pkcs11_common.resource
7+
8+
Suite Setup Custom Setup
9+
Suite Teardown Get Suite Logs
10+
11+
Test Tags adapter:docker theme:cryptoki compatibility
12+
13+
14+
*** Variables ***
15+
${TEDGE_P11_SERVER_VERSION} 1.6.1
16+
17+
18+
*** Test Cases ***
19+
# the test cases are basically copy-pasted from private_key_storage.robot, as the purpose of this suite is to run the
20+
# exact same tests with a slightly different setup. It would be easiest if we could import the test cases themselves
21+
# from another test suite, but this isn't possible. So we extract reusable keywords into a resource file, but test cases
22+
# remain duplicated.
23+
Use Private Key in SoftHSM2 using tedge-p11-server
24+
Tedge Reconnect Should Succeed
25+
26+
Renew certificate
27+
Execute Command tedge cert renew c8y
28+
Tedge Reconnect Should Succeed
29+
30+
31+
*** Keywords ***
32+
Custom Setup
33+
${DEVICE_SN}= Setup register=${False}
34+
Set Suite Variable ${DEVICE_SN}
35+
36+
# this doesn't install anything but adds cloudsmith repo to apt
37+
Execute Command curl -1sLf 'https://dl.cloudsmith.io/public/thinedge/tedge-main/setup.deb.sh' | sudo -E bash
38+
Execute Command cmd=apt-get install -y --allow-downgrades tedge-p11-server=${TEDGE_P11_SERVER_VERSION}
39+
${stdout}= Execute Command tedge-p11-server -V strip=True
40+
Should Be Equal ${stdout} tedge-p11-server ${TEDGE_P11_SERVER_VERSION}
41+
42+
# Allow the tedge user to access softhsm
43+
Execute Command sudo usermod -a -G softhsm tedge
44+
Transfer To Device ${CURDIR}/data/init_softhsm.sh /usr/bin/
45+
46+
# initialize the soft hsm and create a certificate signing request
47+
Execute Command tedge config set device.cryptoki.pin 123456
48+
Execute Command tedge config set device.cryptoki.module_path /usr/lib/softhsm/libsofthsm2.so
49+
Execute Command sudo -u tedge /usr/bin/init_softhsm.sh --device-id "${DEVICE_SN}" --pin 123456
50+
51+
# configure tedge
52+
${domain}= Cumulocity.Get Domain
53+
Execute Command tedge config set c8y.url "${domain}"
54+
Execute Command tedge config set mqtt.bridge.built_in true
55+
Execute Command tedge config set device.cryptoki.mode socket
56+
57+
${csr_path}= Execute Command cmd=tedge config get device.csr_path strip=${True}
58+
Register Device With Cumulocity CA ${DEVICE_SN} csr_path=${csr_path}
59+
60+
Unset tedge-p11-server Uri

0 commit comments

Comments
 (0)