1
0
Fork 0
forked from forgejo/forgejo

[Vendor] update certmagic (#15590)

* update github.com/caddyserver/certmagic v0.12.0 -> v0.13.0

* migrate
This commit is contained in:
6543 2021-04-22 22:42:33 +02:00 committed by GitHub
parent e7fc078891
commit 8ea1d32bea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
177 changed files with 4725 additions and 1984 deletions

View file

@ -123,22 +123,19 @@ type tlsALPNSolver struct {
// Present adds the certificate to the certificate cache and, if
// needed, starts a TLS server for answering TLS-ALPN challenges.
func (s *tlsALPNSolver) Present(ctx context.Context, chal acme.Challenge) error {
// load the certificate into the cache; this isn't strictly necessary
// if we're using the distributed solver since our GetCertificate
// function will check storage for the keyAuth anyway, but it seems
// like loading it into the cache is the right thing to do
// we pre-generate the certificate for efficiency with multi-perspective
// validation, so it only has to be done once (at least, by this instance;
// distributed solving does not have that luxury, oh well) - update the
// challenge data in memory to be the generated certificate
cert, err := acmez.TLSALPN01ChallengeCert(chal)
if err != nil {
return err
}
certHash := hashCertificateChain(cert.Certificate)
s.config.certCache.mu.Lock()
s.config.certCache.cache[tlsALPNCertKeyName(chal.Identifier.Value)] = Certificate{
Certificate: *cert,
Names: []string{chal.Identifier.Value},
hash: certHash, // perhaps not necesssary
}
s.config.certCache.mu.Unlock()
activeChallengesMu.Lock()
chalData := activeChallenges[chal.Identifier.Value]
chalData.data = cert
activeChallenges[chal.Identifier.Value] = chalData
activeChallengesMu.Unlock()
// the rest of this function increments the
// challenge count for the solver at this
@ -273,13 +270,6 @@ func (s *DNS01Solver) Present(ctx context.Context, challenge acme.Challenge) err
dnsName := challenge.DNS01TXTRecordName()
keyAuth := challenge.DNS01KeyAuthorization()
rec := libdns.Record{
Type: "TXT",
Name: dnsName,
Value: keyAuth,
TTL: s.TTL,
}
// multiple identifiers can have the same ACME challenge
// domain (e.g. example.com and *.example.com) so we need
// to ensure that we don't solve those concurrently and
@ -292,6 +282,13 @@ func (s *DNS01Solver) Present(ctx context.Context, challenge acme.Challenge) err
return fmt.Errorf("could not determine zone for domain %q: %v", dnsName, err)
}
rec := libdns.Record{
Type: "TXT",
Name: libdns.RelativeName(dnsName+".", zone),
Value: keyAuth,
TTL: s.TTL,
}
results, err := s.DNSProvider.AppendRecords(ctx, zone, []libdns.Record{rec})
if err != nil {
return fmt.Errorf("adding temporary record for zone %s: %w", zone, err)
@ -458,20 +455,19 @@ func (mmu *mapMutex) locked(key interface{}) (ok bool) {
// sharing sync and storage, and using the facilities provided by
// this package for solving the challenges.
type distributedSolver struct {
// The config with a certificate cache
// with a reference to the storage to
// use which is shared among all the
// instances in the cluster - REQUIRED.
acmeManager *ACMEManager
// The storage backing the distributed solver. It must be
// the same storage configuration as what is solving the
// challenge in order to be effective.
storage Storage
// The storage key prefix, associated with the issuer
// that is solving the challenge.
storageKeyIssuerPrefix string
// Since the distributedSolver is only a
// wrapper over an actual solver, place
// the actual solver here.
solver acmez.Solver
// The CA endpoint URL associated with
// this solver.
caURL string
}
// Present invokes the underlying solver's Present method
@ -483,7 +479,7 @@ func (dhs distributedSolver) Present(ctx context.Context, chal acme.Challenge) e
return err
}
err = dhs.acmeManager.config.Storage.Store(dhs.challengeTokensKey(chal.Identifier.Value), infoBytes)
err = dhs.storage.Store(dhs.challengeTokensKey(chal.Identifier.Value), infoBytes)
if err != nil {
return err
}
@ -495,10 +491,18 @@ func (dhs distributedSolver) Present(ctx context.Context, chal acme.Challenge) e
return nil
}
// Wait wraps the underlying solver's Wait() method, if any. Implements acmez.Waiter.
func (dhs distributedSolver) Wait(ctx context.Context, challenge acme.Challenge) error {
if waiter, ok := dhs.solver.(acmez.Waiter); ok {
return waiter.Wait(ctx, challenge)
}
return nil
}
// CleanUp invokes the underlying solver's CleanUp method
// and also cleans up any assets saved to storage.
func (dhs distributedSolver) CleanUp(ctx context.Context, chal acme.Challenge) error {
err := dhs.acmeManager.config.Storage.Delete(dhs.challengeTokensKey(chal.Identifier.Value))
err := dhs.storage.Delete(dhs.challengeTokensKey(chal.Identifier.Value))
if err != nil {
return err
}
@ -511,7 +515,7 @@ func (dhs distributedSolver) CleanUp(ctx context.Context, chal acme.Challenge) e
// challengeTokensPrefix returns the key prefix for challenge info.
func (dhs distributedSolver) challengeTokensPrefix() string {
return path.Join(dhs.acmeManager.storageKeyCAPrefix(dhs.caURL), "challenge_tokens")
return path.Join(dhs.storageKeyIssuerPrefix, "challenge_tokens")
}
// challengeTokensKey returns the key to use to store and access
@ -607,6 +611,15 @@ func dialTCPSocket(addr string) error {
return err
}
// GetACMEChallenge returns an active ACME challenge for the given identifier,
// or false if no active challenge for that identifier is known.
func GetACMEChallenge(identifier string) (Challenge, bool) {
activeChallengesMu.Lock()
chalData, ok := activeChallenges[identifier]
activeChallengesMu.Unlock()
return chalData, ok
}
// The active challenge solvers, keyed by listener address,
// and protected by a mutex. Note that the creation of
// solver listeners and the incrementing of their counts
@ -616,8 +629,56 @@ var (
solversMu sync.Mutex
)
// activeChallenges holds information about all known, currently-active
// ACME challenges, keyed by identifier. CertMagic guarantees that
// challenges for the same identifier do not overlap, by its locking
// mechanisms; thus if a challenge comes in for a certain identifier,
// we can be confident that if this process initiated the challenge,
// the correct information to solve it is in this map. (It may have
// alternatively been initiated by another instance in a cluster, in
// which case the distributed solver will take care of that.)
var (
activeChallenges = make(map[string]Challenge)
activeChallengesMu sync.Mutex
)
// Challenge is an ACME challenge, but optionally paired with
// data that can make it easier or more efficient to solve.
type Challenge struct {
acme.Challenge
data interface{}
}
// solverWrapper should be used to wrap all challenge solvers so that
// we can add the challenge info to memory; this makes challenges globally
// solvable by a single HTTP or TLS server even if multiple servers with
// different configurations/scopes need to get certificates.
type solverWrapper struct{ acmez.Solver }
func (sw solverWrapper) Present(ctx context.Context, chal acme.Challenge) error {
activeChallengesMu.Lock()
activeChallenges[chal.Identifier.Value] = Challenge{Challenge: chal}
activeChallengesMu.Unlock()
return sw.Solver.Present(ctx, chal)
}
func (sw solverWrapper) Wait(ctx context.Context, chal acme.Challenge) error {
if waiter, ok := sw.Solver.(acmez.Waiter); ok {
return waiter.Wait(ctx, chal)
}
return nil
}
func (sw solverWrapper) CleanUp(ctx context.Context, chal acme.Challenge) error {
activeChallengesMu.Lock()
delete(activeChallenges, chal.Identifier.Value)
activeChallengesMu.Unlock()
return sw.Solver.CleanUp(ctx, chal)
}
// Interface guards
var (
_ acmez.Solver = (*DNS01Solver)(nil)
_ acmez.Waiter = (*DNS01Solver)(nil)
_ acmez.Solver = (*solverWrapper)(nil)
_ acmez.Waiter = (*solverWrapper)(nil)
_ acmez.Waiter = (*distributedSolver)(nil)
)