If someone used the example the way it was defined, file-access issues
may arise. This new example add two new hooks to fix it. The example
should now work in most environment although the path may need to be
adapted.
Documentation is a crucial point for every project, and the most
effective and traditional way to document a program is to write man
page. Here, the mdoc is used because it is simple.
Because the documentation is quite different from the project itself,
the man pages and others helpful files are distributed under a different
license. For this usage, the GNU All-Permissive License is adequate.
https://www.gnu.org/prep/maintain/html_node/License-Notices-for-Other-Files.html
man 7 groff_mdoc
The previous system was too limited when it comes to flexibility using
hooks. This limitation came from the false idea that, for a given
certificate, all challenges must be validated with the same method. In
order to prove that false, domains in a certificate can now make use of
any challenge type available.
In order to be more flexible, hooks are now given a type and are defined
in the same registry (instead of 6). Each one will be called when
considered relevant based on its type.
Sometimes, it is not possible to use certificates signed by a known
certificate authority. Hence, in order to prevent a TLS error, it is
required to explicitly add a new trusted root certificate.
This is the case with Pebble, which provides the certificate.
https://github.com/letsencrypt/pebble#avoiding-client-https-errors
AlpnError::ALERT_FATAL has been added in OpenSSL 1.1.0, hence build will
fail on any previous version. This commit allows older versions to fall
back to AlpnError::NOACK instead.
ACMEd should and will remain as simple as possible and let the user
alone take care of the challenge validation. However, this philosophy
does not forbid the project itself to distribute additional tools that
are designed to improve the user experience. Because the TLS-ALPN
ecosystem is currently very slim, adding tacd is really benefic to
ACMEd.
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.