2 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2009, 2010
3 * Free Software Foundation, Inc.
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GnuTLS.
9 * The GnuTLS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
26 /* This file contains everything for the Ephemeral Diffie-Hellman
27 * (DHE) key exchange. This is used in the handshake procedure of the
28 * certificate authentication.
31 #include "gnutls_int.h"
32 #include "gnutls_auth.h"
33 #include "gnutls_errors.h"
34 #include "gnutls_dh.h"
35 #include "gnutls_num.h"
36 #include "gnutls_sig.h"
37 #include <gnutls_datum.h>
38 #include <gnutls_algorithms.h>
39 #include <auth_cert.h>
40 #include <gnutls_x509.h>
41 #include <gnutls_state.h>
42 #include <auth_dh_common.h>
44 static int gen_dhe_server_kx (gnutls_session_t, opaque **);
45 static int proc_dhe_server_kx (gnutls_session_t, opaque *, size_t);
46 static int proc_dhe_client_kx (gnutls_session_t, opaque *, size_t);
48 const mod_auth_st dhe_rsa_auth_struct = {
50 _gnutls_gen_cert_server_certificate,
51 _gnutls_gen_cert_client_certificate,
53 _gnutls_gen_dh_common_client_kx,
54 _gnutls_gen_cert_client_cert_vrfy, /* gen client cert vrfy */
55 _gnutls_gen_cert_server_cert_req, /* server cert request */
57 _gnutls_proc_cert_server_certificate,
58 _gnutls_proc_cert_client_certificate,
61 _gnutls_proc_cert_client_cert_vrfy, /* proc client cert vrfy */
62 _gnutls_proc_cert_cert_req /* proc server cert request */
65 const mod_auth_st dhe_dss_auth_struct = {
67 _gnutls_gen_cert_server_certificate,
68 _gnutls_gen_cert_client_certificate,
70 _gnutls_gen_dh_common_client_kx,
71 _gnutls_gen_cert_client_cert_vrfy, /* gen client cert vrfy */
72 _gnutls_gen_cert_server_cert_req, /* server cert request */
74 _gnutls_proc_cert_server_certificate,
75 _gnutls_proc_cert_client_certificate,
78 _gnutls_proc_cert_client_cert_vrfy, /* proc client cert vrfy */
79 _gnutls_proc_cert_cert_req /* proc server cert request */
84 gen_dhe_server_kx (gnutls_session_t session, opaque ** data)
88 int ret = 0, data_size;
89 gnutls_cert *apr_cert_list;
90 gnutls_privkey_t apr_pkey;
91 int apr_cert_list_length;
92 gnutls_datum_t signature = { NULL, 0 }, ddata;
93 gnutls_certificate_credentials_t cred;
94 gnutls_dh_params_t dh_params;
95 gnutls_sign_algorithm_t sign_algo;
96 gnutls_protocol_t ver = gnutls_protocol_get_version (session);
98 cred = (gnutls_certificate_credentials_t)
99 _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
103 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
106 /* find the appropriate certificate */
108 _gnutls_get_selected_cert (session, &apr_cert_list,
109 &apr_cert_list_length, &apr_pkey)) < 0)
116 _gnutls_get_dh_params (cred->dh_params, cred->params_func, session);
117 mpis = _gnutls_dh_params_to_mpi (dh_params);
121 return GNUTLS_E_NO_TEMPORARY_DH_PARAMS;
127 if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_CERTIFICATE,
128 sizeof (cert_auth_info_st), 0)) < 0)
134 _gnutls_dh_set_group (session, g, p);
136 ret = _gnutls_dh_common_print_server_kx (session, g, p, data, 0);
144 /* Generate the signature. */
147 ddata.size = data_size;
149 if (apr_cert_list_length > 0)
152 _gnutls_handshake_sign_data (session, &apr_cert_list[0],
153 apr_pkey, &ddata, &signature,
163 ret = data_size; /* do not put a signature - ILLEGAL! */
167 *data = gnutls_realloc_fast (*data, data_size + signature.size + 4);
171 ret = GNUTLS_E_MEMORY_ERROR;
175 if (_gnutls_version_has_selectable_sighash (ver))
177 const sign_algorithm_st *aid;
179 if (sign_algo == GNUTLS_SIGN_UNKNOWN)
181 ret = GNUTLS_E_UNKNOWN_ALGORITHM;
185 aid = _gnutls_sign_to_tls_aid (sign_algo);
189 ret = GNUTLS_E_UNKNOWN_ALGORITHM;
193 (*data)[data_size++] = aid->hash_algorithm;
194 (*data)[data_size++] = aid->sign_algorithm;
197 _gnutls_write_datum16 (&(*data)[data_size], signature);
198 data_size += signature.size + 2;
200 _gnutls_free_datum (&signature);
205 _gnutls_free_datum (&signature);
212 proc_dhe_server_kx (gnutls_session_t session, opaque * data,
217 gnutls_datum_t vparams, signature;
219 cert_auth_info_t info = _gnutls_get_auth_info (session);
220 ssize_t data_size = _data_size;
221 gnutls_cert peer_cert;
222 gnutls_sign_algorithm_t sign_algo = GNUTLS_SIGN_UNKNOWN;
223 gnutls_protocol_t ver = gnutls_protocol_get_version (session);
225 if (info == NULL || info->ncerts == 0)
228 /* we need this in order to get peer's certificate */
229 return GNUTLS_E_INTERNAL_ERROR;
232 ret = _gnutls_proc_dh_common_server_kx (session, data, _data_size, 0);
239 /* VERIFY SIGNATURE */
244 sigdata = &data[vparams.size];
245 if (_gnutls_version_has_selectable_sighash (ver))
247 sign_algorithm_st aid;
249 DECR_LEN (data_size, 1);
250 aid.hash_algorithm = *sigdata++;
251 DECR_LEN (data_size, 1);
252 aid.sign_algorithm = *sigdata++;
253 sign_algo = _gnutls_tls_aid_to_sign (&aid);
254 if (sign_algo == GNUTLS_SIGN_UNKNOWN)
257 return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
260 DECR_LEN (data_size, 2);
261 sigsize = _gnutls_read_uint16 (sigdata);
264 DECR_LEN (data_size, sigsize);
265 signature.data = sigdata;
266 signature.size = sigsize;
269 _gnutls_get_auth_info_gcert (&peer_cert,
270 session->security_parameters.cert_type,
271 info, CERT_NO_COPY)) < 0)
278 _gnutls_handshake_verify_data (session, &peer_cert, &vparams, &signature,
281 _gnutls_gcert_deinit (&peer_cert);
294 proc_dhe_client_kx (gnutls_session_t session, opaque * data,
297 gnutls_certificate_credentials_t cred;
300 const bigint_t *mpis;
301 gnutls_dh_params_t dh_params;
303 cred = (gnutls_certificate_credentials_t)
304 _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
308 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
312 _gnutls_get_dh_params (cred->dh_params, cred->params_func, session);
313 mpis = _gnutls_dh_params_to_mpi (dh_params);
317 return GNUTLS_E_NO_TEMPORARY_DH_PARAMS;
323 ret = _gnutls_proc_dh_common_client_kx (session, data, _data_size, g, p);