Skip to content

Commit

Permalink
ACME based certificates, BYOC.
Browse files Browse the repository at this point in the history
  • Loading branch information
can1357 committed Mar 10, 2024
1 parent 347ca40 commit 45837b9
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 3 deletions.
3 changes: 2 additions & 1 deletion vhttp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"get.pme.sh/pmesh/security"
"get.pme.sh/pmesh/urlsigner"
"get.pme.sh/pmesh/xlog"
"golang.org/x/crypto/acme"
)

type ipinfoWrapper struct{ netx.IPInfoProvider }
Expand Down Expand Up @@ -189,7 +190,7 @@ func NewServer(ctx context.Context) (s *Server) {
GetCertificate: s.GetCertificate,
PreferServerCipherSuites: true,
CurvePreferences: []tls.CurveID{tls.CurveP256, tls.X25519},
NextProtos: []string{"h2", "http/1.1"},
NextProtos: []string{"h2", "http/1.1", acme.ALPNProto},
}),
}
s.Server.RegisterOnShutdown(func() { logw.Flush() })
Expand Down
55 changes: 53 additions & 2 deletions vhttp/vhost.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,67 @@ package vhttp

import (
"crypto/tls"
"errors"
"fmt"
"net/http"
"strings"
"sync"
"sync/atomic"

"get.pme.sh/pmesh/config"
"get.pme.sh/pmesh/hosts"
"get.pme.sh/pmesh/netx"
"get.pme.sh/pmesh/security"
"get.pme.sh/pmesh/xlog"
"golang.org/x/crypto/acme/autocert"

"github.com/samber/lo"
)

type CertProvider struct {
CertPath string `yaml:"cert,omitempty"` // Path to the TLS certificate.
KeyPath string `yaml:"key,omitempty"` // Path to the TLS key.
certMu sync.Mutex
cache atomic.Pointer[tls.Certificate]
}

var getLetsEncrypt = sync.OnceValue(func() *autocert.Manager {
return &autocert.Manager{
Prompt: autocert.AcceptTOS,
Cache: autocert.DirCache(config.CertDir.Path()),
}
})

func (cp *CertProvider) GetCertificate(chi *tls.ClientHelloInfo) (cert *tls.Certificate, err error) {
if cp.CertPath == "letsencrypt" {
return getLetsEncrypt().GetCertificate(chi)
} else if cp.CertPath != "" {
if cert = cp.cache.Load(); cert != nil {
return
}

cp.certMu.Lock()
defer cp.certMu.Unlock()
if cert = cp.cache.Load(); cert != nil {
return
}

scert, err := security.LoadCertificate(cp.CertPath, cp.KeyPath)
if err == nil {
cp.cache.Store(scert.TLS)
cert = scert.TLS
}
return cert, err
}
return nil, errors.New("no certificate")
}

type VirtualHostOptions struct {
Hostnames []string `yaml:"-"`
NoUpgrade bool `yaml:"no_upgrade,omitempty"` // Do not upgrade HTTP to HTTPS.
Hostnames []string `yaml:"-"`
NoUpgrade bool `yaml:"no_upgrade,omitempty"` // Do not upgrade HTTP to HTTPS.
Certs map[string]*CertProvider `yaml:"certs,omitempty"` // TLS certificates.
}

type VirtualHost struct {
VirtualHostOptions
Mux
Expand Down Expand Up @@ -140,6 +183,14 @@ func (mux *TopLevelMux) GetCertificate(chi *tls.ClientHelloInfo) (cert *tls.Cert
if sni := chi.ServerName; sni != "" {
_, _, vhg = hosts.MatchMap(unique, sni)
if vhg != nil {
for _, vh := range vhg.hosts {
if vh.Certs != nil {
_, _, prov := hosts.MatchMap(vh.Certs, sni)
if prov != nil {
return prov.GetCertificate(chi)
}
}
}
cert = security.ObtainCertificate(config.Get().Secret, sni).TLS
}
}
Expand Down

0 comments on commit 45837b9

Please sign in to comment.