summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Eremin-Solenikov <dbaryshkov@gmail.com>2019-12-29 10:00:06 +0000
committerDmitry Eremin-Solenikov <dbaryshkov@gmail.com>2019-12-29 10:00:06 +0000
commitfb5035e58461cba9d22adc3c2b30e50358d8b307 (patch)
tree16f134ce7e31726a24c75c150f96ca760016e3c1
parent72b19c838054f56d098711a8b221788d0fd44d49 (diff)
parent9d1c8553e2b48d91128c2f044f6f920292036b8e (diff)
downloadgnutls-fb5035e58461cba9d22adc3c2b30e50358d8b307.tar.gz
Merge branch 'gost-split-5' into 'master'
Workaround for SChannel limitations See merge request gnutls/gnutls!1138
-rw-r--r--lib/auth/cert.c2
-rw-r--r--lib/ext/signature.c68
-rw-r--r--lib/ext/signature.h3
-rw-r--r--lib/tls-sig.c2
-rw-r--r--lib/tls13/certificate_request.c2
-rw-r--r--lib/tls13/certificate_verify.c2
-rw-r--r--tests/tls12-server-kx-neg.c20
7 files changed, 91 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 <algorithms.h>
#include <abstract_int.h>
+/*
+ * 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);
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
};