Skip to content

Commit

Permalink
Add the root_certificates parameter
Browse files Browse the repository at this point in the history
Being able to define root certificates in the command line is not enough
for two reasons:
 1. It is always global, you cannot define a root certificate for a
    specific endpoint.
 2. Daemon scripts and unit files are not meant to be changed every time
    you need to add a root certificate.

For those reasons, it is now to possible to define root certificates in
the configuration. Those defined in the `global` section will be used on
every endpoint, just like those added via the command line. Those
defined in an endpoint will be used in this endpoint only.
  • Loading branch information
breard-r committed Oct 10, 2020
1 parent 48179d1 commit 9ec48e7
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 108 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [Unreleased]

### Added
- In the configuration, `root_certificates` has been added to the `global` and `endpoint` sections as an array of strings representing the path to root certificate files.


## [0.12.0] - 2020-09-26

### Added
Expand Down
22 changes: 7 additions & 15 deletions acmed/src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,7 @@ impl Account {
.or_insert_with(AccountEndpoint::new);
}

pub fn synchronize(
&mut self,
endpoint: &mut Endpoint,
root_certs: &[String],
) -> Result<(), Error> {
pub fn synchronize(&mut self, endpoint: &mut Endpoint) -> Result<(), Error> {
let acc_ep = self.get_endpoint(&endpoint.name)?;
if !acc_ep.account_url.is_empty() {
if let Some(ec) = &self.external_account {
Expand All @@ -217,7 +213,7 @@ impl Account {
&endpoint.name
);
self.info(&msg);
register_account(endpoint, root_certs, self)?;
register_account(endpoint, self)?;
return Ok(());
}
}
Expand All @@ -226,23 +222,19 @@ impl Account {
let contacts_changed = ct_hash != acc_ep.contacts_hash;
let key_changed = key_hash != acc_ep.key_hash;
if contacts_changed {
update_account_contacts(endpoint, root_certs, self)?;
update_account_contacts(endpoint, self)?;
}
if key_changed {
update_account_key(endpoint, root_certs, self)?;
update_account_key(endpoint, self)?;
}
} else {
register_account(endpoint, root_certs, self)?;
register_account(endpoint, self)?;
}
Ok(())
}

pub fn register(
&mut self,
endpoint: &mut Endpoint,
root_certs: &[String],
) -> Result<(), Error> {
register_account(endpoint, root_certs, self)
pub fn register(&mut self, endpoint: &mut Endpoint) -> Result<(), Error> {
register_account(endpoint, self)
}

pub fn save(&self) -> Result<(), Error> {
Expand Down
28 changes: 13 additions & 15 deletions acmed/src/acme_proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,26 +84,25 @@ macro_rules! set_empty_data_builder {

pub fn request_certificate(
cert: &Certificate,
root_certs: &[String],
endpoint: &mut Endpoint,
account: &mut Account,
) -> Result<(), Error> {
let mut hook_datas = vec![];
let endpoint_name = endpoint.name.clone();

// Refresh the directory
http::refresh_directory(endpoint, root_certs).map_err(HttpError::in_err)?;
http::refresh_directory(endpoint).map_err(HttpError::in_err)?;

// Synchronize the account
account.synchronize(endpoint, root_certs)?;
account.synchronize(endpoint)?;

// Create a new order
let mut new_reg = false;
let (order, order_url) = loop {
let new_order = NewOrder::new(&cert.identifiers);
let new_order = serde_json::to_string(&new_order)?;
let data_builder = set_data_builder!(account, endpoint_name, new_order.as_bytes());
match http::new_order(endpoint, root_certs, &data_builder) {
match http::new_order(endpoint, &data_builder) {
Ok((order, order_url)) => {
if let Some(e) = order.get_error() {
cert.warn(&e.prefix("Error").message);
Expand All @@ -112,7 +111,7 @@ pub fn request_certificate(
}
Err(e) => {
if !new_reg && e.is_acme_err(AcmeError::AccountDoesNotExist) {
account.register(endpoint, root_certs)?;
account.register(endpoint)?;
new_reg = true;
} else {
return Err(HttpError::in_err(e));
Expand All @@ -125,7 +124,7 @@ pub fn request_certificate(
for auth_url in order.authorizations.iter() {
// Fetch the authorization
let data_builder = set_empty_data_builder!(account, endpoint_name);
let auth = http::get_authorization(endpoint, root_certs, &data_builder, &auth_url)
let auth = http::get_authorization(endpoint, &data_builder, &auth_url)
.map_err(HttpError::in_err)?;
if let Some(e) = auth.get_error() {
cert.warn(&e.prefix("error").message);
Expand Down Expand Up @@ -158,16 +157,15 @@ pub fn request_certificate(
// Tell the server the challenge has been completed
let chall_url = challenge.get_url();
let data_builder = set_data_builder!(account, endpoint_name, b"{}");
let _ =
http::post_jose_no_response(endpoint, root_certs, &data_builder, &chall_url)
.map_err(HttpError::in_err)?;
let _ = http::post_jose_no_response(endpoint, &data_builder, &chall_url)
.map_err(HttpError::in_err)?;
}
}

// Pool the authorization in order to see whether or not it is valid
let data_builder = set_empty_data_builder!(account, endpoint_name);
let break_fn = |a: &Authorization| a.status == AuthorizationStatus::Valid;
let _ = http::pool_authorization(endpoint, root_certs, &data_builder, &break_fn, &auth_url)
let _ = http::pool_authorization(endpoint, &data_builder, &break_fn, &auth_url)
.map_err(HttpError::in_err)?;
for (data, hook_type) in hook_datas.iter() {
cert.call_challenge_hooks_clean(&data, (*hook_type).to_owned())?;
Expand All @@ -179,7 +177,7 @@ pub fn request_certificate(
// Pool the order in order to see whether or not it is ready
let data_builder = set_empty_data_builder!(account, endpoint_name);
let break_fn = |o: &Order| o.status == OrderStatus::Ready;
let order = http::pool_order(endpoint, root_certs, &data_builder, &break_fn, &order_url)
let order = http::pool_order(endpoint, &data_builder, &break_fn, &order_url)
.map_err(HttpError::in_err)?;

// Finalize the order by sending the CSR
Expand Down Expand Up @@ -209,7 +207,7 @@ pub fn request_certificate(
});
let csr = csr.to_string();
let data_builder = set_data_builder!(account, endpoint_name, csr.as_bytes());
let order = http::finalize_order(endpoint, root_certs, &data_builder, &order.finalize)
let order = http::finalize_order(endpoint, &data_builder, &order.finalize)
.map_err(HttpError::in_err)?;
if let Some(e) = order.get_error() {
cert.warn(&e.prefix("error").message);
Expand All @@ -218,16 +216,16 @@ pub fn request_certificate(
// Pool the order in order to see whether or not it is valid
let data_builder = set_empty_data_builder!(account, endpoint_name);
let break_fn = |o: &Order| o.status == OrderStatus::Valid;
let order = http::pool_order(endpoint, root_certs, &data_builder, &break_fn, &order_url)
let order = http::pool_order(endpoint, &data_builder, &break_fn, &order_url)
.map_err(HttpError::in_err)?;

// Download the certificate
let crt_url = order
.certificate
.ok_or_else(|| Error::from("no certificate available for download"))?;
let data_builder = set_empty_data_builder!(account, endpoint_name);
let crt = http::get_certificate(endpoint, root_certs, &data_builder, &crt_url)
.map_err(HttpError::in_err)?;
let crt =
http::get_certificate(endpoint, &data_builder, &crt_url).map_err(HttpError::in_err)?;
storage::write_certificate(&cert.file_manager, &crt.as_bytes())?;

cert.info(&format!(
Expand Down
25 changes: 7 additions & 18 deletions acmed/src/acme_proto/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::set_data_builder;
use acme_common::error::Error;

macro_rules! create_account_if_does_not_exist {
($e: expr, $endpoint: ident, $root_certs: ident, $account: ident) => {
($e: expr, $endpoint: ident, $account: ident) => {
match $e {
Ok(r) => Ok(r),
Err(he) => match he {
Expand All @@ -20,7 +20,7 @@ macro_rules! create_account_if_does_not_exist {
$endpoint.name
);
$account.debug(&msg);
return register_account($endpoint, $root_certs, $account);
return register_account($endpoint, $account);
}
_ => Err(HttpError::in_err(he.to_owned())),
},
Expand All @@ -30,11 +30,7 @@ macro_rules! create_account_if_does_not_exist {
};
}

pub fn register_account(
endpoint: &mut Endpoint,
root_certs: &[String],
account: &mut BaseAccount,
) -> Result<(), Error> {
pub fn register_account(endpoint: &mut Endpoint, account: &mut BaseAccount) -> Result<(), Error> {
account.debug(&format!(
"creating account on endpoint \"{}\"...",
&endpoint.name
Expand All @@ -47,7 +43,7 @@ pub fn register_account(
let data_builder =
|n: &str, url: &str| encode_jwk(kp_ref, signature_algorithm, acc_ref.as_bytes(), url, n);
let (acc_rep, account_url) =
http::new_account(endpoint, root_certs, &data_builder).map_err(HttpError::in_err)?;
http::new_account(endpoint, &data_builder).map_err(HttpError::in_err)?;
account.set_account_url(&endpoint.name, &account_url)?;
let orders_url = match acc_rep.orders {
Some(url) => url,
Expand Down Expand Up @@ -75,7 +71,6 @@ pub fn register_account(

pub fn update_account_contacts(
endpoint: &mut Endpoint,
root_certs: &[String],
account: &mut BaseAccount,
) -> Result<(), Error> {
let endpoint_name = endpoint.name.clone();
Expand All @@ -89,9 +84,8 @@ pub fn update_account_contacts(
let data_builder = set_data_builder!(account, endpoint_name, acc_up_struct.as_bytes());
let url = account.get_endpoint(&endpoint_name)?.account_url.clone();
create_account_if_does_not_exist!(
http::post_jose_no_response(endpoint, root_certs, &data_builder, &url),
http::post_jose_no_response(endpoint, &data_builder, &url),
endpoint,
root_certs,
account
)?;
account.update_contacts_hash(&endpoint_name)?;
Expand All @@ -103,11 +97,7 @@ pub fn update_account_contacts(
Ok(())
}

pub fn update_account_key(
endpoint: &mut Endpoint,
root_certs: &[String],
account: &mut BaseAccount,
) -> Result<(), Error> {
pub fn update_account_key(endpoint: &mut Endpoint, account: &mut BaseAccount) -> Result<(), Error> {
let endpoint_name = endpoint.name.clone();
account.debug(&format!(
"updating account key on endpoint \"{}\"...",
Expand Down Expand Up @@ -137,9 +127,8 @@ pub fn update_account_key(
)
};
create_account_if_does_not_exist!(
http::post_jose_no_response(endpoint, root_certs, &data_builder, &url),
http::post_jose_no_response(endpoint, &data_builder, &url),
endpoint,
root_certs,
account
)?;
account.update_key_hash(&endpoint_name)?;
Expand Down
Loading

0 comments on commit 9ec48e7

Please sign in to comment.