Add psktool to @direntry. Alphasort @direntry.
[gnutls.git] / lib / gnutls_srp.c
blob84eb1fd151e2618e40b1023d781ee7eb590c79b7
1 /*
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008 Free Software Foundation
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GNUTLS.
8 * The GNUTLS library 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.
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.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21 * USA
25 #include <gnutls_int.h>
26 #include <gnutls_errors.h>
27 #include <auth_srp.h>
28 #include <gnutls_state.h>
30 #ifdef ENABLE_SRP
32 #include <gnutls_srp.h>
33 #include <auth_srp_passwd.h>
34 #include <gnutls_mpi.h>
35 #include <gnutls_num.h>
36 #include <gnutls_helper.h>
38 #include "debug.h"
41 /* Here functions for SRP (like g^x mod n) are defined
44 int
45 _gnutls_srp_gx (opaque * text, size_t textsize, opaque ** result,
46 mpi_t g, mpi_t prime, gnutls_alloc_function galloc_func)
48 mpi_t x, e;
49 size_t result_size;
51 if (_gnutls_mpi_scan_nz (&x, text, &textsize))
53 gnutls_assert ();
54 return GNUTLS_E_MPI_SCAN_FAILED;
57 e = _gnutls_mpi_alloc_like (prime);
58 if (e == NULL)
60 gnutls_assert ();
61 _gnutls_mpi_release (&x);
62 return GNUTLS_E_MEMORY_ERROR;
65 /* e = g^x mod prime (n) */
66 _gnutls_mpi_powm (e, g, x, prime);
67 _gnutls_mpi_release (&x);
69 _gnutls_mpi_print (NULL, &result_size, e);
70 if (result != NULL)
72 *result = galloc_func (result_size);
73 if ((*result) == NULL)
74 return GNUTLS_E_MEMORY_ERROR;
76 _gnutls_mpi_print (*result, &result_size, e);
79 _gnutls_mpi_release (&e);
81 return result_size;
86 /****************
87 * Choose a random value b and calculate B = (k* v + g^b) % N.
88 * where k == SHA1(N|g)
89 * Return: B and if ret_b is not NULL b.
91 mpi_t
92 _gnutls_calc_srp_B (mpi_t * ret_b, mpi_t g, mpi_t n, mpi_t v)
94 mpi_t tmpB = NULL, tmpV = NULL;
95 mpi_t b = NULL, B = NULL, k = NULL;
96 int bits;
99 /* calculate: B = (k*v + g^b) % N
101 bits = _gnutls_mpi_get_nbits (n);
102 b = _gnutls_mpi_snew (bits);
103 if (b == NULL)
105 gnutls_assert ();
106 return NULL;
109 tmpV = _gnutls_mpi_alloc_like (n);
111 if (tmpV == NULL)
113 gnutls_assert ();
114 goto error;
117 _gnutls_mpi_randomize (b, bits, GCRY_STRONG_RANDOM);
119 tmpB = _gnutls_mpi_snew (bits);
120 if (tmpB == NULL)
122 gnutls_assert ();
123 goto error;
126 B = _gnutls_mpi_snew (bits);
127 if (B == NULL)
129 gnutls_assert ();
130 goto error;
133 k = _gnutls_calc_srp_u (n, g, n);
134 if (k == NULL)
136 gnutls_assert ();
137 goto error;
140 _gnutls_mpi_mulm (tmpV, k, v, n);
141 _gnutls_mpi_powm (tmpB, g, b, n);
143 _gnutls_mpi_addm (B, tmpV, tmpB, n);
145 _gnutls_mpi_release (&k);
146 _gnutls_mpi_release (&tmpB);
147 _gnutls_mpi_release (&tmpV);
149 if (ret_b)
150 *ret_b = b;
151 else
152 _gnutls_mpi_release (&b);
154 return B;
156 error:
157 _gnutls_mpi_release (&b);
158 _gnutls_mpi_release (&B);
159 _gnutls_mpi_release (&k);
160 _gnutls_mpi_release (&tmpB);
161 _gnutls_mpi_release (&tmpV);
162 return NULL;
166 /* This calculates the SHA1(A | B)
167 * A and B will be left-padded with zeros to fill n_size.
169 mpi_t
170 _gnutls_calc_srp_u (mpi_t A, mpi_t B, mpi_t n)
172 size_t b_size, a_size;
173 opaque *holder, hd[MAX_HASH_SIZE];
174 size_t holder_size, hash_size, n_size;
175 digest_hd_st td;
176 int ret;
177 mpi_t res;
179 /* get the size of n in bytes */
180 _gnutls_mpi_print (NULL, &n_size, n);
182 _gnutls_mpi_print (NULL, &a_size, A);
183 _gnutls_mpi_print (NULL, &b_size, B);
185 if (a_size > n_size || b_size > n_size)
187 gnutls_assert ();
188 return NULL; /* internal error */
191 holder_size = n_size + n_size;
193 holder = gnutls_calloc (1, holder_size);
194 if (holder == NULL)
195 return NULL;
197 _gnutls_mpi_print (&holder[n_size - a_size], &a_size, A);
198 _gnutls_mpi_print (&holder[n_size + n_size - b_size], &b_size, B);
200 ret = _gnutls_hash_init (&td, GNUTLS_MAC_SHA1);
201 if (ret < 0)
203 gnutls_free (holder);
204 gnutls_assert ();
205 return NULL;
207 _gnutls_hash (&td, holder, holder_size);
208 _gnutls_hash_deinit (&td, hd);
210 /* convert the bytes of hd to integer
212 hash_size = 20; /* SHA */
213 ret = _gnutls_mpi_scan_nz (&res, hd, &hash_size);
214 gnutls_free (holder);
216 if (ret < 0)
218 gnutls_assert ();
219 return NULL;
222 return res;
225 /* S = (A * v^u) ^ b % N
226 * this is our shared key (server premaster secret)
228 mpi_t
229 _gnutls_calc_srp_S1 (mpi_t A, mpi_t b, mpi_t u, mpi_t v, mpi_t n)
231 mpi_t tmp1 = NULL, tmp2 = NULL;
232 mpi_t S = NULL;
234 S = _gnutls_mpi_alloc_like (n);
235 if (S == NULL)
236 return NULL;
238 tmp1 = _gnutls_mpi_alloc_like (n);
239 tmp2 = _gnutls_mpi_alloc_like (n);
241 if (tmp1 == NULL || tmp2 == NULL)
242 goto freeall;
244 _gnutls_mpi_powm (tmp1, v, u, n);
245 _gnutls_mpi_mulm (tmp2, A, tmp1, n);
246 _gnutls_mpi_powm (S, tmp2, b, n);
248 _gnutls_mpi_release (&tmp1);
249 _gnutls_mpi_release (&tmp2);
251 return S;
253 freeall:
254 _gnutls_mpi_release (&tmp1);
255 _gnutls_mpi_release (&tmp2);
256 return NULL;
259 /* A = g^a % N
260 * returns A and a (which is random)
262 mpi_t
263 _gnutls_calc_srp_A (mpi_t * a, mpi_t g, mpi_t n)
265 mpi_t tmpa;
266 mpi_t A;
267 int bits;
269 bits = _gnutls_mpi_get_nbits (n);
270 tmpa = _gnutls_mpi_snew (bits);
271 if (tmpa == NULL)
273 gnutls_assert ();
274 return NULL;
277 _gnutls_mpi_randomize (tmpa, bits, GCRY_STRONG_RANDOM);
279 A = _gnutls_mpi_snew (bits);
280 if (A == NULL)
282 gnutls_assert ();
283 _gnutls_mpi_release (&tmpa);
284 return NULL;
286 _gnutls_mpi_powm (A, g, tmpa, n);
288 if (a != NULL)
289 *a = tmpa;
290 else
291 _gnutls_mpi_release (&tmpa);
293 return A;
296 /* generate x = SHA(s | SHA(U | ":" | p))
297 * The output is exactly 20 bytes
300 _gnutls_calc_srp_sha (const char *username, const char *password,
301 opaque * salt, int salt_size, size_t * size,
302 void *digest)
304 digest_hd_st td;
305 opaque res[MAX_HASH_SIZE];
306 int ret;
308 *size = 20;
310 ret = _gnutls_hash_init (&td, GNUTLS_MAC_SHA1);
311 if (ret < 0)
313 return GNUTLS_E_MEMORY_ERROR;
315 _gnutls_hash (&td, username, strlen (username));
316 _gnutls_hash (&td, ":", 1);
317 _gnutls_hash (&td, password, strlen (password));
319 _gnutls_hash_deinit (&td, res);
321 ret = _gnutls_hash_init (&td, GNUTLS_MAC_SHA1);
322 if (ret < 0)
324 return GNUTLS_E_MEMORY_ERROR;
327 _gnutls_hash (&td, salt, salt_size);
328 _gnutls_hash (&td, res, 20); /* 20 bytes is the output of sha1 */
330 _gnutls_hash_deinit (&td, digest);
332 return 0;
336 _gnutls_calc_srp_x (char *username, char *password, opaque * salt,
337 size_t salt_size, size_t * size, void *digest)
340 return _gnutls_calc_srp_sha (username, password, salt,
341 salt_size, size, digest);
345 /* S = (B - k*g^x) ^ (a + u * x) % N
346 * this is our shared key (client premaster secret)
348 mpi_t
349 _gnutls_calc_srp_S2 (mpi_t B, mpi_t g, mpi_t x, mpi_t a, mpi_t u, mpi_t n)
351 mpi_t S = NULL, tmp1 = NULL, tmp2 = NULL;
352 mpi_t tmp4 = NULL, tmp3 = NULL, k = NULL;
354 S = _gnutls_mpi_alloc_like (n);
355 if (S == NULL)
356 return NULL;
358 tmp1 = _gnutls_mpi_alloc_like (n);
359 tmp2 = _gnutls_mpi_alloc_like (n);
360 tmp3 = _gnutls_mpi_alloc_like (n);
361 if (tmp1 == NULL || tmp2 == NULL || tmp3 == NULL)
363 goto freeall;
366 k = _gnutls_calc_srp_u (n, g, n);
367 if (k == NULL)
369 gnutls_assert ();
370 goto freeall;
373 _gnutls_mpi_powm (tmp1, g, x, n); /* g^x */
374 _gnutls_mpi_mulm (tmp3, tmp1, k, n); /* k*g^x mod n */
375 _gnutls_mpi_subm (tmp2, B, tmp3, n);
377 tmp4 = _gnutls_mpi_alloc_like (n);
378 if (tmp4 == NULL)
379 goto freeall;
381 _gnutls_mpi_mul (tmp1, u, x);
382 _gnutls_mpi_add (tmp4, a, tmp1);
383 _gnutls_mpi_powm (S, tmp2, tmp4, n);
385 _gnutls_mpi_release (&tmp1);
386 _gnutls_mpi_release (&tmp2);
387 _gnutls_mpi_release (&tmp3);
388 _gnutls_mpi_release (&tmp4);
389 _gnutls_mpi_release (&k);
391 return S;
393 freeall:
394 _gnutls_mpi_release (&k);
395 _gnutls_mpi_release (&tmp1);
396 _gnutls_mpi_release (&tmp2);
397 _gnutls_mpi_release (&tmp3);
398 _gnutls_mpi_release (&tmp4);
399 _gnutls_mpi_release (&S);
400 return NULL;
404 * gnutls_srp_free_client_credentials - Used to free an allocated gnutls_srp_client_credentials_t structure
405 * @sc: is an #gnutls_srp_client_credentials_t structure.
407 * This structure is complex enough to manipulate directly thus
408 * this helper function is provided in order to free (deallocate) it.
411 void
412 gnutls_srp_free_client_credentials (gnutls_srp_client_credentials_t sc)
414 gnutls_free (sc->username);
415 gnutls_free (sc->password);
416 gnutls_free (sc);
420 * gnutls_srp_allocate_client_credentials - Used to allocate an gnutls_srp_server_credentials_t structure
421 * @sc: is a pointer to an #gnutls_srp_server_credentials_t structure.
423 * This structure is complex enough to manipulate directly thus
424 * this helper function is provided in order to allocate it.
426 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
427 * error code.
430 gnutls_srp_allocate_client_credentials (gnutls_srp_client_credentials_t * sc)
432 *sc = gnutls_calloc (1, sizeof (srp_client_credentials_st));
434 if (*sc == NULL)
435 return GNUTLS_E_MEMORY_ERROR;
437 return 0;
441 * gnutls_srp_set_client_credentials - Used to set the username/password, in a gnutls_srp_client_credentials_t structure
442 * @res: is an #gnutls_srp_client_credentials_t structure.
443 * @username: is the user's userid
444 * @password: is the user's password
446 * This function sets the username and password, in a
447 * #gnutls_srp_client_credentials_t structure. Those will be used in
448 * SRP authentication. @username and @password should be ASCII
449 * strings or UTF-8 strings prepared using the "SASLprep" profile of
450 * "stringprep".
452 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
453 * error code.
456 gnutls_srp_set_client_credentials (gnutls_srp_client_credentials_t res,
457 const char *username, const char *password)
460 if (username == NULL || password == NULL)
462 gnutls_assert ();
463 return GNUTLS_E_INVALID_REQUEST;
466 res->username = gnutls_strdup (username);
467 if (res->username == NULL)
468 return GNUTLS_E_MEMORY_ERROR;
470 res->password = gnutls_strdup (password);
471 if (res->password == NULL)
473 gnutls_free (res->username);
474 return GNUTLS_E_MEMORY_ERROR;
477 return 0;
481 * gnutls_srp_free_server_credentials - Used to free an allocated gnutls_srp_server_credentials_t structure
482 * @sc: is an #gnutls_srp_server_credentials_t structure.
484 * This structure is complex enough to manipulate directly thus
485 * this helper function is provided in order to free (deallocate) it.
488 void
489 gnutls_srp_free_server_credentials (gnutls_srp_server_credentials_t sc)
491 gnutls_free (sc->password_file);
492 gnutls_free (sc->password_conf_file);
494 gnutls_free (sc);
498 * gnutls_srp_allocate_server_credentials - Used to allocate an gnutls_srp_server_credentials_t structure
499 * @sc: is a pointer to an #gnutls_srp_server_credentials_t structure.
501 * This structure is complex enough to manipulate directly thus this
502 * helper function is provided in order to allocate it.
504 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
505 * error code.
508 gnutls_srp_allocate_server_credentials (gnutls_srp_server_credentials_t * sc)
510 *sc = gnutls_calloc (1, sizeof (srp_server_cred_st));
512 if (*sc == NULL)
513 return GNUTLS_E_MEMORY_ERROR;
515 return 0;
519 * gnutls_srp_set_server_credentials_file - Used to set the password files, in a gnutls_srp_server_credentials_t structure
520 * @res: is an #gnutls_srp_server_credentials_t structure.
521 * @password_file: is the SRP password file (tpasswd)
522 * @password_conf_file: is the SRP password conf file (tpasswd.conf)
524 * This function sets the password files, in a
525 * #gnutls_srp_server_credentials_t structure. Those password files
526 * hold usernames and verifiers and will be used for SRP
527 * authentication.
529 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
530 * error code.
533 gnutls_srp_set_server_credentials_file (gnutls_srp_server_credentials_t
534 res, const char *password_file,
535 const char *password_conf_file)
538 if (password_file == NULL || password_conf_file == NULL)
540 gnutls_assert ();
541 return GNUTLS_E_INVALID_REQUEST;
544 /* Check if the files can be opened */
545 if (_gnutls_file_exists (password_file) != 0)
547 gnutls_assert ();
548 return GNUTLS_E_FILE_ERROR;
551 if (_gnutls_file_exists (password_conf_file) != 0)
553 gnutls_assert ();
554 return GNUTLS_E_FILE_ERROR;
557 res->password_file = gnutls_strdup (password_file);
558 if (res->password_file == NULL)
560 gnutls_assert ();
561 return GNUTLS_E_MEMORY_ERROR;
564 res->password_conf_file = gnutls_strdup (password_conf_file);
565 if (res->password_conf_file == NULL)
567 gnutls_assert ();
568 gnutls_free (res->password_file);
569 res->password_file = NULL;
570 return GNUTLS_E_MEMORY_ERROR;
573 return 0;
578 * gnutls_srp_set_server_credentials_function - Used to set a callback to retrieve the user's SRP credentials
579 * @cred: is a #gnutls_srp_server_credentials_t structure.
580 * @func: is the callback function
582 * This function can be used to set a callback to retrieve the user's SRP credentials.
583 * The callback's function form is:
584 * int (*callback)(gnutls_session_t, const char* username,
585 * gnutls_datum_t* salt, gnutls_datum_t *verifier, gnutls_datum_t* g,
586 * gnutls_datum_t* n);
588 * @username contains the actual username.
589 * The @salt, @verifier, @generator and @prime must be filled
590 * in using the gnutls_malloc(). For convenience @prime and @generator
591 * may also be one of the static parameters defined in extra.h.
593 * In case the callback returned a negative number then gnutls will
594 * assume that the username does not exist.
596 * In order to prevent attackers from guessing valid usernames,
597 * if a user does not exist, g and n values should be filled in
598 * using a random user's parameters. In that case the callback must
599 * return the special value (1).
601 * The callback function will only be called once per handshake.
602 * The callback function should return 0 on success, while
603 * -1 indicates an error.
606 void
607 gnutls_srp_set_server_credentials_function (gnutls_srp_server_credentials_t
608 cred,
609 gnutls_srp_server_credentials_function
610 * func)
612 cred->pwd_callback = func;
616 * gnutls_srp_set_client_credentials_function - Used to set a callback to retrieve the username and password
617 * @cred: is a #gnutls_srp_server_credentials_t structure.
618 * @func: is the callback function
620 * This function can be used to set a callback to retrieve the username and
621 * password for client SRP authentication.
623 * The callback's function form is:
625 * int (*callback)(gnutls_session_t, char** username, char**password);
627 * The @username and @password must be allocated using
628 * gnutls_malloc(). @username and @password should be ASCII strings
629 * or UTF-8 strings prepared using the "SASLprep" profile of
630 * "stringprep".
632 * The callback function will be called once per handshake before the
633 * initial hello message is sent.
635 * The callback should not return a negative error code the second
636 * time called, since the handshake procedure will be aborted.
638 * The callback function should return 0 on success.
639 * -1 indicates an error.
641 void
642 gnutls_srp_set_client_credentials_function (gnutls_srp_client_credentials_t cred,
643 gnutls_srp_client_credentials_function * func)
645 cred->get_function = func;
650 * gnutls_srp_server_get_username - return the username of the peer
651 * @session: is a gnutls session
653 * This function will return the username of the peer. This should
654 * only be called in case of SRP authentication and in case of a
655 * server. Returns NULL in case of an error.
657 * Returns: SRP username of the peer, or NULL in case of error.
659 const char *
660 gnutls_srp_server_get_username (gnutls_session_t session)
662 srp_server_auth_info_t info;
664 CHECK_AUTH (GNUTLS_CRD_SRP, NULL);
666 info = _gnutls_get_auth_info (session);
667 if (info == NULL)
668 return NULL;
669 return info->username;
673 * gnutls_srp_verifier - Used to calculate an SRP verifier
674 * @username: is the user's name
675 * @password: is the user's password
676 * @salt: should be some randomly generated bytes
677 * @generator: is the generator of the group
678 * @prime: is the group's prime
679 * @res: where the verifier will be stored.
681 * This function will create an SRP verifier, as specified in
682 * RFC2945. The @prime and @generator should be one of the static
683 * parameters defined in gnutls/extra.h or may be generated using the
684 * libgcrypt functions gcry_prime_generate() and
685 * gcry_prime_group_generator().
687 * The verifier will be allocated with @malloc and will be stored in
688 * @res using binary format.
690 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
691 * error code.
694 gnutls_srp_verifier (const char *username, const char *password,
695 const gnutls_datum_t * salt,
696 const gnutls_datum_t * generator,
697 const gnutls_datum_t * prime, gnutls_datum_t * res)
699 mpi_t _n, _g;
700 int ret;
701 size_t digest_size = 20, size;
702 opaque digest[20];
704 ret = _gnutls_calc_srp_sha (username, password, salt->data,
705 salt->size, &digest_size, digest);
706 if (ret < 0)
708 gnutls_assert ();
709 return ret;
712 size = prime->size;
713 if (_gnutls_mpi_scan_nz (&_n, prime->data, &size))
715 gnutls_assert ();
716 return GNUTLS_E_MPI_SCAN_FAILED;
719 size = generator->size;
720 if (_gnutls_mpi_scan_nz (&_g, generator->data, &size))
722 gnutls_assert ();
723 return GNUTLS_E_MPI_SCAN_FAILED;
726 ret = _gnutls_srp_gx (digest, 20, &res->data, _g, _n, malloc);
727 if (ret < 0)
729 gnutls_assert ();
730 return ret;
732 res->size = ret;
734 return 0;
737 #endif /* ENABLE_SRP */