2 * Copyright (C) 2002,2003,2004,2005,2009,2010,2011 Free Software
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 the code the Certificate Type TLS extension.
27 * This extension is currently gnutls specific.
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>
40 static int _gnutls_signature_algorithm_recv_params (gnutls_session_t session
,
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
);
51 extension_entry_st ext_mod_sig
= {
52 .name
= "SIGNATURE ALGORITHMS",
53 .type
= GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS
,
54 .parse_type
= GNUTLS_EXT_TLS
,
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
,
65 /* TLS 1.2 signature algorithms */
66 gnutls_sign_algorithm_t sign_algorithms
[MAX_SIGNATURE_ALGORITHMS
];
67 uint16_t sign_algorithms_size
;
70 /* generates a SignatureAndHashAlgorithm structure with length as prefix
71 * by using the setup priorities.
74 _gnutls_sign_algorithm_write_params (gnutls_session_t session
, opaque
* data
,
77 opaque
*p
= data
, *len_p
;
79 const sign_algorithm_st
*aid
;
81 if (max_data_size
< (session
->internals
.priorities
.sign_algo
.algorithms
*2) + 2)
84 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
92 for (i
= j
= 0; j
< session
->internals
.priorities
.sign_algo
.algorithms
; i
+= 2, j
++)
94 /* In gnutls we keep a state of SHA1 and SHA256 and thus cannot
97 hash
= _gnutls_sign_get_hash_algorithm(session
->internals
.priorities
.sign_algo
.priority
[j
]);
98 if (hash
!= GNUTLS_DIG_SHA1
&& hash
!= GNUTLS_DIG_SHA256
)
102 _gnutls_sign_to_tls_aid (session
->internals
.priorities
.
103 sign_algo
.priority
[j
]);
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
;
112 *p
= aid
->sign_algorithm
;
117 _gnutls_write_uint16 (len
, len_p
);
123 /* Parses the Signature Algorithm structure and stores data into
124 * session->security_parameters.extensions.
127 _gnutls_sign_algorithm_parse_data (gnutls_session_t session
,
128 const opaque
* data
, size_t data_size
)
132 extension_priv_data_t epriv
;
134 priv
= gnutls_calloc (1, sizeof (*priv
));
138 return GNUTLS_E_MEMORY_ERROR
;
141 for (i
= 0; i
< data_size
; i
+= 2)
143 sign_algorithm_st aid
;
145 aid
.hash_algorithm
= data
[i
];
146 aid
.sign_algorithm
= data
[i
+ 1];
148 sig
= _gnutls_tls_aid_to_sign (&aid
);
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
));
154 if (sig
!= GNUTLS_SIGN_UNKNOWN
)
156 hash
= _gnutls_sign_get_hash_algorithm(sig
);
157 if (hash
!= GNUTLS_DIG_SHA1
&& hash
!= GNUTLS_DIG_SHA256
)
160 priv
->sign_algorithms
[priv
->sign_algorithms_size
++] = sig
;
161 if (priv
->sign_algorithms_size
== MAX_SIGNATURE_ALGORITHMS
)
167 _gnutls_ext_set_session_data (session
,
168 GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS
, epriv
);
174 * In case of a server: if a SIGNATURE_ALGORITHMS extension type is
175 * received then it stores into the session security parameters the
178 * In case of a client: If a signature_algorithms have been specified
179 * then it is an error;
183 _gnutls_signature_algorithm_recv_params (gnutls_session_t session
,
187 ssize_t data_size
= _data_size
;
190 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
)
192 /* nothing for now */
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
198 /* return GNUTLS_E_UNEXPECTED_PACKET; */
202 /* SERVER SIDE - we must check if the sent cert type is the right one
208 DECR_LEN (data_size
, 2);
209 len
= _gnutls_read_uint16 (data
);
210 DECR_LEN (data_size
, len
);
212 ret
= _gnutls_sign_algorithm_parse_data (session
, data
+ 2, len
);
224 /* returns data_size or a negative number on failure
227 _gnutls_signature_algorithm_send_params (gnutls_session_t session
,
228 opaque
* data
, size_t data_size
)
231 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
233 /* this function sends the client extension data */
234 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
235 && _gnutls_version_has_selectable_sighash (ver
))
237 if (session
->internals
.priorities
.sign_algo
.algorithms
> 0)
240 _gnutls_sign_algorithm_write_params (session
, data
, data_size
);
250 /* if we are here it means we don't send the extension */
254 int cert_compatible_with_sig(gnutls_cert
* cert
, gnutls_protocol_t ver
,
255 gnutls_sign_algorithm_t sign
)
257 unsigned int hash_len
;
259 if (cert
->subject_pk_algorithm
== GNUTLS_PK_DSA
)
261 int hash_algo
= _gnutls_dsa_q_to_hash (cert
->params
[1], &hash_len
);
263 /* DSA keys over 1024 bits cannot be used with TLS 1.x, x<2 */
264 if (!_gnutls_version_has_selectable_sighash (ver
))
266 if (hash_algo
!= GNUTLS_DIG_SHA1
)
267 return gnutls_assert_val(GNUTLS_E_INCOMPAT_DSA_KEY_WITH_TLS_PROTOCOL
);
271 if (_gnutls_hash_get_algo_len(_gnutls_sign_get_hash_algorithm(sign
)) < hash_len
)
272 return GNUTLS_E_UNWANTED_ALGORITHM
;
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.
284 gnutls_sign_algorithm_t
285 _gnutls_session_get_sign_algo (gnutls_session_t session
, gnutls_cert
* cert
)
289 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
291 extension_priv_data_t epriv
;
294 _gnutls_ext_get_session_data (session
,
295 GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS
,
299 if (ret
< 0 || !_gnutls_version_has_selectable_sighash (ver
)
300 || priv
->sign_algorithms_size
== 0)
301 /* none set, allow SHA-1 only */
303 return _gnutls_x509_pk_to_sign (cert
->subject_pk_algorithm
, GNUTLS_DIG_SHA1
);
306 for (i
= 0; i
< priv
->sign_algorithms_size
; i
++)
308 if (_gnutls_sign_get_pk_algorithm (priv
->sign_algorithms
[i
]) == cert
->subject_pk_algorithm
)
310 if (cert_compatible_with_sig(cert
, ver
, priv
->sign_algorithms
[i
]) < 0)
313 return priv
->sign_algorithms
[i
];
317 return GNUTLS_SIGN_UNKNOWN
;
321 /* Check if the given signature algorithm is accepted by
322 * the peer. Returns 0 on success or a negative value
326 _gnutls_session_sign_algo_requested (gnutls_session_t session
,
327 gnutls_sign_algorithm_t sig
)
331 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
333 extension_priv_data_t epriv
;
335 if (!_gnutls_version_has_selectable_sighash (ver
))
341 _gnutls_ext_get_session_data (session
,
342 GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS
,
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
)
356 if (priv
->sign_algorithms_size
== 0)
357 /* none set, allow all */
362 for (i
= 0; i
< priv
->sign_algorithms_size
; i
++)
364 if (priv
->sign_algorithms
[i
] == sig
)
370 return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM
;
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.
378 _gnutls_session_sign_algo_enabled (gnutls_session_t session
,
379 gnutls_sign_algorithm_t sig
)
383 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
385 extension_priv_data_t epriv
;
388 _gnutls_ext_get_session_data (session
,
389 GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS
,
398 if (!_gnutls_version_has_selectable_sighash (ver
)
399 || priv
->sign_algorithms_size
== 0)
400 /* none set, allow all */
405 for (i
= 0; i
< session
->internals
.priorities
.sign_algo
.algorithms
; i
++)
407 if (session
->internals
.priorities
.sign_algo
.priority
[i
] == sig
)
413 return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM
;
417 signature_algorithms_deinit_data (extension_priv_data_t priv
)
419 gnutls_free (priv
.ptr
);
423 signature_algorithms_pack (extension_priv_data_t epriv
, gnutls_buffer_st
* ps
)
425 sig_ext_st
*priv
= epriv
.ptr
;
428 BUFFER_APPEND_NUM (ps
, priv
->sign_algorithms_size
);
429 for (i
= 0; i
< priv
->sign_algorithms_size
; i
++)
431 BUFFER_APPEND_NUM (ps
, priv
->sign_algorithms
[i
]);
437 signature_algorithms_unpack (gnutls_buffer_st
* ps
,
438 extension_priv_data_t
* _priv
)
442 extension_priv_data_t epriv
;
444 priv
= gnutls_calloc (1, sizeof (*priv
));
448 return GNUTLS_E_MEMORY_ERROR
;
451 BUFFER_POP_NUM (ps
, priv
->sign_algorithms_size
);
452 for (i
= 0; i
< priv
->sign_algorithms_size
; i
++)
454 BUFFER_POP_NUM (ps
, priv
->sign_algorithms
[i
]);
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
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.
482 * This function is useful in the certificate callback functions
483 * to assist in selecting the correct certificate.
485 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
486 * an error code is returned.
491 gnutls_sign_algorithm_get_requested (gnutls_session_t session
,
493 gnutls_sign_algorithm_t
* algo
)
495 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
497 extension_priv_data_t epriv
;
501 _gnutls_ext_get_session_data (session
,
502 GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS
,
511 if (!_gnutls_version_has_selectable_sighash (ver
)
512 || priv
->sign_algorithms_size
== 0)
514 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
517 if (indx
< priv
->sign_algorithms_size
)
519 *algo
= priv
->sign_algorithms
[indx
];
523 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;