summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2004-07-28 10:28:48 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2004-07-28 10:28:48 +0000
commit131a588a720c2f0d3193bd70e8495eda21f58ad0 (patch)
tree42557fd4736b59c456fbf946ec29ddee38b55727 /lib
parent3875ce124736753d5eaaac4a42b22b51700f8347 (diff)
downloadgnutls-131a588a720c2f0d3193bd70e8495eda21f58ad0.tar.gz
SRP ciphersuites were moved to the gnutls (lgpl) library.
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am8
-rw-r--r--lib/auth_srp.c782
-rw-r--r--lib/auth_srp.h64
-rw-r--r--lib/auth_srp_passwd.c409
-rw-r--r--lib/auth_srp_passwd.h18
-rw-r--r--lib/auth_srp_rsa.c200
-rw-r--r--lib/auth_srp_sb64.c426
-rw-r--r--lib/ext_srp.c152
-rw-r--r--lib/ext_srp.h9
-rw-r--r--lib/gnutls.h.in.in49
-rw-r--r--lib/gnutls_algorithms.c7
-rw-r--r--lib/gnutls_extensions.c6
-rw-r--r--lib/gnutls_srp.c702
-rw-r--r--lib/gnutls_srp.h15
14 files changed, 2844 insertions, 3 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index f4dbe60d71..9882ceb832 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -35,7 +35,8 @@ EXTRA_DIST = debug.h gnutls_compress.h defines.h gnutls.asn pkix.asn \
gnutls_sig.h gnutls_mem.h gnutls_ui.h \
io_debug.h ext_max_record.h gnutls_session_pack.h \
gnutls_alert.h gnutls_str.h gnutls_state.h gnutls_x509.h \
- ext_cert_type.h gnutls_rsa_export.h ext_server_name.h auth_dh_common.h
+ ext_cert_type.h gnutls_rsa_export.h ext_server_name.h auth_dh_common.h \
+ ext_srp.h gnutls_srp.h auth_srp.h auth_srp_passwd.h
lib_LTLIBRARIES = libgnutls.la
X509_COBJECTS = x509/crl.c x509/dn.c x509/common.c x509/x509.c x509/extensions.c \
@@ -44,6 +45,9 @@ X509_COBJECTS = x509/crl.c x509/dn.c x509/common.c x509/x509.c x509/extensions.c
x509/privkey_pkcs8.c x509/pkcs12.c x509/pkcs12_bag.c x509/pkcs12_encr.c \
x509/x509_write.c x509/crl_write.c x509/compat.c
+SRP_COBJECTS = ext_srp.c gnutls_srp.c auth_srp.c auth_srp_passwd.c \
+ auth_srp_sb64.c auth_srp_rsa.c
+
COBJECTS = gnutls_record.c gnutls_compress.c debug.c \
gnutls_cipher.c gnutls_buffers.c gnutls_handshake.c gnutls_num.c \
gnutls_errors.c gnutls_algorithms.c gnutls_dh.c gnutls_kx.c \
@@ -63,7 +67,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c \
# Separate so we can create the documentation
-libgnutls_la_SOURCES = $(COBJECTS) $(X509_COBJECTS) $(MINITASN1_COBJECTS)
+libgnutls_la_SOURCES = $(COBJECTS) $(X509_COBJECTS) $(MINITASN1_COBJECTS) $(SRP_COBJECTS)
libgnutls_la_LDFLAGS = $(LIBTASN1_LIBS) $(LIBGCRYPT_LIBS) \
$(libgnutls_version_script_cmd) \
diff --git a/lib/auth_srp.c b/lib/auth_srp.c
new file mode 100644
index 0000000000..671ec20fa0
--- /dev/null
+++ b/lib/auth_srp.c
@@ -0,0 +1,782 @@
+/*
+ * Copyright (C) 2001,2002,2003 Nikos Mavroyanopoulos
+ * Copyright (C) 2004 Free Software Foundation
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <gnutls_int.h>
+
+#ifdef ENABLE_SRP
+
+#include "gnutls_errors.h"
+#include "auth_srp_passwd.h"
+#include "gnutls_auth.h"
+#include "gnutls_auth_int.h"
+#include "gnutls_srp.h"
+#include "debug.h"
+#include "gnutls_num.h"
+#include "auth_srp.h"
+#include <gnutls_str.h>
+#include <gnutls_datum.h>
+#include <gnutls_alert.h>
+
+int _gnutls_gen_srp_server_kx(gnutls_session_t, opaque **);
+int _gnutls_gen_srp_client_kx(gnutls_session_t, opaque **);
+
+int _gnutls_proc_srp_server_kx(gnutls_session_t, opaque *, size_t);
+int _gnutls_proc_srp_client_kx(gnutls_session_t, opaque *, size_t);
+
+const mod_auth_st srp_auth_struct = {
+ "SRP",
+ NULL,
+ NULL,
+ _gnutls_gen_srp_server_kx,
+ _gnutls_gen_srp_client_kx,
+ NULL,
+ NULL,
+
+ NULL,
+ NULL, /* certificate */
+ _gnutls_proc_srp_server_kx,
+ _gnutls_proc_srp_client_kx,
+ NULL,
+ NULL
+};
+
+
+#define _b session->key->b
+#define B session->key->B
+#define _a session->key->a
+#define A session->key->A
+#define N session->key->client_p
+#define G session->key->client_g
+#define V session->key->x
+#define S session->key->KEY
+
+/* Checks if b%n==0 which is a fatal srp error.
+ * Returns a proper error code in that case, and 0 when
+ * all are ok.
+ */
+inline static int check_b_mod_n(mpi_t b, mpi_t n)
+{
+ int ret;
+ mpi_t r = _gnutls_mpi_alloc_like(b);
+
+ if (r == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ _gnutls_mpi_mod(r, b, n);
+ ret = _gnutls_mpi_cmp_ui(r, 0);
+
+ _gnutls_mpi_release(&r);
+
+ if (ret == 0) {
+ gnutls_assert();
+ return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ }
+
+ return 0;
+}
+
+/* Checks if a%n==0,+1,-1%n which is a fatal srp error.
+ * Returns a proper error code in that case, and 0 when
+ * all are ok.
+ */
+inline static int check_a_mod_n(mpi_t a, mpi_t n)
+{
+ int ret;
+ mpi_t r = _gnutls_mpi_alloc_like(a);
+
+ if (r == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ _gnutls_mpi_mod(r, a, n);
+ ret = _gnutls_mpi_cmp_ui(r, 0);
+
+ _gnutls_mpi_release(&r);
+
+ if (ret == 0) {
+ gnutls_assert();
+ return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ }
+
+ return 0;
+}
+
+
+/* Send the first key exchange message ( g, n, s) and append the verifier algorithm number
+ * Data is allocated by the caller, and should have data_size size.
+ */
+int _gnutls_gen_srp_server_kx(gnutls_session_t session, opaque ** data)
+{
+ int ret;
+ uint8 *data_n, *data_s;
+ uint8 *data_g;
+ char *username;
+ SRP_PWD_ENTRY *pwd_entry;
+ srp_server_auth_info_t info;
+ ssize_t data_size;
+ size_t n_b, tmp_size;
+ char buf[64];
+ uint8 *data_b;
+
+ if ((ret =
+ _gnutls_auth_info_set(session, GNUTLS_CRD_SRP,
+ sizeof(srp_server_auth_info_st), 1)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ info = _gnutls_get_auth_info(session);
+ username = info->username;
+
+ _gnutls_str_cpy(username, MAX_SRP_USERNAME,
+ session->security_parameters.extensions.srp_username);
+
+ ret = _gnutls_srp_pwd_read_entry(session, username, &pwd_entry);
+
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* copy from pwd_entry to local variables (actually in session) */
+ if (_gnutls_mpi_scan(&G, pwd_entry->g.data, &pwd_entry->g.size) < 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ tmp_size = pwd_entry->n.size;
+ if (_gnutls_mpi_scan(&N, pwd_entry->n.data, &tmp_size) < 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ tmp_size = pwd_entry->v.size;
+ if (_gnutls_mpi_scan(&V, pwd_entry->v.data, &tmp_size) < 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ /* Calculate: B = (k*v + g^b) % N
+ */
+ B = _gnutls_calc_srp_B(&_b, G, N, V);
+ if (B == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ if (_gnutls_mpi_print(NULL, &n_b, B) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_PRINT_FAILED;
+ }
+
+
+ /* Allocate size to hold the N, g, s, B
+ */
+
+ data_size = (pwd_entry->n.size + 2 + pwd_entry->g.size + 2 +
+ pwd_entry->salt.size + 1) + (n_b + 2);
+
+ (*data) = gnutls_malloc(data_size);
+ if ((*data) == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ /* copy N (mod n)
+ */
+ data_n = *data;
+ _gnutls_write_datum16(data_n, pwd_entry->n);
+
+
+ /* copy G (generator) to data
+ */
+ data_g = &data_n[2 + pwd_entry->n.size];
+ _gnutls_write_datum16(data_g, pwd_entry->g);
+
+
+ /* copy the salt
+ */
+ data_s = &data_g[2 + pwd_entry->g.size];
+ _gnutls_write_datum8(data_s, pwd_entry->salt);
+
+
+ /* Copy the B value
+ */
+
+ data_b = &data_s[1 + pwd_entry->salt.size];
+ if (_gnutls_mpi_print(&data_b[2], &n_b, B) != 0)
+ return GNUTLS_E_MPI_PRINT_FAILED;
+ _gnutls_write_uint16(n_b, data_b);
+
+ _gnutls_hard_log("INT: SRP B[%d]: %s\n", n_b,
+ _gnutls_bin2hex(&data_b[2], n_b, buf, sizeof(buf)));
+
+ _gnutls_srp_entry_free(pwd_entry);
+
+ return data_size;
+}
+
+/* return A = g^a % N */
+int _gnutls_gen_srp_client_kx(gnutls_session_t session, opaque ** data)
+{
+ size_t n_a;
+ int ret;
+ uint8 *data_a;
+ char *username, *password;
+ size_t n_size = 0;
+ char buf[64];
+ const gnutls_srp_client_credentials_t cred =
+ _gnutls_get_cred(session->key, GNUTLS_CRD_SRP, NULL);
+
+ if (cred == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ if (session->internals.srp_username == NULL) {
+ username = cred->username;
+ password = cred->password;
+ } else {
+ username = session->internals.srp_username;
+ password = session->internals.srp_password;
+ }
+
+ if (username == NULL || password == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ /* calc A = g^a % N
+ */
+ if (G == NULL || N == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ /* get the size of n in bytes */
+ _gnutls_mpi_print( NULL, &n_size, N);
+
+ A = _gnutls_calc_srp_A(&_a, G, N);
+ if (A == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ /* Rest of SRP calculations
+ */
+
+ /* calculate u */
+ session->key->u = _gnutls_calc_srp_u(A, B, n_size);
+ if (session->key->u == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ _gnutls_dump_mpi("SRP U: ", session->key->u);
+
+ /* S = (B - g^x) ^ (a + u * x) % N */
+ S = _gnutls_calc_srp_S2(B, G, session->key->x, _a, session->key->u, N);
+ if (S == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ _gnutls_dump_mpi("SRP B: ", B);
+
+ _gnutls_mpi_release(&_b);
+ _gnutls_mpi_release(&V);
+ _gnutls_mpi_release(&session->key->u);
+ _gnutls_mpi_release(&B);
+
+ ret = _gnutls_generate_session_key(session->key);
+ _gnutls_mpi_release(&S);
+
+ if (ret < 0)
+ return ret;
+
+ if (_gnutls_mpi_print(NULL, &n_a, A) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_PRINT_FAILED;
+ }
+
+ (*data) = gnutls_malloc(n_a + 2);
+ if ((*data) == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ /* copy A */
+ data_a = (*data);
+ if (_gnutls_mpi_print(&data_a[2], &n_a, A) != 0) {
+ gnutls_free(*data);
+ return GNUTLS_E_MPI_PRINT_FAILED;
+ }
+ _gnutls_hard_log("INT: SRP A[%d]: %s\n", n_a,
+ _gnutls_bin2hex(&data_a[2], n_a, buf, sizeof(buf)));
+
+ _gnutls_mpi_release(&A);
+
+ _gnutls_write_uint16(n_a, data_a);
+
+ return n_a + 2;
+}
+
+
+/* just read A and put it to session */
+int _gnutls_proc_srp_client_kx(gnutls_session_t session, opaque * data,
+ size_t _data_size)
+{
+ size_t _n_A;
+ ssize_t data_size = _data_size;
+ int ret;
+ size_t n_size = 0;
+
+ DECR_LEN(data_size, 2);
+ _n_A = _gnutls_read_uint16(&data[0]);
+
+ DECR_LEN(data_size, _n_A);
+ if (_gnutls_mpi_scan(&A, &data[2], &_n_A) || A == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ _gnutls_dump_mpi("SRP A: ", A);
+ _gnutls_dump_mpi("SRP B: ", B);
+
+ /* Checks if A % n == 0.
+ */
+ if ((ret = check_a_mod_n(A, N)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* Start the SRP calculations.
+ * - Calculate u
+ */
+ /* get the size of n in bytes */
+ _gnutls_mpi_print( NULL, &n_size, N);
+
+ session->key->u = _gnutls_calc_srp_u(A, B, n_size);
+ if (session->key->u == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ _gnutls_dump_mpi("SRP U: ", session->key->u);
+
+ /* S = (A * v^u) ^ b % N
+ */
+ S = _gnutls_calc_srp_S1(A, _b, session->key->u, V, N);
+ if (S == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ _gnutls_dump_mpi("SRP S: ", S);
+
+ _gnutls_mpi_release(&A);
+ _gnutls_mpi_release(&_b);
+ _gnutls_mpi_release(&V);
+ _gnutls_mpi_release(&session->key->u);
+ _gnutls_mpi_release(&B);
+
+ ret = _gnutls_generate_session_key(session->key);
+ _gnutls_mpi_release(&S);
+
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return 0;
+}
+
+
+
+/* Static parameters according to draft-ietf-tls-srp-07
+ * Note that if more parameters are added check_g_n()
+ * and _gnutls_srp_entry_free() should be changed.
+ */
+static const unsigned char srp_params_1024[] = {
+ 0xEE, 0xAF, 0x0A, 0xB9, 0xAD, 0xB3, 0x8D, 0xD6,
+ 0x9C, 0x33, 0xF8, 0x0A, 0xFA, 0x8F, 0xC5, 0xE8,
+ 0x60, 0x72, 0x61, 0x87, 0x75, 0xFF, 0x3C, 0x0B,
+ 0x9E, 0xA2, 0x31, 0x4C, 0x9C, 0x25, 0x65, 0x76,
+ 0xD6, 0x74, 0xDF, 0x74, 0x96, 0xEA, 0x81, 0xD3,
+ 0x38, 0x3B, 0x48, 0x13, 0xD6, 0x92, 0xC6, 0xE0,
+ 0xE0, 0xD5, 0xD8, 0xE2, 0x50, 0xB9, 0x8B, 0xE4,
+ 0x8E, 0x49, 0x5C, 0x1D, 0x60, 0x89, 0xDA, 0xD1,
+ 0x5D, 0xC7, 0xD7, 0xB4, 0x61, 0x54, 0xD6, 0xB6,
+ 0xCE, 0x8E, 0xF4, 0xAD, 0x69, 0xB1, 0x5D, 0x49,
+ 0x82, 0x55, 0x9B, 0x29, 0x7B, 0xCF, 0x18, 0x85,
+ 0xC5, 0x29, 0xF5, 0x66, 0x66, 0x0E, 0x57, 0xEC,
+ 0x68, 0xED, 0xBC, 0x3C, 0x05, 0x72, 0x6C, 0xC0,
+ 0x2F, 0xD4, 0xCB, 0xF4, 0x97, 0x6E, 0xAA, 0x9A,
+ 0xFD, 0x51, 0x38, 0xFE, 0x83, 0x76, 0x43, 0x5B,
+ 0x9F, 0xC6, 0x1D, 0x2F, 0xC0, 0xEB, 0x06, 0xE3
+};
+
+static const unsigned char srp_generator = 0x02;
+
+const gnutls_datum_t gnutls_srp_1024_group_prime = {
+ (void *) srp_params_1024, sizeof(srp_params_1024)
+};
+const gnutls_datum_t gnutls_srp_1024_group_generator = {
+ (void *) &srp_generator, sizeof(srp_generator)
+};
+
+static const unsigned char srp_params_1536[] = {
+ 0x9D, 0xEF, 0x3C, 0xAF, 0xB9, 0x39, 0x27, 0x7A, 0xB1,
+ 0xF1, 0x2A, 0x86, 0x17, 0xA4, 0x7B, 0xBB, 0xDB, 0xA5,
+ 0x1D, 0xF4, 0x99, 0xAC, 0x4C, 0x80, 0xBE, 0xEE, 0xA9,
+ 0x61, 0x4B, 0x19, 0xCC, 0x4D, 0x5F, 0x4F, 0x5F, 0x55,
+ 0x6E, 0x27, 0xCB, 0xDE, 0x51, 0xC6, 0xA9, 0x4B, 0xE4,
+ 0x60, 0x7A, 0x29, 0x15, 0x58, 0x90, 0x3B, 0xA0, 0xD0,
+ 0xF8, 0x43, 0x80, 0xB6, 0x55, 0xBB, 0x9A, 0x22, 0xE8,
+ 0xDC, 0xDF, 0x02, 0x8A, 0x7C, 0xEC, 0x67, 0xF0, 0xD0,
+ 0x81, 0x34, 0xB1, 0xC8, 0xB9, 0x79, 0x89, 0x14, 0x9B,
+ 0x60, 0x9E, 0x0B, 0xE3, 0xBA, 0xB6, 0x3D, 0x47, 0x54,
+ 0x83, 0x81, 0xDB, 0xC5, 0xB1, 0xFC, 0x76, 0x4E, 0x3F,
+ 0x4B, 0x53, 0xDD, 0x9D, 0xA1, 0x15, 0x8B, 0xFD, 0x3E,
+ 0x2B, 0x9C, 0x8C, 0xF5, 0x6E, 0xDF, 0x01, 0x95, 0x39,
+ 0x34, 0x96, 0x27, 0xDB, 0x2F, 0xD5, 0x3D, 0x24, 0xB7,
+ 0xC4, 0x86, 0x65, 0x77, 0x2E, 0x43, 0x7D, 0x6C, 0x7F,
+ 0x8C, 0xE4, 0x42, 0x73, 0x4A, 0xF7, 0xCC, 0xB7, 0xAE,
+ 0x83, 0x7C, 0x26, 0x4A, 0xE3, 0xA9, 0xBE, 0xB8, 0x7F,
+ 0x8A, 0x2F, 0xE9, 0xB8, 0xB5, 0x29, 0x2E, 0x5A, 0x02,
+ 0x1F, 0xFF, 0x5E, 0x91, 0x47, 0x9E, 0x8C, 0xE7, 0xA2,
+ 0x8C, 0x24, 0x42, 0xC6, 0xF3, 0x15, 0x18, 0x0F, 0x93,
+ 0x49, 0x9A, 0x23, 0x4D, 0xCF, 0x76, 0xE3, 0xFE, 0xD1,
+ 0x35, 0xF9, 0xBB
+};
+
+const gnutls_datum_t gnutls_srp_1536_group_prime = {
+ (void *) srp_params_1536, sizeof(srp_params_1536)
+};
+const gnutls_datum_t gnutls_srp_1536_group_generator = {
+ (void *) &srp_generator, sizeof(srp_generator)
+};
+
+static const unsigned char srp_params_2048[] = {
+ 0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B, 0xF1,
+ 0x66, 0xDE, 0x5E, 0x13, 0x89, 0x58, 0x2F, 0xAF, 0x72,
+ 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07, 0xFC, 0x31, 0x92,
+ 0x94, 0x3D, 0xB5, 0x60, 0x50, 0xA3, 0x73, 0x29, 0xCB,
+ 0xB4, 0xA0, 0x99, 0xED, 0x81, 0x93, 0xE0, 0x75, 0x77,
+ 0x67, 0xA1, 0x3D, 0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03,
+ 0x31, 0x0D, 0xCD, 0x7F, 0x48, 0xA9, 0xDA, 0x04, 0xFD,
+ 0x50, 0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0,
+ 0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3, 0x66,
+ 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8, 0x29, 0x18,
+ 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8, 0x55, 0xF9, 0x79,
+ 0x93, 0xEC, 0x97, 0x5E, 0xEA, 0xA8, 0x0D, 0x74, 0x0A,
+ 0xDB, 0xF4, 0xFF, 0x74, 0x73, 0x59, 0xD0, 0x41, 0xD5,
+ 0xC3, 0x3E, 0xA7, 0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14,
+ 0x77, 0x3B, 0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80,
+ 0x16, 0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81,
+ 0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A, 0x5B,
+ 0x9D, 0x32, 0xE6, 0x88, 0xF8, 0x77, 0x48, 0x54, 0x45,
+ 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D, 0x5E, 0xA7, 0x7A,
+ 0x27, 0x75, 0xD2, 0xEC, 0xFA, 0x03, 0x2C, 0xFB, 0xDB,
+ 0xF5, 0x2F, 0xB3, 0x78, 0x61, 0x60, 0x27, 0x90, 0x04,
+ 0xE5, 0x7A, 0xE6, 0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE,
+ 0x53, 0x29, 0x9C, 0xCC, 0x04, 0x1C, 0x7B, 0xC3, 0x08,
+ 0xD8, 0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82,
+ 0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6, 0x94,
+ 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4, 0x35, 0xDE,
+ 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75, 0x9B, 0x65, 0xE3,
+ 0x72, 0xFC, 0xD6, 0x8E, 0xF2, 0x0F, 0xA7, 0x11, 0x1F,
+ 0x9E, 0x4A, 0xFF, 0x73
+};
+
+const gnutls_datum_t gnutls_srp_2048_group_prime = {
+ (void *) srp_params_2048, sizeof(srp_params_2048)
+};
+const gnutls_datum_t gnutls_srp_2048_group_generator = {
+ (void *) &srp_generator, sizeof(srp_generator)
+};
+
+
+/* Check if G and N are parameters from the SRP draft.
+ */
+static int check_g_n(const opaque * g, size_t n_g,
+ const opaque * n, size_t n_n)
+{
+
+ if (n_g != 1 || g[0] != srp_generator)
+ return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+
+ if (n_n == sizeof(srp_params_1024) &&
+ memcmp(srp_params_1024, n, n_n) == 0) {
+ return 0;
+ }
+
+ if (n_n == sizeof(srp_params_1536) &&
+ memcmp(srp_params_1536, n, n_n) == 0) {
+ return 0;
+ }
+
+ if (n_n == sizeof(srp_params_2048) &&
+ memcmp(srp_params_2048, n, n_n) == 0) {
+ return 0;
+ }
+
+ return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+}
+
+/* Check if N is a prime and G a generator of the
+ * group.
+ */
+static int group_check_g_n(mpi_t g, mpi_t n)
+{
+ mpi_t q = NULL, two = NULL, w = NULL;
+ int ret;
+
+ /* N must be of the form N=2q+1
+ * where q is also a prime.
+ */
+ if (_gnutls_prime_check(n, 0) != 0) {
+ _gnutls_dump_mpi("no prime N: ", n);
+ gnutls_assert();
+ return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ }
+
+ two = _gnutls_mpi_new(4);
+ if (two == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ q = _gnutls_mpi_alloc_like(n);
+ if (q == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto error;
+ }
+
+ /* q = n-1
+ */
+ _gnutls_mpi_sub_ui(q, n, 1);
+
+ /* q = q/2, remember that q is divisible by 2 (prime - 1)
+ */
+ _gnutls_mpi_set_ui(two, 2);
+ _gnutls_mpi_div(q, NULL, q, two, 0);
+
+ if (_gnutls_prime_check(q, 0) != 0) {
+ /* N was not on the form N=2q+1, where q = prime
+ */
+ _gnutls_dump_mpi("no prime Q: ", q);
+ gnutls_assert();
+ return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ }
+
+ /* We also check whether g is a generator,
+ */
+
+ /* check if g < q < N
+ */
+ if (_gnutls_mpi_cmp(g, q) >= 0) {
+ gnutls_assert();
+ ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ goto error;
+ }
+
+ w = _gnutls_mpi_alloc_like(q);
+ if (w == NULL) {
+ gnutls_assert();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto error;
+ }
+
+ /* check if g^q mod N == N-1
+ * w = g^q mod N
+ */
+ _gnutls_mpi_powm(w, g, q, n);
+
+ /* w++
+ */
+ _gnutls_mpi_add_ui(w, w, 1);
+
+ if (_gnutls_mpi_cmp(w, n) != 0) {
+ gnutls_assert();
+ ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
+ goto error;
+ }
+
+ ret = 0;
+
+ error:
+ _gnutls_mpi_release(&q);
+ _gnutls_mpi_release(&two);
+ _gnutls_mpi_release(&w);
+
+ return ret;
+
+}
+
+/* receive the key exchange message ( n, g, s, B)
+ */
+int _gnutls_proc_srp_server_kx(gnutls_session_t session, opaque * data,
+ size_t _data_size)
+{
+ uint8 n_s;
+ uint16 n_g, n_n, n_b;
+ size_t _n_s, _n_g, _n_n, _n_b;
+ const uint8 *data_n;
+ const uint8 *data_g;
+ const uint8 *data_s;
+ const uint8 *data_b;
+ int i, ret;
+ opaque hd[SRP_MAX_HASH_SIZE];
+ char *username, *password;
+ ssize_t data_size = _data_size;
+
+ const gnutls_srp_client_credentials_t cred =
+ _gnutls_get_cred(session->key, GNUTLS_CRD_SRP, NULL);
+
+ if (cred == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ if (session->internals.srp_username == NULL) {
+ username = cred->username;
+ password = cred->password;
+ } else {
+ username = session->internals.srp_username;
+ password = session->internals.srp_password;
+ }
+
+ if (username == NULL || password == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ i = 0;
+
+ /* Read N
+ */
+ DECR_LEN(data_size, 2);
+ n_n = _gnutls_read_uint16(&data[i]);
+ i += 2;
+
+ DECR_LEN(data_size, n_n);
+ data_n = &data[i];
+ i += n_n;
+
+ /* Read G
+ */
+ DECR_LEN(data_size, 2);
+ n_g = _gnutls_read_uint16(&data[i]);
+ i += 2;
+
+ DECR_LEN(data_size, n_g);
+ data_g = &data[i];
+ i += n_g;
+
+ /* Read salt
+ */
+ DECR_LEN(data_size, 1);
+ n_s = data[i];
+ i += 1;
+
+ DECR_LEN(data_size, n_s);
+ data_s = &data[i];
+ i += n_s;
+
+ /* Read B
+ */
+ DECR_LEN(data_size, 2);
+ n_b = _gnutls_read_uint16(&data[i]);
+ i += 2;
+
+ DECR_LEN(data_size, n_b);
+ data_b = &data[i];
+ i += n_b;
+
+ _n_s = n_s;
+ _n_g = n_g;
+ _n_n = n_n;
+ _n_b = n_b;
+
+ if (_gnutls_mpi_scan(&N, data_n, &_n_n) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ if (_gnutls_mpi_scan(&G, data_g, &_n_g) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ if (_gnutls_mpi_scan(&B, data_b, &_n_b) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+
+ /* Check if the g and n are from the SRP
+ * draft. Otherwise check if N is a prime and G
+ * a generator.
+ */
+ if ((ret = check_g_n(data_g, _n_g, data_n, _n_n)) < 0) {
+ _gnutls_x509_log("Checking the SRP group parameters.\n");
+ if ((ret = group_check_g_n(G, N)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ }
+
+ /* Checks if b % n == 0
+ */
+ if ((ret = check_b_mod_n(B, N)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+
+ /* generate x = SHA(s | SHA(U | ":" | p))
+ * (or the equivalent using bcrypt)
+ */
+ if ((ret =
+ _gnutls_calc_srp_x(username, password, (opaque *) data_s, n_s,
+ &_n_g, hd)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ if (_gnutls_mpi_scan(&session->key->x, hd, &_n_g) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+
+ return i; /* return the processed data
+ * needed in auth_srp_rsa.
+ */
+}
+
+#endif /* ENABLE_SRP */
diff --git a/lib/auth_srp.h b/lib/auth_srp.h
new file mode 100644
index 0000000000..992cf9247c
--- /dev/null
+++ b/lib/auth_srp.h
@@ -0,0 +1,64 @@
+#ifndef AUTH_SRP_H
+# define AUTH_SRP_H
+
+#include <gnutls_auth.h>
+
+
+typedef int gnutls_srp_server_credentials_function(gnutls_session_t,
+ const char *username, gnutls_datum_t * salt, gnutls_datum_t * verifier,
+ gnutls_datum_t * generator, gnutls_datum_t * prime);
+
+typedef int gnutls_srp_client_credentials_function(gnutls_session_t,
+ unsigned int times, char **username, char** password);
+
+
+typedef struct {
+ char *username;
+ char *password;
+ gnutls_srp_client_credentials_function *get_function;
+} srp_client_credentials_st;
+
+#define gnutls_srp_client_credentials_t srp_client_credentials_st*
+
+typedef struct {
+ char *password_file;
+ char *password_conf_file;
+ /* callback function, instead of reading the
+ * password files.
+ */
+ gnutls_srp_server_credentials_function *pwd_callback;
+} srp_server_cred_st;
+
+#define gnutls_srp_server_credentials_t srp_server_cred_st*
+
+/* these structures should not use allocated data */
+typedef struct srp_server_auth_info_st {
+ char username[MAX_SRP_USERNAME];
+} *srp_server_auth_info_t;
+
+extern const gnutls_datum_t gnutls_srp_1024_group_prime;
+extern const gnutls_datum_t gnutls_srp_1024_group_generator;
+extern const gnutls_datum_t gnutls_srp_1536_group_prime;
+extern const gnutls_datum_t gnutls_srp_1536_group_generator;
+extern const gnutls_datum_t gnutls_srp_2048_group_prime;
+extern const gnutls_datum_t gnutls_srp_2048_group_generator;
+
+
+#ifdef ENABLE_SRP
+
+int _gnutls_proc_srp_server_hello(gnutls_session_t state,
+ const opaque * data, size_t data_size);
+int _gnutls_gen_srp_server_hello(gnutls_session_t state, opaque * data,
+ size_t data_size);
+
+int _gnutls_gen_srp_server_kx(gnutls_session_t, opaque **);
+int _gnutls_gen_srp_client_kx(gnutls_session_t, opaque **);
+
+int _gnutls_proc_srp_server_kx(gnutls_session_t, opaque *, size_t);
+int _gnutls_proc_srp_client_kx(gnutls_session_t, opaque *, size_t);
+
+typedef struct srp_server_auth_info_st srp_server_auth_info_st;
+
+#endif /* ENABLE_SRP */
+
+#endif
diff --git a/lib/auth_srp_passwd.c b/lib/auth_srp_passwd.c
new file mode 100644
index 0000000000..56af4f0d85
--- /dev/null
+++ b/lib/auth_srp_passwd.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2001,2002,2003 Nikos Mavroyanopoulos
+ * Copyright (C) 2004 Free Software Foundation
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* Functions for operating in an SRP passwd file are included here */
+
+#include <gnutls_int.h>
+
+#ifdef ENABLE_SRP
+
+#include "x509_b64.h"
+#include "gnutls_errors.h"
+#include <auth_srp_passwd.h>
+#include "auth_srp.h"
+#include "gnutls_auth_int.h"
+#include "gnutls_srp.h"
+#include "gnutls_random.h"
+#include "gnutls_dh.h"
+#include "debug.h"
+#include <gnutls_str.h>
+#include <gnutls_datum.h>
+#include <gnutls_num.h>
+
+static int _randomize_pwd_entry(SRP_PWD_ENTRY * entry);
+
+/* this function parses tpasswd.conf file. Format is:
+ * string(username):base64(v):base64(salt):int(index)
+ */
+static int pwd_put_values(SRP_PWD_ENTRY * entry, char *str)
+{
+ char *p;
+ int len, ret;
+ opaque *verifier;
+ size_t verifier_size;
+ int indx;
+
+ p = strrchr(str, ':'); /* we have index */
+ if (p == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_SRP_PWD_PARSING_ERROR;
+ }
+
+ *p = '\0';
+ p++;
+
+ len = strlen(p);
+ indx = atoi(p);
+ if (indx == 0) {
+ gnutls_assert();
+ return GNUTLS_E_SRP_PWD_PARSING_ERROR;
+ }
+
+ /* now go for salt */
+ p = strrchr(str, ':'); /* we have salt */
+ if (p == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_SRP_PWD_PARSING_ERROR;
+ }
+
+ *p = '\0';
+ p++;
+
+ len = strlen(p);
+
+ entry->salt.size = _gnutls_sbase64_decode(p, len, &entry->salt.data);
+
+ if (entry->salt.size <= 0) {
+ gnutls_assert();
+ return GNUTLS_E_SRP_PWD_PARSING_ERROR;
+ }
+
+ /* now go for verifier */
+ p = strrchr(str, ':'); /* we have verifier */
+ if (p == NULL) {
+ _gnutls_free_datum(&entry->salt);
+ return GNUTLS_E_SRP_PWD_PARSING_ERROR;
+ }
+
+ *p = '\0';
+ p++;
+
+ len = strlen(p);
+ ret = _gnutls_sbase64_decode(p, len, &verifier);
+ if (ret <= 0) {
+ gnutls_assert();
+ _gnutls_free_datum(&entry->salt);
+ return GNUTLS_E_SRP_PWD_PARSING_ERROR;
+ }
+
+ verifier_size = ret;
+ entry->v.data = verifier;
+ entry->v.size = verifier_size;
+
+ /* now go for username */
+ *p = '\0';
+
+ entry->username = gnutls_strdup(str);
+ if (entry->username == NULL) {
+ _gnutls_free_datum(&entry->salt);
+ _gnutls_free_datum(&entry->v);
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ return indx;
+}
+
+
+/* this function parses tpasswd.conf file. Format is:
+ * int(index):base64(n):int(g)
+ */
+static int pwd_put_values2(SRP_PWD_ENTRY * entry, char *str)
+{
+ char *p;
+ int len;
+ opaque *tmp;
+ int ret;
+
+ p = strrchr(str, ':'); /* we have g */
+ if (p == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_SRP_PWD_PARSING_ERROR;
+ }
+
+ *p = '\0';
+ p++;
+
+ /* read the generator */
+ len = strlen(p);
+ if (p[len - 1] == '\n' || p[len - 1] == ' ')
+ len--;
+ ret = _gnutls_sbase64_decode(p, len, &tmp);
+
+ if (ret < 0) {
+ gnutls_assert();
+ return GNUTLS_E_SRP_PWD_PARSING_ERROR;
+ }
+
+ entry->g.data = tmp;
+ entry->g.size = ret;
+
+ /* now go for n - modulo */
+ p = strrchr(str, ':'); /* we have n */
+ if (p == NULL) {
+ _gnutls_free_datum(&entry->g);
+ gnutls_assert();
+ return GNUTLS_E_SRP_PWD_PARSING_ERROR;
+ }
+
+ *p = '\0';
+ p++;
+
+ len = strlen(p);
+ ret = _gnutls_sbase64_decode(p, len, &tmp);
+
+ if (ret < 0) {
+ gnutls_assert();
+ _gnutls_free_datum(&entry->g);
+ return GNUTLS_E_SRP_PWD_PARSING_ERROR;
+ }
+
+ entry->n.data = tmp;
+ entry->n.size = ret;
+
+ return 0;
+}
+
+
+/* this function opens the tpasswd.conf file and reads the g and n
+ * values. They are put in the entry.
+ */
+static int pwd_read_conf(const char *pconf_file, SRP_PWD_ENTRY * entry,
+ int index)
+{
+ FILE *fd;
+ char line[2 * 1024];
+ uint i, len;
+ char indexstr[10];
+
+ sprintf(indexstr, "%d", index); /* Flawfinder: ignore */
+
+ fd = fopen(pconf_file, "r");
+ if (fd == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_FILE_ERROR;
+ }
+
+ len = strlen(indexstr);
+ while (fgets(line, sizeof(line), fd) != NULL) {
+ /* move to first ':' */
+ i = 0;
+ while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof(line))) {
+ i++;
+ }
+ if (strncmp(indexstr, line, GMAX(i, len)) == 0) {
+ if ((index = pwd_put_values2(entry, line)) >= 0)
+ return 0;
+ else {
+ return GNUTLS_E_SRP_PWD_ERROR;
+ }
+ }
+ }
+ return GNUTLS_E_SRP_PWD_ERROR;
+
+}
+
+int _gnutls_srp_pwd_read_entry(gnutls_session_t state, char *username,
+ SRP_PWD_ENTRY ** _entry)
+{
+ const gnutls_srp_server_credentials_t cred;
+ FILE *fd;
+ char line[2 * 1024];
+ uint i, len;
+ int ret;
+ int index, last_index;
+ SRP_PWD_ENTRY *entry;
+
+ *_entry = gnutls_calloc(1, sizeof(SRP_PWD_ENTRY));
+ if (*_entry == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ entry = *_entry;
+
+ cred = _gnutls_get_cred(state->key, GNUTLS_CRD_SRP, NULL);
+ if (cred == NULL) {
+ gnutls_assert();
+ _gnutls_srp_entry_free(entry);
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ /* if the callback which sends the parameters is
+ * set, use it.
+ */
+ if (cred->pwd_callback != NULL) {
+ ret = cred->pwd_callback(state, username, &entry->salt,
+ &entry->v, &entry->g, &entry->n);
+
+ if (ret == 1) { /* the user does not exist */
+ if (entry->g.size != 0 && entry->n.size != 0) {
+ ret = _randomize_pwd_entry(entry);
+ if (ret < 0) {
+ _gnutls_srp_entry_free(entry);
+ return ret;
+ }
+ return 0;
+ } else {
+ gnutls_assert();
+ ret = -1; /* error in the callback */
+ }
+ }
+
+ if (ret < 0) {
+ gnutls_assert();
+ _gnutls_srp_entry_free(entry);
+ return GNUTLS_E_SRP_PWD_ERROR;
+ }
+
+ return 0;
+ }
+
+ /* The callback was not set. Proceed.
+ */
+
+ if (cred->password_file == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_SRP_PWD_ERROR;
+ }
+
+ /* Open the selected password file.
+ */
+ fd = fopen(cred->password_file, "r");
+ if (fd == NULL) {
+ gnutls_assert();
+ _gnutls_srp_entry_free(entry);
+ return GNUTLS_E_SRP_PWD_ERROR;
+ }
+
+ last_index = 1; /* a default value */
+
+ len = strlen(username);
+ while (fgets(line, sizeof(line), fd) != NULL) {
+ /* move to first ':' */
+ i = 0;
+ while ((line[i] != ':') && (line[i] != '\0') && (i < sizeof(line))) {
+ i++;
+ }
+
+ if (strncmp(username, line, GMAX(i, len)) == 0) {
+ if ((index = pwd_put_values(entry, line)) >= 0) {
+ /* Keep the last index in memory, so we can retrieve fake parameters (g,n)
+ * when the user does not exist.
+ */
+ last_index = index;
+ if (pwd_read_conf(cred->password_conf_file, entry, index)
+ == 0) {
+ return 0;
+ } else {
+ gnutls_assert();
+ _gnutls_srp_entry_free(entry);
+ return GNUTLS_E_SRP_PWD_ERROR;
+ }
+ } else {
+ gnutls_assert();
+ _gnutls_srp_entry_free(entry);
+ return GNUTLS_E_SRP_PWD_ERROR;
+ }
+ }
+ }
+
+ /* user was not found. Fake him. Actually read the g,n values from
+ * the last index found and randomize the entry.
+ */
+ if (pwd_read_conf(cred->password_conf_file, entry, last_index) == 0) {
+ ret = _randomize_pwd_entry(entry);
+ if (ret < 0) {
+ gnutls_assert();
+ _gnutls_srp_entry_free(entry);
+ return ret;
+ }
+
+ return 0;
+ }
+
+ gnutls_assert();
+ _gnutls_srp_entry_free(entry);
+ return GNUTLS_E_SRP_PWD_ERROR;
+
+}
+
+/* Randomizes the given password entry. It actually sets the verifier
+ * and the salt. Returns 0 on success.
+ */
+static int _randomize_pwd_entry(SRP_PWD_ENTRY * entry)
+{
+ unsigned char rnd;
+
+ if (entry->g.size == 0 || entry->n.size == 0) {
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ _gnutls_get_random(&rnd, 1, GNUTLS_WEAK_RANDOM);
+ entry->salt.size = (rnd % 10) + 9;
+
+ entry->v.data = gnutls_malloc(20);
+ entry->v.size = 20;
+ if (entry->v.data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ _gnutls_get_random(entry->v.data, 20, GNUTLS_WEAK_RANDOM);
+
+ entry->salt.data = gnutls_malloc(entry->salt.size);
+ if (entry->salt.data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ if (_gnutls_get_random
+ (entry->salt.data, entry->salt.size, GNUTLS_WEAK_RANDOM) < 0) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ return 0;
+}
+
+/* Free all the entry parameters, except if g and n are
+ * the static ones defined in extra.h
+ */
+void _gnutls_srp_entry_free(SRP_PWD_ENTRY * entry)
+{
+ _gnutls_free_datum(&entry->v);
+ _gnutls_free_datum(&entry->salt);
+
+ if (entry->g.data != gnutls_srp_1024_group_generator.data)
+ _gnutls_free_datum(&entry->g);
+
+ if (entry->n.data != gnutls_srp_1024_group_prime.data &&
+ entry->n.data != gnutls_srp_1536_group_prime.data &&
+ entry->n.data != gnutls_srp_2048_group_prime.data)
+ _gnutls_free_datum(&entry->n);
+
+ gnutls_free(entry->username);
+ gnutls_free(entry);
+}
+
+
+#endif /* ENABLE SRP */
diff --git a/lib/auth_srp_passwd.h b/lib/auth_srp_passwd.h
new file mode 100644
index 0000000000..a9ff502536
--- /dev/null
+++ b/lib/auth_srp_passwd.h
@@ -0,0 +1,18 @@
+#ifdef ENABLE_SRP
+
+typedef struct {
+ char* username;
+
+ gnutls_datum_t salt;
+ gnutls_datum_t v;
+ gnutls_datum_t g;
+ gnutls_datum_t n;
+} SRP_PWD_ENTRY;
+
+/* this is locally allocated. It should be freed using the provided function */
+int _gnutls_srp_pwd_read_entry( gnutls_session_t state, char* username, SRP_PWD_ENTRY**);
+void _gnutls_srp_entry_free( SRP_PWD_ENTRY * entry);
+int _gnutls_sbase64_encode(uint8 * data, size_t data_size, uint8 ** result);
+int _gnutls_sbase64_decode(uint8 * data, size_t data_size, uint8 ** result);
+
+#endif /* ENABLE_SRP */
diff --git a/lib/auth_srp_rsa.c b/lib/auth_srp_rsa.c
new file mode 100644
index 0000000000..00f853060c
--- /dev/null
+++ b/lib/auth_srp_rsa.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2001,2002,2003 Nikos Mavroyanopoulos
+ * Copyright (C) 2004 Free Software Foundation
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <gnutls_int.h>
+
+#ifdef ENABLE_SRP
+
+#include "gnutls_errors.h"
+#include "auth_srp_passwd.h"
+#include "gnutls_auth.h"
+#include "gnutls_auth_int.h"
+#include "gnutls_srp.h"
+#include "debug.h"
+#include "gnutls_num.h"
+#include "auth_srp.h"
+#include <gnutls_str.h>
+#include <auth_cert.h>
+#include <gnutls_datum.h>
+#include <gnutls_sig.h>
+#include <auth_srp.h>
+#include <gnutls_x509.h>
+#include <gnutls_extra.h>
+
+static int gen_srp_cert_server_kx(gnutls_session_t, opaque **);
+static int proc_srp_cert_server_kx(gnutls_session_t, opaque *, size_t);
+
+const mod_auth_st srp_rsa_auth_struct = {
+ "SRP",
+ _gnutls_gen_cert_server_certificate,
+ NULL,
+ gen_srp_cert_server_kx,
+ _gnutls_gen_srp_client_kx,
+ NULL,
+ NULL,
+
+ _gnutls_proc_cert_server_certificate,
+ NULL, /* certificate */
+ proc_srp_cert_server_kx,
+ _gnutls_proc_srp_client_kx,
+ NULL,
+ NULL
+};
+
+const mod_auth_st srp_dss_auth_struct = {
+ "SRP",
+ _gnutls_gen_cert_server_certificate,
+ NULL,
+ gen_srp_cert_server_kx,
+ _gnutls_gen_srp_client_kx,
+ NULL,
+ NULL,
+
+ _gnutls_proc_cert_server_certificate,
+ NULL, /* certificate */
+ proc_srp_cert_server_kx,
+ _gnutls_proc_srp_client_kx,
+ NULL,
+ NULL
+};
+
+static int gen_srp_cert_server_kx(gnutls_session_t session, opaque ** data)
+{
+ ssize_t ret, data_size;
+ gnutls_datum_t signature, ddata;
+ const gnutls_certificate_credentials_t cred;
+ gnutls_cert *apr_cert_list;
+ gnutls_privkey *apr_pkey;
+ int apr_cert_list_length;
+
+ ret = _gnutls_gen_srp_server_kx(session, data);
+
+ if (ret < 0)
+ return ret;
+
+ data_size = ret;
+ ddata.data = *data;
+ ddata.size = data_size;
+
+ cred = _gnutls_get_cred(session->key, GNUTLS_CRD_CERTIFICATE, NULL);
+ if (cred == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ /* find the appropriate certificate */
+ if ((ret =
+ _gnutls_get_selected_cert(session, &apr_cert_list,
+ &apr_cert_list_length,
+ &apr_pkey)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ if ((ret =
+ _gnutls_tls_sign_params(session, &apr_cert_list[0],
+ apr_pkey, &ddata, &signature)) < 0) {
+ gnutls_assert();
+ gnutls_free(*data);
+ return ret;
+ }
+
+ *data = gnutls_realloc_fast(*data, data_size + signature.size + 2);
+ if (*data == NULL) {
+ _gnutls_free_datum(&signature);
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ _gnutls_write_datum16(&(*data)[data_size], signature);
+ data_size += signature.size + 2;
+
+ _gnutls_free_datum(&signature);
+
+ return data_size;
+
+}
+
+static int proc_srp_cert_server_kx(gnutls_session_t session, opaque * data,
+ size_t _data_size)
+{
+ ssize_t ret;
+ int sigsize;
+ gnutls_datum_t vparams, signature;
+ ssize_t data_size;
+ cert_auth_info_t info;
+ gnutls_cert peer_cert;
+ opaque *p;
+
+ ret = _gnutls_proc_srp_server_kx(session, data, _data_size);
+ if (ret < 0)
+ return ret;
+
+ data_size = _data_size - ret;
+
+ info = _gnutls_get_auth_info(session);
+ if (info == NULL || info->ncerts == 0) {
+ gnutls_assert();
+ /* we need this in order to get peer's certificate */
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ /* VERIFY SIGNATURE */
+
+ vparams.size = ret; /* all the data minus the signature */
+ vparams.data = data;
+
+ p = &data[vparams.size];
+
+ DECR_LEN(data_size, 2);
+ sigsize = _gnutls_read_uint16(p);
+
+ DECR_LEN(data_size, sigsize);
+ signature.data = &p[2];
+ signature.size = sigsize;
+
+ ret =
+ _gnutls_raw_cert_to_gcert(&peer_cert,
+ session->security_parameters.cert_type,
+ &info->raw_certificate_list[0],
+ CERT_NO_COPY);
+
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret =
+ _gnutls_verify_sig_params(session,
+ &peer_cert, &vparams, &signature);
+
+ _gnutls_gcert_deinit(&peer_cert);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return 0;
+}
+
+
+#endif /* ENABLE_SRP */
diff --git a/lib/auth_srp_sb64.c b/lib/auth_srp_sb64.c
new file mode 100644
index 0000000000..c446508fe6
--- /dev/null
+++ b/lib/auth_srp_sb64.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2001,2002,2003 Nikos Mavroyanopoulos
+ * Copyright (C) 2004 Free Software Foundation
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+
+#ifdef ENABLE_SRP
+
+/* this a modified base64 for srp !!!
+ * It seems that everybody makes an own base64 conversion.
+ */
+static const uint8 b64table[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
+
+static const uint8 asciitable[128] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x3e, 0x3f,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
+ 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
+ 0x23, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
+ 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,
+ 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff,
+ 0xff, 0xff
+};
+
+inline static int encode(uint8 * result, const uint8 * rdata, int left)
+{
+
+ int data_len;
+ int c, ret = 4;
+ uint8 data[3];
+
+ if (left > 3)
+ data_len = 3;
+ else
+ data_len = left;
+
+ data[0] = data[1] = data[2] = 0;
+ memcpy(data, rdata, data_len);
+
+ switch (data_len) {
+ case 3:
+ result[0] = b64table[((data[0] & 0xfc) >> 2)];
+ result[1] =
+ b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
+ ((data[1] & 0xf0) >> 4))];
+ result[2] =
+ b64table[((((data[1] & 0x0f) << 2) & 0xff) |
+ ((data[2] & 0xc0) >> 6))];
+ result[3] = b64table[(data[2] & 0x3f) & 0xff];
+ break;
+ case 2:
+ if ((c = ((data[0] & 0xf0) >> 4)) != 0) {
+ result[0] = b64table[c];
+ result[1] =
+ b64table[((((data[0] & 0x0f) << 2) & 0xff) |
+ ((data[1] & 0xc0) >> 6))];
+ result[2] = b64table[(data[1] & 0x3f) & 0xff];
+ result[3] = '\0';
+ ret -= 1;
+ } else {
+ if ((c =
+ ((data[0] & 0x0f) << 2) | ((data[1] & 0xc0) >> 6)) != 0) {
+ result[0] = b64table[c];
+ result[1] = b64table[data[1] & 0x3f];
+ result[2] = '\0';
+ result[3] = '\0';
+ ret -= 2;
+ } else {
+ result[0] = b64table[data[0] & 0x3f];
+ result[1] = '\0';
+ result[2] = '\0';
+ result[3] = '\0';
+ ret -= 3;
+ }
+ }
+ break;
+ case 1:
+ if ((c = ((data[0] & 0xc0) >> 6)) != 0) {
+ result[0] = b64table[c];
+ result[1] = b64table[(data[0] & 0x3f) & 0xff];
+ result[2] = '\0';
+ result[3] = '\0';
+ ret -= 2;
+ } else {
+ result[0] = b64table[(data[0] & 0x3f) & 0xff];
+ result[1] = '\0';
+ result[2] = '\0';
+ result[3] = '\0';
+ ret -= 3;
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ return ret;
+
+}
+
+/* encodes data and puts the result into result (locally allocated)
+ * The result_size is the return value
+ */
+int _gnutls_sbase64_encode(uint8 * data, size_t data_size, uint8 ** result)
+{
+ uint i, j;
+ int ret, tmp;
+ opaque tmpres[4];
+ int mod = data_size % 3;
+
+ ret = mod;
+ if (ret != 0)
+ ret = 4;
+ else
+ ret = 0;
+
+ ret += (data_size * 4) / 3;
+
+ (*result) = gnutls_calloc(1, ret + 1);
+ if ((*result) == NULL)
+ return -1;
+
+ i = j = 0;
+/* encode the bytes that are not a multiple of 3
+ */
+ if (mod > 0) {
+ tmp = encode(tmpres, &data[0], mod);
+ if (tmp < 0) {
+ gnutls_free((*result));
+ return tmp;
+ }
+
+ memcpy(&(*result)[0], tmpres, tmp);
+ i = mod;
+ j = tmp;
+
+ }
+/* encode the rest
+ */
+ for (; i < data_size; i += 3, j += 4) {
+ tmp = encode(tmpres, &data[i], data_size - i);
+ if (tmp < 0) {
+ gnutls_free((*result));
+ return tmp;
+ }
+ memcpy(&(*result)[j], tmpres, tmp);
+ }
+
+ return strlen(*result);
+}
+
+
+/* data must be 4 bytes
+ * result should be 3 bytes
+ */
+#define TOASCII(c) (c < 127 ? asciitable[c] : 0xff)
+inline static int decode(uint8 * result, const uint8 * data)
+{
+ uint8 a1, a2;
+ int ret = 3;
+
+ memset(result, 0, 3);
+
+ a1 = TOASCII(data[3]);
+ a2 = TOASCII(data[2]);
+ if (a1 != 0xff)
+ result[2] = a1 & 0xff;
+ else
+ return -1;
+ if (a2 != 0xff)
+ result[2] |= ((a2 & 0x03) << 6) & 0xff;
+
+ a1 = a2;
+ a2 = TOASCII(data[1]);
+ if (a1 != 0xff)
+ result[1] = ((a1 & 0x3c) >> 2);
+ if (a2 != 0xff)
+ result[1] |= ((a2 & 0x0f) << 4);
+ else if (a1 == 0xff || result[1] == 0)
+ ret--;
+
+ a1 = a2;
+ a2 = TOASCII(data[0]);
+ if (a1 != 0xff)
+ result[0] = (((a1 & 0x30) >> 4) & 0xff);
+ if (a2 != 0xff)
+ result[0] |= ((a2 << 2) & 0xff);
+ else if (a1 == 0xff || result[0] == 0)
+ ret--;
+
+ return ret;
+}
+
+/* decodes data and puts the result into result (locally allocated)
+ * The result_size is the return value.
+ * That function does not ignore newlines tabs etc. You should remove them
+ * before calling it.
+ */
+int _gnutls_sbase64_decode(uint8 * data, size_t idata_size,
+ uint8 ** result)
+{
+ uint i, j;
+ int ret, left;
+ int data_size, tmp;
+ uint8 datrev[4];
+ uint8 tmpres[3];
+
+ data_size = (idata_size / 4) * 4;
+ left = idata_size % 4;
+
+ ret = (data_size / 4) * 3;
+
+ if (left > 0)
+ ret += 3;
+
+ (*result) = gnutls_malloc(ret + 1);
+ if ((*result) == NULL)
+ return -1;
+
+ /* the first "block" is treated with special care */
+ tmp = 0;
+ if (left > 0) {
+ memset(datrev, 0, 4);
+ memcpy(&datrev[4 - left], data, left);
+
+ tmp = decode(tmpres, datrev);
+ if (tmp < 0) {
+ gnutls_free((*result));
+ *result = NULL;
+ return tmp;
+ }
+
+ memcpy(*result, &tmpres[3 - tmp], tmp);
+ if (tmp < 3)
+ ret -= (3 - tmp);
+ }
+
+ /* rest data */
+ for (i = left, j = tmp; i < idata_size; i += 4) {
+ tmp = decode(tmpres, &data[i]);
+ if (tmp < 0) {
+ gnutls_free((*result));
+ *result = NULL;
+ return tmp;
+ }
+ memcpy(&(*result)[j], tmpres, tmp);
+ if (tmp < 3)
+ ret -= (3 - tmp);
+ j += 3;
+ }
+
+ return ret;
+}
+
+/**
+ * gnutls_srp_base64_encode - This function will convert raw data to base64 encoded
+ * @data: contain the raw data
+ * @result: the place where base64 data will be copied
+ * @result_size: holds the size of the result
+ *
+ * This function will convert the given data to printable data, using the base64
+ * encoding, as used in the libsrp. This is the encoding used in SRP password files.
+ * If the provided buffer is not long enough GNUTLS_E_SHORT_MEMORY_BUFFER is returned.
+ *
+ **/
+int gnutls_srp_base64_encode(const gnutls_datum_t * data, char *result,
+ int *result_size)
+{
+ opaque *ret;
+ int size;
+
+ size = _gnutls_sbase64_encode(data->data, data->size, &ret);
+ if (size < 0)
+ return size;
+
+ if (result == NULL || *result_size < size) {
+ gnutls_free(ret);
+ *result_size = size;
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ } else {
+ memcpy(result, ret, size);
+ gnutls_free(ret);
+ *result_size = size;
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_srp_base64_encode_alloc - This function will convert raw data to Base64 encoded
+ * @data: contains the raw data
+ * @result: will hold the newly allocated encoded data
+ *
+ * This function will convert the given data to printable data, using the base64
+ * encoding. This is the encoding used in SRP password files. This function will
+ * allocate the required memory to hold the encoded data.
+ *
+ * You should use gnutls_free() to free the returned data.
+ *
+ **/
+int gnutls_srp_base64_encode_alloc(const gnutls_datum_t * data,
+ gnutls_datum_t * result)
+{
+ opaque *ret;
+ int size;
+
+ size = _gnutls_sbase64_encode(data->data, data->size, &ret);
+ if (size < 0)
+ return size;
+
+ if (result == NULL) {
+ gnutls_free(ret);
+ return GNUTLS_E_INVALID_REQUEST;
+ } else {
+ result->data = ret;
+ result->size = size;
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_srp_base64_decode - This function will decode base64 encoded data
+ * @b64_data: contain the encoded data
+ * @result: the place where decoded data will be copied
+ * @result_size: holds the size of the result
+ *
+ * This function will decode the given encoded data, using the base64 encoding
+ * found in libsrp.
+ *
+ * Note that b64_data should be null terminated.
+ *
+ * Returns GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not long enough,
+ * or 0 on success.
+ **/
+int gnutls_srp_base64_decode(const gnutls_datum_t * b64_data, char *result,
+ int *result_size)
+{
+ opaque *ret;
+ int size;
+
+ size = _gnutls_sbase64_decode(b64_data->data, b64_data->size, &ret);
+ if (size < 0)
+ return size;
+
+ if (result == NULL || *result_size < size) {
+ gnutls_free(ret);
+ *result_size = size;
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ } else {
+ memcpy(result, ret, size);
+ gnutls_free(ret);
+ *result_size = size;
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_srp_base64_decode_alloc - This function will decode base64 encoded data
+ * @b64_data: contains the encoded data
+ * @result: the place where decoded data lie
+ *
+ * This function will decode the given encoded data. The decoded data
+ * will be allocated, and stored into result.
+ * It will decode using the base64 algorithm found in libsrp.
+ *
+ * You should use gnutls_free() to free the returned data.
+ *
+ **/
+int gnutls_srp_base64_decode_alloc(const gnutls_datum_t * b64_data,
+ gnutls_datum_t * result)
+{
+ opaque *ret;
+ int size;
+
+ size = _gnutls_sbase64_decode(b64_data->data, b64_data->size, &ret);
+ if (size < 0)
+ return size;
+
+ if (result == NULL) {
+ gnutls_free(ret);
+ return GNUTLS_E_INVALID_REQUEST;
+ } else {
+ result->data = ret;
+ result->size = size;
+ }
+
+ return 0;
+}
+
+#endif /* ENABLE_SRP */
diff --git a/lib/ext_srp.c b/lib/ext_srp.c
new file mode 100644
index 0000000000..8bb1cbc7de
--- /dev/null
+++ b/lib/ext_srp.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2001,2002,2003 Nikos Mavroyanopoulos
+ * Copyright (C) 2004 Free Software Foundation
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <gnutls_int.h>
+#include <ext_srp.h>
+
+#ifdef ENABLE_SRP
+
+#include "gnutls_auth_int.h"
+#include "auth_srp.h"
+#include "gnutls_errors.h"
+#include "gnutls_algorithms.h"
+#include <gnutls_num.h>
+
+int _gnutls_srp_recv_params(gnutls_session_t session, const opaque * data,
+ size_t _data_size)
+{
+ uint8 len;
+ ssize_t data_size = _data_size;
+
+ if (_gnutls_kx_priority(session, GNUTLS_KX_SRP) < 0 &&
+ _gnutls_kx_priority(session, GNUTLS_KX_SRP_DSS) < 0 &&
+ _gnutls_kx_priority(session, GNUTLS_KX_SRP_RSA) < 0) {
+ /* algorithm was not allowed in this session
+ */
+ return 0;
+ }
+
+ if (session->security_parameters.entity == GNUTLS_SERVER) {
+ if (data_size > 0) {
+ len = data[0];
+ DECR_LEN(data_size, len);
+
+ if (sizeof
+ (session->security_parameters.extensions.srp_username) <=
+ len) {
+ gnutls_assert();
+ return GNUTLS_E_ILLEGAL_SRP_USERNAME;
+ }
+ memcpy(session->security_parameters.extensions.srp_username,
+ &data[1], len);
+ session->security_parameters.extensions.srp_username[len] = 0; /* null terminated */
+ }
+ }
+ return 0;
+}
+
+/* Checks if the given cipher suite is an SRP one
+ */
+inline static int is_srp(cipher_suite_st suite)
+{
+ int kx = _gnutls_cipher_suite_get_kx_algo(&suite);
+
+ if (IS_SRP_KX(kx))
+ return 1;
+ return 0;
+}
+
+/* returns data_size or a negative number on failure
+ * data is allocated locally
+ */
+int _gnutls_srp_send_params(gnutls_session_t session, opaque * data,
+ size_t data_size)
+{
+ uint len;
+
+ if (_gnutls_kx_priority(session, GNUTLS_KX_SRP) < 0 &&
+ _gnutls_kx_priority(session, GNUTLS_KX_SRP_DSS) < 0 &&
+ _gnutls_kx_priority(session, GNUTLS_KX_SRP_RSA) < 0) {
+ /* algorithm was not allowed in this session
+ */
+ return 0;
+ }
+
+ /* this function sends the client extension data (username) */
+ if (session->security_parameters.entity == GNUTLS_CLIENT) {
+ const gnutls_srp_client_credentials_t cred =
+ _gnutls_get_cred(session->key, GNUTLS_CRD_SRP, NULL);
+
+ if (cred == NULL)
+ return 0;
+
+ if (cred->username != NULL) { /* send username */
+ len = GMIN(strlen(cred->username), 255);
+
+ if (data_size < len + 1) {
+ gnutls_assert();
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ }
+
+ data[0] = (uint8) len;
+ memcpy(&data[1], cred->username, len);
+ return len + 1;
+ } else if (cred->get_function != NULL) {
+ /* Try the callback
+ */
+ char *username = NULL, *password = NULL;
+
+ if (cred->
+ get_function(session,
+ session->internals.handshake_restarted,
+ &username, &password) < 0 || username == NULL
+ || password == NULL) {
+
+ if (session->internals.handshake_restarted) {
+ gnutls_assert();
+ return GNUTLS_E_ILLEGAL_SRP_USERNAME;
+ }
+
+ return 0;
+ }
+
+ len = GMIN(strlen(username), 255);
+
+ if (data_size < len + 1) {
+ gnutls_free(username);
+ gnutls_free(password);
+ gnutls_assert();
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ }
+
+ session->internals.srp_username = username;
+ session->internals.srp_password = password;
+
+ data[0] = (uint8) len;
+ memcpy(&data[1], username, len);
+ return len + 1;
+ }
+ }
+ return 0;
+}
+
+#endif /* ENABLE_SRP */
diff --git a/lib/ext_srp.h b/lib/ext_srp.h
new file mode 100644
index 0000000000..8f69518be9
--- /dev/null
+++ b/lib/ext_srp.h
@@ -0,0 +1,9 @@
+#ifdef ENABLE_SRP
+
+#define IS_SRP_KX(kx) ((kx == GNUTLS_KX_SRP || (kx == GNUTLS_KX_SRP_RSA) || \
+ kx == GNUTLS_KX_SRP_DSS)?1:0)
+
+int _gnutls_srp_recv_params( gnutls_session_t state, const opaque* data, size_t data_size);
+int _gnutls_srp_send_params( gnutls_session_t state, opaque* data, size_t);
+
+#endif
diff --git a/lib/gnutls.h.in.in b/lib/gnutls.h.in.in
index 26b6b7bb01..a391345413 100644
--- a/lib/gnutls.h.in.in
+++ b/lib/gnutls.h.in.in
@@ -497,3 +497,52 @@ void gnutls_openpgp_send_key(gnutls_session_t session, gnutls_openpgp_key_status
int gnutls_fingerprint(gnutls_digest_algorithm_t algo, const gnutls_datum_t* data,
void* result, size_t* result_size);
+
+/* SRP
+ */
+
+typedef struct DSTRUCT* gnutls_srp_server_credentials_t;
+typedef struct DSTRUCT* gnutls_srp_client_credentials_t;
+
+void gnutls_srp_free_client_credentials( gnutls_srp_client_credentials_t sc);
+int gnutls_srp_allocate_client_credentials( gnutls_srp_client_credentials_t *sc);
+int gnutls_srp_set_client_credentials( gnutls_srp_client_credentials_t res, char *username, char* password);
+
+void gnutls_srp_free_server_credentials( gnutls_srp_server_credentials_t sc);
+int gnutls_srp_allocate_server_credentials( gnutls_srp_server_credentials_t *sc);
+int gnutls_srp_set_server_credentials_file( gnutls_srp_server_credentials_t res,
+ const char *password_file, const char* password_conf_file);
+
+const char* gnutls_srp_server_get_username( gnutls_session_t state);
+
+int gnutls_srp_verifier( const char* username, const char* password, const gnutls_datum_t *salt,
+ const gnutls_datum_t* g, const gnutls_datum_t* n,
+ gnutls_datum_t * res);
+
+/* The static parameters defined in draft-ietf-tls-srp-05
+ * Those should be used as input to gnutls_srp_verifier().
+ */
+extern const gnutls_datum_t gnutls_srp_2048_group_prime;
+extern const gnutls_datum_t gnutls_srp_2048_group_generator;
+
+extern const gnutls_datum_t gnutls_srp_1536_group_prime;
+extern const gnutls_datum_t gnutls_srp_1536_group_generator;
+
+extern const gnutls_datum_t gnutls_srp_1024_group_prime;
+extern const gnutls_datum_t gnutls_srp_1024_group_generator;
+
+typedef int gnutls_srp_server_credentials_function(
+ gnutls_session_t,
+ const char* username, gnutls_datum_t* salt,
+ gnutls_datum_t* verifier, gnutls_datum_t* generator,
+ gnutls_datum_t* prime
+);
+void gnutls_srp_set_server_credentials_function(
+ gnutls_srp_server_credentials_t,
+ gnutls_srp_server_credentials_function *);
+
+typedef int gnutls_srp_client_credentials_function(gnutls_session_t, unsigned int,
+ char **, char**);
+void gnutls_srp_set_client_credentials_function( gnutls_srp_client_credentials_t,
+ gnutls_srp_client_credentials_function *);
+
diff --git a/lib/gnutls_algorithms.c b/lib/gnutls_algorithms.c
index e0ee6000db..2c8d181ce7 100644
--- a/lib/gnutls_algorithms.c
+++ b/lib/gnutls_algorithms.c
@@ -217,6 +217,9 @@ extern mod_auth_st rsa_export_auth_struct;
extern mod_auth_st dhe_rsa_auth_struct;
extern mod_auth_st dhe_dss_auth_struct;
extern mod_auth_st anon_auth_struct;
+extern mod_auth_st srp_auth_struct;
+extern mod_auth_st srp_rsa_auth_struct;
+extern mod_auth_st srp_dss_auth_struct;
#define MAX_KX_ALGOS 10
@@ -230,6 +233,10 @@ gnutls_kx_algo_entry _gnutls_kx_algorithms[MAX_KX_ALGOS] = {
{"RSA EXPORT", GNUTLS_KX_RSA_EXPORT, &rsa_export_auth_struct, 0, 1},
{"DHE RSA", GNUTLS_KX_DHE_RSA, &dhe_rsa_auth_struct, 1, 0},
{"DHE DSS", GNUTLS_KX_DHE_DSS, &dhe_dss_auth_struct, 1, 0},
+
+ {"SRP DSS", GNUTLS_KX_SRP_DSS, &srp_dss_auth_struct, 0, 0},
+ {"SRP RSA", GNUTLS_KX_SRP_RSA, &srp_rsa_auth_struct, 0, 0},
+ {"SRP", GNUTLS_KX_SRP, &srp_auth_struct, 0, 0},
/* other algorithms are appended here by gnutls-extra
* initialization function.
*/
diff --git a/lib/gnutls_extensions.c b/lib/gnutls_extensions.c
index adfd109552..ee1cf1e86c 100644
--- a/lib/gnutls_extensions.c
+++ b/lib/gnutls_extensions.c
@@ -31,7 +31,8 @@
#include "ext_max_record.h"
#include <ext_cert_type.h>
#include <ext_server_name.h>
-#include "gnutls_num.h"
+#include <ext_srp.h>
+#include <gnutls_num.h>
/* Key Exchange Section */
#define GNUTLS_EXTENSION_ENTRY(type, ext_func_recv, ext_func_send) \
@@ -51,6 +52,9 @@ gnutls_extension_entry _gnutls_extensions[MAX_EXT_SIZE] = {
GNUTLS_EXTENSION_ENTRY(GNUTLS_EXTENSION_SERVER_NAME,
_gnutls_server_name_recv_params,
_gnutls_server_name_send_params),
+ GNUTLS_EXTENSION_ENTRY(GNUTLS_EXTENSION_SRP,
+ _gnutls_srp_recv_params,
+ _gnutls_srp_send_params),
{0, 0, 0, 0}
};
diff --git a/lib/gnutls_srp.c b/lib/gnutls_srp.c
new file mode 100644
index 0000000000..e1374f4bac
--- /dev/null
+++ b/lib/gnutls_srp.c
@@ -0,0 +1,702 @@
+/*
+ * Copyright (C) 2001,2002,2003 Nikos Mavroyanopoulos
+ * Copyright (C) 2004 Free Software Foundation
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <auth_srp.h>
+#include <gnutls_state.h>
+
+#ifdef ENABLE_SRP
+
+#include <gnutls_srp.h>
+#include <auth_srp_passwd.h>
+#include <gnutls_mpi.h>
+#include <gnutls_num.h>
+#include "debug.h"
+
+
+/* Here functions for SRP (like g^x mod n) are defined
+ */
+
+int _gnutls_srp_gx(opaque * text, size_t textsize, opaque ** result,
+ mpi_t g, mpi_t prime,
+ gnutls_alloc_function galloc_func)
+{
+ mpi_t x, e;
+ size_t result_size;
+
+ if (_gnutls_mpi_scan(&x, text, &textsize)) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ e = _gnutls_mpi_alloc_like(prime);
+ if (e == NULL) {
+ gnutls_assert();
+ _gnutls_mpi_release(&x);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ /* e = g^x mod prime (n) */
+ _gnutls_mpi_powm(e, g, x, prime);
+ _gnutls_mpi_release(&x);
+
+ _gnutls_mpi_print(NULL, &result_size, e);
+ if (result != NULL) {
+ *result = galloc_func(result_size);
+ if ((*result) == NULL)
+ return GNUTLS_E_MEMORY_ERROR;
+
+ _gnutls_mpi_print(*result, &result_size, e);
+ }
+
+ _gnutls_mpi_release(&e);
+
+ return result_size;
+
+}
+
+
+/****************
+ * Choose a random value b and calculate B = (k* v + g^b) % N.
+ * where k == SHA1(N|g)
+ * Return: B and if ret_b is not NULL b.
+ */
+mpi_t _gnutls_calc_srp_B(mpi_t * ret_b, mpi_t g, mpi_t n, mpi_t v)
+{
+ mpi_t tmpB = NULL, tmpV = NULL;
+ mpi_t b = NULL, B = NULL, k = NULL;
+ int bits;
+ size_t n_size = 0;
+
+ /* get the size of n in bytes */
+ _gnutls_mpi_print( NULL, &n_size, n);
+
+ /* calculate: B = (k*v + g^b) % N
+ */
+ bits = _gnutls_mpi_get_nbits(n);
+ b = _gnutls_mpi_snew(bits);
+ if (b == NULL) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ tmpV = _gnutls_mpi_alloc_like(n);
+
+ if (tmpV == NULL) {
+ gnutls_assert();
+ goto error;
+ }
+
+ _gnutls_mpi_randomize(b, bits, GCRY_STRONG_RANDOM);
+
+ tmpB = _gnutls_mpi_snew(bits);
+ if (tmpB == NULL) {
+ gnutls_assert();
+ goto error;
+ }
+
+ B = _gnutls_mpi_snew(bits);
+ if (B == NULL) {
+ gnutls_assert();
+ goto error;
+ }
+
+ k = _gnutls_calc_srp_u(n, g, n_size);
+ if (k == NULL) {
+ gnutls_assert();
+ goto error;
+ }
+
+ _gnutls_mpi_mulm(tmpV, k, v, n);
+ _gnutls_mpi_powm(tmpB, g, b, n);
+
+ _gnutls_mpi_addm(B, tmpV, tmpB, n);
+
+ _gnutls_mpi_release(&k);
+ _gnutls_mpi_release(&tmpB);
+ _gnutls_mpi_release(&tmpV);
+
+ if (ret_b)
+ *ret_b = b;
+ else
+ _gnutls_mpi_release(&b);
+
+ return B;
+
+ error:
+ _gnutls_mpi_release(&b);
+ _gnutls_mpi_release(&B);
+ _gnutls_mpi_release(&k);
+ _gnutls_mpi_release(&tmpB);
+ _gnutls_mpi_release(&tmpV);
+ return NULL;
+
+}
+
+/* This calculates the SHA1(A | B)
+ * A and B will be left-padded with zeros to fill n_size.
+ */
+mpi_t _gnutls_calc_srp_u(mpi_t A, mpi_t B, size_t n_size)
+{
+ size_t b_size, a_size;
+ opaque *holder, hd[MAX_HASH_SIZE];
+ size_t holder_size, hash_size;
+ GNUTLS_HASH_HANDLE td;
+ int ret;
+ mpi_t res;
+
+ _gnutls_mpi_print(NULL, &a_size, A);
+ _gnutls_mpi_print(NULL, &b_size, B);
+
+ if (a_size > n_size || b_size > n_size) {
+ gnutls_assert();
+ return NULL; /* internal error */
+ }
+
+ holder_size = n_size + n_size;
+
+ holder = gnutls_calloc(1, holder_size);
+ if (holder == NULL)
+ return NULL;
+
+ _gnutls_mpi_print(&holder[n_size - a_size], &a_size, A);
+ _gnutls_mpi_print(&holder[n_size + n_size - b_size], &b_size, B);
+
+ td = _gnutls_hash_init(GNUTLS_MAC_SHA);
+ if (td == NULL) {
+ gnutls_free(holder);
+ gnutls_assert();
+ return NULL;
+ }
+ _gnutls_hash(td, holder, holder_size);
+ _gnutls_hash_deinit(td, hd);
+
+ /* convert the bytes of hd to integer
+ */
+ hash_size = 20; /* SHA */
+ ret = _gnutls_mpi_scan(&res, hd, &hash_size);
+ gnutls_free(holder);
+
+ if (ret < 0) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ return res;
+}
+
+/* S = (A * v^u) ^ b % N
+ * this is our shared key (server premaster secret)
+ */
+mpi_t _gnutls_calc_srp_S1(mpi_t A, mpi_t b, mpi_t u,
+ mpi_t v, mpi_t n)
+{
+ mpi_t tmp1 = NULL, tmp2 = NULL;
+ mpi_t S = NULL;
+
+ S = _gnutls_mpi_alloc_like(n);
+ if (S == NULL)
+ return NULL;
+
+ tmp1 = _gnutls_mpi_alloc_like(n);
+ tmp2 = _gnutls_mpi_alloc_like(n);
+
+ if (tmp1 == NULL || tmp2 == NULL)
+ goto freeall;
+
+ _gnutls_mpi_powm(tmp1, v, u, n);
+ _gnutls_mpi_mulm(tmp2, A, tmp1, n);
+ _gnutls_mpi_powm(S, tmp2, b, n);
+
+ _gnutls_mpi_release(&tmp1);
+ _gnutls_mpi_release(&tmp2);
+
+ return S;
+
+ freeall:
+ _gnutls_mpi_release(&tmp1);
+ _gnutls_mpi_release(&tmp2);
+ return NULL;
+}
+
+/* A = g^a % N
+ * returns A and a (which is random)
+ */
+mpi_t _gnutls_calc_srp_A(mpi_t * a, mpi_t g, mpi_t n)
+{
+ mpi_t tmpa;
+ mpi_t A;
+ int bits;
+
+ bits = _gnutls_mpi_get_nbits(n);
+ tmpa = _gnutls_mpi_snew(bits);
+ if (tmpa == NULL) {
+ gnutls_assert();
+ return NULL;
+ }
+
+ _gnutls_mpi_randomize(tmpa, bits, GCRY_STRONG_RANDOM);
+
+ A = _gnutls_mpi_snew(bits);
+ if (A == NULL) {
+ gnutls_assert();
+ _gnutls_mpi_release(&tmpa);
+ return NULL;
+ }
+ _gnutls_mpi_powm(A, g, tmpa, n);
+
+ if (a != NULL)
+ *a = tmpa;
+ else
+ _gnutls_mpi_release(&tmpa);
+
+ return A;
+}
+
+/* generate x = SHA(s | SHA(U | ":" | p))
+ * The output is exactly 20 bytes
+ */
+int _gnutls_calc_srp_sha(const char *username, const char *password,
+ opaque * salt, int salt_size, size_t * size,
+ void *digest)
+{
+ GNUTLS_HASH_HANDLE td;
+ opaque res[MAX_HASH_SIZE];
+
+ *size = 20;
+
+ td = _gnutls_hash_init(GNUTLS_MAC_SHA);
+ if (td == NULL) {
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ _gnutls_hash(td, username, strlen(username));
+ _gnutls_hash(td, ":", 1);
+ _gnutls_hash(td, password, strlen(password));
+
+ _gnutls_hash_deinit(td, res);
+
+ td = _gnutls_hash_init(GNUTLS_MAC_SHA);
+ if (td == NULL) {
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ _gnutls_hash(td, salt, salt_size);
+ _gnutls_hash(td, res, 20); /* 20 bytes is the output of sha1 */
+
+ _gnutls_hash_deinit(td, digest);
+
+ return 0;
+}
+
+int _gnutls_calc_srp_x(char *username, char *password, opaque * salt,
+ size_t salt_size, size_t * size, void *digest)
+{
+
+ return _gnutls_calc_srp_sha(username, password, salt,
+ salt_size, size, digest);
+}
+
+
+/* S = (B - k*g^x) ^ (a + u * x) % N
+ * this is our shared key (client premaster secret)
+ */
+mpi_t _gnutls_calc_srp_S2(mpi_t B, mpi_t g, mpi_t x,
+ mpi_t a, mpi_t u, mpi_t n)
+{
+ mpi_t S = NULL, tmp1 = NULL, tmp2 = NULL;
+ mpi_t tmp4 = NULL, tmp3 = NULL, k = NULL;
+ size_t n_size = 0;
+
+ /* get the size of n in bytes */
+ _gnutls_mpi_print( NULL, &n_size, n);
+
+ S = _gnutls_mpi_alloc_like(n);
+ if (S == NULL)
+ return NULL;
+
+ tmp1 = _gnutls_mpi_alloc_like(n);
+ tmp2 = _gnutls_mpi_alloc_like(n);
+ tmp3 = _gnutls_mpi_alloc_like(n);
+ if (tmp1 == NULL || tmp2 == NULL || tmp3 == NULL) {
+ goto freeall;
+ }
+
+ k = _gnutls_calc_srp_u(n, g, n_size);
+ if (k == NULL) {
+ gnutls_assert();
+ goto freeall;
+ }
+
+ _gnutls_mpi_powm(tmp1, g, x, n); /* g^x */
+ _gnutls_mpi_mulm(tmp3, tmp1, k, n); /* k*g^x mod n */
+ _gnutls_mpi_subm(tmp2, B, tmp3, n);
+
+ tmp4 = _gnutls_mpi_alloc_like(n);
+ if (tmp4 == NULL)
+ goto freeall;
+
+ _gnutls_mpi_mul(tmp1, u, x);
+ _gnutls_mpi_add(tmp4, a, tmp1);
+ _gnutls_mpi_powm(S, tmp2, tmp4, n);
+
+ _gnutls_mpi_release(&tmp1);
+ _gnutls_mpi_release(&tmp2);
+ _gnutls_mpi_release(&tmp3);
+ _gnutls_mpi_release(&tmp4);
+ _gnutls_mpi_release(&k);
+
+ return S;
+
+ freeall:
+ _gnutls_mpi_release(&k);
+ _gnutls_mpi_release(&tmp1);
+ _gnutls_mpi_release(&tmp2);
+ _gnutls_mpi_release(&tmp3);
+ _gnutls_mpi_release(&tmp4);
+ _gnutls_mpi_release(&S);
+ return NULL;
+}
+
+/**
+ * gnutls_srp_free_server_credentials - Used to free an allocated gnutls_srp_client_credentials_t structure
+ * @sc: is an &gnutls_srp_client_credentials_t structure.
+ *
+ * This structure is complex enough to manipulate directly thus
+ * this helper function is provided in order to free (deallocate) it.
+ *
+ **/
+void gnutls_srp_free_client_credentials(gnutls_srp_client_credentials_t sc)
+{
+ gnutls_free(sc->username);
+ gnutls_free(sc->password);
+ gnutls_free(sc);
+}
+
+/**
+ * gnutls_srp_allocate_server_credentials - Used to allocate an gnutls_srp_server_credentials_t structure
+ * @sc: is a pointer to an &gnutls_srp_server_credentials_t structure.
+ *
+ * This structure is complex enough to manipulate directly thus
+ * this helper function is provided in order to allocate it.
+ *
+ * Returns 0 on success.
+ **/
+int gnutls_srp_allocate_client_credentials(gnutls_srp_client_credentials_t *
+ sc)
+{
+ *sc = gnutls_calloc(1, sizeof(srp_client_credentials_st));
+
+ if (*sc == NULL)
+ return GNUTLS_E_MEMORY_ERROR;
+
+ return 0;
+}
+
+/**
+ * gnutls_srp_set_client_credentials - Used to set the username/password, in a gnutls_srp_client_credentials_t structure
+ * @res: is an &gnutls_srp_client_credentials_t structure.
+ * @username: is the user's userid
+ * @password: is the user's password
+ *
+ * This function sets the username and password, in a gnutls_srp_client_credentials_t structure.
+ * Those will be used in SRP authentication. @username and @password should be ASCII
+ * strings or UTF-8 strings prepared using the "SASLprep" profile of "stringprep".
+ *
+ * Returns 0 on success.
+ **/
+int gnutls_srp_set_client_credentials(gnutls_srp_client_credentials_t res,
+ char *username, char *password)
+{
+
+ if (username == NULL || password == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ res->username = gnutls_strdup(username);
+ if (res->username == NULL)
+ return GNUTLS_E_MEMORY_ERROR;
+
+ res->password = gnutls_strdup(password);
+ if (res->password == NULL) {
+ gnutls_free(res->username);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_srp_free_server_credentials - Used to free an allocated gnutls_srp_server_credentials_t structure
+ * @sc: is an &gnutls_srp_server_credentials_t structure.
+ *
+ * This structure is complex enough to manipulate directly thus
+ * this helper function is provided in order to free (deallocate) it.
+ *
+ **/
+void gnutls_srp_free_server_credentials(gnutls_srp_server_credentials_t sc)
+{
+ gnutls_free(sc->password_file);
+ gnutls_free(sc->password_conf_file);
+
+ gnutls_free(sc);
+}
+
+/**
+ * gnutls_srp_allocate_server_credentials - Used to allocate an gnutls_srp_server_credentials_t structure
+ * @sc: is a pointer to an &gnutls_srp_server_credentials_t structure.
+ *
+ * This structure is complex enough to manipulate directly thus
+ * this helper function is provided in order to allocate it.
+ *
+ * Returns 0 on success.
+ **/
+int gnutls_srp_allocate_server_credentials(gnutls_srp_server_credentials_t *
+ sc)
+{
+ *sc = gnutls_calloc(1, sizeof(srp_server_cred_st));
+
+ if (*sc == NULL)
+ return GNUTLS_E_MEMORY_ERROR;
+
+ return 0;
+}
+
+inline static int file_exists(const char *file)
+{
+ FILE *fd;
+
+ fd = fopen(file, "r");
+ if (fd == NULL)
+ return -1;
+
+ fclose(fd);
+ return 0;
+}
+
+/**
+ * gnutls_srp_set_server_credentials_file - Used to set the password files, in a gnutls_srp_server_credentials_t structure
+ * @res: is an &gnutls_srp_server_credentials_t structure.
+ * @password_file: is the SRP password file (tpasswd)
+ * @password_conf_file: is the SRP password conf file (tpasswd.conf)
+ *
+ * This function sets the password files, in a gnutls_srp_server_credentials_t structure.
+ * Those password files hold usernames and verifiers and will be used for SRP authentication.
+ *
+ * Returns 0 on success.
+ *
+ **/
+int gnutls_srp_set_server_credentials_file(gnutls_srp_server_credentials_t
+ res, const char *password_file,
+ const char *password_conf_file)
+{
+
+ if (password_file == NULL || password_conf_file == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ /* Check if the files can be opened */
+ if (file_exists(password_file) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_FILE_ERROR;
+ }
+
+ if (file_exists(password_conf_file) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_FILE_ERROR;
+ }
+
+ res->password_file = gnutls_strdup(password_file);
+ if (res->password_file == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ res->password_conf_file = gnutls_strdup(password_conf_file);
+ if (res->password_conf_file == NULL) {
+ gnutls_assert();
+ gnutls_free(res->password_file);
+ res->password_file = NULL;
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ return 0;
+}
+
+
+/**
+ * gnutls_srp_set_server_credentials_function - Used to set a callback to retrieve the user's SRP credentials
+ * @cred: is a &gnutls_srp_server_credentials_t structure.
+ * @func: is the callback function
+ *
+ * This function can be used to set a callback to retrieve the user's SRP credentials.
+ * The callback's function form is:
+ * int (*callback)(gnutls_session_t, const char* username,
+ * gnutls_datum_t* salt, gnutls_datum_t *verifier, gnutls_datum_t* g,
+ * gnutls_datum_t* n);
+ *
+ * @username contains the actual username.
+ * The @salt, @verifier, @generator and @prime must be filled
+ * in using the gnutls_malloc(). For convenience @prime and @generator
+ * may also be one of the static parameters defined in extra.h.
+ *
+ * In case the callback returned a negative number then gnutls will
+ * assume that the username does not exist.
+ *
+ * In order to prevent attackers from guessing valid usernames,
+ * if a user does not exist, g and n values should be filled in
+ * using a random user's parameters. In that case the callback must
+ * return the special value (1).
+ *
+ * The callback function will only be called once per handshake.
+ * The callback function should return 0 on success, while
+ * -1 indicates an error.
+ *
+ **/
+void
+gnutls_srp_set_server_credentials_function(gnutls_srp_server_credentials_t
+ cred, gnutls_srp_server_credentials_function * func)
+{
+ cred->pwd_callback = func;
+}
+
+/**
+ * gnutls_srp_set_client_credentials_function - Used to set a callback to retrieve the username and password
+ * @cred: is a &gnutls_srp_server_credentials_t structure.
+ * @func: is the callback function
+ *
+ * This function can be used to set a callback to retrieve the username and
+ * password for client SRP authentication.
+ * The callback's function form is:
+ * int (*callback)(gnutls_session_t, unsigned int times, char** username,
+ * char** password);
+ *
+ * The @username and @password must be allocated using gnutls_malloc().
+ * @times will be 0 the first time called, and 1 the second.
+ * @username and @password should be ASCII strings or UTF-8 strings
+ * prepared using the "SASLprep" profile of "stringprep".
+ *
+ * The callback function will be called once or twice per handshake.
+ * The first time called, is before the ciphersuite is negotiated.
+ * At that time if the callback returns a negative error code,
+ * the callback will be called again if SRP has been
+ * negotiated. This uses a special TLS-SRP idiom in order to avoid
+ * asking the user for SRP password and username if the server does
+ * not support SRP.
+ *
+ * The callback should not return a negative error code the second
+ * time called, since the handshake procedure will be aborted.
+ *
+ * The callback function should return 0 on success.
+ * -1 indicates an error.
+ *
+ **/
+void
+gnutls_srp_set_client_credentials_function(gnutls_srp_client_credentials_t
+ cred,
+ gnutls_srp_client_credentials_function
+ * func)
+{
+ cred->get_function = func;
+}
+
+
+/**
+ * gnutls_srp_server_get_username - This function returns the username of the peer
+ * @session: is a gnutls session
+ *
+ * This function will return the username of the peer. This should only be
+ * called in case of SRP authentication and in case of a server.
+ * Returns NULL in case of an error.
+ *
+ **/
+const char *gnutls_srp_server_get_username(gnutls_session_t session)
+{
+ srp_server_auth_info_t info;
+
+ CHECK_AUTH(GNUTLS_CRD_SRP, NULL);
+
+ info = _gnutls_get_auth_info(session);
+ if (info == NULL)
+ return NULL;
+ return info->username;
+}
+
+/**
+ * gnutls_srp_verifier - Used to calculate an SRP verifier
+ * @username: is the user's name
+ * @password: is the user's password
+ * @salt: should be some randomly generated bytes
+ * @generator: is the generator of the group
+ * @prime: is the group's prime
+ * @res: where the verifier will be stored.
+ *
+ * This function will create an SRP verifier, as specified in RFC2945.
+ * The @prime and @generator should be one of the static parameters defined
+ * in gnutls/extra.h or may be generated using the GCRYPT functions
+ * gcry_prime_generate() and gcry_prime_group_generator().
+ * The verifier will be allocated with @malloc and will be stored in @res using
+ * binary format.
+ *
+ **/
+int gnutls_srp_verifier(const char *username, const char *password,
+ const gnutls_datum_t * salt,
+ const gnutls_datum_t * generator,
+ const gnutls_datum_t * prime, gnutls_datum_t * res)
+{
+ mpi_t _n, _g;
+ int ret;
+ size_t digest_size = 20, size;
+ opaque digest[20];
+
+ ret = _gnutls_calc_srp_sha(username, password, salt->data,
+ salt->size, &digest_size, digest);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ size = prime->size;
+ if (_gnutls_mpi_scan(&_n, prime->data, &size)) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ size = generator->size;
+ if (_gnutls_mpi_scan(&_g, generator->data, &size)) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ ret = _gnutls_srp_gx(digest, 20, &res->data, _g, _n, malloc);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ res->size = ret;
+
+ return 0;
+}
+
+#endif /* ENABLE_SRP */
diff --git a/lib/gnutls_srp.h b/lib/gnutls_srp.h
new file mode 100644
index 0000000000..1aeb6046a8
--- /dev/null
+++ b/lib/gnutls_srp.h
@@ -0,0 +1,15 @@
+#ifdef ENABLE_SRP
+
+int _gnutls_srp_gx(opaque *text, size_t textsize, opaque** result, mpi_t g, mpi_t prime, gnutls_alloc_function);
+mpi_t _gnutls_calc_srp_B(mpi_t * ret_b, mpi_t g, mpi_t n, mpi_t v);
+mpi_t _gnutls_calc_srp_u( mpi_t A, mpi_t B, size_t n_size);
+mpi_t _gnutls_calc_srp_S1(mpi_t A, mpi_t b, mpi_t u, mpi_t v, mpi_t n);
+mpi_t _gnutls_calc_srp_A(mpi_t *a, mpi_t g, mpi_t n);
+mpi_t _gnutls_calc_srp_S2(mpi_t B, mpi_t g, mpi_t x, mpi_t a, mpi_t u, mpi_t n);
+int _gnutls_calc_srp_x( char* username, char* password, opaque* salt, size_t salt_size, size_t* size, void* digest);
+int _gnutls_srp_gn( opaque** ret_g, opaque** ret_n, int bits);
+
+/* g is defined to be 2 */
+#define SRP_MAX_HASH_SIZE 24
+
+#endif