Skip to content

Commit 138eef4

Browse files
committed
tapcfg: add price oracle TLS config
We don't skip certificate verification by default, and also default to trusting the operating system's root CA list.
1 parent bf0387b commit 138eef4

File tree

5 files changed

+92
-16
lines changed

5 files changed

+92
-16
lines changed

rfq/cli.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ const (
2222
type CliConfig struct {
2323
PriceOracleAddress string `long:"priceoracleaddress" description:"Price oracle gRPC server address (rfqrpc://<hostname>:<port>). To use the integrated mock, use the following value: use_mock_price_oracle_service_promise_to_not_use_on_mainnet"`
2424

25+
PriceOracleTLS bool `long:"priceoracletls" description:"Enable TLS for communication with a price oracle."`
26+
27+
PriceOracleTLSInsecure bool `long:"priceoracletlsinsecure" description:"Disable verification of price oracle certificates."`
28+
29+
PriceOracleTLSNoSystemCAs bool `long:"priceoracletlsnosystemcas" description:"Disable use of the operating system's list of root CA's when verifiying price oracle certificates."`
30+
31+
PriceOracleTLSCertPath string `long:"priceoracletlscertpath" description:"Path to a PEM-encoded x509 certificate to use when constructing a TLS connection with a price oracle."`
32+
2533
SendPriceHint bool `long:"sendpricehint" description:"Send a price hint from the local price oracle to the RFQ peer when requesting a quote. For privacy reasons, this should only be turned on for self-hosted or trusted price oracles."`
2634

2735
PriceOracleSendPeerId bool `long:"priceoraclesendpeerid" description:"Send the peer ID (public key of the peer) to the price oracle when requesting a price rate. For privacy reasons, this should only be turned on for self-hosted or trusted price oracles."`

rfq/tls.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@ type TLSConfig struct {
2525
CustomCertificates []byte
2626
}
2727

28-
// DefaultTLSConfig returns a default TLS configuration.
29-
func DefaultTLSConfig() *TLSConfig {
30-
return &TLSConfig{
31-
InsecureSkipVerify: true,
32-
}
33-
}
34-
3528
// configureTransportCredentials configures the TLS transport credentials to
3629
// be used for RPC connections.
3730
func configureTransportCredentials(

sample-tapd.conf

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
; always set to false.
1212

1313
; If only one value is specified for an option, then this is also the
14-
; default value used by tapd. In case of multiple (example) values, the default
15-
; is explicitly mentioned.
14+
; default value used by tapd. In case of multiple (example) values, the default
15+
; is explicitly mentioned.
1616
; If the part after the equal sign is empty then tapd has no default for this
1717
; option.
1818

@@ -435,6 +435,21 @@
435435
; use_mock_price_oracle_service_promise_to_not_use_on_mainnet
436436
; experimental.rfq.priceoracleaddress=
437437

438+
; Enable TLS for price oracle communication.
439+
; experimental.rfq.priceoracletls=true
440+
441+
; Skip price oracle certificate verification, yielding an insecure (cleartext)
442+
; channel with the price oracle. Should only be used for testing.
443+
; experimental.rfq.priceoracletlsinsecure=false
444+
445+
; Disable use of the operating system's root CA list when verifying a
446+
; price oracle's certificate.
447+
; experimental.rfq.priceoracletlsnosystemcas=false
448+
449+
; Path to a custom certificate (root CA or self-signed) to be used to
450+
; secure communication with a price oracle.
451+
; experimental.rfq.priceoracletlscertpath=
452+
438453
; Send a price hint from the local price oracle to the RFQ peer when requesting
439454
; a quote. For privacy reasons, this should only be turned on for self-hosted or
440455
; trusted price oracles.
@@ -445,7 +460,7 @@
445460
; self-hosted or trusted price oracles.
446461
; experimental.rfq.priceoraclesendpeerid=false
447462

448-
; The default price deviation inparts per million that is accepted by
463+
; The default price deviation inparts per million that is accepted by
449464
; the RFQ negotiator.
450465
; Example: 50,000 ppm => price deviation is set to 5% .
451466
; experimental.rfq.acceptpricedeviationppm=50000

tapcfg/config.go

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,24 @@ const (
143143
// defaultMailboxAuthTimeout is the default timeout we'll use for
144144
// mailbox message retrieval client authentication.
145145
defaultMailboxAuthTimeout = 10 * time.Second
146+
147+
// defaultPriceOracleTLS is the default TLS setting to use when
148+
// communicating with price oracles.
149+
defaultPriceOracleTLS = true
150+
151+
// defaultPriceOracleTLSInsecure is the default value we'll use for
152+
// deciding to verify certificates in TLS connections with price
153+
// oracles.
154+
defaultPriceOracleTLSInsecure = false
155+
156+
// defaultPriceOracleNoSystemCAs is the default value we'll use
157+
// regarding trust of the operating system's root CA list. We'll use
158+
// 'false', i.e. we will trust the OS root CA list by default.
159+
defaultPriceOracleTLSNoSystemCAs = false
160+
161+
// defaultPriceOracleTLSCertPath is the default (empty) path to a
162+
// certificate to use for securing price oracle communication.
163+
defaultPriceOracleTLSCertPath = ""
146164
)
147165

148166
var (
@@ -317,8 +335,11 @@ type ExperimentalConfig struct {
317335
Rfq rfq.CliConfig `group:"rfq" namespace:"rfq"`
318336
}
319337

320-
// Validate returns an error if the configuration is invalid.
321-
func (c *ExperimentalConfig) Validate() error {
338+
// CleanAndValidate performs final processing on the ExperimentalConfig,
339+
// returning an error if the configuration is invalid.
340+
func (c *ExperimentalConfig) CleanAndValidate() error {
341+
c.Rfq.PriceOracleTLSCertPath = CleanAndExpandPath(
342+
c.Rfq.PriceOracleTLSCertPath)
322343
return c.Rfq.Validate()
323344
}
324345

@@ -478,7 +499,11 @@ func DefaultConfig() Config {
478499
},
479500
Experimental: &ExperimentalConfig{
480501
Rfq: rfq.CliConfig{
481-
AcceptPriceDeviationPpm: rfq.DefaultAcceptPriceDeviationPpm,
502+
AcceptPriceDeviationPpm: rfq.DefaultAcceptPriceDeviationPpm,
503+
PriceOracleTLS: defaultPriceOracleTLS,
504+
PriceOracleTLSInsecure: defaultPriceOracleTLSInsecure,
505+
PriceOracleTLSNoSystemCAs: defaultPriceOracleTLSNoSystemCAs,
506+
PriceOracleTLSCertPath: defaultPriceOracleTLSCertPath,
482507
},
483508
},
484509
}
@@ -914,8 +939,8 @@ func ValidateConfig(cfg Config, cfgLogger btclog.Logger) (*Config, error) {
914939
}
915940
}
916941

917-
// Validate the experimental command line config.
918-
err = cfg.Experimental.Validate()
942+
// Clean and validate the experimental command line config.
943+
err = cfg.Experimental.CleanAndValidate()
919944
if err != nil {
920945
return nil, fmt.Errorf("error in experimental command line "+
921946
"config: %w", err)
@@ -1150,6 +1175,35 @@ func getCertificateConfig(cfg *Config, cfgLogger btclog.Logger) (*tls.Config,
11501175
return tlsCfg, restCreds, nil
11511176
}
11521177

1178+
// getPriceOracleTLSConfig returns a TLS configuration for a price oracle,
1179+
// given a valid RFQ CLI configuration.
1180+
func getPriceOracleTLSConfig(rfqCfg rfq.CliConfig) (*rfq.TLSConfig, error) {
1181+
var certBytes []byte
1182+
1183+
// Read any specified certificate data.
1184+
if rfqCfg.PriceOracleTLSCertPath != "" {
1185+
var err error
1186+
certBytes, err = os.ReadFile(
1187+
rfqCfg.PriceOracleTLSCertPath)
1188+
if err != nil {
1189+
return nil, fmt.Errorf("unable to read "+
1190+
"price oracle certificate: %w", err)
1191+
}
1192+
}
1193+
1194+
// Construct the oracle's TLS configuration.
1195+
tlsConfig := &rfq.TLSConfig{
1196+
Enabled: rfqCfg.PriceOracleTLS,
1197+
InsecureSkipVerify: rfqCfg.PriceOracleTLSInsecure,
1198+
// Note the subtle flip on the flag, since the user has
1199+
// configured whether to *not* trust the system CA's.
1200+
TrustSystemRootCAs: !rfqCfg.PriceOracleTLSNoSystemCAs,
1201+
CustomCertificates: certBytes,
1202+
}
1203+
1204+
return tlsConfig, nil
1205+
}
1206+
11531207
// fileExists reports whether the named file or directory exists.
11541208
// This function is taken from https://github.com/btcsuite/btcd
11551209
func fileExists(name string) bool {

tapcfg/server.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,8 +461,14 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger,
461461
// skip setting suggested prices for outgoing quote requests.
462462

463463
default:
464+
tlsConfig, err := getPriceOracleTLSConfig(rfqCfg)
465+
if err != nil {
466+
return nil, fmt.Errorf("couldn't construct price "+
467+
"oracle configuration: %w", err)
468+
}
469+
464470
priceOracle, err = rfq.NewRpcPriceOracle(
465-
rfqCfg.PriceOracleAddress, rfq.DefaultTLSConfig(),
471+
rfqCfg.PriceOracleAddress, tlsConfig,
466472
)
467473
if err != nil {
468474
return nil, fmt.Errorf("unable to create price "+

0 commit comments

Comments
 (0)