From 69ffa3a65a5a676a8b7d9bac2ff1f784dda37a72 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sat, 9 Nov 2019 02:01:22 +0300 Subject: SignatureAlgorithms: force-enable GOST signatures for GOST KX SChannel-based clients can not send GOST identifiers as a part of SignatureAlgorithms extension. To mitigate this forcefully enable GOST signature algorithms if client sends GOST ciphersuite. Signed-off-by: Dmitry Eremin-Solenikov --- lib/auth/cert.c | 2 +- lib/ext/signature.c | 68 +++++++++++++++++++++++++++++++++++++++-- lib/ext/signature.h | 3 +- lib/tls-sig.c | 2 +- lib/tls13/certificate_request.c | 2 +- lib/tls13/certificate_verify.c | 2 +- 6 files changed, 71 insertions(+), 8 deletions(-) diff --git a/lib/auth/cert.c b/lib/auth/cert.c index fabd7c8a41..3073a33d34 100644 --- a/lib/auth/cert.c +++ b/lib/auth/cert.c @@ -1516,7 +1516,7 @@ int cert_select_sign_algorithm(gnutls_session_t session, return 0; } - algo = _gnutls_session_get_sign_algo(session, cert, pkey, 0); + algo = _gnutls_session_get_sign_algo(session, cert, pkey, 0, cs->kx_algorithm); if (algo == GNUTLS_SIGN_UNKNOWN) return gnutls_assert_val(GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY); diff --git a/lib/ext/signature.c b/lib/ext/signature.c index 3f3652f51e..bb350f5863 100644 --- a/lib/ext/signature.c +++ b/lib/ext/signature.c @@ -35,6 +35,14 @@ #include #include +/* + * Some (all SChannel) clients fail to send proper SigAlgs due to Micro$oft crazyness. + * Patch the extension for them. + */ +#ifdef ENABLE_GOST +#define GOST_SIG_FIXUP_SCHANNEL +#endif + static int _gnutls_signature_algorithm_recv_params(gnutls_session_t session, const uint8_t * data, @@ -265,6 +273,23 @@ _gnutls_signature_algorithm_send_params(gnutls_session_t session, return 0; } +#ifdef GOST_SIG_FIXUP_SCHANNEL +static bool +is_gost_sig_present(sig_ext_st *priv) +{ + unsigned i; + const gnutls_sign_entry_st *se; + + for (i = 0; i < priv->sign_algorithms_size; i++) { + se = _gnutls_sign_to_entry(priv->sign_algorithms[i]); + if (se != NULL && _sign_is_gost(se)) + return true; + } + + return false; +} +#endif + /* Returns a requested by the peer signature algorithm that * matches the given certificate's public key algorithm. * @@ -277,7 +302,8 @@ gnutls_sign_algorithm_t _gnutls_session_get_sign_algo(gnutls_session_t session, gnutls_pcert_st * cert, gnutls_privkey_t privkey, - unsigned client_cert) + unsigned client_cert, + gnutls_kx_algorithm_t kx_algorithm) { unsigned i; int ret; @@ -296,9 +322,45 @@ _gnutls_session_get_sign_algo(gnutls_session_t session, _gnutls_hello_ext_get_priv(session, GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS, &epriv); - priv = epriv; + if (ret < 0) + priv = NULL; + else + priv = epriv; + +#ifdef GOST_SIG_FIXUP_SCHANNEL + /* + * Some (all SChannel) clients fail to send proper SigAlgs due to Micro$oft crazyness. + * If we are negotiating GOST KX (because we have received GOST + * ciphersuites) and if we have received no GOST SignatureAlgorithms, + * assume that the client could not send them and continue negotiation + * as if correct algorithm was sent. + */ + if (_gnutls_kx_is_vko_gost(kx_algorithm) && + (!priv || + !is_gost_sig_present(priv) || + !_gnutls_version_has_selectable_sighash(ver))) { + gnutls_digest_algorithm_t dig; + + _gnutls_handshake_log("EXT[%p]: GOST KX, but no GOST SigAlgs received, patching up.", session); + + if (cert_algo == GNUTLS_PK_GOST_01) + dig = GNUTLS_DIG_GOSTR_94; + else if (cert_algo == GNUTLS_PK_GOST_12_256) + dig = GNUTLS_DIG_STREEBOG_256; + else if (cert_algo == GNUTLS_PK_GOST_12_512) + dig = GNUTLS_DIG_STREEBOG_512; + else + dig = GNUTLS_DIG_SHA1; + + ret = gnutls_pk_to_sign(cert_algo, dig); + + if (!client_cert && _gnutls_session_sign_algo_enabled(session, ret) < 0) + goto fail; + return ret; + } +#endif - if (ret < 0 || !_gnutls_version_has_selectable_sighash(ver)) { + if (!priv || !_gnutls_version_has_selectable_sighash(ver)) { /* none set, allow SHA-1 only */ ret = gnutls_pk_to_sign(cert_algo, GNUTLS_DIG_SHA1); diff --git a/lib/ext/signature.h b/lib/ext/signature.h index a6448f34b6..ef42763cfe 100644 --- a/lib/ext/signature.h +++ b/lib/ext/signature.h @@ -34,7 +34,8 @@ gnutls_sign_algorithm_t _gnutls_session_get_sign_algo(gnutls_session_t session, gnutls_pcert_st * cert, gnutls_privkey_t privkey, - unsigned client_cert); + unsigned client_cert, + gnutls_kx_algorithm_t kx_algorithm); int _gnutls_sign_algorithm_parse_data(gnutls_session_t session, const uint8_t * data, size_t data_size); diff --git a/lib/tls-sig.c b/lib/tls-sig.c index 80514430ab..779e02c18f 100644 --- a/lib/tls-sig.c +++ b/lib/tls-sig.c @@ -627,7 +627,7 @@ _gnutls_handshake_sign_crt_vrfy12(gnutls_session_t session, const gnutls_sign_entry_st *se; int ret; - sign_algo = _gnutls_session_get_sign_algo(session, cert, pkey, 1); + sign_algo = _gnutls_session_get_sign_algo(session, cert, pkey, 1, GNUTLS_KX_UNKNOWN); if (sign_algo == GNUTLS_SIGN_UNKNOWN) { gnutls_assert(); return GNUTLS_E_UNWANTED_ALGORITHM; diff --git a/lib/tls13/certificate_request.c b/lib/tls13/certificate_request.c index d56ce42738..58fdbbc187 100644 --- a/lib/tls13/certificate_request.c +++ b/lib/tls13/certificate_request.c @@ -187,7 +187,7 @@ int _gnutls13_recv_certificate_request_int(gnutls_session_t session, gnutls_buff if (apr_cert_list_length > 0) { gnutls_sign_algorithm_t algo; - algo = _gnutls_session_get_sign_algo(session, &apr_cert_list[0], apr_pkey, 0); + algo = _gnutls_session_get_sign_algo(session, &apr_cert_list[0], apr_pkey, 0, GNUTLS_KX_UNKNOWN); if (algo == GNUTLS_SIGN_UNKNOWN) { _gnutls_handshake_log("HSK[%p]: rejecting client auth because of no suitable signature algorithm\n", session); _gnutls_selected_certs_deinit(session); diff --git a/lib/tls13/certificate_verify.c b/lib/tls13/certificate_verify.c index 6c3617c026..45ff6facfc 100644 --- a/lib/tls13/certificate_verify.c +++ b/lib/tls13/certificate_verify.c @@ -188,7 +188,7 @@ int _gnutls13_send_certificate_verify(gnutls_session_t session, unsigned again) } if (server) { - algo = _gnutls_session_get_sign_algo(session, &apr_cert_list[0], apr_pkey, 0); + algo = _gnutls_session_get_sign_algo(session, &apr_cert_list[0], apr_pkey, 0, GNUTLS_KX_UNKNOWN); if (algo == GNUTLS_SIGN_UNKNOWN) return gnutls_assert_val(GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY); -- cgit v1.2.1 From 9d1c8553e2b48d91128c2f044f6f920292036b8e Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Sat, 9 Nov 2019 02:29:19 +0300 Subject: tls12-server-kx-neg: add tests without GOST signature algorithms Add tests mimicking SChannel clients which are unable to send proper SignatureAlgorithms extension. Signed-off-by: Dmitry Eremin-Solenikov --- tests/tls12-server-kx-neg.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/tls12-server-kx-neg.c b/tests/tls12-server-kx-neg.c index 88d2666ef2..2d36c28882 100644 --- a/tests/tls12-server-kx-neg.c +++ b/tests/tls12-server-kx-neg.c @@ -526,6 +526,26 @@ test_case_st tests[] = { .server_prio = "NORMAL:-KX-ALL:+VKO-GOST-12:+GROUP-GOST-ALL:+GOST28147-TC26Z-CNT:+GOST28147-TC26Z-IMIT:+SIGN-GOSTR341012-512:+SIGN-GOSTR341012-256:+SIGN-GOSTR341001:-VERS-ALL:+VERS-TLS1.2", .client_prio = "NORMAL:-KX-ALL:+VKO-GOST-12:+GROUP-GOST-ALL:+GOST28147-TC26Z-CNT:+GOST28147-TC26Z-IMIT:+SIGN-GOSTR341012-512:+SIGN-GOSTR341012-256:+SIGN-GOSTR341001:-VERS-ALL:+VERS-TLS1.2" }, + { + .name = "TLS 1.2 VKO-GOST-12 with cred and GOST12-256 cert client lacking signature algs (like SChannel)", + .server_ret = 0, + .client_ret = 0, + .have_cert_cred = 1, + .have_gost12_256_cert = 1, + .not_on_fips = 1, + .server_prio = "NORMAL:-KX-ALL:+VKO-GOST-12:+GROUP-GOST-ALL:+GOST28147-TC26Z-CNT:+GOST28147-TC26Z-IMIT:+SIGN-GOSTR341012-512:+SIGN-GOSTR341012-256:+SIGN-GOSTR341001:-VERS-ALL:+VERS-TLS1.2", + .client_prio = "NONE:+VKO-GOST-12:+GROUP-GOST-ALL:+GOST28147-TC26Z-CNT:+GOST28147-TC26Z-IMIT:+VERS-TLS1.2:+SIGN-RSA-SHA256" + }, + { + .name = "TLS 1.2 VKO-GOST-12 with cred and GOST12-512 cert client lacking signature algs (like SChannel)", + .server_ret = 0, + .client_ret = 0, + .have_cert_cred = 1, + .have_gost12_512_cert = 1, + .not_on_fips = 1, + .server_prio = "NORMAL:-KX-ALL:+VKO-GOST-12:+GROUP-GOST-ALL:+GOST28147-TC26Z-CNT:+GOST28147-TC26Z-IMIT:+SIGN-GOSTR341012-512:+SIGN-GOSTR341012-256:+SIGN-GOSTR341001:-VERS-ALL:+VERS-TLS1.2", + .client_prio = "NONE:+VKO-GOST-12:+GROUP-GOST-ALL:+GOST28147-TC26Z-CNT:+GOST28147-TC26Z-IMIT:+VERS-TLS1.2:+SIGN-RSA-SHA256" + }, #endif }; -- cgit v1.2.1