Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## Added

- `ssl_verify_client` option (#207).

## Changed

## Fixed

- Do not recreate server if it's address and port were not changed (#219).
- Server doesn't change after updating parameters on config reload (#216).
- **Breaking change**: Mutual TLS with `ca_file` option enabled (#217).

## [1.8.0] - 2025-07-07

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ httpd = require('http.server').new(host, port[, { options } ])
* `ssl_ciphers` is a colon-separated list of SSL ciphers, optional;
* `ssl_password` is a password for decrypting SSL private key, optional;
* `ssl_password_file` is a SSL file with key for decrypting SSL private key, optional.
* `ssl_verify_client` is an option that allows to verify client. It has following values:
* `off` (default) means that no client's certs will be verified;
* `on` means that server will verify client's certs;
* `optional` means that server will verify client's certs only if it exist.

## Using routes

Expand Down
20 changes: 19 additions & 1 deletion http/server.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,12 @@ local function url_for_httpd(httpd, name, args, query)
end
end

local VERIFY_CLIENT_OPTS = {
off = sslsocket.SET_VERIFY_FLAGS.SSL_VERIFY_NONE,
optional = sslsocket.SET_VERIFY_FLAGS.SSL_VERIFY_PEER,
on = bit.bor(sslsocket.SET_VERIFY_FLAGS.SSL_VERIFY_PEER, sslsocket.SET_VERIFY_FLAGS.SSL_VERIFY_FAIL_IF_NO_PEER),
}

local function create_ssl_ctx(host, port, opts)
local ok, ctx = pcall(sslsocket.ctx, sslsocket.tls_server_method())
if ok ~= true then
Expand Down Expand Up @@ -1328,7 +1334,11 @@ local function create_ssl_ctx(host, port, opts)
)
end

sslsocket.ctx_set_verify(ctx, 0x01 + 0x02)
local set_verify_flag = (
opts.ssl_verify_client and VERIFY_CLIENT_OPTS[opts.ssl_verify_client] or
VERIFY_CLIENT_OPTS.off
)
sslsocket.ctx_set_verify(ctx, set_verify_flag)
end

if opts.ssl_ciphers ~= nil then
Expand Down Expand Up @@ -1383,6 +1393,12 @@ local function validate_ssl_opts(opts)
errorf("%s option must be a string", key)
end

if key == 'ssl_verify_client' then
if VERIFY_CLIENT_OPTS[value] == nil then
errorf('%q option not exists. Available options: "on", "off", "optional"', value)
end
end

if string.find(key, 'file') ~= nil and fio.path.exists(value) ~= true then
errorf("file %q not exists", value)
end
Expand Down Expand Up @@ -1429,6 +1445,7 @@ local exports = {
ssl_password_file = options.ssl_password_file,
ssl_ca_file = options.ssl_ca_file,
ssl_ciphers = options.ssl_ciphers,
ssl_verify_client = options.ssl_verify_client,
})

local default = {
Expand Down Expand Up @@ -1499,6 +1516,7 @@ local exports = {
ssl_password_file = self.options.ssl_password_file,
ssl_ca_file = self.options.ssl_ca_file,
ssl_ciphers = self.options.ssl_ciphers,
ssl_verify_client = self.options.ssl_verify_client,
})
return sslsocket.tcp_server(host, port, handler, timeout, ssl_ctx)
end
Expand Down
8 changes: 8 additions & 0 deletions http/sslsocket.lua
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ pcall(ffi.cdef, [[
const void *needle, size_t needlelen);
]])

local SET_VERIFY_FLAGS = {
SSL_VERIFY_NONE = 0x00,
SSL_VERIFY_PEER = 0x01,
SSL_VERIFY_FAIL_IF_NO_PEER = 0x02,
}

local function slice_wait(timeout, starttime)
if timeout == nil then
return nil
Expand Down Expand Up @@ -452,6 +458,8 @@ local function tcp_server(host, port, handler, timeout, sslctx)
end

return {
SET_VERIFY_FLAGS = SET_VERIFY_FLAGS,

tls_server_method = tls_server_method,

ctx = ctx,
Expand Down
1 change: 1 addition & 0 deletions roles/httpd.lua
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ local function parse_params(node)
ssl_password_file = node.ssl_password_file,
ssl_ca_file = node.ssl_ca_file,
ssl_ciphers = node.ssl_ciphers,
ssl_verify_client = node.ssl_verify_client,
}
end

