Skip to content
This repository has been archived by the owner on Jul 30, 2020. It is now read-only.

Commit

Permalink
autocert: create a Policy struct for SAN handling
Browse files Browse the repository at this point in the history
the previous setup of having an array of SANs with the 0th element used
as the CommonName was very confusing. Just make things explicit with a
struct.
  • Loading branch information
Brandon Philips committed Jul 31, 2019
1 parent cca79e4 commit 3204c66
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 39 deletions.
28 changes: 17 additions & 11 deletions autocert/autocert.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func AcceptTOS(tosURL string) bool { return true }
// It returns a non-nil error if the host should be rejected.
// The returned error is accessible via tls.Conn.Handshake and its callers.
// See Manager's HostPolicy field and GetCertificate method docs for more details.
type HostPolicy func(ctx context.Context, host string) ([]string, error)
type HostPolicy func(ctx context.Context, host string) (Policy, error)

// HostWhitelist returns a policy where only the specified host names are allowed.
// Only exact matches are currently supported. Subdomains, regexp or wildcard
Expand All @@ -74,17 +74,22 @@ func HostWhitelist(hosts ...string) HostPolicy {
whitelist[h] = true
}
}
return func(_ context.Context, host string) ([]string, error) {
return func(_ context.Context, host string) (Policy, error) {
if !whitelist[host] {
return []string{}, fmt.Errorf("acme/autocert: host %q not configured in HostWhitelist", host)
return Policy{}, fmt.Errorf("acme/autocert: host %q not configured in HostWhitelist", host)
}
return []string{host}, nil
return Policy{CommonName: host}, nil
}
}

type Policy struct {
CommonName string
DNSNames []string
}

// defaultHostPolicy is used when Manager.HostPolicy is not set.
func defaultHostPolicy(_ context.Context, host string) ([]string, error) {
return []string{host}, nil
func defaultHostPolicy(_ context.Context, host string) (Policy, error) {
return Policy{CommonName: host}, nil
}

// Manager is a stateful certificate manager built on top of acme.Client.
Expand Down Expand Up @@ -270,7 +275,7 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
defer cancel()

// get the sans for this hostname and validate it is OK
san, err := m.hostPolicy()(ctx, strings.TrimSuffix(name, "."))
policy, err := m.hostPolicy()(ctx, strings.TrimSuffix(name, "."))
if err != nil {
return nil, err
}
Expand All @@ -292,9 +297,6 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
return nil, fmt.Errorf("acme/autocert: no token cert for %q", name)
}

// from here on out the name should only be the CN
name = san[0]

// regular domain
ck := certKey{
domain: strings.TrimSuffix(name, "."), // golang.org/issue/18114
Expand All @@ -308,7 +310,7 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
return nil, err
}

cert, err = m.createCert(ctx, ck, san)
cert, err = m.createCert(ctx, ck, policy.DNSNames)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -659,6 +661,10 @@ func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck cert
return nil, nil, err
}

if err := m.verify(ctx, client, ck.domain); err != nil {
return nil, nil, err
}

for _, domain := range san {
if err := m.verify(ctx, client, domain); err != nil {
return nil, nil, err
Expand Down
53 changes: 25 additions & 28 deletions rget/cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,19 +100,6 @@ func (r sumRepo) handler(resp http.ResponseWriter, req *http.Request) {
resp.WriteHeader(http.StatusOK)
return
}
err = gc.Put(context.Background(), sums.ShortDomain(), sha256file)
if err != nil {
fmt.Printf("git put error: %v\n", err)
http.Error(resp, "internal service error", http.StatusInternalServerError)
return
}

err = gc.Put(context.Background(), sums.Domain(), sha256file)
if err != nil {
fmt.Printf("git put error: %v\n", err)
http.Error(resp, "internal service error", http.StatusInternalServerError)
return
}

// Step 3. Create the Certificate object for the domain and save that as well
ctdomain := sums.Domain() + "." + domain
Expand Down Expand Up @@ -159,48 +146,58 @@ func server(cmd *cobra.Command, args []string) {
panic(err)
}

hostPolicyNoLog := func(ctx context.Context, host string) ([]string, error) {
hostPolicyNoLog := func(ctx context.Context, host string) (autocert.Policy, error) {
if rgetwellknown.PublicServiceHost == host {
return []string{host}, nil
return autocert.Policy{CommonName: host}, nil
}

if !strings.HasSuffix(host, "."+rgetwellknown.PublicServiceHost) {
return nil, fmt.Errorf("not in TLD %v", rgetwellknown.PublicServiceHost)
return autocert.Policy{}, fmt.Errorf("not in TLD %v", rgetwellknown.PublicServiceHost)
}

key := strings.TrimSuffix(host, "."+rgetwellknown.PublicServiceHost)

// Reduce to the shortest domain
parts := strings.Split(key, ".")
if len(parts) == 0 {
return nil, errors.New("common name empty")
return autocert.Policy{}, errors.New("common name empty")
}
key = parts[0]

_, err := pubgc.Get(ctx, key)
matches, err := pubgc.Prefix(ctx, key)
if err != nil {
return autocert.Policy{}, err
}

if len(matches) != 1 {
fmt.Printf("unknown merkle prefix %v for %v\n", key, host)
// TODO(philips): leak a nicer error
return nil, err
}

matches, err := pubgc.Prefix(ctx, key)
content, err := pubgc.Get(ctx, matches[0])
if err != nil {
return nil, err
fmt.Printf("unknown merkle prefix %v for %v\n", key, host)
// TODO(philips): leak a nicer error
return autocert.Policy{}, err
}

for i := range matches {
matches[i] = matches[i] + "." + rgetwellknown.PublicServiceHost
sums := rgethash.FromSHA256SumFile(string(content))

p := autocert.Policy{
CommonName: sums.ShortDomain() + "." + rgetwellknown.PublicServiceHost,
DNSNames: []string{
matches[1] + "." + rgetwellknown.PublicServiceHost,
sums.Domain() + "." + rgetwellknown.PublicServiceHost,
},
}

return matches, nil
return p, nil
}

hostPolicy := func(ctx context.Context, host string) ([]string, error) {
hostPolicy := func(ctx context.Context, host string) (autocert.Policy, error) {
fmt.Printf("hostPolicy called %v\n", host)
sans, err := hostPolicyNoLog(ctx, host)
policy, err := hostPolicyNoLog(ctx, host)
fmt.Printf("hostPolicy err %v\n", err)
return sans, err
return policy, err
}

m := &autocert.Manager{
Expand Down

0 comments on commit 3204c66

Please sign in to comment.