Tizen 2.0 Release
[external/libgnutls26.git] / lib / auth_dhe.c
1 /*
2  * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2009, 2010
3  * Free Software Foundation, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
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.
13  *
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.
18  *
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,
22  * USA
23  *
24  */
25
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.
29  */
30
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>
43
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);
47
48 const mod_auth_st dhe_rsa_auth_struct = {
49   "DHE_RSA",
50   _gnutls_gen_cert_server_certificate,
51   _gnutls_gen_cert_client_certificate,
52   gen_dhe_server_kx,
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 */
56
57   _gnutls_proc_cert_server_certificate,
58   _gnutls_proc_cert_client_certificate,
59   proc_dhe_server_kx,
60   proc_dhe_client_kx,
61   _gnutls_proc_cert_client_cert_vrfy,   /* proc client cert vrfy */
62   _gnutls_proc_cert_cert_req    /* proc server cert request */
63 };
64
65 const mod_auth_st dhe_dss_auth_struct = {
66   "DHE_DSS",
67   _gnutls_gen_cert_server_certificate,
68   _gnutls_gen_cert_client_certificate,
69   gen_dhe_server_kx,
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 */
73
74   _gnutls_proc_cert_server_certificate,
75   _gnutls_proc_cert_client_certificate,
76   proc_dhe_server_kx,
77   proc_dhe_client_kx,
78   _gnutls_proc_cert_client_cert_vrfy,   /* proc client cert vrfy */
79   _gnutls_proc_cert_cert_req    /* proc server cert request */
80 };
81
82
83 static int
84 gen_dhe_server_kx (gnutls_session_t session, opaque ** data)
85 {
86   bigint_t g, p;
87   const bigint_t *mpis;
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);
97
98   cred = (gnutls_certificate_credentials_t)
99     _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
100   if (cred == NULL)
101     {
102       gnutls_assert ();
103       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
104     }
105
106   /* find the appropriate certificate */
107   if ((ret =
108        _gnutls_get_selected_cert (session, &apr_cert_list,
109                                   &apr_cert_list_length, &apr_pkey)) < 0)
110     {
111       gnutls_assert ();
112       return ret;
113     }
114
115   dh_params =
116     _gnutls_get_dh_params (cred->dh_params, cred->params_func, session);
117   mpis = _gnutls_dh_params_to_mpi (dh_params);
118   if (mpis == NULL)
119     {
120       gnutls_assert ();
121       return GNUTLS_E_NO_TEMPORARY_DH_PARAMS;
122     }
123
124   p = mpis[0];
125   g = mpis[1];
126
127   if ((ret = _gnutls_auth_info_set (session, GNUTLS_CRD_CERTIFICATE,
128                                     sizeof (cert_auth_info_st), 0)) < 0)
129     {
130       gnutls_assert ();
131       return ret;
132     }
133
134   _gnutls_dh_set_group (session, g, p);
135
136   ret = _gnutls_dh_common_print_server_kx (session, g, p, data, 0);
137   if (ret < 0)
138     {
139       gnutls_assert ();
140       return ret;
141     }
142   data_size = ret;
143
144   /* Generate the signature. */
145
146   ddata.data = *data;
147   ddata.size = data_size;
148
149   if (apr_cert_list_length > 0)
150     {
151       if ((ret =
152            _gnutls_handshake_sign_data (session, &apr_cert_list[0],
153                                         apr_pkey, &ddata, &signature,
154                                         &sign_algo)) < 0)
155         {
156           gnutls_assert ();
157           goto cleanup;
158         }
159     }
160   else
161     {
162       gnutls_assert ();
163       ret = data_size;         /* do not put a signature - ILLEGAL! */
164       goto cleanup;
165     }
166
167   *data = gnutls_realloc_fast (*data, data_size + signature.size + 4);
168   if (*data == NULL)
169     {
170       gnutls_assert ();
171       ret = GNUTLS_E_MEMORY_ERROR;
172       goto cleanup;
173     }
174
175   if (_gnutls_version_has_selectable_sighash (ver))
176     {
177       const sign_algorithm_st *aid;
178
179       if (sign_algo == GNUTLS_SIGN_UNKNOWN)
180         {
181           ret = GNUTLS_E_UNKNOWN_ALGORITHM;
182           goto cleanup;
183         }
184
185       aid = _gnutls_sign_to_tls_aid (sign_algo);
186       if (aid == NULL)
187         {
188           gnutls_assert();
189           ret = GNUTLS_E_UNKNOWN_ALGORITHM;
190           goto cleanup;
191         }
192       
193       (*data)[data_size++] = aid->hash_algorithm;
194       (*data)[data_size++] = aid->sign_algorithm;
195     }
196
197   _gnutls_write_datum16 (&(*data)[data_size], signature);
198   data_size += signature.size + 2;
199
200   _gnutls_free_datum (&signature);
201
202   return data_size;
203
204 cleanup:
205   _gnutls_free_datum (&signature);
206   gnutls_free(*data);
207   return ret;
208
209 }
210
211 static int
212 proc_dhe_server_kx (gnutls_session_t session, opaque * data,
213                     size_t _data_size)
214 {
215   int sigsize;
216   opaque *sigdata;
217   gnutls_datum_t vparams, signature;
218   int ret;
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);
224
225   if (info == NULL || info->ncerts == 0)
226     {
227       gnutls_assert ();
228       /* we need this in order to get peer's certificate */
229       return GNUTLS_E_INTERNAL_ERROR;
230     }
231
232   ret = _gnutls_proc_dh_common_server_kx (session, data, _data_size, 0);
233   if (ret < 0)
234     {
235       gnutls_assert ();
236       return ret;
237     }
238
239   /* VERIFY SIGNATURE */
240
241   vparams.size = ret;
242   vparams.data = data;
243
244   sigdata = &data[vparams.size];
245   if (_gnutls_version_has_selectable_sighash (ver))
246     {
247       sign_algorithm_st aid;
248
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)
255         {
256           gnutls_assert ();
257           return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
258         }
259     }
260   DECR_LEN (data_size, 2);
261   sigsize = _gnutls_read_uint16 (sigdata);
262   sigdata += 2;
263
264   DECR_LEN (data_size, sigsize);
265   signature.data = sigdata;
266   signature.size = sigsize;
267
268   if ((ret =
269        _gnutls_get_auth_info_gcert (&peer_cert,
270                                     session->security_parameters.cert_type,
271                                     info, CERT_NO_COPY)) < 0)
272     {
273       gnutls_assert ();
274       return ret;
275     }
276
277   ret =
278     _gnutls_handshake_verify_data (session, &peer_cert, &vparams, &signature,
279                                    sign_algo);
280
281   _gnutls_gcert_deinit (&peer_cert);
282   if (ret < 0)
283     {
284       gnutls_assert ();
285       return ret;
286     }
287
288   return ret;
289 }
290
291
292
293 static int
294 proc_dhe_client_kx (gnutls_session_t session, opaque * data,
295                     size_t _data_size)
296 {
297   gnutls_certificate_credentials_t cred;
298   int ret;
299   bigint_t p, g;
300   const bigint_t *mpis;
301   gnutls_dh_params_t dh_params;
302
303   cred = (gnutls_certificate_credentials_t)
304     _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
305   if (cred == NULL)
306     {
307       gnutls_assert ();
308       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
309     }
310
311   dh_params =
312     _gnutls_get_dh_params (cred->dh_params, cred->params_func, session);
313   mpis = _gnutls_dh_params_to_mpi (dh_params);
314   if (mpis == NULL)
315     {
316       gnutls_assert ();
317       return GNUTLS_E_NO_TEMPORARY_DH_PARAMS;
318     }
319
320   p = mpis[0];
321   g = mpis[1];
322
323   ret = _gnutls_proc_dh_common_client_kx (session, data, _data_size, g, p);
324
325   return ret;
326
327 }