Expand Down
10 changes: 10 additions & 0 deletions test/helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ helpers.base_host = '127.0.0.1'
helpers.base_uri = ('http://%s:%s'):format(helpers.base_host, helpers.base_port)
helpers.tls_uri = ('https://%s:%s'):format('localhost', helpers.base_port)

local is_tarantool1 = luatest_utils.version_ge(
luatest_utils.get_tarantool_version(),
luatest_utils.version(1, 0, 0)
)

helpers.CONNECTION_REFUSED_ERR_MSG = "Failure when receiving data from the peer: Connection refused"
if is_tarantool1 then
helpers.CONNECTION_REFUSED_ERR_MSG = "Failure when receiving data from the peer"
end

helpers.get_testdir_path = function()
local path = os.getenv('LUA_SOURCE_DIR') or './'
return fio.pathjoin(path, 'test')
Expand Down
71 changes: 67 additions & 4 deletions test/integration/http_tls_enabled_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,6 @@ local client_test_cases = {
ssl_cert_file = fio.pathjoin(ssl_data_dir, 'server.crt'),
ssl_ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt'),
},
request_opts = {
ssl_cert = fio.pathjoin(ssl_data_dir, 'client.crt'),
ssl_key = fio.pathjoin(ssl_data_dir, 'client.key'),
},
},
test_client_password_key_missing = {
ssl_opts = {
Expand Down Expand Up @@ -149,6 +145,73 @@ local client_test_cases = {
},
expected_err_msg = "curl: Problem with the local SSL certificate",
},
test_verify_client_optional_with_certs_valid = {
ssl_opts = {
ssl_verify_client = 'optional',
ssl_key_file = fio.pathjoin(ssl_data_dir, 'server.key'),
ssl_cert_file = fio.pathjoin(ssl_data_dir, 'server.crt'),
ssl_ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt'),
},
request_opts = {
ssl_cert = fio.pathjoin(ssl_data_dir, 'client.crt'),
ssl_key = fio.pathjoin(ssl_data_dir, 'client.key'),
},
},
test_verify_client_optional_with_certs_invalid = {
ssl_opts = {
ssl_verify_client = 'optional',
ssl_key_file = fio.pathjoin(ssl_data_dir, 'server.key'),
ssl_cert_file = fio.pathjoin(ssl_data_dir, 'server.crt'),
ssl_ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt'),
},
request_opts = {
ssl_cert = fio.pathjoin(ssl_data_dir, 'bad_client.crt'),
ssl_key = fio.pathjoin(ssl_data_dir, 'bad_client.key'),
},
expected_err_msg = helpers.CONNECTION_REFUSED_ERR_MSG,
},
test_verify_client_optional_withouts_certs = {
ssl_opts = {
ssl_verify_client = 'optional',
ssl_key_file = fio.pathjoin(ssl_data_dir, 'server.key'),
ssl_cert_file = fio.pathjoin(ssl_data_dir, 'server.crt'),
ssl_ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt'),
},
},
test_verify_client_on_valid = {
ssl_opts = {
ssl_verify_client = 'on',
ssl_key_file = fio.pathjoin(ssl_data_dir, 'server.key'),
ssl_cert_file = fio.pathjoin(ssl_data_dir, 'server.crt'),
ssl_ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt'),
},
request_opts = {
ssl_cert = fio.pathjoin(ssl_data_dir, 'client.crt'),
ssl_key = fio.pathjoin(ssl_data_dir, 'client.key'),
},
},
test_verify_client_on_invalid = {
ssl_opts = {
ssl_verify_client = 'on',
ssl_key_file = fio.pathjoin(ssl_data_dir, 'server.key'),
ssl_cert_file = fio.pathjoin(ssl_data_dir, 'server.crt'),
ssl_ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt'),
},
request_opts = {
ssl_cert = fio.pathjoin(ssl_data_dir, 'bad_client.crt'),
ssl_key = fio.pathjoin(ssl_data_dir, 'bad_client.key'),
},
expected_err_msg = helpers.CONNECTION_REFUSED_ERR_MSG,
},
test_verify_client_on_certs_missing = {
ssl_opts = {
ssl_verify_client = 'on',
ssl_key_file = fio.pathjoin(ssl_data_dir, 'server.key'),
ssl_cert_file = fio.pathjoin(ssl_data_dir, 'server.crt'),
ssl_ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt'),
},
expected_err_msg = helpers.CONNECTION_REFUSED_ERR_MSG,
},
}

