Tizen 2.0 Release
[external/libgnutls26.git] / lib / ext_signature.c
1 /*
2  * Copyright (C) 2002,2003,2004,2005,2009,2010,2011 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 the code the Certificate Type TLS extension.
27  * This extension is currently gnutls specific.
28  */
29
30 #include "gnutls_int.h"
31 #include "gnutls_errors.h"
32 #include "gnutls_num.h"
33 #include <ext_signature.h>
34 #include <gnutls_state.h>
35 #include <gnutls_num.h>
36 #include <gnutls_algorithms.h>
37 #include <x509/common.h> /* dsa_q_to_hash */
38 #include <gnutls_cert.h>
39
40 static int _gnutls_signature_algorithm_recv_params (gnutls_session_t session,
41                                                     const opaque * data,
42                                                     size_t data_size);
43 static int _gnutls_signature_algorithm_send_params (gnutls_session_t session,
44                                                     opaque * data, size_t);
45 static void signature_algorithms_deinit_data (extension_priv_data_t priv);
46 static int signature_algorithms_pack (extension_priv_data_t epriv,
47                                       gnutls_buffer_st * ps);
48 static int signature_algorithms_unpack (gnutls_buffer_st * ps,
49                                         extension_priv_data_t * _priv);
50
51 extension_entry_st ext_mod_sig = {
52   .name = "SIGNATURE ALGORITHMS",
53   .type = GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS,
54   .parse_type = GNUTLS_EXT_TLS,
55
56   .recv_func = _gnutls_signature_algorithm_recv_params,
57   .send_func = _gnutls_signature_algorithm_send_params,
58   .pack_func = signature_algorithms_pack,
59   .unpack_func = signature_algorithms_unpack,
60   .deinit_func = signature_algorithms_deinit_data,
61 };
62
63 typedef struct
64 {
65   /* TLS 1.2 signature algorithms */
66   gnutls_sign_algorithm_t sign_algorithms[MAX_SIGNATURE_ALGORITHMS];
67   uint16_t sign_algorithms_size;
68 } sig_ext_st;
69
70 /* generates a SignatureAndHashAlgorithm structure with length as prefix
71  * by using the setup priorities.
72  */
73 int
74 _gnutls_sign_algorithm_write_params (gnutls_session_t session, opaque * data,
75                                      size_t max_data_size)
76 {
77   opaque *p = data, *len_p;
78   int len, i, j, hash;
79   const sign_algorithm_st *aid;
80
81   if (max_data_size < (session->internals.priorities.sign_algo.algorithms*2) + 2)
82     {
83       gnutls_assert ();
84       return GNUTLS_E_SHORT_MEMORY_BUFFER;
85     }
86
87   len = 0;
88   len_p = p;
89
90   p += 2;
91
92   for (i = j = 0; j < session->internals.priorities.sign_algo.algorithms; i += 2, j++)
93     {
94       /* In gnutls we keep a state of SHA1 and SHA256 and thus cannot
95        * use anything else.
96        */
97       hash = _gnutls_sign_get_hash_algorithm(session->internals.priorities.sign_algo.priority[j]);
98       if (hash != GNUTLS_DIG_SHA1 && hash != GNUTLS_DIG_SHA256)
99         continue;
100       
101       aid =
102         _gnutls_sign_to_tls_aid (session->internals.priorities.
103                                  sign_algo.priority[j]);
104
105       if (aid == NULL)
106         continue;
107         
108        _gnutls_debug_log ("EXT[SIGA]: sent signature algo (%d.%d) %s\n", aid->hash_algorithm, 
109          aid->sign_algorithm, gnutls_sign_get_name(session->internals.priorities.sign_algo.priority[j]));
110       *p = aid->hash_algorithm;
111       p++;
112       *p = aid->sign_algorithm;
113       p++;
114       len+=2;
115     }
116
117   _gnutls_write_uint16 (len, len_p);
118
119   return len + 2;
120 }
121
122
123 /* Parses the Signature Algorithm structure and stores data into
124  * session->security_parameters.extensions.
125  */
126 int
127 _gnutls_sign_algorithm_parse_data (gnutls_session_t session,
128                                    const opaque * data, size_t data_size)
129 {
130   int sig, i, hash;
131   sig_ext_st *priv;
132   extension_priv_data_t epriv;
133
134   priv = gnutls_calloc (1, sizeof (*priv));
135   if (priv == NULL)
136     {
137       gnutls_assert ();
138       return GNUTLS_E_MEMORY_ERROR;
139     }
140
141   for (i = 0; i < data_size; i += 2)
142     {
143       sign_algorithm_st aid;
144
145       aid.hash_algorithm = data[i];
146       aid.sign_algorithm = data[i + 1];
147
148       sig = _gnutls_tls_aid_to_sign (&aid);
149
150        _gnutls_debug_log ("EXT[SIGA]: rcvd signature algo (%d.%d) %s\n", aid.hash_algorithm, 
151          aid.sign_algorithm, gnutls_sign_get_name(sig));
152
153
154       if (sig != GNUTLS_SIGN_UNKNOWN)
155         {
156           hash = _gnutls_sign_get_hash_algorithm(sig);
157           if (hash != GNUTLS_DIG_SHA1 && hash != GNUTLS_DIG_SHA256)
158             continue;
159
160           priv->sign_algorithms[priv->sign_algorithms_size++] = sig;
161           if (priv->sign_algorithms_size == MAX_SIGNATURE_ALGORITHMS)
162             break;
163         }
164     }
165
166   epriv.ptr = priv;
167   _gnutls_ext_set_session_data (session,
168                                 GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS, epriv);
169
170   return 0;
171 }
172
173 /*
174  * In case of a server: if a SIGNATURE_ALGORITHMS extension type is
175  * received then it stores into the session security parameters the
176  * new value.
177  *
178  * In case of a client: If a signature_algorithms have been specified
179  * then it is an error;
180  */
181
182 static int
183 _gnutls_signature_algorithm_recv_params (gnutls_session_t session,
184                                          const opaque * data,
185                                          size_t _data_size)
186 {
187   ssize_t data_size = _data_size;
188   int ret;
189
190   if (session->security_parameters.entity == GNUTLS_CLIENT)
191     {
192       /* nothing for now */
193       gnutls_assert ();
194       /* Although TLS 1.2 mandates that we must not accept reply
195        * to this message, there are good reasons to just ignore it. Check
196        * http://www.ietf.org/mail-archive/web/tls/current/msg03880.html
197        */
198       /* return GNUTLS_E_UNEXPECTED_PACKET; */
199     }
200   else
201     {
202       /* SERVER SIDE - we must check if the sent cert type is the right one
203        */
204       if (data_size > 2)
205         {
206           uint16_t len;
207
208           DECR_LEN (data_size, 2);
209           len = _gnutls_read_uint16 (data);
210           DECR_LEN (data_size, len);
211
212           ret = _gnutls_sign_algorithm_parse_data (session, data + 2, len);
213           if (ret < 0)
214             {
215               gnutls_assert ();
216               return ret;
217             }
218         }
219     }
220
221   return 0;
222 }
223
224 /* returns data_size or a negative number on failure
225  */
226 static int
227 _gnutls_signature_algorithm_send_params (gnutls_session_t session,
228                                          opaque * data, size_t data_size)
229 {
230   int ret;
231   gnutls_protocol_t ver = gnutls_protocol_get_version (session);
232
233   /* this function sends the client extension data */
234   if (session->security_parameters.entity == GNUTLS_CLIENT
235       && _gnutls_version_has_selectable_sighash (ver))
236     {
237       if (session->internals.priorities.sign_algo.algorithms > 0)
238         {
239           ret =
240             _gnutls_sign_algorithm_write_params (session, data, data_size);
241           if (ret < 0)
242             {
243               gnutls_assert ();
244               return ret;
245             }
246           return ret;
247         }
248     }
249
250   /* if we are here it means we don't send the extension */
251   return 0;
252 }
253
254 int cert_compatible_with_sig(gnutls_cert* cert, gnutls_protocol_t ver, 
255   gnutls_sign_algorithm_t sign)
256 {
257 unsigned int hash_len;
258
259   if (cert->subject_pk_algorithm == GNUTLS_PK_DSA)
260     { /* override */
261       int hash_algo = _gnutls_dsa_q_to_hash (cert->params[1], &hash_len);
262
263       /* DSA keys over 1024 bits cannot be used with TLS 1.x, x<2 */
264       if (!_gnutls_version_has_selectable_sighash (ver))
265         {
266           if (hash_algo != GNUTLS_DIG_SHA1)
267             return gnutls_assert_val(GNUTLS_E_INCOMPAT_DSA_KEY_WITH_TLS_PROTOCOL);
268         }
269       else
270         {
271           if (_gnutls_hash_get_algo_len(_gnutls_sign_get_hash_algorithm(sign)) < hash_len)
272             return GNUTLS_E_UNWANTED_ALGORITHM;
273         }
274         
275     }
276
277   return 0;
278 }
279
280 /* Returns a requested by the peer signature algorithm that
281  * matches the given public key algorithm. Index can be increased
282  * to return the second choice etc.
283  */
284 gnutls_sign_algorithm_t
285 _gnutls_session_get_sign_algo (gnutls_session_t session, gnutls_cert* cert)
286 {
287   unsigned i;
288   int ret;
289   gnutls_protocol_t ver = gnutls_protocol_get_version (session);
290   sig_ext_st *priv;
291   extension_priv_data_t epriv;
292
293   ret =
294     _gnutls_ext_get_session_data (session,
295                                   GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS,
296                                   &epriv);
297   priv = epriv.ptr;
298
299   if (ret < 0 || !_gnutls_version_has_selectable_sighash (ver)
300       || priv->sign_algorithms_size == 0)
301     /* none set, allow SHA-1 only */
302     {
303       return _gnutls_x509_pk_to_sign (cert->subject_pk_algorithm, GNUTLS_DIG_SHA1);
304     }
305
306   for (i = 0; i < priv->sign_algorithms_size; i++)
307     {
308       if (_gnutls_sign_get_pk_algorithm (priv->sign_algorithms[i]) == cert->subject_pk_algorithm)
309         {
310           if (cert_compatible_with_sig(cert, ver, priv->sign_algorithms[i]) < 0)
311             continue;
312
313           return priv->sign_algorithms[i];
314         }
315     }
316
317   return GNUTLS_SIGN_UNKNOWN;
318 }
319
320
321 /* Check if the given signature algorithm is accepted by
322  * the peer. Returns 0 on success or a negative value
323  * on error.
324  */
325 int
326 _gnutls_session_sign_algo_requested (gnutls_session_t session,
327                                      gnutls_sign_algorithm_t sig)
328 {
329   unsigned i;
330   int ret, hash;
331   gnutls_protocol_t ver = gnutls_protocol_get_version (session);
332   sig_ext_st *priv;
333   extension_priv_data_t epriv;
334
335   if (!_gnutls_version_has_selectable_sighash (ver))
336     {
337       return 0;
338     }
339
340   ret =
341     _gnutls_ext_get_session_data (session,
342                                   GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS,
343                                   &epriv);
344   if (ret < 0)
345     {
346       gnutls_assert ();
347       /* extension not received allow SHA1 and SHA256 */
348       hash = _gnutls_sign_get_hash_algorithm (sig);
349       if (hash == GNUTLS_DIG_SHA1 || hash == GNUTLS_DIG_SHA256)
350         return 0;
351       else
352         return ret;
353     }
354   priv = epriv.ptr;
355
356   if (priv->sign_algorithms_size == 0)
357     /* none set, allow all */
358     {
359       return 0;
360     }
361
362   for (i = 0; i < priv->sign_algorithms_size; i++)
363     {
364       if (priv->sign_algorithms[i] == sig)
365         {
366           return 0;             /* ok */
367         }
368     }
369
370   return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
371 }
372
373 /* Check if the given signature algorithm is supported.
374  * This means that it is enabled by the priority functions,
375  * and in case of a server a matching certificate exists.
376  */
377 int
378 _gnutls_session_sign_algo_enabled (gnutls_session_t session,
379                                    gnutls_sign_algorithm_t sig)
380 {
381   unsigned i;
382   int ret;
383   gnutls_protocol_t ver = gnutls_protocol_get_version (session);
384   sig_ext_st *priv;
385   extension_priv_data_t epriv;
386
387   ret =
388     _gnutls_ext_get_session_data (session,
389                                   GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS,
390                                   &epriv);
391   if (ret < 0)
392     {
393       gnutls_assert ();
394       return 0;
395     }
396   priv = epriv.ptr;
397
398   if (!_gnutls_version_has_selectable_sighash (ver)
399       || priv->sign_algorithms_size == 0)
400     /* none set, allow all */
401     {
402       return 0;
403     }
404
405   for (i = 0; i < session->internals.priorities.sign_algo.algorithms; i++)
406     {
407       if (session->internals.priorities.sign_algo.priority[i] == sig)
408         {
409           return 0;             /* ok */
410         }
411     }
412
413   return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM;
414 }
415
416 static void
417 signature_algorithms_deinit_data (extension_priv_data_t priv)
418 {
419   gnutls_free (priv.ptr);
420 }
421
422 static int
423 signature_algorithms_pack (extension_priv_data_t epriv, gnutls_buffer_st * ps)
424 {
425   sig_ext_st *priv = epriv.ptr;
426   int ret, i;
427
428   BUFFER_APPEND_NUM (ps, priv->sign_algorithms_size);
429   for (i = 0; i < priv->sign_algorithms_size; i++)
430     {
431       BUFFER_APPEND_NUM (ps, priv->sign_algorithms[i]);
432     }
433   return 0;
434 }
435
436 static int
437 signature_algorithms_unpack (gnutls_buffer_st * ps,
438                              extension_priv_data_t * _priv)
439 {
440   sig_ext_st *priv;
441   int i, ret;
442   extension_priv_data_t epriv;
443
444   priv = gnutls_calloc (1, sizeof (*priv));
445   if (priv == NULL)
446     {
447       gnutls_assert ();
448       return GNUTLS_E_MEMORY_ERROR;
449     }
450
451   BUFFER_POP_NUM (ps, priv->sign_algorithms_size);
452   for (i = 0; i < priv->sign_algorithms_size; i++)
453     {
454       BUFFER_POP_NUM (ps, priv->sign_algorithms[i]);
455     }
456
457   epriv.ptr = priv;
458   *_priv = epriv;
459
460   return 0;
461
462 error:
463   gnutls_free (priv);
464   return ret;
465 }
466
467
468
469 /**
470  * gnutls_sign_algorithm_get_requested:
471  * @session: is a #gnutls_session_t structure.
472  * @indx: is an index of the signature algorithm to return
473  * @algo: the returned certificate type will be stored there
474  *
475  * Returns the signature algorithm specified by index that was
476  * requested by the peer. If the specified index has no data available
477  * this function returns %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE.  If
478  * the negotiated TLS version does not support signature algorithms
479  * then %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned even
480  * for the first index.  The first index is 0.
481  *
482  * This function is useful in the certificate callback functions
483  * to assist in selecting the correct certificate.
484  *
485  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
486  *   an error code is returned.
487  *
488  * Since: 2.10.0
489  **/
490 int
491 gnutls_sign_algorithm_get_requested (gnutls_session_t session,
492                                      size_t indx,
493                                      gnutls_sign_algorithm_t * algo)
494 {
495   gnutls_protocol_t ver = gnutls_protocol_get_version (session);
496   sig_ext_st *priv;
497   extension_priv_data_t epriv;
498   int ret;
499
500   ret =
501     _gnutls_ext_get_session_data (session,
502                                   GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS,
503                                   &epriv);
504   if (ret < 0)
505     {
506       gnutls_assert ();
507       return ret;
508     }
509   priv = epriv.ptr;
510
511   if (!_gnutls_version_has_selectable_sighash (ver)
512       || priv->sign_algorithms_size == 0)
513     {
514       return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
515     }
516
517   if (indx < priv->sign_algorithms_size)
518     {
519       *algo = priv->sign_algorithms[indx];
520       return 0;
521     }
522   else
523     return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
524 }