/* * Copyright (C) 2007-2012 Free Software Foundation, Inc. * * Author: Nikos Mavrogiannopoulos, Simon Josefsson * * This file is part of GnuTLS. * * GnuTLS is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuTLS 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GnuTLS; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include "utils.h" #include "../lib/gnutls_int.h" #include "../lib/gnutls_mpi.h" #include "../lib/gnutls_errors.h" #include "../lib/debug.h" static void tls_log_func (int level, const char *str) { fprintf (stderr, "|<%d>| %s", level, str); } #define RND_BITS 510 /* not multiple of 8 */ void doit (void) { int rc; bigint_t n1, n2, n3, n4; gnutls_global_init (); gnutls_global_set_log_function (tls_log_func); if (debug) gnutls_global_set_log_level (99); n1 = _gnutls_mpi_new (1000); if (n1 == NULL) fail ("mpi_new failed\n"); n2 = _gnutls_mpi_set_ui (NULL, 2); if (n2 == NULL) fail ("mpi_set_ui failed\n"); n3 = _gnutls_mpi_set_ui (NULL, 5); if (n3 == NULL) fail ("mpi_set_ui failed\n"); _gnutls_mpi_randomize (n1, RND_BITS, GNUTLS_RND_NONCE); _gnutls_mpi_log ("rand:", n1); rc = _gnutls_mpi_get_nbits (n1); if (rc > RND_BITS) fail ("mpi_get_nbits failed... returned %d\n", rc); n4 = _gnutls_mpi_addm (NULL, n1, n3, n2); if (n4 == NULL) fail ("mpi_set_ui failed\n"); if (_gnutls_mpi_cmp_ui (n4, 0) != 0 && _gnutls_mpi_cmp_ui (n4, 1) != 0) fail ("mpi_cmp_ui failed\n"); _gnutls_mpi_release (&n1); _gnutls_mpi_release (&n2); _gnutls_mpi_release (&n3); _gnutls_mpi_release (&n4); gnutls_global_deinit (); if (debug) success ("mpi ops ok\n"); }
/* Check if N is a prime and G a generator of the * group. This check is only done if N is big enough. * Otherwise only the included parameters must be used. */ static int group_check_g_n(gnutls_session_t session, bigint_t g, bigint_t n) { bigint_t q = NULL, two = NULL, w = NULL; int ret; if (_gnutls_mpi_get_nbits(n) < (session->internals.srp_prime_bits ? session->internals.srp_prime_bits : 2048)) { gnutls_assert(); return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } /* N must be of the form N=2q+1 * where q is also a prime. */ if (_gnutls_prime_check(n) != 0) { _gnutls_mpi_log("no prime N: ", n); gnutls_assert(); return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } ret = _gnutls_mpi_init_multi(&two, &q, &w, NULL); if (ret < 0) { gnutls_assert(); return ret; } /* q = n-1 */ ret = _gnutls_mpi_sub_ui(q, n, 1); if (ret < 0) { gnutls_assert(); goto error; } /* q = q/2, remember that q is divisible by 2 (prime - 1) */ ret = _gnutls_mpi_set_ui(two, 2); if (ret < 0) { gnutls_assert(); goto error; } ret = _gnutls_mpi_div(q, q, two); if (ret < 0) { gnutls_assert(); goto error; } if (_gnutls_prime_check(q) != 0) { /* N was not on the form N=2q+1, where q = prime */ _gnutls_mpi_log("no prime Q: ", q); gnutls_assert(); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto error; } /* 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; } /* check if g^q mod N == N-1 * w = g^q mod N */ ret = _gnutls_mpi_powm(w, g, q, n); if (ret < 0) { gnutls_assert(); goto error; } /* w++ */ ret = _gnutls_mpi_add_ui(w, w, 1); if (ret < 0) { gnutls_assert(); goto error; } 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; }
/* just read A and put it to session */ int _gnutls_proc_srp_client_kx(gnutls_session_t session, uint8_t * data, size_t _data_size) { ssize_t _n_A; ssize_t data_size = _data_size; int ret; DECR_LEN(data_size, 2); _n_A = _gnutls_read_uint16(&data[0]); DECR_LEN(data_size, _n_A); if (_gnutls_mpi_init_scan_nz(&A, &data[2], _n_A) || A == NULL) { gnutls_assert(); return GNUTLS_E_MPI_SCAN_FAILED; } _gnutls_mpi_log("SRP A: ", A); _gnutls_mpi_log("SRP B: ", B); /* Checks if A % n == 0. */ if ((ret = check_param_mod_n(A, N, 1)) < 0) { gnutls_assert(); return ret; } /* Start the SRP calculations. * - Calculate u */ session->key.u = _gnutls_calc_srp_u(A, B, N); if (session->key.u == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } _gnutls_mpi_log("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_mpi_log("SRP S: ", S); _gnutls_mpi_release(&A); zrelease_temp_mpi_key(&_b); zrelease_temp_mpi_key(&V); zrelease_temp_mpi_key(&session->key.u); zrelease_temp_mpi_key(&B); ret = _gnutls_mpi_dprint(session->key.srp_key, &session->key.key); zrelease_temp_mpi_key(&S); if (ret < 0) { gnutls_assert(); return ret; } return 0; }
/* return A = g^a % N */ int _gnutls_gen_srp_client_kx(gnutls_session_t session, gnutls_buffer_st * data) { int ret; char *username, *password; gnutls_srp_client_credentials_t cred; extension_priv_data_t epriv; srp_ext_st *priv; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SRP, &epriv); if (ret < 0) { /* peer didn't send a username */ gnutls_assert(); return GNUTLS_E_UNKNOWN_SRP_USERNAME; } priv = epriv; cred = (gnutls_srp_client_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_SRP); if (cred == NULL) { gnutls_assert(); return GNUTLS_E_INSUFFICIENT_CREDENTIALS; } if (priv->username == NULL) { username = cred->username; password = cred->password; } else { username = priv->username; password = priv->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; } 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); if (session->key.u == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } _gnutls_mpi_log("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_mpi_log("SRP B: ", B); zrelease_temp_mpi_key(&_b); zrelease_temp_mpi_key(&V); zrelease_temp_mpi_key(&session->key.u); zrelease_temp_mpi_key(&B); ret = _gnutls_mpi_dprint(session->key.srp_key, &session->key.key); zrelease_temp_mpi_key(&S); if (ret < 0) { gnutls_assert(); return ret; } ret = _gnutls_buffer_append_mpi(data, 16, A, 0); if (ret < 0) return gnutls_assert_val(ret); _gnutls_mpi_log("SRP A: ", A); _gnutls_mpi_release(&A); return data->length; }
/* 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, gnutls_buffer_st * data) { int ret; char *username; SRP_PWD_ENTRY *pwd_entry; srp_server_auth_info_t info; size_t tmp_size; extension_priv_data_t epriv; srp_ext_st *priv; ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SRP, &epriv); if (ret < 0) { /* peer didn't send a username */ gnutls_assert(); return GNUTLS_E_UNKNOWN_SRP_USERNAME; } priv = epriv; 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, GNUTLS_CRD_SRP); if (info == NULL) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); username = info->username; _gnutls_str_cpy(username, MAX_USERNAME_SIZE, priv->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) */ tmp_size = pwd_entry->g.size; if (_gnutls_mpi_init_scan_nz(&G, pwd_entry->g.data, tmp_size) < 0) { gnutls_assert(); ret = GNUTLS_E_MPI_SCAN_FAILED; goto cleanup; } tmp_size = pwd_entry->n.size; if (_gnutls_mpi_init_scan_nz(&N, pwd_entry->n.data, tmp_size) < 0) { gnutls_assert(); ret = GNUTLS_E_MPI_SCAN_FAILED; goto cleanup; } tmp_size = pwd_entry->v.size; if (_gnutls_mpi_init_scan_nz(&V, pwd_entry->v.data, tmp_size) < 0) { gnutls_assert(); ret = GNUTLS_E_MPI_SCAN_FAILED; goto cleanup; } /* Calculate: B = (k*v + g^b) % N */ B = _gnutls_calc_srp_B(&_b, G, N, V); if (B == NULL) { gnutls_assert(); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } /* copy N (mod n) */ ret = _gnutls_buffer_append_data_prefix(data, 16, pwd_entry->n.data, pwd_entry->n.size); if (ret < 0) { gnutls_assert(); goto cleanup; } /* copy G (generator) to data */ ret = _gnutls_buffer_append_data_prefix(data, 16, pwd_entry->g.data, pwd_entry->g.size); if (ret < 0) { gnutls_assert(); goto cleanup; } /* copy the salt */ ret = _gnutls_buffer_append_data_prefix(data, 8, pwd_entry->salt.data, pwd_entry->salt.size); if (ret < 0) { gnutls_assert(); goto cleanup; } /* Copy the B value */ ret = _gnutls_buffer_append_mpi(data, 16, B, 0); if (ret < 0) { gnutls_assert(); goto cleanup; } _gnutls_mpi_log("SRP B: ", B); ret = data->length; cleanup: _gnutls_srp_entry_free(pwd_entry); return ret; }
static int _rsa_generate_params (bigint_t * resarr, int *resarr_len, int bits) { int ret, i; gcry_sexp_t parms, key, list; bigint_t tmp; if (*resarr_len < RSA_PRIVATE_PARAMS) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } ret = gcry_sexp_build (&parms, NULL, "(genkey(rsa(nbits %d)))", bits); if (ret != 0) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } /* generate the RSA key */ ret = gcry_pk_genkey (&key, parms); gcry_sexp_release (parms); if (ret != 0) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } list = gcry_sexp_find_token (key, "n", 0); if (list == NULL) { gnutls_assert (); gcry_sexp_release (key); return GNUTLS_E_INTERNAL_ERROR; } resarr[0] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); list = gcry_sexp_find_token (key, "e", 0); if (list == NULL) { gnutls_assert (); gcry_sexp_release (key); return GNUTLS_E_INTERNAL_ERROR; } resarr[1] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); list = gcry_sexp_find_token (key, "d", 0); if (list == NULL) { gnutls_assert (); gcry_sexp_release (key); return GNUTLS_E_INTERNAL_ERROR; } resarr[2] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); list = gcry_sexp_find_token (key, "p", 0); if (list == NULL) { gnutls_assert (); gcry_sexp_release (key); return GNUTLS_E_INTERNAL_ERROR; } resarr[3] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); list = gcry_sexp_find_token (key, "q", 0); if (list == NULL) { gnutls_assert (); gcry_sexp_release (key); return GNUTLS_E_INTERNAL_ERROR; } resarr[4] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); list = gcry_sexp_find_token (key, "u", 0); if (list == NULL) { gnutls_assert (); gcry_sexp_release (key); return GNUTLS_E_INTERNAL_ERROR; } resarr[5] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); gcry_sexp_release (key); _gnutls_mpi_log ("n: ", resarr[0]); _gnutls_mpi_log ("e: ", resarr[1]); _gnutls_mpi_log ("d: ", resarr[2]); _gnutls_mpi_log ("p: ", resarr[3]); _gnutls_mpi_log ("q: ", resarr[4]); _gnutls_mpi_log ("u: ", resarr[5]); /* generate e1 and e2 */ *resarr_len = 6; tmp = _gnutls_mpi_alloc_like (resarr[0]); if (tmp == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ret = _gnutls_calc_rsa_exp (resarr, 2 + *resarr_len); if (ret < 0) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } (*resarr_len) += 2; return 0; cleanup: for (i = 0; i < *resarr_len; i++) _gnutls_mpi_release (&resarr[i]); return ret; }
static int _dsa_generate_params (bigint_t * resarr, int *resarr_len, int bits) { int ret; gcry_sexp_t parms, key, list; /* FIXME: Remove me once we depend on 1.3.1 */ if (bits > 1024 && gcry_check_version ("1.3.1") == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (bits < 512) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } ret = gcry_sexp_build (&parms, NULL, "(genkey(dsa(nbits %d)))", bits); if (ret != 0) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } /* generate the DSA key */ ret = gcry_pk_genkey (&key, parms); gcry_sexp_release (parms); if (ret != 0) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } list = gcry_sexp_find_token (key, "p", 0); if (list == NULL) { gnutls_assert (); gcry_sexp_release (key); return GNUTLS_E_INTERNAL_ERROR; } resarr[0] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); list = gcry_sexp_find_token (key, "q", 0); if (list == NULL) { gnutls_assert (); gcry_sexp_release (key); return GNUTLS_E_INTERNAL_ERROR; } resarr[1] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); list = gcry_sexp_find_token (key, "g", 0); if (list == NULL) { gnutls_assert (); gcry_sexp_release (key); return GNUTLS_E_INTERNAL_ERROR; } resarr[2] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); list = gcry_sexp_find_token (key, "y", 0); if (list == NULL) { gnutls_assert (); gcry_sexp_release (key); return GNUTLS_E_INTERNAL_ERROR; } resarr[3] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); list = gcry_sexp_find_token (key, "x", 0); if (list == NULL) { gnutls_assert (); gcry_sexp_release (key); return GNUTLS_E_INTERNAL_ERROR; } resarr[4] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); gcry_sexp_release (list); gcry_sexp_release (key); _gnutls_mpi_log ("p: ", resarr[0]); _gnutls_mpi_log ("q: ", resarr[1]); _gnutls_mpi_log ("g: ", resarr[2]); _gnutls_mpi_log ("y: ", resarr[3]); _gnutls_mpi_log ("x: ", resarr[4]); *resarr_len = 5; return 0; }
/* return A = g^a % N */ int _gnutls_gen_srp_client_kx (gnutls_session_t session, opaque ** data) { size_t n_a; int ret; uint8_t *data_a; char *username, *password; char buf[64]; gnutls_srp_client_credentials_t cred; cred = (gnutls_srp_client_credentials_t) _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; } 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); if (session->key->u == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } _gnutls_mpi_log ("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_mpi_log ("SRP B: ", B); _gnutls_mpi_release (&_b); _gnutls_mpi_release (&V); _gnutls_mpi_release (&session->key->u); _gnutls_mpi_release (&B); ret = _gnutls_mpi_dprint (session->key->KEY, &session->key->key); _gnutls_mpi_release (&S); if (ret < 0) { gnutls_assert (); return ret; } if (_gnutls_mpi_print (A, NULL, &n_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 (A, &data_a[2], &n_a) != 0) { gnutls_free (*data); return GNUTLS_E_MPI_PRINT_FAILED; } _gnutls_hard_log ("INT: SRP A[%d]: %s\n", (int) 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; }