for name, tc in pairs(client_test_cases) do
Expand Down
6 changes: 6 additions & 0 deletions test/integration/http_tls_enabled_validate_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ local test_cases = {
},
expected_err_msg = "ssl_ciphers option must be a string",
},
ssl_verify_client_incorrect_value = {
opts = {
ssl_verify_client = "unknown",
},
expected_err_msg = '"unknown" option not exists. Available options: "on", "off", "optional"'
},
}

for name, case in pairs(test_cases) do
Expand Down
56 changes: 56 additions & 0 deletions test/integration/httpd_role_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,59 @@ g.test_enable_tls_on_config_reload = function(cg)
local resp = http_client:get('http://localhost:13000/ping')
t.assert_equals(resp.status, 444, 'response not 444')
end

g.test_ssl_verify_client = function(cg)
t.skip_if(not cg.params.use_tls, 'tls config required')

local cfg = table.copy(tls_config)

cfg.groups['group-001'].replicasets['replicaset-001'].roles_cfg['roles.httpd'].default
.ssl_ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt')
cfg.groups['group-001'].replicasets['replicaset-001'].roles_cfg['roles.httpd'].default
.ssl_verify_client = "on"
treegen.write_file(cg.server.chdir, 'config.yaml', yaml.encode(cfg))
local _, err = cg.server:eval("require('config'):reload()")
t.assert_not(err)

t.assert_error_msg_contains(helpers.CONNECTION_REFUSED_ERR_MSG, function()
http_client:get('https://localhost:13000/ping', {
ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt')
})
end)

local resp = http_client:get('https://localhost:13000/ping', {
ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt'),
ssl_cert = fio.pathjoin(ssl_data_dir, 'client.crt'),
ssl_key = fio.pathjoin(ssl_data_dir, 'client.key'),
})
t.assert_equals(resp.status, 200, 'response not 200')
t.assert_equals(resp.body, 'pong')

cfg.groups['group-001'].replicasets['replicaset-001'].roles_cfg['roles.httpd'].default
.ssl_verify_client = "optional"
treegen.write_file(cg.server.chdir, 'config.yaml', yaml.encode(cfg))
_, err = cg.server:eval("require('config'):reload()")
t.assert_not(err)

t.assert_error_msg_contains(helpers.CONNECTION_REFUSED_ERR_MSG, function()
http_client:get('https://localhost:13000/ping', {
ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt'),
ssl_cert = fio.pathjoin(ssl_data_dir, 'bad_client.crt'),
ssl_key = fio.pathjoin(ssl_data_dir, 'bad_client.key'),
})
end)

resp = http_client:get('https://localhost:13000/ping', {
ca_file = fio.pathjoin(ssl_data_dir, 'ca.crt'),
ssl_cert = fio.pathjoin(ssl_data_dir, 'client.crt'),
ssl_key = fio.pathjoin(ssl_data_dir, 'client.key'),
})
t.assert_equals(resp.status, 200, 'response not 200')
t.assert_equals(resp.body, 'pong')
end

