Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
DifferentialOrange committed Jul 26, 2023
1 parent b30e2b6 commit 1c49429
Show file tree
Hide file tree
Showing 13 changed files with 385 additions and 69 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ jobs:
- sdk-version: 'bundle-2.10.0-1-gfa775b383-r486-linux-x86_64'
coveralls: false
ssl: true
- sdk-path: 'dev/linux/x86_64/master/'
sdk-version: 'sdk-gc64-2.11.0-entrypoint-113-g803baaffe-r529.linux.x86_64'
- sdk-path: 'release/linux/x86_64/2.11/'
sdk-version: 'sdk-gc64-2.11.0-0-r563.linux.x86_64'
coveralls: true
ssl: true

Expand Down
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,15 @@
work_dir*
.rocks
bench*

testdata/*.crt
!testdata/ca.crt
!testdata/invalidhost.crt
!testdata/localhost.crt
testdata/*.csr
testdata/*.ext
testdata/*.key
!testdata/localhost.key
!testdata/localhost.enc.key
testdata/*.pem
testdata/*.srl
5 changes: 5 additions & 0 deletions connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,11 @@ type SslOpts struct {
//
// * https://www.openssl.org/docs/man1.1.1/man1/ciphers.html
Ciphers string
// Password is a password for decrypting private SSL key file.
Password string
// PasswordFile is a path to the list of passwords for decrypting private SSL
// key file. Connection tries every line from the file as a password.
PasswordFile string
}

// Clone returns a copy of the Opts object.
Expand Down
67 changes: 61 additions & 6 deletions ssl.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
package tarantool

import (
"bufio"
"errors"
"fmt"
"io/ioutil"
"net"
"os"
"strings"
"time"

"github.com/tarantool/go-openssl"
Expand Down Expand Up @@ -43,7 +47,7 @@ func sslCreateContext(opts SslOpts) (ctx interface{}, err error) {
}

if opts.KeyFile != "" {
if err = sslLoadKey(sslCtx, opts.KeyFile); err != nil {
if err = sslLoadKey(sslCtx, opts.KeyFile, opts.Password, opts.PasswordFile); err != nil {
return
}
}
Expand Down Expand Up @@ -95,16 +99,67 @@ func sslLoadCert(ctx *openssl.Ctx, certFile string) (err error) {
return
}

func sslLoadKey(ctx *openssl.Ctx, keyFile string) (err error) {
func sslLoadKey(ctx *openssl.Ctx, keyFile string, password string,
passwordFile string) error {
var keyBytes []byte
var err error

if keyBytes, err = ioutil.ReadFile(keyFile); err != nil {
return
return err
}

var key openssl.PrivateKey
if key, err = openssl.LoadPrivateKeyFromPEM(keyBytes); err != nil {
return
var errs []error

// If key is encrypted and password is not provided,
// openssl.LoadPrivateKeyFromPEM(keyBytes) asks to enter PEM pass phrase
// interactively. On the other hand,
// openssl.LoadPrivateKeyFromPEMWithPassword(keyBytes, '') works fine for
// non-encrypted key.
if key, err = openssl.LoadPrivateKeyFromPEMWithPassword(keyBytes, password); err == nil {
return ctx.UsePrivateKey(key)
} else {
errs = append(errs, err)
}

if passwordFile != "" {
var file *os.File
file, err = os.Open(passwordFile)
if err == nil {
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
password = strings.TrimSpace(scanner.Text())

if key, err = openssl.LoadPrivateKeyFromPEMWithPassword(keyBytes, password); err == nil {

Check failure on line 135 in ssl.go

View workflow job for this annotation

GitHub Actions / golangci-lint

line is 105 characters (lll)
return ctx.UsePrivateKey(key)
} else {
errs = append(errs, err)
}
}
} else {
errs = append(errs, err)
}
}

if len(errs) > 1 {
// Convenient multiple error wrapping was introduced only in Go 1.20
// https://pkg.go.dev/errors#example-Join
// https://github.com/golang/go/issues/53435
rerr := errors.New("Got multiple errors on SSL decryption")

Check failure on line 150 in ssl.go

View workflow job for this annotation

GitHub Actions / golangci-lint

ST1005: error strings should not be capitalized (stylecheck)
var i int
for i, err = range errs {
if i == 0 {
// gofmt forbids error strings to end with punctuation or newlines
rerr = fmt.Errorf("%s: %w", rerr, err)
} else {
rerr = fmt.Errorf("%s, %w", rerr, err)
}
}

return rerr
}

return ctx.UsePrivateKey(key)
return errs[0]
}
165 changes: 165 additions & 0 deletions ssl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ func serverTnt(serverOpts, clientOpts SslOpts, auth Auth) (test_helpers.Tarantoo
listen += fmt.Sprintf("ssl_ciphers=%s&", ciphers)
}

password := serverOpts.Password
if password != "" {
listen += fmt.Sprintf("ssl_password=%s&", password)
}

passwordFile := serverOpts.PasswordFile
if passwordFile != "" {
listen += fmt.Sprintf("ssl_password_file=%s&", passwordFile)
}

listen = listen[:len(listen)-1]

return test_helpers.StartTarantool(test_helpers.StartOpts{
Expand All @@ -139,6 +149,21 @@ func serverTntStop(inst test_helpers.TarantoolInstance) {
test_helpers.StopTarantoolWithCleanup(inst)
}

func skipEncrypted(t testing.TB, serverOpts SslOpts) {
if serverOpts.Password == "" && serverOpts.PasswordFile == "" {
return
}

isLess, err := test_helpers.IsTarantoolVersionLess(2, 11, 0)
if err != nil {
t.Fatalf("Could not check the Tarantool version")
}

if isLess {
t.Skipf("Skipping test for Tarantool without SSL encryption support")
}
}

func assertConnectionSslFail(t testing.TB, serverOpts, clientOpts SslOpts) {
t.Helper()

Expand Down Expand Up @@ -171,6 +196,8 @@ func assertConnectionSslOk(t testing.TB, serverOpts, clientOpts SslOpts) {
func assertConnectionTntFail(t testing.TB, serverOpts, clientOpts SslOpts) {
t.Helper()

skipEncrypted(t, serverOpts)

inst, err := serverTnt(serverOpts, clientOpts, AutoAuth)
serverTntStop(inst)

Expand All @@ -182,6 +209,8 @@ func assertConnectionTntFail(t testing.TB, serverOpts, clientOpts SslOpts) {
func assertConnectionTntOk(t testing.TB, serverOpts, clientOpts SslOpts) {
t.Helper()

skipEncrypted(t, serverOpts)

inst, err := serverTnt(serverOpts, clientOpts, AutoAuth)
serverTntStop(inst)

Expand Down Expand Up @@ -431,6 +460,142 @@ var tests = []test{
Ciphers: "TLS_AES_128_GCM_SHA256",
},
},
{
"pass_no_key_encrypt",
true,
SslOpts{
KeyFile: "testdata/localhost.key",
CertFile: "testdata/localhost.crt",
CaFile: "testdata/ca.crt",
},
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
Password: "mysslpassword",
},
},
{
"pass_file_no_key_encrypt",
true,
SslOpts{
KeyFile: "testdata/localhost.key",
CertFile: "testdata/localhost.crt",
CaFile: "testdata/ca.crt",
},
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
PasswordFile: "testdata/passwords",
},
},
{
"pass_key_encrypt",
true,
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
CaFile: "testdata/ca.crt",
Password: "mysslpassword",
},
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
Password: "mysslpassword",
},
},
{
"pass_file_key_encrypt",
true,
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
CaFile: "testdata/ca.crt",
PasswordFile: "testdata/passwords",
},
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
PasswordFile: "testdata/passwords",
},
},
{
"pass_and_pass_file_key_encrypt",
true,
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
CaFile: "testdata/ca.crt",
PasswordFile: "testdata/passwords",
},
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
Password: "mysslpassword",
PasswordFile: "testdata/passwords",
},
},
{
"inv_pass_and_pass_file_key_encrypt",
true,
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
CaFile: "testdata/ca.crt",
PasswordFile: "testdata/passwords",
},
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
Password: "invalidpassword",
PasswordFile: "testdata/passwords",
},
},
{
"pass_and_inv_pass_file_key_encrypt",
true,
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
CaFile: "testdata/ca.crt",
PasswordFile: "testdata/passwords",
},
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
Password: "mysslpassword",
PasswordFile: "testdata/invalidpasswords",
},
},
{
"pass_and_inv_pass_file_key_encrypt",
false,
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
CaFile: "testdata/ca.crt",
PasswordFile: "testdata/passwords",
},
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
Password: "invalidpassword",
PasswordFile: "testdata/invalidpasswords",
},
},
{
"no_pass_key_encrypt",
false,
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
CaFile: "testdata/ca.crt",
PasswordFile: "testdata/passwords",
},
SslOpts{
KeyFile: "testdata/localhost.enc.key",
CertFile: "testdata/localhost.crt",
},
},
}

func isTestTntSsl() bool {
Expand Down
32 changes: 16 additions & 16 deletions testdata/ca.crt
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDLzCCAhegAwIBAgIUMMZTmNkhr4qOfSwInVk2dAJvoBEwDQYJKoZIhvcNAQEL
MIIDLzCCAhegAwIBAgIUaw6WTgYBXFRqlGbKRYczFApoNU4wDQYJKoZIhvcNAQEL
BQAwJzELMAkGA1UEBhMCVVMxGDAWBgNVBAMMD0V4YW1wbGUtUm9vdC1DQTAeFw0y
MjA1MjYwNjE3NDBaFw00NDEwMjkwNjE3NDBaMCcxCzAJBgNVBAYTAlVTMRgwFgYD
MzA3MjYwODM3MTZaFw00NTEyMjkwODM3MTZaMCcxCzAJBgNVBAYTAlVTMRgwFgYD
VQQDDA9FeGFtcGxlLVJvb3QtQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCRq/eaA3I6CB8t770H2XDdzcp1yuC/+TZOxV5o0LuRkogTvL2kYULBrfx1
rVZu8zQJTx1fmSRj1cN8j+IrmXN5goZ3mYFTnnIOgkyi+hJysVlo5s0Kp0qtLLGM
OuaVbxw2oAy75if5X3pFpiDaMvFBtJKsh8+SkncBIC5bbKC5AoLdFANLmPiH0CGr
Mv3rL3ycnbciI6J4uKHcWnYGGiMjBomaZ7jd/cOjcjmGfpI5d0nq13G11omkyEyR
wNX0eJRL02W+93Xu7tD+FEFMxFvak+70GvX+XWomwYw/Pjlio8KbTAlJxhfK2Lh6
H798k17VfxIrOk0KjzZS7+a20hZ/AgMBAAGjUzBRMB0GA1UdDgQWBBT2f5o8r75C
PWST36akpkKRRTbhvjAfBgNVHSMEGDAWgBT2f5o8r75CPWST36akpkKRRTbhvjAP
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA9pb75p6mnqp2MQHSr
5SKRf2UV4wQIUtXgF6V9vNfvVzJii+Lzrqir1YMk5QgavCzD96KlJcqJCcH559RY
5743AxI3tdWfA3wajBctoy35oYnT4M30qbkryYLTUlv7PmeNWvrksTURchyyDt5/
3T73yj5ZalmzKN6+xLfUDdnudspfWlUMutKU50MU1iuQESf4Fwd53vOg9jMcWJ2E
vAgfVI0XAvYdU3ybJrUvBq5zokYR2RzGv14uHxwVPnLBjrBEHRnbrXvLZJhuIS2b
xZ3CqwWi+9bvNqHz09HvhkU2b6fCGweKaAUGSo8OfQ5FRkjTUomMI/ZLs/qtJ6JR
zzVt
AoIBAQCunm5E+dyoYw+ECp0vOabsA4L7C+dUQLhfqdOEwFSpSanjBTuUEAPB+fEr
wqaZXI2EnUSxYEYO03TkZmWoJgRJq+00laWPA4AuKHpg4SS/LUoveQiQdsie+kUj
YMFu3rtP2CvTMpC4HMRK2CviOnU9iA4hPvRx4o5tESxLW31jNnBDeC/tsEVVR/6i
lwB9Oh1RbZI/c429N67qq5C2rpU5+o+YszDou36WTxw6XeXdkw7QF4W2BNLysPLJ
AY+aPrUVxKDOgDNk77h41HDqu+SuDg6mg528yfRqyAd4ooEE8MLcT0xztn1U8HvZ
SKwWTnS8TSzCmQptRGPlb5oES/NlAgMBAAGjUzBRMB0GA1UdDgQWBBQ/S0H0dFUy
OuEQ/kgDzGarWm2vlDAfBgNVHSMEGDAWgBQ/S0H0dFUyOuEQ/kgDzGarWm2vlDAP
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCoP+kH96+b6GWByPTo
LRK/QJmpPRWiZ5naV6CXJQNYg+nVG9wdiGXxEx4BBZs6yGdeHdiWCWbuRPMyH0Wp
w2ajMmK7pC8+MGKzMSC/EISPFwKYumwe/6zNnde7eZ19n7EFwrOihgEf+hNfjOCj
CqDIfMb2ztEHY7mEABMXDviKI80om2P1oIkHj5MD7z8ZetJRf1qCH7ke2cdTJ+Zr
XNGiJ7sz3xRQO/QRCkbBbr/d4zeX3A5/+MXHLtzbPiWs+/XaDbGJTQIO5hFfwwAC
v1/VrNmsy+3YYLLTZzmfpa60Sk3NsZbIQdvwLJJj8pOmH/zae7UZlrxlGWjQKvH5
evsP
-----END CERTIFICATE-----
Loading

0 comments on commit 1c49429

Please sign in to comment.