OCSP stapling
This commit is contained in:
parent
2949995abc
commit
b39ee8ede5
30 changed files with 1576 additions and 178 deletions
|
|
@ -3,7 +3,9 @@ package integration
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
|
@ -24,6 +26,7 @@ import (
|
|||
"github.com/stretchr/testify/suite"
|
||||
"github.com/traefik/traefik/v3/integration/try"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"golang.org/x/crypto/ocsp"
|
||||
)
|
||||
|
||||
// SimpleSuite tests suite.
|
||||
|
|
@ -1598,6 +1601,132 @@ func (s *SimpleSuite) TestMaxHeaderBytes() {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestSimpleOCSP() {
|
||||
defaultCert, err := tls.LoadX509KeyPair("fixtures/ocsp/default.crt", "fixtures/ocsp/default.key")
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
serverCert, err := tls.LoadX509KeyPair("fixtures/ocsp/server.crt", "fixtures/ocsp/server.key")
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
defaultOCSPResponseTmpl := ocsp.Response{
|
||||
SerialNumber: defaultCert.Leaf.SerialNumber,
|
||||
Status: ocsp.Good,
|
||||
ThisUpdate: defaultCert.Leaf.NotBefore,
|
||||
NextUpdate: defaultCert.Leaf.NotAfter,
|
||||
}
|
||||
defaultOCSPResponse, err := ocsp.CreateResponse(defaultCert.Leaf, defaultCert.Leaf, defaultOCSPResponseTmpl, defaultCert.PrivateKey.(crypto.Signer))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
serverOCSPResponseTmpl := ocsp.Response{
|
||||
SerialNumber: serverCert.Leaf.SerialNumber,
|
||||
Status: ocsp.Good,
|
||||
ThisUpdate: serverCert.Leaf.NotBefore,
|
||||
NextUpdate: serverCert.Leaf.NotAfter,
|
||||
}
|
||||
serverOCSPResponse, err := ocsp.CreateResponse(serverCert.Leaf, serverCert.Leaf, serverOCSPResponseTmpl, serverCert.PrivateKey.(crypto.Signer))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
responderCalled := make(chan struct{})
|
||||
responder := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
ct := req.Header.Get("Content-Type")
|
||||
assert.Equal(s.T(), "application/ocsp-request", ct)
|
||||
|
||||
reqBytes, err := io.ReadAll(req.Body)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
ocspReq, err := ocsp.ParseRequest(reqBytes)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
var ocspResponse []byte
|
||||
switch ocspReq.SerialNumber.String() {
|
||||
case defaultCert.Leaf.SerialNumber.String():
|
||||
ocspResponse = defaultOCSPResponse
|
||||
case serverCert.Leaf.SerialNumber.String():
|
||||
ocspResponse = serverOCSPResponse
|
||||
default:
|
||||
s.T().Fatalf("Unexpected OCSP request for serial number: %s", ocspReq.SerialNumber)
|
||||
}
|
||||
|
||||
rw.Header().Set("Content-Type", "application/ocsp-response")
|
||||
|
||||
_, err = rw.Write(ocspResponse)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
responderCalled <- struct{}{}
|
||||
}))
|
||||
s.T().Cleanup(responder.Close)
|
||||
|
||||
file := s.adaptFile("fixtures/ocsp/simple.toml", struct {
|
||||
ResponderURL string
|
||||
}{responder.URL})
|
||||
|
||||
s.traefikCmd(withConfigFile(file))
|
||||
|
||||
select {
|
||||
case <-responderCalled:
|
||||
case <-time.After(5 * time.Second):
|
||||
s.T().Fatal("OCSP responder was not called")
|
||||
}
|
||||
|
||||
select {
|
||||
case <-responderCalled:
|
||||
case <-time.After(5 * time.Second):
|
||||
s.T().Fatal("OCSP responder was not called")
|
||||
}
|
||||
|
||||
// Check that the response is stapled.
|
||||
|
||||
// Create a TLS client configuration that checks for OCSP stapling for the default cert.
|
||||
var verifyCallCount int
|
||||
clientConfig := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: "unknown",
|
||||
VerifyConnection: func(state tls.ConnectionState) error {
|
||||
s.T().Helper()
|
||||
|
||||
verifyCallCount++
|
||||
assert.Equal(s.T(), "default.local", state.PeerCertificates[0].Subject.CommonName)
|
||||
assert.Equal(s.T(), defaultOCSPResponse, state.OCSPResponse)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// Connect to the server and verify OCSP stapling.
|
||||
conn, err := tls.DialWithDialer(&net.Dialer{Timeout: 5 * time.Second}, "tcp", "127.0.0.1:8000", clientConfig)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
s.T().Cleanup(func() {
|
||||
_ = conn.Close()
|
||||
})
|
||||
|
||||
assert.Equal(s.T(), 1, verifyCallCount)
|
||||
|
||||
// Create a TLS client configuration that checks for OCSP stapling for a cert in the store.
|
||||
verifyCallCount = 0
|
||||
clientConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: "server.local",
|
||||
VerifyConnection: func(state tls.ConnectionState) error {
|
||||
s.T().Helper()
|
||||
|
||||
verifyCallCount++
|
||||
assert.Equal(s.T(), "server.local", state.PeerCertificates[0].Subject.CommonName)
|
||||
assert.Equal(s.T(), serverOCSPResponse, state.OCSPResponse)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// Connect to the server and verify OCSP stapling.
|
||||
conn, err = tls.DialWithDialer(&net.Dialer{Timeout: 5 * time.Second}, "tcp", "127.0.0.1:8000", clientConfig)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
s.T().Cleanup(func() {
|
||||
_ = conn.Close()
|
||||
})
|
||||
|
||||
assert.Equal(s.T(), 1, verifyCallCount)
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestSanitizePath() {
|
||||
s.createComposeProject("base")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue