2 * Copyright (C) 2002-2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 /* This file contains the code the Certificate Type TLS extension.
24 * This extension is currently gnutls specific.
27 #include "gnutls_int.h"
28 #include "gnutls_errors.h"
29 #include "gnutls_num.h"
30 #include <gnutls/gnutls.h>
31 #include <ext/signature.h>
32 #include <gnutls_state.h>
33 #include <gnutls_num.h>
34 #include <algorithms.h>
35 #include <abstract_int.h>
37 static int _gnutls_signature_algorithm_recv_params (gnutls_session_t session
,
40 static int _gnutls_signature_algorithm_send_params (gnutls_session_t session
,
41 gnutls_buffer_st
* extdata
);
42 static void signature_algorithms_deinit_data (extension_priv_data_t priv
);
43 static int signature_algorithms_pack (extension_priv_data_t epriv
,
44 gnutls_buffer_st
* ps
);
45 static int signature_algorithms_unpack (gnutls_buffer_st
* ps
,
46 extension_priv_data_t
* _priv
);
48 extension_entry_st ext_mod_sig
= {
49 .name
= "SIGNATURE ALGORITHMS",
50 .type
= GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS
,
51 .parse_type
= GNUTLS_EXT_TLS
,
53 .recv_func
= _gnutls_signature_algorithm_recv_params
,
54 .send_func
= _gnutls_signature_algorithm_send_params
,
55 .pack_func
= signature_algorithms_pack
,
56 .unpack_func
= signature_algorithms_unpack
,
57 .deinit_func
= signature_algorithms_deinit_data
,
62 /* TLS 1.2 signature algorithms */
63 gnutls_sign_algorithm_t sign_algorithms
[MAX_SIGNATURE_ALGORITHMS
];
64 uint16_t sign_algorithms_size
;
67 /* generates a SignatureAndHashAlgorithm structure with length as prefix
68 * by using the setup priorities.
71 _gnutls_sign_algorithm_write_params (gnutls_session_t session
, uint8_t * data
,
74 uint8_t *p
= data
, *len_p
;
75 unsigned int len
, i
, j
;
76 const sign_algorithm_st
*aid
;
78 if (max_data_size
< (session
->internals
.priorities
.sign_algo
.algorithms
*2) + 2)
81 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
89 for (i
= j
= 0; j
< session
->internals
.priorities
.sign_algo
.algorithms
; i
+= 2, j
++)
92 _gnutls_sign_to_tls_aid (session
->internals
.priorities
.
93 sign_algo
.priority
[j
]);
98 _gnutls_handshake_log ("EXT[%p]: sent signature algo (%d.%d) %s\n", session
, aid
->hash_algorithm
,
99 aid
->sign_algorithm
, gnutls_sign_get_name(session
->internals
.priorities
.sign_algo
.priority
[j
]));
100 *p
= aid
->hash_algorithm
;
102 *p
= aid
->sign_algorithm
;
107 _gnutls_write_uint16 (len
, len_p
);
112 /* Parses the Signature Algorithm structure and stores data into
113 * session->security_parameters.extensions.
116 _gnutls_sign_algorithm_parse_data (gnutls_session_t session
,
117 const uint8_t * data
, size_t data_size
)
121 extension_priv_data_t epriv
;
123 priv
= gnutls_calloc (1, sizeof (*priv
));
127 return GNUTLS_E_MEMORY_ERROR
;
130 for (i
= 0; i
< data_size
; i
+= 2)
132 sign_algorithm_st aid
;
134 aid
.hash_algorithm
= data
[i
];
135 aid
.sign_algorithm
= data
[i
+ 1];
137 sig
= _gnutls_tls_aid_to_sign (&aid
);
139 _gnutls_handshake_log ("EXT[%p]: rcvd signature algo (%d.%d) %s\n", session
, aid
.hash_algorithm
,
140 aid
.sign_algorithm
, gnutls_sign_get_name(sig
));
142 if (sig
!= GNUTLS_SIGN_UNKNOWN
)
144 priv
->sign_algorithms
[priv
->sign_algorithms_size
++] = sig
;
145 if (priv
->sign_algorithms_size
== MAX_SIGNATURE_ALGORITHMS
)
151 _gnutls_ext_set_session_data (session
,
152 GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS
, epriv
);
158 * In case of a server: if a SIGNATURE_ALGORITHMS extension type is
159 * received then it stores into the session security parameters the
162 * In case of a client: If a signature_algorithms have been specified
163 * then it is an error;
167 _gnutls_signature_algorithm_recv_params (gnutls_session_t session
,
168 const uint8_t * data
,
171 ssize_t data_size
= _data_size
;
174 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
)
176 /* nothing for now */
178 /* Although TLS 1.2 mandates that we must not accept reply
179 * to this message, there are good reasons to just ignore it. Check
180 * http://www.ietf.org/mail-archive/web/tls/current/msg03880.html
182 /* return GNUTLS_E_UNEXPECTED_PACKET; */
186 /* SERVER SIDE - we must check if the sent cert type is the right one
192 DECR_LEN (data_size
, 2);
193 len
= _gnutls_read_uint16 (data
);
194 DECR_LEN (data_size
, len
);
196 ret
= _gnutls_sign_algorithm_parse_data (session
, data
+ 2, len
);
208 /* returns data_size or a negative number on failure
211 _gnutls_signature_algorithm_send_params (gnutls_session_t session
,
212 gnutls_buffer_st
* extdata
)
215 size_t init_length
= extdata
->length
;
216 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
218 /* this function sends the client extension data */
219 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
220 && _gnutls_version_has_selectable_sighash (ver
))
222 if (session
->internals
.priorities
.sign_algo
.algorithms
> 0)
224 uint8_t p
[MAX_SIGN_ALGO_SIZE
];
227 _gnutls_sign_algorithm_write_params (session
, p
, sizeof(p
));
229 return gnutls_assert_val(ret
);
231 ret
= _gnutls_buffer_append_data(extdata
, p
, ret
);
233 return gnutls_assert_val(ret
);
235 return extdata
->length
- init_length
;
239 /* if we are here it means we don't send the extension */
243 /* Returns a requested by the peer signature algorithm that
244 * matches the given certificate's public key algorithm.
246 gnutls_sign_algorithm_t
247 _gnutls_session_get_sign_algo (gnutls_session_t session
, gnutls_pcert_st
* cert
)
251 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
253 extension_priv_data_t epriv
;
254 unsigned int cert_algo
;
256 cert_algo
= gnutls_pubkey_get_pk_algorithm(cert
->pubkey
, NULL
);
259 _gnutls_ext_get_session_data (session
,
260 GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS
,
264 if (ret
< 0 || !_gnutls_version_has_selectable_sighash (ver
)
265 || priv
->sign_algorithms_size
== 0)
266 /* none set, allow SHA-1 only */
268 return gnutls_pk_to_sign (cert_algo
, GNUTLS_DIG_SHA1
);
271 for (i
= 0; i
< priv
->sign_algorithms_size
; i
++)
273 if (gnutls_sign_get_pk_algorithm (priv
->sign_algorithms
[i
]) == cert_algo
)
275 if (_gnutls_pubkey_compatible_with_sig(session
, cert
->pubkey
, ver
, priv
->sign_algorithms
[i
]) < 0)
278 if (_gnutls_session_sign_algo_enabled(session
, priv
->sign_algorithms
[i
]) < 0)
281 return priv
->sign_algorithms
[i
];
285 return GNUTLS_SIGN_UNKNOWN
;
288 /* Check if the given signature algorithm is supported.
289 * This means that it is enabled by the priority functions,
290 * and in case of a server a matching certificate exists.
293 _gnutls_session_sign_algo_enabled (gnutls_session_t session
,
294 gnutls_sign_algorithm_t sig
)
298 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
300 extension_priv_data_t epriv
;
303 _gnutls_ext_get_session_data (session
,
304 GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS
,
313 if (!_gnutls_version_has_selectable_sighash (ver
)
314 || priv
->sign_algorithms_size
== 0)
315 /* none set, allow all */
320 for (i
= 0; i
< session
->internals
.priorities
.sign_algo
.algorithms
; i
++)
322 if (session
->internals
.priorities
.sign_algo
.priority
[i
] == sig
)
328 return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM
;
332 signature_algorithms_deinit_data (extension_priv_data_t priv
)
334 gnutls_free (priv
.ptr
);
338 signature_algorithms_pack (extension_priv_data_t epriv
, gnutls_buffer_st
* ps
)
340 sig_ext_st
*priv
= epriv
.ptr
;
343 BUFFER_APPEND_NUM (ps
, priv
->sign_algorithms_size
);
344 for (i
= 0; i
< priv
->sign_algorithms_size
; i
++)
346 BUFFER_APPEND_NUM (ps
, priv
->sign_algorithms
[i
]);
352 signature_algorithms_unpack (gnutls_buffer_st
* ps
,
353 extension_priv_data_t
* _priv
)
357 extension_priv_data_t epriv
;
359 priv
= gnutls_calloc (1, sizeof (*priv
));
363 return GNUTLS_E_MEMORY_ERROR
;
366 BUFFER_POP_NUM (ps
, priv
->sign_algorithms_size
);
367 for (i
= 0; i
< priv
->sign_algorithms_size
; i
++)
369 BUFFER_POP_NUM (ps
, priv
->sign_algorithms
[i
]);
385 * gnutls_sign_algorithm_get_requested:
386 * @session: is a #gnutls_session_t structure.
387 * @indx: is an index of the signature algorithm to return
388 * @algo: the returned certificate type will be stored there
390 * Returns the signature algorithm specified by index that was
391 * requested by the peer. If the specified index has no data available
392 * this function returns %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE. If
393 * the negotiated TLS version does not support signature algorithms
394 * then %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned even
395 * for the first index. The first index is 0.
397 * This function is useful in the certificate callback functions
398 * to assist in selecting the correct certificate.
400 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
401 * an error code is returned.
406 gnutls_sign_algorithm_get_requested (gnutls_session_t session
,
408 gnutls_sign_algorithm_t
* algo
)
410 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
412 extension_priv_data_t epriv
;
416 _gnutls_ext_get_session_data (session
,
417 GNUTLS_EXTENSION_SIGNATURE_ALGORITHMS
,
426 if (!_gnutls_version_has_selectable_sighash (ver
)
427 || priv
->sign_algorithms_size
== 0)
429 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
432 if (indx
< priv
->sign_algorithms_size
)
434 *algo
= priv
->sign_algorithms
[indx
];
438 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
442 * gnutls_sign_algorithm_get:
443 * @session: is a #gnutls_session_t structure.
445 * Returns the signature algorithm that is (or will be) used in this
446 * session to sign data.
448 * Returns: The sign algorithm or %GNUTLS_SIGN_UNKNOWN.
453 gnutls_sign_algorithm_get (gnutls_session_t session
)
455 return session
->security_parameters
.sign_algo
;