LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib/auth - srp_passwd.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 142 240 59.2 %
Date: 2020-10-30 04:50:48 Functions: 5 6 83.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2001-2012 Free Software Foundation, 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             : /* Functions for operating in an SRP passwd file are included here */
      24             : 
      25             : #include "gnutls_int.h"
      26             : 
      27             : #ifdef ENABLE_SRP
      28             : 
      29             : #include "x509_b64.h"
      30             : #include "errors.h"
      31             : #include <auth/srp_passwd.h>
      32             : #include <auth/srp_kx.h>
      33             : #include "auth.h"
      34             : #include "srp.h"
      35             : #include "dh.h"
      36             : #include "debug.h"
      37             : #include <str.h>
      38             : #include <datum.h>
      39             : #include <num.h>
      40             : #include <random.h>
      41             : #include <algorithms.h>
      42             : 
      43             : static int _randomize_pwd_entry(SRP_PWD_ENTRY * entry,
      44             :                                 gnutls_srp_server_credentials_t cred,
      45             :                                 const char * username);
      46             : 
      47             : /* this function parses tpasswd.conf file. Format is:
      48             :  * string(username):base64(v):base64(salt):int(index)
      49             :  */
      50           9 : static int parse_tpasswd_values(SRP_PWD_ENTRY * entry, char *str)
      51             : {
      52           9 :         char *p;
      53           9 :         int len, ret;
      54           9 :         uint8_t *verifier;
      55           9 :         size_t verifier_size;
      56           9 :         int indx;
      57             : 
      58           9 :         p = strrchr(str, ':');  /* we have index */
      59           9 :         if (p == NULL) {
      60           0 :                 gnutls_assert();
      61           0 :                 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
      62             :         }
      63             : 
      64           9 :         *p = '\0';
      65           9 :         p++;
      66             : 
      67           9 :         indx = atoi(p);
      68           9 :         if (indx == 0) {
      69           0 :                 gnutls_assert();
      70           0 :                 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
      71             :         }
      72             : 
      73             :         /* now go for salt */
      74           9 :         p = strrchr(str, ':');  /* we have salt */
      75           9 :         if (p == NULL) {
      76           0 :                 gnutls_assert();
      77           0 :                 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
      78             :         }
      79             : 
      80           9 :         *p = '\0';
      81           9 :         p++;
      82             : 
      83           9 :         len = strlen(p);
      84             : 
      85          18 :         entry->salt.size =
      86           9 :             _gnutls_sbase64_decode(p, len, &entry->salt.data);
      87             : 
      88           9 :         if (entry->salt.size <= 0) {
      89           0 :                 gnutls_assert();
      90           0 :                 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
      91             :         }
      92             : 
      93             :         /* now go for verifier */
      94           9 :         p = strrchr(str, ':');  /* we have verifier */
      95           9 :         if (p == NULL) {
      96           0 :                 _gnutls_free_datum(&entry->salt);
      97           0 :                 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
      98             :         }
      99             : 
     100           9 :         *p = '\0';
     101           9 :         p++;
     102             : 
     103           9 :         len = strlen(p);
     104           9 :         ret = _gnutls_sbase64_decode(p, len, &verifier);
     105           9 :         if (ret <= 0) {
     106           0 :                 gnutls_assert();
     107           0 :                 _gnutls_free_datum(&entry->salt);
     108           0 :                 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
     109             :         }
     110             : 
     111           9 :         verifier_size = ret;
     112           9 :         entry->v.data = verifier;
     113           9 :         entry->v.size = verifier_size;
     114             : 
     115             :         /* now go for username */
     116           9 :         *p = '\0';
     117             : 
     118           9 :         entry->username = gnutls_strdup(str);
     119           9 :         if (entry->username == NULL) {
     120           0 :                 _gnutls_free_datum(&entry->salt);
     121           0 :                 _gnutls_free_key_datum(&entry->v);
     122           0 :                 gnutls_assert();
     123           0 :                 return GNUTLS_E_MEMORY_ERROR;
     124             :         }
     125             : 
     126             :         return indx;
     127             : }
     128             : 
     129             : 
     130             : /* this function parses tpasswd.conf file. Format is:
     131             :  * int(index):base64(n):int(g)
     132             :  */
     133           9 : static int parse_tpasswd_conf_values(SRP_PWD_ENTRY * entry, char *str)
     134             : {
     135           9 :         char *p;
     136           9 :         int len;
     137           9 :         uint8_t *tmp;
     138           9 :         int ret;
     139             : 
     140           9 :         p = strrchr(str, ':');  /* we have g */
     141           9 :         if (p == NULL) {
     142           0 :                 gnutls_assert();
     143           0 :                 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
     144             :         }
     145             : 
     146           9 :         *p = '\0';
     147           9 :         p++;
     148             : 
     149             :         /* read the generator */
     150           9 :         len = strlen(p);
     151           9 :         if (p[len - 1] == '\n' || p[len - 1] == ' ')
     152           9 :                 len--;
     153           9 :         ret = _gnutls_sbase64_decode(p, len, &tmp);
     154             : 
     155           9 :         if (ret < 0) {
     156           0 :                 gnutls_assert();
     157           0 :                 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
     158             :         }
     159             : 
     160           9 :         entry->g.data = tmp;
     161           9 :         entry->g.size = ret;
     162             : 
     163             :         /* now go for n - modulo */
     164           9 :         p = strrchr(str, ':');  /* we have n */
     165           9 :         if (p == NULL) {
     166           0 :                 _gnutls_free_datum(&entry->g);
     167           0 :                 gnutls_assert();
     168           0 :                 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
     169             :         }
     170             : 
     171           9 :         *p = '\0';
     172           9 :         p++;
     173             : 
     174           9 :         len = strlen(p);
     175           9 :         ret = _gnutls_sbase64_decode(p, len, &tmp);
     176             : 
     177           9 :         if (ret < 0) {
     178           0 :                 gnutls_assert();
     179           0 :                 _gnutls_free_datum(&entry->g);
     180           0 :                 return GNUTLS_E_SRP_PWD_PARSING_ERROR;
     181             :         }
     182             : 
     183           9 :         entry->n.data = tmp;
     184           9 :         entry->n.size = ret;
     185             : 
     186           9 :         return 0;
     187             : }
     188             : 
     189             : 
     190             : /* this function opens the tpasswd.conf file and reads the g and n
     191             :  * values. They are put in the entry.
     192             :  */
     193             : static int
     194           9 : pwd_read_conf(const char *pconf_file, SRP_PWD_ENTRY * entry, int idx)
     195             : {
     196           9 :         FILE *fp;
     197           9 :         char *line = NULL;
     198           9 :         size_t line_size = 0;
     199           9 :         unsigned i, len;
     200           9 :         char indexstr[10];
     201           9 :         int ret;
     202             : 
     203           9 :         snprintf(indexstr, sizeof(indexstr), "%u", (unsigned int) idx);
     204             : 
     205           9 :         fp = fopen(pconf_file, "re");
     206           9 :         if (fp == NULL) {
     207           0 :                 gnutls_assert();
     208           0 :                 return GNUTLS_E_FILE_ERROR;
     209             :         }
     210             : 
     211           9 :         len = strlen(indexstr);
     212          24 :         while (getline(&line, &line_size, fp) > 0) {
     213             :                 /* move to first ':' */
     214             :                 i = 0;
     215          48 :                 while ((i < line_size) && (line[i] != ':')
     216          24 :                        && (line[i] != '\0')) {
     217          24 :                         i++;
     218             :                 }
     219             : 
     220          24 :                 if (strncmp(indexstr, line, MAX(i, len)) == 0) {
     221           9 :                         if (parse_tpasswd_conf_values(entry, line) >= 0) {
     222           9 :                                 ret = 0;
     223           9 :                                 goto cleanup;
     224             :                         } else {
     225           0 :                                 ret = GNUTLS_E_SRP_PWD_ERROR;
     226           0 :                                 goto cleanup;
     227             :                         }
     228             :                 }
     229             :         }
     230             :         ret = GNUTLS_E_SRP_PWD_ERROR;
     231             : 
     232           9 : cleanup:
     233           9 :         zeroize_key(line, line_size);
     234           9 :         free(line);
     235           9 :         fclose(fp);
     236           9 :         return ret;
     237             : 
     238             : }
     239             : 
     240             : int
     241         174 : _gnutls_srp_pwd_read_entry(gnutls_session_t state, char *username,
     242             :                            SRP_PWD_ENTRY ** _entry)
     243             : {
     244         174 :         gnutls_srp_server_credentials_t cred;
     245         174 :         FILE *fp = NULL;
     246         174 :         char *line = NULL;
     247         174 :         size_t line_size = 0;
     248         174 :         unsigned i, len;
     249         174 :         int ret;
     250         174 :         int idx;
     251         174 :         SRP_PWD_ENTRY *entry = NULL;
     252             : 
     253         174 :         *_entry = gnutls_calloc(1, sizeof(SRP_PWD_ENTRY));
     254         174 :         if (*_entry == NULL) {
     255           0 :                 gnutls_assert();
     256           0 :                 return GNUTLS_E_MEMORY_ERROR;
     257             :         }
     258         174 :         entry = *_entry;
     259             : 
     260         174 :         cred = (gnutls_srp_server_credentials_t)
     261         174 :             _gnutls_get_cred(state, GNUTLS_CRD_SRP);
     262         174 :         if (cred == NULL) {
     263           0 :                 gnutls_assert();
     264           0 :                 ret = GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     265           0 :                 goto cleanup;
     266             :         }
     267             : 
     268             :         /* if the callback which sends the parameters is
     269             :          * set, use it.
     270             :          */
     271         174 :         if (cred->pwd_callback != NULL) {
     272         165 :                 ret = cred->pwd_callback(state, username, &entry->salt,
     273             :                                          &entry->v, &entry->g, &entry->n);
     274             : 
     275         165 :                 if (ret == 1) { /* the user does not exist */
     276           0 :                         if (entry->g.size != 0 && entry->n.size != 0) {
     277           0 :                                 ret = _randomize_pwd_entry(entry, cred, username);
     278           0 :                                 if (ret < 0) {
     279           0 :                                         gnutls_assert();
     280           0 :                                         goto cleanup;
     281             :                                 }
     282             :                                 return 0;
     283             :                         } else {
     284           0 :                                 gnutls_assert();
     285             :                                 ret = -1;       /* error in the callback */
     286             :                         }
     287             :                 }
     288             : 
     289         165 :                 if (ret < 0) {
     290           0 :                         gnutls_assert();
     291           0 :                         ret = GNUTLS_E_SRP_PWD_ERROR;
     292           0 :                         goto cleanup;
     293             :                 }
     294             : 
     295             :                 return 0;
     296             :         }
     297             : 
     298             :         /* The callback was not set. Proceed.
     299             :          */
     300             : 
     301           9 :         if (cred->password_file == NULL) {
     302           0 :                 gnutls_assert();
     303           0 :                 ret = GNUTLS_E_SRP_PWD_ERROR;
     304           0 :                 goto cleanup;
     305             :         }
     306             : 
     307             :         /* Open the selected password file.
     308             :          */
     309           9 :         fp = fopen(cred->password_file, "re");
     310           9 :         if (fp == NULL) {
     311           0 :                 gnutls_assert();
     312           0 :                 ret = GNUTLS_E_SRP_PWD_ERROR;
     313           0 :                 goto cleanup;
     314             :         }
     315             : 
     316           9 :         len = strlen(username);
     317          24 :         while (getline(&line, &line_size, fp) > 0) {
     318             :                 /* move to first ':' */
     319             :                 i = 0;
     320         135 :                 while ((i < line_size) && (line[i] != '\0')
     321         135 :                        && (line[i] != ':')) {
     322         111 :                         i++;
     323             :                 }
     324             : 
     325          24 :                 if (strncmp(username, line, MAX(i, len)) == 0) {
     326           9 :                         if ((idx = parse_tpasswd_values(entry, line)) >= 0) {
     327             :                                 /* Keep the last index in memory, so we can retrieve fake parameters (g,n)
     328             :                                  * when the user does not exist.
     329             :                                  */
     330           9 :                                 if (pwd_read_conf
     331           9 :                                     (cred->password_conf_file, entry,
     332             :                                      idx) == 0) {
     333           9 :                                         ret = 0;
     334           9 :                                         goto found;
     335             :                                 } else {
     336           0 :                                         gnutls_assert();
     337           0 :                                         ret = GNUTLS_E_SRP_PWD_ERROR;
     338           0 :                                         goto cleanup;
     339             :                                 }
     340             :                         } else {
     341           0 :                                 gnutls_assert();
     342           0 :                                 ret = GNUTLS_E_SRP_PWD_ERROR;
     343           0 :                                 goto cleanup;
     344             :                         }
     345             :                 }
     346             :         }
     347             : 
     348             :         /* user was not found. Fake him. Actually read the g,n values from
     349             :          * the last index found and randomize the entry.
     350             :          */
     351           0 :         if (pwd_read_conf(cred->password_conf_file, entry, 1) == 0) {
     352           0 :                 ret = _randomize_pwd_entry(entry, cred, username);
     353           0 :                 if (ret < 0) {
     354           0 :                         gnutls_assert();
     355           0 :                         goto cleanup;
     356             :                 }
     357             : 
     358           0 :                 ret = 0;
     359           0 :                 goto found;
     360             :         }
     361             : 
     362             :         ret = GNUTLS_E_SRP_PWD_ERROR;
     363             : 
     364           0 : cleanup:
     365           0 :         gnutls_assert();
     366           0 :         _gnutls_srp_entry_free(entry);
     367             : 
     368           9 : found:
     369           9 :         if (line) {
     370           9 :                 zeroize_key(line, line_size);
     371           9 :                 free(line);
     372             :         }
     373           9 :         if (fp)
     374           9 :                 fclose(fp);
     375             :         return ret;
     376             : }
     377             : 
     378             : /* Randomizes the given password entry. It actually sets the verifier
     379             :  * to random data and sets the salt based on fake_salt_seed and
     380             :  * username. Returns 0 on success.
     381             :  */
     382           0 : static int _randomize_pwd_entry(SRP_PWD_ENTRY * entry,
     383             :                                 gnutls_srp_server_credentials_t sc,
     384             :                                 const char * username)
     385             : {
     386           0 :         int ret;
     387           0 :         const mac_entry_st *me = mac_to_entry(SRP_FAKE_SALT_MAC);
     388           0 :         mac_hd_st ctx;
     389           0 :         size_t username_len = strlen(username);
     390             : 
     391           0 :         if (entry->g.size == 0 || entry->n.size == 0) {
     392           0 :                 gnutls_assert();
     393           0 :                 return GNUTLS_E_INTERNAL_ERROR;
     394             :         }
     395             : 
     396           0 :         entry->v.data = gnutls_malloc(20);
     397           0 :         entry->v.size = 20;
     398           0 :         if (entry->v.data == NULL) {
     399           0 :                 gnutls_assert();
     400           0 :                 return GNUTLS_E_MEMORY_ERROR;
     401             :         }
     402             : 
     403           0 :         ret = gnutls_rnd(GNUTLS_RND_NONCE, entry->v.data, 20);
     404           0 :         if (ret < 0) {
     405           0 :                 gnutls_assert();
     406           0 :                 return ret;
     407             :         }
     408             : 
     409             :         /* Always allocate and work with the output size of the MAC,
     410             :          * even if they don't need salts that long, for convenience.
     411             :          *
     412             :          * In case an error occurs 'entry' (and the salt inside)
     413             :          * is deallocated by our caller: _gnutls_srp_pwd_read_entry().
     414             :          */
     415           0 :         entry->salt.data = gnutls_malloc(me->output_size);
     416           0 :         if (entry->salt.data == NULL) {
     417           0 :                 gnutls_assert();
     418           0 :                 return GNUTLS_E_MEMORY_ERROR;
     419             :         }
     420             : 
     421           0 :         ret = _gnutls_mac_init(&ctx, me, sc->fake_salt_seed,
     422           0 :                                sc->fake_salt_seed_size);
     423             : 
     424           0 :         if (ret < 0) {
     425           0 :                 gnutls_assert();
     426           0 :                 return ret;
     427             :         }
     428             : 
     429           0 :         _gnutls_mac(&ctx, "salt", 4);
     430           0 :         _gnutls_mac(&ctx, username, username_len);
     431           0 :         _gnutls_mac_deinit(&ctx, entry->salt.data);
     432             : 
     433             :         /* Set length to the actual number of bytes they asked for.
     434             :          * This is always less than or equal to the output size of
     435             :          * the MAC, enforced by gnutls_srp_set_server_fake_salt_seed().
     436             :          */
     437           0 :         entry->salt.size = sc->fake_salt_length;
     438             : 
     439           0 :         return 0;
     440             : }
     441             : 
     442             : /* Free all the entry parameters, except if g and n are
     443             :  * the static ones defined in gnutls.h
     444             :  */
     445         174 : void _gnutls_srp_entry_free(SRP_PWD_ENTRY * entry)
     446             : {
     447         174 :         _gnutls_free_key_datum(&entry->v);
     448         174 :         _gnutls_free_datum(&entry->salt);
     449             : 
     450         174 :         if ((entry->g.data != gnutls_srp_1024_group_generator.data) &&
     451         174 :             (entry->g.data != gnutls_srp_1536_group_generator.data) &&
     452         174 :             (entry->g.data != gnutls_srp_2048_group_generator.data) &&
     453         174 :             (entry->g.data != gnutls_srp_3072_group_generator.data) &&
     454         174 :             (entry->g.data != gnutls_srp_4096_group_generator.data) &&
     455         174 :             (entry->g.data != gnutls_srp_8192_group_generator.data))
     456         174 :                 _gnutls_free_datum(&entry->g);
     457             : 
     458         174 :         if (entry->n.data != gnutls_srp_1024_group_prime.data &&
     459         174 :             entry->n.data != gnutls_srp_1536_group_prime.data &&
     460         174 :             entry->n.data != gnutls_srp_2048_group_prime.data &&
     461         174 :             entry->n.data != gnutls_srp_3072_group_prime.data &&
     462         174 :             entry->n.data != gnutls_srp_4096_group_prime.data &&
     463         174 :             entry->n.data != gnutls_srp_8192_group_prime.data)
     464         174 :                 _gnutls_free_datum(&entry->n);
     465             : 
     466         174 :         gnutls_free(entry->username);
     467         174 :         gnutls_free(entry);
     468         174 : }
     469             : 
     470             : #endif                          /* ENABLE SRP */

Generated by: LCOV version 1.14