]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added support for the extended master secret calculation
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 8 Oct 2014 12:09:30 +0000 (14:09 +0200)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 8 Oct 2014 12:19:59 +0000 (14:19 +0200)
That is performed implicitly unless GNUTLS_NO_EXTENSIONS is specified.
The implementation follows draft-ietf-tls-session-hash-02.

13 files changed:
lib/ext/Makefile.am
lib/ext/ext_master_secret.c [new file with mode: 0644]
lib/ext/ext_master_secret.h [new file with mode: 0644]
lib/gnutls_constate.c
lib/gnutls_extensions.c
lib/gnutls_handshake.c
lib/gnutls_handshake.h
lib/gnutls_int.h
lib/gnutls_kx.c
lib/gnutls_session_pack.c
lib/gnutls_state.c
lib/includes/gnutls/gnutls.h.in
lib/libgnutls.map

index b532f7d6bc20574d2f5bdc13d781bee8dd58ad3e..9b7012bed2a280c8582d9abd5bd0684090f5aeaf 100644 (file)
@@ -39,8 +39,8 @@ libgnutls_ext_la_SOURCES = max_record.c cert_type.c \
        max_record.h cert_type.h server_name.h srp.h \
        session_ticket.h signature.h safe_renegotiation.h \
        session_ticket.c srp.c ecc.c ecc.h heartbeat.c heartbeat.h \
-       status_request.h status_request.c \
-       dumbfw.c dumbfw.h
+       status_request.h status_request.c dumbfw.c dumbfw.h \
+       ext_master_secret.c ext_master_secret.h
 
 if ENABLE_ALPN
 libgnutls_ext_la_SOURCES += alpn.c alpn.h
diff --git a/lib/ext/ext_master_secret.c b/lib/ext/ext_master_secret.c
new file mode 100644 (file)
index 0000000..0fc5d28
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser 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/>
+ *
+ */
+
+/* This file contains the code for the Max Record Size TLS extension.
+ */
+
+#include "gnutls_int.h"
+#include "gnutls_errors.h"
+#include "gnutls_num.h"
+#include <gnutls_extensions.h>
+#include <ext/ext_master_secret.h>
+
+static int _gnutls_ext_master_secret_recv_params(gnutls_session_t session,
+                                         const uint8_t * data,
+                                         size_t data_size);
+static int _gnutls_ext_master_secret_send_params(gnutls_session_t session,
+                                         gnutls_buffer_st * extdata);
+
+extension_entry_st ext_mod_ext_master_secret = {
+       .name = "EXT MASTER SECRET",
+       .type = GNUTLS_EXTENSION_EXT_MASTER_SECRET,
+       .parse_type = GNUTLS_EXT_TLS,
+
+       .recv_func = _gnutls_ext_master_secret_recv_params,
+       .send_func = _gnutls_ext_master_secret_send_params,
+       .pack_func = NULL,
+       .unpack_func = NULL,
+       .deinit_func = NULL
+};
+
+/* 
+ * In case of a server: if an EXT_MASTER_SECRET extension type is received then it
+ * sets a flag into the session security parameters.
+ *
+ */
+static int
+_gnutls_ext_master_secret_recv_params(gnutls_session_t session,
+                              const uint8_t * data, size_t _data_size)
+{
+       ssize_t data_size = _data_size;
+
+       if (session->internals.try_ext_master_secret == 0) {
+               return 0;
+       }
+
+       if (data_size != 0) {
+               return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+       }
+       session->security_parameters.ext_master_secret = 1;
+
+       return 0;
+}
+
+/* returns data_size or a negative number on failure
+ */
+static int
+_gnutls_ext_master_secret_send_params(gnutls_session_t session,
+                              gnutls_buffer_st * extdata)
+{
+       if (session->internals.try_ext_master_secret == 0) {
+            return 0;
+       }
+
+       /* this function sends the client extension data */
+       if (session->security_parameters.entity == GNUTLS_CLIENT) {
+               return GNUTLS_E_INT_RET_0;
+       } else { /* server side */
+               if (session->security_parameters.ext_master_secret != 0)
+                       return GNUTLS_E_INT_RET_0;
+       }
+
+       return 0;
+}
+
+/**
+ * gnutls_session_ext_master_secret_status:
+ * @session: is a #gnutls_session_t structure.
+ *
+ * Get the status of the extended master secret extension negotiation.
+ * This is in accordance to draft-ietf-tls-session-hash-01
+ *
+ * Returns: Non-zero if the negotiation was successful or zero otherwise.
+ **/
+unsigned gnutls_session_ext_master_secret_status(gnutls_session_t session)
+{
+       return session->security_parameters.ext_master_secret;
+}
+
diff --git a/lib/ext/ext_master_secret.h b/lib/ext/ext_master_secret.h
new file mode 100644 (file)
index 0000000..2cdb295
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser 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/>
+ *
+ */
+
+#ifndef EXT_EXT_MASTER_SECRET_H
+#define EXT_EXT_MASTER_SECRET_H
+
+#include <gnutls_extensions.h>
+
+extern extension_entry_st ext_mod_ext_master_secret;
+
+#endif
index 97c538d34d4b284c112e733cb83eb99eec0b4a8d..e9b9678f4224da1a212dc8ab28defad357774469 100644 (file)
@@ -388,6 +388,7 @@ int _gnutls_epoch_set_keys(gnutls_session_t session, uint16_t epoch)
        dst->cert_type = src->cert_type; \
        dst->compression_method = src->compression_method; \
        dst->timestamp = src->timestamp; \
