OCSP stapling
This commit is contained in:
parent
2949995abc
commit
b39ee8ede5
30 changed files with 1576 additions and 178 deletions
|
|
@ -1,14 +1,22 @@
|
|||
package tls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/patrickmn/go-cache"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/traefik/traefik/v3/pkg/types"
|
||||
"golang.org/x/crypto/ocsp"
|
||||
)
|
||||
|
||||
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
|
||||
|
|
@ -76,10 +84,10 @@ func TestTLSInStore(t *testing.T) {
|
|||
},
|
||||
}}
|
||||
|
||||
tlsManager := NewManager()
|
||||
tlsManager := NewManager(nil)
|
||||
tlsManager.UpdateConfigs(t.Context(), nil, nil, dynamicConfigs)
|
||||
|
||||
certs := tlsManager.GetStore("default").DynamicCerts.Get().(map[string]*tls.Certificate)
|
||||
certs := tlsManager.GetStore("default").DynamicCerts.Get().(map[string]*CertificateData)
|
||||
if len(certs) == 0 {
|
||||
t.Fatal("got error: default store must have TLS certificates.")
|
||||
}
|
||||
|
|
@ -93,7 +101,7 @@ func TestTLSInvalidStore(t *testing.T) {
|
|||
},
|
||||
}}
|
||||
|
||||
tlsManager := NewManager()
|
||||
tlsManager := NewManager(nil)
|
||||
tlsManager.UpdateConfigs(t.Context(),
|
||||
map[string]Store{
|
||||
"default": {
|
||||
|
|
@ -104,7 +112,7 @@ func TestTLSInvalidStore(t *testing.T) {
|
|||
},
|
||||
}, nil, dynamicConfigs)
|
||||
|
||||
certs := tlsManager.GetStore("default").DynamicCerts.Get().(map[string]*tls.Certificate)
|
||||
certs := tlsManager.GetStore("default").DynamicCerts.Get().(map[string]*CertificateData)
|
||||
if len(certs) == 0 {
|
||||
t.Fatal("got error: default store must have TLS certificates.")
|
||||
}
|
||||
|
|
@ -157,7 +165,7 @@ func TestManager_Get(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
tlsManager := NewManager()
|
||||
tlsManager := NewManager(nil)
|
||||
tlsManager.UpdateConfigs(t.Context(), nil, tlsConfigs, dynamicConfigs)
|
||||
|
||||
for _, test := range testCases {
|
||||
|
|
@ -296,7 +304,7 @@ func TestClientAuth(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
tlsManager := NewManager()
|
||||
tlsManager := NewManager(nil)
|
||||
tlsManager.UpdateConfigs(t.Context(), nil, tlsConfigs, nil)
|
||||
|
||||
for _, test := range testCases {
|
||||
|
|
@ -323,8 +331,108 @@ func TestClientAuth(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestManager_UpdateConfigs_OCSPConfig(t *testing.T) {
|
||||
leafCert, err := tls.X509KeyPair([]byte(certWithOCSPServer), []byte(certKey))
|
||||
require.NoError(t, err)
|
||||
|
||||
issuerCert, err := tls.X509KeyPair([]byte(caCert), []byte(caKey))
|
||||
require.NoError(t, err)
|
||||
|
||||
thisUpdate, err := time.Parse("2006-01-02", "2025-01-01")
|
||||
require.NoError(t, err)
|
||||
nextUpdate, err := time.Parse("2006-01-02", "2025-01-02")
|
||||
require.NoError(t, err)
|
||||
|
||||
ocspResponseTmpl := ocsp.Response{
|
||||
SerialNumber: leafCert.Leaf.SerialNumber,
|
||||
TBSResponseData: []byte("foo"),
|
||||
ThisUpdate: thisUpdate,
|
||||
NextUpdate: nextUpdate,
|
||||
}
|
||||
|
||||
ocspResponse, err := ocsp.CreateResponse(leafCert.Leaf, leafCert.Leaf, ocspResponseTmpl, issuerCert.PrivateKey.(crypto.Signer))
|
||||
require.NoError(t, err)
|
||||
|
||||
responderCall := make(chan struct{})
|
||||
|
||||
handler := func(rw http.ResponseWriter, req *http.Request) {
|
||||
ct := req.Header.Get("Content-Type")
|
||||
assert.Equal(t, "application/ocsp-request", ct)
|
||||
|
||||
reqBytes, err := io.ReadAll(req.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = ocsp.ParseRequest(reqBytes)
|
||||
require.NoError(t, err)
|
||||
|
||||
rw.Header().Set("Content-Type", "application/ocsp-response")
|
||||
|
||||
_, err = rw.Write(ocspResponse)
|
||||
require.NoError(t, err)
|
||||
|
||||
responderCall <- struct{}{}
|
||||
}
|
||||
|
||||
responder := httptest.NewServer(http.HandlerFunc(handler))
|
||||
t.Cleanup(responder.Close)
|
||||
|
||||
testContext, cancel := context.WithCancel(t.Context())
|
||||
t.Cleanup(cancel)
|
||||
|
||||
tlsManager := NewManager(&OCSPConfig{
|
||||
ResponderOverrides: map[string]string{
|
||||
"ocsp.example.com": responder.URL,
|
||||
},
|
||||
})
|
||||
|
||||
go tlsManager.Run(testContext)
|
||||
|
||||
tlsManager.ocspStapler.cache.Set("existing", &ocspEntry{
|
||||
leaf: leafCert.Leaf,
|
||||
issuer: issuerCert.Leaf,
|
||||
staple: []byte("foo"),
|
||||
nextUpdate: time.Now().Add(time.Hour),
|
||||
}, cache.NoExpiration)
|
||||
tlsManager.ocspStapler.cache.Set("existingWithTTL", &ocspEntry{
|
||||
leaf: leafCert.Leaf,
|
||||
issuer: issuerCert.Leaf,
|
||||
staple: []byte("foo"),
|
||||
nextUpdate: time.Now().Add(time.Hour),
|
||||
}, 2*defaultCacheDuration)
|
||||
|
||||
tlsManager.UpdateConfigs(testContext, nil, nil, []*CertAndStores{
|
||||
{
|
||||
Certificate: Certificate{
|
||||
CertFile: certWithOCSPServer,
|
||||
KeyFile: certKey,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Asserting that UpdateConfigs resets the expiration for existing entries.
|
||||
_, expiration, ok := tlsManager.ocspStapler.cache.GetWithExpiration("existing")
|
||||
require.True(t, ok)
|
||||
assert.Greater(t, expiration, time.Now())
|
||||
// But not for entries with TTL already set.
|
||||
_, expiration, ok = tlsManager.ocspStapler.cache.GetWithExpiration("existingWithTTL")
|
||||
require.True(t, ok)
|
||||
assert.Greater(t, expiration, time.Now().Add(defaultCacheDuration))
|
||||
|
||||
select {
|
||||
case <-responderCall:
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatal("Timeout waiting for OCSP responder call")
|
||||
}
|
||||
|
||||
assert.Len(t, tlsManager.ocspStapler.cache.Items(), 3)
|
||||
|
||||
certHash := hashRawCert(leafCert.Leaf.Raw)
|
||||
_, ok = tlsManager.ocspStapler.cache.Get(certHash)
|
||||
require.True(t, ok)
|
||||
}
|
||||
|
||||
func TestManager_Get_DefaultValues(t *testing.T) {
|
||||
tlsManager := NewManager()
|
||||
tlsManager := NewManager(nil)
|
||||
|
||||
// Ensures we won't break things for Traefik users when updating Go
|
||||
config, _ := tlsManager.Get("default", "default")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue