summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/algorithms.h1
-rw-r--r--lib/algorithms/ciphersuites.c23
-rw-r--r--lib/algorithms/kx.c39
-rw-r--r--lib/algorithms/publickey.c1
-rw-r--r--lib/auth/Makefile.am2
-rw-r--r--lib/auth/cert.h7
-rw-r--r--lib/auth/psk.c4
-rw-r--r--lib/auth/psk.h4
-rw-r--r--lib/auth/rsa.c3
-rw-r--r--lib/auth/rsa_common.h43
-rw-r--r--lib/auth/rsa_psk.c536
-rw-r--r--lib/gnutls_cert.c39
-rw-r--r--lib/gnutls_handshake.c32
-rw-r--r--lib/gnutls_int.h2
-rw-r--r--lib/gnutls_state.c6
-rw-r--r--lib/includes/gnutls/gnutls.h.in2
16 files changed, 724 insertions, 20 deletions
diff --git a/lib/algorithms.h b/lib/algorithms.h
index 76888b5a56..a4675cd262 100644
--- a/lib/algorithms.h
+++ b/lib/algorithms.h
@@ -250,6 +250,7 @@ _gnutls_cipher_get_tag_size (const cipher_entry_st* e)
/* Functions for key exchange. */
int _gnutls_kx_needs_dh_params (gnutls_kx_algorithm_t algorithm);
+int _gnutls_kx_needs_rsa_params (gnutls_kx_algorithm_t algorithm);
mod_auth_st *_gnutls_kx_auth_struct (gnutls_kx_algorithm_t algorithm);
int _gnutls_kx_is_ok (gnutls_kx_algorithm_t algorithm);
diff --git a/lib/algorithms/ciphersuites.c b/lib/algorithms/ciphersuites.c
index 99edc49e87..b82eae6566 100644
--- a/lib/algorithms/ciphersuites.c
+++ b/lib/algorithms/ciphersuites.c
@@ -82,6 +82,11 @@ typedef struct
#define GNUTLS_DHE_PSK_SHA_AES_128_CBC_SHA1 { 0x00, 0x90 }
#define GNUTLS_DHE_PSK_SHA_AES_256_CBC_SHA1 { 0x00, 0x91 }
+#define GNUTLS_RSA_PSK_SHA_ARCFOUR_SHA1 { 0x00, 0x92 }
+#define GNUTLS_RSA_PSK_SHA_3DES_EDE_CBC_SHA1 { 0x00, 0x93 }
+#define GNUTLS_RSA_PSK_SHA_AES_128_CBC_SHA1 { 0x00, 0x94 }
+#define GNUTLS_RSA_PSK_SHA_AES_256_CBC_SHA1 { 0x00, 0x95 }
+
/* SRP (rfc5054)
*/
@@ -607,6 +612,24 @@ static const gnutls_cipher_suite_entry cs_algorithms[] = {
GNUTLS_MAC_UMAC_96, GNUTLS_SSL3,
GNUTLS_DTLS_VERSION_MIN),
+ /* RSA-PSK */
+ ENTRY (GNUTLS_RSA_PSK_SHA_ARCFOUR_SHA1,
+ GNUTLS_CIPHER_ARCFOUR, GNUTLS_KX_RSA_PSK,
+ GNUTLS_MAC_SHA1, GNUTLS_TLS1,
+ GNUTLS_VERSION_UNKNOWN),
+ ENTRY (GNUTLS_RSA_PSK_SHA_3DES_EDE_CBC_SHA1,
+ GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_RSA_PSK,
+ GNUTLS_MAC_SHA1, GNUTLS_TLS1,
+ GNUTLS_DTLS_VERSION_MIN),
+ ENTRY (GNUTLS_RSA_PSK_SHA_AES_128_CBC_SHA1,
+ GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_RSA_PSK,
+ GNUTLS_MAC_SHA1, GNUTLS_TLS1,
+ GNUTLS_DTLS_VERSION_MIN),
+ ENTRY (GNUTLS_RSA_PSK_SHA_AES_256_CBC_SHA1,
+ GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_RSA_PSK,
+ GNUTLS_MAC_SHA1, GNUTLS_TLS1,
+ GNUTLS_DTLS_VERSION_MIN),
+
/* DHE-PSK */
ENTRY (GNUTLS_DHE_PSK_SHA_ARCFOUR_SHA1,
GNUTLS_CIPHER_ARCFOUR, GNUTLS_KX_DHE_PSK,
diff --git a/lib/algorithms/kx.c b/lib/algorithms/kx.c
index 0865b0d74b..2123feb1cd 100644
--- a/lib/algorithms/kx.c
+++ b/lib/algorithms/kx.c
@@ -37,6 +37,7 @@ 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;
+extern mod_auth_st rsa_psk_auth_struct;
extern mod_auth_st srp_rsa_auth_struct;
extern mod_auth_st srp_dss_auth_struct;
@@ -63,6 +64,7 @@ static const gnutls_cred_map cred_mappings[] = {
{GNUTLS_KX_DHE_RSA, GNUTLS_CRD_CERTIFICATE, GNUTLS_CRD_CERTIFICATE},
{GNUTLS_KX_PSK, GNUTLS_CRD_PSK, GNUTLS_CRD_PSK},
{GNUTLS_KX_DHE_PSK, GNUTLS_CRD_PSK, GNUTLS_CRD_PSK},
+ {GNUTLS_KX_RSA_PSK, GNUTLS_CRD_PSK, GNUTLS_CRD_CERTIFICATE},
{GNUTLS_KX_ECDHE_PSK, GNUTLS_CRD_PSK, GNUTLS_CRD_PSK},
{GNUTLS_KX_SRP, GNUTLS_CRD_SRP, GNUTLS_CRD_SRP},
{GNUTLS_KX_SRP_RSA, GNUTLS_CRD_SRP, GNUTLS_CRD_CERTIFICATE},
@@ -83,41 +85,44 @@ struct gnutls_kx_algo_entry
gnutls_kx_algorithm_t algorithm;
mod_auth_st *auth_struct;
int needs_dh_params;
+ int needs_rsa_params;
};
typedef struct gnutls_kx_algo_entry gnutls_kx_algo_entry;
static const gnutls_kx_algo_entry _gnutls_kx_algorithms[] = {
#if defined(ENABLE_ANON) && defined(ENABLE_DHE)
- {"ANON-DH", GNUTLS_KX_ANON_DH, &anon_auth_struct, 1},
+ {"ANON-DH", GNUTLS_KX_ANON_DH, &anon_auth_struct, 1, 0},
#endif
#if defined(ENABLE_ANON) && defined(ENABLE_ECDHE)
- {"ANON-ECDH", GNUTLS_KX_ANON_ECDH, &anon_ecdh_auth_struct, 0},
+ {"ANON-ECDH", GNUTLS_KX_ANON_ECDH, &anon_ecdh_auth_struct, 0, 0},
#endif
{"RSA", GNUTLS_KX_RSA, &rsa_auth_struct, 0},
#ifdef ENABLE_DHE
- {"DHE-RSA", GNUTLS_KX_DHE_RSA, &dhe_rsa_auth_struct, 1},
- {"DHE-DSS", GNUTLS_KX_DHE_DSS, &dhe_dss_auth_struct, 1},
+ {"DHE-RSA", GNUTLS_KX_DHE_RSA, &dhe_rsa_auth_struct, 1, 0},
+ {"DHE-DSS", GNUTLS_KX_DHE_DSS, &dhe_dss_auth_struct, 1, 0},
#endif
#ifdef ENABLE_ECDHE
- {"ECDHE-RSA", GNUTLS_KX_ECDHE_RSA, &ecdhe_rsa_auth_struct, 0},
- {"ECDHE-ECDSA", GNUTLS_KX_ECDHE_ECDSA, &ecdhe_ecdsa_auth_struct, 0},
+ {"ECDHE-RSA", GNUTLS_KX_ECDHE_RSA, &ecdhe_rsa_auth_struct, 0, 0},
+ {"ECDHE-ECDSA", GNUTLS_KX_ECDHE_ECDSA, &ecdhe_ecdsa_auth_struct, 0, 0},
#endif
#ifdef ENABLE_SRP
- {"SRP-DSS", GNUTLS_KX_SRP_DSS, &srp_dss_auth_struct, 0},
- {"SRP-RSA", GNUTLS_KX_SRP_RSA, &srp_rsa_auth_struct, 0},
- {"SRP", GNUTLS_KX_SRP, &srp_auth_struct, 0},
+ {"SRP-DSS", GNUTLS_KX_SRP_DSS, &srp_dss_auth_struct, 0, 0},
+ {"SRP-RSA", GNUTLS_KX_SRP_RSA, &srp_rsa_auth_struct, 0, 0},
+ {"SRP", GNUTLS_KX_SRP, &srp_auth_struct, 0, 0},
#endif
#ifdef ENABLE_PSK
- {"PSK", GNUTLS_KX_PSK, &psk_auth_struct, 0},
+ {"PSK", GNUTLS_KX_PSK, &psk_auth_struct, 0, 0},
+ {"RSA-PSK", GNUTLS_KX_RSA_PSK, &rsa_psk_auth_struct, 0,
+ 1 /* needs RSA params */},
# ifdef ENABLE_DHE
{"DHE-PSK", GNUTLS_KX_DHE_PSK, &dhe_psk_auth_struct,
- 1 /* needs DHE params */},
+ 1 /* needs DHE params */, 0},
# endif
# ifdef ENABLE_ECDHE
- {"ECDHE-PSK", GNUTLS_KX_ECDHE_PSK, &ecdhe_psk_auth_struct, 0},
+ {"ECDHE-PSK", GNUTLS_KX_ECDHE_PSK, &ecdhe_psk_auth_struct, 0, 0},
# endif
#endif
- {0, 0, 0, 0}
+ {0, 0, 0, 0, 0}
};
#define GNUTLS_KX_LOOP(b) \
@@ -260,6 +265,14 @@ _gnutls_map_kx_get_kx (gnutls_credentials_type_t type, int server)
return ret;
}
+int
+_gnutls_kx_needs_rsa_params (gnutls_kx_algorithm_t algorithm)
+{
+ ssize_t ret = 0;
+ GNUTLS_KX_ALG_LOOP (ret = p->needs_rsa_params);
+ return ret;
+}
+
/* Returns the credentials type required for this
* Key exchange method.
*/
diff --git a/lib/algorithms/publickey.c b/lib/algorithms/publickey.c
index 7e5c8789b3..3de256336b 100644
--- a/lib/algorithms/publickey.c
+++ b/lib/algorithms/publickey.c
@@ -53,6 +53,7 @@ static const gnutls_pk_map pk_mappings[] = {
{GNUTLS_KX_ECDHE_ECDSA, GNUTLS_PK_EC, CIPHER_SIGN},
{GNUTLS_KX_DHE_DSS, GNUTLS_PK_DSA, CIPHER_SIGN},
{GNUTLS_KX_SRP_DSS, GNUTLS_PK_DSA, CIPHER_SIGN},
+ {GNUTLS_KX_RSA_PSK, GNUTLS_PK_RSA, CIPHER_ENCRYPT},
{0, 0, 0}
};
diff --git a/lib/auth/Makefile.am b/lib/auth/Makefile.am
index e1abdc0b35..3caad98ffe 100644
--- a/lib/auth/Makefile.am
+++ b/lib/auth/Makefile.am
@@ -35,7 +35,7 @@ endif
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 srp.c \
+ rsa_psk.c dhe_psk.c psk.c psk_passwd.c rsa.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 anon_ecdh.c \
ecdhe.c ecdhe.h
diff --git a/lib/auth/cert.h b/lib/auth/cert.h
index 03fd3e97b6..b0c7932f4a 100644
--- a/lib/auth/cert.h
+++ b/lib/auth/cert.h
@@ -42,6 +42,7 @@ typedef struct {
typedef struct gnutls_certificate_credentials_st
{
gnutls_dh_params_t dh_params;
+ gnutls_rsa_params_t rsa_params;
/* this callback is used to retrieve the DH or RSA
* parameters.
*/
@@ -145,6 +146,12 @@ void _gnutls_selected_certs_deinit (gnutls_session_t session);
void _gnutls_selected_certs_set (gnutls_session_t session,
gnutls_pcert_st * certs, int ncerts,
gnutls_privkey_t key, int need_free);
+
+gnutls_rsa_params_t _gnutls_certificate_get_rsa_params (gnutls_rsa_params_t
+ rsa_params,
+ gnutls_params_function
+ * func,
+ gnutls_session_t);
int _gnutls_get_auth_info_pcert (gnutls_pcert_st* gcert,
gnutls_certificate_type_t type,
diff --git a/lib/auth/psk.c b/lib/auth/psk.c
index 351eb286d0..053f6027fa 100644
--- a/lib/auth/psk.c
+++ b/lib/auth/psk.c
@@ -34,13 +34,9 @@
#include <gnutls_str.h>
#include <gnutls_datum.h>
-int _gnutls_gen_psk_server_kx (gnutls_session_t session, gnutls_buffer_st* data);
-int _gnutls_gen_psk_client_kx (gnutls_session_t, gnutls_buffer_st*);
int _gnutls_proc_psk_client_kx (gnutls_session_t, uint8_t *, size_t);
-int _gnutls_proc_psk_server_kx (gnutls_session_t session, uint8_t * data,
- size_t _data_size);
const mod_auth_st psk_auth_struct = {
"PSK",
diff --git a/lib/auth/psk.h b/lib/auth/psk.h
index 455cea7a69..1507425f47 100644
--- a/lib/auth/psk.h
+++ b/lib/auth/psk.h
@@ -67,6 +67,10 @@ typedef struct psk_auth_info_st psk_auth_info_st;
int
_gnutls_set_psk_session_key (gnutls_session_t session, gnutls_datum_t* key, gnutls_datum_t * psk2);
+int _gnutls_gen_psk_server_kx (gnutls_session_t session, gnutls_buffer_st* data);
+int _gnutls_gen_psk_client_kx (gnutls_session_t, gnutls_buffer_st*);
+int _gnutls_proc_psk_server_kx (gnutls_session_t session, uint8_t * data,
+ size_t _data_size);
int _gnutls_find_psk_key( gnutls_session_t session, gnutls_psk_client_credentials_t cred,
gnutls_datum_t * username, gnutls_datum_t* key, int* free);
diff --git a/lib/auth/rsa.c b/lib/auth/rsa.c
index 4f55fa46d3..5a17627f62 100644
--- a/lib/auth/rsa.c
+++ b/lib/auth/rsa.c
@@ -40,6 +40,7 @@
#include <random.h>
#include <gnutls_mpi.h>
#include <abstract_int.h>
+#include <auth/rsa_common.h>
int _gnutls_gen_rsa_client_kx (gnutls_session_t, gnutls_buffer_st*);
static int proc_rsa_client_kx (gnutls_session_t, uint8_t *, size_t);
@@ -63,7 +64,7 @@ const mod_auth_st rsa_auth_struct = {
/* This function reads the RSA parameters from peer's certificate;
*/
-static int
+int
_gnutls_get_public_rsa_params (gnutls_session_t session,
gnutls_pk_params_st * params)
{
diff --git a/lib/auth/rsa_common.h b/lib/auth/rsa_common.h
new file mode 100644
index 0000000000..858d18f174
--- /dev/null
+++ b/lib/auth/rsa_common.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2010
+ * Free Software Foundation, Inc.
+ *
+ * Copyright (C) 2011
+ * Bardenheuer GmbH, Munich and Bundesdruckerei GmbH, Berlin
+ *
+ * Copyright (C) 2013
+ * Frank Morgner <morgner@informatik.hu-berlin.de>
+ *
+ * Author: Frank Morgner
+ *
+ * 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 program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef AUTH_RSA_COMMON
+# define AUTH_RSA_COMMON
+
+#include <abstract_int.h>
+
+int
+_gnutls_get_public_rsa_params (gnutls_session_t session,
+ gnutls_pk_params_st * params);
+
+int
+_gnutls_get_private_rsa_params (gnutls_session_t session,
+ gnutls_pk_params_st** params);
+
+#endif
diff --git a/lib/auth/rsa_psk.c b/lib/auth/rsa_psk.c
new file mode 100644
index 0000000000..abb5199343
--- /dev/null
+++ b/lib/auth/rsa_psk.c
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2009, 2010
+ * Free Software Foundation, Inc.
+ *
+ * Copyright (C) 2011
+ * Bardenheuer GmbH, Munich and Bundesdruckerei GmbH, Berlin
+ *
+ * Copyright (C) 2013
+ * Frank Morgner
+ *
+ * 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
+ *
+ */
+
+#include <gnutls_int.h>
+
+#ifdef ENABLE_PSK
+
+#include "gnutls_auth.h"
+#include "gnutls_dh.h"
+#include "gnutls_errors.h"
+#include "gnutls_mpi.h"
+#include "gnutls_num.h"
+#include "gnutls_int.h"
+#include "gnutls_pk.h"
+#include "random.h"
+#include <abstract_int.h>
+#include <algorithms.h>
+#include <auth/dh_common.h>
+#include <auth/psk.h>
+#include <auth/psk_passwd.h>
+#include <auth/rsa_common.h>
+#include <cert.h>
+#include <gnutls_datum.h>
+#include <gnutls_state.h>
+
+static int _gnutls_gen_rsa_psk_client_kx (gnutls_session_t session, gnutls_buffer_st* data);
+static int _gnutls_proc_rsa_psk_client_kx (gnutls_session_t, uint8_t *, size_t);
+
+const mod_auth_st rsa_psk_auth_struct = {
+ "RSA PSK",
+ NULL,/*_gnutls_gen_cert_server_certificate,*/
+ NULL, /* generate_client_certificate */
+ _gnutls_gen_psk_server_kx,
+ _gnutls_gen_rsa_psk_client_kx,
+ NULL, /* generate_client_cert_vrfy */
+ NULL, /* generate_server_certificate_request */
+ _gnutls_proc_crt,
+ NULL, /* process_client_certificate */
+ _gnutls_proc_psk_server_kx,
+ _gnutls_proc_rsa_psk_client_kx,
+ NULL, /* process_client_cert_vrfy */
+ NULL /* process_server_certificate_reuqest */
+};
+
+/* This function reads the RSA parameters from the private key
+ */
+int
+_gnutls_get_private_rsa_params (gnutls_session_t session,
+ gnutls_pk_params_st** params)
+{
+ int ret;
+ gnutls_certificate_credentials_t cred;
+ gnutls_rsa_params_t rsa_params;
+
+ cred = (gnutls_certificate_credentials_t)
+ _gnutls_get_cred (session, GNUTLS_CRD_CERTIFICATE, NULL);
+ if (cred == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ if (session->internals.selected_cert_list == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ ret = _gnutls_pubkey_is_over_rsa_512(session->internals.selected_cert_list[0].pubkey);
+
+ if (_gnutls_cipher_suite_get_kx_algo
+ (session->security_parameters.cipher_suite)
+ != GNUTLS_KX_RSA_EXPORT || ret < 0)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ rsa_params =
+ _gnutls_certificate_get_rsa_params (cred->rsa_params,
+ cred->params_func, session);
+ /* EXPORT case: */
+ if (rsa_params == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS;
+ }
+
+ /* In the export case, we do use temporary RSA params
+ * of 512 bits size. The params in the certificate are
+ * used to sign this temporary stuff.
+ */
+ *params = &rsa_params->params;
+
+ return 0;
+}
+
+/* Set the PSK premaster secret.
+ */
+int
+set_rsa_psk_session_key (gnutls_session_t session,
+ gnutls_datum_t * rsa_secret)
+{
+ gnutls_datum_t pwd_psk = { NULL, 0 };
+ gnutls_datum_t *ppsk;
+ unsigned char *p;
+ size_t rsa_secret_size;
+ int ret;
+
+ if (session->security_parameters.entity == GNUTLS_CLIENT)
+ {
+ gnutls_psk_client_credentials_t cred;
+
+ cred = (gnutls_psk_client_credentials_t)
+ _gnutls_get_cred (session, GNUTLS_CRD_PSK, NULL);
+
+ if (cred == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ ppsk = &cred->key;
+
+ }
+ else
+ { /* SERVER side */
+ psk_auth_info_t info;
+
+ info = _gnutls_get_auth_info (session);
+
+ /* find the key of this username
+ */
+ ret = _gnutls_psk_pwd_find_entry (session, info->username, &pwd_psk);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+ ppsk = &pwd_psk;
+ }
+
+ rsa_secret_size = rsa_secret->size;
+
+ /* set the session key
+ */
+ session->key.key.size = 2 + rsa_secret_size + 2 + ppsk->size;
+ session->key.key.data = gnutls_malloc (session->key.key.size);
+ if (session->key.key.data == NULL)
+ {
+ gnutls_assert ();
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto error;
+ }
+
+ /* format of the premaster secret:
+ * (uint16_t) other_secret size (48)
+ * other_secret: 2 byte version + 46 byte random
+ * (uint16_t) psk_size
+ * the psk
+ */
+ _gnutls_write_uint16 (rsa_secret_size, session->key.key.data);
+ memcpy (&session->key.key.data[2], rsa_secret->data, rsa_secret->size);
+ p = &session->key.key.data[rsa_secret_size + 2];
+ _gnutls_write_uint16 (ppsk->size, p);
+ if (ppsk->data != NULL)
+ memcpy (p+2, ppsk->data, ppsk->size);
+
+ ret = 0;
+
+error:
+ _gnutls_free_datum (&pwd_psk);
+ return ret;
+}
+
+/* Generate client key exchange message
+ *
+ *
+ * struct {
+ * select (KeyExchangeAlgorithm) {
+ * uint8_t psk_identity<0..2^16-1>;
+ * EncryptedPreMasterSecret;
+ * } exchange_keys;
+ * } ClientKeyExchange;
+ */
+static int
+_gnutls_gen_rsa_psk_client_kx (gnutls_session_t session, gnutls_buffer_st* data)
+{
+ cert_auth_info_t auth = session->key.auth_info;
+ gnutls_datum_t sdata; /* data to send */
+ gnutls_pk_params_st params;
+ int ret;
+
+ if (auth == NULL)
+ {
+ /* this shouldn't have happened. The proc_certificate
+ * function should have detected that.
+ */
+ gnutls_assert ();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ gnutls_datum_t premaster_secret;
+ premaster_secret.size = GNUTLS_MASTER_SIZE;
+ premaster_secret.data = gnutls_secure_malloc (premaster_secret.size);
+
+ if (premaster_secret.data == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ /* Generate random */
+ ret = _gnutls_rnd (GNUTLS_RND_RANDOM, premaster_secret.data,
+ premaster_secret.size);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ /* Set version */
+ if (session->internals.rsa_pms_version[0] == 0)
+ {
+ premaster_secret.data[0] = _gnutls_get_adv_version_major (session);
+ premaster_secret.data[1] = _gnutls_get_adv_version_minor (session);
+ }
+ else
+ { /* use the version provided */
+ premaster_secret.data[0] = session->internals.rsa_pms_version[0];
+ premaster_secret.data[1] = session->internals.rsa_pms_version[1];
+ }
+
+ /* move RSA parameters to key (session).
+ */
+ if ((ret =
+ _gnutls_get_public_rsa_params (session, &params)) < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ /* Encrypt premaster secret */
+ if ((ret =
+ _gnutls_pk_encrypt (GNUTLS_PK_RSA, &sdata, &premaster_secret,
+ &params)) < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ gnutls_pk_params_release(&params);
+
+
+/* retrieve PSK credentials */
+ gnutls_psk_client_credentials_t cred;
+
+ cred = (gnutls_psk_client_credentials_t)
+ _gnutls_get_cred (session, GNUTLS_CRD_PSK, NULL);
+
+ if (cred == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ /* TODO: Bei dhe_psk wird keine PSK aufgerufen, wenn die Parameter
+ leer sind. Die Funktion wird an dieser Stelle dann abgebrochen.
+ Können diese womöglich an anderer Stelle übergeben werden? */
+ if (cred->username.data == NULL && cred->key.data == NULL &&
+ cred->get_function != NULL)
+ {
+ char *username;
+ gnutls_datum_t key;
+
+ ret = cred->get_function (session, &username, &key);
+ if (ret)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ ret = _gnutls_set_datum (&cred->username, username, strlen (username));
+ gnutls_free (username);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ _gnutls_free_datum (&key);
+ return ret;
+ }
+
+ ret = _gnutls_set_datum (&cred->key, key.data, key.size);
+ _gnutls_free_datum (&key);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ }
+ else if (cred->username.data == NULL || cred->key.data == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ /* Here we set the PSK key */
+ ret = set_rsa_psk_session_key (session, &premaster_secret);
+
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+
+/* Create message for client key exchange
+ *
+ * struct {
+ * uint8_t psk_identity<0..2^16-1>;
+ * EncryptedPreMasterSecret;
+ * }
+ */
+ _gnutls_buffer_init (data);
+
+ /* Write psk_identity and EncryptedPreMasterSecret into data stream
+ */
+ ret = _gnutls_buffer_append_data_prefix (data, 16, cred->username.data,
+ cred->username.size);
+ if (ret < 0)
+ {
+ _gnutls_free_datum (&sdata);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ ret = _gnutls_buffer_append_data_prefix (data, 16, sdata.data,
+ sdata.size);
+ if (ret < 0)
+ {
+ _gnutls_free_datum (&sdata);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ _gnutls_free_datum (&sdata);
+ _gnutls_free_datum (&premaster_secret);
+
+ return data->length;
+}
+
+/*
+ Process the client key exchange message
+*/
+static int
+_gnutls_proc_rsa_psk_client_kx (gnutls_session_t session, uint8_t * data,
+ size_t _data_size)
+{
+ gnutls_datum_t username;
+ psk_auth_info_t info;
+ gnutls_datum_t plaintext;
+ gnutls_datum_t ciphertext;
+ int ret, dsize;
+ gnutls_pk_params_st *params;
+ int randomize_key = 0;
+ ssize_t data_size = _data_size;
+ gnutls_psk_server_credentials_t cred;
+
+ cred = (gnutls_psk_server_credentials_t)
+ _gnutls_get_cred (session, GNUTLS_CRD_PSK, NULL);
+
+ if (cred == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
+ ret = _gnutls_auth_info_set (session, GNUTLS_CRD_PSK,
+ sizeof (psk_auth_info_st), 1);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ /*** 1. Extract user psk_identity ***/
+
+ DECR_LEN (data_size, 2);
+ username.size = _gnutls_read_uint16 (&data[0]);
+
+ DECR_LEN(data_size, username.size);
+
+ username.data = &data[2];
+
+ /* copy the username to the auth info structures
+ */
+ info = _gnutls_get_auth_info (session);
+
+ if (username.size > MAX_USERNAME_SIZE)
+ {
+ gnutls_assert();
+ return GNUTLS_E_ILLEGAL_SRP_USERNAME;
+ }
+
+ memcpy (info->username, username.data, username.size);
+ info->username[username.size] = 0;
+
+ /* Adjust data so it points to EncryptedPreMasterSecret */
+ data += username.size + 2;
+
+
+ /*** 2. Decrypt and extract EncryptedPreMasterSecret ***/
+
+ DECR_LEN (data_size, 2);
+ ciphertext.data = &data[2];
+ dsize = _gnutls_read_uint16 (data);
+
+ if (dsize != data_size)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+ }
+ ciphertext.size = dsize;
+
+
+ ret = _gnutls_get_private_rsa_params (session, &params);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ ret = _gnutls_pk_decrypt (GNUTLS_PK_RSA, &ciphertext, &plaintext, params); /* btype==2 */
+
+ if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE)
+ {
+ /* In case decryption fails then don't inform
+ * the peer. Just use a random key. (in order to avoid
+ * attack against pkcs-1 formating).
+ */
+ gnutls_assert ();
+ _gnutls_debug_log ("auth_rsa: Possible PKCS #1 format attack\n");
+ randomize_key = 1;
+ }
+ else
+ {
+ /* If the secret was properly formatted, then
+ * check the version number.
+ */
+ if (_gnutls_get_adv_version_major (session) != plaintext.data[0]
+ || _gnutls_get_adv_version_minor (session) != plaintext.data[1])
+ {
+ /* No error is returned here, if the version number check
+ * fails. We proceed normally.
+ * That is to defend against the attack described in the paper
+ * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima,
+ * Ondej Pokorny and Tomas Rosa.
+ */
+ gnutls_assert ();
+ _gnutls_debug_log
+ ("auth_rsa: Possible PKCS #1 version check format attack\n");
+ }
+ }
+
+
+ gnutls_datum_t premaster_secret;
+
+ if (randomize_key != 0)
+ {
+ premaster_secret.size = GNUTLS_MASTER_SIZE;
+ premaster_secret.data = gnutls_malloc (premaster_secret.size);
+ if (premaster_secret.data == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ /* we do not need strong random numbers here.
+ */
+ ret = _gnutls_rnd (GNUTLS_RND_NONCE, premaster_secret.data,
+ premaster_secret.size);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ }
+ else
+ {
+ premaster_secret.data = plaintext.data;
+ premaster_secret.size = plaintext.size;
+ }
+
+
+ /* This is here to avoid the version check attack
+ * discussed above.
+ */
+
+ premaster_secret.data[0] = _gnutls_get_adv_version_major (session);
+ premaster_secret.data[1] = _gnutls_get_adv_version_minor (session);
+
+ ret = set_rsa_psk_session_key (session, &premaster_secret);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ _gnutls_free_datum (&premaster_secret);
+ return 0;
+}
+
+#endif /* ENABLE_PSK */
diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c
index dffd6c16a4..a89adf4332 100644
--- a/lib/gnutls_cert.c
+++ b/lib/gnutls_cert.c
@@ -139,6 +139,45 @@ gnutls_certificate_free_ca_names (gnutls_certificate_credentials_t sc)
_gnutls_free_datum (&sc->x509_rdn_sequence);
}
+/*-
+ * _gnutls_certificate_get_rsa_params - Returns the RSA parameters pointer
+ * @rsa_params: holds the RSA parameters or NULL.
+ * @func: function to retrieve the parameters or NULL.
+ * @session: The session.
+ *
+ * This function will return the rsa parameters pointer.
+ -*/
+gnutls_rsa_params_t
+_gnutls_certificate_get_rsa_params (gnutls_rsa_params_t rsa_params,
+ gnutls_params_function * func,
+ gnutls_session_t session)
+{
+ gnutls_params_st params;
+ int ret;
+
+ if (session->internals.params.rsa_params)
+ {
+ return session->internals.params.rsa_params;
+ }
+
+ if (rsa_params)
+ {
+ session->internals.params.rsa_params = rsa_params;
+ }
+ else if (func)
+ {
+ ret = func (session, GNUTLS_PARAMS_RSA_EXPORT, &params);
+ if (ret == 0 && params.type == GNUTLS_PARAMS_RSA_EXPORT)
+ {
+ session->internals.params.rsa_params = params.params.rsa_export;
+ session->internals.params.free_rsa_params = params.deinit;
+ }
+ }
+
+ return session->internals.params.rsa_params;
+}
+
+
/**
* gnutls_certificate_free_credentials:
* @sc: is a #gnutls_certificate_credentials_t structure.
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index 8065d6b3e0..37d269b3fe 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -3252,6 +3252,20 @@ _gnutls_recv_hello_request (gnutls_session_t session, void *data,
}
}
+/* returns e and m, depends on the requested bits.
+ * We only support limited key sizes.
+ */
+static const gnutls_pk_params_st*
+_gnutls_rsa_params_to_mpi (gnutls_rsa_params_t rsa_params)
+{
+ if (rsa_params == NULL)
+ {
+ return NULL;
+ }
+
+ return &rsa_params->params;
+}
+
/* Returns 1 if the given KX has not the corresponding parameters
* (DH or RSA) set up. Otherwise returns 0.
*/
@@ -3262,6 +3276,7 @@ check_server_params (gnutls_session_t session,
{
int cred_type;
gnutls_dh_params_t dh_params = NULL;
+ gnutls_rsa_params_t rsa_params = NULL;
int j;
cred_type = _gnutls_map_kx_get_cred (kx, 1);
@@ -3280,6 +3295,10 @@ check_server_params (gnutls_session_t session,
dh_params =
_gnutls_get_dh_params (x509_cred->dh_params,
x509_cred->params_func, session);
+ rsa_params =
+ _gnutls_certificate_get_rsa_params (x509_cred->rsa_params,
+ x509_cred->params_func,
+ session);
}
/* Check also if the certificate supports the
@@ -3332,6 +3351,19 @@ check_server_params (gnutls_session_t session,
else
return 0; /* no need for params */
+ /* If the key exchange method needs RSA or DH params,
+ * but they are not set then remove it.
+ */
+ if (_gnutls_kx_needs_rsa_params (kx) != 0)
+ {
+ /* needs rsa params. */
+ if (_gnutls_rsa_params_to_mpi (rsa_params) == NULL)
+ {
+ gnutls_assert ();
+ return 1;
+ }
+ }
+
if (_gnutls_kx_needs_dh_params (kx) != 0)
{
/* needs DH params. */
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index bffa3e41d7..eaccdbaaf5 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -703,6 +703,8 @@ typedef struct
{
gnutls_dh_params_t dh_params;
int free_dh_params;
+ gnutls_rsa_params_t rsa_params;
+ int free_rsa_params;
} internal_params_st;
/* DTLS session state
diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c
index a7e8a6b81c..8ce1649a6e 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -233,6 +233,9 @@ deinit_internal_params (gnutls_session_t session)
gnutls_dh_params_deinit (session->internals.params.dh_params);
#endif
+ if (session->internals.params.free_rsa_params)
+ gnutls_rsa_params_deinit (session->internals.params.rsa_params);
+
_gnutls_handshake_hash_buffers_clear (session);
memset (&session->internals.params, 0, sizeof (session->internals.params));
@@ -1117,7 +1120,8 @@ _gnutls_session_is_psk (gnutls_session_t session)
kx =
_gnutls_cipher_suite_get_kx_algo (session->
security_parameters.cipher_suite);
- if (kx == GNUTLS_KX_PSK || kx == GNUTLS_KX_DHE_PSK)
+ if (kx == GNUTLS_KX_PSK || kx == GNUTLS_KX_DHE_PSK
+ || kx == GNUTLS_KX_RSA_PSK)
return 1;
return 0;
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index f2e6c8996c..25fb7fdc2d 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -144,6 +144,7 @@ extern "C"
* @GNUTLS_KX_PSK: PSK key-exchange algorithm.
* @GNUTLS_KX_DHE_PSK: DHE-PSK key-exchange algorithm.
* @GNUTLS_KX_ECDHE_PSK: ECDHE-PSK key-exchange algorithm.
+ * @GNUTLS_KX_RSA_PSK: RSA-PSK key-exchange algorithm.
*
* Enumeration of different key exchange algorithms.
*/
@@ -164,6 +165,7 @@ extern "C"
GNUTLS_KX_ECDHE_RSA = 12,
GNUTLS_KX_ECDHE_ECDSA = 13,
GNUTLS_KX_ECDHE_PSK = 14,
+ GNUTLS_KX_RSA_PSK = 15,
} gnutls_kx_algorithm_t;
/**