2 * Copyright (C) 2004, 2005, 2006, 2007 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 /* Here lies the code of the gnutls_*_set_priority() functions.
28 #include "gnutls_int.h"
29 #include "gnutls_algorithms.h"
30 #include "gnutls_errors.h"
31 #include <gnutls_num.h>
34 break_comma_list (char *etag
,
35 char **broken_etag
, int *elements
, int max_elements
,
39 * gnutls_cipher_set_priority - Sets the priority on the ciphers supported by gnutls.
40 * @session: is a #gnutls_session_t structure.
41 * @list: is a 0 terminated list of gnutls_cipher_algorithm_t elements.
43 * Sets the priority on the ciphers supported by gnutls.
44 * Priority is higher for elements specified before others.
45 * After specifying the ciphers you want, you must append a 0.
46 * Note that the priority is set on the client. The server does
47 * not use the algorithm's priority except for disabling
48 * algorithms that were not specified.
50 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
53 gnutls_cipher_set_priority (gnutls_session_t session
, const int *list
)
57 while (list
[num
] != 0)
61 session
->internals
.priorities
.cipher
.algorithms
= num
;
63 for (i
= 0; i
< num
; i
++)
65 session
->internals
.priorities
.cipher
.priority
[i
] = list
[i
];
72 _set_priority (priority_st
* st
, const int *list
)
76 while (list
[num
] != 0)
82 for (i
= 0; i
< num
; i
++)
84 st
->priority
[i
] = list
[i
];
92 * gnutls_kx_set_priority - Sets the priority on the key exchange algorithms supported by gnutls.
93 * @session: is a #gnutls_session_t structure.
94 * @list: is a 0 terminated list of gnutls_kx_algorithm_t elements.
96 * Sets the priority on the key exchange algorithms supported by gnutls.
97 * Priority is higher for elements specified before others.
98 * After specifying the algorithms you want, you must append a 0.
99 * Note that the priority is set on the client. The server does
100 * not use the algorithm's priority except for disabling
101 * algorithms that were not specified.
103 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
106 gnutls_kx_set_priority (gnutls_session_t session
, const int *list
)
108 return _set_priority (&session
->internals
.priorities
.kx
, list
);
112 * gnutls_mac_set_priority - Sets the priority on the mac algorithms supported by gnutls.
113 * @session: is a #gnutls_session_t structure.
114 * @list: is a 0 terminated list of gnutls_mac_algorithm_t elements.
116 * Sets the priority on the mac algorithms supported by gnutls.
117 * Priority is higher for elements specified before others.
118 * After specifying the algorithms you want, you must append a 0.
119 * Note that the priority is set on the client. The server does
120 * not use the algorithm's priority except for disabling
121 * algorithms that were not specified.
123 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
126 gnutls_mac_set_priority (gnutls_session_t session
, const int *list
)
128 return _set_priority (&session
->internals
.priorities
.mac
, list
);
132 * gnutls_compression_set_priority - Sets the priority on the compression algorithms supported by gnutls.
133 * @session: is a #gnutls_session_t structure.
134 * @list: is a 0 terminated list of gnutls_compression_method_t elements.
136 * Sets the priority on the compression algorithms supported by gnutls.
137 * Priority is higher for elements specified before others.
138 * After specifying the algorithms you want, you must append a 0.
139 * Note that the priority is set on the client. The server does
140 * not use the algorithm's priority except for disabling
141 * algorithms that were not specified.
143 * TLS 1.0 does not define any compression algorithms except
144 * NULL. Other compression algorithms are to be considered
145 * as gnutls extensions.
147 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
150 gnutls_compression_set_priority (gnutls_session_t session
, const int *list
)
152 return _set_priority (&session
->internals
.priorities
.compression
, list
);
156 * gnutls_protocol_set_priority - Sets the priority on the protocol versions supported by gnutls.
157 * @session: is a #gnutls_session_t structure.
158 * @list: is a 0 terminated list of gnutls_protocol_t elements.
160 * Sets the priority on the protocol versions supported by gnutls.
161 * This function actually enables or disables protocols. Newer protocol
162 * versions always have highest priority.
164 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
167 gnutls_protocol_set_priority (gnutls_session_t session
, const int *list
)
171 ret
= _set_priority (&session
->internals
.priorities
.protocol
, list
);
173 /* set the current version to the first in the chain.
174 * This will be overridden later.
177 _gnutls_set_current_version (session
, list
[0]);
183 * gnutls_certificate_type_set_priority - Sets the priority on the certificate types supported by gnutls.
184 * @session: is a #gnutls_session_t structure.
185 * @list: is a 0 terminated list of gnutls_certificate_type_t elements.
187 * Sets the priority on the certificate types supported by gnutls.
188 * Priority is higher for elements specified before others.
189 * After specifying the types you want, you must append a 0.
190 * Note that the certificate type priority is set on the client.
191 * The server does not use the cert type priority except for disabling
192 * types that were not specified.
194 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
197 gnutls_certificate_type_set_priority (gnutls_session_t session
,
200 #ifdef ENABLE_OPENPGP
201 return _set_priority (&session
->internals
.priorities
.cert_type
, list
);
205 return GNUTLS_E_UNIMPLEMENTED_FEATURE
;
210 static const int protocol_priority
[] = {
211 /* GNUTLS_TLS1_2, -- not finalized yet! */
218 static const int kx_priority_performance
[] = {
227 /* GNUTLS_KX_ANON_DH: Man-in-the-middle prone, don't add!
228 * GNUTLS_KX_RSA_EXPORT: Deprecated, don't add!
233 static const int kx_priority_export
[] = {
242 GNUTLS_KX_RSA_EXPORT
,
246 static const int kx_priority_secure
[] = {
247 /* The ciphersuites that offer forward secrecy take
258 /* GNUTLS_KX_ANON_DH: Man-in-the-middle prone, don't add!
259 * GNUTLS_KX_RSA_EXPORT: Deprecated, don't add!
264 static const int cipher_priority_performance
[] = {
265 GNUTLS_CIPHER_ARCFOUR_128
,
266 #ifdef ENABLE_CAMELLIA
267 GNUTLS_CIPHER_CAMELLIA_128_CBC
,
269 GNUTLS_CIPHER_AES_128_CBC
,
270 GNUTLS_CIPHER_3DES_CBC
,
271 GNUTLS_CIPHER_AES_256_CBC
,
272 #ifdef ENABLE_CAMELLIA
273 GNUTLS_CIPHER_CAMELLIA_256_CBC
,
275 /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
279 static const int cipher_priority_normal
[] = {
280 GNUTLS_CIPHER_AES_128_CBC
,
281 #ifdef ENABLE_CAMELLIA
282 GNUTLS_CIPHER_CAMELLIA_128_CBC
,
284 GNUTLS_CIPHER_AES_256_CBC
,
285 #ifdef ENABLE_CAMELLIA
286 GNUTLS_CIPHER_CAMELLIA_256_CBC
,
288 GNUTLS_CIPHER_3DES_CBC
,
289 GNUTLS_CIPHER_ARCFOUR_128
,
290 /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
294 static const int cipher_priority_secure128
[] = {
295 GNUTLS_CIPHER_AES_128_CBC
,
296 #ifdef ENABLE_CAMELLIA
297 GNUTLS_CIPHER_CAMELLIA_128_CBC
,
299 GNUTLS_CIPHER_3DES_CBC
,
300 GNUTLS_CIPHER_ARCFOUR_128
,
301 /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
306 static const int cipher_priority_secure256
[] = {
307 GNUTLS_CIPHER_AES_256_CBC
,
308 #ifdef ENABLE_CAMELLIA
309 GNUTLS_CIPHER_CAMELLIA_256_CBC
,
311 GNUTLS_CIPHER_AES_128_CBC
,
312 #ifdef ENABLE_CAMELLIA
313 GNUTLS_CIPHER_CAMELLIA_128_CBC
,
315 GNUTLS_CIPHER_3DES_CBC
,
316 GNUTLS_CIPHER_ARCFOUR_128
,
317 /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
321 /* The same as cipher_priority_security_normal + arcfour-40. */
322 static const int cipher_priority_export
[] = {
323 GNUTLS_CIPHER_AES_128_CBC
,
324 GNUTLS_CIPHER_AES_256_CBC
,
325 #ifdef ENABLE_CAMELLIA
326 GNUTLS_CIPHER_CAMELLIA_128_CBC
,
327 GNUTLS_CIPHER_CAMELLIA_256_CBC
,
329 GNUTLS_CIPHER_3DES_CBC
,
330 GNUTLS_CIPHER_ARCFOUR_128
,
331 GNUTLS_CIPHER_ARCFOUR_40
,
335 static const int comp_priority
[] = {
336 /* compression should be explicitely requested to be enabled */
342 static const int mac_priority_performance
[] = {
348 static const int mac_priority_secure
[] = {
354 static int cert_type_priority
[] = {
360 typedef void (rmadd_func
) (priority_st
* priority_list
, int alg
);
363 prio_remove (priority_st
* priority_list
, int algo
)
366 int pos
= -1; /* the position of the cipher to remove */
368 while (priority_list
->priority
[i
] != 0)
370 if (priority_list
->priority
[i
] == algo
)
377 priority_list
->priority
[pos
] = priority_list
->priority
[i
- 1];
378 priority_list
->priority
[i
- 1] = 0;
379 priority_list
->algorithms
--;
386 prio_add (priority_st
* priority_list
, int algo
)
389 while (priority_list
->priority
[i
] != 0)
391 if (algo
== priority_list
->priority
[i
])
392 return; /* if it exists */
398 priority_list
->priority
[i
] = algo
;
399 priority_list
->algorithms
++;
407 * gnutls_priority_set - Sets priorities for the cipher suites supported by gnutls.
408 * @session: is a #gnutls_session_t structure.
409 * @priority: is a #gnutls_priority_t structure.
411 * Sets the priorities to use on the ciphers, key exchange methods,
412 * macs and compression methods.
414 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
417 gnutls_priority_set (gnutls_session_t session
, gnutls_priority_t priority
)
419 if (priority
== NULL
)
422 return GNUTLS_E_NO_CIPHER_SUITES
;
425 memcpy (&session
->internals
.priorities
, priority
,
426 sizeof (struct gnutls_priority_st
));
432 #define MAX_ELEMENTS 48
435 * gnutls_priority_init - Sets priorities for the cipher suites supported by gnutls.
436 * @priority_cache: is a #gnutls_prioritity_t structure.
437 * @priorities: is a string describing priorities
438 * @err_pos: In case of an error this will have the position in the string the error occured
440 * Sets priorities for the ciphers, key exchange methods, macs and
441 * compression methods. This is to avoid using the
442 * gnutls_*_priority() functions.
444 * The #priorities option allows you to specify a semi-colon
445 * separated list of the cipher priorities to enable.
447 * Unless the first keyword is "NONE" the defaults are:
448 * Protocols: TLS1.1, TLS1.0, and SSL3.0.
450 * Certificate types: X.509, OpenPGP.
452 * You can also use predefined sets of ciphersuites: "PERFORMANCE"
453 * all the "secure" ciphersuites are enabled, limited to 128 bit
454 * ciphers and sorted by terms of speed performance.
456 * "NORMAL" option enables all "secure" ciphersuites. The 256-bit ciphers
457 * are included as a fallback only. The ciphers are sorted by security margin.
459 * "SECURE128" flag enables all "secure" ciphersuites with ciphers up to
460 * 128 bits, sorted by security margin.
462 * "SECURE256" flag enables all "secure" ciphersuites including the 256 bit
463 * ciphers, sorted by security margin.
465 * "EXPORT" all the ciphersuites are enabled, including the
466 * low-security 40 bit ciphers.
468 * "NONE" nothing is enabled. This disables even protocols and
469 * compression methods.
472 * '!' or '-' appended with an algorithm will remove this algorithm.
473 * '+' appended with an algorithm will add this algorithm.
474 * '%COMPAT' will enable compatibility features for a server.
476 * To avoid collisions in order to specify a compression algorithm in
477 * this string you have to prefix it with "COMP-", protocol versions
478 * with "VERS-" and certificate types with "CTYPE-". All other
479 * algorithms don't need a prefix.
481 * For key exchange algorithms when in NORMAL or SECURE levels the
482 * perfect forward secrecy algorithms take precendence of the other
483 * protocols. In all cases all the supported key exchange algorithms
484 * are enabled (except for the RSA-EXPORT which is only enabled in
487 * Note that although one can select very long key sizes (such as 256 bits)
488 * for symmetric algorithms, to actually increase security the public key
489 * algorithms have to use longer key sizes as well.
491 * Examples: "NORMAL:!AES-128-CBC",
492 * "EXPORT:!VERS-TLS1.0:+COMP-DEFLATE:+CTYPE-OPENPGP",
493 * "NONE:+VERS-TLS1.0:+AES-128-CBC:+RSA:+SHA1:+COMP-NULL", "NORMAL",
496 * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
497 * %GNUTLS_E_SUCCESS on success, or an error code.
500 gnutls_priority_init (gnutls_priority_t
* priority_cache
,
501 const char *priorities
, const char **err_pos
)
503 char *broken_list
[MAX_ELEMENTS
];
504 int broken_list_size
, i
, j
;
509 *priority_cache
= gnutls_calloc (1, sizeof (struct gnutls_priority_st
));
510 if (*priority_cache
== NULL
)
513 return GNUTLS_E_MEMORY_ERROR
;
516 if (priorities
== NULL
)
517 priorities
= "NORMAL";
519 darg
= gnutls_strdup (priorities
);
523 return GNUTLS_E_MEMORY_ERROR
;
526 break_comma_list (darg
, broken_list
, &broken_list_size
, MAX_ELEMENTS
, ':');
527 /* This is our default set of protocol version, certificate types and
528 * compression methods.
530 if (strcasecmp (broken_list
[0], "NONE") != 0)
532 _set_priority (&(*priority_cache
)->protocol
, protocol_priority
);
533 _set_priority (&(*priority_cache
)->compression
, comp_priority
);
534 _set_priority (&(*priority_cache
)->cert_type
, cert_type_priority
);
542 for (; i
< broken_list_size
; i
++)
544 if (strcasecmp (broken_list
[i
], "PERFORMANCE") == 0)
546 _set_priority (&(*priority_cache
)->cipher
,
547 cipher_priority_performance
);
548 _set_priority (&(*priority_cache
)->kx
, kx_priority_performance
);
549 _set_priority (&(*priority_cache
)->mac
, mac_priority_performance
);
551 else if (strcasecmp (broken_list
[i
], "NORMAL") == 0)
553 _set_priority (&(*priority_cache
)->cipher
, cipher_priority_normal
);
554 _set_priority (&(*priority_cache
)->kx
, kx_priority_secure
);
555 _set_priority (&(*priority_cache
)->mac
, mac_priority_secure
);
557 else if (strcasecmp (broken_list
[i
], "SECURE256") == 0 || strcasecmp (broken_list
[i
], "SECURE") == 0)
559 _set_priority (&(*priority_cache
)->cipher
, cipher_priority_secure256
);
560 _set_priority (&(*priority_cache
)->kx
, kx_priority_secure
);
561 _set_priority (&(*priority_cache
)->mac
, mac_priority_secure
);
563 else if (strcasecmp (broken_list
[i
], "SECURE128") == 0)
565 _set_priority (&(*priority_cache
)->cipher
, cipher_priority_secure128
);
566 _set_priority (&(*priority_cache
)->kx
, kx_priority_secure
);
567 _set_priority (&(*priority_cache
)->mac
, mac_priority_secure
);
569 else if (strcasecmp (broken_list
[i
], "EXPORT") == 0)
571 _set_priority (&(*priority_cache
)->cipher
, cipher_priority_export
);
572 _set_priority (&(*priority_cache
)->kx
, kx_priority_export
);
573 _set_priority (&(*priority_cache
)->mac
, mac_priority_secure
);
574 } /* now check if the element is something like -ALGO */
575 else if (broken_list
[i
][0] == '!' || broken_list
[i
][0] == '+'
576 || broken_list
[i
][0] == '-')
578 if (broken_list
[i
][0] == '+')
584 gnutls_mac_get_id (&broken_list
[i
][1])) != GNUTLS_MAC_UNKNOWN
)
585 fn (&(*priority_cache
)->mac
, algo
);
586 else if ((algo
= gnutls_cipher_get_id (&broken_list
[i
][1])) !=
587 GNUTLS_CIPHER_UNKNOWN
)
588 fn (&(*priority_cache
)->cipher
, algo
);
589 else if ((algo
= gnutls_kx_get_id (&broken_list
[i
][1])) !=
591 fn (&(*priority_cache
)->kx
, algo
);
592 else if (strncasecmp (&broken_list
[i
][1], "VERS-", 5) == 0)
595 gnutls_protocol_get_id (&broken_list
[i
][6])) !=
596 GNUTLS_VERSION_UNKNOWN
)
597 fn (&(*priority_cache
)->protocol
, algo
);
598 } /* now check if the element is something like -ALGO */
599 else if (strncasecmp (&broken_list
[i
][1], "COMP-", 5) == 0)
602 gnutls_compression_get_id (&broken_list
[i
][6])) !=
604 fn (&(*priority_cache
)->compression
, algo
);
605 } /* now check if the element is something like -ALGO */
606 else if (strncasecmp (&broken_list
[i
][1], "CTYPE-", 6) == 0)
609 gnutls_certificate_type_get_id (&broken_list
[i
][7])) !=
611 fn (&(*priority_cache
)->cert_type
, algo
);
612 } /* now check if the element is something like -ALGO */
616 else if (broken_list
[i
][0] == '%')
618 if (strcasecmp (&broken_list
[i
][1], "COMPAT") == 0)
619 (*priority_cache
)->no_padding
= 1;
631 if (err_pos
!= NULL
&& i
< broken_list_size
)
633 *err_pos
= priorities
;
634 for (j
= 0; j
< i
; j
++)
636 (*err_pos
) += strlen (broken_list
[j
]) + 1;
641 return GNUTLS_E_INVALID_REQUEST
;
646 * gnutls_priority_deinit - Deinitialize the priorities cache for the cipher suites supported by gnutls.
647 * @priority_cache: is a #gnutls_prioritity_t structure.
649 * Deinitializes the priority cache.
653 gnutls_priority_deinit (gnutls_priority_t priority_cache
)
655 gnutls_free (priority_cache
);
660 * gnutls_priority_set_direct - Sets priorities for the cipher suites supported by gnutls.
661 * @session: is a #gnutls_session_t structure.
662 * @priorities: is a string describing priorities
663 * @err_pos: In case of an error this will have the position in the string the error occured
665 * Sets the priorities to use on the ciphers, key exchange methods,
666 * macs and compression methods. This function avoids keeping a
667 * priority cache and is used to directly set string priorities to a
668 * TLS session. For documentation check the gnutls_priority_init().
670 * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
671 * %GNUTLS_E_SUCCESS on success, or an error code.
674 gnutls_priority_set_direct (gnutls_session_t session
, const char *priorities
,
675 const char **err_pos
)
677 gnutls_priority_t prio
;
680 ret
= gnutls_priority_init (&prio
, priorities
, err_pos
);
687 ret
= gnutls_priority_set (session
, prio
);
694 gnutls_priority_deinit (prio
);
699 /* Breaks a list of "xxx", "yyy", to a character array, of
700 * MAX_COMMA_SEP_ELEMENTS size; Note that the given string is modified.
703 break_comma_list (char *etag
,
704 char **broken_etag
, int *elements
, int max_elements
,
715 broken_etag
[*elements
] = p
;
723 p
++; /* move to next entry and skip white
730 while (p
!= NULL
&& *elements
< max_elements
);
734 * gnutls_set_default_priority - Sets some default priority on the cipher suites supported by gnutls.
735 * @session: is a #gnutls_session_t structure.
737 * Sets some default priority on the ciphers, key exchange methods,
738 * macs and compression methods.
740 * This is the same as calling:
742 * gnutls_priority_set_direct (session, "NORMAL", NULL);
744 * This function is kept around for backwards compatibility, but
745 * because of its wide use it is still fully supported. If you wish
746 * to allow users to provide a string that specify which ciphers to
747 * use (which is recommended), you should use
748 * gnutls_priority_set_direct() or gnutls_priority_set() instead.
750 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
753 gnutls_set_default_priority (gnutls_session_t session
)
755 return gnutls_priority_set_direct (session
, "NORMAL", NULL
);
759 * gnutls_set_default_export_priority - Sets some default priority on the cipher suites supported by gnutls.
760 * @session: is a #gnutls_session_t structure.
762 * Sets some default priority on the ciphers, key exchange methods, macs
763 * and compression methods. This function also includes weak algorithms.
765 * This is the same as calling:
767 * gnutls_priority_set_direct (session, "EXPORT", NULL);
769 * This function is kept around for backwards compatibility, but
770 * because of its wide use it is still fully supported. If you wish
771 * to allow users to provide a string that specify which ciphers to
772 * use (which is recommended), you should use
773 * gnutls_priority_set_direct() or gnutls_priority_set() instead.
775 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
778 gnutls_set_default_export_priority (gnutls_session_t session
)
780 return gnutls_priority_set_direct (session
, "EXPORT", NULL
);