LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib/ext - server_cert_type.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 78 95 82.1 %
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) 2016 - 2018 ARPA2 project
       3             :  *
       4             :  * Author: Tom Vrancken (dev@tomvrancken.nl)
       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             :  * This file is part of the server_certificate_type extension as
      22             :  * defined in RFC7250 (https://tools.ietf.org/html/rfc7250).
      23             :  *
      24             :  * The server_certificate_type extension in the client hello indicates
      25             :  * the types of certificates the client is able to process when provided
      26             :  * by the server in a subsequent certificate payload.
      27             :  */
      28             : 
      29             : #include <gnutls_int.h>
      30             : #include <gnutls/gnutls.h>
      31             : #include "ext/cert_types.h"
      32             : #include "ext/server_cert_type.h"
      33             : #include "hello_ext.h"
      34             : #include "hello_ext_lib.h"
      35             : #include "errors.h"
      36             : #include "state.h"
      37             : #include "datum.h"
      38             : 
      39             : 
      40             : static int _gnutls_server_cert_type_recv_params(gnutls_session_t session,
      41             :                                                 const uint8_t* data,
      42             :                                                 size_t data_size);
      43             : static int _gnutls_server_cert_type_send_params(gnutls_session_t session,
      44             :                                                 gnutls_buffer_st* data);
      45             : 
      46             : 
      47             : const hello_ext_entry_st ext_mod_server_cert_type = {
      48             :         .name = "Server Certificate Type",
      49             :         .tls_id = 20,
      50             :         .gid = GNUTLS_EXTENSION_SERVER_CERT_TYPE,
      51             :         .client_parse_point = GNUTLS_EXT_TLS,
      52             :         .server_parse_point = GNUTLS_EXT_TLS,
      53             :         .validity = GNUTLS_EXT_FLAG_TLS |
      54             :                 GNUTLS_EXT_FLAG_DTLS |
      55             :                 GNUTLS_EXT_FLAG_CLIENT_HELLO |
      56             :                 GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO |
      57             :                 GNUTLS_EXT_FLAG_EE,
      58             :         .recv_func = _gnutls_server_cert_type_recv_params,
      59             :         .send_func = _gnutls_server_cert_type_send_params,
      60             :         .pack_func = _gnutls_hello_ext_default_pack,
      61             :         .unpack_func = _gnutls_hello_ext_default_unpack,
      62             :         .deinit_func = _gnutls_hello_ext_default_deinit,
      63             :         .cannot_be_overriden = 1
      64             : };
      65             : 
      66             : 
      67          72 : static int _gnutls_server_cert_type_recv_params(gnutls_session_t session,
      68             :                                                 const uint8_t* data,
      69             :                                                 size_t data_size)
      70             : {
      71          72 :         int ret;
      72          72 :         gnutls_datum_t cert_types; // Holds the received cert types
      73          72 :         gnutls_datum_t sent_cert_types; // Holds the previously sent cert types
      74          72 :         gnutls_certificate_type_t cert_type;
      75             : 
      76          72 :         uint8_t i, found = 0;
      77          72 :         const uint8_t* pdata = data;
      78             : 
      79             :         /* Only activate this extension if we have cert credentials set
      80             :          * and alternative cert types are allowed */
      81         144 :         if (!are_alternative_cert_types_allowed(session) ||
      82          72 :                 (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL))
      83           0 :                 return 0;
      84             : 
      85          72 :         if (!IS_SERVER(session)) {      // client mode
      86             : 
      87             :                 /* Compare packet length with expected packet length. For the
      88             :                  * client this is a single byte. */
      89          35 :                 if (data_size != 1) {
      90           0 :                         return
      91           0 :                                         gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
      92             :                 }
      93             : 
      94             :                 /* The server picked one of the offered cert types if he supports
      95             :                  * at least one of them. If both parties play by the rules then we
      96             :                  * may only receive a cert type that we offered, i.e. one that we
      97             :                  * support. Because the world isn't as beautiful as it may seem,
      98             :                  * we're going to check it nevertheless. */
      99          35 :                 cert_type = IANA2cert_type(pdata[0]);
     100             : 
     101             :                 // Check validity of cert type
     102          33 :                 if (cert_type == GNUTLS_CRT_UNKNOWN) {
     103           0 :                         return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE);
     104             :                 }
     105             : 
     106             :                 /* Get the cert types that we sent to the server (they were stored
     107             :                  * in IANA representation.
     108             :                  */
     109          35 :                 ret = _gnutls_hello_ext_get_datum(session,
     110             :                                                          GNUTLS_EXTENSION_SERVER_CERT_TYPE,
     111             :                                                          &sent_cert_types);
     112          35 :                 if (ret < 0) {
     113             :                         /* This should not happen and indicate a memory corruption!
     114             :                          * Assertion are always on in production code so execution
     115             :                          * will halt here. */
     116           0 :                         assert(false);
     117             :                 }
     118             : 
     119             :                 // Check whether what we got back is actually offered by us
     120         102 :                 for (i = 0; i < sent_cert_types.size; i++) {
     121         102 :                         if (IANA2cert_type(sent_cert_types.data[i]) == cert_type)
     122          35 :                                 found = 1;
     123             :                 }
     124             : 
     125          35 :                 if (found) {
     126             :                         // Everything OK, now set the server certificate type
     127          35 :                         _gnutls_session_server_cert_type_set(session, cert_type);
     128          35 :                         ret = GNUTLS_E_SUCCESS;
     129             :                 } else {
     130             :                         // No valid cert type found
     131             :                         ret = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
     132             :                 }
     133             : 
     134          35 :                 return ret;
     135             : 
     136             :         } else {                // server mode
     137             :                 // Compare packet length with expected packet length.
     138          37 :                 DECR_LEN(data_size, 1);
     139          37 :                 if (data[0] != data_size) {
     140           0 :                         return
     141           0 :                                         gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     142             :                 }
     143          37 :                 pdata += 1;
     144             : 
     145             :                 // Assign the contents of our data buffer to a gnutls_datum_t
     146          37 :                 cert_types.data = (uint8_t*)pdata; // Need casting to get rid of 'discards const qualifier' warning
     147          37 :                 cert_types.size = data_size;
     148             : 
     149             :                 // Store the server certificate types in our session
     150          37 :                 _gnutls_hello_ext_set_datum(session,
     151             :                                                          GNUTLS_EXTENSION_SERVER_CERT_TYPE,
     152             :                                                          &cert_types);
     153             : 
     154             :                 /* We receive a list of supported certificate types that the client
     155             :                  * is able to process when offered by the server via a subsequent
     156             :                  * Certificate message. This list is sorted by order of preference.
     157             :                  * We now check in this order of preference whether we support any
     158             :                  * of these certificate types.
     159             :                  */
     160         105 :                 for (i = 0; i < cert_types.size; i++) {
     161             :                         // Convert to internal representation
     162          68 :                         cert_type = IANA2cert_type(cert_types.data[i]);
     163             : 
     164             :                         // If we have an invalid cert id then continue to the next
     165          33 :                         if (cert_type == GNUTLS_CRT_UNKNOWN)
     166           0 :                                 continue;
     167             : 
     168             :                         // Check for support of this cert type
     169          68 :                         if (_gnutls_session_cert_type_supported
     170             :                                         (session, cert_type, true, GNUTLS_CTYPE_SERVER) == 0) {
     171             :                                 found = 1;
     172             :                                 break;
     173             :                         }
     174             :                 }
     175             : 
     176             :                 // We found a matching ctype, we pick this one
     177          37 :                 if (found) {
     178          37 :                         _gnutls_session_server_cert_type_set(session, cert_type);
     179          37 :                         ret = GNUTLS_E_SUCCESS;
     180             :                 } else {
     181             :                         /* If no supported certificate type can be found we terminate
     182             :                          * with a fatal alert of type "unsupported_certificate"
     183             :                          * (according to specification rfc7250).
     184             :                          */
     185             :                         ret = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
     186             :                 }
     187             : 
     188          37 :                 return ret;
     189             :         }
     190             : }
     191             : 
     192        3823 : static int _gnutls_server_cert_type_send_params(gnutls_session_t session,
     193             :                                                 gnutls_buffer_st* data)
     194             : {
     195        3823 :         int ret;
     196        3823 :         uint8_t cert_type; // Holds an IANA cert type ID
     197        3823 :         uint8_t i = 0, num_cert_types = 0;
     198        3823 :         priority_st* cert_priorities;
     199        3823 :         gnutls_datum_t tmp_cert_types; // For type conversion
     200        3823 :         uint8_t cert_types[GNUTLS_CRT_MAX]; // The list with supported cert types. Inv: 0 <= cert type Id < 256
     201             : 
     202             :         /* Only activate this extension if we have cert credentials set
     203             :          * and alternative cert types are allowed */
     204        4317 :         if (!are_alternative_cert_types_allowed(session) ||
     205         494 :                 (_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE) == NULL))
     206        3329 :                 return 0;
     207             : 
     208         494 :         if (!IS_SERVER(session)) {      // Client mode
     209             :                 // For brevity
     210         458 :                 cert_priorities =
     211         458 :                                 &session->internals.priorities->server_ctype;
     212             : 
     213             :                 /* Retrieve server certificate type priorities if any. If no
     214             :                  * priorities are set then the default server certificate type
     215             :                  * initialization values apply. This default is currently set to
     216             :                  * X.509 in which case we don't enable this extension.
     217             :                  */
     218         458 :                 if (cert_priorities->num_priorities > 0) {        // Priorities are explicitly set
     219             :                         /* If the certificate priority is explicitly set to only
     220             :                          * X.509 (default) then, according to spec we don't send
     221             :                          * this extension. We check this here to avoid further work in
     222             :                          * this routine. We also check it below after pruning supported
     223             :                          * types.
     224             :                          */
     225         365 :                         if (cert_priorities->num_priorities == 1 &&
     226         331 :                                         cert_priorities->priorities[0] == DEFAULT_CERT_TYPE) {
     227         327 :                                 _gnutls_handshake_log
     228             :                                                 ("EXT[%p]: Server certificate type was set to default cert type (%s). "
     229             :                                                  "We therefore do not send this extension.\n",
     230             :                                                  session,
     231             :                                                  gnutls_certificate_type_get_name(DEFAULT_CERT_TYPE));
     232             : 
     233             :                                 // Explicitly set but default ctype, so don't send anything
     234         327 :                                 return 0;
     235             :                         }
     236             : 
     237             :                         /* We are only allowed to send certificate types that we support.
     238             :                          * Therefore we check this here and prune our original list.
     239             :                          * This check might seem redundant now because we don't check for
     240             :                          * credentials (they are not needed for a client) and only check the
     241             :                          * priorities over which we already iterate. In the future,
     242             :                          * additional checks might be necessary and they can be easily
     243             :                          * added in the ..type_supported() routine without modifying the
     244             :                          * structure of the code here.
     245             :                          */
     246         110 :                         for (i = 0; i < cert_priorities->num_priorities; i++) {
     247          72 :                                 if (_gnutls_session_cert_type_supported
     248          72 :                                                 (session, cert_priorities->priorities[i],
     249             :                                                  false, GNUTLS_CTYPE_SERVER) == 0) {
     250             :                                         /* Check whether we are allowed to store another cert type
     251             :                                          * in our buffer. In other words, prevent a possible buffer
     252             :                                          * overflow. This situation can occur when a user sets
     253             :                                          * duplicate cert types in the priority strings. */
     254          72 :                                         if (num_cert_types >= GNUTLS_CRT_MAX)
     255           0 :                                                 return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
     256             : 
     257             :                                         // Convert to IANA representation
     258          72 :                                         ret = cert_type2IANA(cert_priorities->priorities[i]);
     259             : 
     260          38 :                                         if (ret < 0)
     261           0 :                                                 return gnutls_assert_val(ret);
     262             : 
     263          72 :                                         cert_type = ret; // For readability
     264             : 
     265             :                                         // Add this cert type to our list with supported types
     266          72 :                                         cert_types[num_cert_types] = cert_type;
     267          72 :                                         num_cert_types++;
     268             : 
     269          72 :                                         _gnutls_handshake_log
     270             :                                                         ("EXT[%p]: Server certificate type %s (%d) was queued.\n",
     271             :                                                          session,
     272             :                                                          gnutls_certificate_type_get_name(cert_priorities->priorities[i]),
     273             :                                                          cert_type);
     274             :                                 }
     275             :                         }
     276             : 
     277             :                         /* Check whether there are any supported certificate types left
     278             :                          * after the previous pruning step. If not, we do not send this
     279             :                          * extension. Also, if the only supported type is the default type
     280             :                          * we do not send this extension (according to RFC7250).
     281             :                          */
     282          38 :                         if (num_cert_types == 0) {      // For now, this should not occur since we only check priorities while pruning.
     283           0 :                                 _gnutls_handshake_log
     284             :                                                 ("EXT[%p]: Server certificate types were set but none of them is supported. "
     285             :                                                  "We do not send this extension.\n",
     286             :                                                  session);
     287             : 
     288           0 :                                 return 0;
     289          38 :                         } else if (num_cert_types == 1 &&
     290           4 :                                          IANA2cert_type(cert_types[0]) == DEFAULT_CERT_TYPE) {
     291           0 :                                 _gnutls_handshake_log
     292             :                                                 ("EXT[%p]: The only supported server certificate type is (%s) which is the default. "
     293             :                                                  "We therefore do not send this extension.\n",
     294             :                                                  session,
     295             :                                                  gnutls_certificate_type_get_name(DEFAULT_CERT_TYPE));
     296             : 
     297           0 :                                 return 0;
     298             :                         }
     299             : 
     300             :                         /* We have data to send and store a copy internally. We convert
     301             :                          * our list with supported cert types to a datum_t in order to
     302             :                          * be able to make the ..._set_datum call.
     303             :                          */
     304          38 :                         tmp_cert_types.data = cert_types;
     305          38 :                         tmp_cert_types.size = num_cert_types;
     306             : 
     307          38 :                         _gnutls_hello_ext_set_datum(session,
     308             :                                                                  GNUTLS_EXTENSION_SERVER_CERT_TYPE,
     309             :                                                                  &tmp_cert_types);
     310             : 
     311             :                         /* Serialize the certificate types into a sequence of octets
     312             :                          * uint8: length of sequence of cert types (1 octet)
     313             :                          * uint8: cert types (0 <= #octets <= 255)
     314             :                          */
     315          38 :                         ret = _gnutls_buffer_append_data_prefix(data, 8,
     316             :                                                                 cert_types,
     317             :                                                                 num_cert_types);
     318             : 
     319             :                         // Check for errors and cleanup in case of error
     320          38 :                         if (ret < 0) {
     321           0 :                                 return gnutls_assert_val(ret);
     322             :                         } else {
     323             :                                 // Number of bytes we are sending
     324          38 :                                 return num_cert_types + 1;
     325             :                         }
     326             :                 }
     327             :         } else {        // Server mode
     328             :                 // Retrieve negotiated server certificate type and send it
     329          36 :                 ret = cert_type2IANA(get_certificate_type(
     330             :                                         session, GNUTLS_CTYPE_SERVER));
     331             : 
     332           2 :                 if (ret < 0)
     333           0 :                         return gnutls_assert_val(ret);
     334             : 
     335          36 :                 cert_type = ret; // For readability
     336             : 
     337          36 :                 ret = gnutls_buffer_append_data(data, &cert_type, 1);
     338             : 
     339          36 :                 if (ret < 0)
     340           0 :                         return gnutls_assert_val(ret);
     341             : 
     342             :                 return 1;       // sent one byte
     343             :         }
     344             : 
     345             :         // In all other cases don't enable this extension
     346             :         return 0;
     347             : }
     348             : 
     349             : 
     350             : /** Extension interface **/
     351             : 
     352             : /* The interface is defined in state.c:
     353             :  * Public:
     354             :  * - gnutls_certificate_type_get2
     355             :  *
     356             :  * Private:
     357             :  * - _gnutls_session_server_cert_type_set
     358             :  */

Generated by: LCOV version 1.14