diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-05-16 22:20:17 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-05-20 12:31:22 +0200 |
commit | 78b9114c2c025090262e5b365fc199ce2f88334b (patch) | |
tree | 36e81a209054f87f404a5a768ef3253f614e2f02 | |
parent | f90470a7b4c672a916c4513cecf4b9a6bce0eb67 (diff) | |
download | gnutls-78b9114c2c025090262e5b365fc199ce2f88334b.tar.gz |
Initial ecc support. Adds support for anonymous ECDH ciphersuites.
46 files changed, 2655 insertions, 17 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index bb5975cd6f..17a1b8732b 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -68,7 +68,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c gnutls_cipher.c \ gnutls_datum.c gnutls_session_pack.c gnutls_mpi.c \ gnutls_pk.c gnutls_cert.c gnutls_global.c gnutls_constate.c \ gnutls_anon_cred.c pkix_asn1_tab.c gnutls_asn1_tab.c \ - gnutls_mem.c gnutls_ui.c gnutls_sig.c \ + gnutls_mem.c gnutls_ui.c gnutls_sig.c gnutls_ecc.c \ gnutls_dh_primes.c gnutls_alert.c system.c \ gnutls_str.c gnutls_state.c gnutls_x509.c gnutls_rsa_export.c \ gnutls_helper.c gnutls_supplemental.c crypto.c random.c \ diff --git a/lib/auth/Makefile.am b/lib/auth/Makefile.am index c459ffe25a..92519def81 100644 --- a/lib/auth/Makefile.am +++ b/lib/auth/Makefile.am @@ -38,4 +38,5 @@ noinst_LTLIBRARIES = libgnutls_auth.la libgnutls_auth_la_SOURCES = anon.c cert.c dh_common.c dhe.c \ dhe_psk.c psk.c psk_passwd.c rsa.c rsa_export.c srp.c \ srp_passwd.c srp_rsa.c srp_sb64.c anon.h cert.h dh_common.h \ - psk.h psk_passwd.h srp.h srp_passwd.h + psk.h psk_passwd.h srp.h srp_passwd.h anon_ecdh.c \ + ecdh_common.c diff --git a/lib/auth/anon.h b/lib/auth/anon.h index ab5063d5a0..b2616df247 100644 --- a/lib/auth/anon.h +++ b/lib/auth/anon.h @@ -44,6 +44,7 @@ typedef struct gnutls_anon_client_credentials_st typedef struct anon_auth_info_st { dh_info_st dh; + ecc_curve_t curve; } *anon_auth_info_t; typedef struct anon_auth_info_st anon_auth_info_st; diff --git a/lib/auth/anon_ecdh.c b/lib/auth/anon_ecdh.c new file mode 100644 index 0000000000..5e9932faa3 --- /dev/null +++ b/lib/auth/anon_ecdh.c @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2009, 2010 Free + * Software Foundation, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains the Anonymous Diffie-Hellman key exchange part of + * the anonymous authentication. The functions here are used in the + * handshake. + */ + +#include <gnutls_int.h> + +#ifdef ENABLE_ANON + +#include "gnutls_auth.h" +#include "gnutls_errors.h" +#include "gnutls_dh.h" +#include "auth/anon.h" +#include "gnutls_num.h" +#include "gnutls_mpi.h" +#include <gnutls_state.h> +#include <auth/ecdh_common.h> +#include <ext/ecc.h> + +static int gen_anon_ecdh_server_kx (gnutls_session_t, gnutls_buffer_st*); +static int proc_anon_ecdh_client_kx (gnutls_session_t, opaque *, size_t); +static int proc_anon_ecdh_server_kx (gnutls_session_t, opaque *, size_t); + +const mod_auth_st anon_ecdh_auth_struct = { + "ANON ECDH", + NULL, + NULL, + gen_anon_ecdh_server_kx, + _gnutls_gen_ecdh_common_client_kx, /* this can be shared */ + NULL, + NULL, + + NULL, + NULL, /* certificate */ + proc_anon_ecdh_server_kx, + proc_anon_ecdh_client_kx, + NULL, + NULL +}; + +static int +gen_anon_ecdh_server_kx (gnutls_session_t session, gnutls_buffer_st* data) +{ + ecc_curve_t curve; + int ret; + gnutls_anon_server_credentials_t cred; + + cred = (gnutls_anon_server_credentials_t) + _gnutls_get_cred (session->key, GNUTLS_CRD_ANON, NULL); + if (cred == NULL) + { + gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + curve = _gnutls_session_ecc_curve_get(session); + if (curve == GNUTLS_ECC_CURVE_INVALID) + return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES); + + if ((ret = + _gnutls_auth_info_set (session, GNUTLS_CRD_ANON, + sizeof (anon_auth_info_st), 1)) < 0) + { + gnutls_assert (); + return ret; + } + + ret = _gnutls_ecdh_common_print_server_kx (session, data, curve); + if (ret < 0) + { + gnutls_assert (); + } + + return ret; +} + + +static int +proc_anon_ecdh_client_kx (gnutls_session_t session, opaque * data, + size_t _data_size) +{ + gnutls_anon_server_credentials_t cred; + ecc_curve_t curve; + + cred = (gnutls_anon_server_credentials_t) + _gnutls_get_cred (session->key, GNUTLS_CRD_ANON, NULL); + if (cred == NULL) + { + gnutls_assert (); + return GNUTLS_E_INSUFFICIENT_CREDENTIALS; + } + + curve = _gnutls_session_ecc_curve_get(session); + if (curve == GNUTLS_ECC_CURVE_INVALID) + return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES); + + return _gnutls_proc_ecdh_common_client_kx (session, data, _data_size, curve); +} + +int +proc_anon_ecdh_server_kx (gnutls_session_t session, opaque * data, + size_t _data_size) +{ + + int ret; + + /* set auth_info */ + if ((ret = + _gnutls_auth_info_set (session, GNUTLS_CRD_ANON, + sizeof (anon_auth_info_st), 1)) < 0) + { + gnutls_assert (); + return ret; + } + + ret = _gnutls_proc_ecdh_common_server_kx (session, data, _data_size); + if (ret < 0) + { + gnutls_assert (); + return ret; + } + + return 0; +} + +#endif /* ENABLE_ANON */ diff --git a/lib/auth/ecdh_common.c b/lib/auth/ecdh_common.c new file mode 100644 index 0000000000..e3d247e8c1 --- /dev/null +++ b/lib/auth/ecdh_common.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains common stuff in Ephemeral Diffie-Hellman (DHE) + * and Anonymous DH key exchange(DHA). These are used in the handshake + * procedure of the certificate and anoymous authentication. + */ + +#include "gnutls_int.h" +#include "gnutls_auth.h" +#include "gnutls_errors.h" +#include "gnutls_dh.h" +#include "gnutls_num.h" +#include "gnutls_sig.h" +#include <gnutls_datum.h> +#include <gnutls_x509.h> +#include <gnutls_state.h> +#include <auth/ecdh_common.h> +#include <gnutls_ecc.h> +#include <ext/ecc.h> +#include <gnutls_algorithms.h> +#include <auth/psk.h> +#include <gnutls_pk.h> + +static int calc_ecdh_key( gnutls_session_t session) +{ +gnutls_pk_params_st pub; +int ret; + + pub.params[0] = session->key->ecdh_params.params[0]; + pub.params[1] = session->key->ecdh_params.params[1]; + pub.params[2] = session->key->ecdh_params.params[2]; + pub.params[3] = session->key->ecdh_params.params[3]; + pub.params[4] = session->key->ecdh_x; + pub.params[5] = session->key->ecdh_y; + pub.params[6] = _gnutls_mpi_new(1); + if (pub.params[6] == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + _gnutls_mpi_set_ui(pub.params[6], 1); + + ret = _gnutls_pk_derive(GNUTLS_PK_ECDH, &session->key->key, &session->key->ecdh_params, &pub); + + _gnutls_mpi_release(&pub.params[6]); + + if (ret < 0) + return gnutls_assert_val(ret); + + return 0; +} + + +int +_gnutls_proc_ecdh_common_client_kx (gnutls_session_t session, + opaque * data, size_t _data_size, + ecc_curve_t curve) +{ + ssize_t data_size = _data_size; + int ret, i = 0; + int point_size; + + DECR_LEN (data_size, 1); + point_size = data[i]; + i+=1; + + DECR_LEN (data_size, point_size); + ret = _gnutls_ecc_ansi_x963_import(curve, &data[i], point_size, &session->key->ecdh_x, &session->key->ecdh_y); + if (ret < 0) + return gnutls_assert_val(ret); + + /* generate pre-shared key */ + ret = calc_ecdh_key(session); + if (ret < 0) + return gnutls_assert_val(ret); + + return 0; +} + +int +_gnutls_gen_ecdh_common_client_kx (gnutls_session_t session, gnutls_buffer_st* data) +{ + int ret; + gnutls_datum_t out; + int curve = _gnutls_session_ecc_curve_get(session); + + /* generate temporal key */ + ret = _gnutls_pk_generate(GNUTLS_PK_ECDH, curve, &session->key->ecdh_params); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_ecc_ansi_x963_export(curve, session->key->ecdh_params.params[4] /* x */, + session->key->ecdh_params.params[5] /* y */, &out); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_buffer_append_data_prefix(data, 8, out.data, out.size); + + _gnutls_free_datum(&out); + + if (ret < 0) + return gnutls_assert_val(ret); + + /* generate pre-shared key */ + ret = calc_ecdh_key(session); + if (ret < 0) + return gnutls_assert_val(ret); + + return data->length; +} + +int +_gnutls_proc_ecdh_common_server_kx (gnutls_session_t session, + opaque * data, size_t _data_size) +{ + int i, ret, point_size; + ecc_curve_t curve; + ssize_t data_size = _data_size; + + i = 0; + DECR_LEN (data_size, 1); + if (data[i++] != 3) + return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES); + + DECR_LEN (data_size, 2); + curve = _gnutls_num_to_ecc(_gnutls_read_uint16 (&data[i])); + i += 2; + + ret = _gnutls_session_supports_ecc_curve(session, curve); + if (ret < 0) + return gnutls_assert_val(ret); + + DECR_LEN (data_size, 1); + point_size = data[i]; + i+=1; + + DECR_LEN (data_size, point_size); + ret = _gnutls_ecc_ansi_x963_import(curve, &data[i], point_size, &session->key->ecdh_x, &session->key->ecdh_y); + if (ret < 0) + return gnutls_assert_val(ret); + + return ret; +} + +/* If the psk flag is set, then an empty psk_identity_hint will + * be inserted */ +int _gnutls_ecdh_common_print_server_kx (gnutls_session_t session, gnutls_buffer_st* data, + ecc_curve_t curve) +{ + opaque p; + int ret; + gnutls_datum_t out; + + /* curve type */ + p = 3; + + ret = _gnutls_buffer_append_data(data, &p, 1); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_buffer_append_prefix(data, 16, _gnutls_ecc_to_num(curve)); + if (ret < 0) + return gnutls_assert_val(ret); + + /* generate temporal key */ + ret = _gnutls_pk_generate(GNUTLS_PK_ECDH, curve, &session->key->ecdh_params); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_ecc_ansi_x963_export(curve, session->key->ecdh_params.params[4] /* x */, + session->key->ecdh_params.params[5] /* y */, &out); + if (ret < 0) + return gnutls_assert_val(ret); + + ret = _gnutls_buffer_append_data_prefix(data, 8, out.data, out.size); + + _gnutls_free_datum(&out); + + if (ret < 0) + return gnutls_assert_val(ret); + + return data->length; +} diff --git a/lib/auth/ecdh_common.h b/lib/auth/ecdh_common.h new file mode 100644 index 0000000000..1fa6eba39a --- /dev/null +++ b/lib/auth/ecdh_common.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +#ifndef AUTH_ECDH_COMMON +#define AUTH_ECDH_COMMON + +#include <gnutls_auth.h> + +int _gnutls_gen_ecdh_common_client_kx (gnutls_session_t, gnutls_buffer_st*); +int _gnutls_proc_ecdh_common_client_kx (gnutls_session_t session, + opaque * data, size_t _data_size, + ecc_curve_t curve); +int _gnutls_ecdh_common_print_server_kx (gnutls_session_t, gnutls_buffer_st* data, + ecc_curve_t curve); +int _gnutls_proc_ecdh_common_server_kx (gnutls_session_t session, opaque * data, + size_t _data_size); + + + +#endif diff --git a/lib/ext/Makefile.am b/lib/ext/Makefile.am index a949912125..90dcb072ab 100644 --- a/lib/ext/Makefile.am +++ b/lib/ext/Makefile.am @@ -39,4 +39,4 @@ libgnutls_ext_la_SOURCES = max_record.c cert_type.c \ server_name.c signature.c safe_renegotiation.c \ max_record.h cert_type.h server_name.h srp.h \ session_ticket.h signature.h safe_renegotiation.h \ - session_ticket.c srp.c + session_ticket.c srp.c ecc.c diff --git a/lib/ext/ecc.c b/lib/ext/ecc.c new file mode 100644 index 0000000000..11c00716e4 --- /dev/null +++ b/lib/ext/ecc.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2002, 2003, 2004, 2005, 2010 Free Software Foundation, + * Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* This file contains the code the Certificate Type TLS extension. + * This extension is currently gnutls specific. + */ + +#include "gnutls_int.h" +#include "gnutls_errors.h" +#include "gnutls_num.h" +#include <ext/ecc.h> +#include <gnutls_state.h> +#include <gnutls_num.h> + +/* Maps record size to numbers according to the + * extensions draft. + */ + +static int _gnutls_supported_ecc_recv_params (gnutls_session_t session, + const opaque * data, + size_t data_size); +static int _gnutls_supported_ecc_send_params (gnutls_session_t session, + gnutls_buffer_st * extdata); + +static int _gnutls_supported_ecc_pf_recv_params (gnutls_session_t session, + const opaque * data, + size_t data_size); +static int _gnutls_supported_ecc_pf_send_params (gnutls_session_t session, + gnutls_buffer_st * extdata); + +extension_entry_st ext_mod_supported_ecc = { + .name = "SUPPORTED ECC", + .type = GNUTLS_EXTENSION_SUPPORTED_ECC, + .parse_type = GNUTLS_EXT_TLS, + + .recv_func = _gnutls_supported_ecc_recv_params, + .send_func = _gnutls_supported_ecc_send_params, + .pack_func = NULL, + .unpack_func = NULL, + .deinit_func = NULL +}; + +extension_entry_st ext_mod_supported_ecc_pf = { + .name = "SUPPORTED ECC POINT FORMATS", + .type = GNUTLS_EXTENSION_SUPPORTED_ECC_PF, + .parse_type = GNUTLS_EXT_TLS, + + .recv_func = _gnutls_supported_ecc_pf_recv_params, + .send_func = _gnutls_supported_ecc_pf_send_params, + .pack_func = NULL, + .unpack_func = NULL, + .deinit_func = NULL +}; + +/* + * In case of a server: if a SUPPORTED_ECC extension type is received then it stores + * into the session security parameters the new value. The server may use gnutls_session_certificate_type_get(), + * to access it. + * + * In case of a client: If a supported_eccs have been specified then we send the extension. + * + */ +static int +_gnutls_supported_ecc_recv_params (gnutls_session_t session, + const opaque * data, size_t _data_size) +{ + int new_type = -1, ret, i; + ssize_t data_size = _data_size; + uint16_t len; + const opaque* p = data; + + if (session->security_parameters.entity == GNUTLS_CLIENT) + { + /* A client shouldn't receive this extension */ + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION); + } + else + { /* SERVER SIDE - we must check if the sent supported ecc type is the right one + */ + if (data_size < 2) + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION); + + DECR_LEN (data_size, 2); + len = _gnutls_read_uint16(p); + p += 2; + + DECR_LEN (data_size, len); + + for (i = 0; i < len; i+=2) + { + new_type = _gnutls_num_to_ecc (_gnutls_read_uint16(&p[i])); + if (new_type < 0) + continue; + + /* Check if we support this supported_ecc */ + if ((ret = + _gnutls_session_supports_ecc_curve (session, new_type)) < 0) + { + gnutls_assert (); + continue; + } + else + break; + /* new_type is ok */ + } + + if (new_type < 0) + { + gnutls_assert (); + return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + } + + if ((ret = + _gnutls_session_supports_ecc_curve (session, new_type)) < 0) + { + /* The peer has requested unsupported ecc + * types. Instead of failing, procceed normally. + * (the ciphersuite selection would fail, or a + * non certificate ciphersuite will be selected). + */ + return gnutls_assert_val(0); + } + + _gnutls_session_ecc_curve_set (session, new_type); + } + + return 0; +} + + +/* returns data_size or a negative number on failure + */ +static int +_gnutls_supported_ecc_send_params (gnutls_session_t session, gnutls_buffer_st* extdata) +{ + unsigned len, i; + int ret; + uint16_t p; + + /* this extension is only being sent on client side */ + if (session->security_parameters.entity == GNUTLS_CLIENT) + { + + if (session->internals.priorities.supported_ecc.algorithms > 0) + { + + len = session->internals.priorities.supported_ecc.algorithms; + + /* this is a vector! + */ + ret = _gnutls_buffer_append_prefix(extdata, 16, len*2); + if (ret < 0) + return gnutls_assert_val(ret); + + for (i = 0; i < len; i++) + { + p = + _gnutls_ecc_to_num (session->internals.priorities. + supported_ecc.priority[i]); + ret = _gnutls_buffer_append_prefix(extdata, 16, p); + if (ret < 0) + return gnutls_assert_val(ret); + } + return (len + 1)*2; + } + + } + + return 0; +} + +/* + * In case of a server: if a SUPPORTED_ECC extension type is received then it stores + * into the session security parameters the new value. The server may use gnutls_session_certificate_type_get(), + * to access it. + * + * In case of a client: If a supported_eccs have been specified then we send the extension. + * + */ +static int +_gnutls_supported_ecc_pf_recv_params (gnutls_session_t session, + const opaque * data, size_t _data_size) +{ +int len, i; +int uncompressed = 0; +int data_size = _data_size; + + if (session->security_parameters.entity == GNUTLS_CLIENT) + { + if (data_size < 1) + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION); + + len = data[0]; + DECR_LEN (data_size, len+1); + + for (i=0;i<len;i++) + if (data[1+i] == 0) /* uncompressed */ + uncompressed = 1; + + if (uncompressed == 0) + return gnutls_assert_val(GNUTLS_E_UNKNOWN_PK_ALGORITHM); + } + else + { + /* only sanity check here. We only support uncompressed points + * and a client must support it thus nothing to check. + */ + if (_data_size < 1) + return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION); + } + + return 0; +} + +/* returns data_size or a negative number on failure + */ +static int +_gnutls_supported_ecc_pf_send_params (gnutls_session_t session, gnutls_buffer_st* extdata) +{ + const opaque p[2] = {0x01, 0x00}; /* only support uncompressed point format */ + + /* this extension is only being sent on client and server side */ + _gnutls_buffer_append_data(extdata, p, 2); + return 2; +} + +/* Maps numbers to record sizes according to the + * extensions draft. + */ +int +_gnutls_num_to_ecc (int num) +{ + switch (num) + { + case 23: + /* sec256r1 */ + return GNUTLS_ECC_CURVE_SECP256R1; + case 24: + return GNUTLS_ECC_CURVE_SECP384R1; + default: + return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + } +} + +/* Maps record size to numbers according to the + * extensions draft. + */ +int +_gnutls_ecc_to_num (ecc_curve_t supported_ecc) +{ + switch (supported_ecc) + { + case GNUTLS_ECC_CURVE_SECP256R1: + return 23; + case GNUTLS_ECC_CURVE_SECP384R1: + return 24; + default: + return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; + } +} + +/* Returns 0 if the given ECC curve is allowed in the current + * session. A negative error value is returned otherwise. + */ +int +_gnutls_session_supports_ecc_curve (gnutls_session_t session, int ecc_type) +{ + unsigned i; + + if (session->internals.priorities.supported_ecc.algorithms > 0) + { + for (i = 0; i < session->internals.priorities.supported_ecc.algorithms; i++) + { + if (session->internals.priorities.supported_ecc.priority[i] == ecc_type) + return 0; + } + } + + return GNUTLS_E_ECC_NO_SUPPORTED_CURVES; +} diff --git a/lib/ext/ecc.h b/lib/ext/ecc.h new file mode 100644 index 0000000000..745a000815 --- /dev/null +++ b/lib/ext/ecc.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ +#ifndef EXT_ECC_H +#define EXT_ECC_H + +#include <gnutls_extensions.h> + +extern extension_entry_st ext_mod_supported_ecc; +extern extension_entry_st ext_mod_supported_ecc_pf; + +int _gnutls_num_to_ecc (int num); +int _gnutls_ecc_to_num (ecc_curve_t); +int +_gnutls_session_supports_ecc_curve (gnutls_session_t session, int ecc_type); + +#endif diff --git a/lib/gnutls_algorithms.c b/lib/gnutls_algorithms.c index b54e5cd9e4..295bb87e26 100644 --- a/lib/gnutls_algorithms.c +++ b/lib/gnutls_algorithms.c @@ -70,6 +70,7 @@ typedef struct static const gnutls_cred_map cred_mappings[] = { {GNUTLS_KX_ANON_DH, GNUTLS_CRD_ANON, GNUTLS_CRD_ANON}, + {GNUTLS_KX_ANON_ECDH, GNUTLS_CRD_ANON, GNUTLS_CRD_ANON}, {GNUTLS_KX_RSA, GNUTLS_CRD_CERTIFICATE, GNUTLS_CRD_CERTIFICATE}, {GNUTLS_KX_RSA_EXPORT, GNUTLS_CRD_CERTIFICATE, GNUTLS_CRD_CERTIFICATE}, {GNUTLS_KX_DHE_DSS, GNUTLS_CRD_CERTIFICATE, GNUTLS_CRD_CERTIFICATE}, @@ -260,6 +261,7 @@ 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 anon_ecdh_auth_struct; extern mod_auth_st srp_auth_struct; extern mod_auth_st psk_auth_struct; extern mod_auth_st dhe_psk_auth_struct; @@ -279,6 +281,7 @@ typedef struct gnutls_kx_algo_entry gnutls_kx_algo_entry; static const gnutls_kx_algo_entry _gnutls_kx_algorithms[] = { #ifdef ENABLE_ANON {"ANON-DH", GNUTLS_KX_ANON_DH, &anon_auth_struct, 1, 0}, + {"ANON-ECDH", GNUTLS_KX_ANON_ECDH, &anon_ecdh_auth_struct, 0, 0}, #endif {"RSA", GNUTLS_KX_RSA, &rsa_auth_struct, 0, 0}, {"RSA-EXPORT", GNUTLS_KX_RSA_EXPORT, &rsa_export_auth_struct, 0, @@ -463,7 +466,11 @@ typedef struct #define GNUTLS_PSK_NULL_SHA256 { 0x00, 0xB0 } #define GNUTLS_DHE_PSK_NULL_SHA256 { 0x00, 0xB4 } -/* Safe renegotiation */ +/* ECC */ +#define GNUTLS_ECDH_ANON_3DES_EDE_CBC_SHA { 0xC0, 0x17 } +#define GNUTLS_ECDH_ANON_AES_128_CBC_SHA { 0xC0, 0x18 } +#define GNUTLS_ECDH_ANON_AES_256_CBC_SHA { 0xC0, 0x19 } + #define CIPHER_SUITES_COUNT sizeof(cs_algorithms)/sizeof(gnutls_cipher_suite_entry)-1 @@ -761,6 +768,19 @@ static const gnutls_cipher_suite_entry cs_algorithms[] = { GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_ANON_DH, GNUTLS_MAC_AEAD, GNUTLS_TLS1_2, GNUTLS_VERSION_MAX, 1), +/* ECC-ANON */ + GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_ECDH_ANON_3DES_EDE_CBC_SHA, + GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_ANON_ECDH, + GNUTLS_MAC_SHA1, GNUTLS_TLS1_0, + GNUTLS_VERSION_MAX, 1), + GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_ECDH_ANON_AES_128_CBC_SHA, + GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_ANON_ECDH, + GNUTLS_MAC_SHA1, GNUTLS_TLS1_0, + GNUTLS_VERSION_MAX, 1), + GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_ECDH_ANON_AES_256_CBC_SHA, + GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_ANON_ECDH, + GNUTLS_MAC_SHA1, GNUTLS_TLS1_0, + GNUTLS_VERSION_MAX, 1), {0, {{0, 0}}, 0, 0, 0, 0, 0, 0} }; @@ -2174,6 +2194,109 @@ _gnutls_sign_to_tls_aid (gnutls_sign_algorithm_t sign) return ret; } +/* ECC curves; + */ + +static const gnutls_ecc_curve_entry_st ecc_curves[] = { + { + .name = "SECP256R1", + .id = GNUTLS_ECC_CURVE_SECP256R1, + .size = 32, + .prime = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", + .B = "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", + .order = "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", + .Gx = "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", + .Gy = "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", + }, + { + .name = "SECP384R1", + .id = GNUTLS_ECC_CURVE_SECP384R1, + .size = 48, + .prime = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", + .B = "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", + .order = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", + .Gx = "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", + .Gy = "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F" + }, + {0, 0, 0} +}; + +#define GNUTLS_ECC_CURVE_LOOP(b) \ + { const gnutls_ecc_curve_entry_st *p; \ + for(p = ecc_curves; p->name != NULL; p++) { b ; } } + +/*- + * _gnutls_ecc_curve_get_name: + * @curve: is an ECC curve + * + * Convert a #ecc_curve_t value to a string. + * + * Returns: a string that contains the name of the specified + * curve or %NULL. + -*/ +const char * +_gnutls_ecc_curve_get_name (ecc_curve_t curve) +{ + const char *ret = NULL; + + GNUTLS_ECC_CURVE_LOOP( + if (p->id == curve) + { + ret = p->name; + break; + } + ); + + return ret; +} + +/*- + * _gnutls_ecc_curve_get_params: + * @curve: is an ECC curve + * + * Returns the information on a curve. + * + * Returns: a pointer to #gnutls_ecc_curve_entry_st or %NULL. + -*/ +const gnutls_ecc_curve_entry_st * +_gnutls_ecc_curve_get_params (ecc_curve_t curve) +{ + const gnutls_ecc_curve_entry_st *ret = NULL; + + GNUTLS_ECC_CURVE_LOOP( + if (p->id == curve) + { + ret = p; + break; + } + ); + + return ret; +} + +/*- + * _gnutls_ecc_curve_get_size: + * @curve: is an ECC curve + * + * Returns the size in bytes of the curve. + * + * Returns: a the size or zero. + -*/ +int _gnutls_ecc_curve_get_size (ecc_curve_t curve) +{ + int ret = 0; + + GNUTLS_ECC_CURVE_LOOP( + if (p->id == curve) + { + ret = p->size; + break; + } + ); + + return ret; +} + /* pk algorithms; @@ -2197,6 +2320,7 @@ static const gnutls_pk_entry pk_algorithms[] = { {"DSA", PK_DSA_OID, GNUTLS_PK_DSA}, {"GOST R 34.10-2001", PK_GOST_R3410_2001_OID, GNUTLS_PK_UNKNOWN}, {"GOST R 34.10-94", PK_GOST_R3410_94_OID, GNUTLS_PK_UNKNOWN}, + {"ECDH", "1.2.840.10045.2.1", GNUTLS_PK_ECDH}, {0, 0, 0} }; diff --git a/lib/gnutls_algorithms.h b/lib/gnutls_algorithms.h index 5c867b8dc6..049c1e218a 100644 --- a/lib/gnutls_algorithms.h +++ b/lib/gnutls_algorithms.h @@ -125,4 +125,28 @@ int _gnutls_kx_priority (gnutls_session_t session, unsigned int _gnutls_pk_bits_to_subgroup_bits (unsigned int pk_bits); +/* ECC */ +struct gnutls_ecc_curve_entry_st +{ + const char *name; + ecc_curve_t id; + int size; /* the size in bytes */ + + /** The prime that defines the field the curve is in (encoded in hex) */ + const char *prime; + /** The fields B param (hex) */ + const char *B; + /** The order of the curve (hex) */ + const char *order; + /** The x co-ordinate of the base point on the curve (hex) */ + const char *Gx; + /** The y co-ordinate of the base point on the curve (hex) */ + const char *Gy; +}; +typedef struct gnutls_ecc_curve_entry_st gnutls_ecc_curve_entry_st; + +const char * _gnutls_ecc_curve_get_name (ecc_curve_t curve); +const gnutls_ecc_curve_entry_st * _gnutls_ecc_curve_get_params (ecc_curve_t curve); +int _gnutls_ecc_curve_get_size (ecc_curve_t curve); + #endif diff --git a/lib/gnutls_dh.c b/lib/gnutls_dh.c index 2c6a6c32a2..0badeece14 100644 --- a/lib/gnutls_dh.c +++ b/lib/gnutls_dh.c @@ -147,3 +147,4 @@ _gnutls_get_dh_params (gnutls_dh_params_t dh_params, return session->internals.params.dh_params; } + diff --git a/lib/gnutls_ecc.c b/lib/gnutls_ecc.c new file mode 100644 index 0000000000..c15600836c --- /dev/null +++ b/lib/gnutls_ecc.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA + * + */ + +/* Helper functions for ECC handling + * based on public domain code by Tom St. Dennis. + */ +#include <gnutls_int.h> +#include <gnutls_mpi.h> +#include <gnutls_ecc.h> +#include <gnutls_algorithms.h> +#include <gnutls_errors.h> + +int _gnutls_ecc_ansi_x963_export(ecc_curve_t curve, bigint_t x, bigint_t y, gnutls_datum_t * out) +{ + int numlen = _gnutls_ecc_curve_get_size(curve); + int byte_size, ret; + size_t size; + + if (numlen == 0) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + out->size = 1 + 2*numlen; + + out->data = gnutls_malloc(out->size); + if (out->data == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + memset(out->data, 0, out->size); + + /* store byte 0x04 */ + out->data[0] = 0x04; + + /* pad and store x */ + byte_size = (_gnutls_mpi_get_nbits(x)+7)/8; + size = out->size - (1+(numlen-byte_size)); + ret = _gnutls_mpi_print(x, &out->data[1+(numlen-byte_size)], &size); + if (ret < 0) + return gnutls_assert_val(ret); + + byte_size = (_gnutls_mpi_get_nbits(y)+7)/8; + size = out->size - (1+(numlen+numlen-byte_size)); + ret = _gnutls_mpi_print(y, &out->data[1+numlen+numlen-byte_size], &size); + if (ret < 0) + return gnutls_assert_val(ret); + + /* pad and store y */ + return 0; +} + + +int _gnutls_ecc_ansi_x963_import(ecc_curve_t curve, const opaque *in, unsigned long inlen, bigint_t* x, bigint_t* y) +{ + int ret; + int numlen = _gnutls_ecc_curve_get_size(curve); + + /* must be odd */ + if ((inlen & 1) == 0 || numlen == 0) + { + return GNUTLS_E_INVALID_REQUEST; + } + + /* check for 4, 6 or 7 */ + if (in[0] != 4 && in[0] != 6 && in[0] != 7) { + return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); + } + + /* read data */ + ret = _gnutls_mpi_scan(x, in+1, (inlen-1)>>1); + if (ret < 0) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + ret = _gnutls_mpi_scan(y, in+1+((inlen-1)>>1), (inlen-1)>>1); + if (ret < 0) + { + _gnutls_mpi_release(x); + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + } + + return 0; +} diff --git a/lib/gnutls_ecc.h b/lib/gnutls_ecc.h new file mode 100644 index 0000000000..5f91ac5800 --- /dev/null +++ b/lib/gnutls_ecc.h @@ -0,0 +1,2 @@ +int _gnutls_ecc_ansi_x963_import(ecc_curve_t curve, const opaque *in, unsigned long inlen, bigint_t* x, bigint_t* y); +int _gnutls_ecc_ansi_x963_export(ecc_curve_t curve, bigint_t x, bigint_t y, gnutls_datum_t * out); diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index c5405694d1..9f700b7e08 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -328,6 +328,8 @@ static const gnutls_error_entry error_algorithms[] = { GNUTLS_E_TIMEDOUT, 1), ERROR_ENTRY (N_("The operation was cancelled due to user error"), GNUTLS_E_USER_ERROR, 1), + ERROR_ENTRY (N_("No supported ECC curves were found"), + GNUTLS_E_ECC_NO_SUPPORTED_CURVES, 1), {NULL, NULL, 0, 0} }; diff --git a/lib/gnutls_extensions.c b/lib/gnutls_extensions.c index 5f2116729a..215685154b 100644 --- a/lib/gnutls_extensions.c +++ b/lib/gnutls_extensions.c @@ -39,6 +39,7 @@ #include <ext/safe_renegotiation.h> #include <ext/signature.h> #include <ext/safe_renegotiation.h> +#include <ext/ecc.h> #include <gnutls_num.h> @@ -334,6 +335,14 @@ _gnutls_ext_init (void) if (ret != GNUTLS_E_SUCCESS) return ret; + ret = _gnutls_ext_register (&ext_mod_supported_ecc); + if (ret != GNUTLS_E_SUCCESS) + return ret; + + ret = _gnutls_ext_register (&ext_mod_supported_ecc_pf); + if (ret != GNUTLS_E_SUCCESS) + return ret; + ret = _gnutls_ext_register (&ext_mod_sig); if (ret != GNUTLS_E_SUCCESS) return ret; diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c index c69adcf74d..0499002b68 100644 --- a/lib/gnutls_global.c +++ b/lib/gnutls_global.c @@ -186,6 +186,7 @@ static int _gnutls_init = 0; * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned, * otherwise an error code is returned. **/ +int ecc_test(void); int gnutls_global_init (void) { @@ -194,6 +195,10 @@ gnutls_global_init (void) if (_gnutls_init++) goto out; + + res = ecc_test(); + if (res != 0) + exit(1); if (gl_sockets_startup (SOCKETS_1_1)) return GNUTLS_E_LIBRARY_VERSION_MISMATCH; diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index ab9776ec92..d67bddb0b3 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -217,6 +217,8 @@ typedef enum extensions_t GNUTLS_EXTENSION_SERVER_NAME = 0, GNUTLS_EXTENSION_MAX_RECORD_SIZE = 1, GNUTLS_EXTENSION_CERT_TYPE = 9, + GNUTLS_EXTENSION_SUPPORTED_ECC = 10, + GNUTLS_EXTENSION_SUPPORTED_ECC_PF = 11, GNUTLS_EXTENSION_SRP = 12, GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS = 13, GNUTLS_EXTENSION_SESSION_TICKET = 35, @@ -224,6 +226,13 @@ typedef enum extensions_t } extensions_t; typedef enum +{ + GNUTLS_ECC_CURVE_INVALID=0, + GNUTLS_ECC_CURVE_SECP256R1, + GNUTLS_ECC_CURVE_SECP384R1, +} ecc_curve_t; + +typedef enum { CIPHER_STREAM, CIPHER_BLOCK } cipher_type_t; #define RESUME_TRUE 0 @@ -339,6 +348,11 @@ typedef struct auth_cred_st struct gnutls_key_st { + /* For ECDH KX */ + gnutls_pk_params_st ecdh_params; + bigint_t ecdh_x; + bigint_t ecdh_y; + /* For DH KX */ gnutls_datum_t key; bigint_t KEY; @@ -470,6 +484,7 @@ typedef struct uint16_t max_record_recv_size; /* holds the negotiated certificate type */ gnutls_certificate_type_t cert_type; + ecc_curve_t ecc_curve; /* holds the first supported ECC curve requested by client */ gnutls_protocol_t version; /* moved here */ /* FIXME: The following are not saved in the session storage @@ -543,6 +558,7 @@ struct gnutls_priority_st priority_st protocol; priority_st cert_type; priority_st sign_algo; + priority_st supported_ecc; /* to disable record padding */ int no_padding:1; diff --git a/lib/gnutls_pk.c b/lib/gnutls_pk.c index f6284fd1c4..5fc3aa216f 100644 --- a/lib/gnutls_pk.c +++ b/lib/gnutls_pk.c @@ -531,7 +531,7 @@ _generate_params (int algo, bigint_t * resarr, unsigned int *resarr_len, int ret; unsigned int i; - ret = _gnutls_pk_ops.generate (algo, bits, ¶ms); + ret = _gnutls_pk_generate (algo, bits, ¶ms); if (ret < 0) { diff --git a/lib/gnutls_pk.h b/lib/gnutls_pk.h index f9b5174d56..07a1acd7e9 100644 --- a/lib/gnutls_pk.h +++ b/lib/gnutls_pk.h @@ -33,6 +33,8 @@ extern gnutls_crypto_pk_st _gnutls_pk_ops; #define _gnutls_pk_decrypt( algo, ciphertext, plaintext, params) _gnutls_pk_ops.decrypt( algo, ciphertext, plaintext, params) #define _gnutls_pk_sign( algo, sig, data, params) _gnutls_pk_ops.sign( algo, sig, data, params) #define _gnutls_pk_verify( algo, data, sig, params) _gnutls_pk_ops.verify( algo, data, sig, params) +#define _gnutls_pk_derive( algo, out, pub, priv) _gnutls_pk_ops.derive( algo, out, pub, priv) +#define _gnutls_pk_generate( algo, bits, priv) _gnutls_pk_ops.generate( algo, bits, priv) inline static int _gnutls_pk_fixup (gnutls_pk_algorithm_t algo, gnutls_direction_t direction, diff --git a/lib/gnutls_priority.c b/lib/gnutls_priority.c index ec3dee3a4c..c06a22dc28 100644 --- a/lib/gnutls_priority.c +++ b/lib/gnutls_priority.c @@ -215,6 +215,12 @@ gnutls_certificate_type_set_priority (gnutls_session_t session, #endif } +static const int supported_ecc_default[] = { + GNUTLS_ECC_CURVE_SECP256R1, + GNUTLS_ECC_CURVE_SECP384R1, + 0 +}; + static const int protocol_priority[] = { GNUTLS_TLS1_2, GNUTLS_TLS1_1, @@ -570,10 +576,12 @@ gnutls_priority_init (gnutls_priority_t * priority_cache, _set_priority (&(*priority_cache)->compression, comp_priority); _set_priority (&(*priority_cache)->cert_type, cert_type_priority); _set_priority (&(*priority_cache)->sign_algo, sign_priority_default); + _set_priority (&(*priority_cache)->supported_ecc, supported_ecc_default); i = 0; } else { + _set_priority (&(*priority_cache)->supported_ecc, supported_ecc_default); i = 1; } diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c index a8111ba7a7..ab4d9d0793 100644 --- a/lib/gnutls_state.c +++ b/lib/gnutls_state.c @@ -65,6 +65,14 @@ _gnutls_session_cert_type_set (gnutls_session_t session, session->security_parameters.cert_type = ct; } +void +_gnutls_session_ecc_curve_set (gnutls_session_t session, + ecc_curve_t c) +{ + _gnutls_handshake_log("HSK[%p]: Selected ECC curve (%d)\n", session, c); + session->security_parameters.ecc_curve = c; +} + /** * gnutls_cipher_get: * @session: is a #gnutls_session_t structure. @@ -443,6 +451,10 @@ gnutls_deinit (gnutls_session_t session) if (session->key != NULL) { + gnutls_pk_params_release(&session->key->ecdh_params); + _gnutls_mpi_release (&session->key->ecdh_x); + _gnutls_mpi_release (&session->key->ecdh_y); + _gnutls_mpi_release (&session->key->KEY); _gnutls_mpi_release (&session->key->client_Y); _gnutls_mpi_release (&session->key->client_p); diff --git a/lib/gnutls_state.h b/lib/gnutls_state.h index 8132a2ffcd..edd4b0dab1 100644 --- a/lib/gnutls_state.h +++ b/lib/gnutls_state.h @@ -30,6 +30,16 @@ void _gnutls_session_cert_type_set (gnutls_session_t session, gnutls_certificate_type_t); + +inline static ecc_curve_t _gnutls_session_ecc_curve_get(gnutls_session_t session) +{ + return session->security_parameters.ecc_curve; +} + +void +_gnutls_session_ecc_curve_set (gnutls_session_t session, + ecc_curve_t c); + void _gnutls_record_set_default_version (gnutls_session_t session, unsigned char major, unsigned char minor); diff --git a/lib/includes/gnutls/crypto.h b/lib/includes/gnutls/crypto.h index a1cf4b5ba8..0f37a6def0 100644 --- a/lib/includes/gnutls/crypto.h +++ b/lib/includes/gnutls/crypto.h @@ -278,6 +278,16 @@ extern "C" * [2] is g * [3] is y (public key) * [4] is x (private key only) + * + * ECDH: + * [0] is prime + * [1] is order + * [2] is Gx + * [3] is Gy + * [4] is x + * [5] is y + * [6] is z + * [7] is k (private key) */ /** @@ -311,7 +321,6 @@ extern "C" int (*verify) (gnutls_pk_algorithm_t, const gnutls_datum_t * data, const gnutls_datum_t * signature, const gnutls_pk_params_st * pub); - int (*generate) (gnutls_pk_algorithm_t, unsigned int nbits, gnutls_pk_params_st *); /* this function should convert params to ones suitable @@ -319,6 +328,10 @@ extern "C" */ int (*pk_fixup_private_params) (gnutls_pk_algorithm_t, gnutls_direction_t, gnutls_pk_params_st *); + int (*derive) (gnutls_pk_algorithm_t, gnutls_datum_t * out, + const gnutls_pk_params_st * priv, + const gnutls_pk_params_st * pub); + } gnutls_crypto_pk_st; diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index f85b6b397b..053970f3b4 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -129,6 +129,7 @@ extern "C" * @GNUTLS_KX_DHE_DSS: DHE-DSS key-exchange algorithm. * @GNUTLS_KX_DHE_RSA: DHE-RSA key-exchange algorithm. * @GNUTLS_KX_ANON_DH: Anon-DH key-exchange algorithm. + * @GNUTLS_KX_ANON_ECDH: Anon-ECDH key-exchange algorithm. * @GNUTLS_KX_SRP: SRP key-exchange algorithm. * @GNUTLS_KX_RSA_EXPORT: RSA-EXPORT key-exchange algorithm. * @GNUTLS_KX_SRP_RSA: SRP-RSA key-exchange algorithm. @@ -150,7 +151,8 @@ extern "C" GNUTLS_KX_SRP_RSA = 7, GNUTLS_KX_SRP_DSS = 8, GNUTLS_KX_PSK = 9, - GNUTLS_KX_DHE_PSK = 10 + GNUTLS_KX_DHE_PSK = 10, + GNUTLS_KX_ANON_ECDH = 11, } gnutls_kx_algorithm_t; /** @@ -163,7 +165,8 @@ extern "C" typedef enum { GNUTLS_PARAMS_RSA_EXPORT = 1, - GNUTLS_PARAMS_DH = 2 + GNUTLS_PARAMS_DH = 2, + GNUTLS_PARAMS_ECDH = 3, } gnutls_params_type_t; /** @@ -554,6 +557,7 @@ extern "C" * @GNUTLS_PK_RSA: RSA public-key algorithm. * @GNUTLS_PK_DSA: DSA public-key algorithm. * @GNUTLS_PK_DH: Diffie-Hellman algorithm. Used to generate parameters. + * @GNUTLS_PK_ECDH: Elliptic curve Diffie-Hellman algorithm. Used to generate parameters. * * Enumeration of different public-key algorithms. */ @@ -562,7 +566,8 @@ extern "C" GNUTLS_PK_UNKNOWN = 0, GNUTLS_PK_RSA = 1, GNUTLS_PK_DSA = 2, - GNUTLS_PK_DH = 3 + GNUTLS_PK_DH = 3, + GNUTLS_PK_ECDH = 4, } gnutls_pk_algorithm_t; const char *gnutls_pk_algorithm_get_name (gnutls_pk_algorithm_t algorithm); @@ -647,6 +652,9 @@ extern "C" struct gnutls_dh_params_int; typedef struct gnutls_dh_params_int *gnutls_dh_params_t; + struct gnutls_ecdh_params_int; + typedef struct gnutls_ecdh_params_int *gnutls_ecdh_params_t; + /* XXX ugly. */ struct gnutls_x509_privkey_int; typedef struct gnutls_x509_privkey_int *gnutls_rsa_params_t; @@ -667,6 +675,7 @@ extern "C" union params { gnutls_dh_params_t dh; + gnutls_ecdh_params_t ecdh; gnutls_rsa_params_t rsa_export; } params; int deinit; @@ -1750,6 +1759,7 @@ extern "C" #define GNUTLS_E_CRYPTO_INIT_FAILED -318 #define GNUTLS_E_TIMEDOUT -319 #define GNUTLS_E_USER_ERROR -320 +#define GNUTLS_E_ECC_NO_SUPPORTED_CURVES -321 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250 diff --git a/lib/nettle/Makefile.am b/lib/nettle/Makefile.am index e902e774d5..0516800762 100644 --- a/lib/nettle/Makefile.am +++ b/lib/nettle/Makefile.am @@ -34,4 +34,9 @@ endif noinst_LTLIBRARIES = libcrypto.la -libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c rnd.c init.c egd.c egd.h +libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c rnd.c init.c egd.c egd.h \ + multi.c ecc_free.c ecc.h ecc_make_key.c ecc_shared_secret.c \ + ecc_test.c ltc_ecc_map.c \ + ltc_ecc_mulmod.c ltc_ecc_points.c \ + ltc_ecc_projective_add_point.c ltc_ecc_projective_dbl_point.c \ + mp_unsigned_bin.c ecc_sign_hash.c ecc_verify_hash.c diff --git a/lib/nettle/ecc.h b/lib/nettle/ecc.h new file mode 100644 index 0000000000..0ba3b0b08c --- /dev/null +++ b/lib/nettle/ecc.h @@ -0,0 +1,123 @@ +#include <gmp.h> +#include <nettle/nettle-types.h> +#include <nettle/dsa.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <assert.h> + +#define LTC_MECC +#define ECC256 + +#define PK_PRIVATE 1 +#define PK_PUBLIC 2 + +/* ---- ECC Routines ---- */ +/* size of our temp buffers for exported keys */ +#define ECC_BUF_SIZE 512 + +/* max private key size */ +#define ECC_MAXSIZE 66 + +/** Structure defines a NIST GF(p) curve */ +typedef struct { + /** The size of the curve in octets */ + int size; + + /** name of curve */ + const char *name; + + /** The prime that defines the field the curve is in (encoded in hex) */ + const char *prime; + + /** The fields B param (hex) */ + const char *B; + + /** The order of the curve (hex) */ + const char *order; + + /** The x co-ordinate of the base point on the curve (hex) */ + const char *Gx; + + /** The y co-ordinate of the base point on the curve (hex) */ + const char *Gy; +} ltc_ecc_set_type; + +/** A point on a ECC curve, stored in Jacbobian format such that (x,y,z) => (x/z^2, y/z^3, 1) when interpretted as affine */ +typedef struct { + /** The x co-ordinate */ + mpz_t x; + + /** The y co-ordinate */ + mpz_t y; + + /** The z co-ordinate */ + mpz_t z; +} ecc_point; + +/** An ECC key */ +typedef struct { + /** Type of key, PK_PRIVATE or PK_PUBLIC */ + int type; + + mpz_t prime; + mpz_t order; + mpz_t Gx; + mpz_t Gy; + + /** The public key */ + ecc_point pubkey; + + /** The private key */ + mpz_t k; +} ecc_key; + +/** the ECC params provided */ +extern const ltc_ecc_set_type ltc_ecc_sets[]; + +int ecc_test(void); +void ecc_sizes(int *low, int *high); +int ecc_get_size(ecc_key *key); + +int ecc_make_key(void *random_ctx, nettle_random_func random, ecc_key *key, const ltc_ecc_set_type *dp); +int ecc_make_key_ex(void *random_ctx, nettle_random_func random, ecc_key *key, mpz_t prime, mpz_t order, mpz_t Gx, mpz_t Gy); +void ecc_free(ecc_key *key); + +int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, + unsigned char *out, unsigned long *outlen); + +int ecc_sign_hash(const unsigned char *in, unsigned long inlen, + struct dsa_signature *signature, + void *random_ctx, nettle_random_func random, ecc_key *key); + +int ecc_verify_hash(struct dsa_signature * signature, + const unsigned char *hash, unsigned long hashlen, + int *stat, ecc_key *key); + +/* low level functions */ +ecc_point *ltc_ecc_new_point(void); +void ltc_ecc_del_point(ecc_point *p); +int ltc_ecc_is_valid_idx(int n); + +/* point ops (mp == montgomery digit) */ +/* R = 2P */ +int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mpz_t modulus); + +/* R = P + Q */ +int ltc_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mpz_t modulus); + +/* R = kG */ +int ltc_ecc_mulmod(mpz_t k, ecc_point *G, ecc_point *R, mpz_t modulus, int map); + +/* map P to affine from projective */ +int ltc_ecc_map(ecc_point *P, mpz_t modulus); + +/* helper functions */ +int mp_init_multi(mpz_t *a, ...); +void mp_clear_multi(mpz_t *a, ...); +unsigned long mp_unsigned_bin_size(mpz_t a); +int mp_to_unsigned_bin(mpz_t a, unsigned char *b); +int mp_read_unsigned_bin(mpz_t a, unsigned char *b, unsigned long len); +#define mp_isodd(a) (mpz_size(a) > 0 ? (mpz_getlimbn(a, 0) & 1 ? 1 : 0) : 0) + +#define MP_DIGIT_BIT (sizeof(mp_limb_t) * 8 - GMP_NAIL_BITS) diff --git a/lib/nettle/ecc_free.c b/lib/nettle/ecc_free.c new file mode 100644 index 0000000000..7cc9774db2 --- /dev/null +++ b/lib/nettle/ecc_free.c @@ -0,0 +1,40 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ +#include "ecc.h" + +/** + @file ecc_free.c + ECC Crypto, Tom St Denis +*/ + +#ifdef LTC_MECC + +/** + Free an ECC key from memory + @param key The key you wish to free +*/ +void ecc_free(ecc_key *key) +{ + assert(key != NULL); + mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, &key->prime, &key->order, &key->Gx, &key->Gy, NULL); +} + +#endif +/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_free.c,v $ */ +/* $Revision: 1.6 $ */ +/* $Date: 2007/05/12 14:32:35 $ */ + diff --git a/lib/nettle/ecc_make_key.c b/lib/nettle/ecc_make_key.c new file mode 100644 index 0000000000..3ca757115a --- /dev/null +++ b/lib/nettle/ecc_make_key.c @@ -0,0 +1,125 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ +#include "ecc.h" + +/** + @file ecc_make_key.c + ECC Crypto, Tom St Denis +*/ + +#ifdef LTC_MECC + +/** + Make a new ECC key + @param prng An active PRNG state + @param wprng The index of the PRNG you wish to use + @param keysize The keysize for the new key (in octets from 20 to 65 bytes) + @param key [out] Destination of the newly created key + @return 0 if successful, upon error all allocated memory will be freed +*/ + +int ecc_make_key_ex(void *random_ctx, nettle_random_func random, ecc_key *key, mpz_t prime, mpz_t order, mpz_t Gx, mpz_t Gy) +{ + int err; + ecc_point *base; + unsigned char *buf; + int keysize; + + assert(key != NULL); + assert(random != NULL); + + keysize = mp_unsigned_bin_size(order); + + /* allocate ram */ + base = NULL; + buf = malloc(keysize); + if (buf == NULL) { + return -1; + } + + /* make up random string */ + random(random_ctx, keysize, buf); + + /* setup the key variables */ + if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, &key->prime, &key->order, &key->Gx, &key->Gy, NULL)) != 0) { + goto ERR_BUF; + } + base = ltc_ecc_new_point(); + if (base == NULL) { + err = -1; + goto errkey; + } + + /* read in the specs for this key */ + mpz_set(key->prime, prime); + mpz_set(key->order, order); + mpz_set(key->Gx, Gx); + mpz_set(key->Gy, Gy); + + mpz_set(base->x, key->Gx); + mpz_set(base->y, key->Gy); + mpz_set_ui(base->z, 1); + if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)buf, keysize)) != 0) { goto errkey; } + + /* the key should be smaller than the order of base point */ + if (mpz_cmp(key->k, key->order) >= 0) { + mpz_mod(key->k, key->k, key->order); + } + /* make the public key */ + if ((err = ltc_ecc_mulmod(key->k, base, &key->pubkey, key->prime, 1)) != 0) { goto errkey; } + key->type = PK_PRIVATE; + + /* free up ram */ + err = 0; + goto cleanup; +errkey: + mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, &key->order, &key->prime, &key->Gx, &key->Gy, NULL); +cleanup: + ltc_ecc_del_point(base); +ERR_BUF: + free(buf); + return err; +} + +int ecc_make_key(void *random_ctx, nettle_random_func random, ecc_key *key, const ltc_ecc_set_type *dp) +{ + mpz_t prime, order, Gx, Gy; + int err; + + /* setup the key variables */ + if ((err = mp_init_multi(&prime, &order, &Gx, &Gy, NULL)) != 0) { + goto cleanup; + } + + /* read in the specs for this key */ + mpz_set_str(prime, (char *)dp->prime, 16); + mpz_set_str(order, (char *)dp->order, 16); + mpz_set_str(Gx, (char *)dp->Gx, 16); + mpz_set_str(Gy, (char *)dp->Gy, 16); + + err = ecc_make_key_ex(random_ctx, random, key, prime, order, Gx, Gy); + + mp_clear_multi(&prime, &order, &Gx, &Gy, NULL); +cleanup: + return err; +} + +#endif +/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_make_key.c,v $ */ +/* $Revision: 1.13 $ */ +/* $Date: 2007/05/12 14:32:35 $ */ + diff --git a/lib/nettle/ecc_shared_secret.c b/lib/nettle/ecc_shared_secret.c new file mode 100644 index 0000000000..a3eb46a868 --- /dev/null +++ b/lib/nettle/ecc_shared_secret.c @@ -0,0 +1,80 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ +#include "ecc.h" +#include <string.h> + +/** + @file ecc_shared_secret.c + ECC Crypto, Tom St Denis +*/ + +#ifdef LTC_MECC + +/** + Create an ECC shared secret between two keys + @param private_key The private ECC key + @param public_key The public key + @param out [out] Destination of the shared secret (Conforms to EC-DH from ANSI X9.63) + @param outlen [in/out] The max size and resulting size of the shared secret + @return 0 if successful +*/ +int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, + unsigned char *out, unsigned long *outlen) +{ + unsigned long x; + ecc_point *result; + int err; + + assert(private_key != NULL); + assert(public_key != NULL); + assert(out != NULL); + assert(outlen != NULL); + + /* type valid? */ + if (private_key->type != PK_PRIVATE) { + return -1; + } + + /* make new point */ + result = ltc_ecc_new_point(); + if (result == NULL) { + return -1; + } + + if ((err = ltc_ecc_mulmod(private_key->k, &public_key->pubkey, result, private_key->prime, 1)) != 0) { goto done; } + + x = (unsigned long)mp_unsigned_bin_size(private_key->prime); + if (*outlen < x) { + *outlen = x; + err = -1; + goto done; + } + memset(out, 0, x); + if ((err = mp_to_unsigned_bin(result->x, out + (x - mp_unsigned_bin_size(result->x)))) != 0) { goto done; } + + err = 0; + *outlen = x; +done: + ltc_ecc_del_point(result); + return err; +} + +#endif +/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_shared_secret.c,v $ */ +/* $Revision: 1.10 $ */ +/* $Date: 2007/05/12 14:32:35 $ */ + diff --git a/lib/nettle/ecc_sign_hash.c b/lib/nettle/ecc_sign_hash.c new file mode 100644 index 0000000000..b2da7f22c6 --- /dev/null +++ b/lib/nettle/ecc_sign_hash.c @@ -0,0 +1,103 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ +#include "ecc.h" +#include <nettle/dsa.h> + +/** + @file ecc_sign_hash.c + ECC Crypto, Tom St Denis +*/ + +#ifdef LTC_MECC + +/** + Sign a message digest + @param in The message digest to sign + @param inlen The length of the digest + @param signature The destination for the signature + @param prng An active PRNG state + @param wprng The index of the PRNG you wish to use + @param key A private ECC key + @return 0 if successful +*/ +int ecc_sign_hash(const unsigned char *in, unsigned long inlen, + struct dsa_signature *signature, + void *random_ctx, nettle_random_func random, ecc_key *key) +{ + ecc_key pubkey; + mpz_t r, s, e; + int err; + + assert(in != NULL); + assert(signature != NULL); + assert(key != NULL); + + /* is this a private key? */ + if (key->type != PK_PRIVATE) { + return -1; + } + + /* get the hash and load it as a bignum into 'e' */ + /* init the bignums */ + if ((err = mp_init_multi(&r, &s, &e, NULL)) != 0) { + return err; + } + if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, (int)inlen)) != 0) { goto errnokey; } + + /* make up a key and export the public copy */ + for (;;) { + if ((err = ecc_make_key_ex(random_ctx, random, &pubkey, key->prime, key->order, key->Gx, key->Gy)) != 0) { + goto errnokey; + } + + /* find r = x1 mod n */ + mpz_mod(r, pubkey.pubkey.x, pubkey.order); + + if (mpz_cmp_ui(r, 0) == 0) { + ecc_free(&pubkey); + } else { + /* find s = (e + xr)/k */ + mpz_invert(pubkey.k, pubkey.k, pubkey.order); + + /* mulmod */ + mpz_mul(s, key->k, r); + mpz_mod(s, s, pubkey.order); + mpz_add(s, e, s); + mpz_mod(s, s, pubkey.order); + + mpz_mul(s, s, pubkey.k); + mpz_mod(s, s, pubkey.order); + ecc_free(&pubkey); + if (mpz_cmp_ui(s,0) != 0) { + break; + } + } + } + + memcpy(&signature->r, &r, sizeof(signature->r)); + memcpy(&signature->s, &s, sizeof(signature->s)); + +errnokey: + mp_clear_multi(&e, NULL); + return err; +} + +#endif +/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_sign_hash.c,v $ */ +/* $Revision: 1.11 $ */ +/* $Date: 2007/05/12 14:32:35 $ */ + diff --git a/lib/nettle/ecc_test.c b/lib/nettle/ecc_test.c new file mode 100644 index 0000000000..4c74a9f7a6 --- /dev/null +++ b/lib/nettle/ecc_test.c @@ -0,0 +1,125 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ +#include "ecc.h" +#include "gnettle.h" +#include <gnutls_int.h> +#include <gnutls_algorithms.h> + +/** + @file ecc_test.c + ECC Crypto, Tom St Denis +*/ + +#ifdef LTC_MECC + +/** + Perform on the ECC system + @return 0 if successful +*/ +int ecc_test(void) +{ + mpz_t modulus, order; + ecc_point *G, *GG; + int i, err; + + if ((err = mp_init_multi(&modulus, &order, NULL)) != 0) { + return err; + } + + G = ltc_ecc_new_point(); + GG = ltc_ecc_new_point(); + if (G == NULL || GG == NULL) { + mp_clear_multi(&modulus,&order, NULL); + ltc_ecc_del_point(G); + ltc_ecc_del_point(GG); + return -1; + } + + for (i = 1; i<=2; i++) { + const gnutls_ecc_curve_entry_st *st = _gnutls_ecc_curve_get_params (i); + + printf("Testing %s (%d)\n", _gnutls_ecc_curve_get_name(i), i); + + if (mpz_set_str(modulus, (char *)st->prime, 16) != 0) { +fprintf(stderr, "XXX %d\n", __LINE__); + err = -1; + goto done; + } + + if (mpz_set_str(order, (char *)st->order, 16) != 0) { +fprintf(stderr, "XXX %d\n", __LINE__); + err = -1; + goto done; + } + + /* is prime actually prime? */ + if ((err = mpz_probab_prime_p(modulus, PRIME_CHECK_PARAM)) <= 0) { +fprintf(stderr, "XXX %d\n", __LINE__); + err = -1; + goto done; + } + + if ((err = mpz_probab_prime_p(order, PRIME_CHECK_PARAM)) <= 0) { +fprintf(stderr, "XXX %d\n", __LINE__); + err = -1; + goto done; + } + + if (mpz_set_str(G->x, (char *)st->Gx, 16) != 0) { +fprintf(stderr, "XXX %d\n", __LINE__); + err = -1; + goto done; + } + + if (mpz_set_str(G->y, (char *)st->Gy, 16) != 0) { +fprintf(stderr, "XXX %d\n", __LINE__); + err = -1; + goto done; + } + mpz_set_ui(G->z, 1); + + /* then we should have G == (order + 1)G */ + mpz_add_ui(order, order, 1); + if ((err = ltc_ecc_mulmod(order, G, GG, modulus, 1)) != 0) { goto done; } + + if (mpz_cmp(G->y, GG->y) != 0) { +fprintf(stderr, "XXX %d\n", __LINE__); + err = -1; + goto done; + } + + if (mpz_cmp(G->x, GG->x) != 0) { +fprintf(stderr, "XXX %d\n", __LINE__); + err = -1; + goto done; + } + + } + err = 0; +done: + ltc_ecc_del_point(GG); + ltc_ecc_del_point(G); + mp_clear_multi(&order, &modulus, NULL); + return err; +} + +#endif + +/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_test.c,v $ */ +/* $Revision: 1.12 $ */ +/* $Date: 2007/05/12 14:32:35 $ */ + diff --git a/lib/nettle/ecc_verify_hash.c b/lib/nettle/ecc_verify_hash.c new file mode 100644 index 0000000000..71315f3795 --- /dev/null +++ b/lib/nettle/ecc_verify_hash.c @@ -0,0 +1,135 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ +#include "ecc.h" + +/** + @file ecc_verify_hash.c + ECC Crypto, Tom St Denis +*/ + +#ifdef LTC_MECC + +/* verify + * + * w = s^-1 mod n + * u1 = xw + * u2 = rw + * X = u1*G + u2*Q + * v = X_x1 mod n + * accept if v == r + */ + +/** + Verify an ECC signature + @param signature The signature to verify + @param hash The hash (message digest) that was signed + @param hashlen The length of the hash (octets) + @param stat Result of signature, 1==valid, 0==invalid + @param key The corresponding public ECC key + @return 0 if successful (even if the signature is not valid) +*/ +int ecc_verify_hash(struct dsa_signature * signature, + const unsigned char *hash, unsigned long hashlen, + int *stat, ecc_key *key) +{ + ecc_point *mG, *mQ; + mpz_t v, w, u1, u2, e; + int err; + + assert(signature != NULL); + assert(hash != NULL); + assert(stat != NULL); + assert(key != NULL); + + /* default to invalid signature */ + *stat = 0; + + /* allocate ints */ + if ((err = mp_init_multi(&v, &w, &u1, &u2, &e, NULL)) != 0) { + return -1; + } + + /* allocate points */ + mG = ltc_ecc_new_point(); + mQ = ltc_ecc_new_point(); + if (mQ == NULL || mG == NULL) { + err = -1; + goto error; + } + + /* check for zero */ + if (mpz_cmp_ui(signature->r,0) == 0 || mpz_cmp_ui(signature->s,0) == 0 || + mpz_cmp(signature->r, key->order) >= 0 || mpz_cmp(signature->s, key->order) >= 0) { + err = -1; + goto error; + } + + /* read hash */ + if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, (int)hashlen)) != 0) { goto error; } + + /* w = s^-1 mod n */ + mpz_invert(w, signature->s, key->order); + + /* u1 = ew */ + mpz_mul(u1, e, w); + mpz_mod(u1, u1, key->order); + + /* u2 = rw */ + mpz_mul(u2, signature->r, w); + mpz_mod(u2, u2, key->order); + + /* find mG and mQ */ + mpz_set(mG->x, key->Gx); + mpz_set(mG->y, key->Gy); + mpz_set_ui(mG->z, 1); + + mpz_set(mQ->x, key->pubkey.x); + mpz_set(mQ->y, key->pubkey.y); + mpz_set(mQ->z, key->pubkey.z); + + /* compute u1*mG + u2*mQ = mG */ + if ((err = ltc_ecc_mulmod(u1, mG, mG, key->prime, 0)) != 0) { goto error; } + if ((err = ltc_ecc_mulmod(u2, mQ, mQ, key->prime, 0)) != 0) { goto error; } + + /* add them */ + if ((err = ltc_ecc_projective_add_point(mQ, mG, mG, key->prime)) != 0) { goto error; } + + /* reduce */ + if ((err = ltc_ecc_map(mG, key->prime)) != 0) { goto error; } + + /* v = X_x1 mod n */ + mpz_mod(v, mG->x, key->order); + + /* does v == r */ + if (mpz_cmp(v, signature->r) == 0) { + *stat = 1; + } + + /* clear up and return */ + err = 0; +error: + ltc_ecc_del_point(mG); + ltc_ecc_del_point(mQ); + mp_clear_multi(&v, &w, &u1, &u2, &e, NULL); + return err; +} + +#endif +/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ecc_verify_hash.c,v $ */ +/* $Revision: 1.14 $ */ +/* $Date: 2007/05/12 14:32:35 $ */ + diff --git a/lib/nettle/gnettle.h b/lib/nettle/gnettle.h new file mode 100644 index 0000000000..768590c73d --- /dev/null +++ b/lib/nettle/gnettle.h @@ -0,0 +1,2 @@ +#define PRIME_CHECK_PARAM 8 + diff --git a/lib/nettle/ltc_ecc_map.c b/lib/nettle/ltc_ecc_map.c new file mode 100644 index 0000000000..f22426009d --- /dev/null +++ b/lib/nettle/ltc_ecc_map.c @@ -0,0 +1,73 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ +#include "ecc.h" + +/** + @file ltc_ecc_map.c + ECC Crypto, Tom St Denis +*/ + +#ifdef LTC_MECC + +/** + Map a projective jacbobian point back to affine space + @param P [in/out] The point to map + @param modulus The modulus of the field the ECC curve is in + @param mp The "b" value from montgomery_setup() + @return 0 on success +*/ +int ltc_ecc_map(ecc_point *P, mpz_t modulus) +{ + mpz_t t1, t2; + int err; + + assert(P != NULL); + + if ((err = mp_init_multi(&t1, &t2, NULL)) != 0) { + return -1; + } + + mpz_mod(P->z, P->z, modulus); + + /* get 1/z */ + mpz_invert(t1, P->z, modulus); + + /* get 1/z^2 and 1/z^3 */ + mpz_mul(t2, t1, t1); + mpz_mod(t2, t2, modulus); + mpz_mul(t1, t1, t2); + mpz_mod(t1, t1, modulus); + + /* multiply against x/y */ + mpz_mul(P->x, P->x, t2); + mpz_mod(P->x, P->x, modulus); + mpz_mul(P->y, P->y, t1); + mpz_mod(P->y, P->y, modulus); + mpz_set_ui(P->z, 1); + + err = 0; + + mp_clear_multi(&t1, &t2, NULL); + return err; +} + +#endif + +/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ltc_ecc_map.c,v $ */ +/* $Revision: 1.7 $ */ +/* $Date: 2007/05/12 14:32:35 $ */ + diff --git a/lib/nettle/ltc_ecc_mulmod.c b/lib/nettle/ltc_ecc_mulmod.c new file mode 100644 index 0000000000..ab845ce014 --- /dev/null +++ b/lib/nettle/ltc_ecc_mulmod.c @@ -0,0 +1,141 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ +#include "ecc.h" + +/** + @file ltc_ecc_mulmod_timing.c + ECC Crypto, Tom St Denis +*/ + +#ifdef LTC_MECC + +/** + Perform a point multiplication (timing resistant) + @param k The scalar to multiply by + @param G The base point + @param R [out] Destination for kG + @param modulus The modulus of the field the ECC curve is in + @param map Boolean whether to map back to affine or not (1==map, 0 == leave in projective) + @return 0 on success +*/ +int ltc_ecc_mulmod(mpz_t k, ecc_point *G, ecc_point *R, mpz_t modulus, int map) +{ + ecc_point *tG, *M[3]; + int i, j, err; + unsigned long buf; + int first, bitbuf, bitcpy, bitcnt, mode, digidx; + + assert(k != NULL); + assert(G != NULL); + assert(R != NULL); + assert(modulus != NULL); + + /* alloc ram for window temps */ + for (i = 0; i < 3; i++) { + M[i] = ltc_ecc_new_point(); + if (M[i] == NULL) { + for (j = 0; j < i; j++) { + ltc_ecc_del_point(M[j]); + } + return -1; + } + } + + /* make a copy of G incase R==G */ + tG = ltc_ecc_new_point(); + if (tG == NULL) { err = -1; goto done; } + + /* tG = G and convert to montgomery */ + mpz_set(tG->x, G->x); + mpz_set(tG->y, G->y); + mpz_set(tG->z, G->z); + + /* calc the M tab */ + /* M[0] == G */ + mpz_set(M[0]->x, tG->x); + mpz_set(M[0]->y, tG->y); + mpz_set(M[0]->z, tG->z); + /* M[1] == 2G */ + if ((err = ltc_ecc_projective_dbl_point(tG, M[1], modulus)) != 0) { goto done; } + + /* setup sliding window */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = mpz_size(k) - 1; + bitcpy = bitbuf = 0; + first = 1; + + /* perform ops */ + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + if (digidx == -1) { + break; + } + buf = mpz_getlimbn(k, digidx); + bitcnt = (int) MP_DIGIT_BIT; + --digidx; + } + + /* grab the next msb from the ltiplicand */ + i = (buf >> (MP_DIGIT_BIT - 1)) & 1; + buf <<= 1; + + if (mode == 0 && i == 0) { + /* dummy operations */ + if ((err = ltc_ecc_projective_add_point(M[0], M[1], M[2], modulus)) != 0) { goto done; } + if ((err = ltc_ecc_projective_dbl_point(M[1], M[2], modulus)) != 0) { goto done; } + continue; + } + + if (mode == 0 && i == 1) { + mode = 1; + /* dummy operations */ + if ((err = ltc_ecc_projective_add_point(M[0], M[1], M[2], modulus)) != 0) { goto done; } + if ((err = ltc_ecc_projective_dbl_point(M[1], M[2], modulus)) != 0) { goto done; } + continue; + } + + if ((err = ltc_ecc_projective_add_point(M[0], M[1], M[i^1], modulus)) != 0) { goto done; } + if ((err = ltc_ecc_projective_dbl_point(M[i], M[i], modulus)) != 0) { goto done; } + } + + /* copy result out */ + mpz_set(R->x, M[0]->x); + mpz_set(R->y, M[0]->y); + mpz_set(R->z, M[0]->z); + + /* map R back from projective space */ + if (map) { + err = ltc_ecc_map(R, modulus); + } else { + err = 0; + } +done: + ltc_ecc_del_point(tG); + for (i = 0; i < 3; i++) { + ltc_ecc_del_point(M[i]); + } + return err; +} + +#endif +/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod_timing.c,v $ */ +/* $Revision: 1.13 $ */ +/* $Date: 2007/05/12 14:32:35 $ */ + diff --git a/lib/nettle/ltc_ecc_points.c b/lib/nettle/ltc_ecc_points.c new file mode 100644 index 0000000000..93ad85d403 --- /dev/null +++ b/lib/nettle/ltc_ecc_points.c @@ -0,0 +1,60 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ +#include "ecc.h" + +/** + @file ltc_ecc_points.c + ECC Crypto, Tom St Denis +*/ + +#ifdef LTC_MECC + +/** + Allocate a new ECC point + @return A newly allocated point or NULL on error +*/ +ecc_point *ltc_ecc_new_point(void) +{ + ecc_point *p; + p = calloc(1, sizeof(*p)); + if (p == NULL) { + return NULL; + } + if (mp_init_multi(&p->x, &p->y, &p->z, NULL) != 0) { + free(p); + return NULL; + } + return p; +} + +/** Free an ECC point from memory + @param p The point to free +*/ +void ltc_ecc_del_point(ecc_point *p) +{ + /* prevents free'ing null arguments */ + if (p != NULL) { + mp_clear_multi(&p->x, &p->y, &p->z, NULL); /* note: p->z may be NULL but that's ok with this function anyways */ + free(p); + } +} + +#endif +/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ltc_ecc_points.c,v $ */ +/* $Revision: 1.7 $ */ +/* $Date: 2007/05/12 14:32:35 $ */ + diff --git a/lib/nettle/ltc_ecc_projective_add_point.c b/lib/nettle/ltc_ecc_projective_add_point.c new file mode 100644 index 0000000000..2b008367c6 --- /dev/null +++ b/lib/nettle/ltc_ecc_projective_add_point.c @@ -0,0 +1,195 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ +#include "ecc.h" + +/** + @file ltc_ecc_projective_add_point.c + ECC Crypto, Tom St Denis +*/ + +#if defined(LTC_MECC) && (!defined(LTC_MECC_ACCEL) || defined(LTM_LTC_DESC)) + +/** + Add two ECC points + @param P The point to add + @param Q The point to add + @param R [out] The destination of the double + @param modulus The modulus of the field the ECC curve is in + @param mp The "b" value from montgomery_setup() + @return 0 on success +*/ +int ltc_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mpz_t modulus) +{ + mpz_t t1, t2, x, y, z; + int err; + + assert(P != NULL); + assert(Q != NULL); + assert(R != NULL); + assert(modulus != NULL); + + if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != 0) { + return err; + } + + /* should we dbl instead? */ + mpz_sub(t1, modulus, Q->y); + + if ( (mpz_cmp(P->x, Q->x) == 0) && + (Q->z != NULL && mpz_cmp(P->z, Q->z) == 0) && + (mpz_cmp(P->y, Q->y) == 0 || mpz_cmp(P->y, t1) == 0)) { + mp_clear_multi(&t1, &t2, &x, &y, &z, NULL); + return ltc_ecc_projective_dbl_point(P, R, modulus); + } + + mpz_set(x, P->x); + mpz_set(y, P->y); + mpz_set(z, P->z); + + /* if Z is one then these are no-operations */ + if (mpz_cmp_ui(Q->z, 1) != 0) { + /* T1 = Z' * Z' */ + mpz_mul(t1, Q->z, Q->z); + mpz_mod(t1, t1, modulus); + /* X = X * T1 */ + mpz_mul(x, x, t1); + mpz_mod(x, x, modulus); + /* T1 = Z' * T1 */ + mpz_mul(t1, t1, Q->z); + mpz_mod(t1, t1, modulus); + /* Y = Y * T1 */ + mpz_mul(y, y, t1); + mpz_mod(y, y, modulus); + } + + /* T1 = Z*Z */ + mpz_mul(t1, z, z); + mpz_mod(t1, t1, modulus); + /* T2 = X' * T1 */ + mpz_mul(t2, t1, Q->x); + mpz_mod(t2, t2, modulus); + /* T1 = Z * T1 */ + mpz_mul(t1, t1, z); + mpz_mod(t1, t1, modulus); + /* T1 = Y' * T1 */ + mpz_mul(t1, t1, Q->y); + mpz_mod(t1, t1, modulus); + + /* Y = Y - T1 */ + mpz_sub(y, y, t1); + if (mpz_cmp_ui(y, 0) < 0) { + mpz_add(y, y, modulus); + } + /* T1 = 2T1 */ + mpz_add(t1, t1, t1); + if (mpz_cmp(t1, modulus) >= 0) { + mpz_sub(t1, t1, modulus); + } + /* T1 = Y + T1 */ + mpz_add(t1, t1, y); + if (mpz_cmp(t1, modulus) >= 0) { + mpz_sub(t1, t1, modulus); + } + /* X = X - T2 */ + mpz_sub(x, x, t2); + if (mpz_cmp_ui(x, 0) < 0) { + mpz_add(x, x, modulus); + } + /* T2 = 2T2 */ + mpz_add(t2, t2, t2); + if (mpz_cmp(t2, modulus) >= 0) { + mpz_sub(t2, t2, modulus); + } + /* T2 = X + T2 */ + mpz_add(t2, t2, x); + if (mpz_cmp(t2, modulus) >= 0) { + mpz_sub(t2, t2, modulus); + } + + /* if Z' != 1 */ + if (mpz_cmp_ui(Q->z, 1) != 0) { + /* Z = Z * Z' */ + mpz_mul(z, z, Q->z); + mpz_mod(z, z, modulus); + } + + /* Z = Z * X */ + mpz_mul(z, z, x); + mpz_mod(z, z, modulus); + + /* T1 = T1 * X */ + mpz_mul(t1, t1, x); + mpz_mod(t1, t1, modulus); + /* X = X * X */ + mpz_mul(x, x, x); + mpz_mod(x, x, modulus); + /* T2 = T2 * x */ + mpz_mul(t2, t2, x); + mpz_mod(t2, t2, modulus); + /* T1 = T1 * X */ + mpz_mul(t1, t1, x); + mpz_mod(t1, t1, modulus); + + /* X = Y*Y */ + mpz_mul(x, y, y); + mpz_mod(x, x, modulus); + /* X = X - T2 */ + mpz_sub(x, x, t2); + if (mpz_cmp_ui(x, 0) < 0) { + mpz_add(x, x, modulus); + } + + /* T2 = T2 - X */ + mpz_sub(t2, t2, x); + if (mpz_cmp_ui(t2, 0) < 0) { + mpz_add(t2, t2, modulus); + } + /* T2 = T2 - X */ + mpz_sub(t2, t2, x); + if (mpz_cmp_ui(t2, 0) < 0) { + mpz_add(t2, t2, modulus); + } + /* T2 = T2 * Y */ + mpz_mul(t2, t2, y); + mpz_mod(t2, t2, modulus); + /* Y = T2 - T1 */ + mpz_sub(y, t2, t1); + if (mpz_cmp_ui(y, 0) < 0) { + mpz_add(y, y, modulus); + } + /* Y = Y/2 */ + if (mp_isodd(y)) { + mpz_add(y, y, modulus); + } + mpz_divexact_ui(y, y, 2); + + mpz_set(R->x, x); + mpz_set(R->y, y); + mpz_set(R->z, z); + + err = 0; + + mp_clear_multi(&t1, &t2, &x, &y, &z, NULL); + return err; +} + +#endif + +/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ltc_ecc_projective_add_point.c,v $ */ +/* $Revision: 1.16 $ */ +/* $Date: 2007/05/12 14:32:35 $ */ + diff --git a/lib/nettle/ltc_ecc_projective_dbl_point.c b/lib/nettle/ltc_ecc_projective_dbl_point.c new file mode 100644 index 0000000000..d9b7ec6e6c --- /dev/null +++ b/lib/nettle/ltc_ecc_projective_dbl_point.c @@ -0,0 +1,146 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ +#include "ecc.h" + +/** + @file ltc_ecc_projective_dbl_point.c + ECC Crypto, Tom St Denis +*/ + +#if defined(LTC_MECC) && (!defined(LTC_MECC_ACCEL) || defined(LTM_LTC_DESC)) + +/** + Double an ECC point + @param P The point to double + @param R [out] The destination of the double + @param modulus The modulus of the field the ECC curve is in + @param mp The "b" value from montgomery_setup() + @return 0 on success +*/ +int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mpz_t modulus) +{ + mpz_t t1, t2; + int err; + + assert(P != NULL); + assert(R != NULL); + assert(modulus != NULL); + + if ((err = mp_init_multi(&t1, &t2, NULL)) != 0) { + return err; + } + + if (P != R) { + mpz_set(R->x, P->x); + mpz_set(R->y, P->y); + mpz_set(R->z, P->z); + } + + /* t1 = Z * Z */ + mpz_mul(t1, R->z, R->z); + mpz_mod(t1, t1, modulus); + /* Z = Y * Z */ + mpz_mul(R->z, R->y, R->z); + mpz_mod(R->z, R->z, modulus); + /* Z = 2Z */ + mpz_add(R->z, R->z, R->z); + if (mpz_cmp(R->z, modulus) >= 0) { + mpz_sub(R->z, R->z, modulus); + } + + /* T2 = X - T1 */ + mpz_sub(t2, R->x, t1); + if (mpz_cmp_ui(t2, 0) < 0) { + mpz_add(t2, t2, modulus); + } + /* T1 = X + T1 */ + mpz_add(t1, t1, R->x); + if (mpz_cmp(t1, modulus) >= 0) { + mpz_sub(t1, t1, modulus); + } + /* T2 = T1 * T2 */ + mpz_mul(t2, t1, t2); + mpz_mod(t2, t2, modulus); + /* T1 = 2T2 */ + mpz_add(t1, t2, t2); + if (mpz_cmp(t1, modulus) >= 0) { + mpz_sub(t1, t1, modulus); + } + /* T1 = T1 + T2 */ + mpz_add(t1, t1, t2); + if (mpz_cmp(t1, modulus) >= 0) { + mpz_sub(t1, t1, modulus); + } + + /* Y = 2Y */ + mpz_add(R->y, R->y, R->y); + if (mpz_cmp(R->y, modulus) >= 0) { + mpz_sub(R->y, R->y, modulus); + } + /* Y = Y * Y */ + mpz_mul(R->y, R->y, R->y); + mpz_mod(R->y, R->y, modulus); + /* T2 = Y * Y */ + mpz_mul(t2, R->y, R->y); + mpz_mod(t2, t2, modulus); + /* T2 = T2/2 */ + if (mp_isodd(t2)) { + mpz_add(t2, t2, modulus); + } + mpz_divexact_ui(t2, t2, 2); + /* Y = Y * X */ + mpz_mul(R->y, R->y, R->x); + mpz_mod(R->y, R->y, modulus); + + /* X = T1 * T1 */ + mpz_mul(R->x, t1, t1); + mpz_mod(R->x, R->x, modulus); + /* X = X - Y */ + mpz_sub(R->x, R->x, R->y); + if (mpz_cmp_ui(R->x, 0) < 0) { + mpz_add(R->x, R->x, modulus); + } + /* X = X - Y */ + mpz_sub(R->x, R->x, R->y); + if (mpz_cmp_ui(R->x, 0) < 0) { + mpz_add(R->x, R->x, modulus); + } + + /* Y = Y - X */ + mpz_sub(R->y, R->y, R->x); + if (mpz_cmp_ui(R->y, 0) < 0) { + mpz_add(R->y, R->y, modulus); + } + /* Y = Y * T1 */ + mpz_mul(R->y, R->y, t1); + mpz_mod(R->y, R->y, modulus); + /* Y = Y - T2 */ + mpz_sub(R->y, R->y, t2); + if (mpz_cmp_ui(R->y, 0) < 0) { + mpz_add( R->y, R->y, modulus); + } + + err = 0; + + mp_clear_multi(&t1, &t2, NULL); + return err; +} +#endif +/* $Source: /cvs/libtom/libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c,v $ */ +/* $Revision: 1.11 $ */ +/* $Date: 2007/05/12 14:32:35 $ */ + diff --git a/lib/nettle/mp_unsigned_bin.c b/lib/nettle/mp_unsigned_bin.c new file mode 100644 index 0000000000..0da8bba32e --- /dev/null +++ b/lib/nettle/mp_unsigned_bin.c @@ -0,0 +1,28 @@ +#include "ecc.h" + +unsigned long mp_unsigned_bin_size(mpz_t a) +{ + unsigned long t; + assert(a != NULL); + + t = mpz_sizeinbase(a, 2); + if (mpz_cmp_ui((a), 0) == 0) return 0; + return (t>>3) + ((t&7)?1:0); +} + +int mp_to_unsigned_bin(mpz_t a, unsigned char *b) +{ + assert(a != NULL); + assert(b != NULL); + mpz_export(b, NULL, 1, 1, 1, 0, a); + + return 0; +} + +int mp_read_unsigned_bin(mpz_t a, unsigned char *b, unsigned long len) +{ + assert(a != NULL); + assert(b != NULL); + mpz_import(a, len, 1, 1, 1, 0, b); + return 0; +} diff --git a/lib/nettle/mpi.c b/lib/nettle/mpi.c index c76705c18f..eef8a2cc36 100644 --- a/lib/nettle/mpi.c +++ b/lib/nettle/mpi.c @@ -33,6 +33,7 @@ #include <gnutls_mpi.h> #include <gmp.h> #include <nettle/bignum.h> +#include <gnettle.h> #include <random.h> #define TOMPZ(x) (*((mpz_t*)(x))) @@ -390,7 +391,6 @@ wrap_nettle_mpi_mul_ui (bigint_t w, const bigint_t a, unsigned long b) } -#define PRIME_CHECK_PARAM 8 static int wrap_nettle_prime_check (bigint_t pp) { diff --git a/lib/nettle/multi.c b/lib/nettle/multi.c new file mode 100644 index 0000000000..788c8e9a00 --- /dev/null +++ b/lib/nettle/multi.c @@ -0,0 +1,46 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ +#include <gmp.h> +#include <stdarg.h> +#include <ecc.h> + +int mp_init_multi(mpz_t *a, ...) +{ + mpz_t *cur = a; + int np = 0; + va_list args; + + va_start(args, a); + while (cur != NULL) { + mpz_init(*cur); + ++np; + cur = va_arg(args, mpz_t*); + } + va_end(args); + return 0; +} + +void mp_clear_multi(mpz_t *a, ...) +{ + mpz_t *cur = a; + va_list args; + + va_start(args, a); + while (cur != NULL) { + mpz_clear(*cur); + cur = va_arg(args, mpz_t*); + } + va_end(args); +} + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c index 5ee9769d0d..f1722bede7 100644 --- a/lib/nettle/pk.c +++ b/lib/nettle/pk.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 - * Free Software Foundation, Inc. + * Copyright (C) 2010 Free Software Foundation, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -42,9 +41,13 @@ #include <nettle/rsa.h> #include <random.h> #include <gnutls/crypto.h> +#include "rnd.h" +#include "ecc.h" #define TOMPZ(x) (*((mpz_t*)(x))) +static inline int is_supported_curve(int curve); + static void rnd_func (void *_ctx, unsigned length, uint8_t * data) { @@ -81,6 +84,69 @@ _rsa_params_to_privkey (const gnutls_pk_params_st * pk_params, } +static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo, gnutls_datum_t * out, + const gnutls_pk_params_st * priv, + const gnutls_pk_params_st * pub) +{ + int ret; + + switch (algo) + { + case GNUTLS_PK_ECDH: + { + ecc_key ecc_pub, ecc_priv; + int curve = priv->flags; + unsigned long sz; + + if (is_supported_curve(curve) == 0) + return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES); + + ecc_pub.type = PK_PUBLIC; + memcpy(&ecc_pub.prime, pub->params[0], sizeof(mpz_t)); + memcpy(&ecc_pub.order, pub->params[1], sizeof(mpz_t)); + memcpy(&ecc_pub.Gx, pub->params[2], sizeof(mpz_t)); + memcpy(&ecc_pub.Gy, pub->params[3], sizeof(mpz_t)); + memcpy(&ecc_pub.pubkey.x, pub->params[4], sizeof(mpz_t)); + memcpy(&ecc_pub.pubkey.y, pub->params[5], sizeof(mpz_t)); + memcpy(&ecc_pub.pubkey.z, pub->params[6], sizeof(mpz_t)); + + ecc_priv.type = PK_PRIVATE; + memcpy(&ecc_priv.prime, priv->params[0], sizeof(mpz_t)); + memcpy(&ecc_priv.order, priv->params[1], sizeof(mpz_t)); + memcpy(&ecc_priv.Gx, priv->params[2], sizeof(mpz_t)); + memcpy(&ecc_priv.Gy, priv->params[3], sizeof(mpz_t)); + memcpy(&ecc_priv.pubkey.x, priv->params[4], sizeof(mpz_t)); + memcpy(&ecc_priv.pubkey.y, priv->params[5], sizeof(mpz_t)); + memcpy(&ecc_priv.pubkey.z, priv->params[6], sizeof(mpz_t)); + memcpy(&ecc_priv.k, priv->params[7], sizeof(mpz_t)); + + sz = ECC_BUF_SIZE; + out->data = gnutls_malloc(sz); + if (out->data == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + ret = ecc_shared_secret(&ecc_priv, &ecc_pub, out->data, &sz); + if (ret != 0) + { + gnutls_free(out->data); + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + } + out->size = sz; + break; + } + default: + gnutls_assert (); + ret = GNUTLS_E_INTERNAL_ERROR; + goto cleanup; + } + + ret = 0; + +cleanup: + + return ret; +} + static int _wrap_nettle_pk_encrypt (gnutls_pk_algorithm_t algo, gnutls_datum_t * ciphertext, @@ -89,7 +155,6 @@ _wrap_nettle_pk_encrypt (gnutls_pk_algorithm_t algo, { int ret; - /* make a sexp from pkey */ switch (algo) { case GNUTLS_PK_RSA: @@ -486,6 +551,15 @@ cleanup: return ret; } +static inline int is_supported_curve(int curve) +{ + if (_gnutls_ecc_curve_get_name(curve) != NULL) + return 1; + else + return 0; +} + + static int wrap_nettle_pk_generate_params (gnutls_pk_algorithm_t algo, unsigned int level /*bits */ , @@ -605,6 +679,56 @@ rsa_fail: break; } + case GNUTLS_PK_ECDH: + { + ecc_key key; + ltc_ecc_set_type tls_ecc_set; + const gnutls_ecc_curve_entry_st *st; + + st = _gnutls_ecc_curve_get_params(level); + if (st == NULL) + return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES); + + tls_ecc_set.size = st->size; + tls_ecc_set.prime = st->prime; + tls_ecc_set.order = st->order; + tls_ecc_set.Gx = st->Gx; + tls_ecc_set.Gy = st->Gy; + + ret = ecc_make_key(NULL, _int_random_func, &key, &tls_ecc_set); + if (ret != 0) + return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); + + params->params_nr = 0; + for (i = 0; i < ECDH_PRIVATE_PARAMS; i++) + { + params->params[i] = _gnutls_mpi_alloc_like(&key.prime); + if (params->params[i] == NULL) + { + ret = GNUTLS_E_MEMORY_ERROR; + goto ecc_fail; + } + params->params_nr++; + } + params->flags = level; + + mpz_set(TOMPZ(params->params[0]), key.prime); + mpz_set(TOMPZ(params->params[1]), key.order); + mpz_set(TOMPZ(params->params[2]), key.Gx); + mpz_set(TOMPZ(params->params[3]), key.Gy); + mpz_set(TOMPZ(params->params[4]), key.pubkey.x); + mpz_set(TOMPZ(params->params[5]), key.pubkey.y); + mpz_set(TOMPZ(params->params[6]), key.pubkey.z); + mpz_set(TOMPZ(params->params[7]), key.k); + +ecc_fail: + ecc_free(&key); + + if (ret < 0) + goto fail; + + break; + } default: gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; @@ -666,4 +790,5 @@ gnutls_crypto_pk_st _gnutls_pk_ops = { .verify = _wrap_nettle_pk_verify, .generate = wrap_nettle_pk_generate_params, .pk_fixup_private_params = wrap_nettle_pk_fixup, + .derive = _wrap_nettle_pk_derive, }; diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c index 8af0adde57..b503e10e1d 100644 --- a/lib/nettle/rnd.c +++ b/lib/nettle/rnd.c @@ -33,6 +33,7 @@ #include <gnutls_errors.h> #include <gnutls_num.h> #include <nettle/yarrow.h> +#include "rnd.h" #define SOURCES 2 @@ -440,7 +441,6 @@ wrap_nettle_rnd_init (void **ctx) } - static int wrap_nettle_rnd (void *_ctx, int level, void *data, size_t datasize) { @@ -467,6 +467,14 @@ wrap_nettle_rnd (void *_ctx, int level, void *data, size_t datasize) return 0; } +/* internal function to provide to nettle functions that + * require a nettle_random_func(). + */ +void _int_random_func(void *ctx, unsigned length, uint8_t *dst) +{ + wrap_nettle_rnd(ctx, 0, dst, length); +} + int crypto_rnd_prio = INT_MAX; gnutls_crypto_rnd_st _gnutls_rnd_ops = { diff --git a/lib/nettle/rnd.h b/lib/nettle/rnd.h new file mode 100644 index 0000000000..5deefd392c --- /dev/null +++ b/lib/nettle/rnd.h @@ -0,0 +1,2 @@ +void _int_random_func(void *ctx, + unsigned length, uint8_t *dst); diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h index bde3aefa76..b35ecd2d00 100644 --- a/lib/x509/x509_int.h +++ b/lib/x509/x509_int.h @@ -78,14 +78,15 @@ typedef struct gnutls_pkcs7_int /* parameters should not be larger than this limit */ #define DSA_PUBLIC_PARAMS 4 #define RSA_PUBLIC_PARAMS 2 +#define ECDH_PUBLIC_PARAMS 7 + #define MAX_PRIV_PARAMS_SIZE GNUTLS_MAX_PK_PARAMS /* ok for RSA and DSA */ /* parameters should not be larger than this limit */ #define DSA_PRIVATE_PARAMS 5 -#define DSA_PUBLIC_PARAMS 4 #define RSA_PRIVATE_PARAMS 8 -#define RSA_PUBLIC_PARAMS 2 +#define ECDH_PRIVATE_PARAMS 8 #if MAX_PRIV_PARAMS_SIZE - RSA_PRIVATE_PARAMS < 0 #error INCREASE MAX_PRIV_PARAMS |