test(tls-partial-chains): renewed intermediate_cacert
This commit is contained in:
parent
11c8e937b4
commit
8503d3c6dd
|
@ -8,8 +8,7 @@
|
|||
Prior to the improvement, the `key` in `${key}` could only contain letters, numbers, and underscores. Now the `key` supports any UTF8 character after the improvement.
|
||||
|
||||
- Adds a new feature to enable partial certificate chain validation for TLS listeners[#10553](https://github.com/emqx/emqx/pull/10553).
|
||||
If TLS listener has `partial_chain` set to `cacert_from_cacertfile`,
|
||||
the certificate in the `cacertfile` will be used as the `cacert` for chain path validation. If the `cacertfile` has a chain of certificates, the cert at the end of the file will be used as the `cacert` for path validation.
|
||||
If partial_chain is set to 'true', the last certificate in cacertfile is treated as the terminal of the certificate trust-chain. That is, the TLS handshake does not require full trust-chain, and EMQX will not try to validate the chain all the way up to the root CA.
|
||||
|
||||
## Bug fixes
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
改进前,`${key}` 中的 `key` 只能包含字母、数字和下划线。改进后 `key` 支持任意的 UTF8 字符了。
|
||||
|
||||
- 增加了一个新的功能,为TLS监听器启用部分证书链验证[#10553](https://github.com/emqx/emqx/pull/10553)。
|
||||
如果TLS监听器的 `partial_chain` 设置为 `cacert_from_cacertfile`,
|
||||
`cacertfile` 中的证书将被用作链式路径验证的 `cacert` 。如果 `cacertfile` 文件有一连串的证书,文件末尾的证书将被用作路径验证的 `cacert`。
|
||||
如果 partial_chain 设置为“true”,cacertfile 中的最后一个证书将被视为证书信任链的顶端证书。 也就是说,TLS 握手不需要完整的链,并且 EMQX 不会尝试一直验证链直到根 CA。
|
||||
|
||||
|
||||
## 修复
|
||||
|
||||
|
|
|
@ -186,7 +186,9 @@ opt_partial_chain(SslOpts) ->
|
|||
case proplists:get_value(partial_chain, SslOpts, undefined) of
|
||||
undefined ->
|
||||
SslOpts;
|
||||
cacert_from_cacertfile ->
|
||||
false ->
|
||||
SslOpts;
|
||||
V when V =:= cacert_from_cacertfile orelse V == true ->
|
||||
replace(SslOpts, partial_chain, cacert_from_cacertfile(SslOpts))
|
||||
end.
|
||||
|
||||
|
|
|
@ -70,6 +70,51 @@ t_conn_success_with_intermediate_cacert_bundle(Config) ->
|
|||
fail_when_ssl_error(Socket),
|
||||
ssl:close(Socket).
|
||||
|
||||
t_conn_success_with_renewed_intermediate_cacert(Config) ->
|
||||
Port = emqx_test_tls_certs_helper:select_free_port(ssl),
|
||||
DataDir = ?config(data_dir, Config),
|
||||
Options = [{ssl_options, [ {cacertfile, filename:join(DataDir, "intermediate1_renewed.pem")}
|
||||
, {certfile, filename:join(DataDir, "server1.pem")}
|
||||
, {keyfile, filename:join(DataDir, "server1.key")}
|
||||
| ?config(ssl_config, Config)
|
||||
]}],
|
||||
emqx_listeners:start_listener(ssl, Port, Options),
|
||||
{ok, Socket} = ssl:connect({127, 0, 0, 1}, Port, [{keyfile, filename:join(DataDir, "client1.key")},
|
||||
{certfile, filename:join(DataDir, "client1.pem")}
|
||||
], 1000),
|
||||
fail_when_ssl_error(Socket),
|
||||
ssl:close(Socket).
|
||||
|
||||
t_conn_fail_with_renewed_intermediate_cacert_and_client_using_old_complete_bundle(Config) ->
|
||||
Port = emqx_test_tls_certs_helper:select_free_port(ssl),
|
||||
DataDir = ?config(data_dir, Config),
|
||||
Options = [{ssl_options, [ {cacertfile, filename:join(DataDir, "intermediate2_renewed.pem")}
|
||||
, {certfile, filename:join(DataDir, "server2.pem")}
|
||||
, {keyfile, filename:join(DataDir, "server2.key")}
|
||||
| ?config(ssl_config, Config)
|
||||
]}],
|
||||
emqx_listeners:start_listener(ssl, Port, Options),
|
||||
{ok, Socket} = ssl:connect({127, 0, 0, 1}, Port, [{keyfile, filename:join(DataDir, "client2.key")},
|
||||
{certfile, filename:join(DataDir, "client2-complete-bundle.pem")}
|
||||
], 1000),
|
||||
fail_when_no_ssl_alert(Socket, unknown_ca),
|
||||
ssl:close(Socket).
|
||||
|
||||
t_conn_fail_with_renewed_intermediate_cacert_other_client(Config) ->
|
||||
Port = emqx_test_tls_certs_helper:select_free_port(ssl),
|
||||
DataDir = ?config(data_dir, Config),
|
||||
Options = [{ssl_options, [ {cacertfile, filename:join(DataDir, "intermediate1_renewed.pem")}
|
||||
, {certfile, filename:join(DataDir, "server1.pem")}
|
||||
, {keyfile, filename:join(DataDir, "server1.key")}
|
||||
| ?config(ssl_config, Config)
|
||||
]}],
|
||||
emqx_listeners:start_listener(ssl, Port, Options),
|
||||
{ok, Socket} = ssl:connect({127, 0, 0, 1}, Port, [{keyfile, filename:join(DataDir, "client2.key")},
|
||||
{certfile, filename:join(DataDir, "client2.pem")}
|
||||
], 1000),
|
||||
fail_when_no_ssl_alert(Socket, unknown_ca),
|
||||
ssl:close(Socket).
|
||||
|
||||
t_conn_fail_with_intermediate_cacert_bundle_but_incorrect_order(Config) ->
|
||||
Port = emqx_test_tls_certs_helper:select_free_port(ssl),
|
||||
DataDir = ?config(data_dir, Config),
|
||||
|
@ -208,5 +253,5 @@ t_conn_success_with_server_intermediate_and_client_root_chain(Config) ->
|
|||
ssl_config_verify_partial_chain() ->
|
||||
[ {verify, verify_peer}
|
||||
, {fail_if_no_peer_cert, true}
|
||||
, {partial_chain, cacert_from_cacertfile}
|
||||
, {partial_chain, true}
|
||||
].
|
||||
|
|
|
@ -73,7 +73,9 @@ gen_host_cert(H, CaName, Path, Opts) ->
|
|||
CN = str(H),
|
||||
HKey = filename(Path, "~s.key", [H]),
|
||||
HCSR = filename(Path, "~s.csr", [H]),
|
||||
HCSR2 = filename(Path, "~s.csr", [H]),
|
||||
HPEM = filename(Path, "~s.pem", [H]),
|
||||
HPEM2 = filename(Path, "~s_renewed.pem", [H]),
|
||||
HEXT = filename(Path, "~s.extfile", [H]),
|
||||
PasswordArg =
|
||||
case maps:get(password, Opts, undefined) of
|
||||
|
@ -82,44 +84,56 @@ gen_host_cert(H, CaName, Path, Opts) ->
|
|||
Password ->
|
||||
io_lib:format(" -passout pass:'~s' ", [Password])
|
||||
end,
|
||||
CSR_Cmd =
|
||||
lists:flatten(
|
||||
io_lib:format(
|
||||
"openssl req -new ~s -newkey ec:~s "
|
||||
"-keyout ~s -out ~s "
|
||||
"-addext \"subjectAltName=DNS:~s\" "
|
||||
"-addext basicConstraints=CA:TRUE "
|
||||
"-addext keyUsage=digitalSignature,keyAgreement,keyCertSign "
|
||||
"-subj \"/C=SE/O=Internet Widgits Pty Ltd/CN=~s\"",
|
||||
[PasswordArg, ECKeyFile, HKey, HCSR, CN, CN]
|
||||
)
|
||||
),
|
||||
|
||||
create_file(
|
||||
HEXT,
|
||||
"keyUsage=digitalSignature,keyAgreement,keyCertSign\n"
|
||||
"basicConstraints=CA:TRUE \n"
|
||||
"subjectAltName=DNS:~s\n",
|
||||
[CN]
|
||||
HEXT,
|
||||
"keyUsage=digitalSignature,keyAgreement,keyCertSign\n"
|
||||
"basicConstraints=CA:TRUE \n"
|
||||
"subjectAltName=DNS:~s\n",
|
||||
[CN]
|
||||
),
|
||||
CERT_Cmd =
|
||||
lists:flatten(
|
||||
|
||||
CSR_Cmd = csr_cmd(PasswordArg, ECKeyFile, HKey, HCSR, CN),
|
||||
CSR_Cmd2 = csr_cmd(PasswordArg, ECKeyFile, HKey, HCSR2, CN),
|
||||
|
||||
CERT_Cmd = cert_sign_cmd(HEXT, HCSR, ca_cert_name(Path, CaName), ca_key_name(Path, CaName), HPEM),
|
||||
%% 2nd cert for testing renewed cert.
|
||||
CERT_Cmd2 = cert_sign_cmd(HEXT, HCSR, ca_cert_name(Path, CaName), ca_key_name(Path, CaName), HPEM2),
|
||||
ct:pal(os:cmd(CSR_Cmd)),
|
||||
ct:pal(os:cmd(CSR_Cmd2)),
|
||||
ct:pal(os:cmd(CERT_Cmd)),
|
||||
ct:pal(os:cmd(CERT_Cmd2)),
|
||||
file:delete(HEXT).
|
||||
|
||||
cert_sign_cmd(ExtFile, CSRFile, CACert, CAKey, OutputCert)->
|
||||
lists:flatten(
|
||||
io_lib:format(
|
||||
"openssl x509 -req "
|
||||
"-extfile ~s "
|
||||
"-in ~s -CA ~s -CAkey ~s -CAcreateserial "
|
||||
"-out ~s -days 500",
|
||||
[
|
||||
HEXT,
|
||||
HCSR,
|
||||
ca_cert_name(Path, CaName),
|
||||
ca_key_name(Path, CaName),
|
||||
HPEM
|
||||
ExtFile,
|
||||
CSRFile,
|
||||
CACert,
|
||||
CAKey,
|
||||
OutputCert
|
||||
]
|
||||
)
|
||||
),
|
||||
ct:pal(os:cmd(CSR_Cmd)),
|
||||
ct:pal(os:cmd(CERT_Cmd)),
|
||||
file:delete(HEXT).
|
||||
).
|
||||
|
||||
csr_cmd(PasswordArg, ECKeyFile, HKey, HCSR, CN) ->
|
||||
lists:flatten(
|
||||
io_lib:format(
|
||||
"openssl req -new ~s -newkey ec:~s "
|
||||
"-keyout ~s -out ~s "
|
||||
"-addext \"subjectAltName=DNS:~s\" "
|
||||
"-addext basicConstraints=CA:TRUE "
|
||||
"-addext keyUsage=digitalSignature,keyAgreement,keyCertSign "
|
||||
"-subj \"/C=SE/O=Internet Widgits Pty Ltd/CN=~s\"",
|
||||
[PasswordArg, ECKeyFile, HKey, HCSR, CN, CN]
|
||||
)
|
||||
).
|
||||
|
||||
filename(Path, F, A) ->
|
||||
filename:join(Path, str(io_lib:format(F, A))).
|
||||
|
|
Loading…
Reference in New Issue