The account public and private keys are stored in files with names
derives from the account name itself. Because the account name may
contain characters incompatible with a file name, it needs to be
sanitized. Additionally, the account files does not need to be publicly
accessed, therefore their name should only be deterministic. This last
property allows to use a simple solution for sanitation: encode the name
in base64. This way, it is deterministic, unique for each account and
only contains safe characters.
Note the base64 variant used is, as for the ACME protocol, the one with
the URL and filename safe alphabet
https://tools.ietf.org/html/rfc4648#section-5
Some errors, like the badNonce one, are recoverable. Hence, the client
is expected to retry. ACMEd will now re-send the associated request
until it succeed or the max retries number is reached. Each retry is
preceded by a small waiting time in order to let the server recover in
case it was faulty.
Before this commit, the configuration would be considered invalid if at
least one hook and one group were not present. For obvious reasons,
groups, which are simply an ordered aggregation of hooks, should be
optional. On the other hand, hooks may seem mandatory since it is the
only way to validate a challenge. However, this is false in some
circumstances, for example in a test environment when running the client
against a test server that does not perform challenge validation.
https://github.com/letsencrypt/pebble#skipping-validation
As stated in the RFC 8555, the client should explicitly ask the user for
the terms of service agreement. In the case of ACMEd, the retained
method is to ask for a `tos_agreed` field to be set to true or false in
the configuration. This field has been set in the endpoint object rather
than in the account one because the same account can be used on multiple
endpoints.
Defining an account solely by an email address is not the best strategy
since the ACME protocol does not require it and also allows for more
contacts information. Although this commit does not change the "one
email" policy, it sets the bases so it could evolve in the future.
In release mode, the executable size should be kept to the bare minimum
in order to be used in environments with low storage and reduce the data
consumption when pre-built packages are downloaded. Because performance
is absolutely not needed, it allows to a quite aggressive compiling
strategy (opt-level = 'z').
https://doc.rust-lang.org/cargo/reference/manifest.html#the-profile-sectionsFixes#1
Although the `acme-lib` crate comes very handy when creating a simple
ACME client, a more advanced one may not want to use it. First of all,
`acme-lib` does not support all of the ACME specification, some very
interesting one are not implemented. Also, it does not store the account
public key, which does not allow to revoke certificates.
In addition to those two critical points, I would also add `acme-lib`
has some troubles with its own dependencies: it uses both `openssl` and
`ring`, which is redundant and contribute to inflate the size of the
binary. Some of the dependencies also makes an excessive use of logging:
even if logging is very useful, in some cases it really is too much and
debugging becomes a nightmare.
ref #1
Due to a bug in the `acme-lib` dependency, the Certificate Signing
Request was not built correctly. This issue caused the ACME server to
reject such CSR when ordiring more than two domains.
algesten/acme-lib#3
Not doing so may result in race conditions, hence breaking the promise
that hooks are called in sequential order.
Also, debug output has been added to the hooks.
It is considered a good practice to archive old certificates and private
keys instead of simply dropping them away. Because ACMEd should not
impose a way of doing things to system administrators, hooks are the way
to go.
Some configurations may require to run the same bunch of hooks for
several domains. In order to limit repetition, it is now possible to
create a group that will reference to hooks or hook groups.
When hooks are called, there is an option to feed stdin with a custom
string. However, if any error happen, the .unwrap() causes the daemon
to panic. This fix transforms it into an error than can be handled.
The default behavior of most ACME clients is to generate a new key pair
at each renewal. While this choice is respectable and perfectly
justified in most configuration, it is also quite incompatible with the
use of HTTP Public Key Pinning (HPKP). Although HPKP is not wildly
supported and sometimes deprecated, users wishing to use it should not
be blocked.
https://tools.ietf.org/html/rfc7469https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning
Both markdown and CommonMark support only 2 level of heading underline.
A third level using the `~` character is only supported as an extension
in some implementations. While GitHub and most software do not support
it, it is a better choice to switch to ATX headings.
https://daringfireball.net/projects/markdown/syntaxhttps://spec.commonmark.org/