g.after_test('test_ssl_verify_client', function(cg)
treegen.write_file(cg.server.chdir, 'config.yaml', yaml.encode(tls_config))
local _, err = cg.server:eval("require('config'):reload()")
t.assert_not(err)
end)
32 changes: 32 additions & 0 deletions test/ssl_data/bad_client.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFkDCCA3igAwIBAgIUdML0W9aabPXYExbeWFU4c5s7/ZYwDQYJKoZIhvcNAQEL
BQAwVTEQMA4GA1UECwwHVW5rbm93bjEQMA4GA1UECgwHVW5rbm93bjEQMA4GA1UE
BwwHVW5rbm93bjEQMA4GA1UECAwHdW5rbm93bjELMAkGA1UEBhMCQVUwIBcNMjUx
MTAxMTM1NzM4WhgPMjEyNTEwMDgxMzU3MzhaMGkxEjAQBgNVBAMMCWxvY2FsaG9z
dDEQMA4GA1UECwwHVW5rbm93bjEQMA4GA1UECgwHVW5rbm93bjEQMA4GA1UEBwwH
VW5rbm93bjEQMA4GA1UECAwHdW5rbm93bjELMAkGA1UEBhMCQVUwggIiMA0GCSqG
SIb3DQEBAQUAA4ICDwAwggIKAoICAQC9AKdee4oztHzNrfDvf0wrijKPaHCKtrwz
7vegGUiP6cQRLn9RO+OHnvZOxii/QdCtFAZHDLyhd5pwzyiJxh6iup2teOkmE9jQ
RdkFkZifJe5hzuRvZKj0Wdqe0T2bNzlNH2ejDrTD+I2n1N33pDcg7OIzm7w/FyV7
HdXOU52cOrwcCv+5OdG8qxr7KunrD/Es5HMr3YkNeEk6PNAZeKIFHEmiIZoavfcZ
v1Ks78jRNh1/FehgM1lrCvhAF7S+u3NTKoMRutLMMNJ67ag9bwVbeYgxtXFLwFr/
GBx+K1xnG9rsI6TiC48OoYBKSgFXmDLu27scgtIlbdlcMJBX4ElpTiLcPvo62UoC
TaImArBFaiFsO3QeG4Db6i20zXrlpTWJMDTq06Uk9zScpHGlFDLsLt3Ptk7hw9wf
kU/vMO/GAgU/ShQbTK/Cw0ZodTpAcCyyH60owx4ynBd+XgHEa3jbG2MAOsPtbgUL
OnboFUkwtwvKN+M647aD8OLQWGCgNOQM05MDe4BJnFf9yQEU0gyWQVT6n3hhgV3Z
RWZ4nrEz7qJf4ay+kvLrvP7jdELMmb2p+HATdzeiAb6jpIsmse6x/DfL96qc1j8G
H9P60W9oE0ISR+7Fy15Y+Wqov/WnrpbCIA/yw6JdjDRb+4qjY2+BmpGIwKWKND5I
C33s6oCh5wIDAQABo0IwQDAdBgNVHQ4EFgQUpiDiWDD57qUoauGYNJjODpqGr3Iw
HwYDVR0jBBgwFoAUfete7UEBQwYIC4dsESdN4ryLsZIwDQYJKoZIhvcNAQELBQAD
ggIBAGLBf4N8956edEl1o1lDyCk/NSdwk0th2LGZMh7WRLpGwh+Qwf42x5INjcBd
p8y2E6Avx5rtSDBgEqt7c1/Ug0aKlNxgu588MtBIaAy6PeyfPK1yjWE5MwSOFONn
qHcPKc92eixyZyv9BAC2PiqskFzTDAEQ78n1TBH4pgVurfoSybYOZcCy4nS6ug77
HNNVKoGX2TQUclC4ZToywYextggZALZEL+xxNz8Xt+1ak6GLhOFfxvGJU43lY4dd
PDiueObzeFrLkHq/Tt0l9p7glV0DHW4MC3R8w5fKIUyXcXGBX+UB2ewFaiDHsWCt
NiuSbWtOkAnt6I5I8h2exbC1mWbUzUTyMV9zfYmwXJrvtN5DiBhBOXODZns1ZWck
AKgyOhma8Uey7VaDuhNbobHh7eRhkD1qqX2+OQAHX8z19vGTWmwyCqjhuNdFd1uu
PLaGrqo8e1GrdrwcZeVrSI9Cp15zi4LmLnG8YiDG5RkoIR6h3VKNmZsq8/U/7ouS
pyx5TRsY9s2v37dTJIFEmeUuG4GDW4EG2DDtJ75qXlipfCHLe4BT0cSKYCAXpJ1v
aqUYzPPmiP9q1wYfIkuNjJ3AGwPGoaCpBOMFrul8XU3Qk+kjXfVw3ZD6wR20iL86
46UvD+VktOt6EZTOGjTdEjlyOzvRQdqqMIIiVNRx7gT8TlrN
-----END CERTIFICATE-----
52 changes: 52 additions & 0 deletions test/ssl_data/bad_client.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
4xz9jwcKbEzsHdwVB+OoRs47xcWsd923
-----END PRIVATE KEY-----
18 changes: 18 additions & 0 deletions test/unit/httpd_role_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,24 @@ local validation_cases = {
},
},
err = "log_requests option should be a string",
},
["ssl_verify_client_invalid_type"] = {
cfg = {
server = {
listen = "localhost:123",
ssl_verify_client = 1,
}
},
err = "ssl_verify_client option must be a string",
},
["ssl_verify_client_invalid_value"] = {
cfg = {
server = {
listen = "localhost:123",
ssl_verify_client = "unknown",
}
},
err = '"unknown" option not exists. Available options: "on", "off", "optional"',
}
}

Expand Down
Loading