Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
caddy
Commits
bedad34b
Commit
bedad34b
authored
Sep 14, 2016
by
Matthew Holt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Clean up some significant portions of the TLS management code
parent
0e7635c5
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
112 additions
and
166 deletions
+112
-166
caddyhttp/httpserver/https.go
caddyhttp/httpserver/https.go
+1
-1
caddytls/client.go
caddytls/client.go
+58
-31
caddytls/config.go
caddytls/config.go
+16
-108
caddytls/filestorage.go
caddytls/filestorage.go
+0
-1
caddytls/handshake.go
caddytls/handshake.go
+24
-20
caddytls/maintain.go
caddytls/maintain.go
+13
-5
No files found.
caddyhttp/httpserver/https.go
View file @
bedad34b
...
@@ -23,7 +23,7 @@ func activateHTTPS(cctx caddy.Context) error {
...
@@ -23,7 +23,7 @@ func activateHTTPS(cctx caddy.Context) error {
// place certificates and keys on disk
// place certificates and keys on disk
for
_
,
c
:=
range
ctx
.
siteConfigs
{
for
_
,
c
:=
range
ctx
.
siteConfigs
{
err
:=
c
.
TLS
.
ObtainCert
(
operatorPresent
)
err
:=
c
.
TLS
.
ObtainCert
(
c
.
TLS
.
Hostname
,
operatorPresent
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
...
caddytls/client.go
View file @
bedad34b
...
@@ -18,11 +18,13 @@ import (
...
@@ -18,11 +18,13 @@ import (
// acmeMu ensures that only one ACME challenge occurs at a time.
// acmeMu ensures that only one ACME challenge occurs at a time.
var
acmeMu
sync
.
Mutex
var
acmeMu
sync
.
Mutex
// ACMEClient is an acme.Client with custom state attached.
// ACMEClient is a wrapper over acme.Client with
// some custom state attached. It is used to obtain,
// renew, and revoke certificates with ACME.
type
ACMEClient
struct
{
type
ACMEClient
struct
{
*
acme
.
Client
AllowPrompts
bool
AllowPrompts
bool
config
*
Config
config
*
Config
acmeClient
*
acme
.
Client
}
}
// newACMEClient creates a new ACMEClient given an email and whether
// newACMEClient creates a new ACMEClient given an email and whether
...
@@ -100,7 +102,11 @@ var newACMEClient = func(config *Config, allowPrompts bool) (*ACMEClient, error)
...
@@ -100,7 +102,11 @@ var newACMEClient = func(config *Config, allowPrompts bool) (*ACMEClient, error)
}
}
}
}
c
:=
&
ACMEClient
{
Client
:
client
,
AllowPrompts
:
allowPrompts
,
config
:
config
}
c
:=
&
ACMEClient
{
AllowPrompts
:
allowPrompts
,
config
:
config
,
acmeClient
:
client
,
}
if
config
.
DNSProvider
==
""
{
if
config
.
DNSProvider
==
""
{
// Use HTTP and TLS-SNI challenges by default
// Use HTTP and TLS-SNI challenges by default
...
@@ -116,15 +122,15 @@ var newACMEClient = func(config *Config, allowPrompts bool) (*ACMEClient, error)
...
@@ -116,15 +122,15 @@ var newACMEClient = func(config *Config, allowPrompts bool) (*ACMEClient, error)
// See if TLS challenge needs to be handled by our own facilities
// See if TLS challenge needs to be handled by our own facilities
if
caddy
.
HasListenerWithAddress
(
net
.
JoinHostPort
(
config
.
ListenHost
,
TLSSNIChallengePort
))
{
if
caddy
.
HasListenerWithAddress
(
net
.
JoinHostPort
(
config
.
ListenHost
,
TLSSNIChallengePort
))
{
c
.
SetChallengeProvider
(
acme
.
TLSSNI01
,
tlsSniSolver
{})
c
.
acmeClient
.
SetChallengeProvider
(
acme
.
TLSSNI01
,
tlsSniSolver
{})
}
}
// Always respect user's bind preferences by using config.ListenHost
// Always respect user's bind preferences by using config.ListenHost
err
:=
c
.
SetHTTPAddress
(
net
.
JoinHostPort
(
config
.
ListenHost
,
useHTTPPort
))
err
:=
c
.
acmeClient
.
SetHTTPAddress
(
net
.
JoinHostPort
(
config
.
ListenHost
,
useHTTPPort
))
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
err
=
c
.
SetTLSAddress
(
net
.
JoinHostPort
(
config
.
ListenHost
,
""
))
err
=
c
.
acmeClient
.
SetTLSAddress
(
net
.
JoinHostPort
(
config
.
ListenHost
,
""
))
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
@@ -145,23 +151,50 @@ var newACMEClient = func(config *Config, allowPrompts bool) (*ACMEClient, error)
...
@@ -145,23 +151,50 @@ var newACMEClient = func(config *Config, allowPrompts bool) (*ACMEClient, error)
}
}
// Use the DNS challenge exclusively
// Use the DNS challenge exclusively
c
.
ExcludeChallenges
([]
acme
.
Challenge
{
acme
.
HTTP01
,
acme
.
TLSSNI01
})
c
.
acmeClient
.
ExcludeChallenges
([]
acme
.
Challenge
{
acme
.
HTTP01
,
acme
.
TLSSNI01
})
c
.
SetChallengeProvider
(
acme
.
DNS01
,
prov
)
c
.
acmeClient
.
SetChallengeProvider
(
acme
.
DNS01
,
prov
)
}
}
return
c
,
nil
return
c
,
nil
}
}
// Obtain obtains a single certificate for names. It stores the certificate
// Obtain obtains a single certificate for name. It stores the certificate
// on the disk if successful.
// on the disk if successful. This function is safe for concurrent use.
func
(
c
*
ACMEClient
)
Obtain
(
names
[]
string
)
error
{
//
// Right now our storage mechanism only supports one name per certificate,
// so this function (along with Renew and Revoke) only accepts one domain
// as input. It can be easily modified to support SAN certificates if our
// storage mechanism is upgraded later.
//
// Callers who have access to a Config value should use the ObtainCert
// method on that instead of this lower-level method.
func
(
c
*
ACMEClient
)
Obtain
(
name
string
)
error
{
// Get access to ACME storage
storage
,
err
:=
c
.
config
.
StorageFor
(
c
.
config
.
CAUrl
)
if
err
!=
nil
{
return
err
}
// We must lock the obtain with the storage engine
if
lockObtained
,
err
:=
storage
.
LockRegister
(
name
);
err
!=
nil
{
return
err
}
else
if
!
lockObtained
{
log
.
Printf
(
"[INFO] Certificate for %v is already being obtained elsewhere"
,
name
)
return
nil
}
defer
func
()
{
if
err
:=
storage
.
UnlockRegister
(
name
);
err
!=
nil
{
log
.
Printf
(
"[ERROR] Unable to unlock obtain lock for %v: %v"
,
name
,
err
)
}
}()
Attempts
:
Attempts
:
for
attempts
:=
0
;
attempts
<
2
;
attempts
++
{
for
attempts
:=
0
;
attempts
<
2
;
attempts
++
{
namesObtaining
.
Add
(
names
)
namesObtaining
.
Add
(
[]
string
{
name
}
)
acmeMu
.
Lock
()
acmeMu
.
Lock
()
certificate
,
failures
:=
c
.
ObtainCertificate
(
names
,
true
,
nil
)
certificate
,
failures
:=
c
.
acmeClient
.
ObtainCertificate
([]
string
{
name
}
,
true
,
nil
)
acmeMu
.
Unlock
()
acmeMu
.
Unlock
()
namesObtaining
.
Remove
(
names
)
namesObtaining
.
Remove
(
[]
string
{
name
}
)
if
len
(
failures
)
>
0
{
if
len
(
failures
)
>
0
{
// Error - try to fix it or report it to the user and abort
// Error - try to fix it or report it to the user and abort
var
errMsg
string
// we'll combine all the failures into a single error message
var
errMsg
string
// we'll combine all the failures into a single error message
...
@@ -178,7 +211,7 @@ Attempts:
...
@@ -178,7 +211,7 @@ Attempts:
promptedForAgreement
=
true
promptedForAgreement
=
true
}
}
if
Agreed
||
!
c
.
AllowPrompts
{
if
Agreed
||
!
c
.
AllowPrompts
{
err
:=
c
.
AgreeToTOS
()
err
:=
c
.
acmeClient
.
AgreeToTOS
()
if
err
!=
nil
{
if
err
!=
nil
{
return
errors
.
New
(
"error agreeing to updated terms: "
+
err
.
Error
())
return
errors
.
New
(
"error agreeing to updated terms: "
+
err
.
Error
())
}
}
...
@@ -193,13 +226,9 @@ Attempts:
...
@@ -193,13 +226,9 @@ Attempts:
}
}
// Success - immediately save the certificate resource
// Success - immediately save the certificate resource
storage
,
err
:=
c
.
config
.
StorageFor
(
c
.
config
.
CAUrl
)
if
err
!=
nil
{
return
err
}
err
=
saveCertResource
(
storage
,
certificate
)
err
=
saveCertResource
(
storage
,
certificate
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"error saving assets for %v: %v"
,
name
s
,
err
)
return
fmt
.
Errorf
(
"error saving assets for %v: %v"
,
name
,
err
)
}
}
break
break
...
@@ -208,13 +237,11 @@ Attempts:
...
@@ -208,13 +237,11 @@ Attempts:
return
nil
return
nil
}
}
// Renew renews the managed certificate for name. Right now our storage
// Renew renews the managed certificate for name. This function is
// mechanism only supports one name per certificate, so this function only
// safe for concurrent use.
// accepts one domain as input. It can be easily modified to support SAN
// certificates if, one day, they become desperately needed enough that our
// storage mechanism is upgraded to be more complex to support SAN certs.
//
//
// Anyway, this function is safe for concurrent use.
// Callers who have access to a Config value should use the RenewCert
// method on that instead of this lower-level method.
func
(
c
*
ACMEClient
)
Renew
(
name
string
)
error
{
func
(
c
*
ACMEClient
)
Renew
(
name
string
)
error
{
// Get access to ACME storage
// Get access to ACME storage
storage
,
err
:=
c
.
config
.
StorageFor
(
c
.
config
.
CAUrl
)
storage
,
err
:=
c
.
config
.
StorageFor
(
c
.
config
.
CAUrl
)
...
@@ -251,7 +278,7 @@ func (c *ACMEClient) Renew(name string) error {
...
@@ -251,7 +278,7 @@ func (c *ACMEClient) Renew(name string) error {
for
attempts
:=
0
;
attempts
<
2
;
attempts
++
{
for
attempts
:=
0
;
attempts
<
2
;
attempts
++
{
namesObtaining
.
Add
([]
string
{
name
})
namesObtaining
.
Add
([]
string
{
name
})
acmeMu
.
Lock
()
acmeMu
.
Lock
()
newCertMeta
,
err
=
c
.
RenewCertificate
(
certMeta
,
true
)
newCertMeta
,
err
=
c
.
acmeClient
.
RenewCertificate
(
certMeta
,
true
)
acmeMu
.
Unlock
()
acmeMu
.
Unlock
()
namesObtaining
.
Remove
([]
string
{
name
})
namesObtaining
.
Remove
([]
string
{
name
})
if
err
==
nil
{
if
err
==
nil
{
...
@@ -259,10 +286,10 @@ func (c *ACMEClient) Renew(name string) error {
...
@@ -259,10 +286,10 @@ func (c *ACMEClient) Renew(name string) error {
break
break
}
}
// If the legal terms
changed and need to be agreed to again,
// If the legal terms
were updated and need to be
// we can handle that.
//
agreed to again,
we can handle that.
if
_
,
ok
:=
err
.
(
acme
.
TOSError
);
ok
{
if
_
,
ok
:=
err
.
(
acme
.
TOSError
);
ok
{
err
:=
c
.
AgreeToTOS
()
err
:=
c
.
acmeClient
.
AgreeToTOS
()
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -304,7 +331,7 @@ func (c *ACMEClient) Revoke(name string) error {
...
@@ -304,7 +331,7 @@ func (c *ACMEClient) Revoke(name string) error {
return
err
return
err
}
}
err
=
c
.
Client
.
RevokeCertificate
(
siteData
.
Cert
)
err
=
c
.
acme
Client
.
RevokeCertificate
(
siteData
.
Cert
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
...
caddytls/config.go
View file @
bedad34b
...
@@ -3,13 +3,9 @@ package caddytls
...
@@ -3,13 +3,9 @@ package caddytls
import
(
import
(
"crypto/tls"
"crypto/tls"
"crypto/x509"
"crypto/x509"
"encoding/json"
"errors"
"fmt"
"fmt"
"io/ioutil"
"io/ioutil"
"time"
"log"
"net/url"
"net/url"
"strings"
"strings"
...
@@ -116,24 +112,21 @@ type OnDemandState struct {
...
@@ -116,24 +112,21 @@ type OnDemandState struct {
// If it reaches MaxObtain, on-demand issuances must fail.
// If it reaches MaxObtain, on-demand issuances must fail.
ObtainedCount
int32
ObtainedCount
int32
//
Based on
max_certs in tls config, it specifies the
//
Set from
max_certs in tls config, it specifies the
// maximum number of certificates that can be issued.
// maximum number of certificates that can be issued.
MaxObtain
int32
MaxObtain
int32
}
}
// ObtainCert obtains a certificate for c.Hostname, as long as a certificate
// ObtainCert obtains a certificate for name using c, as long
// does not already exist in storage on disk. It only obtains and stores
// as a certificate does not already exist in storage for that
// certificates (and their keys) to disk, it does not load them into memory.
// name. The name must qualify and c must be flagged as Managed.
// If allowPrompts is true, the user may be shown a prompt. If proxyACME is
// This function is a no-op if storage already has a certificate
// true, the relevant ACME challenges will be proxied to the alternate port.
// for name.
func
(
c
*
Config
)
ObtainCert
(
allowPrompts
bool
)
error
{
//
return
c
.
obtainCertName
(
c
.
Hostname
,
allowPrompts
)
// It only obtains and stores certificates (and their keys),
}
// it does not load them into memory. If allowPrompts is true,
// the user may be shown a prompt.
// obtainCertName gets a certificate for name using the ACME config c
func
(
c
*
Config
)
ObtainCert
(
name
string
,
allowPrompts
bool
)
error
{
// if c and name both qualify. It places the certificate in storage.
// It is a no-op if the storage already has a certificate for name.
func
(
c
*
Config
)
obtainCertName
(
name
string
,
allowPrompts
bool
)
error
{
if
!
c
.
Managed
||
!
HostQualifies
(
name
)
{
if
!
c
.
Managed
||
!
HostQualifies
(
name
)
{
return
nil
return
nil
}
}
...
@@ -142,29 +135,13 @@ func (c *Config) obtainCertName(name string, allowPrompts bool) error {
...
@@ -142,29 +135,13 @@ func (c *Config) obtainCertName(name string, allowPrompts bool) error {
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
siteExists
,
err
:=
storage
.
SiteExists
(
name
)
siteExists
,
err
:=
storage
.
SiteExists
(
name
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
if
siteExists
{
if
siteExists
{
return
nil
return
nil
}
}
// We must lock the obtain with the storage engine
if
lockObtained
,
err
:=
storage
.
LockRegister
(
name
);
err
!=
nil
{
return
err
}
else
if
!
lockObtained
{
log
.
Printf
(
"[INFO] Certificate for %v is already being obtained elsewhere"
,
name
)
return
nil
}
defer
func
()
{
if
err
:=
storage
.
UnlockRegister
(
name
);
err
!=
nil
{
log
.
Printf
(
"[ERROR] Unable to unlock obtain lock for %v: %v"
,
name
,
err
)
}
}()
if
c
.
ACMEEmail
==
""
{
if
c
.
ACMEEmail
==
""
{
c
.
ACMEEmail
=
getEmail
(
storage
,
allowPrompts
)
c
.
ACMEEmail
=
getEmail
(
storage
,
allowPrompts
)
}
}
...
@@ -173,86 +150,17 @@ func (c *Config) obtainCertName(name string, allowPrompts bool) error {
...
@@ -173,86 +150,17 @@ func (c *Config) obtainCertName(name string, allowPrompts bool) error {
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
return
client
.
Obtain
(
name
)
return
client
.
Obtain
([]
string
{
name
})
}
}
// RenewCert renews the certificate for c.Hostname. If there is already a lock
// RenewCert renews the certificate for name using c. It stows the
// on renewal, this will not perform the renewal and no error will occur.
// renewed certificate and its assets in storage if successful.
func
(
c
*
Config
)
RenewCert
(
allowPrompts
bool
)
error
{
func
(
c
*
Config
)
RenewCert
(
name
string
,
allowPrompts
bool
)
error
{
return
c
.
renewCertName
(
c
.
Hostname
,
allowPrompts
)
}
// renewCertName renews the certificate for the given name. If there is already
// a lock on renewal, this will not perform the renewal and no error will
// occur.
func
(
c
*
Config
)
renewCertName
(
name
string
,
allowPrompts
bool
)
error
{
storage
,
err
:=
c
.
StorageFor
(
c
.
CAUrl
)
if
err
!=
nil
{
return
err
}
// We must lock the renewal with the storage engine
if
lockObtained
,
err
:=
storage
.
LockRegister
(
name
);
err
!=
nil
{
return
err
}
else
if
!
lockObtained
{
log
.
Printf
(
"[INFO] Certificate for %v is already being renewed elsewhere"
,
name
)
return
nil
}
defer
func
()
{
if
err
:=
storage
.
UnlockRegister
(
name
);
err
!=
nil
{
log
.
Printf
(
"[ERROR] Unable to unlock renewal lock for %v: %v"
,
name
,
err
)
}
}()
// Prepare for renewal (load PEM cert, key, and meta)
siteData
,
err
:=
storage
.
LoadSite
(
name
)
if
err
!=
nil
{
return
err
}
var
certMeta
acme
.
CertificateResource
err
=
json
.
Unmarshal
(
siteData
.
Meta
,
&
certMeta
)
certMeta
.
Certificate
=
siteData
.
Cert
certMeta
.
PrivateKey
=
siteData
.
Key
client
,
err
:=
newACMEClient
(
c
,
allowPrompts
)
client
,
err
:=
newACMEClient
(
c
,
allowPrompts
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
return
client
.
Renew
(
name
)
// Perform renewal and retry if necessary, but not too many times.
var
newCertMeta
acme
.
CertificateResource
var
success
bool
for
attempts
:=
0
;
attempts
<
2
;
attempts
++
{
namesObtaining
.
Add
([]
string
{
name
})
acmeMu
.
Lock
()
newCertMeta
,
err
=
client
.
RenewCertificate
(
certMeta
,
true
)
acmeMu
.
Unlock
()
namesObtaining
.
Remove
([]
string
{
name
})
if
err
==
nil
{
success
=
true
break
}
// If the legal terms were updated and need to be
// agreed to again, we can handle that.
if
_
,
ok
:=
err
.
(
acme
.
TOSError
);
ok
{
err
:=
client
.
AgreeToTOS
()
if
err
!=
nil
{
return
err
}
continue
}
// For any other kind of error, wait 10s and try again.
time
.
Sleep
(
10
*
time
.
Second
)
}
if
!
success
{
return
errors
.
New
(
"too many renewal attempts; last error: "
+
err
.
Error
())
}
return
saveCertResource
(
storage
,
newCertMeta
)
}
}
// StorageFor obtains a TLS Storage instance for the given CA URL which should
// StorageFor obtains a TLS Storage instance for the given CA URL which should
...
...
caddytls/filestorage.go
View file @
bedad34b
...
@@ -123,7 +123,6 @@ func (s FileStorage) readFile(file string) ([]byte, error) {
...
@@ -123,7 +123,6 @@ func (s FileStorage) readFile(file string) ([]byte, error) {
return
nil
,
ErrNotExist
(
err
)
return
nil
,
ErrNotExist
(
err
)
}
}
return
b
,
err
return
b
,
err
}
}
// SiteExists implements Storage.SiteExists by checking for the presence of
// SiteExists implements Storage.SiteExists by checking for the presence of
...
...
caddytls/handshake.go
View file @
bedad34b
...
@@ -172,22 +172,25 @@ func (cg configGroup) obtainOnDemandCertificate(name string, cfg *Config) (Certi
...
@@ -172,22 +172,25 @@ func (cg configGroup) obtainOnDemandCertificate(name string, cfg *Config) (Certi
return
cg
.
getCertDuringHandshake
(
name
,
true
,
false
)
return
cg
.
getCertDuringHandshake
(
name
,
true
,
false
)
}
}
// looks like it's up to us to do all the work and obtain the cert
// looks like it's up to us to do all the work and obtain the cert.
// make a chan others can wait on if needed
wait
=
make
(
chan
struct
{})
wait
=
make
(
chan
struct
{})
obtainCertWaitChans
[
name
]
=
wait
obtainCertWaitChans
[
name
]
=
wait
obtainCertWaitChansMu
.
Unlock
()
obtainCertWaitChansMu
.
Unlock
()
// Unblock waiters and delete waitgroup when we return
// do the obtain
defer
func
()
{
obtainCertWaitChansMu
.
Lock
()
close
(
wait
)
delete
(
obtainCertWaitChans
,
name
)
obtainCertWaitChansMu
.
Unlock
()
}()
log
.
Printf
(
"[INFO] Obtaining new certificate for %s"
,
name
)
log
.
Printf
(
"[INFO] Obtaining new certificate for %s"
,
name
)
err
:=
cfg
.
ObtainCert
(
name
,
false
)
// immediately unblock anyone waiting for it; doing this in
// a defer would risk deadlock because of the recursive call
// to getCertDuringHandshake below when we return!
obtainCertWaitChansMu
.
Lock
()
close
(
wait
)
delete
(
obtainCertWaitChans
,
name
)
obtainCertWaitChansMu
.
Unlock
()
if
err
:=
cfg
.
obtainCertName
(
name
,
false
);
err
!=
nil
{
if
err
!=
nil
{
// Failed to solve challenge, so don't allow another on-demand
// Failed to solve challenge, so don't allow another on-demand
// issue for this name to be attempted for a little while.
// issue for this name to be attempted for a little while.
failedIssuanceMu
.
Lock
()
failedIssuanceMu
.
Lock
()
...
@@ -208,7 +211,7 @@ func (cg configGroup) obtainOnDemandCertificate(name string, cfg *Config) (Certi
...
@@ -208,7 +211,7 @@ func (cg configGroup) obtainOnDemandCertificate(name string, cfg *Config) (Certi
lastIssueTime
=
time
.
Now
()
lastIssueTime
=
time
.
Now
()
lastIssueTimeMu
.
Unlock
()
lastIssueTimeMu
.
Unlock
()
//
The
certificate is already on disk; now just start over to load it and serve it
// certificate is already on disk; now just start over to load it and serve it
return
cg
.
getCertDuringHandshake
(
name
,
true
,
false
)
return
cg
.
getCertDuringHandshake
(
name
,
true
,
false
)
}
}
...
@@ -265,17 +268,18 @@ func (cg configGroup) renewDynamicCertificate(name string, cfg *Config) (Certifi
...
@@ -265,17 +268,18 @@ func (cg configGroup) renewDynamicCertificate(name string, cfg *Config) (Certifi
obtainCertWaitChans
[
name
]
=
wait
obtainCertWaitChans
[
name
]
=
wait
obtainCertWaitChansMu
.
Unlock
()
obtainCertWaitChansMu
.
Unlock
()
// unblock waiters and delete waitgroup when we return
// do the renew
defer
func
()
{
obtainCertWaitChansMu
.
Lock
()
close
(
wait
)
delete
(
obtainCertWaitChans
,
name
)
obtainCertWaitChansMu
.
Unlock
()
}()
log
.
Printf
(
"[INFO] Renewing certificate for %s"
,
name
)
log
.
Printf
(
"[INFO] Renewing certificate for %s"
,
name
)
err
:=
cfg
.
RenewCert
(
name
,
false
)
// immediately unblock anyone waiting for it; doing this in
// a defer would risk deadlock because of the recursive call
// to getCertDuringHandshake below when we return!
obtainCertWaitChansMu
.
Lock
()
close
(
wait
)
delete
(
obtainCertWaitChans
,
name
)
obtainCertWaitChansMu
.
Unlock
()
err
:=
cfg
.
renewCertName
(
name
,
false
)
if
err
!=
nil
{
if
err
!=
nil
{
return
Certificate
{},
err
return
Certificate
{},
err
}
}
...
...
caddytls/maintain.go
View file @
bedad34b
...
@@ -99,12 +99,20 @@ func RenewManagedCertificates(allowPrompts bool) (err error) {
...
@@ -99,12 +99,20 @@ func RenewManagedCertificates(allowPrompts bool) (err error) {
continue
continue
}
}
// This works well because managed certs are only associated with one name per config.
// Get the name which we should use to renew this certificate;
// Note, the renewal inside here may not actually occur and no error will be returned
// we only support managing certificates with one name per cert,
// due to renewal lock (i.e. because a renewal is already happening). This lack of
// so this should be easy. We can't rely on cert.Config.Hostname
// error is by intention to force cache invalidation as though it has renewed.
// because it may be a wildcard value from the Caddyfile (e.g.
err
:=
cert
.
Config
.
RenewCert
(
allowPrompts
)
// *.something.com) which, as of 2016, is not supported by ACME.
var
renewName
string
for
_
,
name
:=
range
cert
.
Names
{
if
name
!=
""
{
renewName
=
name
break
}
}
err
:=
cert
.
Config
.
RenewCert
(
renewName
,
allowPrompts
)
if
err
!=
nil
{
if
err
!=
nil
{
if
allowPrompts
&&
timeLeft
<
0
{
if
allowPrompts
&&
timeLeft
<
0
{
// Certificate renewal failed, the operator is present, and the certificate
// Certificate renewal failed, the operator is present, and the certificate
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment