Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ Both the client-side and the server-side TLS termination can be separately confi
## Modes of operation

Server
- TCP/HTTP server with regular TLS on the server side, to allow the client to verify the server's TLS certificate.
- TCP/HTTP server with aTLS on the server side, to allow client verify the server measurement.
- TCP/HTTP server that verifies the client (via client-side aTLS certificate). The measurement is passed along to the proxy target as header.
- TCP/HTTP server that verifies the client (via client-side aTLS certificate). The measurement is passed along to the proxy target as header. Valid for both server-side TLS and aTLS.
- TCP/HTTP server that performs mutual attestation, that is it both provides its own attestation, and verifies the client. The *client's* measurement is forwarded as a header.

Client
- Client making a request, verifying server aTLS (supporting one or multiple whitelisted measurements). The *server's* measurement is returned as a header.
- Client making a request, verifying server's TLS certificate.
- Client making a request, verifying server aTLS certificate (supporting one or multiple whitelisted measurements). The *server's* measurement is returned as a header.
- Client making a request with a client-side aTLS cert.
- Client making a request mutual attestation, both verifying server aTLS and providing the client-side aTLS handshake. The *sever's* measurement is returned as a header.

Expand All @@ -38,6 +40,8 @@ Client
- `--listen-addr`: address to listen on (default: "127.0.0.1:8080")
- `--target-addr`: address to proxy requests to (default: "https://localhost:80")
- `--server-attestation-type`: type of attestation to present (none, azure-tdx) (default: "azure-tdx")
- `--tls-certificate`: Certificate to present (PEM). Only valid for --server-attestation-type=none and with --tls-private-key.
- `--tls-private-key`: "Private key for the certificate (PEM). Only valid with --tls-certificate.
- `--client-attestation-type`: type of attestation to expect and verify (none, azure-tdx) (default: "none")
- `--client-measurements`: optional path to JSON measurements enforced on the client
- `--log-json`: log in JSON format (default: false)
Expand All @@ -57,9 +61,10 @@ make build-proxy-server
sudo ./build/proxy-server --listen-addr=<listen-addr> --target-addr=<target-addr> [--server-attestation-type=<server-attestation-type>] [--client-attestation-type=<client-attestation-type>] [--client-measurements=<client-measurements>]
```

By default the server will present Azure TDX attestation, and you can modify that via the `--server-attestation-type` flag.
By default the server will present Azure TDX attestation, and you can modify that via the `--server-attestation-type` flag.
The server can be made to present a regular TLS certificate through `--tls-certificate` and `--tls-private-key` flags instead of aTLS one.

By default the server will not verify client attestations, you can change that via `--client-attestation-type` and `--client-measurements` flags.
By default the server will not verify client attestations, you can change that via `--client-attestation-type` and `--client-measurements` flags. Valid for both aTLS and regular TLS.


This repository contains a [dummy http server](./cmd/dummy-server/main.go) that you can use for testing the server. Simply run `go run ./cmd/dummy-server/main.go` and point your `--target-addr=http://127.0.0.1:8085`. You can also use the sample [measurements.json](./measurements.json).
Expand All @@ -72,6 +77,8 @@ This repository contains a [dummy http server](./cmd/dummy-server/main.go) that
- `--target-addr`: address to proxy requests to (default: "https://localhost:80")
- `--server-attestation-type`: type of attestation to expect and verify (none, azure-tdx) (default: "azure-tdx")
- `--server-measurements`: optional path to JSON measurements enforced on the server
- `--verify-tls`: verify server's TLS certificate instead of server's attestation. Only valid for server-attestation-type=none.
- `--tls-ca-certificate`: additional CA certificate to verify against (PEM) [default=no additional TLS certs]. Only valid with --verify-tls.
- `--client-attestation-type`: type of attestation to present (none, azure-tdx) (default: "none")
- `--log-json`: log in JSON format (default: false)
- `--log-debug`: log debug messages (default: false)
Expand All @@ -90,9 +97,10 @@ make build-proxy-client
./build/proxy-client --listen-addr=<listen-addr> --target-addr=<target-addr> [--server-measurements=<server-measurements-file>] [--server-attestation-type=<server-attestation-type>] [--client-attestation-type=<client-attestation-type>]
```

By default the client will expect the server to present an Azure TDX attestation, and you can modify that via the `--server-attestation-type` and `--server-measurements` flags.
By default the client will expect the server to present an Azure TDX attestation, and you can modify that via the `--server-attestation-type` and `--server-measurements` flags.
The server can also be a regular TLS server, which you can configure with the `--verify-tls` flag, which is only valid in combination with `--server-attestation-type=none`. Non-standard CA for the server can also be configured with `--tls-ca-certificate`.

By default the client will not present client attestations, you can change that via `--client-attestation-type` flag.
By default the client will not present client attestations, you can change that via `--client-attestation-type` flag. Valid for both aTLS and TLS server proxies.

This repository contains a sample [measurements.json](./measurements.json) file that you can use. The client will (correctly) complain about unexpected measurements that you can then correct.

Expand Down
46 changes: 45 additions & 1 deletion cmd/proxy-client/main.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package main

import (
"crypto/x509"
"errors"
"log"
"net/http"
"os"

"github.com/flashbots/cvm-reverse-proxy/common"
"github.com/flashbots/cvm-reverse-proxy/internal/atls"
"github.com/flashbots/cvm-reverse-proxy/proxy"

"github.com/urfave/cli/v2" // imports as package "cli"
)

Expand All @@ -32,6 +33,15 @@ var flags []cli.Flag = []cli.Flag{
Name: "server-measurements",
Usage: "optional path to JSON measurements enforced on the server",
},
&cli.BoolFlag{
Name: "verify-tls",
Value: false,
Usage: "verify server's TLS certificate instead of server's attestation. Only valid for server-attestation-type=none.",
},
&cli.StringFlag{
Name: "tls-ca-certificate",
Usage: "additional CA certificate to verify against (PEM) [default=no additional TLS certs]. Only valid with --verify-tls.",
},
&cli.StringFlag{
Name: "client-attestation-type",
Value: string(proxy.AttestationNone),
Expand Down Expand Up @@ -69,13 +79,20 @@ func runClient(cCtx *cli.Context) error {
logJSON := cCtx.Bool("log-json")
logDebug := cCtx.Bool("log-debug")

verifyTLS := cCtx.Bool("verify-tls")

log := common.SetupLogger(&common.LoggingOpts{
Debug: logDebug,
JSON: logJSON,
Service: "proxy-client",
Version: common.Version,
})

if cCtx.String("server-attestation-type") != "none" && verifyTLS {
log.Error("invalid combination of --verify-tls and --server-attestation-type passed (only 'none' is allowed)")
return errors.New("invalid combination of --verify-tls and --server-attestation-type passed (only 'none' is allowed)")
}

clientAttestationType, err := proxy.ParseAttestationType(cCtx.String("client-attestation-type"))
if err != nil {
log.With("attestation-type", cCtx.String("client-attestation-type")).Error("invalid client-attestation-type passed, see --help")
Expand Down Expand Up @@ -106,6 +123,33 @@ func runClient(cCtx *cli.Context) error {
return err
}

if verifyTLS {
tlsConfig.InsecureSkipVerify = false
tlsConfig.ServerName = ""
}

if additionalTLSCA := cCtx.String("tls-ca-certificate"); additionalTLSCA != "" {
if !verifyTLS {
log.Error("--tls-ca-certificate specified but --verify-tls is not, refusing to continue")
return errors.New("--tls-ca-certificate specified but --verify-tls is not, refusing to continue")
}

certData, err := os.ReadFile(additionalTLSCA)
if err != nil {
log.Error("could not read tls ca certificate data", "err", err)
return err
}

roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM(certData)
if !ok {
log.Error("invalid certificate received", "cert", string(certData))
return errors.New("invalid certificate")
}

tlsConfig.RootCAs = roots
}

proxyHandler := proxy.NewProxy(targetAddr, validators).WithTransport(&http.Transport{TLSClientConfig: tlsConfig})

log.With("listenAddr", listenAddr).Info("about to start proxy")
Expand Down
52 changes: 50 additions & 2 deletions cmd/proxy-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"context"
"crypto/tls"
"errors"
"log"
"net/http"
"os"
Expand All @@ -13,7 +14,6 @@ import (
"github.com/flashbots/cvm-reverse-proxy/common"
"github.com/flashbots/cvm-reverse-proxy/internal/atls"
"github.com/flashbots/cvm-reverse-proxy/proxy"

"github.com/urfave/cli/v2" // imports as package "cli"
)

Expand All @@ -33,6 +33,14 @@ var flags []cli.Flag = []cli.Flag{
Value: string(proxy.AttestationAzureTDX),
Usage: "type of attestation to present (" + proxy.AvailableAttestationTypes + ")",
},
&cli.StringFlag{
Name: "tls-certificate",
Usage: "Certificate to present (PEM). Only valid for --server-attestation-type=none and with --tls-private-key.",
},
&cli.StringFlag{
Name: "tls-private-key",
Usage: "Private key for the certificate (PEM). Only valid with --tls-certificate.",
},
&cli.StringFlag{
Name: "client-attestation-type",
Value: string(proxy.AttestationNone),
Expand Down Expand Up @@ -73,6 +81,10 @@ func runServer(cCtx *cli.Context) error {
clientMeasurements := cCtx.String("client-measurements")
logJSON := cCtx.Bool("log-json")
logDebug := cCtx.Bool("log-debug")
serverAttestationTypeFlag := cCtx.String("server-attestation-type")

certFile := cCtx.String("tls-certificate")
keyFile := cCtx.String("tls-private-key")

log := common.SetupLogger(&common.LoggingOpts{
Debug: logDebug,
Expand All @@ -81,7 +93,18 @@ func runServer(cCtx *cli.Context) error {
Version: common.Version,
})

serverAttestationType, err := proxy.ParseAttestationType(cCtx.String("server-attestation-type"))
useRegularTLS := certFile != "" || keyFile != ""
if serverAttestationTypeFlag != "none" && useRegularTLS {
log.Error("invalid combination of --tls-certificate, --tls-private-key and --server-attestation-type flags passed (only 'none' is allowed)")
return errors.New("invalid combination of --tls-certificate, --tls-private-key and --server-attestation-type flags passed (only 'none' is allowed)")
}

if useRegularTLS && (certFile == "" || keyFile == "") {
log.Error("not all of --tls-certificate and --tls-private-key specified")
return errors.New("not all of --tls-certificate and --tls-private-key specified")
}

serverAttestationType, err := proxy.ParseAttestationType(serverAttestationTypeFlag)
if err != nil {
log.With("attestation-type", cCtx.String("server-attestation-type")).Error("invalid server-attestation-type passed, see --help")
return err
Expand Down Expand Up @@ -112,6 +135,31 @@ func runServer(cCtx *cli.Context) error {
panic(err)
}

if useRegularTLS {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Error("could not load tls key pair", "err", err)
return err
}

atlsGetConfigForClient := confTLS.GetConfigForClient

confTLS = &tls.Config{
GetConfigForClient: func(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
ogClientConfig, err := atlsGetConfigForClient(clientHello)
if err != nil {
return ogClientConfig, err
}

// Note: we don't have to copy the certificate because it's always created per request
ogClientConfig.Certificates = []tls.Certificate{cert}
ogClientConfig.GetCertificate = nil
return ogClientConfig, nil

},
}
}

// Create an HTTP server
server := &http.Server{
Addr: listenAddr,
Expand Down
Loading