PageRenderTime 60ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/auth/srp_passwd.c

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