Skip to content

Commit 0719a07

Browse files
authored
Adds an option to serve and verify regular TLS (#13)
* Adds an option to serve and verify regular TLS * Adds flag to pass an additional CA cert to the client for tls verification * Updates README
1 parent 8ff4c2f commit 0719a07

File tree

3 files changed

+109
-9
lines changed

3 files changed

+109
-9
lines changed

README.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ Both the client-side and the server-side TLS termination can be separately confi
2020
## Modes of operation
2121

2222
Server
23+
- TCP/HTTP server with regular TLS on the server side, to allow the client to verify the server's TLS certificate.
2324
- TCP/HTTP server with aTLS on the server side, to allow client verify the server measurement.
24-
- TCP/HTTP server that verifies the client (via client-side aTLS certificate). The measurement is passed along to the proxy target as header.
25+
- 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.
2526
- 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.
2627

2728
Client
28-
- Client making a request, verifying server aTLS (supporting one or multiple whitelisted measurements). The *server's* measurement is returned as a header.
29+
- Client making a request, verifying server's TLS certificate.
30+
- Client making a request, verifying server aTLS certificate (supporting one or multiple whitelisted measurements). The *server's* measurement is returned as a header.
2931
- Client making a request with a client-side aTLS cert.
3032
- 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.
3133

@@ -38,6 +40,8 @@ Client
3840
- `--listen-addr`: address to listen on (default: "127.0.0.1:8080")
3941
- `--target-addr`: address to proxy requests to (default: "https://localhost:80")
4042
- `--server-attestation-type`: type of attestation to present (none, azure-tdx) (default: "azure-tdx")
43+
- `--tls-certificate`: Certificate to present (PEM). Only valid for --server-attestation-type=none and with --tls-private-key.
44+
- `--tls-private-key`: "Private key for the certificate (PEM). Only valid with --tls-certificate.
4145
- `--client-attestation-type`: type of attestation to expect and verify (none, azure-tdx) (default: "none")
4246
- `--client-measurements`: optional path to JSON measurements enforced on the client
4347
- `--log-json`: log in JSON format (default: false)
@@ -57,9 +61,10 @@ make build-proxy-server
5761
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>]
5862
```
5963

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

62-
By default the server will not verify client attestations, you can change that via `--client-attestation-type` and `--client-measurements` flags.
67+
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.
6368

6469

6570
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).
@@ -72,6 +77,8 @@ This repository contains a [dummy http server](./cmd/dummy-server/main.go) that
7277
- `--target-addr`: address to proxy requests to (default: "https://localhost:80")
7378
- `--server-attestation-type`: type of attestation to expect and verify (none, azure-tdx) (default: "azure-tdx")
7479
- `--server-measurements`: optional path to JSON measurements enforced on the server
80+
- `--verify-tls`: verify server's TLS certificate instead of server's attestation. Only valid for server-attestation-type=none.
81+
- `--tls-ca-certificate`: additional CA certificate to verify against (PEM) [default=no additional TLS certs]. Only valid with --verify-tls.
7582
- `--client-attestation-type`: type of attestation to present (none, azure-tdx) (default: "none")
7683
- `--log-json`: log in JSON format (default: false)
7784
- `--log-debug`: log debug messages (default: false)
@@ -90,9 +97,10 @@ make build-proxy-client
9097
./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>]
9198
```
9299

