Skip to content

Commit

Permalink
Merge pull request #1923 from OffchainLabs/external-signer-mtls
Browse files Browse the repository at this point in the history
Add TLS to the server side, expose optional root certificate path on client side
  • Loading branch information
PlasmaPower authored Oct 17, 2023
2 parents 1350ba3 + cfd7132 commit ffec797
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 5 deletions.
36 changes: 34 additions & 2 deletions arbnode/dataposter/data_poster.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ package dataposter

import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"math/big"
"net/http"
"os"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -170,18 +174,42 @@ func NewDataPoster(ctx context.Context, opts *DataPosterOpts) (*DataPoster, erro
return dp, nil
}

func rpcClient(ctx context.Context, opts *ExternalSignerCfg) (*rpc.Client, error) {
rootCrt, err := os.ReadFile(opts.RootCA)
if err != nil {
return nil, fmt.Errorf("error reading external signer root CA: %w", err)
}
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(rootCrt)
return rpc.DialOptions(
ctx,
opts.URL,
rpc.WithHTTPClient(
&http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
RootCAs: pool,
},
},
},
),
)
}

// externalSigner returns signer function and ethereum address of the signer.
// Returns an error if address isn't specified or if it can't connect to the
// signer RPC server.
func externalSigner(ctx context.Context, opts *ExternalSignerCfg) (signerFn, common.Address, error) {
if opts.Address == "" {
return nil, common.Address{}, errors.New("external signer (From) address specified")
}
sender := common.HexToAddress(opts.Address)
client, err := rpc.DialContext(ctx, opts.URL)

client, err := rpcClient(ctx, opts)
if err != nil {
return nil, common.Address{}, fmt.Errorf("error connecting external signer: %w", err)
}
sender := common.HexToAddress(opts.Address)

var hasher types.Signer
return func(ctx context.Context, addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
Expand Down Expand Up @@ -715,6 +743,9 @@ type ExternalSignerCfg struct {
Address string `koanf:"address"`
// API method name (e.g. eth_signTransaction).
Method string `koanf:"method"`
// Path to the external signer root CA certificate.
// This allows us to use self-signed certificats on the external signer.
RootCA string `koanf:"root-ca"`
}

type DangerousConfig struct {
Expand Down Expand Up @@ -756,6 +787,7 @@ func addExternalSignerOptions(prefix string, f *pflag.FlagSet) {
f.String(prefix+".url", DefaultDataPosterConfig.ExternalSigner.URL, "external signer url")
f.String(prefix+".address", DefaultDataPosterConfig.ExternalSigner.Address, "external signer address")
f.String(prefix+".method", DefaultDataPosterConfig.ExternalSigner.Method, "external signer method")
f.String(prefix+".root-ca", DefaultDataPosterConfig.ExternalSigner.RootCA, "external signer root CA")
}

var DefaultDataPosterConfig = DataPosterConfig{
Expand Down
8 changes: 5 additions & 3 deletions arbnode/dataposter/dataposter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,20 @@ func TestExternalSigner(t *testing.T) {
t.Fatalf("Error shutting down http server: %v", err)
}
})
cert, key := "./testdata/localhost.crt", "./testdata/localhost.key"
go func() {
fmt.Println("Server is listening on port 1234...")
if err := httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
t.Errorf("ListenAndServe() unexpected error: %v", err)
if err := httpSrv.ListenAndServeTLS(cert, key); err != nil && err != http.ErrServerClosed {
t.Errorf("ListenAndServeTLS() unexpected error: %v", err)
return
}
}()
signer, addr, err := externalSigner(ctx,
&ExternalSignerCfg{
Address: srv.address.Hex(),
URL: "http://127.0.0.1:1234",
URL: "https://localhost:1234",
Method: "test_signTransaction",
RootCA: cert,
})
if err != nil {
t.Fatalf("Error getting external signer: %v", err)
Expand Down
52 changes: 52 additions & 0 deletions arbnode/dataposter/testdata/localhost.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[req]
default_bits = 2048
default_keyfile = server-key.pem
distinguished_name = subject
req_extensions = req_ext
x509_extensions = x509_ext
string_mask = utf8only

[subject]
countryName = CH
countryName_default = CH

stateOrProvinceName = Zurich
stateOrProvinceName_default = ZH

localityName = city
localityName_default = Zurich

organizationName = Offchain Labs
organizationName_default = Offchain Labs

commonName = offchainlabs.ch
commonName_default = localhost

emailAddress = Email Address
emailAddress_default = [email protected]

[x509_ext]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer

basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"

[req_ext]
subjectKeyIdentifier = hash

basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"

[alternate_names]
DNS.1 = localhost
DNS.2 = 127.0.0.1

[alternate_names]
DNS.1 = localhost
DNS.2 = 127.0.0.1

28 changes: 28 additions & 0 deletions arbnode/dataposter/testdata/localhost.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN CERTIFICATE-----
MIIEwzCCA6ugAwIBAgIUHx3SdpCP5jXZE7USUqX5uRNFKPIwDQYJKoZIhvcNAQEL
BQAwfzELMAkGA1UEBhMCQ0gxCzAJBgNVBAgMAlpIMQ8wDQYDVQQHDAZadXJpY2gx
FjAUBgNVBAoMDU9mZmNoYWluIExhYnMxEjAQBgNVBAMMCWxvY2FsaG9zdDEmMCQG
CSqGSIb3DQEJARYXYmlnZGVhbEBvZmZjaGFpbmxhYnMuY2gwHhcNMjMxMDE2MTQ0
MDA1WhcNMjQxMDE1MTQ0MDA1WjB/MQswCQYDVQQGEwJDSDELMAkGA1UECAwCWkgx
DzANBgNVBAcMBlp1cmljaDEWMBQGA1UECgwNT2ZmY2hhaW4gTGFiczESMBAGA1UE
AwwJbG9jYWxob3N0MSYwJAYJKoZIhvcNAQkBFhdiaWdkZWFsQG9mZmNoYWlubGFi
cy5jaDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALg7XwaIh4l2Fp8a
MfNMdTQSMPMR0zpnicVTn/eiozWsqlAKaxmQM3PxJ0oVWW3iJ89p4rv5m+UjK6Dr
vsUQOzl8isgyGCTMnkLtxFlyallDNRDawRcuTPuNI9NkdJm+Zz7HooLzFeBDeS13
iRPEXr1T/4af9MjOxqFvbw5xBY9k4tc2hPp6q00948gPWKIB9Mz4thoB2Hl2rQBY
X/WhjSnre9o9qoyBO0XAsG0mssBs1vPa9/aEp7C5cDY0HCuM1RIjhXnRpb8lC9VQ
aC+FozDffmm23EGVpLmyPs590UOtVJdTUd6Q0TAT6d7fjCRUJ12DendQf2uMFV90
u6Yj0zUCAwEAAaOCATUwggExMB0GA1UdDgQWBBT2B3FTGFQ49JyBgDGLoZREOIGD
DTCBqAYDVR0jBIGgMIGdoYGEpIGBMH8xCzAJBgNVBAYTAkNIMQswCQYDVQQIDAJa
SDEPMA0GA1UEBwwGWnVyaWNoMRYwFAYDVQQKDA1PZmZjaGFpbiBMYWJzMRIwEAYD
VQQDDAlsb2NhbGhvc3QxJjAkBgkqhkiG9w0BCQEWF2JpZ2RlYWxAb2ZmY2hhaW5s
YWJzLmNoghQfHdJ2kI/mNdkTtRJSpfm5E0Uo8jAJBgNVHRMEAjAAMAsGA1UdDwQE
AwIFoDAfBgNVHREEGDAWgglsb2NhbGhvc3SCCTEyNy4wLjAuMTAsBglghkgBhvhC
AQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwDQYJKoZIhvcNAQEL
BQADggEBAIkhBcnLeeNwUwb+sSG4Qm8JdeplHPMeViNfFIflUfIIYS00JA2q9w8W
+6Nh8s6Dn20lQETUnesYj97BdqzLjFuJYAlblhE+zP8g/3Mkpu+wZAGvQjUIRyGT
C17BEtQQgAnv5pD22jr9hpLl2KowN6Oo1gzilCA+AtMkNZFIGDOxzuIv2u8rSD89
R/V6UEDMCgusFJnZ/GzKkUNbsrAfNUezNUal+KzMhHGHBwg4jfCNhnAAB43eRtJA
0pSRMMLcUEQnVotXDXYC3DhJmkYp1uXOH/tWs6z9xForOkWFxNMVj+zUWBi7n3Jw
N2BXlb64D96uor13U0dmvQJ72ooJc+A=
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions arbnode/dataposter/testdata/localhost.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4O18GiIeJdhaf
GjHzTHU0EjDzEdM6Z4nFU5/3oqM1rKpQCmsZkDNz8SdKFVlt4ifPaeK7+ZvlIyug
677FEDs5fIrIMhgkzJ5C7cRZcmpZQzUQ2sEXLkz7jSPTZHSZvmc+x6KC8xXgQ3kt
d4kTxF69U/+Gn/TIzsahb28OcQWPZOLXNoT6eqtNPePID1iiAfTM+LYaAdh5dq0A
WF/1oY0p63vaPaqMgTtFwLBtJrLAbNbz2vf2hKewuXA2NBwrjNUSI4V50aW/JQvV
UGgvhaMw335pttxBlaS5sj7OfdFDrVSXU1HekNEwE+ne34wkVCddg3p3UH9rjBVf
dLumI9M1AgMBAAECggEAHuc8oyKrQ5xmooUZHGP2pAeqJNfYXAtqoYpLwtUJ9hKy
1e7NdNIKw3fP/J4UrHk7btAm65us8hSCeMGatEErAhNZT0gR4zhcksMCBPQLkVIT
+HINYjdOzAJqoEbRRUnaVT5VDQy8HmyLCtyqhoGR18XbjshNnhKLYKCJ2z0Lrvf2
3rU7bbt7/rvLitVhxVL8SIe2jWSfIgcEmEAZMigB9WAnUyQ/tAfbPy1I764LLfzD
nLXn7E2OH7GrxkLjOsH9kfERlur7V7IhC9NE/wI0q+rnILRa7Q3+ifRu8qla3bo1
iyHl1ZmsYJ8Jnzbu9exzZaQmk42OoFPcMFm0mRe+2QKBgQDvRv0Q5JhBuVurkU98
lzATwEO0uYmeWDMnHzrFSWAKr/x4LNQ9ytSCfe1aLxgOkZq6dQ3TyZiCYzpmwGz9
K7/gghxmsVDKeCqiGVZOgFAWy7AhQyF6zM60oqqwSvJHhmGTsA/B5LPUiYe9lITW
ZSLVYkOzha7Coa++U8vPzI5VaQKBgQDFG4reFT79j8RKEm9jie6PdRdYMzOSDWty
Gjj5N9Jnlp1k/6RzCxjmp7w7yIorq/7fWZsQtt0UqgayOn25+I8dZeGC0BradUSB
tZbGElxPsF8Jg00ZvvK3G5mpZYDrJCud8Q05EaUZPXv9GuZhozEsTQgylVecVzsN
wyEK8VuZ7QKBgQChx9adUGIdtgzkILiknbh08j8U94mz1SCo5/WdpLHaKAlE29KZ
AQXUQP51Rng2iX4bab9yndCPADZheON3/debHX3EdUkRzFPPC+CN7TW5Y/jvVGtT
kxyDh6Ru1A2iDJr290iAKXjpUB/GL5/tMa5upiTuQYnasOWZgyC/nCf0WQKBgEwn
pRLDMLA1IMjhsInL3BEvU1KvjahLaQ0P1p1rlO6TAcLpBrewPPG5MwACLmhLLtFK
xJ/Dl02Jl8a61KLKxzi7iVLKZuWq00ouR8/FfkcHxOBfC6X74bkff9I0NogjVHrU
jKBVEe3blJEpGIP20mPka1tn2g68oUNi9dxNfm/NAoGAWj/Q0pgnNq0MQ8Lj6m99
1baaXSo8biks3E3A3cqhHQm/j3SRnkf0lueQW8+r9yR9IWdYFXz5Waq13qK+lopE
KDmww0xr8dyMUYTP1vde7np2XKa/OX3iejDzbI3RcZN/DEV+dCBY8pqHHfaAaESu
fwBWvfD8wtwCZzB3lOZEi80=
-----END PRIVATE KEY-----

0 comments on commit ffec797

Please sign in to comment.