LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib/auth - rsa_psk.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 139 179 77.7 %
Date: 2020-10-30 04:50:48 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2009, 2010
       3             :  * Free Software Foundation, Inc.
       4             :  *
       5             :  * Copyright (C) 2011
       6             :  * Bardenheuer GmbH, Munich and Bundesdruckerei GmbH, Berlin
       7             :  *
       8             :  * Copyright (C) 2013 Frank Morgner
       9             :  * Copyright (C) 2013 Nikos Mavrogiannopoulos
      10             :  *
      11             :  * This file is part of GnuTLS.
      12             :  *
      13             :  * The GnuTLS is free software; you can redistribute it and/or
      14             :  * modify it under the terms of the GNU Lesser General Public License
      15             :  * as published by the Free Software Foundation; either version 2.1 of
      16             :  * the License, or (at your option) any later version.
      17             :  *
      18             :  * This library is distributed in the hope that it will be useful, but
      19             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      20             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      21             :  * Lesser General Public License for more details.
      22             :  *
      23             :  * You should have received a copy of the GNU Lesser General Public
      24             :  * License along with this library; if not, write to the Free Software
      25             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
      26             :  * USA
      27             :  *
      28             :  */
      29             : 
      30             : #include "gnutls_int.h"
      31             : 
      32             : #ifdef ENABLE_PSK
      33             : 
      34             : #include "auth.h"
      35             : #include "dh.h"
      36             : #include "errors.h"
      37             : #include "mpi.h"
      38             : #include "num.h"
      39             : #include "gnutls_int.h"
      40             : #include "pk.h"
      41             : #include "random.h"
      42             : #include <abstract_int.h>
      43             : #include <algorithms.h>
      44             : #include <auth/dh_common.h>
      45             : #include <auth/psk.h>
      46             : #include <auth/psk_passwd.h>
      47             : #include <auth/rsa_common.h>
      48             : #include <cert.h>
      49             : #include <datum.h>
      50             : #include <state.h>
      51             : 
      52             : static int _gnutls_gen_rsa_psk_client_kx(gnutls_session_t session,
      53             :                                          gnutls_buffer_st * data);
      54             : static int _gnutls_proc_rsa_psk_client_kx(gnutls_session_t, uint8_t *,
      55             :                                           size_t);
      56             : static int
      57             : _gnutls_proc_rsa_psk_server_kx(gnutls_session_t session, uint8_t * data,
      58             :                            size_t _data_size);
      59             : 
      60             : const mod_auth_st rsa_psk_auth_struct = {
      61             :         "RSA PSK",
      62             :         _gnutls_gen_cert_server_crt,
      63             :         NULL,                   /* generate_client_certificate */
      64             :         _gnutls_gen_psk_server_kx,
      65             :         _gnutls_gen_rsa_psk_client_kx,
      66             :         NULL,                   /* generate_client_cert_vrfy */
      67             :         NULL,                   /* generate_server_certificate_request */
      68             :         _gnutls_proc_crt,
      69             :         NULL,                   /* process_client_certificate */
      70             :         _gnutls_proc_rsa_psk_server_kx,
      71             :         _gnutls_proc_rsa_psk_client_kx,
      72             :         NULL,                   /* process_client_cert_vrfy */
      73             :         NULL                    /* process_server_certificate_reuqest */
      74             : };
      75             : 
      76             : /* Set the PSK premaster secret.
      77             :  */
      78             : static int
      79          33 : set_rsa_psk_session_key(gnutls_session_t session,
      80             :                         gnutls_datum_t * ppsk, gnutls_datum_t * rsa_secret)
      81             : {
      82          33 :         unsigned char *p;
      83          33 :         size_t rsa_secret_size;
      84          33 :         int ret;
      85             : 
      86             : 
      87          33 :         rsa_secret_size = rsa_secret->size;
      88             : 
      89             :         /* set the session key
      90             :          */
      91          33 :         session->key.key.size = 2 + rsa_secret_size + 2 + ppsk->size;
      92          33 :         session->key.key.data = gnutls_malloc(session->key.key.size);
      93          33 :         if (session->key.key.data == NULL) {
      94           0 :                 gnutls_assert();
      95           0 :                 ret = GNUTLS_E_MEMORY_ERROR;
      96           0 :                 goto error;
      97             :         }
      98             : 
      99             :         /* format of the premaster secret:
     100             :          * (uint16_t) other_secret size (48)
     101             :          * other_secret: 2 byte version + 46 byte random
     102             :          * (uint16_t) psk_size
     103             :          * the psk
     104             :          */
     105          33 :         _gnutls_write_uint16(rsa_secret_size, session->key.key.data);
     106          33 :         memcpy(&session->key.key.data[2], rsa_secret->data,
     107          33 :                rsa_secret->size);
     108          33 :         p = &session->key.key.data[rsa_secret_size + 2];
     109          33 :         _gnutls_write_uint16(ppsk->size, p);
     110          33 :         if (ppsk->data != NULL)
     111          33 :                 memcpy(p + 2, ppsk->data, ppsk->size);
     112             : 
     113             :         ret = 0;
     114             : 
     115          33 :       error:
     116          33 :         return ret;
     117             : }
     118             : 
     119             : /* Generate client key exchange message
     120             :  *
     121             :  *
     122             :  * struct {
     123             :  *    select (KeyExchangeAlgorithm) {
     124             :  *       uint8_t psk_identity<0..2^16-1>;
     125             :  *       EncryptedPreMasterSecret;
     126             :  *    } exchange_keys;
     127             :  * } ClientKeyExchange;
     128             :  */
     129             : static int
     130          10 : _gnutls_gen_rsa_psk_client_kx(gnutls_session_t session,
     131             :                               gnutls_buffer_st * data)
     132             : {
     133          10 :         cert_auth_info_t auth = session->key.auth_info;
     134          10 :         gnutls_datum_t sdata;   /* data to send */
     135          10 :         gnutls_pk_params_st params;
     136          10 :         gnutls_psk_client_credentials_t cred;
     137          10 :         gnutls_datum_t username, key;
     138          10 :         int ret, free;
     139          10 :         unsigned init_pos;
     140             : 
     141          10 :         if (auth == NULL) {
     142             :                 /* this shouldn't have happened. The proc_certificate
     143             :                  * function should have detected that.
     144             :                  */
     145           0 :                 gnutls_assert();
     146           0 :                 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     147             :         }
     148             : 
     149          10 :         gnutls_datum_t premaster_secret;
     150          10 :         premaster_secret.size = GNUTLS_MASTER_SIZE;
     151          20 :         premaster_secret.data =
     152          10 :             gnutls_malloc(premaster_secret.size);
     153             : 
     154          10 :         if (premaster_secret.data == NULL) {
     155           0 :                 gnutls_assert();
     156           0 :                 return GNUTLS_E_MEMORY_ERROR;
     157             :         }
     158             : 
     159             :         /* Generate random */
     160          20 :         ret = gnutls_rnd(GNUTLS_RND_RANDOM, premaster_secret.data,
     161          10 :                           premaster_secret.size);
     162          10 :         if (ret < 0) {
     163           0 :                 gnutls_assert();
     164           0 :                 return ret;
     165             :         }
     166             : 
     167             :         /* Set version */
     168          10 :         if (session->internals.rsa_pms_version[0] == 0) {
     169          10 :                 premaster_secret.data[0] =
     170          10 :                     _gnutls_get_adv_version_major(session);
     171          10 :                 premaster_secret.data[1] =
     172          10 :                     _gnutls_get_adv_version_minor(session);
     173             :         } else {                /* use the version provided */
     174           0 :                 premaster_secret.data[0] =
     175             :                     session->internals.rsa_pms_version[0];
     176           0 :                 premaster_secret.data[1] =
     177           0 :                     session->internals.rsa_pms_version[1];
     178             :         }
     179             : 
     180             :         /* move RSA parameters to key (session).
     181             :          */
     182          10 :         if ((ret = _gnutls_get_public_rsa_params(session, &params)) < 0) {
     183           0 :                 gnutls_assert();
     184           0 :                 return ret;
     185             :         }
     186             : 
     187             :         /* Encrypt premaster secret */
     188          20 :         if ((ret =
     189          10 :              _gnutls_pk_encrypt(GNUTLS_PK_RSA, &sdata, &premaster_secret,
     190             :                                 &params)) < 0) {
     191           0 :                 gnutls_assert();
     192           0 :                 return ret;
     193             :         }
     194             : 
     195          10 :         gnutls_pk_params_release(&params);
     196             : 
     197          10 :         cred = (gnutls_psk_client_credentials_t)
     198          10 :             _gnutls_get_cred(session, GNUTLS_CRD_PSK);
     199             : 
     200          10 :         if (cred == NULL) {
     201           0 :                 gnutls_assert();
     202           0 :                 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     203             :         }
     204             : 
     205          10 :         ret = _gnutls_find_psk_key(session, cred, &username, &key, &free);
     206          10 :         if (ret < 0)
     207           0 :                 return gnutls_assert_val(ret);
     208             : 
     209             :         /* Here we set the PSK key */
     210          10 :         ret = set_rsa_psk_session_key(session, &key, &premaster_secret);
     211          10 :         if (ret < 0) {
     212           0 :                 gnutls_assert();
     213           0 :                 goto cleanup;
     214             :         }
     215             : 
     216             :         /* Create message for client key exchange
     217             :          *
     218             :          * struct {
     219             :          *   uint8_t psk_identity<0..2^16-1>;
     220             :          *   EncryptedPreMasterSecret;
     221             :          * }
     222             :          */
     223             : 
     224          10 :         init_pos = data->length;
     225             : 
     226             :         /* Write psk_identity and EncryptedPreMasterSecret into data stream
     227             :          */
     228          10 :         ret =
     229          20 :             _gnutls_buffer_append_data_prefix(data, 16,
     230          10 :                                               username.data,
     231          10 :                                               username.size);
     232          10 :         if (ret < 0) {
     233           0 :                 gnutls_assert();
     234           0 :                 goto cleanup;
     235             :         }
     236             : 
     237          10 :         ret =
     238          20 :             _gnutls_buffer_append_data_prefix(data, 16, sdata.data,
     239          10 :                                               sdata.size);
     240          10 :         if (ret < 0) {
     241           0 :                 gnutls_assert();
     242           0 :                 goto cleanup;
     243             :         }
     244             : 
     245          10 :         ret = data->length - init_pos;
     246             : 
     247          10 :       cleanup:
     248          10 :         _gnutls_free_datum(&sdata);
     249          10 :         _gnutls_free_temp_key_datum(&premaster_secret);
     250          10 :         if (free) {
     251           1 :                 _gnutls_free_temp_key_datum(&key);
     252           1 :                 gnutls_free(username.data);
     253             :         }
     254             : 
     255             :         return ret;
     256             : }
     257             : 
     258             : /*
     259             :   Process the client key exchange message
     260             : */
     261             : static int
     262          28 : _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
     263             :                                size_t _data_size)
     264             : {
     265          28 :         gnutls_datum_t username;
     266          28 :         psk_auth_info_t info;
     267          28 :         gnutls_datum_t plaintext;
     268          28 :         gnutls_datum_t ciphertext;
     269          28 :         gnutls_datum_t pwd_psk = { NULL, 0 };
     270          28 :         int ret, dsize;
     271          28 :         int randomize_key = 0;
     272          28 :         ssize_t data_size = _data_size;
     273          28 :         gnutls_psk_server_credentials_t cred;
     274          28 :         gnutls_datum_t premaster_secret = { NULL, 0 };
     275             : 
     276          28 :         cred = (gnutls_psk_server_credentials_t)
     277          28 :             _gnutls_get_cred(session, GNUTLS_CRD_PSK);
     278             : 
     279          28 :         if (cred == NULL) {
     280           0 :                 gnutls_assert();
     281           0 :                 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     282             :         }
     283             : 
     284          28 :         ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
     285             :                                     sizeof(psk_auth_info_st), 1);
     286          28 :         if (ret < 0) {
     287           0 :                 gnutls_assert();
     288           0 :                 return ret;
     289             :         }
     290             : 
     291             :   /*** 1. Extract user psk_identity ***/
     292             : 
     293          28 :         DECR_LEN(data_size, 2);
     294          27 :         username.size = _gnutls_read_uint16(&data[0]);
     295             : 
     296          27 :         DECR_LEN(data_size, username.size);
     297             : 
     298          26 :         username.data = &data[2];
     299             : 
     300             :         /* copy the username to the auth info structures
     301             :          */
     302          26 :         info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
     303          26 :         if (info == NULL) {
     304           0 :                 gnutls_assert();
     305           0 :                 return GNUTLS_E_INTERNAL_ERROR;
     306             :         }
     307             : 
     308          26 :         if (username.size > MAX_USERNAME_SIZE) {
     309           1 :                 gnutls_assert();
     310           1 :                 return GNUTLS_E_ILLEGAL_SRP_USERNAME;
     311             :         }
     312             : 
     313          25 :         _gnutls_copy_psk_username(info, &username);
     314             : 
     315             :         /* Adjust data so it points to EncryptedPreMasterSecret */
     316          25 :         data += username.size + 2;
     317             : 
     318             :   /*** 2. Decrypt and extract EncryptedPreMasterSecret ***/
     319             : 
     320          25 :         DECR_LEN(data_size, 2);
     321          24 :         ciphertext.data = &data[2];
     322          24 :         dsize = _gnutls_read_uint16(data);
     323             : 
     324          24 :         if (dsize != data_size) {
     325           1 :                 gnutls_assert();
     326           1 :                 return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
     327             :         }
     328          23 :         ciphertext.size = dsize;
     329             : 
     330          23 :         ret =
     331          23 :             gnutls_privkey_decrypt_data(session->internals.selected_key, 0,
     332             :                                         &ciphertext, &plaintext);
     333          23 :         if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE) {
     334             :                 /* In case decryption fails then don't inform
     335             :                  * the peer. Just use a random key. (in order to avoid
     336             :                  * attack against pkcs-1 formatting).
     337             :                  */
     338           6 :                 gnutls_assert();
     339           6 :                 _gnutls_debug_log
     340             :                     ("auth_rsa_psk: Possible PKCS #1 format attack\n");
     341           6 :                 if (ret >= 0) {
     342           1 :                         gnutls_free(plaintext.data);
     343             :                 }
     344           6 :                 randomize_key = 1;
     345             :         } else {
     346             :                 /* If the secret was properly formatted, then
     347             :                  * check the version number.
     348             :                  */
     349          17 :                 if (_gnutls_get_adv_version_major(session) !=
     350          17 :                     plaintext.data[0]
     351          16 :                     || (session->internals.allow_wrong_pms == 0
     352          14 :                         && _gnutls_get_adv_version_minor(session) !=
     353          14 :                         plaintext.data[1])) {
     354             :                         /* No error is returned here, if the version number check
     355             :                          * fails. We proceed normally.
     356             :                          * That is to defend against the attack described in the paper
     357             :                          * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima,
     358             :                          * Ondej Pokorny and Tomas Rosa.
     359             :                          */
     360           1 :                         gnutls_assert();
     361           1 :                         _gnutls_debug_log
     362             :                             ("auth_rsa: Possible PKCS #1 version check format attack\n");
     363             :                 }
     364             :         }
     365             : 
     366             : 
     367           0 :         if (randomize_key != 0) {
     368           6 :                 premaster_secret.size = GNUTLS_MASTER_SIZE;
     369          12 :                 premaster_secret.data =
     370           6 :                     gnutls_malloc(premaster_secret.size);
     371           6 :                 if (premaster_secret.data == NULL) {
     372           0 :                         gnutls_assert();
     373           0 :                         return GNUTLS_E_MEMORY_ERROR;
     374             :                 }
     375             : 
     376             :                 /* we do not need strong random numbers here.
     377             :                  */
     378          12 :                 ret = gnutls_rnd(GNUTLS_RND_NONCE, premaster_secret.data,
     379           6 :                                   premaster_secret.size);
     380           6 :                 if (ret < 0) {
     381           0 :                         gnutls_assert();
     382           0 :                         goto cleanup;
     383             :                 }
     384             :         } else {
     385          17 :                 premaster_secret.data = plaintext.data;
     386          17 :                 premaster_secret.size = plaintext.size;
     387             :         }
     388             : 
     389             :         /* This is here to avoid the version check attack
     390             :          * discussed above.
     391             :          */
     392             : 
     393          23 :         premaster_secret.data[0] = _gnutls_get_adv_version_major(session);
     394          23 :         premaster_secret.data[1] = _gnutls_get_adv_version_minor(session);
     395             : 
     396             :         /* find the key of this username
     397             :          */
     398          23 :         ret =
     399          23 :             _gnutls_psk_pwd_find_entry(session, info->username, strlen(info->username), &pwd_psk);
     400          23 :         if (ret < 0) {
     401           0 :                 gnutls_assert();
     402           0 :                 goto cleanup;
     403             :         }
     404             : 
     405          23 :         ret =
     406          23 :             set_rsa_psk_session_key(session, &pwd_psk, &premaster_secret);
     407          23 :         if (ret < 0) {
     408           0 :                 gnutls_assert();
     409           0 :                 goto cleanup;
     410             :         }
     411             : 
     412             :         ret = 0;
     413          23 :       cleanup:
     414          23 :         _gnutls_free_key_datum(&pwd_psk);
     415          23 :         _gnutls_free_temp_key_datum(&premaster_secret);
     416             : 
     417          23 :         return ret;
     418             : }
     419             : 
     420             : static int
     421          10 : _gnutls_proc_rsa_psk_server_kx(gnutls_session_t session, uint8_t * data,
     422             :                            size_t _data_size)
     423             : {
     424             :         /* In RSA-PSK the key is calculated elsewhere.
     425             :          * Moreover, since we only keep a single auth info structure, we cannot
     426             :          * store the hint (as we store certificate auth info).
     427             :          * Ideally we need to handle that by multiple auth info
     428             :          * structures or something similar.
     429             :          */
     430             : 
     431          10 :         return 0;
     432             : }
     433             : 
     434             : #endif                          /* ENABLE_PSK */

Generated by: LCOV version 1.14