LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib - extv.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 112 115 97.4 %
Date: 2020-10-30 04:50:48 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2017-2018 Red Hat, Inc.
       3             :  *
       4             :  * Author: Nikos Mavrogiannopoulos
       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 "hello_ext.h"
      25             : #include "errors.h"
      26             : #include "extv.h"
      27             : 
      28             : /* Iterates through all extensions found, and calls the cb()
      29             :  * function with their data */
      30      102339 : int _gnutls_extv_parse(void *ctx,
      31             :                        gnutls_ext_raw_process_func cb,
      32             :                        const uint8_t * data, int data_size)
      33             : {
      34      102339 :         int next, ret;
      35      102339 :         int pos = 0;
      36      102339 :         uint16_t tls_id;
      37      102339 :         const uint8_t *sdata;
      38      102339 :         uint16_t size;
      39             : 
      40      102339 :         if (data_size == 0)
      41             :                 return 0;
      42             : 
      43       93817 :         DECR_LENGTH_RET(data_size, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
      44       93809 :         next = _gnutls_read_uint16(data);
      45       93809 :         pos += 2;
      46             : 
      47       93809 :         DECR_LENGTH_RET(data_size, next, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
      48             : 
      49       93524 :         if (next == 0 && data_size == 0) /* field is present, but has zero length? Ignore it. */
      50             :                 return 0;
      51       92284 :         else if (data_size > 0) /* forbid unaccounted data */
      52         119 :                 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
      53             : 
      54     1400200 :         do {
      55     1400200 :                 DECR_LENGTH_RET(next, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
      56     1400190 :                 tls_id = _gnutls_read_uint16(&data[pos]);
      57     1400190 :                 pos += 2;
      58             : 
      59     1400190 :                 DECR_LENGTH_RET(next, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
      60     1400180 :                 size = _gnutls_read_uint16(&data[pos]);
      61     1400180 :                 pos += 2;
      62             : 
      63     1400180 :                 DECR_LENGTH_RET(next, size, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
      64     1400100 :                 sdata = &data[pos];
      65     1400100 :                 pos += size;
      66             : 
      67     1400100 :                 ret = cb(ctx, tls_id, sdata, size);
      68     1400100 :                 if (ret < 0)
      69        2417 :                         return gnutls_assert_val(ret);
      70             :         }
      71     1398200 :         while (next > 2);
      72             : 
      73             :         /* forbid leftovers */
      74       90211 :         if (next > 0)
      75          21 :                 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
      76             : 
      77             :         return 0;
      78             : }
      79             : 
      80             : #define HANDSHAKE_SESSION_ID_POS (34)
      81             : /**
      82             :  * gnutls_ext_raw_parse:
      83             :  * @ctx: a pointer to pass to callback function
      84             :  * @cb: callback function to process each extension found
      85             :  * @data: TLS extension data
      86             :  * @flags: should be zero or %GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO or %GNUTLS_EXT_RAW_FLAG_DTLS_CLIENT_HELLO
      87             :  *
      88             :  * This function iterates through the TLS extensions as passed in
      89             :  * @data, passing the individual extension data to callback. The
      90             :  * @data must conform to Extension extensions<0..2^16-1> format.
      91             :  *
      92             :  * If flags is %GNUTLS_EXT_RAW_TLS_FLAG_CLIENT_HELLO then this function
      93             :  * will parse the extension data from the position, as if the packet in
      94             :  * @data is a client hello (without record or handshake headers) -
      95             :  * as provided by gnutls_handshake_set_hook_function().
      96             :  *
      97             :  * The return value of the callback will be propagated.
      98             :  *
      99             :  * Returns: %GNUTLS_E_SUCCESS on success, or an error code. On unknown
     100             :  *   flags it returns %GNUTLS_E_INVALID_REQUEST.
     101             :  *
     102             :  * Since: 3.6.3
     103             :  **/
     104         163 : int gnutls_ext_raw_parse(void *ctx, gnutls_ext_raw_process_func cb,
     105             :                          const gnutls_datum_t *data, unsigned int flags)
     106             : {
     107         163 :         if (flags & GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO) {
     108          44 :                 size_t size = data->size;
     109          44 :                 size_t len;
     110          44 :                 uint8_t *p = data->data;
     111             : 
     112          44 :                 DECR_LEN(size, HANDSHAKE_SESSION_ID_POS);
     113             : 
     114          41 :                 if (p[0] != 0x03)
     115          20 :                         return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
     116             : 
     117          21 :                 p += HANDSHAKE_SESSION_ID_POS;
     118             : 
     119             :                 /* skip session id */
     120          21 :                 DECR_LEN(size, 1);
     121          20 :                 len = p[0];
     122          20 :                 p++;
     123          20 :                 DECR_LEN(size, len);
     124          19 :                 p += len;
     125             : 
     126             :                 /* CipherSuites */
     127          19 :                 DECR_LEN(size, 2);
     128          18 :                 len = _gnutls_read_uint16(p);
     129          18 :                 p += 2;
     130          18 :                 DECR_LEN(size, len);
     131          16 :                 p += len;
     132             : 
     133             :                 /* legacy_compression_methods */
     134          16 :                 DECR_LEN(size, 1);
     135          15 :                 len = p[0];
     136          15 :                 p++;
     137          15 :                 DECR_LEN(size, len);
     138          14 :                 p += len;
     139             : 
     140          14 :                 if (size == 0)
     141           1 :                         return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
     142             : 
     143          13 :                 return _gnutls_extv_parse(ctx, cb, p, size);
     144         119 :         } else if (flags & GNUTLS_EXT_RAW_FLAG_DTLS_CLIENT_HELLO) {
     145          41 :                 size_t size = data->size;
     146          41 :                 size_t len;
     147          41 :                 uint8_t *p = data->data;
     148             : 
     149          41 :                 DECR_LEN(size, HANDSHAKE_SESSION_ID_POS);
     150             : 
     151          38 :                 if (p[0] != 254)
     152          20 :                         return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
     153             : 
     154          18 :                 p += HANDSHAKE_SESSION_ID_POS;
     155             : 
     156             :                 /* skip session id */
     157          18 :                 DECR_LEN(size, 1);
     158          17 :                 len = p[0];
     159          17 :                 p++;
     160          17 :                 DECR_LEN(size, len);
     161          16 :                 p += len;
     162             : 
     163             :                 /* skip cookie */
     164          16 :                 DECR_LEN(size, 1);
     165          15 :                 len = p[0];
     166          15 :                 p++;
     167          15 :                 DECR_LEN(size, len);
     168          14 :                 p += len;
     169             : 
     170             :                 /* CipherSuites */
     171          14 :                 DECR_LEN(size, 2);
     172          13 :                 len = _gnutls_read_uint16(p);
     173          13 :                 p += 2;
     174          13 :                 DECR_LEN(size, len);
     175          12 :                 p += len;
     176             : 
     177             :                 /* legacy_compression_methods */
     178          12 :                 DECR_LEN(size, 1);
     179          11 :                 len = p[0];
     180          11 :                 p++;
     181          11 :                 DECR_LEN(size, len);
     182          10 :                 p += len;
     183             : 
     184          10 :                 if (size == 0)
     185           1 :                         return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
     186             : 
     187           9 :                 return _gnutls_extv_parse(ctx, cb, p, size);
     188             :         }
     189             : 
     190          78 :         if (flags != 0)
     191           0 :                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
     192             : 
     193          78 :         return _gnutls_extv_parse(ctx, cb, data->data, data->size);
     194             : }
     195             : 
     196             : /* Returns:
     197             :  *  * On success the number of bytes appended (always positive), or zero if not sent
     198             :  *  * On failure, a negative error code.
     199             :  */
     200      635770 : int _gnutls_extv_append(gnutls_buffer_st *buf,
     201             :                         uint16_t tls_id,
     202             :                         void *ctx,
     203             :                         int (*cb)(void *ctx, gnutls_buffer_st *buf))
     204             : {
     205      635770 :         int size_pos, appended, ret;
     206      635770 :         size_t size_prev;
     207             : 
     208      635770 :         ret = _gnutls_buffer_append_prefix(buf, 16, tls_id);
     209      635770 :         if (ret < 0)
     210           0 :                 return gnutls_assert_val(ret);
     211             : 
     212      635770 :         size_pos = buf->length;
     213      635770 :         ret = _gnutls_buffer_append_prefix(buf, 16, 0);
     214      635770 :         if (ret < 0)
     215           0 :                 return gnutls_assert_val(ret);
     216             : 
     217      635770 :         size_prev = buf->length;
     218      635770 :         ret = cb(ctx, buf);
     219      635770 :         if (ret < 0 && ret != GNUTLS_E_INT_RET_0) {
     220         162 :                 return gnutls_assert_val(ret);
     221             :         }
     222             : 
     223             :         /* returning GNUTLS_E_INT_RET_0 means to send an empty
     224             :          * extension of this type.
     225             :          */
     226      635614 :         appended = buf->length - size_prev;
     227             : 
     228      635614 :         if (appended > 0 || ret == GNUTLS_E_INT_RET_0) {
     229       75495 :                 if (ret == GNUTLS_E_INT_RET_0)
     230       17283 :                         appended = 0;
     231             : 
     232             :                 /* write the real size */
     233      150990 :                 _gnutls_write_uint16(appended,
     234       75495 :                                      &buf->data[size_pos]);
     235      560119 :         } else if (appended == 0) {
     236      560119 :                 buf->length -= 4;    /* reset type and size */
     237      560119 :                 return 0;
     238             :         }
     239             : 
     240       75495 :         return appended + 4;
     241             : }
     242             : 

Generated by: LCOV version 1.14