Commit Graph

50 Commits

Author SHA1 Message Date
Nick Ubels
3bad5b6bb5
Check for .internal with SubjectIsInternal (#305) 2024-08-09 18:24:33 -06:00
Matthew Holt
5ee48a3108
Add config option to disable ARI
This may be temporary until ARI is more mature
2024-08-08 08:08:29 -06:00
Matt Holt
0e88b3eaa1
Initial implementation of ARI (#286)
* Initial implementation of ARI

* Enhance redundancy, robustness, and logging

* Improve ARI updating; integrate on-demand TLS; detect changed window
2024-05-07 09:46:03 -06:00
Matthew Holt
f7ea6fb698
Enhancements to make ZeroSSL issuer more usable in Caddy 2024-04-11 12:23:53 -06:00
Matthew Holt
b29d2a03a0
Implement SubjectTransformer
This makes it possible to replace cert subjects with wildcards, for example

Related: #280
2024-04-08 13:35:09 -06:00
Matt Holt
6095ab8069
Initial implementation of ZeroSSL API issuer (#279)
* Initial implementation of ZeroSSL API issuer

Still needs CA support for CommonName-less certs

* Accommodate ZeroSSL CSR requirements; fix DNS prop check

* Fix README example

* Fix comment
2024-04-08 10:59:55 -06:00
Matthew Holt
3dd8f7da62 Log warning if manually-loaded cert has expired
Or is expiring soon

See https://github.com/caddyserver/caddy/issues/6016
2024-01-08 08:45:02 -07:00
Matthew Holt
66685874a8
Add .home.arpa to internal-only hostnames 2023-09-05 09:38:56 -06:00
Matthew Holt
fb1700b298
Getter method for cert hash
Useful downstream where we need to see if cache has a specific cert
2023-07-09 21:47:35 -06:00
Matthew Holt
93a28b732a
Make cache options updateable; new remove methods
These are useful for advanced applications (like Caddy) which would
like to remove certificates from the
cache in a controlled way, and operate the
cache with new settings while running.
2023-07-08 09:56:51 -06:00
Matt Holt
8728b186fa
Refactor Managers into on-demand config (#231) 2023-05-11 12:36:44 -06:00
Matthew Holt
5deb7c2fb0 Make logger values required
Eliminates a bajillion nil checks and footguns
(except in tests, which bypass exported APIs, but that is expected)

Most recent #207

Logging can still be disabled via zap.NewNop(), if necessary.
(But disabling logging in CertMagic is a really bad idea.)
2022-09-26 10:19:30 -06:00
Matthew Holt
bb468ce4b4
Change OnEvent function; emit more events
OnEvent can now control basic program flow for certain events.
For example, it can cancel cert_obtaining or cert_renewing from happening.

Slight API change adds context and changes to map[string]any for data.
This is easier to work with in practice and conforms more with Caddy's
new event system.
2022-08-26 12:17:10 -06:00
Ben Burkert
871b774821
Add one second (at most) to account for NotAfter imprecision (#199)
Fix #197
2022-08-16 18:08:34 -06:00
Matthew Holt
5981e55018
Fix race conditions (close #195)
Also update setting acmez.Client.Logger in accordance
with latest acmez commit, which removes redundant
logger.
2022-08-01 23:04:11 -06:00
Dave Henderson
9a56fcd4f9
Propagate context in the Storage interface methods (#155)
* Add context propagation to the Storage interface

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

* Bump to Go 1.17

* Minor cleanup

* filestorage: Honor context cancellation in List()

Co-authored-by: Matthew Holt <mholt@users.noreply.github.com>
2022-03-07 12:26:52 -07:00
Matt Holt
2d114193c3
storage: Require fs.ErrNotExist (fix #168) (#170)
Also stop using the deprecated io/ioutil package.
Update dependencies.
Update Go version in go.mod.
2022-03-07 11:11:20 -07:00
Matt Holt
797d29bcf3
GetCertificate from external certificate sources (Managers) (#163)
This work made possible by Tailscale: https://tailscale.com - thank you to the Tailscale team!

* Implement custom GetCertificate callback

Useful if another entity is managing certificates and can
provide its own dynamically during handshakes.

* Refactor CustomGetCertificate into OnDemandConfig

* Set certs to managed=true

This is only sorta true, but it allows handshake-time maintenance of the
certificates that are cached from CustomGetCertificate.

Our background maintenance routine skips certs that are OnDemand so it
should be fine.

* Change CustomGetCertificate into interface value

Instead of a function

* Case-insensitive subject name comparison

Hostnames are case-insensitive

Also add context to GetCertificate

* Export a couple of outrageously useful functions

* Allow multiple custom certificate getters

Also minor refactoring and enhancements

* Fix tests

* Rename Getter -> Manager; refactor

And don't cache externally managed certs

* Minor updates to comments
2022-02-17 14:37:50 -07:00
Matt Holt
eef59acc1d
Fix force-renewing revoked on-demand certs (#166)
* Fix force-renewing revoked on-demand certs

Follow-up to 9245be5a2f

* One more fix for on-demand logic of revoked certs

* OCSP revocation checks at startup, too

Required significant refactoring, hope it works.
Yet again way too late at night for this...
2022-02-01 09:05:24 -07:00
Matthew Holt
066b08905b
More debug logging (cert selection, handshakes) 2021-08-30 12:54:05 -06:00
Matt Holt
07f7d0dec1
Allow forced renewals; fix renew on OCSP revoke; change key on compromise (#134)
* Begin refactor of ObtainCert and RenewCert to allow force renews

* Don't reuse private key in case of revocation due to key compromise

* Improve logging in renew

* Run OCSP check at start of cache maintenance

Otherwise we wait until first tick (currently 1 hour) which might be too long

* Fix obtain; move some things around

Obtain now tries to reuse private key if exists, but if it doesn't exist, that shouldn't be an error (so we clear the error in that case).

Moved the removal of compromised private keys to have logging make more sense.
2021-06-12 13:47:47 -06:00
Matthew Holt
df1d58e0e1
Improve wildcard matching tests
Honoring RFC 2818
2021-02-10 14:36:08 -07:00
Matthew Holt
5a926ec14f
Update subject certificate qualifications
I suppose * is a valid subject -- technically -- but it probably won't
be accepted by browsers. They usually only accept wildcards
for subdomains.

Related, but only tangentially:
https://github.com/caddyserver/caddy/issues/3977
2021-01-19 14:53:32 -07:00
Matthew Holt
725b69d53d
Configurable OCSP stapling
Allows disabling it entirely, or overriding responder URLs

See https://github.com/caddyserver/caddy/issues/3714
2021-01-07 15:45:22 -07:00
Matt Holt
0f8a9f6887
Implement multiple issuer support (#109)
* Implement multiple issuer support

This change refactors Config.Issuer to be Config.Issuers, an array of
issuers. Each Issuer will be tried in turn until one succeeds. During
retries, each attempt will try each configured Issuer. When loading
certs from storage, CertMagic will look in each Issuer's storage
location for a qualifying asset. If multiple Issuers have one in storage
then the most-recently-issued cert will be selected.

This is a breaking change in that Config now accepts a slice of Issuers
rather than a single Issuer. The Revoker field is removed, as supporting
it is optional anyway. If the Issuer is also a Revoker, it can be used
implicitly to revoke certificates.

Also added a const for ZeroSSL's ACME endpoint.

* Load matching wildcard on-demand from storage

With this change, a config using on-demand TLS can load a certificate
for "sub.example.com" from storage using a matching  wildcard cert
(i.e. "*.example.com") if no better matching certificate is available.

* Fix distributed solving with tls-alpn challenges

The type assertion in handshake.go was problematic since there's no
guarantee that an ACME issuer would be a concrete ACMEManager type.

Refactored the code to accept IssuerKey values generally, rather than
specific ACMEManager values only.

This fixes solving tls-alpn challenges in distributed settings.

More cleanup can be done, another time.
2020-11-16 10:53:41 -07:00
Matthew Holt
90d1550af4
Refactor subject qualification logic
This is necessary to support a nuance in Caddy where we have to see if a
subject qualifies for a public certificate but with custom wildcard
checking. So we separate the wildcard check from other checks.
2020-10-21 09:08:19 -06:00
Matthew Holt
81657a2337
Lower max stack trace size
64 MB... what was I thinking?
2020-09-17 12:16:14 -06:00
Matthew Holt
e7f9729bad
Renew managed on-demand certificates at handshake-time if necessary
If the machine goes to sleep or the process gets suspended, background
maintenance won't happen, so we need to check for expiration of all
managed, on-demand certificates at every handshake. Fortunately, this is
pretty cheap because it's simple date math.

https://caddy.community/t/local-certificates-not-renewing-on-demand/9482
2020-08-17 12:14:46 -06:00
Matthew Holt
e6076585c0
Convert (most of the library) to structured logs (closes #19)
Logging is now configurable through setting the Logging field on the
various relevant struct types. This is a more useful, consistent, and
higher-performing experience with logs than the std lib logger we used
before.

This isn't a 100% complete transition because there are some parts of
the code base that don't have obvious or easy access to a logger.
They are mostly fringe/edge cases though, and most are error logs, so
you shouldn't see them under normal circumstances. They still emit to
the std lib logger, so it's not like any errors get hidden: they are
just unstructured until we find a way to give them access to a logger.
2020-07-29 19:38:12 -06:00
Matthew Holt
0a90841d31
Consider client's signature support when choosing certificates
This allows two certs (say, RSA and ECDSA) for the same names to be
loaded, and CertMagic will consider which one the client supports and
use that.

We used to extract just select fields from the leaf certificate so that
we didn't need to fill memory with more data than necessary, but in
order to use the stdlib's SupportsCertificate() method, we have to keep
the full tls.Certificate.Leaf field set for speed during handshakes.
2020-04-01 18:25:02 -06:00
Matthew Holt
6c5ba250d1
Add MatchWildcard() method for comparing names with wildcards
CertMagic currently does wildcard matching in two places:
- Cache.AllMatchingCertificates() for finding all certs in cache
- Config.getCertificate() for finding one cert in cache at handshake

But those implementations will not use MatchWildcard() because their
looping logic is slightly customized.

Caddy, however, has need to compare DNS names with wildcards in at
least two places:
- Matching TLS connection policies by ServerName (SNI)
- Matching TLS automation policies by subject names

So this function is a good implementation for that.
2020-03-26 13:58:05 -06:00
Matthew Holt
6000a83cf1
Add .local TLD to list of internal-only names
Also improve comment on Storage interface's Delete method.
2020-03-23 13:34:23 -06:00
Matthew Holt
73714d1207
Minor tweak 2020-03-17 21:01:38 -06:00
Matthew Holt
e9f9f60183
Separate logic for qualifying names for any cert vs. public certs 2020-03-13 19:09:36 -06:00
Matthew Holt
5265f2bcb1
Rename function 2020-03-12 16:02:48 -06:00
Matthew Holt
11467829d4
Update HostQualifies logic to be specific for public certs
Because CertMagic can now be used for more than just publicly-trusted
certificates.
2020-03-07 18:56:16 -07:00
Matthew Holt
8a7197beca
Change renewal window to a ratio of cert lifetime instead of hard coded
This allows CertMagic to accommodate certificates with extremely short
lifetimes (new defaults work with cert lifetimes < 24h, but I wouldn't
want to push it < 30m with these defaults).
2020-02-24 18:42:27 -07:00
Matthew Holt
37e754b40c
Major refactor to improve performance, correctness, and extensibility
Breaking changes; thank goodness we're not 1.0 yet 😅 - read on!

This change completely separates ACME-specific code from the rest of the
certificate management process, allowing pluggable sources for certs
that aren't ACME.

Notably, most of Config was spliced into ACMEManager. Similarly, there's
now Default and DefaultACME.

Storage structure had to be reconfigured. Certificates are no longer in
the acme/ subfolder since they can be obtained by ways other than ACME!
Certificates moved to a new certificates/ subfolder. The subfolders in
that folder use the path of the ACME endpoint instead of just the host,
so that also changed. Be aware that unless you move your certs over,
CertMagic will not find them and will attempt to get new ones. That is
usually fine for most users, but for extremely large deployments, you
will want to move them over first.

Old certs path:
  acme/acme-staging-v02.api.letsencrypt.org/...

New certs path:
  certificates/acme-staging-v02.api.letsencrypt.org-directory/...

That's all for significant storage changes!

But this refactor also vastly improves performance, especially at scale,
and makes CertMagic way more resilient to errors. Retries are done on
the staging endpoint by default, so they won't count against your rate
limit. If your hardware can handle it, I'm now pretty confident that you
can give CertMagic a million domain names and it will gracefully manage
them, as fast as it can within internal and external rate limits, even
in the presence of errors. Errors will of course slow some things down,
but you should be good to go if you're monitoring logs and can fix any
misconfigurations or other external errors!

Several other mostly-minor enhancements fix bugs, especially at scale.
For example, duplicated renewal tasks (that continuously fail) will not
pile up on each other: only one will operate, under exponential backoff.

Closes #50 and fixes #55
2020-02-21 14:32:57 -07:00
Matthew Holt
7311b4680c
Perform OCSP staple updates outside of lock on certCache
Also add some log entries when certs are replaced in cache
2020-01-10 11:18:37 -07:00
Matthew Holt
96223721b8
Reject common special characters in HostQualifies 2019-10-14 13:58:44 -06:00
Matthew Holt
5dca2331a8
Attempt to replace managed certs when OCSP status is Revoked 2019-09-18 06:00:34 -06:00
Matthew Holt
6a42ef9fe8
Optional tags for unmanaged certificates
This allows for user-loaded certificates to be associated with arbitrary
values such as user-provided IDs or categories. This can be useful if
multiple certificates satisfy a ClientHello but if a specific one still
needs to be chosen. See for example:
https://github.com/mholt/caddy/issues/2588

This is a breaking API change since we need to expose a tags parameter
to the caching functions, but we're not 1.0 yet so we will try this
API change and see how it goes.
2019-06-24 11:51:58 -06:00
Matthew Holt
2ab9ab6dfa
CertificateSelector interface; CertMetadata embedded struct 2019-05-27 11:49:05 -06:00
Matthew Holt
9f9dd53d26
Add hook for custom certificate selection logic (mholt/caddy#2588) 2019-05-23 16:11:32 -06:00
Matt Holt
8f7a1caa59
Significant refactoring to improve correctness and flexibility (#39)
* Significant refactor

This refactoring expands the capabilities of the library for advanced
use cases, as well as improving the overall architecture, including
possible memory leak fixes if used over a long period with many certs
loaded into memory. This refactor enables using different configs
depending on the certificate.

The public API has changed slightly, however, and arguably it is
slightly less convenient/elegant. I have never quite found the perfect
design for this package, and this certainly isn't it, but I think it's
better than what we had before.

There is still work to be done, but this is a good step forward. I've
decoupled Storage from Cache, and made it easier and more correct for
Configs (and Storage values) to be short-lived. Cache is the only value
that should be long-lived.

Note that CertMagic no longer automatically takes care of storage (i.e.
it used to delete old OCSP staples, but now it doesn't). The functions
to do this are still there and even exported, and now we expect the
application to call the cleanup functions when it wants to.

* Fix little oopsies

* Create Manager abstraction so obtain/renew isn't limited to ACME
2019-04-20 10:44:55 -06:00
Joël Gähwiler
c777edeef8 Use DefaultServerName when SNI missing (#23)
* properly test non sni connections by passing in a fake connection

* added default server name

* Refactor default server name (SNI) implementation
2019-02-02 11:10:17 -07:00
Matt Holt
a3b276a1b4
storage: Replace TryLock and Wait with Lock; simplify FileStorage
* Replace TryLock and Wait with Lock, and check for idempotency (issue #5)

* Fix logic of lock waiter creation in FileStorage (+ improve client log)

* Return from Wait() if lock file becomes stale

* Remove racy deletion of empty lock folder

* move all (FileStorage) methods to (*FileStorage) so assignments to fields like fileStorageNameLocks aren't lost

* rework lock acquisition

* Create lockDir just before lock file creation to reduce the chance that another process calls Unlock() and removes lockDir while we were waiting, preventing us from creating the lock file.
* Use the same strategy that Wait() uses to avoid depending on internal state.

* fix unlock of unlocked mutex

* Move fileStorageNameLocksMu into FileStorage struct

* implement new lockfile removal strategy and simplify the lock acquisition loop.

* readme: Add link to full examples

* Rework file lock obtaining and waiting logic

* Remove not-useful optimization to simplify file-locking logic
2018-12-19 14:25:11 -07:00
Matthew Holt
277fd1bdc5
Use fmt.Errorf; customize HTTPTimeout and UserAgent 2018-12-10 18:52:10 -07:00
Matthew Holt
1f94da1ed1
Compatibility with refactored lego core
lego commit: 42941ccea6b431ebff203d4cb520991fb7b47951
2018-12-10 00:26:09 -07:00
Matthew Holt
bea13a36c8
Initial commit 2018-12-09 20:15:26 -07:00