diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2018-03-10 11:57:18 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2018-03-10 11:57:18 +0000 |
commit | 2d18661f21ab564e4d870ac320e15be9e2fcfebb (patch) | |
tree | 762e26344d99a905ca3f5ffd8766de1b90e68735 | |
parent | 659adce03edaf71538e9d61fb5092e393f8867f4 (diff) | |
parent | f14942024a6032e884fc8be4ff641149bc145ffc (diff) | |
download | gnutls-2d18661f21ab564e4d870ac320e15be9e2fcfebb.tar.gz |
Merge branch 'tmp-nmav-draft-ietf-tls-tls13-22' into 'master'
Move to draft-ietf-tls-tls-23
Closes #391, #400, #393, #389, #397, #398, #395, and #396
See merge request gnutls/gnutls!610
42 files changed, 1260 insertions, 400 deletions
diff --git a/lib/alert.c b/lib/alert.c index aec54615cf..182e97f21b 100644 --- a/lib/alert.c +++ b/lib/alert.c @@ -192,6 +192,7 @@ int gnutls_error_to_alert(int err, int *level) switch (err) { /* send appropriate alert */ case GNUTLS_E_PK_SIG_VERIFY_FAILED: + case GNUTLS_E_ERROR_IN_FINISHED_PACKET: ret = GNUTLS_A_DECRYPT_ERROR; _level = GNUTLS_AL_FATAL; break; diff --git a/lib/algorithms.h b/lib/algorithms.h index 556bc33901..495b20d439 100644 --- a/lib/algorithms.h +++ b/lib/algorithms.h @@ -327,6 +327,18 @@ struct gnutls_sign_entry_st { gnutls_pk_algorithm_t pk; gnutls_digest_algorithm_t hash; + /* if non-zero it must be the algorithm of the + * private key used or certificate. This is for algorithms + * which can have a different public key type than the + * private key (e.g., RSA PKCS#1 1.5 certificate, but + * an RSA-PSS private key, or an RSA private key and + * an RSA-PSS certificate). */ + gnutls_pk_algorithm_t priv_pk; + gnutls_pk_algorithm_t cert_pk; + + /* non-zero if it is ok to use under TLS1.3 */ + unsigned tls13_ok; + /* if this signature algorithm is restricted to a curve * under TLS 1.3. */ gnutls_ecc_curve_t curve; @@ -342,6 +354,28 @@ const gnutls_sign_entry_st *_gnutls_sign_to_entry(gnutls_sign_algorithm_t sign); const gnutls_sign_entry_st *_gnutls_pk_to_sign_entry(gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t hash); const gnutls_sign_entry_st *_gnutls_oid_to_sign_entry(const char *oid); +/* returns true if that signature can be generated + * from the given private key algorithm. */ +inline static unsigned +sign_supports_priv_pk_algorithm(const gnutls_sign_entry_st *se, gnutls_pk_algorithm_t pk) +{ + if (pk == se->pk || (se->priv_pk && se->priv_pk == pk)) + return 1; + + return 0; +} + +/* returns true if that signature can be verified with + * the given public key algorithm. */ +inline static unsigned +sign_supports_cert_pk_algorithm(const gnutls_sign_entry_st *se, gnutls_pk_algorithm_t pk) +{ + if (pk == se->pk || (se->cert_pk && se->cert_pk == pk)) + return 1; + + return 0; +} + bool _gnutls_sign_is_secure2(const gnutls_sign_entry_st *se, unsigned int flags); gnutls_pk_algorithm_t _gnutls_x509_sign_to_pk(gnutls_sign_algorithm_t diff --git a/lib/algorithms/protocols.c b/lib/algorithms/protocols.c index a7af6b834d..12ac1acf12 100644 --- a/lib/algorithms/protocols.c +++ b/lib/algorithms/protocols.c @@ -116,7 +116,7 @@ static const version_entry_st sup_versions[] = { .id = GNUTLS_TLS1_3, .age = 5, .major = 0x7f, - .minor = 21, + .minor = 23, .transport = GNUTLS_STREAM, .supported = 1, .explicit_iv = 0, diff --git a/lib/algorithms/sign.c b/lib/algorithms/sign.c index 33fd881892..5a45e9fa10 100644 --- a/lib/algorithms/sign.c +++ b/lib/algorithms/sign.c @@ -36,9 +36,6 @@ # define SHA1_SECURE_VAL _INSECURE_FOR_CERTS #endif -/* Signature algorithms may be listed twice with a different PK algorithm, - * e.g., RSA-PSS-SHA256 can be generated by GNUTLS_PK_RSA or GNUTLS_PK_RSA_PSS. - */ static const gnutls_sign_entry_st sign_algorithms[] = { /* RSA-PKCS#1 1.5: must be before PSS, * so that gnutls_pk_to_sign() will return @@ -67,37 +64,52 @@ static const gnutls_sign_entry_st sign_algorithms[] = { .oid = PK_PKIX1_RSA_PSS_OID, .id = GNUTLS_SIGN_RSA_PSS_SHA256, .pk = GNUTLS_PK_RSA_PSS, + .priv_pk = GNUTLS_PK_RSA, /* PKCS#11 doesn't separate RSA from RSA-PSS privkeys */ .hash = GNUTLS_DIG_SHA256, - .aid = {{8, 4}, SIG_SEM_DEFAULT}}, - {.name = "RSA-PSS-SHA256", + .tls13_ok = 1, + .aid = {{8, 9}, SIG_SEM_DEFAULT}}, + {.name = "RSA-PSS-RSAE-SHA256", .oid = PK_PKIX1_RSA_PSS_OID, - .id = GNUTLS_SIGN_RSA_PSS_SHA256, - .pk = GNUTLS_PK_RSA, + .id = GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, + .pk = GNUTLS_PK_RSA_PSS, + .cert_pk = GNUTLS_PK_RSA, + .priv_pk = GNUTLS_PK_RSA, .hash = GNUTLS_DIG_SHA256, + .tls13_ok = 1, .aid = {{8, 4}, SIG_SEM_DEFAULT}}, {.name = "RSA-PSS-SHA384", .oid = PK_PKIX1_RSA_PSS_OID, .id = GNUTLS_SIGN_RSA_PSS_SHA384, .pk = GNUTLS_PK_RSA_PSS, + .priv_pk = GNUTLS_PK_RSA, .hash = GNUTLS_DIG_SHA384, - .aid = {{8, 5}, SIG_SEM_DEFAULT}}, - {.name = "RSA-PSS-SHA384", + .tls13_ok = 1, + .aid = {{8, 0x0A}, SIG_SEM_DEFAULT}}, + {.name = "RSA-PSS-RSAE-SHA384", .oid = PK_PKIX1_RSA_PSS_OID, - .id = GNUTLS_SIGN_RSA_PSS_SHA384, - .pk = GNUTLS_PK_RSA, + .id = GNUTLS_SIGN_RSA_PSS_RSAE_SHA384, + .pk = GNUTLS_PK_RSA_PSS, + .cert_pk = GNUTLS_PK_RSA, + .priv_pk = GNUTLS_PK_RSA, .hash = GNUTLS_DIG_SHA384, + .tls13_ok = 1, .aid = {{8, 5}, SIG_SEM_DEFAULT}}, {.name = "RSA-PSS-SHA512", .oid = PK_PKIX1_RSA_PSS_OID, .id = GNUTLS_SIGN_RSA_PSS_SHA512, .pk = GNUTLS_PK_RSA_PSS, + .priv_pk = GNUTLS_PK_RSA, .hash = GNUTLS_DIG_SHA512, - .aid = {{8, 6}, SIG_SEM_DEFAULT}}, - {.name = "RSA-PSS-SHA512", + .tls13_ok = 1, + .aid = {{8, 0x0B}, SIG_SEM_DEFAULT}}, + {.name = "RSA-PSS-RSAE-SHA512", .oid = PK_PKIX1_RSA_PSS_OID, - .id = GNUTLS_SIGN_RSA_PSS_SHA512, - .pk = GNUTLS_PK_RSA, + .id = GNUTLS_SIGN_RSA_PSS_RSAE_SHA512, + .pk = GNUTLS_PK_RSA_PSS, + .cert_pk = GNUTLS_PK_RSA, + .priv_pk = GNUTLS_PK_RSA, .hash = GNUTLS_DIG_SHA512, + .tls13_ok = 1, .aid = {{8, 6}, SIG_SEM_DEFAULT}}, /* Ed25519: The hash algorithm here is set to be SHA512, although that is @@ -108,6 +120,7 @@ static const gnutls_sign_entry_st sign_algorithms[] = { .id = GNUTLS_SIGN_EDDSA_ED25519, .pk = GNUTLS_PK_EDDSA_ED25519, .hash = GNUTLS_DIG_SHA512, + .tls13_ok = 1, .aid = {{8, 7}, SIG_SEM_DEFAULT}}, /* ECDSA */ @@ -144,18 +157,21 @@ static const gnutls_sign_entry_st sign_algorithms[] = { .pk = GNUTLS_PK_ECDSA, .curve = GNUTLS_ECC_CURVE_SECP256R1, .hash = GNUTLS_DIG_SHA256, + .tls13_ok = 1, .aid = {{4, 3}, SIG_SEM_TLS13}}, {.name = "ECDSA-SECP384R1-SHA384", .id = GNUTLS_SIGN_ECDSA_SECP384R1_SHA384, .pk = GNUTLS_PK_ECDSA, .curve = GNUTLS_ECC_CURVE_SECP384R1, .hash = GNUTLS_DIG_SHA384, + .tls13_ok = 1, .aid = {{5, 3}, SIG_SEM_TLS13}}, {.name = "ECDSA-SECP521R1-SHA512", .id = GNUTLS_SIGN_ECDSA_SECP521R1_SHA512, .pk = GNUTLS_PK_ECDSA, .curve = GNUTLS_ECC_CURVE_SECP521R1, .hash = GNUTLS_DIG_SHA512, + .tls13_ok = 1, .aid = {{6, 3}, SIG_SEM_TLS13}}, /* ECDSA-SHA3 */ @@ -616,7 +632,8 @@ gnutls_sign_get_pk_algorithm(gnutls_sign_algorithm_t sign) * @pk: is a public key algorithm * * This function returns non-zero if the public key algorithm corresponds to - * the given signature algorithm. + * the given signature algorithm. That is, if that signature can be generated + * from the given private key algorithm. * * Since: 3.6.0 * @@ -625,7 +642,16 @@ gnutls_sign_get_pk_algorithm(gnutls_sign_algorithm_t sign) unsigned gnutls_sign_supports_pk_algorithm(gnutls_sign_algorithm_t sign, gnutls_pk_algorithm_t pk) { - GNUTLS_SIGN_LOOP( if(p->id && p->id == sign && pk == p->pk) { return 1; } ); + const gnutls_sign_entry_st *p; + unsigned r; + + for(p = sign_algorithms; p->name != NULL; p++) { + if (p->id && p->id == sign) { + r = sign_supports_priv_pk_algorithm(p, pk); + if (r != 0) + return r; + } + } return 0; } diff --git a/lib/buffers.c b/lib/buffers.c index 414ea50307..52729f3723 100644 --- a/lib/buffers.c +++ b/lib/buffers.c @@ -900,17 +900,17 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel, return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET); - hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2; + hsk->rtype = hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2; hsk->sequence = 0; hsk->start_offset = 0; hsk->end_offset = hsk->length; } else #endif - { /* TLS or DTLS handshake headers */ + { /* TLS or DTLS handshake headers */ - hsk->htype = dataptr[0]; + hsk->rtype = hsk->htype = dataptr[0]; /* we do not use DECR_LEN because we know * that the packet has enough data. @@ -932,6 +932,15 @@ parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel, MIN((_mbuffer_get_udata_size(bufel) - handshake_header_size), hsk->length); } + + /* TLS1.3: distinguish server hello versus hello retry request. + * The epitome of slick protocol design. */ + if (hsk->htype == GNUTLS_HANDSHAKE_SERVER_HELLO && hsk->start_offset == 0 && !IS_DTLS(session)) { + if (_mbuffer_get_udata_size(bufel) > handshake_header_size+2+GNUTLS_RANDOM_SIZE && + memcmp(dataptr+handshake_header_size+2, HRR_RANDOM, GNUTLS_RANDOM_SIZE) == 0) { + hsk->htype = GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST; + } + } } data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size; diff --git a/lib/ext/dumbfw.c b/lib/ext/dumbfw.c index 3ffeeca560..7faff65693 100644 --- a/lib/ext/dumbfw.c +++ b/lib/ext/dumbfw.c @@ -40,7 +40,7 @@ const hello_ext_entry_st ext_mod_dumbfw = { .tls_id = 21, .gid = GNUTLS_EXTENSION_DUMBFW, .parse_type = GNUTLS_EXT_APPLICATION, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_HRR, + .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO, .recv_func = NULL, .send_func = _gnutls_dumbfw_send_params, diff --git a/lib/ext/key_share.c b/lib/ext/key_share.c index d4cf9b78c8..f110e10268 100644 --- a/lib/ext/key_share.c +++ b/lib/ext/key_share.c @@ -45,7 +45,7 @@ static int key_share_send_params(gnutls_session_t session, const hello_ext_entry_st ext_mod_key_share = { .name = "Key Share", - .tls_id = 40, + .tls_id = 51, .gid = GNUTLS_EXTENSION_KEY_SHARE, .parse_type = _GNUTLS_EXT_TLS_POST_CS, .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO|GNUTLS_EXT_FLAG_HRR, diff --git a/lib/ext/signature.c b/lib/ext/signature.c index 8b4bb1ac65..7bf2761fdf 100644 --- a/lib/ext/signature.c +++ b/lib/ext/signature.c @@ -283,6 +283,7 @@ _gnutls_session_get_sign_algo(gnutls_session_t session, sig_ext_st *priv; gnutls_ext_priv_data_t epriv; unsigned int cert_algo; + const gnutls_sign_entry_st *se; if (unlikely(ver == NULL)) return gnutls_assert_val(GNUTLS_SIGN_UNKNOWN); @@ -304,23 +305,28 @@ _gnutls_session_get_sign_algo(gnutls_session_t session, return ret; } + + for (i = 0; i < priv->sign_algorithms_size; i++) { - _gnutls_handshake_log("checking cert compat with %s\n", gnutls_sign_algorithm_get_name(priv->sign_algorithms[i])); + se = _gnutls_sign_to_entry(priv->sign_algorithms[i]); + if (se == NULL) + continue; + + _gnutls_handshake_log("checking cert compat with %s\n", se->name); if (_gnutls_privkey_compatible_with_sig(privkey, priv->sign_algorithms[i]) == 0) continue; - if (gnutls_sign_supports_pk_algorithm(priv->sign_algorithms[i], cert_algo) != 0) { + if (sign_supports_cert_pk_algorithm(se, cert_algo) != 0) { if (_gnutls_pubkey_compatible_with_sig - (session, cert->pubkey, ver, - priv->sign_algorithms[i]) < 0) + (session, cert->pubkey, ver, se->id) < 0) continue; if (_gnutls_session_sign_algo_enabled - (session, priv->sign_algorithms[i]) < 0) + (session, se->id) < 0) continue; - return priv->sign_algorithms[i]; + return se->id; } } @@ -328,7 +334,7 @@ _gnutls_session_get_sign_algo(gnutls_session_t session, * using algorithms we don't always enable by default (e.g., DSA-SHA1), * continue and sign with it. */ if (client_cert) { - _gnutls_audit_log(session, "No shared signature schemes with peer for client certificate (%s). Is the certificate a legacy one?", + _gnutls_audit_log(session, "No shared signature schemes with peer for client certificate (%s). Is the certificate a legacy one?\n", gnutls_pk_get_name(cert_algo)); } @@ -357,8 +363,9 @@ _gnutls_session_sign_algo_enabled(gnutls_session_t session, if (ver->tls13_sem) { /* disallow RSA, DSA, and SHA1 */ const gnutls_sign_entry_st *se; + se = _gnutls_sign_to_entry(sig); - if (se == NULL || se->pk == GNUTLS_PK_RSA || se->pk == GNUTLS_PK_DSA || se->hash == GNUTLS_DIG_SHA1) { + if (se == NULL || (se->tls13_ok == 0)) { gnutls_assert(); goto disallowed; } diff --git a/lib/ext/supported_versions.c b/lib/ext/supported_versions.c index deca74039d..b2eff6be80 100644 --- a/lib/ext/supported_versions.c +++ b/lib/ext/supported_versions.c @@ -29,6 +29,7 @@ #include "num.h" #include <hello_ext.h> #include <ext/supported_versions.h> +#include "handshake.h" static int supported_versions_recv_params(gnutls_session_t session, const uint8_t * data, @@ -40,8 +41,9 @@ const hello_ext_entry_st ext_mod_supported_versions = { .name = "Supported Versions", .tls_id = 43, .gid = GNUTLS_EXTENSION_SUPPORTED_VERSIONS, - .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO, - .parse_type = GNUTLS_EXT_MANDATORY, /* force parsing prior to EXT_TLS extensions */ + .validity = GNUTLS_EXT_FLAG_CLIENT_HELLO|GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO| + GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO|GNUTLS_EXT_FLAG_HRR, + .parse_type = GNUTLS_EXT_VERSION_NEG, /* force parsing prior to EXT_TLS extensions */ .recv_func = supported_versions_recv_params, .send_func = supported_versions_send_params, @@ -99,10 +101,32 @@ supported_versions_recv_params(gnutls_session_t session, /* if we are here, none of the versions were acceptable */ return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); - } else { - /* a server should never send this message */ - gnutls_assert(); - return GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION; + } else { /* client */ + const version_entry_st *vers; + + DECR_LEN(data_size, 2); + + if (data_size != 0) + return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); + + major = data[0]; + minor = data[1]; + + vers = nversion_to_entry(major, minor); + if (!vers) + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + + set_adv_version(session, major, minor); + proto = _gnutls_version_get(major, minor); + + _gnutls_handshake_log("EXT[%p]: Negotiated version: %d.%d\n", + session, (int)major, (int)minor); + + ret = _gnutls_negotiate_version(session, proto, major, minor); + if (ret < 0) { + gnutls_assert(); + return ret; + } } return 0; @@ -116,10 +140,18 @@ supported_versions_send_params(gnutls_session_t session, { uint8_t versions[32]; size_t versions_size; + const version_entry_st *vers; int ret; /* this function sends the client extension data (dnsname) */ if (session->security_parameters.entity == GNUTLS_CLIENT) { + vers = _gnutls_version_max(session); + + /* do not advertise this extension when we haven't TLS1.3 + * enabled. */ + if (vers && !vers->tls13_sem) + return 0; + ret = _gnutls_write_supported_versions(session, versions, sizeof(versions)); if (ret <= 0) /* if this function doesn't succeed do not send anything */ return 0; @@ -131,6 +163,26 @@ supported_versions_send_params(gnutls_session_t session, return gnutls_assert_val(ret); return versions_size+2; + } else { + vers = get_version(session); + if (unlikely(vers == NULL)) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + /* don't use this extension to negotiate versions <= 1.2, + * pretend we don't support it, so that we use a single + * code path to negotiate these protocols. */ + if (!vers->tls13_sem) + return 0; + + ret = _gnutls_buffer_append_data(extdata, &vers->major, 1); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_buffer_append_data(extdata, &vers->minor, 1); + if (ret < 0) + return gnutls_assert_val(ret); + + return 2; } return 0; diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index baa9c14589..1d75c4a09f 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -134,6 +134,16 @@ typedef struct { #define GNUTLS_MASTER_SIZE 48 #define GNUTLS_RANDOM_SIZE 32 +#define HRR_RANDOM \ + "\xCF\x21\xAD\x74\xE5\x9A\x61\x11\xBE\x1D\x8C\x02\x1E\x65\xB8\x91" \ + "\xC2\xA2\x11\x16\x7A\xBB\x8C\x5E\x07\x9E\x09\xE2\xC8\xA8\x33\x9C" + +/* Under TLS1.3 a hello retry request is sent as server hello */ +#define REAL_HSK_TYPE(t) ((t)==GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST?GNUTLS_HANDSHAKE_SERVER_HELLO:t) + +/* Enable: Appendix D4. Middlebox Compatibility Mode */ +#define TLS13_APPENDIX_D4 1 + /* DTLS */ #define DTLS_RETRANS_TIMEOUT 1000 @@ -254,9 +264,10 @@ typedef enum handshake_state_t { STATE0 = 0, STATE1, STATE2, STATE15, STATE16, STATE17, STATE18, STATE19, STATE20 = 20, STATE21, STATE22, STATE30 = 30, STATE31, STATE40 = 40, STATE41, STATE50 = 50, - STATE90=90, STATE91, STATE92, STATE93, + STATE90=90, STATE91, STATE92, STATE93, STATE99=99, STATE100=100, STATE101, STATE102, STATE103, STATE104, STATE105, STATE106, STATE107, STATE108, STATE109, STATE110, + STATE111, STATE150 /* key update */ } handshake_state_t; @@ -362,6 +373,10 @@ typedef enum content_type_t { typedef struct { /* Handshake layer type and sequence of message */ gnutls_handshake_description_t htype; + + /* The "real" type received; that is, it does not distinguish + * HRR from server hello, while htype does */ + gnutls_handshake_description_t rtype; uint32_t length; /* valid in DTLS */ diff --git a/lib/handshake-tls13.c b/lib/handshake-tls13.c index 721f334eca..edb6e80574 100644 --- a/lib/handshake-tls13.c +++ b/lib/handshake-tls13.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Red Hat, Inc. + * Copyright (C) 2017-2018 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -78,62 +78,72 @@ int _gnutls13_handshake_client(gnutls_session_t session) int ret = 0; switch (STATE) { + case STATE99: case STATE100: +#ifdef TLS13_APPENDIX_D4 + /* We send it before keys are generated. That works because CCS + * is always being cached and queued and not being sent directly */ + ret = _gnutls_send_change_cipher_spec(session, AGAIN(STATE100)); + STATE = STATE100; + IMED_RET("send change cipher spec", ret, 0); +#endif + /* fall through */ + case STATE101: ret = generate_hs_traffic_keys(session); - STATE = STATE100; + STATE = STATE101; IMED_RET("generate session keys", ret, 0); /* fall through */ - case STATE101: + case STATE102: ret = _gnutls13_recv_encrypted_extensions(session); - STATE = STATE101; + STATE = STATE102; IMED_RET("recv encrypted extensions", ret, 0); /* fall through */ - case STATE102: + case STATE103: ret = _gnutls13_recv_certificate_request(session); - STATE = STATE102; + STATE = STATE103; IMED_RET("recv certificate request", ret, 0); /* fall through */ - case STATE103: + case STATE104: ret = _gnutls13_recv_certificate(session); - STATE = STATE103; + STATE = STATE104; IMED_RET("recv certificate", ret, 0); /* fall through */ - case STATE104: + case STATE105: ret = _gnutls13_recv_certificate_verify(session); - STATE = STATE104; + STATE = STATE105; IMED_RET("recv server certificate verify", ret, 0); /* fall through */ - case STATE105: + case STATE106: ret = _gnutls_run_verify_callback(session, GNUTLS_CLIENT); - STATE = STATE105; + STATE = STATE106; if (ret < 0) return gnutls_assert_val(ret); FALLTHROUGH; - case STATE106: - ret = _gnutls13_recv_finished(session); - STATE = STATE106; - IMED_RET("recv finished", ret, 0); - /* fall through */ case STATE107: - ret = _gnutls13_send_certificate(session, AGAIN(STATE107)); + ret = _gnutls13_recv_finished(session); STATE = STATE107; - IMED_RET("send certificate", ret, 0); + IMED_RET("recv finished", ret, 0); /* fall through */ case STATE108: - ret = _gnutls13_send_certificate_verify(session, AGAIN(STATE108)); + ret = _gnutls13_send_certificate(session, AGAIN(STATE108)); STATE = STATE108; - IMED_RET("send certificate verify", ret, 0); + IMED_RET("send certificate", ret, 0); /* fall through */ case STATE109: - ret = _gnutls13_send_finished(session, AGAIN(STATE109)); + ret = _gnutls13_send_certificate_verify(session, AGAIN(STATE109)); STATE = STATE109; - IMED_RET("send finished", ret, 0); + IMED_RET("send certificate verify", ret, 0); /* fall through */ case STATE110: + ret = _gnutls13_send_finished(session, AGAIN(STATE110)); + STATE = STATE110; + IMED_RET("send finished", ret, 0); + /* fall through */ + case STATE111: ret = generate_ap_traffic_keys(session); - STATE = STATE110; + STATE = STATE111; IMED_RET("generate app keys", ret, 0); STATE = STATE0; @@ -243,7 +253,7 @@ int _gnutls13_handshake_server(gnutls_session_t session) /* this is triggered by post_client_hello, and instructs the * handshake to proceed but be put on hold */ ret = GNUTLS_E_INTERRUPTED; - STATE = STATE100; /* hello already parsed -> move on */ + STATE = STATE99; /* hello already parsed -> move on */ } else { STATE = STATE92; } @@ -255,62 +265,70 @@ int _gnutls13_handshake_server(gnutls_session_t session) STATE = STATE93; IMED_RET("send hello", ret, 0); /* fall through */ + case STATE99: case STATE100: - ret = - generate_hs_traffic_keys(session); +#ifdef TLS13_APPENDIX_D4 + ret = _gnutls_send_change_cipher_spec(session, AGAIN(STATE100)); STATE = STATE100; - IMED_RET("generate session keys", ret, 0); + IMED_RET("send change cipher spec", ret, 0); +#endif /* fall through */ case STATE101: - ret = _gnutls13_send_encrypted_extensions(session, AGAIN(STATE101)); + ret = + generate_hs_traffic_keys(session); STATE = STATE101; - IMED_RET("send encrypted extensions", ret, 0); + IMED_RET("generate session keys", ret, 0); /* fall through */ case STATE102: - ret = _gnutls13_send_certificate_request(session, AGAIN(STATE102)); + ret = _gnutls13_send_encrypted_extensions(session, AGAIN(STATE102)); STATE = STATE102; - IMED_RET("send certificate request", ret, 0); + IMED_RET("send encrypted extensions", ret, 0); /* fall through */ case STATE103: - ret = _gnutls13_send_certificate(session, AGAIN(STATE103)); + ret = _gnutls13_send_certificate_request(session, AGAIN(STATE103)); STATE = STATE103; - IMED_RET("send certificate", ret, 0); + IMED_RET("send certificate request", ret, 0); /* fall through */ case STATE104: - ret = _gnutls13_send_certificate_verify(session, AGAIN(STATE104)); + ret = _gnutls13_send_certificate(session, AGAIN(STATE104)); STATE = STATE104; - IMED_RET("send certificate verify", ret, 0); + IMED_RET("send certificate", ret, 0); /* fall through */ case STATE105: - ret = _gnutls13_send_finished(session, AGAIN(STATE105)); + ret = _gnutls13_send_certificate_verify(session, AGAIN(STATE105)); STATE = STATE105; - IMED_RET("send finished", ret, 0); + IMED_RET("send certificate verify", ret, 0); /* fall through */ case STATE106: - ret = _gnutls13_recv_certificate(session); + ret = _gnutls13_send_finished(session, AGAIN(STATE106)); STATE = STATE106; - IMED_RET("recv certificate", ret, 0); + IMED_RET("send finished", ret, 0); /* fall through */ case STATE107: - ret = _gnutls13_recv_certificate_verify(session); + ret = _gnutls13_recv_certificate(session); STATE = STATE107; - IMED_RET("recv certificate verify", ret, 0); + IMED_RET("recv certificate", ret, 0); /* fall through */ case STATE108: - ret = _gnutls_run_verify_callback(session, GNUTLS_CLIENT); + ret = _gnutls13_recv_certificate_verify(session); STATE = STATE108; + IMED_RET("recv certificate verify", ret, 0); + /* fall through */ + case STATE109: + ret = _gnutls_run_verify_callback(session, GNUTLS_CLIENT); + STATE = STATE109; if (ret < 0) return gnutls_assert_val(ret); /* fall through */ - case STATE109: + case STATE110: ret = _gnutls13_recv_finished(session); - STATE = STATE109; + STATE = STATE110; IMED_RET("recv finished", ret, 0); /* fall through */ - case STATE110: + case STATE111: ret = generate_ap_traffic_keys(session); - STATE = STATE110; + STATE = STATE111; IMED_RET("generate app keys", ret, 0); STATE = STATE0; diff --git a/lib/handshake.c b/lib/handshake.c index 179fcb8009..955fd5dd08 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2000-2016 Free Software Foundation, Inc. - * Copyright (C) 2015-2017 Red Hat, Inc. + * Copyright (C) 2015-2018 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -422,14 +422,15 @@ _gnutls_finished(gnutls_session_t session, int type, void *ret, /* returns the 0 on success or a negative error code. */ int -_gnutls_negotiate_legacy_version(gnutls_session_t session, +_gnutls_negotiate_version(gnutls_session_t session, gnutls_protocol_t adv_version, uint8_t major, uint8_t minor) { const version_entry_st *vers; /* if we do not support that version, unless that version is TLS 1.2; * TLS 1.2 is handled separately because it is always advertized under TLS 1.3 or later */ - if (adv_version == GNUTLS_VERSION_UNKNOWN || _gnutls_version_is_supported(session, adv_version) == 0) { + if (adv_version == GNUTLS_VERSION_UNKNOWN || + _gnutls_version_is_supported(session, adv_version) == 0) { if (adv_version == GNUTLS_TLS1_2) { vers = _gnutls_version_max(session); @@ -477,6 +478,7 @@ _gnutls_user_hello_func(gnutls_session_t session, gnutls_protocol_t adv_version, uint8_t major, uint8_t minor) { int ret, sret = 0; + const version_entry_st *vers; if (session->internals.user_hello_func != NULL) { ret = session->internals.user_hello_func(session); @@ -489,13 +491,18 @@ _gnutls_user_hello_func(gnutls_session_t session, return ret; } - /* Here we need to renegotiate the version since the callee might - * have disabled some TLS versions. - */ - ret = _gnutls_negotiate_legacy_version(session, adv_version, major, minor); - if (ret < 0) { - gnutls_assert(); - return ret; + vers = get_version(session); + if (!vers->tls13_sem) { + /* Here we need to renegotiate the version since the callee might + * have disabled some TLS versions. We only do it for TLS1.2 or + * earlier, as TLS1.3 uses a different set of ciphersuites, and + * thus we cannot fallback. + */ + ret = _gnutls_negotiate_version(session, adv_version, major, minor); + if (ret < 0) { + gnutls_assert(); + return ret; + } } } return sret; @@ -519,6 +526,7 @@ read_client_hello(gnutls_session_t session, uint8_t * data, int len = datalen; uint8_t major, minor; uint8_t *suite_ptr, *comp_ptr, *session_id, *ext_ptr; + const version_entry_st *vers; DECR_LEN(len, 2); _gnutls_handshake_log("HSK[%p]: Client's version: %d.%d\n", @@ -530,7 +538,7 @@ read_client_hello(gnutls_session_t session, uint8_t * data, minor = data[pos+1]; set_adv_version(session, major, minor); - neg_version = _gnutls_negotiate_legacy_version(session, adv_version, major, minor); + neg_version = _gnutls_negotiate_version(session, adv_version, major, minor); if (neg_version < 0) { gnutls_assert(); return neg_version; @@ -598,46 +606,64 @@ read_client_hello(gnutls_session_t session, uint8_t * data, ext_ptr = &data[pos]; ext_size = len; - /* Parse only the mandatory to read extensions for resumption. - * We don't want to parse any other extensions since - * we don't want new extension values to override the - * resumed ones. - */ + /* Parse only the mandatory to read extensions for resumption + * and version negotiation. We don't want to parse any other + * extensions since we don't want new extension values to override + * the resumed ones. */ ret = _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_CLIENT_HELLO, - GNUTLS_EXT_MANDATORY, - ext_ptr, ext_size); - if (ret < 0) { - gnutls_assert(); - return ret; - } + GNUTLS_EXT_VERSION_NEG, + ext_ptr, ext_size); + if (ret < 0) + return gnutls_assert_val(ret); ret = - _gnutls_server_restore_session(session, session_id, - session_id_len); + _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_CLIENT_HELLO, + GNUTLS_EXT_MANDATORY, + ext_ptr, ext_size); + if (ret < 0) + return gnutls_assert_val(ret); - if (session_id_len > 0) - session->internals.resumption_requested = 1; + vers = get_version(session); + if (unlikely(vers == NULL)) + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); - if (ret == 0) { /* resumed using default TLS resumption! */ - ret = _gnutls_server_select_suite(session, suite_ptr, suite_size, 1); - if (ret < 0) - return gnutls_assert_val(ret); + if (!vers->tls13_sem) { + ret = + _gnutls_server_restore_session(session, session_id, + session_id_len); - ret = resume_copy_required_values(session); - if (ret < 0) - return gnutls_assert_val(ret); + if (session_id_len > 0) + session->internals.resumption_requested = 1; - session->internals.resumed = RESUME_TRUE; + if (ret == 0) { /* resumed using default TLS resumption! */ + ret = _gnutls_server_select_suite(session, suite_ptr, suite_size, 1); + if (ret < 0) + return gnutls_assert_val(ret); - return _gnutls_user_hello_func(session, adv_version, major, minor); - } else { - _gnutls_generate_session_id(session->security_parameters. - session_id, - &session->security_parameters. - session_id_size); + ret = resume_copy_required_values(session); + if (ret < 0) + return gnutls_assert_val(ret); + + session->internals.resumed = RESUME_TRUE; + + return _gnutls_user_hello_func(session, adv_version, major, minor); + } else { + ret = _gnutls_generate_session_id(session->security_parameters. + session_id, + &session->security_parameters. + session_id_size); + if (ret < 0) + return gnutls_assert_val(ret); - session->internals.resumed = RESUME_FALSE; + session->internals.resumed = RESUME_FALSE; + } + } else { /* TLS1.3 */ + /* we echo client's session ID - length was checked previously */ + assert(session_id_len <= GNUTLS_MAX_SESSION_ID_SIZE); + if (session_id_len > 0) + memcpy(session->security_parameters.session_id, session_id, session_id_len); + session->security_parameters.session_id_size = session_id_len; } /* Parse the extensions (if any) @@ -646,8 +672,8 @@ read_client_hello(gnutls_session_t session, uint8_t * data, * sslv3 and higher, even though sslv3 doesn't officially support them. */ ret = _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_CLIENT_HELLO, - GNUTLS_EXT_APPLICATION, - ext_ptr, ext_size); + GNUTLS_EXT_APPLICATION, + ext_ptr, ext_size); /* len is the rest of the parsed length */ if (ret < 0) { gnutls_assert(); @@ -664,7 +690,7 @@ read_client_hello(gnutls_session_t session, uint8_t * data, /* Session tickets are parsed in this point */ ret = _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_CLIENT_HELLO, - GNUTLS_EXT_TLS, ext_ptr, ext_size); + GNUTLS_EXT_TLS, ext_ptr, ext_size); if (ret < 0) { gnutls_assert(); return ret; @@ -1068,9 +1094,22 @@ inline if ((session->internals.h_type == type || session->internals.h_type == GNUTLS_HANDSHAKE_ANY) && (session->internals.h_post == post - || session->internals.h_post == GNUTLS_HOOK_BOTH)) + || session->internals.h_post == GNUTLS_HOOK_BOTH)) { + + /* internal API for testing: when we are expected to + * wait for GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC, we + * do so, but not when doing for all messages. The + * reason is that change cipher specs are not handshake + * messages, and we don't support waiting for them + * consistently (only sending is tracked, not receiving). + */ + if (type == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC && + session->internals.h_type != GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC) + return 0; + return session->internals.h_hook(session, type, post, incoming, &msg); + } } return 0; } @@ -1104,7 +1143,7 @@ _gnutls_send_handshake(gnutls_session_t session, mbuffer_st * bufel, i_datasize = _mbuffer_get_udata_size(bufel); datasize = i_datasize + _mbuffer_get_uhead_size(bufel); - data[pos++] = (uint8_t) type; + data[pos++] = (uint8_t) REAL_HSK_TYPE(type); _gnutls_write_uint24(_mbuffer_get_udata_size(bufel), &data[pos]); pos += 3; @@ -1350,7 +1389,7 @@ _gnutls_recv_handshake(gnutls_session_t session, goto cleanup; } - ret = handshake_hash_add_recvd(session, hsk.htype, + ret = handshake_hash_add_recvd(session, hsk.rtype, hsk.header, hsk.header_size, hsk.data.data, hsk.data.length); @@ -1549,11 +1588,11 @@ set_client_ciphersuite(gnutls_session_t session, uint8_t suite[2]) /* This function returns 0 if we are resuming a session or -1 otherwise. * This also sets the variables in the session. Used only while reading a server - * hello. + * hello. Only applicable to TLS1.2 or earlier. */ static int client_check_if_resuming(gnutls_session_t session, - uint8_t * session_id, int session_id_len) + uint8_t * session_id, int session_id_len) { char buf[2 * GNUTLS_MAX_SESSION_ID_SIZE + 1]; int ret; @@ -1598,13 +1637,6 @@ client_check_if_resuming(gnutls_session_t session, no_resume: /* keep the new session id */ session->internals.resumed = RESUME_FALSE; /* we are not resuming */ - session->security_parameters.session_id_size = - session_id_len; - if (session_id_len > 0) { - memcpy(session->security_parameters.session_id, session_id, - session_id_len); - } - return -1; } } @@ -1619,11 +1651,14 @@ read_server_hello(gnutls_session_t session, uint8_t * data, int datalen) { uint8_t session_id_len = 0; + uint8_t *session_id; + uint8_t *cs_pos, *comp_pos, *srandom_pos; + uint8_t major, minor; int pos = 0; int ret = 0; int len = datalen; - const version_entry_st *vers; - gnutls_ext_flags_t ext_parse_flag; + unsigned ext_parse_flag = 0; + const version_entry_st *vers, *saved_vers; if (datalen < GNUTLS_RANDOM_SIZE+2) { gnutls_assert(); @@ -1634,14 +1669,17 @@ read_server_hello(gnutls_session_t session, session, data[pos], data[pos + 1]); DECR_LEN(len, 2); - vers = nversion_to_entry(data[pos], data[pos + 1]); + major = data[pos]; + minor = data[pos+1]; + + saved_vers = get_version(session); /* will be non-null if HRR has been received */ + + vers = nversion_to_entry(major, minor); if (unlikely(vers == NULL)) return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); - if (_gnutls_version_is_supported(session, vers->id) == 0) { - gnutls_assert(); - return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; - } + if (vers->tls13_sem) /* that shouldn't have been negotiated here */ + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); if (_gnutls_set_current_version(session, vers->id) < 0) return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); @@ -1649,64 +1687,100 @@ read_server_hello(gnutls_session_t session, pos += 2; DECR_LEN(len, GNUTLS_RANDOM_SIZE); - ret = _gnutls_set_server_random(session, vers, &data[pos]); + srandom_pos = &data[pos]; + pos += GNUTLS_RANDOM_SIZE; + + /* Read session ID + */ + DECR_LEN(len, 1); + session_id_len = data[pos++]; + + if (len < session_id_len || session_id_len > GNUTLS_MAX_SESSION_ID_SIZE) { + gnutls_assert(); + return GNUTLS_E_ILLEGAL_PARAMETER; + } + DECR_LEN(len, session_id_len); + session_id = &data[pos]; + pos += session_id_len; + + DECR_LEN(len, 2); + cs_pos = &data[pos]; + pos += 2; + + /* move to compression + */ + DECR_LEN(len, 1); + comp_pos = &data[pos]; + pos++; + + /* parse extensions to figure version */ + ret = + _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO| + GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO, + GNUTLS_EXT_VERSION_NEG, + &data[pos], len); if (ret < 0) return gnutls_assert_val(ret); - pos += GNUTLS_RANDOM_SIZE; + vers = get_version(session); + if (unlikely(vers == NULL)) + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + if (vers->tls13_sem) { + if (major != 0x03 || minor != 0x03) + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + } - if (!vers->tls13_sem) { - /* Read session ID - */ - DECR_LEN(len, 1); - session_id_len = data[pos++]; + if (_gnutls_version_is_supported(session, vers->id) == 0) + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); - if (len < session_id_len || session_id_len > GNUTLS_MAX_SESSION_ID_SIZE) { - gnutls_assert(); - return GNUTLS_E_ILLEGAL_PARAMETER; - } - DECR_LEN(len, session_id_len); + /* set server random - done after final version is selected */ + ret = _gnutls_set_server_random(session, vers, srandom_pos); + if (ret < 0) + return gnutls_assert_val(ret); - /* check if we are resuming and set the appropriate - * values; - */ - if (client_check_if_resuming - (session, &data[pos], session_id_len) == 0) { - pos += session_id_len + 2 + 1; - DECR_LEN(len, 2 + 1); + /* check if we are resuming and set the appropriate + * values; + */ + if (!vers->tls13_sem && + client_check_if_resuming(session, session_id, session_id_len) == 0) { - ret = - _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, - GNUTLS_EXT_MANDATORY, - &data[pos], len); - if (ret < 0) { - gnutls_assert(); - return ret; - } - return 0; - } + ret = + _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO, + GNUTLS_EXT_MANDATORY, + &data[pos], len); + if (ret < 0) + return gnutls_assert_val(ret); - pos += session_id_len; + return 0; + } else { + session->security_parameters.session_id_size = session_id_len; + if (session_id_len > 0) + memcpy(session->security_parameters.session_id, session_id, + session_id_len); } /* Check if the given cipher suite is supported and copy * it to the session. */ - - DECR_LEN(len, 2); - ret = set_client_ciphersuite(session, &data[pos]); + ret = set_client_ciphersuite(session, cs_pos); if (ret < 0) { gnutls_assert(); return ret; } - pos += 2; if (session->internals.hsk_flags & HSK_HRR_RECEIVED) { /* check if ciphersuite matches */ - if (memcmp(session->security_parameters.cs->id, session->internals.hrr_cs, 2) != 0) + if (memcmp(cs_pos, session->internals.hrr_cs, 2) != 0) + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); + + /* check if HRR version matches this version */ + if (vers != saved_vers) return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); } + if (*comp_pos != 0) + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); + if (vers->tls13_sem) { /* TLS 1.3 Early Secret */ ret = _tls13_init_secret(session, NULL, 0); @@ -1719,46 +1793,42 @@ read_server_hello(gnutls_session_t session, if (ret < 0) return gnutls_assert_val(ret); - ext_parse_flag = GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO; + ext_parse_flag |= GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO; } else { - /* move to compression - */ - DECR_LEN(len, 1); - pos++; - ext_parse_flag = GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO; + ext_parse_flag |= GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO; } /* Parse extensions in order. */ ret = _gnutls_parse_hello_extensions(session, - ext_parse_flag, - GNUTLS_EXT_MANDATORY, - &data[pos], len); + ext_parse_flag, + GNUTLS_EXT_MANDATORY, + &data[pos], len); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_parse_hello_extensions(session, - ext_parse_flag, - GNUTLS_EXT_APPLICATION, - &data[pos], len); + ext_parse_flag, + GNUTLS_EXT_APPLICATION, + &data[pos], len); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_parse_hello_extensions(session, - ext_parse_flag, - GNUTLS_EXT_TLS, - &data[pos], len); + ext_parse_flag, + GNUTLS_EXT_TLS, + &data[pos], len); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_parse_hello_extensions(session, - ext_parse_flag, - _GNUTLS_EXT_TLS_POST_CS, - &data[pos], len); + ext_parse_flag, + _GNUTLS_EXT_TLS_POST_CS, + &data[pos], len); if (ret < 0) return gnutls_assert_val(ret); @@ -1793,7 +1863,7 @@ static int send_client_hello(gnutls_session_t session, int again) mbuffer_st *bufel = NULL; int type; int ret = 0; - const version_entry_st *hver, *min_ver; + const version_entry_st *hver, *min_ver, *max_ver; uint8_t tver[2]; gnutls_buffer_st extdata; int rehandshake = 0; @@ -1829,7 +1899,8 @@ static int send_client_hello(gnutls_session_t session, int again) if (hver == NULL) { gnutls_assert(); - return GNUTLS_E_NO_PRIORITIES_WERE_SET; + ret = GNUTLS_E_NO_PRIORITIES_WERE_SET; + goto cleanup; } if (unlikely(session->internals.default_hello_version[0] != 0)) { @@ -1848,7 +1919,8 @@ static int send_client_hello(gnutls_session_t session, int again) (unsigned)tver[0], (unsigned)tver[1]); min_ver = _gnutls_version_lowest(session); - if (min_ver == NULL) { + max_ver = _gnutls_version_max(session); + if (min_ver == NULL || max_ver == NULL) { gnutls_assert(); ret = GNUTLS_E_NO_PRIORITIES_WERE_SET; goto cleanup; @@ -1858,8 +1930,10 @@ static int send_client_hello(gnutls_session_t session, int again) * (RSA uses it). */ set_adv_version(session, hver->major, hver->minor); - if (_gnutls_set_current_version(session, hver->id) < 0) - return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + if (_gnutls_set_current_version(session, hver->id) < 0) { + ret = gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + goto cleanup; + } if (session->internals.priorities->min_record_version != 0) { /* Advertize the lowest supported (SSL 3.0) record packet @@ -1882,24 +1956,43 @@ static int send_client_hello(gnutls_session_t session, int again) if (!(session->internals.hsk_flags & HSK_HRR_RECEIVED) && !(IS_DTLS(session) && session->internals.dtls.hsk_hello_verify_requests == 0)) { ret = _gnutls_gen_client_random(session); - if (ret < 0) - return gnutls_assert_val(ret); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } } ret = _gnutls_buffer_append_data(&extdata, - session->security_parameters.client_random, - GNUTLS_RANDOM_SIZE); + session->security_parameters.client_random, + GNUTLS_RANDOM_SIZE); if (ret < 0) { gnutls_assert(); goto cleanup; } - /* Copy the Session ID +#ifdef TLS13_APPENDIX_D4 + if (max_ver->tls13_sem && + session->security_parameters.session_id_size == 0) { + + /* Under TLS1.3 we generate a random session ID to make + * the TLS1.3 session look like a resumed TLS1.2 session */ + ret = _gnutls_generate_session_id(session->security_parameters. + session_id, + &session->security_parameters. + session_id_size); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + } +#endif + + /* Copy the Session ID - if any */ ret = _gnutls_buffer_append_data_prefix(&extdata, 8, - session->internals.resumed_security_parameters.session_id, - session_id_len); + session->internals.resumed_security_parameters.session_id, + session_id_len); if (ret < 0) { gnutls_assert(); goto cleanup; @@ -1957,8 +2050,8 @@ static int send_client_hello(gnutls_session_t session, int again) ret = _gnutls_gen_hello_extensions(session, &extdata, - GNUTLS_EXT_FLAG_CLIENT_HELLO, - type); + GNUTLS_EXT_FLAG_CLIENT_HELLO, + type); if (ret < 0) { gnutls_assert(); goto cleanup; @@ -1986,7 +2079,8 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) session->security_parameters.session_id_size; char tmpbuf[2 * GNUTLS_MAX_SESSION_ID_SIZE + 1]; const version_entry_st *vers; - gnutls_ext_flags_t ext_parse_flag; + uint8_t vbytes[2]; + unsigned extflag = 0; _gnutls_buffer_init(&buf); @@ -2001,50 +2095,46 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) if (ret < 0) return gnutls_assert_val(ret); - ext_parse_flag = GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO; + vbytes[0] = 0x03; /* TLS1.2 */ + vbytes[1] = 0x03; + extflag |= GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO; } else { - ext_parse_flag = GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO; + vbytes[0] = vers->major; + vbytes[1] = vers->minor; + extflag |= GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO; } ret = _gnutls_buffer_init_handshake_mbuffer(&buf); if (ret < 0) return gnutls_assert_val(ret); - ret = _gnutls_buffer_append_data(&buf, &vers->major, 1); + ret = _gnutls_buffer_append_data(&buf, vbytes, 2); if (ret < 0) { gnutls_assert(); goto fail; } - ret = _gnutls_buffer_append_data(&buf, &vers->minor, 1); + ret = _gnutls_buffer_append_data(&buf, + session->security_parameters.server_random, + GNUTLS_RANDOM_SIZE); if (ret < 0) { gnutls_assert(); goto fail; } - ret = _gnutls_buffer_append_data(&buf, - session->security_parameters.server_random, - GNUTLS_RANDOM_SIZE); + ret = _gnutls_buffer_append_data_prefix(&buf, 8, + session->security_parameters.session_id, + session_id_len); if (ret < 0) { gnutls_assert(); goto fail; } - if (!vers->tls13_sem) { - ret = _gnutls_buffer_append_data_prefix(&buf, 8, - session->security_parameters.session_id, - session_id_len); - if (ret < 0) { - gnutls_assert(); - goto fail; - } - - _gnutls_handshake_log("HSK[%p]: SessionID: %s\n", session, - _gnutls_bin2hex(session-> - security_parameters.session_id, - session_id_len, tmpbuf, - sizeof(tmpbuf), NULL)); - } + _gnutls_handshake_log("HSK[%p]: SessionID: %s\n", session, + _gnutls_bin2hex(session-> + security_parameters.session_id, + session_id_len, tmpbuf, + sizeof(tmpbuf), NULL)); ret = _gnutls_buffer_append_data(&buf, session->security_parameters.cs->id, @@ -2054,17 +2144,16 @@ int _gnutls_send_server_hello(gnutls_session_t session, int again) goto fail; } - if (!vers->tls13_sem) { - ret = _gnutls_buffer_append_prefix(&buf, 8, 0); - if (ret < 0) { - gnutls_assert(); - goto fail; - } + /* compression */ + ret = _gnutls_buffer_append_prefix(&buf, 8, 0); + if (ret < 0) { + gnutls_assert(); + goto fail; } ret = _gnutls_gen_hello_extensions(session, &buf, - ext_parse_flag, + extflag, (session->internals.resumed == RESUME_TRUE) ? GNUTLS_EXT_MANDATORY : @@ -2556,7 +2645,7 @@ static int handshake_client(gnutls_session_t session) const version_entry_st *ver; reset: - if (STATE >= STATE100) + if (STATE >= STATE99) return _gnutls13_handshake_client(session); switch (STATE) { @@ -2605,7 +2694,7 @@ static int handshake_client(gnutls_session_t session) case STATE4: ver = get_version(session); if (ver->tls13_sem) { /* TLS 1.3 state machine */ - STATE = STATE100; + STATE = STATE99; goto reset; } @@ -2778,7 +2867,7 @@ static int handshake_client(gnutls_session_t session) /* This function is to be called if the handshake was successfully * completed. This sends a Change Cipher Spec packet to the peer. */ -static ssize_t send_change_cipher_spec(gnutls_session_t session, int again) +ssize_t _gnutls_send_change_cipher_spec(gnutls_session_t session, int again) { uint8_t *data; mbuffer_st *bufel; @@ -2786,7 +2875,7 @@ static ssize_t send_change_cipher_spec(gnutls_session_t session, int again) const version_entry_st *vers; if (again == 0) { - bufel = _gnutls_handshake_alloc(session, 1); + bufel = _gnutls_handshake_alloc(session, 3); /* max for DTLS0.9 */ if (bufel == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); @@ -2809,6 +2898,13 @@ static ssize_t send_change_cipher_spec(gnutls_session_t session, int again) session->internals.dtls.hsk_write_seq++; } + ret = call_hook_func(session, GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC, GNUTLS_HOOK_PRE, 0, + data, 1); + if (ret < 0) { + _mbuffer_xfree(&bufel); + return gnutls_assert_val(ret); + } + ret = _gnutls_handshake_io_cache_int(session, GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC, @@ -2818,6 +2914,12 @@ static ssize_t send_change_cipher_spec(gnutls_session_t session, int again) return gnutls_assert_val(ret); } + ret = call_hook_func(session, GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC, GNUTLS_HOOK_POST, 0, + data, 1); + if (ret < 0) { + return gnutls_assert_val(ret); + } + _gnutls_handshake_log("REC[%p]: Sent ChangeCipherSpec\n", session); } @@ -2836,7 +2938,7 @@ static int send_handshake_final(gnutls_session_t session, int init) switch (FINAL_STATE) { case STATE0: case STATE1: - ret = send_change_cipher_spec(session, FAGAIN(STATE1)); + ret = _gnutls_send_change_cipher_spec(session, FAGAIN(STATE1)); FINAL_STATE = STATE0; if (ret < 0) { @@ -3021,7 +3123,7 @@ static int handshake_server(gnutls_session_t session) ver = get_version(session); if (ver->tls13_sem) { /* TLS 1.3 state machine */ - STATE = STATE100; + STATE = STATE99; goto reset; } diff --git a/lib/handshake.h b/lib/handshake.h index 109f1247c8..1096226410 100644 --- a/lib/handshake.h +++ b/lib/handshake.h @@ -64,13 +64,15 @@ int _gnutls_generate_session_id(uint8_t * session_id, uint8_t * len); int _gnutls_gen_server_random(gnutls_session_t session, int version); void _gnutls_set_client_random(gnutls_session_t session, uint8_t * rnd); +ssize_t _gnutls_send_change_cipher_spec(gnutls_session_t session, int again); + int _gnutls_send_server_hello(gnutls_session_t session, int again); int _gnutls_find_pk_algos_in_ciphersuites(uint8_t * data, int datalen); int _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data, unsigned int datalen, unsigned int scsv_only); -int _gnutls_negotiate_legacy_version(gnutls_session_t session, +int _gnutls_negotiate_version(gnutls_session_t session, gnutls_protocol_t adv_version, uint8_t major, uint8_t minor); int _gnutls_user_hello_func(gnutls_session_t session, gnutls_protocol_t adv_version, uint8_t major, uint8_t minor); diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index b9142519aa..5b449d148c 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -534,7 +534,6 @@ typedef enum { GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST = 3, GNUTLS_HANDSHAKE_NEW_SESSION_TICKET = 4, GNUTLS_HANDSHAKE_END_OF_EARLY_DATA = 5, - GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST = 6, GNUTLS_HANDSHAKE_ENCRYPTED_EXTENSIONS = 8, GNUTLS_HANDSHAKE_CERTIFICATE_PKT = 11, GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE = 12, @@ -547,7 +546,8 @@ typedef enum { GNUTLS_HANDSHAKE_SUPPLEMENTAL = 23, GNUTLS_HANDSHAKE_KEY_UPDATE = 24, GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC = 254, - GNUTLS_HANDSHAKE_CLIENT_HELLO_V2 = 1024 + GNUTLS_HANDSHAKE_CLIENT_HELLO_V2 = 1024, + GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST = 1025, } gnutls_handshake_description_t; #define GNUTLS_HANDSHAKE_ANY ((unsigned int)-1) @@ -797,9 +797,21 @@ const char *gnutls_pk_algorithm_get_name(gnutls_pk_algorithm_t algorithm); * @GNUTLS_SIGN_RSA_SHA3_256: Digital signature algorithm RSA with SHA3-256. * @GNUTLS_SIGN_RSA_SHA3_384: Digital signature algorithm RSA with SHA3-384. * @GNUTLS_SIGN_RSA_SHA3_512: Digital signature algorithm RSA with SHA3-512. - * @GNUTLS_SIGN_RSA_PSS_SHA256: Digital signature algorithm RSA with SHA-256, with PSS padding. - * @GNUTLS_SIGN_RSA_PSS_SHA384: Digital signature algorithm RSA with SHA-384, with PSS padding. - * @GNUTLS_SIGN_RSA_PSS_SHA512: Digital signature algorithm RSA with SHA-512, with PSS padding. + * @GNUTLS_SIGN_RSA_PSS_RSAE_SHA256: Digital signature algorithm RSA with SHA-256, + * with PSS padding (RSA PKCS#1 1.5 certificate). This signature is identical + * to #GNUTLS_SIGN_RSA_PSS_SHA256, but they are distinct as the TLS1.3 protocol + * treats them differently. + * @GNUTLS_SIGN_RSA_PSS_RSAE_SHA384: Digital signature algorithm RSA with SHA-384, + * with PSS padding (RSA PKCS#1 1.5 certificate). This signature is identical + * to #GNUTLS_SIGN_RSA_PSS_SHA384, but they are distinct as the TLS1.3 protocol + * treats them differently. + * @GNUTLS_SIGN_RSA_PSS_RSAE_SHA512: Digital signature algorithm RSA with SHA-512, + * with PSS padding (RSA PKCS#1 1.5 certificate). This signature is identical + * to #GNUTLS_SIGN_RSA_PSS_SHA512, but they are distinct as the TLS1.3 protocol + * treats them differently. + * @GNUTLS_SIGN_RSA_PSS_SHA256: Digital signature algorithm RSA with SHA-256, with PSS padding (RSA-PSS certificate). + * @GNUTLS_SIGN_RSA_PSS_SHA384: Digital signature algorithm RSA with SHA-384, with PSS padding (RSA-PSS certificate). + * @GNUTLS_SIGN_RSA_PSS_SHA512: Digital signature algorithm RSA with SHA-512, with PSS padding (RSA-PSS certificate). * @GNUTLS_SIGN_EDDSA_ED25519: Digital signature algorithm EdDSA with Ed25519 curve. * * Enumeration of different digital signature algorithms. @@ -849,7 +861,11 @@ typedef enum { GNUTLS_SIGN_ECDSA_SECP256R1_SHA256 = 37, GNUTLS_SIGN_ECDSA_SECP384R1_SHA384 = 38, GNUTLS_SIGN_ECDSA_SECP521R1_SHA512 = 39, - GNUTLS_SIGN_MAX = GNUTLS_SIGN_ECDSA_SECP521R1_SHA512 + + GNUTLS_SIGN_RSA_PSS_RSAE_SHA256 = 40, + GNUTLS_SIGN_RSA_PSS_RSAE_SHA384 = 41, + GNUTLS_SIGN_RSA_PSS_RSAE_SHA512 = 42, + GNUTLS_SIGN_MAX = GNUTLS_SIGN_RSA_PSS_RSAE_SHA512 } gnutls_sign_algorithm_t; /** @@ -2715,25 +2731,24 @@ int gnutls_ext_raw_parse(void *ctx, gnutls_ext_raw_process_func cb, /** * gnutls_ext_parse_type_t: - * @GNUTLS_EXT_NONE: Never parsed - * @GNUTLS_EXT_ANY: Any extension type (internal use only). - * @GNUTLS_EXT_APPLICATION: Application extension. - * @GNUTLS_EXT_TLS: TLS-internal extension. - * @GNUTLS_EXT_MANDATORY: Extension parsed even if resuming (or extensions are disabled). + * @GNUTLS_EXT_NONE: Never to be parsed + * @GNUTLS_EXT_ANY: Any extension type (should not be used as it is used only internally). + * @GNUTLS_EXT_VERSION_NEG: Extensions to be parsed first for TLS version negotiation. + * @GNUTLS_EXT_MANDATORY: Parsed after @GNUTLS_EXT_VERSION_NEG and even when resuming. + * @GNUTLS_EXT_APPLICATION: Parsed after @GNUTLS_EXT_MANDATORY + * @GNUTLS_EXT_TLS: TLS-internal extensions, parsed after @GNUTLS_EXT_APPLICATION. * - * Enumeration of different TLS extension parsing types. This type is - * to indicate whether an extension is useful to application - * level or TLS level only. This is used to decide the appropriate time - * each extension is parsed at during the server or client hello parsing. + * Enumeration of different TLS extension parsing phases. The @gnutls_ext_parse_type_t + * indicates the time/phase an extension is parsed during Client or Server hello parsing. * - * This applies to TLS 1.2 and earlier versions. */ typedef enum { GNUTLS_EXT_ANY = 0, GNUTLS_EXT_APPLICATION = 1, GNUTLS_EXT_TLS = 2, GNUTLS_EXT_MANDATORY = 3, - GNUTLS_EXT_NONE = 4 + GNUTLS_EXT_NONE = 4, + GNUTLS_EXT_VERSION_NEG = 5 } gnutls_ext_parse_type_t; /** diff --git a/lib/priority.c b/lib/priority.c index a83a1ffc78..8e2132ffea 100644 --- a/lib/priority.c +++ b/lib/priority.c @@ -349,6 +349,7 @@ static const int* cipher_priority_secure192 = _cipher_priority_secure192; static const int _sign_priority_default[] = { GNUTLS_SIGN_RSA_SHA256, GNUTLS_SIGN_RSA_PSS_SHA256, + GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_ECDSA_SHA256, GNUTLS_SIGN_ECDSA_SECP256R1_SHA256, @@ -356,11 +357,13 @@ static const int _sign_priority_default[] = { GNUTLS_SIGN_RSA_SHA384, GNUTLS_SIGN_RSA_PSS_SHA384, + GNUTLS_SIGN_RSA_PSS_RSAE_SHA384, GNUTLS_SIGN_ECDSA_SHA384, GNUTLS_SIGN_ECDSA_SECP384R1_SHA384, GNUTLS_SIGN_RSA_SHA512, GNUTLS_SIGN_RSA_PSS_SHA512, + GNUTLS_SIGN_RSA_PSS_RSAE_SHA512, GNUTLS_SIGN_ECDSA_SHA512, GNUTLS_SIGN_ECDSA_SECP521R1_SHA512, @@ -391,17 +394,20 @@ static const int* sign_priority_suiteb192 = _sign_priority_suiteb192; static const int _sign_priority_secure128[] = { GNUTLS_SIGN_RSA_SHA256, GNUTLS_SIGN_RSA_PSS_SHA256, + GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_ECDSA_SHA256, GNUTLS_SIGN_ECDSA_SECP256R1_SHA256, GNUTLS_SIGN_EDDSA_ED25519, GNUTLS_SIGN_RSA_SHA384, GNUTLS_SIGN_RSA_PSS_SHA384, + GNUTLS_SIGN_RSA_PSS_RSAE_SHA384, GNUTLS_SIGN_ECDSA_SHA384, GNUTLS_SIGN_ECDSA_SECP384R1_SHA384, GNUTLS_SIGN_RSA_SHA512, GNUTLS_SIGN_RSA_PSS_SHA512, + GNUTLS_SIGN_RSA_PSS_RSAE_SHA512, GNUTLS_SIGN_ECDSA_SHA512, GNUTLS_SIGN_ECDSA_SECP521R1_SHA512, @@ -412,10 +418,12 @@ static const int* sign_priority_secure128 = _sign_priority_secure128; static const int _sign_priority_secure192[] = { GNUTLS_SIGN_RSA_SHA384, GNUTLS_SIGN_RSA_PSS_SHA384, + GNUTLS_SIGN_RSA_PSS_RSAE_SHA384, GNUTLS_SIGN_ECDSA_SHA384, GNUTLS_SIGN_ECDSA_SECP384R1_SHA384, GNUTLS_SIGN_RSA_SHA512, GNUTLS_SIGN_RSA_PSS_SHA512, + GNUTLS_SIGN_RSA_PSS_RSAE_SHA512, GNUTLS_SIGN_ECDSA_SHA512, GNUTLS_SIGN_ECDSA_SECP521R1_SHA512, diff --git a/lib/privkey.c b/lib/privkey.c index 10afdf90f1..e5b7e83965 100644 --- a/lib/privkey.c +++ b/lib/privkey.c @@ -1148,13 +1148,13 @@ gnutls_privkey_sign_data2(gnutls_privkey_t signer, { int ret; gnutls_x509_spki_st params; - const gnutls_sign_entry_st *e; + const gnutls_sign_entry_st *se; if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); - e = _gnutls_sign_to_entry(algo); - if (e == NULL) + se = _gnutls_sign_to_entry(algo); + if (se == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ret = _gnutls_privkey_get_spki_params(signer, ¶ms); @@ -1163,14 +1163,14 @@ gnutls_privkey_sign_data2(gnutls_privkey_t signer, return ret; } - ret = _gnutls_privkey_update_spki_params(signer, e->pk, e->hash, + ret = _gnutls_privkey_update_spki_params(signer, se->pk, se->hash, flags, ¶ms); if (ret < 0) { gnutls_assert(); return ret; } - return privkey_sign_and_hash_data(signer, _gnutls_sign_to_entry(algo), data, signature, ¶ms); + return privkey_sign_and_hash_data(signer, se, data, signature, ¶ms); } /** @@ -1831,8 +1831,13 @@ unsigned _gnutls_privkey_compatible_with_sig(gnutls_privkey_t privkey, * and RSA keys which cannot do RSA-PSS (e.g., smart card) from * negotiating RSA-PSS sig. */ - if (privkey->pk_algorithm == GNUTLS_PK_RSA_PSS && se->pk != GNUTLS_PK_RSA_PSS) { + + if (se->pk != privkey->pk_algorithm) { /* if the PK algorithm of the signature differs to the one on the pubkey */ + if (!sign_supports_priv_pk_algorithm(se, privkey->pk_algorithm)) { + _gnutls_handshake_log("cannot use privkey of %s with %s\n", + gnutls_pk_get_name(privkey->pk_algorithm), se->name); return 0; + } } if (privkey->type == GNUTLS_PRIVKEY_EXT) { diff --git a/lib/pubkey.c b/lib/pubkey.c index 466e2dee63..d6d374b786 100644 --- a/lib/pubkey.c +++ b/lib/pubkey.c @@ -1518,7 +1518,7 @@ int fixup_spki_params(const gnutls_pk_params_st *key_params, const gnutls_sign_e unsigned bits; if (se->pk != key_params->algo) { - if (!gnutls_sign_supports_pk_algorithm(se->id, key_params->algo)) { + if (!sign_supports_priv_pk_algorithm(se, key_params->algo)) { _gnutls_debug_log("have key: %s/%d, with sign %s/%d\n", gnutls_pk_get_name(key_params->algo), key_params->algo, se->name, se->id); @@ -1729,7 +1729,7 @@ int pubkey_supports_sig(gnutls_pubkey_t pubkey, gnutls_ecc_curve_t curve = pubkey->params.curve; if (curve != se->curve) { - _gnutls_debug_log("have key: ECDSA with %s/%d, with sign %s/%d\n", + _gnutls_handshake_log("have key: ECDSA with %s/%d, with sign %s/%d\n", gnutls_ecc_curve_get_name(curve), (int)curve, se->name, se->id); return gnutls_assert_val(GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY); @@ -1737,8 +1737,8 @@ int pubkey_supports_sig(gnutls_pubkey_t pubkey, } if (se->pk != pubkey->params.algo) { /* if the PK algorithm of the signature differs to the one on the pubkey */ - if (!gnutls_sign_supports_pk_algorithm(se->id, pubkey->params.algo)) { - _gnutls_debug_log("have key: %s/%d, with sign %s/%d\n", + if (!sign_supports_priv_pk_algorithm(se, pubkey->params.algo)) { + _gnutls_handshake_log("have key: %s/%d, with sign %s/%d\n", gnutls_pk_get_name(pubkey->params.algo), pubkey->params.algo, se->name, se->id); return gnutls_assert_val(GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY); diff --git a/lib/record.c b/lib/record.c index 577a15aef8..a8ba45032d 100644 --- a/lib/record.c +++ b/lib/record.c @@ -1,6 +1,7 @@ /* - * Copyright (C) 2000-2016 Free Software Foundation, Inc. - * Copyright (C) 2012-2016 Nikos Mavrogiannopoulos + * Copyright (C) 2000-2018 Free Software Foundation, Inc. + * Copyright (C) 2012-2018 Nikos Mavrogiannopoulos + * Copyright (C) 2018 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -372,7 +373,7 @@ copy_record_version(gnutls_session_t session, if (lver->tls13_sem) { version[0] = 0x03; - version[1] = 0x01; + version[1] = 0x03; } else { version[0] = lver->major; version[1] = lver->minor; @@ -687,8 +688,8 @@ record_check_version(gnutls_session_t session, int diff = 0; if (vers->tls13_sem) { - /* TLS 1.3 requires version to be 0x0301 */ - if (version[0] != 0x03 || version[1] != 0x01) + /* TLS 1.3 requires version to be 0x0303 */ + if (version[0] != 0x03 || version[1] != 0x03) diff = 1; } else { if (vers->major != version[0] || vers->minor != version[1]) @@ -1195,14 +1196,15 @@ _gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type, mbuffer_st *bufel = NULL, *decrypted = NULL; gnutls_datum_t t; int ret; - unsigned int empty_fragments = 0; + unsigned int n_retries = 0; record_parameters_st *record_params; record_state_st *record_state; struct tls_record_st record; + const version_entry_st *vers = get_version(session); - begin: + begin: - if (empty_fragments > DEFAULT_MAX_EMPTY_RECORDS) { + if (n_retries > DEFAULT_MAX_EMPTY_RECORDS) { gnutls_assert(); return GNUTLS_E_TOO_MANY_EMPTY_PACKETS; } @@ -1263,6 +1265,18 @@ _gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type, if (bufel == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + if (vers && vers->tls13_sem && record.type == GNUTLS_CHANGE_CIPHER_SPEC && + record.length == 1 && session->internals.handshake_in_progress) { + _gnutls_read_log("discarding change cipher spec in TLS1.3\n"); + /* we use the same mechanism to retry as when + * receiving multiple empty TLS packets */ + bufel = + _mbuffer_head_pop_first(&session->internals. + record_recv_buffer); + _mbuffer_xfree(&bufel); + n_retries++; + goto begin; + } /* We allocate the maximum possible to allow few compressed bytes to expand to a * full record. Moreover we add space for any pad and the MAC (in case @@ -1362,7 +1376,7 @@ _gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type, */ if (_mbuffer_get_udata_size(decrypted) == 0) { _mbuffer_xfree(&decrypted); - empty_fragments++; + n_retries++; goto begin; } @@ -1387,7 +1401,7 @@ _gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type, return ret; - discard: + discard: session->internals.dtls.packets_dropped++; /* discard the whole received fragment. */ @@ -1397,7 +1411,7 @@ _gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type, _mbuffer_xfree(&bufel); return gnutls_assert_val(GNUTLS_E_AGAIN); - sanity_check_error: + sanity_check_error: if (IS_DTLS(session)) { session->internals.dtls.packets_dropped++; ret = gnutls_assert_val(GNUTLS_E_AGAIN); @@ -1407,11 +1421,11 @@ _gnutls_recv_in_buffers(gnutls_session_t session, content_type_t type, session_unresumable(session); session_invalidate(session); - cleanup: + cleanup: _mbuffer_xfree(&decrypted); return ret; - recv_error: + recv_error: if (ret < 0 && (gnutls_error_is_fatal(ret) == 0 || ret == GNUTLS_E_TIMEDOUT)) diff --git a/lib/sslv2_compat.c b/lib/sslv2_compat.c index 882cbd628d..d466cc30f1 100644 --- a/lib/sslv2_compat.c +++ b/lib/sslv2_compat.c @@ -112,7 +112,7 @@ _gnutls_read_client_hello_v2(gnutls_session_t session, uint8_t * data, adv_version = _gnutls_version_get(major, minor); - ret = _gnutls_negotiate_legacy_version(session, adv_version, major, minor); + ret = _gnutls_negotiate_version(session, adv_version, major, minor); if (ret < 0) { gnutls_assert(); return ret; diff --git a/lib/tls-sig.c b/lib/tls-sig.c index 26b36e6115..87016172e2 100644 --- a/lib/tls-sig.c +++ b/lib/tls-sig.c @@ -87,6 +87,9 @@ _gnutls_handshake_sign_data12(gnutls_session_t session, ("HSK[%p]: signing TLS 1.2 handshake data: using %s\n", session, gnutls_sign_algorithm_get_name(sign_algo)); + if (unlikely(gnutls_sign_supports_pk_algorithm(sign_algo, pkey->pk_algorithm) == 0)) + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); + dconcat.size = GNUTLS_RANDOM_SIZE*2 + params->size; dconcat.data = gnutls_malloc(dconcat.size); if (dconcat.data == NULL) @@ -121,7 +124,8 @@ _gnutls_handshake_sign_data10(gnutls_session_t session, const mac_entry_st *me; gnutls_pk_algorithm_t pk_algo; - if (gnutls_privkey_get_pk_algorithm(pkey, NULL) == GNUTLS_PK_RSA) + pk_algo = gnutls_privkey_get_pk_algorithm(pkey, NULL); + if (pk_algo == GNUTLS_PK_RSA) me = hash_to_entry(GNUTLS_DIG_MD5_SHA1); else me = hash_to_entry( @@ -129,6 +133,9 @@ _gnutls_handshake_sign_data10(gnutls_session_t session, if (me == NULL) return gnutls_assert_val(GNUTLS_E_UNKNOWN_HASH_ALGORITHM); + if (unlikely(gnutls_sign_supports_pk_algorithm(sign_algo, pk_algo) == 0)) + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); + pk_algo = gnutls_sign_get_pk_algorithm(sign_algo); if (pk_algo == GNUTLS_PK_UNKNOWN) return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); diff --git a/lib/tls13-sig.c b/lib/tls13-sig.c index 8995fa456c..334052df2c 100644 --- a/lib/tls13-sig.c +++ b/lib/tls13-sig.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Red Hat, Inc. + * Copyright (C) 2017-2018 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -61,14 +61,18 @@ _gnutls13_handshake_verify_data(gnutls_session_t session, if (ret < 0) return gnutls_assert_val(ret); + if (unlikely(sign_supports_cert_pk_algorithm(se, cert->pubkey->params.algo) == 0)) { + _gnutls_handshake_log("HSK[%p]: certificate of %s cannot be combined with %s sig\n", + session, gnutls_pk_get_name(cert->pubkey->params.algo), se->name); + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); + } + ret = _gnutls_session_sign_algo_enabled(session, se->id); if (ret < 0) return gnutls_assert_val(ret); - if (se->hash == GNUTLS_DIG_SHA1) /* explicitly prohibited */ - return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); - if (se->pk == GNUTLS_PK_RSA) /* explicitly prohibited */ + if (se->tls13_ok == 0) /* explicitly prohibited */ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); _gnutls_buffer_init(&buf); @@ -140,7 +144,10 @@ _gnutls13_handshake_sign_data(gnutls_session_t session, gnutls_buffer_st buf; uint8_t prefix[PREFIX_SIZE]; - if (unlikely(se == NULL || se->hash == GNUTLS_DIG_SHA1 || se->pk == GNUTLS_PK_RSA)) + if (unlikely(se == NULL || se->tls13_ok == 0)) + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); + + if (unlikely(sign_supports_priv_pk_algorithm(se, pkey->pk_algorithm) == 0)) return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); _gnutls_handshake_log diff --git a/lib/tls13/hello_retry.c b/lib/tls13/hello_retry.c index 59f965cd57..51f545ec00 100644 --- a/lib/tls13/hello_retry.c +++ b/lib/tls13/hello_retry.c @@ -34,6 +34,7 @@ int _gnutls13_send_hello_retry_request(gnutls_session_t session, unsigned again) mbuffer_st *bufel = NULL; gnutls_buffer_st buf; const version_entry_st *ver; + const uint8_t vbuf[2] = {0x03, 0x03}; if (again == 0) { ver = get_version(session); @@ -44,11 +45,21 @@ int _gnutls13_send_hello_retry_request(gnutls_session_t session, unsigned again) if (ret < 0) return gnutls_assert_val(ret); - ret = _gnutls_buffer_append_data(&buf, &ver->major, 1); + ret = _gnutls_buffer_append_data(&buf, vbuf, 2); if (ret < 0) return gnutls_assert_val(ret); - ret = _gnutls_buffer_append_data(&buf, &ver->minor, 1); + ret = _gnutls_buffer_append_data(&buf, + HRR_RANDOM, + GNUTLS_RANDOM_SIZE); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + + ret = _gnutls_buffer_append_data_prefix(&buf, 8, + session->security_parameters.session_id, + session->security_parameters.session_id_size); if (ret < 0) { gnutls_assert(); goto cleanup; @@ -60,6 +71,13 @@ int _gnutls13_send_hello_retry_request(gnutls_session_t session, unsigned again) goto cleanup; } + /* compression */ + ret = _gnutls_buffer_append_prefix(&buf, 8, 0); + if (ret < 0) { + gnutls_assert(); + goto cleanup; + } + ret = _gnutls_gen_hello_extensions(session, &buf, GNUTLS_EXT_FLAG_HRR, GNUTLS_EXT_ANY); @@ -85,11 +103,12 @@ int _gnutls13_recv_hello_retry_request(gnutls_session_t session, gnutls_buffer_st *buf) { - const version_entry_st *vers; int ret; uint8_t tmp[2]; const gnutls_cipher_suite_entry_st *cs; const mac_entry_st *prf; + gnutls_datum_t session_id; + uint8_t random[GNUTLS_RANDOM_SIZE]; /* only under TLS 1.3 */ if (IS_DTLS(session)) @@ -100,20 +119,27 @@ _gnutls13_recv_hello_retry_request(gnutls_session_t session, session->internals.hsk_flags |= HSK_HRR_RECEIVED; + /* version */ ret = _gnutls_buffer_pop_data(buf, tmp, 2); if (ret < 0) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); - vers = nversion_to_entry(tmp[0], tmp[1]); - if (unlikely(vers == NULL)) + if (unlikely(tmp[0] != 0x03 || tmp[1] != 0x03)) return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); - if (_gnutls_version_is_supported(session, vers->id) == 0) - return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + ret = _gnutls_buffer_pop_data(buf, random, GNUTLS_RANDOM_SIZE); + if (ret < 0) + return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); - if (_gnutls_set_current_version(session, vers->id) < 0) - return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + if (memcmp(random, HRR_RANDOM, GNUTLS_RANDOM_SIZE) != 0) { + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); + } + ret = _gnutls_buffer_pop_datum_prefix8(buf, &session_id); + if (ret < 0) + return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); + + /* read ciphersuites */ ret = _gnutls_buffer_pop_data(buf, tmp, 2); if (ret < 0) return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); @@ -123,13 +149,20 @@ _gnutls13_recv_hello_retry_request(gnutls_session_t session, return gnutls_assert_val(GNUTLS_E_UNKNOWN_CIPHER_SUITE); _gnutls_handshake_log("EXT[%p]: Hello Retry Request with %s\n", session, cs->name); - memcpy(session->internals.hrr_cs, cs->id, 2); prf = mac_to_entry(cs->prf); if (unlikely(prf == NULL)) return gnutls_assert_val(GNUTLS_E_UNKNOWN_CIPHER_SUITE); + /* compression */ + ret = _gnutls_buffer_pop_data(buf, tmp, 1); + if (ret < 0) + return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH); + + if (unlikely(tmp[0] != 0)) + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); + ret = _gnutls13_handshake_hash_buffers_synth(session, prf, 1); if (ret < 0) return gnutls_assert_val(ret); @@ -139,6 +172,15 @@ _gnutls13_recv_hello_retry_request(gnutls_session_t session, return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH); } + /* figure version first */ + ret = + _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_HRR, + GNUTLS_EXT_VERSION_NEG, + buf->data, buf->length); + if (ret < 0) + return gnutls_assert_val(ret); + + /* parse the rest of extensions */ ret = _gnutls_parse_hello_extensions(session, GNUTLS_EXT_FLAG_HRR, GNUTLS_EXT_ANY, buf->data, buf->length); if (ret < 0) diff --git a/tests/Makefile.am b/tests/Makefile.am index 66766b632c..36a493cdc7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -112,6 +112,8 @@ ctests += tls13/multi-ocsp ctests += tls13/ocsp-client +ctests += tls13/change_cipher_spec + ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniqueid tls-neg-ext-key \ mpi certificate_set_x509_crl dn parse_ca x509-dn x509-dn-decode record-sizes \ hostname-check cve-2008-4989 pkcs12_s2k chainverify record-sizes-range \ diff --git a/tests/common-cert-key-exchange.c b/tests/common-cert-key-exchange.c index ed79973bfe..3f3ce085f5 100644 --- a/tests/common-cert-key-exchange.c +++ b/tests/common-cert-key-exchange.c @@ -49,6 +49,94 @@ static void tls_log_func(int level, const char *str) #define MSG "hello there ppl" +void try_with_key_fail(const char *name, const char *client_prio, + int server_err, int client_err, + const gnutls_datum_t *serv_cert, + const gnutls_datum_t *serv_key, + const gnutls_datum_t *cli_cert, + const gnutls_datum_t *cli_key) +{ + int ret; + /* Server stuff. */ + gnutls_certificate_credentials_t serverx509cred; + gnutls_session_t server; + int sret = GNUTLS_E_AGAIN; + /* Client stuff. */ + gnutls_certificate_credentials_t clientx509cred; + gnutls_session_t client; + int cret = GNUTLS_E_AGAIN; + const char *err; + + /* General init. */ + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(6); + + reset_buffers(); + /* Init server */ + gnutls_certificate_allocate_credentials(&serverx509cred); + + ret = gnutls_certificate_set_x509_key_mem(serverx509cred, + serv_cert, serv_key, + GNUTLS_X509_FMT_PEM); + if (ret < 0) + fail("Could not set key/cert: %s\n", gnutls_strerror(ret)); + + gnutls_init(&server, GNUTLS_SERVER); + gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, + serverx509cred); + + + if (server_priority) + assert(gnutls_priority_set_direct(server, server_priority, NULL) >= 0); + else + assert(gnutls_priority_set_direct(server, client_prio, NULL) >= 0); + + gnutls_transport_set_push_function(server, server_push); + gnutls_transport_set_pull_function(server, server_pull); + gnutls_transport_set_ptr(server, server); + + /* Init client */ + ret = gnutls_certificate_allocate_credentials(&clientx509cred); + if (ret < 0) + exit(1); + + if (cli_cert) { + gnutls_certificate_set_x509_key_mem(clientx509cred, + cli_cert, cli_key, + GNUTLS_X509_FMT_PEM); + gnutls_certificate_server_set_request(server, GNUTLS_CERT_REQUIRE); + } + + ret = gnutls_init(&client, GNUTLS_CLIENT); + if (ret < 0) + exit(1); + + ret = gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, + clientx509cred); + if (ret < 0) + exit(1); + + gnutls_transport_set_push_function(client, client_push); + gnutls_transport_set_pull_function(client, client_pull); + gnutls_transport_set_ptr(client, client); + + ret = gnutls_priority_set_direct(client, client_prio, &err); + if (ret < 0) { + if (ret == GNUTLS_E_INVALID_REQUEST) + fprintf(stderr, "Error in %s\n", err); + exit(1); + } + success("negotiating %s\n", name); + HANDSHAKE_EXPECT(client, server, client_err, server_err); + + gnutls_deinit(client); + gnutls_deinit(server); + + gnutls_certificate_free_credentials(serverx509cred); + gnutls_certificate_free_credentials(clientx509cred); +} + void try_with_key_ks(const char *name, const char *client_prio, gnutls_kx_algorithm_t client_kx, gnutls_sign_algorithm_t server_sign_algo, gnutls_sign_algorithm_t client_sign_algo, diff --git a/tests/common-cert-key-exchange.h b/tests/common-cert-key-exchange.h index 4c7d6c0ca9..b52c95ea72 100644 --- a/tests/common-cert-key-exchange.h +++ b/tests/common-cert-key-exchange.h @@ -36,7 +36,7 @@ extern const char *server_priority; &server_ca3_localhost_cert, &server_ca3_key, NULL, NULL, 0) #define try_ks(name, client_prio, client_kx, group) \ - try_with_key_ks(name, client_prio, client_kx, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN, \ + try_with_key_ks(name, client_prio, client_kx, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_UNKNOWN, \ &server_ca3_localhost_cert, &server_ca3_key, NULL, NULL, 0, group) #define try_cli(name, client_prio, client_kx, server_sign_algo, client_sign_algo, client_cert) \ @@ -67,6 +67,13 @@ void try_with_key(const char *name, const char *client_prio, gnutls_kx_algorithm serv_cert, serv_key, cli_cert, cli_key, client_cert, 0); } +void try_with_key_fail(const char *name, const char *client_prio, + int server_err, int client_err, + const gnutls_datum_t *serv_cert, + const gnutls_datum_t *serv_key, + const gnutls_datum_t *cli_cert, + const gnutls_datum_t *cli_key); + #define dtls_try(name, client_prio, client_kx, server_sign_algo, client_sign_algo) \ dtls_try_with_key(name, client_prio, client_kx, server_sign_algo, client_sign_algo, \ &server_ca3_localhost_cert, &server_ca3_key, NULL, NULL, 0) diff --git a/tests/dtls12-cert-key-exchange.c b/tests/dtls12-cert-key-exchange.c index 0903cafe66..82028041d7 100644 --- a/tests/dtls12-cert-key-exchange.c +++ b/tests/dtls12-cert-key-exchange.c @@ -48,8 +48,8 @@ void doit(void) dtls_try_with_key("DTLS 1.2 with ecdhe ecdsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-DTLS1.2:-KX-ALL:+ECDHE-ECDSA", GNUTLS_KX_ECDHE_ECDSA, GNUTLS_SIGN_ECDSA_SHA256, GNUTLS_SIGN_UNKNOWN, &server_ca3_localhost_ecc_cert, &server_ca3_ecc_key, NULL, NULL, 0); - dtls_try("DTLS 1.2 with ecdhe rsa-pss sig no-cli-cert", "NORMAL:-VERS-ALL:+VERS-DTLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN); - dtls_try("DTLS 1.2 with ecdhe rsa-pss no-cli-cert", "NORMAL:-VERS-ALL:+VERS-DTLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN); + dtls_try("DTLS 1.2 with ecdhe rsa-pss sig no-cli-cert", "NORMAL:-VERS-ALL:+VERS-DTLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-RSAE-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_UNKNOWN); + dtls_try("DTLS 1.2 with ecdhe rsa-pss no-cli-cert", "NORMAL:-VERS-ALL:+VERS-DTLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-RSAE-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_UNKNOWN); dtls_try_with_key("TLS 1.2 with ecdhe rsa-pss/rsa-pss no-cli-cert", "NORMAL:-VERS-ALL:+VERS-DTLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN, &server_ca3_rsa_pss_cert, &server_ca3_rsa_pss_key, NULL, NULL, 0); dtls_try("DTLS 1.2 with rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-DTLS1.2:-KX-ALL:+RSA", GNUTLS_KX_RSA, GNUTLS_SIGN_UNKNOWN, GNUTLS_SIGN_UNKNOWN); @@ -63,7 +63,7 @@ void doit(void) &server_ca3_localhost_ecc_cert, &server_ca3_ecc_key, &server_ca3_localhost_ecc_cert, &server_ca3_ecc_key, USE_CERT); - dtls_try_cli("DTLS 1.2 with ecdhe-rsa-pss cli-cert", "NORMAL:-VERS-ALL:+VERS-DTLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_RSA_PSS_SHA256, USE_CERT); + dtls_try_cli("DTLS 1.2 with ecdhe-rsa-pss cli-cert", "NORMAL:-VERS-ALL:+VERS-DTLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-RSAE-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, USE_CERT); dtls_try_with_key("DTLS 1.2 with ecdhe-rsa-pss/rsa-pss cli-cert", "NORMAL:-VERS-ALL:+VERS-DTLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_RSA_PSS_SHA256, &server_ca3_rsa_pss_cert, &server_ca3_rsa_pss_key, &cli_ca3_rsa_pss_cert, &cli_ca3_rsa_pss_key, USE_CERT); dtls_try_cli("DTLS 1.2 with dhe-rsa ask cli-cert", "NORMAL:-VERS-ALL:+VERS-DTLS1.2:-KX-ALL:+DHE-RSA", GNUTLS_KX_DHE_RSA, GNUTLS_SIGN_RSA_SHA256, GNUTLS_SIGN_UNKNOWN, ASK_CERT); diff --git a/tests/pkcs11/tls-neg-pkcs11-key.c b/tests/pkcs11/tls-neg-pkcs11-key.c index c85d8789df..c32dee27a6 100644 --- a/tests/pkcs11/tls-neg-pkcs11-key.c +++ b/tests/pkcs11/tls-neg-pkcs11-key.c @@ -286,7 +286,7 @@ static const test_st tests[] = { }, {.name = "tls1.2: rsa-pss cert, rsa-sign key no PSS signatures", .pk = GNUTLS_PK_RSA, - .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.2:-SIGN-RSA-PSS-SHA256:-SIGN-RSA-PSS-SHA384:-SIGN-RSA-PSS-SHA512", + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.2:-SIGN-RSA-PSS-SHA256:-SIGN-RSA-PSS-SHA384:-SIGN-RSA-PSS-SHA512:-SIGN-RSA-PSS-RSAE-SHA256:-SIGN-RSA-PSS-RSAE-SHA384:-SIGN-RSA-PSS-RSAE-SHA512", .cert = &server_ca3_rsa_pss_cert, .key = &server_ca3_rsa_pss_key, .exp_kx = GNUTLS_KX_ECDHE_RSA, diff --git a/tests/privkey-verify-broken.c b/tests/privkey-verify-broken.c index aaf640d030..276fcdaafe 100644 --- a/tests/privkey-verify-broken.c +++ b/tests/privkey-verify-broken.c @@ -145,7 +145,7 @@ void doit(void) if (sign_verify_data(pkey, GNUTLS_SIGN_RSA_SHA3_256, 0) < 0) fail("failed verification with SHA3-256!\n"); - if (sign_verify_data(pkey, GNUTLS_SIGN_RSA_PSS_SHA256, 0) < 0) + if (sign_verify_data(pkey, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, 0) < 0) fail("failed verification with SHA256 with PSS!\n"); gnutls_x509_privkey_deinit(pkey); diff --git a/tests/rsa-rsa-pss.c b/tests/rsa-rsa-pss.c index 74ed99055a..2ba926e321 100644 --- a/tests/rsa-rsa-pss.c +++ b/tests/rsa-rsa-pss.c @@ -46,8 +46,8 @@ const gnutls_datum_t raw_data = { 11 }; -static void inv_sign_check(gnutls_pk_algorithm_t algorithm, unsigned sigalgo, - gnutls_privkey_t privkey, int exp_error) +static void inv_sign_check(unsigned sigalgo, + gnutls_privkey_t privkey, int exp_error) { int ret; gnutls_datum_t signature; @@ -55,9 +55,11 @@ static void inv_sign_check(gnutls_pk_algorithm_t algorithm, unsigned sigalgo, ret = gnutls_privkey_sign_data2(privkey, sigalgo, 0, &raw_data, &signature); if (ret != exp_error) - fail("gnutls_privkey_sign_data succeeded with %s and %s: %s\n", gnutls_pk_get_name(algorithm), + fail("gnutls_privkey_sign_data succeeded with %s and %s: %s\n", gnutls_pk_get_name(gnutls_privkey_get_pk_algorithm(privkey, NULL)), gnutls_sign_get_name(sigalgo), gnutls_strerror(ret)); + if (ret == 0) + gnutls_free(signature.data); } static void inv_encryption_check(gnutls_pk_algorithm_t algorithm, @@ -82,8 +84,7 @@ static void inv_encryption_check(gnutls_pk_algorithm_t algorithm, } -static void sign_verify_data(gnutls_pk_algorithm_t algorithm, unsigned sigalgo, - gnutls_privkey_t privkey) +static void sign_verify_data(unsigned sigalgo, gnutls_privkey_t privkey) { int ret; gnutls_pubkey_t pubkey; @@ -112,7 +113,8 @@ static void sign_verify_data(gnutls_pk_algorithm_t algorithm, unsigned sigalgo, void doit(void) { - gnutls_privkey_t pkey; + gnutls_privkey_t pkey_rsa_pss; + gnutls_privkey_t pkey_rsa; gnutls_x509_privkey_t tkey; int ret; gnutls_x509_spki_t spki; @@ -128,46 +130,67 @@ void doit(void) assert(gnutls_x509_spki_init(&spki)>=0); - assert(gnutls_privkey_init(&pkey) >=0); + assert(gnutls_privkey_init(&pkey_rsa) >=0); gnutls_x509_spki_set_rsa_pss_params(spki, GNUTLS_DIG_SHA256, 32); ret = - gnutls_privkey_generate(pkey, GNUTLS_PK_RSA, 2048, 0); + gnutls_privkey_generate(pkey_rsa, GNUTLS_PK_RSA, 2048, 0); if (ret < 0) { fail("gnutls_privkey_generate: %s\n", gnutls_strerror(ret)); } - assert(gnutls_privkey_set_spki(pkey, spki, 0)>=0); - assert(gnutls_privkey_export_x509(pkey, &tkey) >=0); + assert(gnutls_privkey_set_spki(pkey_rsa, spki, 0)>=0); + assert(gnutls_privkey_export_x509(pkey_rsa, &tkey) >=0); gnutls_x509_privkey_export2_pkcs8(tkey, GNUTLS_X509_FMT_PEM, NULL, 0, &tmp); - gnutls_x509_privkey_deinit(tkey); - gnutls_privkey_deinit(pkey); + /* import RSA-PSS version of key */ + assert(gnutls_privkey_init(&pkey_rsa_pss) >=0); + assert(gnutls_privkey_import_x509_raw(pkey_rsa_pss, &tmp, GNUTLS_X509_FMT_PEM, NULL, 0) >= 0); - assert(gnutls_privkey_init(&pkey) >=0); + gnutls_free(tmp.data); - assert(gnutls_privkey_import_x509_raw(pkey, &tmp, GNUTLS_X509_FMT_PEM, NULL, 0) >= 0); + /* import RSA-PSS version of key */ + gnutls_privkey_deinit(pkey_rsa); + gnutls_x509_privkey_export2(tkey, GNUTLS_X509_FMT_PEM, &tmp); + assert(gnutls_privkey_init(&pkey_rsa) >=0); + assert(gnutls_privkey_import_x509_raw(pkey_rsa, &tmp, GNUTLS_X509_FMT_PEM, NULL, 0) >= 0); - if (debug) - printf("%s", tmp.data); + gnutls_x509_privkey_deinit(tkey); + gnutls_free(tmp.data); - sign_verify_data(GNUTLS_PK_RSA_PSS, GNUTLS_SIGN_RSA_PSS_SHA256, pkey); + sign_verify_data(GNUTLS_SIGN_RSA_PSS_SHA256, pkey_rsa_pss); + sign_verify_data(GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, pkey_rsa); + sign_verify_data(GNUTLS_SIGN_RSA_PSS_SHA256, pkey_rsa); if (debug) success("success signing with RSA-PSS-SHA256\n"); - /* check whether the RSA-PSS restrictions are being followed */ - inv_encryption_check(GNUTLS_PK_RSA_PSS, pkey, GNUTLS_E_INVALID_REQUEST); - inv_sign_check(GNUTLS_PK_RSA, GNUTLS_SIGN_RSA_SHA512, pkey, GNUTLS_E_CONSTRAINT_ERROR); - inv_sign_check(GNUTLS_PK_RSA, GNUTLS_SIGN_RSA_SHA256, pkey, GNUTLS_E_CONSTRAINT_ERROR); - inv_sign_check(GNUTLS_PK_RSA_PSS, GNUTLS_SIGN_RSA_PSS_SHA384, pkey, GNUTLS_E_CONSTRAINT_ERROR); - inv_sign_check(GNUTLS_PK_RSA_PSS, GNUTLS_SIGN_RSA_PSS_SHA512, pkey, GNUTLS_E_CONSTRAINT_ERROR); - - gnutls_privkey_deinit(pkey); + /* check whether the RSA-PSS key restrictions are being followed */ + inv_encryption_check(GNUTLS_PK_RSA_PSS, pkey_rsa_pss, GNUTLS_E_INVALID_REQUEST); + inv_sign_check(GNUTLS_SIGN_RSA_SHA512, pkey_rsa_pss, GNUTLS_E_CONSTRAINT_ERROR); + inv_sign_check(GNUTLS_SIGN_RSA_SHA256, pkey_rsa_pss, GNUTLS_E_CONSTRAINT_ERROR); + inv_sign_check(GNUTLS_SIGN_RSA_PSS_SHA384, pkey_rsa_pss, GNUTLS_E_CONSTRAINT_ERROR); + inv_sign_check(GNUTLS_SIGN_RSA_PSS_SHA512, pkey_rsa_pss, GNUTLS_E_CONSTRAINT_ERROR); + inv_sign_check(GNUTLS_SIGN_RSA_PSS_RSAE_SHA384, pkey_rsa_pss, GNUTLS_E_CONSTRAINT_ERROR); + inv_sign_check(GNUTLS_SIGN_RSA_PSS_RSAE_SHA512, pkey_rsa_pss, GNUTLS_E_CONSTRAINT_ERROR); + + /* check whether the RSA key is not being restricted */ + inv_sign_check(GNUTLS_SIGN_RSA_SHA512, pkey_rsa, 0); + inv_sign_check(GNUTLS_SIGN_RSA_SHA256, pkey_rsa, 0); + inv_sign_check(GNUTLS_SIGN_RSA_PSS_RSAE_SHA384, pkey_rsa, 0); + inv_sign_check(GNUTLS_SIGN_RSA_PSS_RSAE_SHA512, pkey_rsa, 0); + /* an RSA key can also generate "pure" for TLS RSA-PSS signatures + * as they are essentially the same thing, and we cannot always + * know whether a key is RSA-PSS only, or not (e.g., in PKCS#11 + * keys). */ + inv_sign_check(GNUTLS_SIGN_RSA_PSS_SHA384, pkey_rsa, 0); + inv_sign_check(GNUTLS_SIGN_RSA_PSS_SHA512, pkey_rsa, 0); + + gnutls_privkey_deinit(pkey_rsa); + gnutls_privkey_deinit(pkey_rsa_pss); gnutls_x509_spki_deinit(spki); - gnutls_free(tmp.data); gnutls_global_deinit(); } diff --git a/tests/suite/tls-fuzzer/gnutls-cert.json b/tests/suite/tls-fuzzer/gnutls-cert.json index 8da7a50a06..781ac2db54 100644 --- a/tests/suite/tls-fuzzer/gnutls-cert.json +++ b/tests/suite/tls-fuzzer/gnutls-cert.json @@ -30,10 +30,10 @@ "-e", "check sigalgs in cert request"] }, {"name" : "test-rsa-pss-sigs-on-certificate-verify.py", - "comment" : "tlsfuzzer doesn't like our set of algorithms", "arguments" : ["-k", "tests/clientX509Key.pem", "-c", "tests/clientX509Cert.pem", - "-e", "check CertificateRequest sigalgs"] + "-e", "check CertificateRequest sigalgs", + "-n", "100"] }, {"name": "test-certificate-malformed.py", "comment" : "tlsfuzzer doesn't like the alerts we send", diff --git a/tests/suite/tls-fuzzer/gnutls-nocert.json b/tests/suite/tls-fuzzer/gnutls-nocert.json index db9ec67844..e5b7a80b4c 100644 --- a/tests/suite/tls-fuzzer/gnutls-nocert.json +++ b/tests/suite/tls-fuzzer/gnutls-nocert.json @@ -5,6 +5,7 @@ "--x509keyfile", "../../../certs/ecc256.pem", "--x509certfile", "../../../certs/cert-ecc256.pem", "--debug=3", + "--noticket", "--priority=@PRIORITY@", "--disable-client-cert", "--port=@PORT@"], "tests" : [ @@ -60,7 +61,9 @@ {"name" : "test-chacha20.py"}, {"name" : "test-aes-gcm-nonces.py" }, {"name" : "test-atypical-padding.py" }, - {"name" : "test-bleichenbacher-workaround.py" }, + {"name" : "test-bleichenbacher-workaround.py", + "arguments" : ["-n", "20"] + }, {"name" : "test-clienthello-md5.py"}, {"name" : "test-client-compatibility.py"}, {"name" : "test-conversation.py"}, @@ -133,10 +136,8 @@ "-e", "small, maximum fragmentation: 1 fragment - 20B extension", "-e", "medium, maximum fragmentation: 1 fragment - 1024B extension"]}, {"name" : "test-sessionID-resumption.py"}, - {"name" : "test-sig-algs.py", - "comment" : "FIXME: these fail, but most likely due to tls-fuzzer issue", - "arguments" : ["-e", "RSA-PSS only - fails in verify if server selects PSS", - "-e", "with RSA-PSS - fails in verify if server selects PSS"]}, + {"name" : "test-sig-algs.py" + }, {"name" : "test-signature-algorithms.py", "comment" : "gnutls doesn't tolerate that much", "arguments" : ["-e", "tolerance max (32764) number of methods"] diff --git a/tests/suite/tls-fuzzer/tlsfuzzer b/tests/suite/tls-fuzzer/tlsfuzzer -Subproject d10aac68845a80e6bef97b9061aa53119baabcc +Subproject ff3ab5e356e413bba5845deecdfe105dd207a9a diff --git a/tests/suite/tls-fuzzer/tlslite-ng b/tests/suite/tls-fuzzer/tlslite-ng -Subproject 79eee6139661bcd2f0c15d0bd7b10308f699e0b +Subproject 57d97d290043c6e1ef730e89b57c11937898667 diff --git a/tests/tls-neg-ext-key.c b/tests/tls-neg-ext-key.c index a02c6b0034..f8b4877a58 100644 --- a/tests/tls-neg-ext-key.c +++ b/tests/tls-neg-ext-key.c @@ -295,7 +295,7 @@ static const test_st tests[] = { }, {.name = "rsa-sign key with rsa-pss sigs prioritized", .pk = GNUTLS_PK_RSA, - .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512:+SIGN-RSA-SHA256:+SIGN-RSA-SHA384:+SIGN-RSA-SHA512", + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-SIGN-ALL:+SIGN-RSA-PSS-RSAE-SHA256:+SIGN-RSA-PSS-RSAE-SHA384:+SIGN-RSA-PSS-RSAE-SHA512:+SIGN-RSA-SHA256:+SIGN-RSA-SHA384:+SIGN-RSA-SHA512", .cert = &server_ca3_localhost_cert, .key = &server_ca3_key, .exp_kx = GNUTLS_KX_ECDHE_RSA @@ -308,9 +308,9 @@ static const test_st tests[] = { .exp_kx = GNUTLS_KX_ECDHE_RSA, .exp_key_err = GNUTLS_E_INVALID_REQUEST }, - {.name = "rsa-pss cert, rsa-sign key", /* we expect the server to refuse negotiating */ + {.name = "rsa-pss cert, rsa-sign key, no rsa-pss-rsae sigs", /* we expect the server to refuse negotiating */ .pk = GNUTLS_PK_RSA, - .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA", + .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512:+SIGN-RSA-SHA256:+SIGN-RSA-SHA384:+SIGN-RSA-SHA512", .cert = &server_ca3_rsa_pss_cert, .key = &server_ca3_rsa_pss_key, .exp_kx = GNUTLS_KX_ECDHE_RSA, diff --git a/tests/tls11-cert-key-exchange.c b/tests/tls11-cert-key-exchange.c index 410126fc74..860574afdc 100644 --- a/tests/tls11-cert-key-exchange.c +++ b/tests/tls11-cert-key-exchange.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Red Hat, Inc. + * Copyright (C) 2015-2018 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -62,5 +62,12 @@ void doit(void) try_with_key("TLS 1.1 with ecdhe ecdsa cert", "NORMAL:-VERS-ALL:+VERS-TLS1.1:-KX-ALL:+ECDHE-ECDSA", GNUTLS_KX_ECDHE_ECDSA, GNUTLS_SIGN_UNKNOWN, GNUTLS_SIGN_UNKNOWN, &server_ca3_localhost_ecc_cert, &server_ca3_ecc_key, &cli_ca3_cert, &cli_ca3_key, ASK_CERT); + /* illegal setups */ + server_priority = NULL; + try_with_key_fail("TLS 1.1 with rsa-pss cert and no cli cert", + "NORMAL:-VERS-ALL:+VERS-TLS1.1:-KX-ALL:+DHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512", + GNUTLS_E_UNWANTED_ALGORITHM, GNUTLS_E_AGAIN, + &server_ca3_rsa_pss_cert, &server_ca3_rsa_pss_key, NULL, NULL); + gnutls_global_deinit(); } diff --git a/tests/tls12-cert-key-exchange.c b/tests/tls12-cert-key-exchange.c index 497c8aee3c..bdfd91f72f 100644 --- a/tests/tls12-cert-key-exchange.c +++ b/tests/tls12-cert-key-exchange.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Red Hat, Inc. + * Copyright (C) 2015-2018 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -47,7 +47,7 @@ void doit(void) try("TLS 1.2 with ecdhe rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_SHA256, GNUTLS_SIGN_UNKNOWN); try_with_key("TLS 1.2 with ecdhe ecdsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-ECDSA", GNUTLS_KX_ECDHE_ECDSA, GNUTLS_SIGN_ECDSA_SHA256, GNUTLS_SIGN_UNKNOWN, &server_ca3_localhost_ecc_cert, &server_ca3_ecc_key, NULL, NULL, 0); - try("TLS 1.2 with ecdhe rsa-pss sig no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN); + try("TLS 1.2 with ecdhe rsa-pss sig no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-RSAE-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_UNKNOWN); /* Test RSA-PSS cert/key combo issues */ try_with_key("TLS 1.2 with ecdhe with rsa-pss-sha256 key no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN, @@ -59,7 +59,7 @@ void doit(void) try_with_key("TLS 1.2 with ecdhe with rsa-pss-sha256 key and rsa-pss-sha512 first sig no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA512:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN, &server_ca3_rsa_pss2_cert, &server_ca3_rsa_pss2_key, NULL, NULL, 0); - try("TLS 1.2 with ecdhe rsa-pss no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN); + try("TLS 1.2 with ecdhe rsa-pss no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-RSAE-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_UNKNOWN); try_with_key("TLS 1.2 with ecdhe rsa-pss/rsa-pss no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN, &server_ca3_rsa_pss_cert, &server_ca3_rsa_pss_key, NULL, NULL, 0); try("TLS 1.2 with rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+RSA", GNUTLS_KX_RSA, GNUTLS_SIGN_UNKNOWN, GNUTLS_SIGN_UNKNOWN); @@ -71,7 +71,7 @@ void doit(void) try_cli("TLS 1.2 with rsa cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+RSA", GNUTLS_KX_RSA, GNUTLS_SIGN_UNKNOWN, GNUTLS_SIGN_RSA_SHA256, USE_CERT); try_with_key("TLS 1.2 with ecdhe ecdsa cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-ECDSA", GNUTLS_KX_ECDHE_ECDSA, GNUTLS_SIGN_ECDSA_SHA256, GNUTLS_SIGN_RSA_SHA256, &server_ca3_localhost_ecc_cert, &server_ca3_ecc_key, &cli_ca3_cert, &cli_ca3_key, USE_CERT); - try_cli("TLS 1.2 with ecdhe-rsa-pss cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_RSA_PSS_SHA256, USE_CERT); + try_cli("TLS 1.2 with ecdhe-rsa-pss cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-RSAE-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, USE_CERT); try_with_key("TLS 1.2 with ecdhe-rsa-pss/rsa-pss cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_RSA_PSS_SHA256, &server_ca3_rsa_pss_cert, &server_ca3_rsa_pss_key, &cli_ca3_rsa_pss_cert, &cli_ca3_rsa_pss_key, USE_CERT); @@ -84,5 +84,23 @@ void doit(void) try_with_key("TLS 1.2 with ecdhe ecdsa cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-ECDSA", GNUTLS_KX_ECDHE_ECDSA, GNUTLS_SIGN_ECDSA_SHA256, GNUTLS_SIGN_UNKNOWN, &server_ca3_localhost_ecc_cert, &server_ca3_ecc_key, &cli_ca3_cert, &cli_ca3_key, ASK_CERT); + /* illegal setups */ + server_priority = "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA"; + try_with_key_fail("TLS 1.2 with rsa cert and only RSA-PSS sig algos in client", + "NORMAL:-VERS-ALL:+VERS-TLS1.2:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512", + GNUTLS_E_NO_CIPHER_SUITES, GNUTLS_E_AGAIN, + &server_ca3_localhost_cert, &server_ca3_key, NULL, NULL); + + server_priority = NULL; + try_with_key_fail("TLS 1.2 with rsa cert and only RSA-PSS sig algos", + "NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-RSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512", + GNUTLS_E_NO_CIPHER_SUITES, GNUTLS_E_AGAIN, + &server_ca3_localhost_cert, &server_ca3_key, NULL, NULL); + + try_with_key_fail("TLS 1.2 with rsa-pss cert and rsa cli cert with only RSA-PSS sig algos", + "NORMAL:-VERS-ALL:+VERS-TLS1.2:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512", + GNUTLS_E_AGAIN, GNUTLS_E_UNWANTED_ALGORITHM, + &server_ca3_rsa_pss_cert, &server_ca3_rsa_pss_key, &cli_ca3_cert, &cli_ca3_key); + gnutls_global_deinit(); } diff --git a/tests/tls13-cert-key-exchange.c b/tests/tls13-cert-key-exchange.c index ca1b205c50..5cf60a7189 100644 --- a/tests/tls13-cert-key-exchange.c +++ b/tests/tls13-cert-key-exchange.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Red Hat, Inc. + * Copyright (C) 2015-2018 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -40,13 +40,13 @@ void doit(void) global_init(); /* TLS 1.3 no clin cert */ - try("TLS 1.3 with ffdhe2048 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-FFDHE2048", GNUTLS_KX_DHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN); - try("TLS 1.3 with ffdhe3072 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-FFDHE3072", GNUTLS_KX_DHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN); - try("TLS 1.3 with ffdhe4096 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-FFDHE4096", GNUTLS_KX_DHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN); - try("TLS 1.3 with secp256r1 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP256R1", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN); - try("TLS 1.3 with secp384r1 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP384R1", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN); - try("TLS 1.3 with secp521r1 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP521R1", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN); - try("TLS 1.3 with x25519 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-X25519", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_SHA256, GNUTLS_SIGN_UNKNOWN); + try("TLS 1.3 with ffdhe2048 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-FFDHE2048", GNUTLS_KX_DHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_UNKNOWN); + try("TLS 1.3 with ffdhe3072 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-FFDHE3072", GNUTLS_KX_DHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_UNKNOWN); + try("TLS 1.3 with ffdhe4096 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-FFDHE4096", GNUTLS_KX_DHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_UNKNOWN); + try("TLS 1.3 with secp256r1 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP256R1", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_UNKNOWN); + try("TLS 1.3 with secp384r1 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP384R1", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_UNKNOWN); + try("TLS 1.3 with secp521r1 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP521R1", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_UNKNOWN); + try("TLS 1.3 with x25519 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-X25519", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, GNUTLS_SIGN_UNKNOWN); try_with_key_ks("TLS 1.3 with secp256r1 ecdsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP256R1", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_ECDSA_SECP256R1_SHA256, GNUTLS_SIGN_UNKNOWN, &server_ca3_localhost_ecc_cert, &server_ca3_ecc_key, NULL, NULL, 0, GNUTLS_GROUP_SECP256R1); @@ -69,7 +69,7 @@ void doit(void) /* client authentication */ try_with_key("TLS 1.3 with rsa-pss cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-KX-ALL:+ECDHE-RSA", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_ECDSA_SECP256R1_SHA256, GNUTLS_SIGN_RSA_PSS_SHA256, &server_ca3_localhost_ecc_cert, &server_ca3_ecc_key, &cli_ca3_rsa_pss_cert, &cli_ca3_rsa_pss_key, USE_CERT); - try_with_key("TLS 1.3 with rsa cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-KX-ALL:+ECDHE-RSA", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_ECDSA_SECP256R1_SHA256, GNUTLS_SIGN_RSA_PSS_SHA256, + try_with_key("TLS 1.3 with rsa cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-KX-ALL:+ECDHE-RSA", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_ECDSA_SECP256R1_SHA256, GNUTLS_SIGN_RSA_PSS_RSAE_SHA256, &server_ca3_localhost_ecc_cert, &server_ca3_ecc_key, &cli_ca3_cert, &cli_ca3_key, USE_CERT); try_with_key("TLS 1.3 with ecdsa cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-KX-ALL:+ECDHE-RSA", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_ECDSA_SECP256R1_SHA256, GNUTLS_SIGN_ECDSA_SECP256R1_SHA256, &server_ca3_localhost_ecc_cert, &server_ca3_ecc_key, &server_ca3_localhost_ecc_cert, &server_ca3_ecc_key, USE_CERT); @@ -97,5 +97,23 @@ void doit(void) try("TLS 1.2 fallback with secp521r1 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2:-GROUP-ALL:+GROUP-SECP521R1", GNUTLS_KX_ECDHE_RSA, GNUTLS_SIGN_RSA_SHA256, GNUTLS_SIGN_UNKNOWN); try("TLS 1.2 fallback with ffdhe2048 rsa no-cli-cert", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2:-KX-ALL:+DHE-RSA:-GROUP-ALL:+GROUP-FFDHE2048", GNUTLS_KX_DHE_RSA, GNUTLS_SIGN_RSA_SHA256, GNUTLS_SIGN_UNKNOWN); + /* illegal setups */ + server_priority = "NORMAL:-VERS-ALL:+VERS-TLS1.3"; + try_with_key_fail("TLS 1.3 with rsa cert and only RSA-PSS sig algos in client", + "NORMAL:-VERS-ALL:+VERS-TLS1.3:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512", + GNUTLS_E_NO_CIPHER_SUITES, GNUTLS_E_AGAIN, + &server_ca3_localhost_cert, &server_ca3_key, NULL, NULL); + + server_priority = NULL; + try_with_key_fail("TLS 1.3 with rsa cert and only RSA-PSS sig algos", + "NORMAL:-VERS-ALL:+VERS-TLS1.3:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512", + GNUTLS_E_NO_CIPHER_SUITES, GNUTLS_E_AGAIN, + &server_ca3_localhost_cert, &server_ca3_key, NULL, NULL); + + try_with_key_fail("TLS 1.3 with rsa-pss cert and rsa cli cert with only RSA-PSS sig algos", + "NORMAL:-VERS-ALL:+VERS-TLS1.3:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512", + GNUTLS_E_AGAIN, GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY, + &server_ca3_rsa_pss_cert, &server_ca3_rsa_pss_key, &cli_ca3_cert, &cli_ca3_key); + gnutls_global_deinit(); } diff --git a/tests/tls13/change_cipher_spec.c b/tests/tls13/change_cipher_spec.c new file mode 100644 index 0000000000..23519d9fd4 --- /dev/null +++ b/tests/tls13/change_cipher_spec.c @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> + +#if defined(_WIN32) + +int main() +{ + exit(77); +} + +#else + +#include <string.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <gnutls/gnutls.h> +#include <gnutls/dtls.h> +#include <signal.h> +#include <assert.h> +#include <errno.h> + +#include "cert-common.h" +#include "utils.h" + +/* This program tests whether the ChangeCipherSpec message + * is ignored during handshake. + */ + +static void server_log_func(int level, const char *str) +{ + fprintf(stderr, "server|<%d>| %s", level, str); +} + +static void client_log_func(int level, const char *str) +{ + fprintf(stderr, "client|<%d>| %s", level, str); +} + +static unsigned client_sent_ccs = 0; +static unsigned server_sent_ccs = 0; + +static int cli_hsk_callback(gnutls_session_t session, unsigned int htype, + unsigned post, unsigned int incoming, const gnutls_datum_t *msg); + +static void client(int fd, unsigned ccs_check) +{ + int ret; + gnutls_certificate_credentials_t x509_cred; + gnutls_session_t session; + char buf[64]; + + global_init(); + client_sent_ccs = 0; + server_sent_ccs = 0; + + if (debug) { + gnutls_global_set_log_function(client_log_func); + gnutls_global_set_log_level(7); + } + + gnutls_certificate_allocate_credentials(&x509_cred); + + /* Initialize TLS session + */ + gnutls_init(&session, GNUTLS_CLIENT|GNUTLS_POST_HANDSHAKE_AUTH); + + gnutls_session_set_ptr(session, &ccs_check); + gnutls_handshake_set_timeout(session, 20 * 1000); + if (ccs_check) { + gnutls_handshake_set_hook_function(session, GNUTLS_HANDSHAKE_ANY, + GNUTLS_HOOK_PRE, + cli_hsk_callback); + } + + ret = gnutls_priority_set_direct(session, "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2:+VERS-TLS1.0", NULL); + if (ret < 0) + fail("cannot set TLS 1.3 priorities\n"); + + + gnutls_certificate_set_x509_key_mem(x509_cred, &cli_ca3_cert, + &cli_ca3_key, + GNUTLS_X509_FMT_PEM); + + /* put the anonymous credentials to the current session + */ + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); + + gnutls_transport_set_int(session, fd); + + /* Perform the TLS handshake + */ + do { + ret = gnutls_handshake(session); + } + while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + + if (ret != 0) + fail("handshake failed: %s\n", gnutls_strerror(ret)); + success("client handshake completed\n"); + + do { + ret = gnutls_record_recv(session, buf, sizeof(buf)); + } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + + if (ret < 0) + fail("client: recv did not succeed as expected: %s\n", gnutls_strerror(ret)); + + close(fd); + + gnutls_deinit(session); + + if (ccs_check) { + if (client_sent_ccs != 1) { + fail("client: did not sent CCS\n"); + } + } + + gnutls_certificate_free_credentials(x509_cred); + + gnutls_global_deinit(); +} + +static int cli_hsk_callback(gnutls_session_t session, unsigned int htype, + unsigned post, unsigned int incoming, const gnutls_datum_t *msg) +{ + unsigned *p; + unsigned ccs_check; + static unsigned hello_received = 0; + + p = gnutls_session_get_ptr(session); + ccs_check = *p; + + assert(ccs_check != 0); + assert(post == GNUTLS_HOOK_PRE); + + if (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO && !incoming) { + hello_received = 1; + + gnutls_handshake_set_hook_function(session, GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC, + GNUTLS_HOOK_PRE, + cli_hsk_callback); + } + + if (htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC && !incoming && hello_received) { + client_sent_ccs++; + assert(msg->size == 1 && msg->data[0] == 0x01); + } + + + return 0; +} + +static int hsk_callback(gnutls_session_t session, unsigned int htype, + unsigned post, unsigned int incoming, const gnutls_datum_t *msg) +{ + int ret; + int fd; + unsigned *p; + unsigned ccs_check; + + p = gnutls_session_get_ptr(session); + ccs_check = *p; + + assert(post == GNUTLS_HOOK_PRE); + + if (!ccs_check) { + if (!incoming || htype == GNUTLS_HANDSHAKE_CLIENT_HELLO || + htype == GNUTLS_HANDSHAKE_FINISHED) + return 0; + + fd = gnutls_transport_get_int(session); + + /* send change cipher spec */ + do { + ret = send(fd, "\x14\x03\x03\x00\x01\x01", 6, 0); + } while(ret == -1 && (errno == EINTR || errno == EAGAIN)); + } else { /* checking whether server received it */ + if (htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC && !incoming) { + server_sent_ccs++; + assert(msg->size == 1 && msg->data[0] == 0x01); + } + } + return 0; +} + +static void server(int fd, unsigned ccs_check) +{ + int ret; + gnutls_session_t session; + gnutls_certificate_credentials_t x509_cred; + + /* this must be called once in the program + */ + global_init(); + + client_sent_ccs = 0; + server_sent_ccs = 0; + + if (debug) { + gnutls_global_set_log_function(server_log_func); + gnutls_global_set_log_level(4711); + } + + gnutls_certificate_allocate_credentials(&x509_cred); + gnutls_certificate_set_x509_key_mem(x509_cred, &server_cert, + &server_key, + GNUTLS_X509_FMT_PEM); + + gnutls_init(&session, GNUTLS_SERVER); + + gnutls_handshake_set_timeout(session, 20 * 1000); + + if (ccs_check) + gnutls_handshake_set_hook_function(session, GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC, + GNUTLS_HOOK_PRE, + hsk_callback); + else + gnutls_handshake_set_hook_function(session, GNUTLS_HANDSHAKE_ANY, + GNUTLS_HOOK_PRE, + hsk_callback); + + /* avoid calling all the priority functions, since the defaults + * are adequate. + */ + assert(gnutls_priority_set_direct(session, "NORMAL:+VERS-TLS1.3", NULL) >= 0); + gnutls_session_set_ptr(session, &ccs_check); + + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); + + gnutls_transport_set_int(session, fd); + + do { + ret = gnutls_handshake(session); + } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); + + if (ret != 0) + fail("handshake failed: %s\n", gnutls_strerror(ret)); + + success("server handshake completed\n"); + + gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUIRE); + /* ask peer for re-authentication */ + do { + ret = gnutls_record_send(session, "\x00", 1); + } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + + if (ret < 0) + fail("server: gnutls_record_send did not succeed as expected: %s\n", gnutls_strerror(ret)); + + close(fd); + gnutls_deinit(session); + + gnutls_certificate_free_credentials(x509_cred); + + if (ccs_check) { + if (server_sent_ccs != 1) { + fail("server: did not sent CCS\n"); + } + } + + gnutls_global_deinit(); + + if (debug) + success("server: client/server hello were verified\n"); +} + +static void ch_handler(int sig) +{ + int status; + wait(&status); + check_wait_status(status); + return; +} + +static +void start(unsigned ccs_check) +{ + int fd[2]; + int ret; + pid_t child; + + signal(SIGCHLD, ch_handler); + + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd); + if (ret < 0) { + perror("socketpair"); + exit(1); + } + + child = fork(); + if (child < 0) { + perror("fork"); + fail("fork"); + exit(1); + } + + if (child) { + /* parent */ + close(fd[1]); + server(fd[0], ccs_check); + kill(child, SIGTERM); + } else { + close(fd[0]); + client(fd[1], ccs_check); + exit(0); + } +} + +void doit(void) +{ + start(0); + start(1); +} + +#endif /* _WIN32 */ diff --git a/tests/tls13/ext-parse.h b/tests/tls13/ext-parse.h index 5b9f5b868f..ff8a200768 100644 --- a/tests/tls13/ext-parse.h +++ b/tests/tls13/ext-parse.h @@ -107,39 +107,29 @@ static unsigned find_client_extension(const gnutls_datum_t *msg, unsigned extnr, static unsigned find_server_extension(const gnutls_datum_t *msg, unsigned extnr, void *priv, ext_parse_func cb) { - unsigned tls13 = 0; unsigned pos = 0; success("server hello of %d bytes\n", msg->size); /* we expect the legacy version to be present */ /* ProtocolVersion legacy_version = 0x0303 */ -#ifdef TLS13_FINAL_VERSION - if (msg->data[0] != 0x03) { -#else - if (msg->data[0] != 0x7f) { -#endif + if (msg->data[0] != 0x03 || msg->data[1] != 0x03) { fail("ProtocolVersion contains %d.%d\n", (int)msg->data[0], (int)msg->data[1]); } if (msg->data[1] >= 0x04) { success("assuming TLS 1.3 or better hello format (seen %d.%d)\n", (int)msg->data[0], (int)msg->data[1]); - tls13 = 1; } pos += 2+TLS_RANDOM_SIZE; - if (!tls13) { - /* legacy_session_id */ - SKIP8(pos, msg->size); - } + /* legacy_session_id */ + SKIP8(pos, msg->size); /* CipherSuite */ pos += 2; - if (!tls13) { - /* legacy_compression_methods */ - SKIP8(pos, msg->size); - } + /* legacy_compression_methods */ + SKIP8(pos, msg->size); pos += 2; diff --git a/tests/tls13/key_share.c b/tests/tls13/key_share.c index a048ccfbdd..205f7d0056 100644 --- a/tests/tls13/key_share.c +++ b/tests/tls13/key_share.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Red Hat, Inc. + * Copyright (C) 2017-2018 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -129,7 +129,7 @@ unsigned int tls_id_to_group[] = { }; -#define TLS_EXT_KEY_SHARE 40 +#define TLS_EXT_KEY_SHARE 51 typedef struct ctx_st { gnutls_group_t group; @@ -154,7 +154,7 @@ void check_ks_contents(void *priv, gnutls_datum_t *msg) pos = 2; - while(pos < msg->size) { + while((unsigned)pos < msg->size) { id = (msg->data[pos] << 8) | msg->data[pos+1]; pos += 2; len -= 2; diff --git a/tests/tls13/prf.c b/tests/tls13/prf.c index 92178980a7..355bf37c63 100644 --- a/tests/tls13/prf.c +++ b/tests/tls13/prf.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2017 Red Hat, Inc. + * Copyright (C) 2015-2018 Red Hat, Inc. * * This file is part of GnuTLS. * @@ -126,18 +126,20 @@ static void dump(const char *name, const uint8_t *data, unsigned data_size) } \ } +#define KEY_EXP_VALUE "\x2a\xba\xd1\x0d\x79\x1d\x63\xaa\x68\xb5\x42\xa7\xbf\xee\x7c\x15\x68\x72\xc4\x94\x92\xfc\x38\x2d\x29\xc4\x2a\x21\xd6\xce\x1a\x30\x9f\x2e" +#define HELLO_VALUE "\x5b\x1e\x8a\xd6\xf4\x41\xca\xed\x60\xff\xd7\xd8\xe3\xcf\x89\xf1\x11\xfb\xc3\x08\x64\x05\xd4\x18\x2c\xf0\x8a\x75\x05\x7d\x65" static void check_prfs(gnutls_session_t session) { unsigned char key_material[512]; int ret; - TRY_OLD(13, "key expansion", 34, (uint8_t*)"\xb1\xc3\x5e\x95\x9f\xf7\x5f\x91\x40\x85\xd7\xe8\xe7\x87\x0f\xb3\x78\xec\xbf\x40\x22\xcb\x24\x6e\x85\x91\xa4\xda\xa0\x48\xa5\xb9\x17\x65"); - TRY_OLD(6, "hello", 31, (uint8_t*)"\x85\x18\x53\x95\xa8\x60\xa5\x75\xd9\xc3\x34\xa3\x45\xa4\x90\xf0\x9c\x3a\xe3\xcf\x9a\x56\x4c\xcc\xeb\xba\x62\x2f\x36\x68\x84"); + TRY_OLD(13, "key expansion", 34, (uint8_t*)KEY_EXP_VALUE); + TRY_OLD(6, "hello", 31, (uint8_t*)HELLO_VALUE); - TRY(13, "key expansion", 0, NULL, 34, (uint8_t*)"\xb1\xc3\x5e\x95\x9f\xf7\x5f\x91\x40\x85\xd7\xe8\xe7\x87\x0f\xb3\x78\xec\xbf\x40\x22\xcb\x24\x6e\x85\x91\xa4\xda\xa0\x48\xa5\xb9\x17\x65"); - TRY(6, "hello", 0, NULL, 31, (uint8_t*)"\x85\x18\x53\x95\xa8\x60\xa5\x75\xd9\xc3\x34\xa3\x45\xa4\x90\xf0\x9c\x3a\xe3\xcf\x9a\x56\x4c\xcc\xeb\xba\x62\x2f\x36\x68\x84"); - TRY(7, "context", 5, "abcd\xfa", 31, (uint8_t*)"\xf4\x49\x53\xf2\x8a\xcc\x59\x52\xa2\x29\x7d\xf4\x2f\x41\x92\x27\x6f\xc5\x1f\x52\xdb\x9a\xa5\x28\x33\x90\x28\x25\x52\x9f\x03"); - TRY(12, "null-context", 0, "", 31, (uint8_t*)"\x91\xb6\xe5\xaf\x3c\x7d\x75\x0a\x66\xe2\xd9\x3d\x57\x2c\x70\x73\x6f\xe2\x8f\x44\x5a\x22\x86\x46\x6b\xe9\x30\xc4\xf4\x0b\x7c"); + TRY(13, "key expansion", 0, NULL, 34, (uint8_t*)KEY_EXP_VALUE); + TRY(6, "hello", 0, NULL, 31, (uint8_t*)HELLO_VALUE); + TRY(7, "context", 5, "abcd\xfa", 31, (uint8_t*)"\x27\x0f\xd4\xa5\x34\xa3\x50\x60\xeb\xa7\x36\x39\x10\xbf\x54\xfb\x5f\x31\x50\xc9\x20\x4c\xe4\x1c\xa0\x6e\x63\xd6\x37\x71\x06"); + TRY(12, "null-context", 0, "", 31, (uint8_t*)"\x11\xf8\x0b\xae\x44\xe4\xed\x79\x39\x80\x8a\x6c\xff\xaa\xec\x77\x01\x9a\x1c\x9e\x14\xe8\x7a\x88\x7a\xb4\x1e\xd3\x2b\xf7\x41"); /* Try whether calling gnutls_prf() with non-null context or server-first * param, will fail */ @@ -173,7 +175,7 @@ static void client(int fd) /* Use default priorities */ ret = gnutls_priority_set_direct(session, - "NONE:+VERS-TLS1.3:+AES-256-GCM:+AEAD:+SIGN-RSA-PSS-SHA384:+GROUP-SECP256R1", + "NONE:+VERS-TLS1.3:+AES-256-GCM:+AEAD:+SIGN-RSA-PSS-RSAE-SHA384:+GROUP-SECP256R1", &err); if (ret < 0) { fail("client: priority set failed (%s): %s\n", @@ -266,7 +268,7 @@ static void server(int fd) * are adequate. */ ret = gnutls_priority_set_direct(session, - "NORMAL:-VERS-ALL:+VERS-TLS1.3:-KX-ALL", NULL); + "NORMAL:-VERS-ALL:+VERS-TLS1.3:-KX-ALL:-SIGN-ALL:+SIGN-RSA-PSS-RSAE-SHA384:-GROUP-ALL:+GROUP-SECP256R1", NULL); if (ret < 0) { fail("server: priority set failed (%s)\n\n", gnutls_strerror(ret)); diff --git a/tests/tls13/supported_versions.c b/tests/tls13/supported_versions.c index 31eb4ddbb6..be0e6f3f2e 100644 --- a/tests/tls13/supported_versions.c +++ b/tests/tls13/supported_versions.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Red Hat, Inc. + * Copyright (C) 2017-2018 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -152,12 +152,8 @@ static int client_hello_callback(gnutls_session_t session, unsigned int htype, success("server hello:\n\t%d.%d\n", (int)msg->data[pos], (int)msg->data[pos+1]); -#ifdef TLS13_FINAL_VERSION - if (msg->data[pos] != 0x03 || msg->data[pos+1] != 0x04) { -#else - if (msg->data[pos] != 0x7f || msg->data[pos+1] != 21) { -#endif - fail("fail expected TLS 1.3 in server hello, got %d.%d\n", (int)msg->data[pos], (int)msg->data[pos+1]); + if (msg->data[pos] != 0x03 || msg->data[pos+1] != 0x03) { + fail("fail expected TLS 1.2 in server hello, got %d.%d\n", (int)msg->data[pos], (int)msg->data[pos+1]); } server_hello_ok = 1; @@ -228,7 +224,7 @@ static int client_hello_callback(gnutls_session_t session, unsigned int htype, #ifdef TLS13_FINAL_VERSION if (msg->data[pos] != 0x03 || msg->data[pos+1] != 0x04) { #else - if (msg->data[pos] != 0x7f || msg->data[pos+1] != 21) { + if (msg->data[pos] != 0x7f || msg->data[pos+1] != 23) { #endif fail("fail expected TLS 1.3, got %d.%d\n", (int)msg->data[pos], (int)msg->data[pos+1]); } |