From 2e7e879d6f69902d06b4759a5f31a083968faa40 Mon Sep 17 00:00:00 2001 From: lublak <44057030+lublak@users.noreply.github.com> Date: Mon, 6 Mar 2023 12:03:41 +0100 Subject: [PATCH] feature: allow preloaded certs with prefork (#2351) * allow preloaded certs with prefork * add to documentation * add comments for ListenMutualTLSWithCertificate * add test for WithCertificate * Update benchmark.yml * Update benchmark.yml * Update benchmark.yml * Update benchmark.yml * Update benchmark.yml * Update benchmark.yml --------- Co-authored-by: RW --- .github/workflows/benchmark.yml | 4 +- docs/api/app.md | 46 ++++++++++++++++ listen.go | 16 ++++++ listen_test.go | 94 +++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 1 deletion(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index fcba117b..6150c2c8 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -38,5 +38,7 @@ jobs: github-token: ${{ secrets.BENCHMARK_TOKEN }} benchmark-data-dir-path: 'benchmarks' fail-on-alert: true - comment-on-alert: true + comment-on-alert: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} + # Enable Job Summary for PRs + #summary-always: ${{ github.event_name != 'push' && github.event_name != 'workflow_dispatch' }} auto-push: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} diff --git a/docs/api/app.md b/docs/api/app.md index 314ea83a..5ab89922 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -525,6 +525,27 @@ Using `ListenTLS` defaults to the following config \( use `Listener` to provide } ``` +## ListenTLSWithCertificate + +```go title="Signature" +func (app *App) ListenTLS(addr string, cert tls.Certificate) error +``` + +```go title="Examples" +app.ListenTLSWithCertificate(":443", cert); +``` + +Using `ListenTLSWithCertificate` defaults to the following config \( use `Listener` to provide your own config \) + +```go title="Default \*tls.Config" +&tls.Config{ + MinVersion: tls.VersionTLS12, + Certificates: []tls.Certificate{ + cert, + }, +} +``` + ## ListenMutualTLS ListenMutualTLS serves HTTPs requests from the given address using certFile, keyFile and clientCertFile are the paths to TLS certificate and key file @@ -550,6 +571,31 @@ Using `ListenMutualTLS` defaults to the following config \( use `Listener` to pr } ``` +## ListenMutualTLSWithCertificate + +ListenMutualTLSWithCertificate serves HTTPs requests from the given address using certFile, keyFile and clientCertFile are the paths to TLS certificate and key file + +```go title="Signature" +func (app *App) ListenMutualTLSWithCertificate(addr string, cert tls.Certificate, clientCertPool *x509.CertPool) error +``` + +```go title="Examples" +app.ListenMutualTLSWithCertificate(":443", cert, clientCertPool); +``` + +Using `ListenMutualTLSWithCertificate` defaults to the following config \( use `Listener` to provide your own config \) + +```go title="Default \*tls.Config" +&tls.Config{ + MinVersion: tls.VersionTLS12, + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: clientCertPool, + Certificates: []tls.Certificate{ + cert, + }, +} +``` + ## Listener You can pass your own [`net.Listener`](https://pkg.go.dev/net/#Listener) using the `Listener` method. This method can be used to enable **TLS/HTTPS** with a custom tls.Config. diff --git a/listen.go b/listen.go index 80acd1ed..d212855c 100644 --- a/listen.go +++ b/listen.go @@ -98,6 +98,14 @@ func (app *App) ListenTLS(addr, certFile, keyFile string) error { return fmt.Errorf("tls: cannot load TLS key pair from certFile=%q and keyFile=%q: %w", certFile, keyFile, err) } + return app.ListenTLSWithCertificate(addr, cert) +} + +// ListenTLS serves HTTPS requests from the given addr. +// cert is a tls.Certificate +// +// app.ListenTLSWithCertificate(":8080", cert) +func (app *App) ListenTLSWithCertificate(addr string, cert tls.Certificate) error { tlsHandler := &TLSHandler{} config := &tls.Config{ MinVersion: tls.VersionTLS12, @@ -161,6 +169,14 @@ func (app *App) ListenMutualTLS(addr, certFile, keyFile, clientCertFile string) clientCertPool := x509.NewCertPool() clientCertPool.AppendCertsFromPEM(clientCACert) + return app.ListenMutualTLSWithCertificate(addr, cert, clientCertPool) +} + +// ListenMutualTLSWithCertificate serves HTTPS requests from the given addr. +// cert is a tls.Certificate and clientCertPool is a *x509.CertPool: +// +// app.ListenMutualTLS(":8080", cert, clientCertPool) +func (app *App) ListenMutualTLSWithCertificate(addr string, cert tls.Certificate, clientCertPool *x509.CertPool) error { tlsHandler := &TLSHandler{} config := &tls.Config{ MinVersion: tls.VersionTLS12, diff --git a/listen_test.go b/listen_test.go index 63283d34..bbd89315 100644 --- a/listen_test.go +++ b/listen_test.go @@ -7,9 +7,11 @@ package fiber import ( "bytes" "crypto/tls" + "crypto/x509" "io" "log" "os" + "path/filepath" "strings" "sync" "testing" @@ -142,6 +144,98 @@ func Test_App_Listener_TLS_Listener(t *testing.T) { utils.AssertEqual(t, nil, app.Listener(ln)) } +// go test -run Test_App_ListenTLSWithCertificate +func Test_App_ListenTLSWithCertificate(t *testing.T) { + t.Parallel() + + // Create tls certificate + cer, err := tls.LoadX509KeyPair("./.github/testdata/ssl.pem", "./.github/testdata/ssl.key") + if err != nil { + utils.AssertEqual(t, nil, err) + } + + app := New() + + // invalid port + utils.AssertEqual(t, false, app.ListenTLSWithCertificate(":99999", cer) == nil) + + go func() { + time.Sleep(1000 * time.Millisecond) + utils.AssertEqual(t, nil, app.Shutdown()) + }() + + utils.AssertEqual(t, nil, app.ListenTLSWithCertificate(":0", cer)) +} + +// go test -run Test_App_ListenTLSWithCertificate_Prefork +func Test_App_ListenTLSWithCertificate_Prefork(t *testing.T) { + testPreforkMaster = true + + // Create tls certificate + cer, err := tls.LoadX509KeyPair("./.github/testdata/ssl.pem", "./.github/testdata/ssl.key") + if err != nil { + utils.AssertEqual(t, nil, err) + } + + app := New(Config{DisableStartupMessage: true, Prefork: true}) + + utils.AssertEqual(t, nil, app.ListenTLSWithCertificate(":99999", cer)) +} + +// go test -run Test_App_ListenMutualTLSWithCertificate +func Test_App_ListenMutualTLSWithCertificate(t *testing.T) { + t.Parallel() + + // Create tls certificate + cer, err := tls.LoadX509KeyPair("./.github/testdata/ssl.pem", "./.github/testdata/ssl.key") + if err != nil { + utils.AssertEqual(t, nil, err) + } + + // Create pool + clientCACert, err := os.ReadFile(filepath.Clean("./.github/testdata/ca-chain.cert.pem")) + if err != nil { + utils.AssertEqual(t, nil, err) + } + clientCertPool := x509.NewCertPool() + clientCertPool.AppendCertsFromPEM(clientCACert) + + app := New() + + // invalid port + utils.AssertEqual(t, false, app.ListenMutualTLSWithCertificate(":99999", cer, clientCertPool) == nil) + + go func() { + time.Sleep(1000 * time.Millisecond) + utils.AssertEqual(t, nil, app.Shutdown()) + }() + + utils.AssertEqual(t, nil, app.ListenMutualTLSWithCertificate(":0", cer, clientCertPool)) +} + +// go test -run Test_App_ListenMutualTLS_Prefork +func Test_App_ListenMutualTLSWithCertificate_Prefork(t *testing.T) { + testPreforkMaster = true + + // Create tls certificate + cer, err := tls.LoadX509KeyPair("./.github/testdata/ssl.pem", "./.github/testdata/ssl.key") + if err != nil { + utils.AssertEqual(t, nil, err) + } + + // Create pool + clientCACert, err := os.ReadFile(filepath.Clean("./.github/testdata/ca-chain.cert.pem")) + if err != nil { + utils.AssertEqual(t, nil, err) + } + clientCertPool := x509.NewCertPool() + clientCertPool.AppendCertsFromPEM(clientCACert) + + app := New(Config{DisableStartupMessage: true, Prefork: true}) + + utils.AssertEqual(t, nil, app.ListenMutualTLSWithCertificate(":99999", cer, clientCertPool)) +} + func captureOutput(f func()) string { reader, writer, err := os.Pipe() if err != nil {