+       dst->ext_master_secret = src->ext_master_secret; \
        dst->max_record_recv_size = src->max_record_recv_size; \
        dst->max_record_send_size = src->max_record_send_size
 
index 36ac43e8ee60e2173943796b31ed77db5a65740a..e8cf539f217906e425020666743d5dab67451c93 100644 (file)
@@ -39,6 +39,7 @@
 #include <ext/safe_renegotiation.h>
 #include <ext/ecc.h>
 #include <ext/status_request.h>
+#include <ext/ext_master_secret.h>
 #include <ext/srtp.h>
 #include <ext/alpn.h>
 #include <ext/dumbfw.h>
@@ -311,6 +312,10 @@ int _gnutls_ext_init(void)
        if (ret != GNUTLS_E_SUCCESS)
                return ret;
 
+       ret = _gnutls_ext_register(&ext_mod_ext_master_secret);
+       if (ret != GNUTLS_E_SUCCESS)
+               return ret;
+
 #ifdef ENABLE_OCSP
        ret = _gnutls_ext_register(&ext_mod_status_request);
        if (ret != GNUTLS_E_SUCCESS)
index 28e4a7eafeb996d9d22bf9a68b60df6850f70b1b..9ddcfbce3e576877c4bbae9479b5f4bb6184cde2 100644 (file)
@@ -3571,3 +3571,69 @@ gnutls_handshake_get_last_out(gnutls_session_t session)
 {
        return session->internals.last_handshake_out;
 }
+
+/* This returns the session hash as in draft-ietf-tls-session-hash-02.
+ *
+ * FIXME: It duplicates some of the actions in _gnutls_handshake_sign_crt_vrfy*.
+ * See whether they can be merged.
+ */
+int _gnutls_handshake_get_session_hash(gnutls_session_t session, gnutls_datum_t *shash)
+{
+       const version_entry_st *ver = get_version(session);
+       int ret;
+       const mac_entry_st *me;
+       uint8_t concat[2*MAX_HASH_SIZE];
+       digest_hd_st td_md5;
+       digest_hd_st td_sha;
+
+       if (unlikely(ver == NULL))
+               return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+       if (_gnutls_version_has_selectable_prf(ver)) { /* TLS 1.2+ */
+               gnutls_mac_algorithm_t prf;
+
+               prf = _gnutls_cipher_suite_get_prf(session->security_parameters.cipher_suite);
+               if (prf == GNUTLS_MAC_UNKNOWN)
+                       return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM);
+
+               me = mac_to_entry(prf);
+
+               ret =
+                   _gnutls_hash_fast((gnutls_digest_algorithm_t)me->id,
+                                     session->internals.handshake_hash_buffer.
+                                     data,
+                                     session->internals.handshake_hash_buffer.
+                                     length, concat);
+               if (ret < 0)
+                       return gnutls_assert_val(ret);
+
+               return _gnutls_set_datum(shash, concat, me->output_size);
+       } else {
+               ret = _gnutls_hash_init(&td_sha, hash_to_entry(GNUTLS_DIG_SHA1));
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+
+               _gnutls_hash(&td_sha,
+                            session->internals.handshake_hash_buffer.data,
+                            session->internals.handshake_hash_buffer.length);
+
+               _gnutls_hash_deinit(&td_sha, &concat[16]);
+
+               ret =
+                   _gnutls_hash_init(&td_md5,
+                                     hash_to_entry(GNUTLS_DIG_MD5));
+               if (ret < 0)
+                       return gnutls_assert_val(ret);
+
+               _gnutls_hash(&td_md5,
+                            session->internals.handshake_hash_buffer.data,
+                            session->internals.handshake_hash_buffer.
+                            length);
+
+               _gnutls_hash_deinit(&td_md5, concat);
+
+               return _gnutls_set_datum(shash, concat, 36);
+       }
+}
index 88a4169b6da9f6603c8e02f275122164a5ca8482..65b190238d1da6e0c884507a697e474ba088b964 100644 (file)
@@ -71,4 +71,6 @@ inline static int handshake_remaining_time(gnutls_session_t session)
        return 0;
 }
 
+int _gnutls_handshake_get_session_hash(gnutls_session_t session, gnutls_datum_t *shash);
+
 #endif
index 106cd73b2519e8ccea1059d78e42c87ac15c050e..c6e541fe1ed0ee8fc265e8667d487524866a89c2 100644 (file)
@@ -285,8 +285,8 @@ typedef enum extensions_t {
        GNUTLS_EXTENSION_HEARTBEAT = 15,
        GNUTLS_EXTENSION_ALPN = 16,
        GNUTLS_EXTENSION_DUMBFW = 21,
+       GNUTLS_EXTENSION_EXT_MASTER_SECRET = 23,
        GNUTLS_EXTENSION_SESSION_TICKET = 35,
-       GNUTLS_EXTENSION_NEW_RECORD_PADDING = 48015,    /* aka: 0xbeaf */
        GNUTLS_EXTENSION_SAFE_RENEGOTIATION = 65281     /* aka: 0xff01 */
 } extensions_t;
 
@@ -529,10 +529,6 @@ typedef struct {
  * session.
  */
 
-/* if you add anything in Security_Parameters struct, then
- * also modify CPY_COMMON in gnutls_constate.c. 
- */
-
 /* Note that the security parameters structure is set up after the
  * handshake has finished. The only value you may depend on while
  * the handshake is in progress is the cipher suite value.
@@ -576,9 +572,15 @@ typedef struct {
        /* Holds the signature algorithm used in this session - If any */
        gnutls_sign_algorithm_t server_sign_algo;
        gnutls_sign_algorithm_t client_sign_algo;
-       
-       /* FIXME: The following are not saved in the session storage
-        * for session resumption.
+
+       /* Whether the master secret negotiation will be according to
+        * draft-ietf-tls-session-hash-01
+        */
+       uint8_t ext_master_secret;
+
+       /* Note: if you add anything in Security_Parameters struct, then
+        * also modify CPY_COMMON in gnutls_constate.c, and gnutls_session_pack.c,
+        * in order to save it in the session storage.
         */
 
        /* Used by extensions that enable supplemental data: Which ones
@@ -994,6 +996,7 @@ typedef struct {
 
        bool sc_random_set;
        bool no_replay_protection;      /* DTLS replay protection */
+       bool try_ext_master_secret;     /* whether to try negotiating the ext master secret */
 
        /* If you add anything here, check _gnutls_handshake_internal_state_clear().
         */
index 04e7a69593c8db3a395d4341bbf10fcb0eb0caf4..d6d41a6ea856c4b9791c9c8c0d7a595d6c57aa5c 100644 (file)
@@ -70,6 +70,10 @@ send_handshake(gnutls_session_t session, uint8_t * data, size_t size,
 
 #define MASTER_SECRET "master secret"
 #define MASTER_SECRET_SIZE (sizeof(MASTER_SECRET)-1)
+
+#define EXT_MASTER_SECRET "extended master secret"
+#define EXT_MASTER_SECRET_SIZE (sizeof(EXT_MASTER_SECRET)-1)
+
 static int generate_normal_master(gnutls_session_t session,
                                  gnutls_datum_t *, int);
 
@@ -114,39 +118,55 @@ generate_normal_master(gnutls_session_t session,
                                         server_random, 32, buf,
                                         sizeof(buf), NULL));
 
-       if (get_num_version(session) == GNUTLS_SSL3) {
+       if (session->security_parameters.ext_master_secret == 0) {
                uint8_t rnd[2 * GNUTLS_RANDOM_SIZE + 1];
-
                memcpy(rnd, session->security_parameters.client_random,
                       GNUTLS_RANDOM_SIZE);
                memcpy(&rnd[GNUTLS_RANDOM_SIZE],
                       session->security_parameters.server_random,
                       GNUTLS_RANDOM_SIZE);
 
-               ret =
-                   _gnutls_ssl3_generate_random(premaster->data,
-                                                premaster->size, rnd,
-                                                2 * GNUTLS_RANDOM_SIZE,
-                                                GNUTLS_MASTER_SIZE,
-                                                session->security_parameters.
-                                                master_secret);
-
+               if (get_num_version(session) == GNUTLS_SSL3) {
+                       ret =
+                           _gnutls_ssl3_generate_random(premaster->data,
+                                                        premaster->size, rnd,
+                                                        2 * GNUTLS_RANDOM_SIZE,
+                                                        GNUTLS_MASTER_SIZE,
+                                                        session->security_parameters.
+                                                        master_secret);
+               } else {
+                       ret =
+                           _gnutls_PRF(session, premaster->data, premaster->size,
+                                       MASTER_SECRET, MASTER_SECRET_SIZE,
+                                       rnd, 2 * GNUTLS_RANDOM_SIZE,
+                                       GNUTLS_MASTER_SIZE,
+                                       session->security_parameters.
+                                       master_secret);
+               }
        } else {
-               uint8_t rnd[2 * GNUTLS_RANDOM_SIZE + 1];
-
-               memcpy(rnd, session->security_parameters.client_random,
-                      GNUTLS_RANDOM_SIZE);
-               memcpy(&rnd[GNUTLS_RANDOM_SIZE],
-                      session->security_parameters.server_random,
-                      GNUTLS_RANDOM_SIZE);
+               gnutls_datum_t shash = {NULL, 0};
 
-               ret =
-                   _gnutls_PRF(session, premaster->data, premaster->size,
-                               MASTER_SECRET, MASTER_SECRET_SIZE,
-                               rnd, 2 * GNUTLS_RANDOM_SIZE,
-                               GNUTLS_MASTER_SIZE,
-                               session->security_parameters.
-                               master_secret);
+               /* draft-ietf-tls-session-hash-02 */
+               ret = _gnutls_handshake_get_session_hash(session, &shash);
+               if (ret < 0)
+                       return gnutls_assert_val(ret);
+               if (get_num_version(session) == GNUTLS_SSL3) {
+                       ret =
+                           _gnutls_ssl3_generate_random(premaster->data,
+                                                        premaster->size, shash.data, shash.size,
+                                                        GNUTLS_MASTER_SIZE,
+                                                        session->security_parameters.
+                                                        master_secret);
+               } else {
+                       ret =
+                           _gnutls_PRF(session, premaster->data, premaster->size,
+                                       EXT_MASTER_SECRET, EXT_MASTER_SECRET_SIZE,
+                                       shash.data, shash.size,
+                                       GNUTLS_MASTER_SIZE,
+                                       session->security_parameters.
+                                       master_secret);
+               }
+               gnutls_free(shash.data);
        }
 
        if (!keep_premaster)
index 7f4111d1a688abaaf1f7a6247979895fa7180d2a..5d63a1a0a80d9227e021ab73040e77ae3480d735 100644 (file)
@@ -768,6 +768,8 @@ pack_security_parameters(gnutls_session_t session, gnutls_buffer_st * ps)
                          session->security_parameters.server_sign_algo);
        BUFFER_APPEND_NUM(ps,
                          session->security_parameters.client_sign_algo);
+       BUFFER_APPEND_NUM(ps,
+                         session->security_parameters.ext_master_secret);
 
        _gnutls_write_uint32(ps->length - cur_size,
                             ps->data + size_offset);
@@ -855,6 +857,9 @@ unpack_security_parameters(gnutls_session_t session, gnutls_buffer_st * ps)
        BUFFER_POP_NUM(ps,
                       session->internals.resumed_security_parameters.
                       client_sign_algo);
+       BUFFER_POP_NUM(ps,
+                      session->internals.resumed_security_parameters.
+                      ext_master_secret);
 
        if (session->internals.resumed_security_parameters.
            max_record_recv_size == 0
index a05c77e7ffea14b83623e5d0b40320ffd31dca2b..ee2cccbc7c3550f41781860265da41cb4432cb4d 100644 (file)
@@ -413,6 +413,9 @@ int gnutls_init(gnutls_session_t * session, unsigned int flags)
 #endif
        }
 
+       if (!(flags & GNUTLS_NO_EXTENSIONS))
+               (*session)->internals.try_ext_master_secret = 1;
+
        if (flags & GNUTLS_NO_REPLAY_PROTECTION)
                (*session)->internals.no_replay_protection = 1;
 
index fbc26f39603e699ef5a9b412efb58293ddc8db19..0647802d671b3ca7d9ccfefafe5d9934fd005e6f 100644 (file)
@@ -1022,6 +1022,7 @@ int gnutls_heartbeat_allowed(gnutls_session_t session, unsigned int type);
 
   /* Safe renegotiation */
 int gnutls_safe_renegotiation_status(gnutls_session_t session);
+unsigned gnutls_session_ext_master_secret_status(gnutls_session_t session);
 
 /**
  * gnutls_supplemental_data_format_type_t:
index a081b5c88eba30756f1a2a425ec8bac5bfeabe2f..f53e06fff27600ac2435f7c062bbafa4e133150a 100644 (file)
@@ -1048,6 +1048,7 @@ GNUTLS_3_1_0 {
        gnutls_x509_crq_get_signature_algorithm;
        gnutls_privkey_import_ext3;
        gnutls_record_discard_queued;
+       gnutls_session_ext_master_secret_status;
 } GNUTLS_3_0_0;
 
 GNUTLS_FIPS140 {