2 * Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GNUTLS.
8 * The GNUTLS library 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 2.1 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
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
25 /* This file contains the code the Certificate Type TLS extension.
26 * This extension is currently gnutls specific.
29 #include "gnutls_int.h"
30 #include "gnutls_errors.h"
31 #include "gnutls_num.h"
32 #include <ext_signature.h>
33 #include <gnutls_state.h>
34 #include <gnutls_num.h>
35 #include <gnutls_algorithms.h>
37 /* generates a SignatureAndHashAlgorithm structure with length as prefix
38 * by using the setup priorities.
40 int _gnutls_sign_algorithm_write_params(gnutls_session_t session
, opaque
*data
, size_t max_data_size
)
45 sign_algorithm_st aid
;
47 len
= session
->internals
.priorities
.sign_algo
.algorithms
* 2;
48 if (max_data_size
< len
+ 2)
51 return GNUTLS_E_SHORT_MEMORY_BUFFER
;
54 _gnutls_write_uint16 (len
, p
);
57 for (i
= j
= 0; i
< len
; i
+= 2, j
++)
59 aid
= _gnutls_sign_to_tls_aid(session
->internals
.priorities
.sign_algo
.priority
[j
]);
60 *p
= aid
.hash_algorithm
;
62 *p
= aid
.sign_algorithm
;
69 /* Parses the Signature Algorithm structure and stores data into
70 * session->security_parameters.extensions.
73 _gnutls_sign_algorithm_parse_data (gnutls_session_t session
, const opaque
* data
,
78 session
->security_parameters
.extensions
.sign_algorithms_size
= 0;
80 for (i
= 0; i
< data_size
; i
+= 2)
82 sign_algorithm_st aid
;
84 aid
.hash_algorithm
= data
[i
];
85 aid
.sign_algorithm
= data
[i
+1];
87 sig
= _gnutls_tls_aid_to_sign(&aid
);
88 if (sig
!= GNUTLS_SIGN_UNKNOWN
)
90 session
->security_parameters
.extensions
.sign_algorithms
[session
->
91 security_parameters
.extensions
.
92 sign_algorithms_size
++]
94 if (session
->security_parameters
.extensions
.sign_algorithms_size
==
95 MAX_SIGNATURE_ALGORITHMS
)
104 * In case of a server: if a SIGNATURE_ALGORITHMS extension type is received then it stores
105 * into the session security parameters the new value.
107 * In case of a client: If a signature_algorithms have been specified then it is an error;
112 _gnutls_signature_algorithm_recv_params (gnutls_session_t session
,
116 ssize_t data_size
= _data_size
;
119 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
)
121 /* nothing for now */
123 /* Although TLS 1.2 mandates that we must not accept reply
124 * to this message, there are good reasons to just ignore it. Check
125 * http://www.ietf.org/mail-archive/web/tls/current/msg03880.html
127 /* return GNUTLS_E_UNEXPECTED_PACKET; */
131 /* SERVER SIDE - we must check if the sent cert type is the right one
138 DECR_LEN (data_size
, 2);
139 len
= _gnutls_read_uint16 (data
);
140 DECR_LEN (data_size
, len
);
142 ret
= _gnutls_sign_algorithm_parse_data (session
, data
+ 2, len
);
154 /* returns data_size or a negative number on failure
157 _gnutls_signature_algorithm_send_params (gnutls_session_t session
,
158 opaque
* data
, size_t data_size
)
161 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
163 /* this function sends the client extension data */
164 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
165 && _gnutls_version_has_selectable_sighash (ver
))
167 if (session
->internals
.priorities
.sign_algo
.algorithms
> 0)
169 ret
= _gnutls_sign_algorithm_write_params(session
, data
, data_size
);
179 /* if we are here it means we don't send the extension */
183 /* Returns a requested by the peer signature algorithm that
184 * matches the given public key algorithm. Index can be increased
185 * to return the second choice etc.
187 gnutls_sign_algorithm_t
188 _gnutls_session_get_sign_algo (gnutls_session_t session
,
189 gnutls_pk_algorithm_t pk
,
190 gnutls_digest_algorithm_t
* hash
)
193 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
196 if (!_gnutls_version_has_selectable_sighash (ver
) || session
->security_parameters
.extensions
.sign_algorithms_size
== 0) /* none set, allow all */
198 *hash
= GNUTLS_DIG_SHA1
;
199 return _gnutls_x509_pk_to_sign (pk
, *hash
);
203 i
< session
->security_parameters
.extensions
.sign_algorithms_size
; i
++)
205 if (_gnutls_sign_get_pk_algorithm
206 (session
->security_parameters
.extensions
.sign_algorithms
[i
]) == pk
)
209 _gnutls_sign_get_hash_algorithm (session
->security_parameters
.
210 extensions
.sign_algorithms
[i
]);
211 return session
->security_parameters
.extensions
.sign_algorithms
[i
];
215 return GNUTLS_SIGN_UNKNOWN
;
219 /* Check if the given signature algorithm is accepted by
220 * the peer. Returns 0 on success or a negative value
224 _gnutls_session_sign_algo_requested (gnutls_session_t session
,
225 gnutls_sign_algorithm_t sig
)
228 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
230 if (!_gnutls_version_has_selectable_sighash (ver
) || session
->security_parameters
.extensions
.sign_algorithms_size
== 0) /* none set, allow all */
236 i
< session
->security_parameters
.extensions
.sign_algorithms_size
; i
++)
238 if (session
->security_parameters
.extensions
.sign_algorithms
[i
] == sig
)
244 return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM
;
247 /* Check if the given signature algorithm is supported.
248 * This means that it is enabled by the priority functions,
249 * and in case of a server a matching certificate exists.
252 _gnutls_session_sign_algo_enabled (gnutls_session_t session
,
253 gnutls_sign_algorithm_t sig
)
256 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
258 if (!_gnutls_version_has_selectable_sighash (ver
) || session
->security_parameters
.extensions
.sign_algorithms_size
== 0) /* none set, allow all */
263 for (i
= 0; i
< session
->internals
.priorities
.sign_algo
.algorithms
; i
++)
265 if (session
->internals
.priorities
.sign_algo
.priority
[i
] == sig
)
271 return GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM
;
275 * gnutls_session_sign_algorithm_get - Returns the signature algorithms requested by peer
276 * @session: is a #gnutls_session_t structure.
277 * @indx: is an index of the signature algorithm to return
278 * @algo: the returned certificate type will be stored there
280 * Returns the signature algorithm specified by index that was requested
281 * by the peer. If the specified index has no data available
282 * this function returns %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE.
283 * If the negotiated TLS version does not support signature algorithms
284 * then %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned even
285 * for the first index.
287 * This function is usefull in the certificate callback functions
288 * to assist in selecting the correct certificate.
290 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
291 * an error code is returned.
293 int gnutls_session_sign_algorithm_get_requested (gnutls_session_t session
,
294 int indx
, gnutls_sign_algorithm_t
*algo
)
296 gnutls_protocol_t ver
= gnutls_protocol_get_version (session
);
298 if (!_gnutls_version_has_selectable_sighash (ver
) || session
->security_parameters
.extensions
.sign_algorithms_size
== 0)
300 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
303 if (indx
< session
->security_parameters
.extensions
.sign_algorithms_size
)
305 *algo
= session
->security_parameters
.extensions
.sign_algorithms
[indx
];
309 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;