LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib/ext - psk_ke_modes.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 82 87 94.3 %
Date: 2020-10-30 04:50:48 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2017 Free Software Foundation, Inc.
       3             :  *
       4             :  * Author: Ander Juaristi
       5             :  *
       6             :  * This file is part of GnuTLS.
       7             :  *
       8             :  * The GnuTLS is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public License
      10             :  * as published by the Free Software Foundation; either version 2.1 of
      11             :  * the License, or (at your option) any later version.
      12             :  *
      13             :  * This library is distributed in the hope that it will be useful, but
      14             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public License
      19             :  * along with this program.  If not, see <https://www.gnu.org/licenses/>
      20             :  *
      21             :  */
      22             : 
      23             : #include "gnutls_int.h"
      24             : #include "ext/psk_ke_modes.h"
      25             : #include "ext/pre_shared_key.h"
      26             : #include <assert.h>
      27             : 
      28             : #define PSK_KE 0
      29             : #define PSK_DHE_KE 1
      30             : 
      31             : static int
      32        5627 : psk_ke_modes_send_params(gnutls_session_t session,
      33             :                          gnutls_buffer_t extdata)
      34             : {
      35        5627 :         int ret;
      36        5627 :         const version_entry_st *vers;
      37        5627 :         uint8_t data[2];
      38        5627 :         unsigned pos, i;
      39        5627 :         unsigned have_dhpsk = 0;
      40        5627 :         unsigned have_psk = 0;
      41             : 
      42             :         /* Server doesn't send psk_key_exchange_modes */
      43        5627 :         if (session->security_parameters.entity == GNUTLS_SERVER)
      44             :                 return 0;
      45             : 
      46             :         /* If session ticket is disabled and no PSK key exchange is
      47             :          * enabled, don't send the extension */
      48        3467 :         if ((session->internals.flags & GNUTLS_NO_TICKETS) &&
      49         105 :             !session->internals.priorities->have_psk)
      50             :                 return 0;
      51             : 
      52        3389 :         vers = _gnutls_version_max(session);
      53        3389 :         if (!vers || !vers->tls13_sem)
      54             :                 return 0;
      55             : 
      56             :         /* We send the list prioritized according to our preferences as a convention
      57             :          * (used throughout the protocol), even if the protocol doesn't mandate that
      58             :          * for this particular message. That way we can keep the TLS 1.2 semantics/
      59             :          * prioritization when negotiating PSK or DHE-PSK. Receiving servers would
      60             :          * very likely respect our prioritization if they parse the message serially. */
      61             :         pos = 0;
      62        7487 :         for (i=0;i<session->internals.priorities->_kx.num_priorities;i++) {
      63        5960 :                 if (session->internals.priorities->_kx.priorities[i] == GNUTLS_KX_PSK && !have_psk) {
      64         423 :                         assert(pos <= 1);
      65         423 :                         data[pos++] = PSK_KE;
      66         423 :                         session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
      67         423 :                         have_psk = 1;
      68        5537 :                 } else if ((session->internals.priorities->_kx.priorities[i] == GNUTLS_KX_DHE_PSK ||
      69         761 :                             session->internals.priorities->_kx.priorities[i] == GNUTLS_KX_ECDHE_PSK) && !have_dhpsk) {
      70         414 :                         assert(pos <= 1);
      71         414 :                         data[pos++] = PSK_DHE_KE;
      72         414 :                         session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
      73         414 :                         have_dhpsk = 1;
      74             :                 }
      75             : 
      76        5960 :                 if (have_psk && have_dhpsk)
      77             :                         break;
      78             :         }
      79             : 
      80             :         /* For session resumption we need to send at least one */
      81        1900 :         if (pos == 0) {
      82        1436 :                 if (session->internals.flags & GNUTLS_NO_TICKETS)
      83             :                         return 0;
      84             : 
      85        1436 :                 data[pos++] = PSK_DHE_KE;
      86        1436 :                 data[pos++] = PSK_KE;
      87        1436 :                 session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
      88        1436 :                 session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
      89             :         }
      90             : 
      91        1900 :         ret = _gnutls_buffer_append_data_prefix(extdata, 8, data, pos);
      92        1900 :         if (ret < 0)
      93           0 :                 return gnutls_assert_val(ret);
      94             : 
      95        1900 :         session->internals.hsk_flags |= HSK_PSK_KE_MODES_SENT;
      96             : 
      97        1900 :         return 0;
      98             : }
      99             : 
     100             : #define MAX_POS INT_MAX
     101             : 
     102             : /*
     103             :  * Since we only support ECDHE-authenticated PSKs, the server
     104             :  * just verifies that a "psk_key_exchange_modes" extension was received,
     105             :  * and that it contains the value one.
     106             :  */
     107             : static int
     108        3001 : psk_ke_modes_recv_params(gnutls_session_t session,
     109             :                          const unsigned char *data, size_t len)
     110             : {
     111        3001 :         uint8_t ke_modes_len;
     112        3001 :         const version_entry_st *vers = get_version(session);
     113        3001 :         gnutls_psk_server_credentials_t cred;
     114        3001 :         int dhpsk_pos = MAX_POS;
     115        3001 :         int psk_pos = MAX_POS;
     116        3001 :         int cli_psk_pos = MAX_POS;
     117        3001 :         int cli_dhpsk_pos = MAX_POS;
     118        3001 :         unsigned i;
     119             : 
     120             :         /* Client doesn't receive psk_key_exchange_modes */
     121        3001 :         if (session->security_parameters.entity == GNUTLS_CLIENT)
     122           0 :                 return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
     123             : 
     124             :         /* we set hsk_flags to HSK_PSK_KE_MODE_INVALID on failure to ensure that
     125             :          * when we parse the pre-shared key extension we detect PSK_KE_MODES as
     126             :          * received. */
     127        3001 :         if (!vers || !vers->tls13_sem) {
     128         125 :                 session->internals.hsk_flags |= HSK_PSK_KE_MODE_INVALID;
     129         127 :                 return gnutls_assert_val(0);
     130             :         }
     131             : 
     132        2876 :         cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(session, GNUTLS_CRD_PSK);
     133        2876 :         if (cred == NULL && (session->internals.flags & GNUTLS_NO_TICKETS)) {
     134         517 :                 session->internals.hsk_flags |= HSK_PSK_KE_MODE_INVALID;
     135         517 :                 return gnutls_assert_val(0);
     136             :         }
     137             : 
     138        2359 :         DECR_LEN(len, 1);
     139        2359 :         ke_modes_len = *(data++);
     140             : 
     141       11452 :         for (i=0;i<session->internals.priorities->_kx.num_priorities;i++) {
     142        9873 :                 if (session->internals.priorities->_kx.priorities[i] == GNUTLS_KX_PSK && psk_pos == MAX_POS) {
     143        1748 :                         psk_pos = i;
     144        8125 :                 } else if ((session->internals.priorities->_kx.priorities[i] == GNUTLS_KX_DHE_PSK ||
     145        1074 :                             session->internals.priorities->_kx.priorities[i] == GNUTLS_KX_ECDHE_PSK) &&
     146             :                             dhpsk_pos == MAX_POS) {
     147        1066 :                         dhpsk_pos = i;
     148             :                 }
     149             : 
     150        9873 :                 if (dhpsk_pos != MAX_POS && psk_pos != MAX_POS)
     151             :                         break;
     152             :         }
     153             : 
     154        2359 :         if (psk_pos == MAX_POS && dhpsk_pos == MAX_POS) {
     155         325 :                 if (!(session->internals.flags & GNUTLS_NO_TICKETS))
     156             :                         dhpsk_pos = 0;
     157           0 :                 else if (session->internals.priorities->groups.size == 0)
     158           0 :                         return gnutls_assert_val(0);
     159             :         }
     160             : 
     161        4718 :         for (i=0;i<ke_modes_len;i++) {
     162        3279 :                 DECR_LEN(len, 1);
     163        3279 :                 if (data[i] == PSK_DHE_KE)
     164        1387 :                         cli_dhpsk_pos = i;
     165        1892 :                 else if (data[i] == PSK_KE)
     166        1892 :                         cli_psk_pos = i;
     167             : 
     168        3279 :                 _gnutls_handshake_log("EXT[%p]: PSK KE mode %.2x received\n",
     169             :                                       session, (unsigned)data[i]);
     170        3279 :                 if (cli_psk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS)
     171             :                         break;
     172             :         }
     173             : 
     174        2359 :         if (session->internals.priorities->server_precedence) {
     175         130 :                 if (dhpsk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS && dhpsk_pos < psk_pos)
     176           0 :                         session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
     177         130 :                 else if (psk_pos != MAX_POS && cli_psk_pos != MAX_POS && psk_pos < dhpsk_pos)
     178         130 :                         session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
     179             :         } else {
     180        2229 :                 if (dhpsk_pos != MAX_POS && cli_dhpsk_pos != MAX_POS && cli_dhpsk_pos < cli_psk_pos)
     181         927 :                         session->internals.hsk_flags |= HSK_PSK_KE_MODE_DHE_PSK;
     182        1302 :                 else if (psk_pos != MAX_POS && cli_psk_pos != MAX_POS && cli_psk_pos < cli_dhpsk_pos)
     183        1299 :                         session->internals.hsk_flags |= HSK_PSK_KE_MODE_PSK;
     184             :         }
     185             : 
     186        2359 :         if ((session->internals.hsk_flags & HSK_PSK_KE_MODE_PSK) ||
     187             :             (session->internals.hsk_flags & HSK_PSK_KE_MODE_DHE_PSK)) {
     188             : 
     189             :                 return 0;
     190             :         } else {
     191           3 :                 session->internals.hsk_flags |= HSK_PSK_KE_MODE_INVALID;
     192           4 :                 return gnutls_assert_val(0);
     193             :         }
     194             : }
     195             : 
     196             : const hello_ext_entry_st ext_mod_psk_ke_modes = {
     197             :         .name = "PSK Key Exchange Modes",
     198             :         .tls_id = 45,
     199             :         .gid = GNUTLS_EXTENSION_PSK_KE_MODES,
     200             :         .client_parse_point = GNUTLS_EXT_TLS,
     201             :         .server_parse_point = GNUTLS_EXT_TLS,
     202             :         .validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO,
     203             :         .send_func = psk_ke_modes_send_params,
     204             :         .recv_func = psk_ke_modes_recv_params
     205             : };

Generated by: LCOV version 1.14