-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Didier Wenzek <[email protected]>
- Loading branch information
1 parent
dea9c13
commit 5335af8
Showing
4 changed files
with
204 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,47 @@ | ||
mod download; | ||
mod renew; | ||
mod upload; | ||
|
||
use crate::cli::certificate::create_csr::CreateCsrCmd; | ||
use crate::read_cert_to_string; | ||
use crate::CertError; | ||
use camino::Utf8PathBuf; | ||
use certificate::NewCertificateConfig; | ||
pub use download::DownloadCertCmd; | ||
pub use renew::RenewCertCmd; | ||
use std::fs::OpenOptions; | ||
use std::io::Write; | ||
use tedge_utils::paths::set_permission; | ||
pub use upload::UploadCertCmd; | ||
|
||
/// Create a device private key and CSR | ||
fn create_device_csr( | ||
common_name: String, | ||
key_path: Utf8PathBuf, | ||
csr_path: Utf8PathBuf, | ||
) -> Result<String, CertError> { | ||
let config = NewCertificateConfig::default(); | ||
let create_cmd = CreateCsrCmd { | ||
id: common_name, | ||
csr_path: csr_path.clone(), | ||
key_path, | ||
user: "tedge".to_string(), | ||
group: "tedge".to_string(), | ||
}; | ||
create_cmd.create_certificate_signing_request(&config)?; | ||
read_cert_to_string(&csr_path) | ||
} | ||
|
||
/// Store a device certificate | ||
fn store_device_cert(cert_path: &Utf8PathBuf, cert: String) -> Result<(), CertError> { | ||
let mut file = OpenOptions::new() | ||
.write(true) | ||
.create_new(true) | ||
.open(cert_path)?; | ||
|
||
file.write_all(cert.as_bytes())?; | ||
file.sync_all()?; | ||
|
||
set_permission(&file, 0o444)?; | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
use crate::cli::certificate::c8y::create_device_csr; | ||
use crate::cli::certificate::c8y::store_device_cert; | ||
use crate::command::Command; | ||
use crate::error; | ||
use crate::get_webpki_error_from_reqwest; | ||
use crate::log::MaybeFancy; | ||
use anyhow::Error; | ||
use camino::Utf8PathBuf; | ||
use certificate::CloudRootCerts; | ||
use hyper::header::AUTHORIZATION; | ||
use hyper::header::CONTENT_TYPE; | ||
use hyper::StatusCode; | ||
use reqwest::blocking::Response; | ||
use tedge_config::HostPort; | ||
use tedge_config::HTTPS_PORT; | ||
use tedge_config::MQTT_TLS_PORT; | ||
use url::Url; | ||
|
||
/// Command to renew a device certificate from Cumulocity | ||
pub struct RenewCertCmd { | ||
/// The device identifier to be used as the common name for the certificate | ||
pub device_id: String, | ||
|
||
/// Cumulocity MQTT end-point where the device is authenticated | ||
pub c8y_mqtt: HostPort<MQTT_TLS_PORT>, | ||
|
||
/// Cumulocity instance from where the device got his current certificate | ||
pub c8y_url: HostPort<HTTPS_PORT>, | ||
|
||
/// Root certificates used to authenticate the Cumulocity instance | ||
pub root_certs: CloudRootCerts, | ||
|
||
/// The path where the device certificate will be stored | ||
pub cert_path: Utf8PathBuf, | ||
|
||
/// The path where the device private key will be stored | ||
pub key_path: Utf8PathBuf, | ||
|
||
/// The path where the device CSR file will be stored | ||
pub csr_path: Utf8PathBuf, | ||
} | ||
|
||
impl Command for RenewCertCmd { | ||
fn description(&self) -> String { | ||
format!("Renew the device certificate from {}", self.c8y_url) | ||
} | ||
|
||
fn execute(&self) -> Result<(), MaybeFancy<Error>> { | ||
Ok(self.renew_device_certificate()?) | ||
} | ||
} | ||
|
||
impl RenewCertCmd { | ||
fn renew_device_certificate(&self) -> Result<(), Error> { | ||
let csr = create_device_csr( | ||
self.device_id.clone(), | ||
self.key_path.clone(), | ||
self.csr_path.clone(), | ||
)?; | ||
|
||
let jwt_token = self.get_jwt_token(); | ||
|
||
let http = self.root_certs.blocking_client(); | ||
let url = format!("https://{}/.well-known/est/simpleenroll", self.c8y_url); | ||
let url = Url::parse(&url)?; | ||
let result = self.post_device_csr(&http, &url, &jwt_token, &csr); | ||
match result { | ||
Ok(response) if response.status() == StatusCode::OK => { | ||
if let Ok(cert) = response.text() { | ||
store_device_cert(&self.cert_path, cert)?; | ||
return Ok(()); | ||
} | ||
error!( | ||
"Fail to extract a certificate from the response returned by {}", | ||
self.c8y_url | ||
); | ||
} | ||
Ok(response) => { | ||
error!( | ||
"The device certificate cannot be renewed on {}: {:?}", | ||
self.c8y_url, | ||
response.status() | ||
); | ||
} | ||
Err(err) => { | ||
error!( | ||
"Fail to connect to {}: {:?}", | ||
self.c8y_url, | ||
get_webpki_error_from_reqwest(err) | ||
) | ||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Post the device CSR | ||
fn post_device_csr( | ||
&self, | ||
http: &reqwest::blocking::Client, | ||
url: &Url, | ||
jwt_token: &str, | ||
csr: &str, | ||
) -> Result<Response, reqwest::Error> { | ||
http.post(url.clone()) | ||
.header(AUTHORIZATION, format!("Bearer {jwt_token}")) | ||
.header(CONTENT_TYPE, "text/plain") | ||
.body(csr.to_string()) | ||
.send() | ||
} | ||
|
||
fn get_jwt_token(&self) -> String { | ||
let _ = self.c8y_mqtt.clone(); | ||
todo!() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters