Tizen 2.0 Release
[external/libgnutls26.git] / lib / auth_dh_common.c
1 /*
2  * Copyright (C) 2002, 2003, 2004, 2005, 2007, 2009, 2010 Free Software
3  * 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 common stuff in Ephemeral Diffie-Hellman (DHE)
27  * and Anonymous DH key exchange(DHA). These are used in the handshake
28  * procedure of the certificate and anoymous 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_x509.h>
39 #include <gnutls_state.h>
40 #include <auth_dh_common.h>
41 #include <gnutls_algorithms.h>
42 #include <auth_psk.h>
43
44 /* Frees the dh_info_st structure.
45  */
46 void
47 _gnutls_free_dh_info (dh_info_st * dh)
48 {
49   dh->secret_bits = 0;
50   _gnutls_free_datum (&dh->prime);
51   _gnutls_free_datum (&dh->generator);
52   _gnutls_free_datum (&dh->public_key);
53 }
54
55 int
56 _gnutls_proc_dh_common_client_kx (gnutls_session_t session,
57                                   opaque * data, size_t _data_size,
58                                   bigint_t g, bigint_t p)
59 {
60   uint16_t n_Y;
61   size_t _n_Y;
62   int ret;
63   ssize_t data_size = _data_size;
64
65
66   DECR_LEN (data_size, 2);
67   n_Y = _gnutls_read_uint16 (&data[0]);
68   _n_Y = n_Y;
69
70   DECR_LEN (data_size, n_Y);
71   if (_gnutls_mpi_scan_nz (&session->key->client_Y, &data[2], _n_Y))
72     {
73       gnutls_assert ();
74       return GNUTLS_E_MPI_SCAN_FAILED;
75     }
76
77   _gnutls_dh_set_peer_public (session, session->key->client_Y);
78
79   session->key->KEY =
80     gnutls_calc_dh_key (session->key->client_Y, session->key->dh_secret, p);
81
82   if (session->key->KEY == NULL)
83     {
84       gnutls_assert ();
85       return GNUTLS_E_MEMORY_ERROR;
86     }
87
88   _gnutls_mpi_release (&session->key->client_Y);
89   _gnutls_mpi_release (&session->key->dh_secret);
90
91
92   if (_gnutls_cipher_suite_get_kx_algo
93       (&session->security_parameters.current_cipher_suite)
94       != GNUTLS_KX_DHE_PSK)
95     {
96       ret = _gnutls_mpi_dprint (session->key->KEY, &session->key->key);
97     }
98   else                          /* In DHE_PSK the key is set differently */
99     {
100       gnutls_datum_t tmp_dh_key;
101       ret = _gnutls_mpi_dprint (session->key->KEY, &tmp_dh_key);
102       if (ret < 0)
103         {
104           gnutls_assert ();
105           return ret;
106         }
107
108       ret = _gnutls_set_psk_session_key (session, NULL, &tmp_dh_key);
109       _gnutls_free_datum (&tmp_dh_key);
110
111     }
112
113   _gnutls_mpi_release (&session->key->KEY);
114
115   if (ret < 0)
116     {
117       return ret;
118     }
119
120   return 0;
121 }
122
123 int _gnutls_gen_dh_common_client_kx (gnutls_session_t session, opaque** data)
124 {
125   return _gnutls_gen_dh_common_client_kx_int(session, data, NULL);
126 }
127
128 int
129 _gnutls_gen_dh_common_client_kx_int (gnutls_session_t session, opaque ** data, gnutls_datum_t* pskkey)
130 {
131   bigint_t x = NULL, X = NULL;
132   size_t n_X;
133   int ret;
134
135   *data = NULL;
136
137   X = gnutls_calc_dh_secret (&x, session->key->client_g,
138                              session->key->client_p);
139   if (X == NULL || x == NULL)
140     {
141       gnutls_assert ();
142       ret = GNUTLS_E_MEMORY_ERROR;
143       goto error;
144     }
145
146   _gnutls_dh_set_secret_bits (session, _gnutls_mpi_get_nbits (x));
147
148   _gnutls_mpi_print (X, NULL, &n_X);
149   (*data) = gnutls_malloc (n_X + 2);
150   if (*data == NULL)
151     {
152       ret = GNUTLS_E_MEMORY_ERROR;
153       goto error;
154     }
155
156   _gnutls_mpi_print (X, &(*data)[2], &n_X);
157   _gnutls_mpi_release (&X);
158
159   _gnutls_write_uint16 (n_X, &(*data)[0]);
160
161   /* calculate the key after calculating the message */
162   session->key->KEY =
163     gnutls_calc_dh_key (session->key->client_Y, x, session->key->client_p);
164
165   if (session->key->KEY == NULL)
166     {
167       gnutls_assert ();
168       ret = GNUTLS_E_MEMORY_ERROR;
169       goto error;
170     }
171
172   /* THESE SHOULD BE DISCARDED */
173   _gnutls_mpi_release (&session->key->client_Y);
174   _gnutls_mpi_release (&session->key->client_p);
175   _gnutls_mpi_release (&session->key->client_g);
176
177   if (_gnutls_cipher_suite_get_kx_algo
178       (&session->security_parameters.current_cipher_suite)
179       != GNUTLS_KX_DHE_PSK)
180     {
181       ret = _gnutls_mpi_dprint (session->key->KEY, &session->key->key);
182     }
183   else                          /* In DHE_PSK the key is set differently */
184     {
185       gnutls_datum_t tmp_dh_key;
186
187       ret = _gnutls_mpi_dprint (session->key->KEY, &tmp_dh_key);
188       if (ret < 0)
189         {
190           gnutls_assert ();
191           goto error;
192         }
193
194       ret = _gnutls_set_psk_session_key (session, pskkey, &tmp_dh_key);
195       _gnutls_free_datum (&tmp_dh_key);
196     }
197
198   _gnutls_mpi_release (&session->key->KEY);
199
200   if (ret < 0)
201     {
202       gnutls_assert ();
203       goto error;
204     }
205
206   ret = n_X + 2;
207
208 error:
209   _gnutls_mpi_release (&x);
210   _gnutls_mpi_release (&X);
211   
212   if (ret < 0)
213     {
214       gnutls_free (*data);
215       *data = NULL;
216     }
217   return ret;
218 }
219
220 int
221 _gnutls_proc_dh_common_server_kx (gnutls_session_t session,
222                                   opaque * data, size_t _data_size, int psk)
223 {
224   uint16_t n_Y, n_g, n_p;
225   size_t _n_Y, _n_g, _n_p;
226   uint8_t *data_p;
227   uint8_t *data_g;
228   uint8_t *data_Y;
229   int i, bits, psk_size, ret;
230   ssize_t data_size = _data_size;
231
232   i = 0;
233
234   if (psk != 0)
235     {
236       DECR_LEN (data_size, 2);
237       psk_size = _gnutls_read_uint16 (&data[i]);
238       DECR_LEN (data_size, psk_size);
239       i += 2 + psk_size;
240     }
241
242   DECR_LEN (data_size, 2);
243   n_p = _gnutls_read_uint16 (&data[i]);
244   i += 2;
245
246   DECR_LEN (data_size, n_p);
247   data_p = &data[i];
248   i += n_p;
249
250   DECR_LEN (data_size, 2);
251   n_g = _gnutls_read_uint16 (&data[i]);
252   i += 2;
253
254   DECR_LEN (data_size, n_g);
255   data_g = &data[i];
256   i += n_g;
257
258   DECR_LEN (data_size, 2);
259   n_Y = _gnutls_read_uint16 (&data[i]);
260   i += 2;
261
262   DECR_LEN (data_size, n_Y);
263   data_Y = &data[i];
264   i += n_Y;
265
266   _n_Y = n_Y;
267   _n_g = n_g;
268   _n_p = n_p;
269
270   if (_gnutls_mpi_scan_nz (&session->key->client_Y, data_Y, _n_Y) != 0)
271     {
272       gnutls_assert ();
273       return GNUTLS_E_MPI_SCAN_FAILED;
274     }
275
276   if (_gnutls_mpi_scan_nz (&session->key->client_g, data_g, _n_g) != 0)
277     {
278       gnutls_assert ();
279       return GNUTLS_E_MPI_SCAN_FAILED;
280     }
281   if (_gnutls_mpi_scan_nz (&session->key->client_p, data_p, _n_p) != 0)
282     {
283       gnutls_assert ();
284       return GNUTLS_E_MPI_SCAN_FAILED;
285     }
286
287   bits = _gnutls_dh_get_allowed_prime_bits (session);
288   if (bits < 0)
289     {
290       gnutls_assert ();
291       return bits;
292     }
293
294   if (_gnutls_mpi_get_nbits (session->key->client_p) < (size_t) bits)
295     {
296       /* the prime used by the peer is not acceptable
297        */
298       gnutls_assert ();
299       return GNUTLS_E_DH_PRIME_UNACCEPTABLE;
300     }
301
302   _gnutls_dh_set_group (session, session->key->client_g,
303                         session->key->client_p);
304   _gnutls_dh_set_peer_public (session, session->key->client_Y);
305
306   ret = n_Y + n_p + n_g + 6;
307   if (psk != 0)
308     ret += 2;
309
310   return ret;
311 }
312
313 /* If the psk flag is set, then an empty psk_identity_hint will
314  * be inserted */
315 int
316 _gnutls_dh_common_print_server_kx (gnutls_session_t session,
317                                    bigint_t g, bigint_t p, opaque ** data,
318                                    int psk)
319 {
320   bigint_t x, X;
321   size_t n_X, n_g, n_p;
322   int ret, data_size, pos;
323   uint8_t *pdata;
324
325   X = gnutls_calc_dh_secret (&x, g, p);
326   if (X == NULL || x == NULL)
327     {
328       gnutls_assert ();
329       return GNUTLS_E_MEMORY_ERROR;
330     }
331
332   session->key->dh_secret = x;
333   _gnutls_dh_set_secret_bits (session, _gnutls_mpi_get_nbits (x));
334
335   _gnutls_mpi_print (g, NULL, &n_g);
336   _gnutls_mpi_print (p, NULL, &n_p);
337   _gnutls_mpi_print (X, NULL, &n_X);
338
339   data_size = n_g + n_p + n_X + 6;
340   if (psk != 0)
341     data_size += 2;
342
343   (*data) = gnutls_malloc (data_size);
344   if (*data == NULL)
345     {
346       _gnutls_mpi_release (&X);
347       return GNUTLS_E_MEMORY_ERROR;
348     }
349
350   pos = 0;
351   pdata = *data;
352
353   if (psk != 0)
354     {
355       _gnutls_write_uint16 (0, &pdata[pos]);
356       pos += 2;
357     }
358
359   _gnutls_mpi_print (p, &pdata[pos + 2], &n_p);
360   _gnutls_write_uint16 (n_p, &pdata[pos]);
361
362   pos += n_p + 2;
363
364   _gnutls_mpi_print (g, &pdata[pos + 2], &n_g);
365   _gnutls_write_uint16 (n_g, &pdata[pos]);
366
367   pos += n_g + 2;
368
369   _gnutls_mpi_print (X, &pdata[pos + 2], &n_X);
370   _gnutls_mpi_release (&X);
371
372   _gnutls_write_uint16 (n_X, &pdata[pos]);
373
374   /* do not use data_size. _gnutls_mpi_print() might
375    * have been pessimist and might have returned initially
376    * more data */
377   ret = n_g + n_p + n_X + 6;
378   if (psk != 0)
379     ret += 2;
380
381   return ret;
382 }