| From e47d30e272a0b3977db8dae09327acad45b931d8 Mon Sep 17 00:00:00 2001 |
| From: mancha <mancha1@zoho.com> |
| Date: Sun, 1 Jun 2014 |
| Subject: CVE-2014-3466 |
| |
| This is a backport adaptation for use with GnuTLS 2.12.23. |
| |
| Relevant upstream commit(s): |
| ------------------------- |
| https://gitorious.org/gnutls/gnutls/commit/688ea6428a432c |
| https://gitorious.org/gnutls/gnutls/commit/a7be326f0e33cf |
| |
| --- |
| lib/gnutls_handshake.c | 2 |
| tests/Makefile.am | 2 |
| tests/long-session-id.c | 268 ++++++++++++++++++++++++++++++++++++++++ |
| 3 files changed, 270 insertions(+), 2 deletions(-) |
| |
| --- a/lib/gnutls_handshake.c |
| +++ b/lib/gnutls_handshake.c |
| @@ -1797,7 +1797,7 @@ _gnutls_read_server_hello (gnutls_sessio |
| DECR_LEN (len, 1); |
| session_id_len = data[pos++]; |
| |
| - if (len < session_id_len) |
| + if (len < session_id_len || session_id_len > TLS_MAX_SESSION_ID_SIZE) |
| { |
| gnutls_assert (); |
| return GNUTLS_E_UNSUPPORTED_VERSION_PACKET; |
| --- a/tests/Makefile.am |
| +++ b/tests/Makefile.am |
| @@ -64,7 +64,7 @@ ctests = simple gc set_pkcs12_cred certd |
| crq_key_id x509sign-verify cve-2009-1415 cve-2009-1416 \ |
| crq_apis init_roundtrip pkcs12_s2k_pem dn2 mini-eagain \ |
| nul-in-x509-names x509_altname pkcs12_encode mini-x509 \ |
| - mini-x509-rehandshake rng-fork x509cert gendh |
| + mini-x509-rehandshake rng-fork x509cert gendh long-session-id |
| |
| if ENABLE_OPENSSL |
| ctests += openssl |
| --- /dev/null |
| +++ b/tests/long-session-id.c |
| @@ -0,0 +1,268 @@ |
| +/* |
| + * Copyright (C) 2012 Free Software Foundation, 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 General Public License |
| + * along with GnuTLS; if not, write to the Free Software Foundation, |
| + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
| + */ |
| + |
| +#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 <signal.h> |
| + |
| +static int debug = 0; |
| +static void terminate(int); |
| + |
| +/* This program tests the robustness of record |
| + * decoding. |
| + */ |
| + |
| +static void client_log_func(int level, const char *str) |
| +{ |
| + fprintf(stderr, "client|<%d>| %s", level, str); |
| +} |
| + |
| +static unsigned char server_cert_pem[] = |
| + "-----BEGIN CERTIFICATE-----\n" |
| + "MIICVjCCAcGgAwIBAgIERiYdMTALBgkqhkiG9w0BAQUwGTEXMBUGA1UEAxMOR251\n" |
| + "VExTIHRlc3QgQ0EwHhcNMDcwNDE4MTMyOTIxWhcNMDgwNDE3MTMyOTIxWjA3MRsw\n" |
| + "GQYDVQQKExJHbnVUTFMgdGVzdCBzZXJ2ZXIxGDAWBgNVBAMTD3Rlc3QuZ251dGxz\n" |
| + "Lm9yZzCBnDALBgkqhkiG9w0BAQEDgYwAMIGIAoGA17pcr6MM8C6pJ1aqU46o63+B\n" |
| + "dUxrmL5K6rce+EvDasTaDQC46kwTHzYWk95y78akXrJutsoKiFV1kJbtple8DDt2\n" |
| + "DZcevensf9Op7PuFZKBroEjOd35znDET/z3IrqVgbtm2jFqab7a+n2q9p/CgMyf1\n" |
| + "tx2S5Zacc1LWn9bIjrECAwEAAaOBkzCBkDAMBgNVHRMBAf8EAjAAMBoGA1UdEQQT\n" |
| + "MBGCD3Rlc3QuZ251dGxzLm9yZzATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHQ8B\n" |
| + "Af8EBQMDB6AAMB0GA1UdDgQWBBTrx0Vu5fglyoyNgw106YbU3VW0dTAfBgNVHSME\n" |
| + "GDAWgBTpPBz7rZJu5gakViyi4cBTJ8jylTALBgkqhkiG9w0BAQUDgYEAaFEPTt+7\n" |
| + "bzvBuOf7+QmeQcn29kT6Bsyh1RHJXf8KTk5QRfwp6ogbp94JQWcNQ/S7YDFHglD1\n" |
| + "AwUNBRXwd3riUsMnsxgeSDxYBfJYbDLeohNBsqaPDJb7XailWbMQKfAbFQ8cnOxg\n" |
| + "rOKLUQRWJ0K3HyXRMhbqjdLIaQiCvQLuizo=\n" "-----END CERTIFICATE-----\n"; |
| + |
| +const gnutls_datum_t server_cert = { server_cert_pem, |
| + sizeof(server_cert_pem) |
| +}; |
| + |
| +static unsigned char server_key_pem[] = |
| + "-----BEGIN RSA PRIVATE KEY-----\n" |
| + "MIICXAIBAAKBgQDXulyvowzwLqknVqpTjqjrf4F1TGuYvkrqtx74S8NqxNoNALjq\n" |
| + "TBMfNhaT3nLvxqResm62ygqIVXWQlu2mV7wMO3YNlx696ex/06ns+4VkoGugSM53\n" |
| + "fnOcMRP/PciupWBu2baMWppvtr6far2n8KAzJ/W3HZLllpxzUtaf1siOsQIDAQAB\n" |
| + "AoGAYAFyKkAYC/PYF8e7+X+tsVCHXppp8AoP8TEZuUqOZz/AArVlle/ROrypg5kl\n" |
| + "8YunrvUdzH9R/KZ7saNZlAPLjZyFG9beL/am6Ai7q7Ma5HMqjGU8kTEGwD7K+lbG\n" |
| + "iomokKMOl+kkbY/2sI5Czmbm+/PqLXOjtVc5RAsdbgvtmvkCQQDdV5QuU8jap8Hs\n" |
| + "Eodv/tLJ2z4+SKCV2k/7FXSKWe0vlrq0cl2qZfoTUYRnKRBcWxc9o92DxK44wgPi\n" |
| + "oMQS+O7fAkEA+YG+K9e60sj1K4NYbMPAbYILbZxORDecvP8lcphvwkOVUqbmxOGh\n" |
| + "XRmTZUuhBrJhJKKf6u7gf3KWlPl6ShKEbwJASC118cF6nurTjuLf7YKARDjNTEws\n" |
| + "qZEeQbdWYINAmCMj0RH2P0mvybrsXSOD5UoDAyO7aWuqkHGcCLv6FGG+qwJAOVqq\n" |
| + "tXdUucl6GjOKKw5geIvRRrQMhb/m5scb+5iw8A4LEEHPgGiBaF5NtJZLALgWfo5n\n" |
| + "hmC8+G8F0F78znQtPwJBANexu+Tg5KfOnzSILJMo3oXiXhf5PqXIDmbN0BKyCKAQ\n" |
| + "LfkcEcUbVfmDaHpvzwY9VEaoMOKVLitETXdNSxVpvWM=\n" |
| + "-----END RSA PRIVATE KEY-----\n"; |
| + |
| +const gnutls_datum_t server_key = { server_key_pem, |
| + sizeof(server_key_pem) |
| +}; |
| + |
| + |
| +/* A very basic TLS client, with anonymous authentication. |
| + */ |
| + |
| +static void client(int fd, const char *prio) |
| +{ |
| + int ret; |
| + gnutls_anon_client_credentials_t anoncred; |
| + gnutls_certificate_credentials_t x509_cred; |
| + gnutls_session_t session; |
| + /* Need to enable anonymous KX specifically. */ |
| + |
| + gnutls_global_init(); |
| + |
| + if (debug) { |
| + gnutls_global_set_log_function(client_log_func); |
| + gnutls_global_set_log_level(7); |
| + } |
| + |
| + gnutls_anon_allocate_client_credentials(&anoncred); |
| + gnutls_certificate_allocate_credentials(&x509_cred); |
| + |
| + /* Initialize TLS session |
| + */ |
| + gnutls_init(&session, GNUTLS_CLIENT); |
| + |
| + /* Use default priorities */ |
| + gnutls_priority_set_direct(session, prio, NULL); |
| + |
| + /* put the anonymous credentials to the current session |
| + */ |
| + gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred); |
| + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); |
| + |
| + gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) fd); |
| + |
| + /* Perform the TLS handshake |
| + */ |
| + do { |
| + ret = gnutls_handshake(session); |
| + } |
| + while (ret < 0 && gnutls_error_is_fatal(ret) == 0); |
| + |
| + if (ret < 0) { |
| + fprintf(stderr, "client: Handshake failed (expected)\n"); |
| + gnutls_perror(ret); |
| + exit(0); |
| + } else { |
| + if (debug) |
| + fprintf(stderr, "client: Handshake was completed\n"); |
| + } |
| + |
| + close(fd); |
| + |
| + gnutls_deinit(session); |
| + |
| + gnutls_anon_free_client_credentials(anoncred); |
| + gnutls_certificate_free_credentials(x509_cred); |
| + |
| + gnutls_global_deinit(); |
| +} |
| + |
| + |
| +/* These are global */ |
| +pid_t child; |
| + |
| +static void terminate(int ret) |
| +{ |
| + kill(child, SIGTERM); |
| + exit(ret); |
| +} |
| + |
| +static void server(int fd, const char *prio) |
| +{ |
| + int ret; |
| + uint8_t id[255]; |
| + uint8_t buffer[] = "\x16\x03\x00\x01\x25" |
| + "\x02\x00\x01\x21" |
| + "\x03\x00"/*Server Version */ |
| + /*Random*/"\x00\x00\x00\x00\x01\x00\x00\x00\x00\x01\x00\x00\x00\x00\x01\x00\x00\x00\x00\x01\x00\x00\x00\x00\x01\x00\x00\x00\x00\x01\x00\x00" |
| + /*SessionID*/"\xfe"; |
| + |
| + ret = read(fd, id, sizeof(id)); |
| + if (ret < 0) { |
| + abort(); |
| + } |
| + |
| + ret = write(fd, buffer, sizeof(buffer)); |
| + if (ret < 0) { |
| + return; |
| + } |
| + |
| + memset(id, 0xff, sizeof(id)); |
| + ret = write(fd, id, sizeof(id)); |
| + if (ret < 0) { |
| + return; |
| + } |
| + |
| + memset(id, 0xff, sizeof(id)); |
| + ret = write(fd, id, sizeof(id)); |
| + if (ret < 0) { |
| + return; |
| + } |
| + sleep(3); |
| + |
| + return; |
| +} |
| + |
| +static void start(const char *prio) |
| +{ |
| + int fd[2]; |
| + int ret; |
| + |
| + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd); |
| + if (ret < 0) { |
| + perror("socketpair"); |
| + exit(1); |
| + } |
| + |
| + child = fork(); |
| + if (child < 0) { |
| + perror("fork"); |
| + exit(1); |
| + } |
| + |
| + if (child) { |
| + /* parent */ |
| + close(fd[1]); |
| + server(fd[0], prio); |
| + kill(child, SIGTERM); |
| + } else { |
| + close(fd[0]); |
| + client(fd[1], prio); |
| + exit(0); |
| + } |
| +} |
| + |
| +static void ch_handler(int sig) |
| +{ |
| + int status, ret = 0; |
| + wait(&status); |
| + if (WEXITSTATUS(status) != 0 || |
| + (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV)) { |
| + if (WIFSIGNALED(status)) { |
| + fprintf(stderr, "Child died with sigsegv\n"); |
| + ret = 1; |
| + } else { |
| + fprintf(stderr, "Child died with status %d\n", |
| + WEXITSTATUS(status)); |
| + } |
| + terminate(ret); |
| + } |
| + return; |
| +} |
| + |
| +int main(int argc, char **argv) |
| +{ |
| + signal(SIGCHLD, ch_handler); |
| + |
| + if (argc > 1) |
| + debug = 1; |
| + |
| + start("NORMAL"); |
| + return 0; |
| +} |
| + |
| +#endif /* _WIN32 */ |