Skip to content

Commit f98f496

Browse files
authored
ENG-22805: ensure correct validation of server certificate (#83)
* ENG-22805: ensure correct validation of server certificate
1 parent d5c758e commit f98f496

File tree

3 files changed

+126
-8
lines changed

3 files changed

+126
-8
lines changed

examples/tls/tls_connect.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/* This file is part of VoltDB.
2+
* Copyright (C) 2022 Volt Active Data Inc.
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Affero General Public License as
6+
* published by the Free Software Foundation, either version 3 of the
7+
* License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Affero General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Affero General Public License
15+
* along with VoltDB. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package main
19+
20+
/*
21+
* Program testing how go handles TLS handshake and server certificate validation.
22+
* Note: couldn't use main_test.go in same directory because it can't be used under GoLand debugger.
23+
*
24+
* Examples:
25+
* go run . -h
26+
* go run . -pem=/Users/rdykiel/ssl/server/volt.certstore.pem
27+
* go run . -altserver=voltdb.com -pem=/Users/rdykiel/ssl/server/volt.certstore.pem
28+
* go run . -altserver=foo.voltdb.com -pem=/Users/rdykiel/ssl/server/volt.certstore.pem
29+
* go run . -altserver=goo.voltdb.com -pem=/Users/rdykiel/ssl/server/volt.certstore.pem
30+
* go run . -insecure
31+
*
32+
* Certificate validation: if insecure = false, go expects to find server or altServer in the
33+
* SubjectAlternativeName extension of the PEM certificate, e.g.:
34+
*
35+
* 1: ObjectId: 2.5.29.17 Criticality=false
36+
* SubjectAlternativeName [
37+
* IPAddress: 127.0.0.1
38+
* DNSName: voltdb.com
39+
* DNSName: foo.voltdb.com
40+
* DNSName: bar.voltdb.com
41+
* ]
42+
*/
43+
44+
import (
45+
"crypto/tls"
46+
"database/sql/driver"
47+
"errors"
48+
"flag"
49+
"github.com/VoltDB/voltdb-client-go/voltdbclient"
50+
"github.com/kr/pretty"
51+
"log"
52+
)
53+
54+
func tlsConnect(server string, altServer string, pemPath string, insecure bool) {
55+
log.Printf("Connecting to %s: altServer %s, pemPath %s, insecure %t",
56+
server, altServer, pemPath, insecure)
57+
58+
// Keep tlsConfig nil unless altServer is provided: in this case we request to
59+
// validate the alternate name instead of the server name
60+
var tlsConfig *tls.Config
61+
if altServer != "" {
62+
tlsConfig = &tls.Config{
63+
InsecureSkipVerify: insecure,
64+
ServerName: altServer,
65+
}
66+
}
67+
68+
conn, err := voltdbclient.OpenTLSConn(server, voltdbclient.ClientConfig{
69+
PEMPath: pemPath,
70+
TLSConfig: tlsConfig,
71+
InsecureSkipVerify: insecure,
72+
ConnectTimeout: 60000000,
73+
})
74+
if err != nil {
75+
log.Fatal(err)
76+
} else if conn == nil {
77+
log.Fatal(errors.New("no connection"))
78+
} else {
79+
log.Printf("connected to: %s", server)
80+
}
81+
82+
var params []driver.Value
83+
for _, s := range []interface{}{"PAUSE_CHECK", int32(0)} {
84+
params = append(params, s)
85+
}
86+
87+
vr, err := conn.Query("@Statistics", params)
88+
if err != nil {
89+
log.Fatal(err)
90+
}
91+
pretty.Print(vr)
92+
log.Println()
93+
log.Printf("SUCCESS")
94+
//defer conn.Close()
95+
}
96+
97+
func main() {
98+
server := flag.String("server", "127.0.0.1", "Server name or IP address")
99+
altServer := flag.String("altserver", "", "Server name to validate instead of server")
100+
pemPath := flag.String("pem", "", "Full path to PEM file")
101+
insecure := flag.Bool("insecure", false, "If true, bypass validation")
102+
103+
flag.Parse()
104+
105+
tlsConnect(*server, *altServer, *pemPath, *insecure)
106+
}

voltdbclient/distributor.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This file is part of VoltDB.
2-
* Copyright (C) 2008-2018 VoltDB Inc.
2+
* Copyright (C) 2008-2022 Volt Active Data Inc.
33
*
44
* This program is free software: you can redistribute it and/or modify
55
* it under the terms of the GNU Affero General Public License as
@@ -160,6 +160,11 @@ func OpenTLSConn(ci string, clientConfig ClientConfig) (*Conn, error) {
160160
return nil, ErrMissingServerArgument
161161
}
162162
cis := strings.Split(ci, ",")
163+
if clientConfig.TLSConfig == nil {
164+
clientConfig.TLSConfig = &tls.Config{
165+
InsecureSkipVerify: clientConfig.InsecureSkipVerify,
166+
}
167+
}
163168
return newTLSConn(cis, clientConfig)
164169
}
165170

voltdbclient/node_conn.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This file is part of VoltDB.
2-
* Copyright (C) 2008-2018 VoltDB Inc.
2+
* Copyright (C) 2008-2022 Volt Active Data Inc.
33
*
44
* This program is free software: you can redistribute it and/or modify
55
* it under the terms of the GNU Affero General Public License as
@@ -50,7 +50,6 @@ const defaultRetryInterval = time.Second
5050

5151
type nodeConn struct {
5252
pemBytes []byte
53-
tlcConfig *tls.Config
5453
insecureSkipVerify bool
5554
connInfo string
5655
Host string
@@ -235,19 +234,26 @@ func (nc *nodeConn) networkConnect(protocolVersion int) (interface{}, *wire.Conn
235234
if !ok {
236235
log.Fatal("failed to parse root certificate")
237236
}
238-
// Use PEM file as your tlsconfig
239-
nc.tlsConfig = &tls.Config{
240-
RootCAs: roots,
241-
InsecureSkipVerify: nc.insecureSkipVerify,
242-
}
237+
238+
// Set up a config using PEM contents as the root CAs
239+
tlsConfigCopy := nc.tlsConfig.Clone()
240+
tlsConfigCopy.RootCAs = roots
241+
nc.tlsConfig = tlsConfigCopy
243242
}
244243
dialer := net.Dialer{
245244
Timeout: to,
246245
}
246+
247+
// In secure mode, go requires a ServerName, so force it if absent
248+
if nc.tlsConfig != nil && nc.tlsConfig.ServerName == "" && !nc.tlsConfig.InsecureSkipVerify {
249+
nc.tlsConfig.ServerName = nc.connInfo
250+
}
251+
247252
conn, err := dialer.Dial("tcp", raddr.String())
248253
if err != nil {
249254
return nil, nil, err
250255
}
256+
251257
tlsConn := tls.Client(conn, nc.tlsConfig)
252258
i, err := nc.setupConn(protocolVersion, u, tlsConn)
253259
if err != nil {
@@ -282,6 +288,7 @@ func (nc *nodeConn) setupConn(protocolVersion int, u *url.URL, tcpConn io.ReadWr
282288
if err != nil {
283289
return nil, err
284290
}
291+
285292
decoder := wire.NewDecoder(tcpConn)
286293
i, err := decoder.Login()
287294
if err != nil {

0 commit comments

Comments
 (0)