93-
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.
100+
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.
101+
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`.
94102

95-
By default the client will not present client attestations, you can change that via `--client-attestation-type` flag.
103+
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.
96104

97105
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.
98106

cmd/proxy-client/main.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package main
22

33
import (
4+
"crypto/x509"
5+
"errors"
46
"log"
57
"net/http"
68
"os"
79

810
"github.com/flashbots/cvm-reverse-proxy/common"
911
"github.com/flashbots/cvm-reverse-proxy/internal/atls"
1012
"github.com/flashbots/cvm-reverse-proxy/proxy"
11-
1213
"github.com/urfave/cli/v2" // imports as package "cli"
1314
)
1415

@@ -32,6 +33,15 @@ var flags []cli.Flag = []cli.Flag{
3233
Name: "server-measurements",
3334
Usage: "optional path to JSON measurements enforced on the server",
3435
},
36+
&cli.BoolFlag{
37+
Name: "verify-tls",
38+
Value: false,
39+
Usage: "verify server's TLS certificate instead of server's attestation. Only valid for server-attestation-type=none.",
40+
},
41+
&cli.StringFlag{
42+
Name: "tls-ca-certificate",
43+
Usage: "additional CA certificate to verify against (PEM) [default=no additional TLS certs]. Only valid with --verify-tls.",
44+
},
3545
&cli.StringFlag{
3646
Name: "client-attestation-type",
3747
Value: string(proxy.AttestationNone),
@@ -69,13 +79,20 @@ func runClient(cCtx *cli.Context) error {
6979
logJSON := cCtx.Bool("log-json")
7080
logDebug := cCtx.Bool("log-debug")
7181

82+
verifyTLS := cCtx.Bool("verify-tls")
83+
7284
log := common.SetupLogger(&common.LoggingOpts{
7385
Debug: logDebug,
7486
JSON: logJSON,
7587
Service: "proxy-client",
7688
Version: common.Version,
7789
})
7890

91+
if cCtx.String("server-attestation-type") != "none" && verifyTLS {
92+
log.Error("invalid combination of --verify-tls and --server-attestation-type passed (only 'none' is allowed)")
93+
return errors.New("invalid combination of --verify-tls and --server-attestation-type passed (only 'none' is allowed)")
94+
}
95+
7996
clientAttestationType, err := proxy.ParseAttestationType(cCtx.String("client-attestation-type"))
8097
if err != nil {
8198
log.With("attestation-type", cCtx.String("client-attestation-type")).Error("invalid client-attestation-type passed, see --help")
@@ -106,6 +123,33 @@ func runClient(cCtx *cli.Context) error {
106123
return err
107124
}
108125

126+
if verifyTLS {
127+
tlsConfig.InsecureSkipVerify = false
128+
tlsConfig.ServerName = ""
129+
}
130+
131+
if additionalTLSCA := cCtx.String("tls-ca-certificate"); additionalTLSCA != "" {
132+
if !verifyTLS {
133+
log.Error("--tls-ca-certificate specified but --verify-tls is not, refusing to continue")
134+
return errors.New("--tls-ca-certificate specified but --verify-tls is not, refusing to continue")
135+
}
136+
137+
certData, err := os.ReadFile(additionalTLSCA)
138+
if err != nil {
139+
log.Error("could not read tls ca certificate data", "err", err)
140+
return err
141+
}
142+
143+
roots := x509.NewCertPool()
144+
ok := roots.AppendCertsFromPEM(certData)
145+
if !ok {
146+
log.Error("invalid certificate received", "cert", string(certData))
147+
return errors.New("invalid certificate")
148+
}
149+
150+
tlsConfig.RootCAs = roots
151+
}
152+
109153
proxyHandler := proxy.NewProxy(targetAddr, validators).WithTransport(&http.Transport{TLSClientConfig: tlsConfig})
110154

111155
log.With("listenAddr", listenAddr).Info("about to start proxy")

cmd/proxy-server/main.go

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"context"
55
"crypto/tls"
6+
"errors"
67
"log"
78
"net/http"
89
"os"
@@ -13,7 +14,6 @@ import (
1314
"github.com/flashbots/cvm-reverse-proxy/common"
1415
"github.com/flashbots/cvm-reverse-proxy/internal/atls"
1516
"github.com/flashbots/cvm-reverse-proxy/proxy"
16-
1717
"github.com/urfave/cli/v2" // imports as package "cli"
1818
)
1919

@@ -33,6 +33,14 @@ var flags []cli.Flag = []cli.Flag{
3333
Value: string(proxy.AttestationAzureTDX),
3434
Usage: "type of attestation to present (" + proxy.AvailableAttestationTypes + ")",
3535
},
36+
&cli.StringFlag{
37+
Name: "tls-certificate",
38+
Usage: "Certificate to present (PEM). Only valid for --server-attestation-type=none and with --tls-private-key.",
39+
},
40+
&cli.StringFlag{
41+
Name: "tls-private-key",
42+
Usage: "Private key for the certificate (PEM). Only valid with --tls-certificate.",
43+
},
3644
&cli.StringFlag{
3745
Name: "client-attestation-type",
3846
Value: string(proxy.AttestationNone),
@@ -73,6 +81,10 @@ func runServer(cCtx *cli.Context) error {
7381
clientMeasurements := cCtx.String("client-measurements")
7482
logJSON := cCtx.Bool("log-json")
7583
logDebug := cCtx.Bool("log-debug")
84+
serverAttestationTypeFlag := cCtx.String("server-attestation-type")
85+
86+
certFile := cCtx.String("tls-certificate")
87+
keyFile := cCtx.String("tls-private-key")
7688

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

84-
serverAttestationType, err := proxy.ParseAttestationType(cCtx.String("server-attestation-type"))
96+
useRegularTLS := certFile != "" || keyFile != ""
97+
if serverAttestationTypeFlag != "none" && useRegularTLS {
98+
log.Error("invalid combination of --tls-certificate, --tls-private-key and --server-attestation-type flags passed (only 'none' is allowed)")
99+
return errors.New("invalid combination of --tls-certificate, --tls-private-key and --server-attestation-type flags passed (only 'none' is allowed)")
100+
}
101+
102+
if useRegularTLS && (certFile == "" || keyFile == "") {
103+
log.Error("not all of --tls-certificate and --tls-private-key specified")
104+
return errors.New("not all of --tls-certificate and --tls-private-key specified")
105+
}
106+
107+
serverAttestationType, err := proxy.ParseAttestationType(serverAttestationTypeFlag)
85108
if err != nil {
86109
log.With("attestation-type", cCtx.String("server-attestation-type")).Error("invalid server-attestation-type passed, see --help")
87110
return err
@@ -112,6 +135,31 @@ func runServer(cCtx *cli.Context) error {
112135
panic(err)
113136
}
114137

138+
if useRegularTLS {
139+
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
140+
if err != nil {
141+
log.Error("could not load tls key pair", "err", err)
142+
return err
143+
}
144+
145+
atlsGetConfigForClient := confTLS.GetConfigForClient
146+
147+
confTLS = &tls.Config{
148+
GetConfigForClient: func(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
149+
ogClientConfig, err := atlsGetConfigForClient(clientHello)
150+
if err != nil {
151+
return ogClientConfig, err
152+
}
153+
154+
// Note: we don't have to copy the certificate because it's always created per request
155+
ogClientConfig.Certificates = []tls.Certificate{cert}
156+
ogClientConfig.GetCertificate = nil
157+
return ogClientConfig, nil
158+
159+
},
160+
}
161+
}
162+
115163
// Create an HTTP server
116164
server := &http.Server{
117165
Addr: listenAddr,

0 commit comments

Comments
 (0)