Tizen 2.0 Release
[external/libgnutls26.git] / lib / gnutls_priority.c
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 /* Here lies the code of the gnutls_*_set_priority() functions.
27  */
28
29 #include "gnutls_int.h"
30 #include "gnutls_algorithms.h"
31 #include "gnutls_errors.h"
32 #include <gnutls_num.h>
33
34 static void
35 break_comma_list (char *etag,
36                   char **broken_etag, int *elements, int max_elements,
37                   char sep);
38
39 /**
40  * gnutls_cipher_set_priority:
41  * @session: is a #gnutls_session_t structure.
42  * @list: is a 0 terminated list of gnutls_cipher_algorithm_t elements.
43  *
44  * Sets the priority on the ciphers supported by gnutls.  Priority is
45  * higher for elements specified before others.  After specifying the
46  * ciphers you want, you must append a 0.  Note that the priority is
47  * set on the client. The server does not use the algorithm's
48  * priority except for disabling algorithms that were not specified.
49  *
50  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
51  **/
52 int
53 gnutls_cipher_set_priority (gnutls_session_t session, const int *list)
54 {
55   int num = 0, i;
56
57   while (list[num] != 0)
58     num++;
59   if (num > MAX_ALGOS)
60     num = MAX_ALGOS;
61   session->internals.priorities.cipher.algorithms = num;
62
63   for (i = 0; i < num; i++)
64     {
65       session->internals.priorities.cipher.priority[i] = list[i];
66     }
67
68   return 0;
69 }
70
71 typedef void (bulk_rmadd_func) (priority_st * priority_list, const int *);
72
73 inline static void
74 _set_priority (priority_st * st, const int *list)
75 {
76   int num = 0, i;
77
78   while (list[num] != 0)
79     num++;
80   if (num > MAX_ALGOS)
81     num = MAX_ALGOS;
82   st->algorithms = num;
83
84   for (i = 0; i < num; i++)
85     {
86       st->priority[i] = list[i];
87     }
88
89   return;
90 }
91
92 static void
93 _clear_priorities (priority_st * st, const int *list)
94 {
95   memset(st, 0, sizeof(*st));  
96 }
97
98 /**
99  * gnutls_kx_set_priority:
100  * @session: is a #gnutls_session_t structure.
101  * @list: is a 0 terminated list of gnutls_kx_algorithm_t elements.
102  *
103  * Sets the priority on the key exchange algorithms supported by
104  * gnutls.  Priority is higher for elements specified before others.
105  * After specifying the algorithms you want, you must append a 0.
106  * Note that the priority is set on the client. The server does not
107  * use the algorithm's priority except for disabling algorithms that
108  * were not specified.
109  *
110  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
111  **/
112 int
113 gnutls_kx_set_priority (gnutls_session_t session, const int *list)
114 {
115   _set_priority (&session->internals.priorities.kx, list);
116   return 0;
117 }
118
119 /**
120  * gnutls_mac_set_priority:
121  * @session: is a #gnutls_session_t structure.
122  * @list: is a 0 terminated list of gnutls_mac_algorithm_t elements.
123  *
124  * Sets the priority on the mac algorithms supported by gnutls.
125  * Priority is higher for elements specified before others.  After
126  * specifying the algorithms you want, you must append a 0.  Note
127  * that the priority is set on the client. The server does not use
128  * the algorithm's priority except for disabling algorithms that were
129  * not specified.
130  *
131  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
132  **/
133 int
134 gnutls_mac_set_priority (gnutls_session_t session, const int *list)
135 {
136   _set_priority (&session->internals.priorities.mac, list);
137   return 0;
138 }
139
140 /**
141  * gnutls_compression_set_priority:
142  * @session: is a #gnutls_session_t structure.
143  * @list: is a 0 terminated list of gnutls_compression_method_t elements.
144  *
145  * Sets the priority on the compression algorithms supported by
146  * gnutls.  Priority is higher for elements specified before others.
147  * After specifying the algorithms you want, you must append a 0.
148  * Note that the priority is set on the client. The server does not
149  * use the algorithm's priority except for disabling algorithms that
150  * were not specified.
151  *
152  * TLS 1.0 does not define any compression algorithms except
153  * NULL. Other compression algorithms are to be considered as gnutls
154  * extensions.
155  *
156  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
157  **/
158 int
159 gnutls_compression_set_priority (gnutls_session_t session, const int *list)
160 {
161   _set_priority (&session->internals.priorities.compression, list);
162   return 0;
163 }
164
165 /**
166  * gnutls_protocol_set_priority:
167  * @session: is a #gnutls_session_t structure.
168  * @list: is a 0 terminated list of gnutls_protocol_t elements.
169  *
170  * Sets the priority on the protocol versions supported by gnutls.
171  * This function actually enables or disables protocols. Newer protocol
172  * versions always have highest priority.
173  *
174  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
175  **/
176 int
177 gnutls_protocol_set_priority (gnutls_session_t session, const int *list)
178 {
179   _set_priority (&session->internals.priorities.protocol, list);
180
181   /* set the current version to the first in the chain.
182    * This will be overridden later.
183    */
184   if (list)
185     _gnutls_set_current_version (session, list[0]);
186
187   return 0;
188 }
189
190 /**
191  * gnutls_certificate_type_set_priority:
192  * @session: is a #gnutls_session_t structure.
193  * @list: is a 0 terminated list of gnutls_certificate_type_t elements.
194  *
195  * Sets the priority on the certificate types supported by gnutls.
196  * Priority is higher for elements specified before others.
197  * After specifying the types you want, you must append a 0.
198  * Note that the certificate type priority is set on the client.
199  * The server does not use the cert type priority except for disabling
200  * types that were not specified.
201  *
202  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
203  **/
204 int
205 gnutls_certificate_type_set_priority (gnutls_session_t session,
206                                       const int *list)
207 {
208 #ifdef ENABLE_OPENPGP
209   _set_priority (&session->internals.priorities.cert_type, list);
210   return 0;
211 #else
212
213   return GNUTLS_E_UNIMPLEMENTED_FEATURE;
214
215 #endif
216 }
217
218 static const int protocol_priority[] = {
219   GNUTLS_TLS1_2,
220   GNUTLS_TLS1_1,
221   GNUTLS_TLS1_0,
222   GNUTLS_SSL3,
223   0
224 };
225
226 static const int kx_priority_performance[] = {
227   GNUTLS_KX_RSA,
228   GNUTLS_KX_DHE_RSA,
229   GNUTLS_KX_DHE_DSS,
230   /* GNUTLS_KX_ANON_DH: Man-in-the-middle prone, don't add!
231    * GNUTLS_KX_RSA_EXPORT: Deprecated, don't add!
232    */
233   0
234 };
235
236 static const int kx_priority_export[] = {
237   GNUTLS_KX_RSA,
238   GNUTLS_KX_DHE_RSA,
239   GNUTLS_KX_DHE_DSS,
240   GNUTLS_KX_RSA_EXPORT,
241   0
242 };
243
244 static const int kx_priority_secure[] = {
245   /* The ciphersuites that offer forward secrecy take
246    * precendance
247    */
248   GNUTLS_KX_DHE_RSA,
249   GNUTLS_KX_DHE_DSS,
250   GNUTLS_KX_RSA,
251   /* GNUTLS_KX_ANON_DH: Man-in-the-middle prone, don't add!
252    * GNUTLS_KX_RSA_EXPORT: Deprecated, don't add!
253    */
254   0
255 };
256
257 static const int cipher_priority_performance[] = {
258   GNUTLS_CIPHER_ARCFOUR_128,
259 #ifdef  ENABLE_CAMELLIA
260   GNUTLS_CIPHER_CAMELLIA_128_CBC,
261 #endif
262   GNUTLS_CIPHER_AES_128_CBC,
263   GNUTLS_CIPHER_3DES_CBC,
264   GNUTLS_CIPHER_AES_256_CBC,
265 #ifdef  ENABLE_CAMELLIA
266   GNUTLS_CIPHER_CAMELLIA_256_CBC,
267 #endif
268   /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
269   0
270 };
271
272 static const int cipher_priority_normal[] = {
273   GNUTLS_CIPHER_AES_128_CBC,
274 #ifdef  ENABLE_CAMELLIA
275   GNUTLS_CIPHER_CAMELLIA_128_CBC,
276 #endif
277   GNUTLS_CIPHER_AES_256_CBC,
278 #ifdef  ENABLE_CAMELLIA
279   GNUTLS_CIPHER_CAMELLIA_256_CBC,
280 #endif
281   GNUTLS_CIPHER_3DES_CBC,
282   GNUTLS_CIPHER_ARCFOUR_128,
283   /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
284   0
285 };
286
287 static const int cipher_priority_secure128[] = {
288   GNUTLS_CIPHER_AES_128_CBC,
289 #ifdef  ENABLE_CAMELLIA
290   GNUTLS_CIPHER_CAMELLIA_128_CBC,
291 #endif
292   GNUTLS_CIPHER_3DES_CBC,
293   GNUTLS_CIPHER_ARCFOUR_128,
294   /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
295   0
296 };
297
298
299 static const int cipher_priority_secure256[] = {
300   GNUTLS_CIPHER_AES_256_CBC,
301 #ifdef  ENABLE_CAMELLIA
302   GNUTLS_CIPHER_CAMELLIA_256_CBC,
303 #endif
304   GNUTLS_CIPHER_AES_128_CBC,
305 #ifdef  ENABLE_CAMELLIA
306   GNUTLS_CIPHER_CAMELLIA_128_CBC,
307 #endif
308   GNUTLS_CIPHER_3DES_CBC,
309   GNUTLS_CIPHER_ARCFOUR_128,
310   /* GNUTLS_CIPHER_ARCFOUR_40: Insecure, don't add! */
311   0
312 };
313
314 /* The same as cipher_priority_security_normal + arcfour-40. */
315 static const int cipher_priority_export[] = {
316   GNUTLS_CIPHER_AES_128_CBC,
317   GNUTLS_CIPHER_AES_256_CBC,
318 #ifdef  ENABLE_CAMELLIA
319   GNUTLS_CIPHER_CAMELLIA_128_CBC,
320   GNUTLS_CIPHER_CAMELLIA_256_CBC,
321 #endif
322   GNUTLS_CIPHER_3DES_CBC,
323   GNUTLS_CIPHER_ARCFOUR_128,
324   GNUTLS_CIPHER_ARCFOUR_40,
325   0
326 };
327
328 static const int comp_priority[] = {
329   /* compression should be explicitely requested to be enabled */
330   GNUTLS_COMP_NULL,
331   0
332 };
333
334 static const int sign_priority_default[] = {
335   GNUTLS_SIGN_DSA_SHA224,
336   GNUTLS_SIGN_DSA_SHA256,
337   GNUTLS_SIGN_RSA_SHA256,
338   GNUTLS_SIGN_RSA_SHA384,
339   GNUTLS_SIGN_RSA_SHA512,
340   GNUTLS_SIGN_RSA_SHA1,
341   GNUTLS_SIGN_DSA_SHA1,
342   0
343 };
344
345 static const int sign_priority_secure128[] = {
346   GNUTLS_SIGN_RSA_SHA256,
347   GNUTLS_SIGN_RSA_SHA384,
348   GNUTLS_SIGN_RSA_SHA512,
349   GNUTLS_SIGN_DSA_SHA1,
350   0
351 };
352
353 static const int sign_priority_secure256[] = {
354   GNUTLS_SIGN_RSA_SHA512,
355   0
356 };
357
358 static const int mac_priority_normal[] = {
359   GNUTLS_MAC_SHA1,
360   GNUTLS_MAC_SHA256,
361   GNUTLS_MAC_MD5,
362   0
363 };
364
365
366 static const int mac_priority_secure[] = {
367   GNUTLS_MAC_SHA256,
368   GNUTLS_MAC_SHA1,
369   0
370 };
371
372 static const int cert_type_priority_default[] = {
373   GNUTLS_CRT_X509,
374   0
375 };
376
377 static const int cert_type_priority_all[] = {
378   GNUTLS_CRT_X509,
379   GNUTLS_CRT_OPENPGP,
380   0
381 };
382
383 typedef void (rmadd_func) (priority_st * priority_list, unsigned int alg);
384
385 static void
386 prio_remove (priority_st * priority_list, unsigned int algo)
387 {
388   int i = 0;
389   int pos = -1;                 /* the position of the cipher to remove */
390
391   while (priority_list->priority[i] != 0)
392     {
393       if (priority_list->priority[i] == algo)
394         pos = i;
395       i++;
396     }
397
398   if (pos >= 0)
399     {
400       priority_list->priority[pos] = priority_list->priority[i - 1];
401       priority_list->priority[i - 1] = 0;
402       priority_list->algorithms--;
403     }
404
405   return;
406 }
407
408 static void
409 prio_add (priority_st * priority_list, unsigned int algo)
410 {
411   register int i = 0;
412   while (priority_list->priority[i] != 0)
413     {
414       if (algo == priority_list->priority[i])
415         return;                 /* if it exists */
416       i++;
417     }
418
419   if (i < MAX_ALGOS)
420     {
421       priority_list->priority[i] = algo;
422       priority_list->algorithms++;
423     }
424
425   return;
426 }
427
428
429 /**
430  * gnutls_priority_set:
431  * @session: is a #gnutls_session_t structure.
432  * @priority: is a #gnutls_priority_t structure.
433  *
434  * Sets the priorities to use on the ciphers, key exchange methods,
435  * macs and compression methods.
436  *
437  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
438  **/
439 int
440 gnutls_priority_set (gnutls_session_t session, gnutls_priority_t priority)
441 {
442   if (priority == NULL)
443     {
444       gnutls_assert ();
445       return GNUTLS_E_NO_CIPHER_SUITES;
446     }
447
448   memcpy (&session->internals.priorities, priority,
449           sizeof (struct gnutls_priority_st));
450
451   /* set the current version to the first in the chain.
452    * This will be overridden later.
453    */
454   if (session->internals.priorities.protocol.algorithms > 0)
455     _gnutls_set_current_version (session,
456                                  session->internals.priorities.protocol.
457                                  priority[0]);
458
459   return 0;
460 }
461
462
463 #define MAX_ELEMENTS 48
464
465 /**
466  * gnutls_priority_init:
467  * @priority_cache: is a #gnutls_prioritity_t structure.
468  * @priorities: is a string describing priorities
469  * @err_pos: In case of an error this will have the position in the string the error occured
470  *
471  * Sets priorities for the ciphers, key exchange methods, macs and
472  * compression methods.
473  *
474  * The #priorities option allows you to specify a colon
475  * separated list of the cipher priorities to enable.
476  *
477  * Common keywords: Some keywords are defined to provide quick access
478  * to common preferences.
479  *
480  * "PERFORMANCE" means all the "secure" ciphersuites are enabled,
481  * limited to 128 bit ciphers and sorted by terms of speed
482  * performance.
483  *
484  * "NORMAL" means all "secure" ciphersuites. The 256-bit ciphers are
485  * included as a fallback only.  The ciphers are sorted by security
486  * margin.
487  *
488  * "SECURE128" means all "secure" ciphersuites with ciphers up to 128
489  * bits, sorted by security margin.
490  *
491  * "SECURE256" means all "secure" ciphersuites including the 256 bit
492  * ciphers, sorted by security margin.
493  *
494  * "EXPORT" means all ciphersuites are enabled, including the
495  * low-security 40 bit ciphers.
496  *
497  * "NONE" means nothing is enabled.  This disables even protocols and
498  * compression methods.
499  *
500  * Special keywords:
501  * "!" or "-" appended with an algorithm will remove this algorithm.
502  *
503  * "+" appended with an algorithm will add this algorithm.
504  *
505  * Check the GnuTLS manual section "Priority strings" for detailed
506  * information.
507  *
508  * Examples:
509  *
510  * "NONE:+VERS-TLS-ALL:+MAC-ALL:+RSA:+AES-128-CBC:+SIGN-ALL:+COMP-NULL"
511  *
512  * "NORMAL:-ARCFOUR-128" means normal ciphers except for ARCFOUR-128.
513  *
514  * "SECURE:-VERS-SSL3.0:+COMP-DEFLATE" means that only secure ciphers are
515  * enabled, SSL3.0 is disabled, and libz compression enabled.
516  *
517  * "NONE:+VERS-TLS-ALL:+AES-128-CBC:+RSA:+SHA1:+COMP-NULL:+SIGN-RSA-SHA1", 
518  *
519  * "NORMAL:%COMPAT" is the most compatible mode.
520  *
521  * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
522  * %GNUTLS_E_SUCCESS on success, or an error code.
523  **/
524 int
525 gnutls_priority_init (gnutls_priority_t * priority_cache,
526                       const char *priorities, const char **err_pos)
527 {
528   char *broken_list[MAX_ELEMENTS];
529   int broken_list_size = 0, i = 0, j;
530   char *darg = NULL;
531   int algo;
532   rmadd_func *fn;
533   bulk_rmadd_func *bulk_fn;
534
535   *priority_cache = gnutls_calloc (1, sizeof (struct gnutls_priority_st));
536   if (*priority_cache == NULL)
537     {
538       gnutls_assert ();
539       return GNUTLS_E_MEMORY_ERROR;
540     }
541
542   /* for now unsafe renegotiation is default on everyone. To be removed
543    * when we make it the default.
544    */
545   (*priority_cache)->sr = SR_PARTIAL;
546   (*priority_cache)->ssl3_record_version = 1;
547
548   if (priorities == NULL)
549     priorities = "NORMAL";
550
551   darg = gnutls_strdup (priorities);
552   if (darg == NULL)
553     {
554       gnutls_assert ();
555       goto error;
556     }
557
558   break_comma_list (darg, broken_list, &broken_list_size, MAX_ELEMENTS, ':');
559   /* This is our default set of protocol version, certificate types and
560    * compression methods.
561    */
562   if (strcasecmp (broken_list[0], "NONE") != 0)
563     {
564       _set_priority (&(*priority_cache)->protocol, protocol_priority);
565       _set_priority (&(*priority_cache)->compression, comp_priority);
566       _set_priority (&(*priority_cache)->cert_type, cert_type_priority_default);
567       _set_priority (&(*priority_cache)->sign_algo, sign_priority_default);
568       i = 0;
569     }
570   else
571     {
572       i = 1;
573     }
574
575   for (; i < broken_list_size; i++)
576     {
577       if (strcasecmp (broken_list[i], "PERFORMANCE") == 0)
578         {
579           _set_priority (&(*priority_cache)->cipher,
580                          cipher_priority_performance);
581           _set_priority (&(*priority_cache)->kx, kx_priority_performance);
582           _set_priority (&(*priority_cache)->mac, mac_priority_normal);
583           _set_priority (&(*priority_cache)->sign_algo,
584                          sign_priority_default);
585         }
586       else if (strcasecmp (broken_list[i], "NORMAL") == 0)
587         {
588           _set_priority (&(*priority_cache)->cipher, cipher_priority_normal);
589           _set_priority (&(*priority_cache)->kx, kx_priority_secure);
590           _set_priority (&(*priority_cache)->mac, mac_priority_normal);
591           _set_priority (&(*priority_cache)->sign_algo,
592                          sign_priority_default);
593         }
594       else if (strcasecmp (broken_list[i], "SECURE256") == 0
595                || strcasecmp (broken_list[i], "SECURE") == 0)
596         {
597           _set_priority (&(*priority_cache)->cipher,
598                          cipher_priority_secure256);
599           _set_priority (&(*priority_cache)->kx, kx_priority_secure);
600           _set_priority (&(*priority_cache)->mac, mac_priority_secure);
601           _set_priority (&(*priority_cache)->sign_algo,
602                          sign_priority_secure256);
603         }
604       else if (strcasecmp (broken_list[i], "SECURE128") == 0)
605         {
606           _set_priority (&(*priority_cache)->cipher,
607                          cipher_priority_secure128);
608           _set_priority (&(*priority_cache)->kx, kx_priority_secure);
609           _set_priority (&(*priority_cache)->mac, mac_priority_secure);
610           _set_priority (&(*priority_cache)->sign_algo,
611                          sign_priority_secure128);
612         }
613       else if (strcasecmp (broken_list[i], "EXPORT") == 0)
614         {
615           _set_priority (&(*priority_cache)->cipher, cipher_priority_export);
616           _set_priority (&(*priority_cache)->kx, kx_priority_export);
617           _set_priority (&(*priority_cache)->mac, mac_priority_secure);
618           _set_priority (&(*priority_cache)->sign_algo,
619                          sign_priority_default);
620         }                       /* now check if the element is something like -ALGO */
621       else if (broken_list[i][0] == '!' || broken_list[i][0] == '+'
622                || broken_list[i][0] == '-')
623         {
624           if (broken_list[i][0] == '+')
625             {
626               fn = prio_add;
627               bulk_fn = _set_priority;
628             }
629           else
630             {
631               fn = prio_remove;
632               bulk_fn = _clear_priorities;
633             }
634
635           if ((algo =
636                gnutls_mac_get_id (&broken_list[i][1])) != GNUTLS_MAC_UNKNOWN)
637             fn (&(*priority_cache)->mac, algo);
638           else if ((algo = gnutls_cipher_get_id (&broken_list[i][1])) !=
639                    GNUTLS_CIPHER_UNKNOWN)
640             fn (&(*priority_cache)->cipher, algo);
641           else if ((algo = gnutls_kx_get_id (&broken_list[i][1])) !=
642                    GNUTLS_KX_UNKNOWN)
643             fn (&(*priority_cache)->kx, algo);
644           else if (strncasecmp (&broken_list[i][1], "VERS-", 5) == 0)
645             {
646               if (strncasecmp (&broken_list[i][1], "VERS-TLS-ALL", 12) == 0)
647                 {
648                   bulk_fn (&(*priority_cache)->protocol,
649                                  protocol_priority);
650                 }
651               else
652                 {
653                   if ((algo =
654                        gnutls_protocol_get_id (&broken_list[i][6])) !=
655                       GNUTLS_VERSION_UNKNOWN)
656                     fn (&(*priority_cache)->protocol, algo);
657                   else
658                     goto error;
659
660                 }
661             }                   /* now check if the element is something like -ALGO */
662           else if (strncasecmp (&broken_list[i][1], "COMP-", 5) == 0)
663             {
664               if (strncasecmp (&broken_list[i][1], "COMP-ALL", 8) == 0)
665                 {
666                   bulk_fn (&(*priority_cache)->compression,
667                                  comp_priority);
668                 }
669               else
670                 {
671                   if ((algo =
672                        gnutls_compression_get_id (&broken_list[i][6])) !=
673                       GNUTLS_COMP_UNKNOWN)
674                     fn (&(*priority_cache)->compression, algo);
675                   else
676                     goto error;
677                 }
678             }                   /* now check if the element is something like -ALGO */
679           else if (strncasecmp (&broken_list[i][1], "CTYPE-", 6) == 0)
680             {
681               if (strncasecmp (&broken_list[i][1], "CTYPE-ALL", 9) == 0)
682                 {
683                   bulk_fn (&(*priority_cache)->cert_type,
684                                  cert_type_priority_all);
685                 }
686               else
687                 {
688                   if ((algo =
689                        gnutls_certificate_type_get_id (&broken_list[i][7])) !=
690                       GNUTLS_CRT_UNKNOWN)
691                     fn (&(*priority_cache)->cert_type, algo);
692                   else
693                     goto error;
694                 }
695             }                   /* now check if the element is something like -ALGO */
696           else if (strncasecmp (&broken_list[i][1], "SIGN-", 5) == 0)
697             {
698               if (strncasecmp (&broken_list[i][1], "SIGN-ALL", 8) == 0)
699                 {
700                   bulk_fn (&(*priority_cache)->sign_algo,
701                                  sign_priority_default);
702                 }
703               else
704                 {
705                   if ((algo =
706                        gnutls_sign_get_id (&broken_list[i][6])) !=
707                       GNUTLS_SIGN_UNKNOWN)
708                     fn (&(*priority_cache)->sign_algo, algo);
709                   else
710                     goto error;
711                 }
712             }
713           else if (strncasecmp (&broken_list[i][1], "MAC-ALL", 7) == 0)
714             {
715                   bulk_fn (&(*priority_cache)->mac,
716                                 mac_priority_secure);
717             }
718           else if (strncasecmp (&broken_list[i][1], "CIPHER-ALL", 7) == 0)
719             {
720                   bulk_fn (&(*priority_cache)->cipher,
721                                 cipher_priority_normal);
722             }
723           else
724             goto error;
725         }
726       else if (broken_list[i][0] == '%')
727         {
728           if (strcasecmp (&broken_list[i][1], "COMPAT") == 0)
729             {
730               (*priority_cache)->no_padding = 1;
731               (*priority_cache)->allow_large_records = 1;
732             }
733           else if (strcasecmp (&broken_list[i][1],
734                                "VERIFY_ALLOW_SIGN_RSA_MD5") == 0)
735             {
736               prio_add (&(*priority_cache)->sign_algo, GNUTLS_SIGN_RSA_MD5);
737               (*priority_cache)->additional_verify_flags |=
738                 GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5;
739             }
740           else if (strcasecmp (&broken_list[i][1],
741                                "SSL3_RECORD_VERSION") == 0)
742             (*priority_cache)->ssl3_record_version = 1;
743           else if (strcasecmp (&broken_list[i][1],
744                                "LATEST_RECORD_VERSION") == 0)
745             (*priority_cache)->ssl3_record_version = 0;
746           else if (strcasecmp (&broken_list[i][1],
747                                "VERIFY_ALLOW_X509_V1_CA_CRT") == 0)
748             (*priority_cache)->additional_verify_flags |=
749               GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT;
750           else if (strcasecmp (&broken_list[i][1],
751                                "UNSAFE_RENEGOTIATION") == 0)
752             {
753               (*priority_cache)->sr = SR_UNSAFE;
754             }
755           else if (strcasecmp (&broken_list[i][1], "SAFE_RENEGOTIATION") == 0)
756             {
757               (*priority_cache)->sr = SR_SAFE;
758             }
759           else if (strcasecmp (&broken_list[i][1],
760                                "PARTIAL_RENEGOTIATION") == 0)
761             {
762               (*priority_cache)->sr = SR_PARTIAL;
763             }
764           else if (strcasecmp (&broken_list[i][1],
765                                "DISABLE_SAFE_RENEGOTIATION") == 0)
766             {
767               (*priority_cache)->sr = SR_DISABLED;
768             }
769           else
770             goto error;
771         }
772       else
773         goto error;
774     }
775
776   gnutls_free (darg);
777   return 0;
778
779 error:
780   if (err_pos != NULL && i < broken_list_size)
781     {
782       *err_pos = priorities;
783       for (j = 0; j < i; j++)
784         {
785           (*err_pos) += strlen (broken_list[j]) + 1;
786         }
787     }
788   gnutls_free (darg);
789   gnutls_free (*priority_cache);
790
791   return GNUTLS_E_INVALID_REQUEST;
792
793 }
794
795 /**
796  * gnutls_priority_deinit:
797  * @priority_cache: is a #gnutls_prioritity_t structure.
798  *
799  * Deinitializes the priority cache.
800  **/
801 void
802 gnutls_priority_deinit (gnutls_priority_t priority_cache)
803 {
804   gnutls_free (priority_cache);
805 }
806
807
808 /**
809  * gnutls_priority_set_direct:
810  * @session: is a #gnutls_session_t structure.
811  * @priorities: is a string describing priorities
812  * @err_pos: In case of an error this will have the position in the string the error occured
813  *
814  * Sets the priorities to use on the ciphers, key exchange methods,
815  * macs and compression methods.  This function avoids keeping a
816  * priority cache and is used to directly set string priorities to a
817  * TLS session.  For documentation check the gnutls_priority_init().
818  *
819  * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
820  * %GNUTLS_E_SUCCESS on success, or an error code.
821  **/
822 int
823 gnutls_priority_set_direct (gnutls_session_t session,
824                             const char *priorities, const char **err_pos)
825 {
826   gnutls_priority_t prio;
827   int ret;
828
829   ret = gnutls_priority_init (&prio, priorities, err_pos);
830   if (ret < 0)
831     {
832       gnutls_assert ();
833       return ret;
834     }
835
836   ret = gnutls_priority_set (session, prio);
837   if (ret < 0)
838     {
839       gnutls_assert ();
840       return ret;
841     }
842
843   gnutls_priority_deinit (prio);
844
845   return 0;
846 }
847
848 /* Breaks a list of "xxx", "yyy", to a character array, of
849  * MAX_COMMA_SEP_ELEMENTS size; Note that the given string is modified.
850   */
851 static void
852 break_comma_list (char *etag,
853                   char **broken_etag, int *elements, int max_elements,
854                   char sep)
855 {
856   char *p = etag;
857   if (sep == 0)
858     sep = ',';
859
860   *elements = 0;
861
862   do
863     {
864       broken_etag[*elements] = p;
865
866       (*elements)++;
867
868       p = strchr (p, sep);
869       if (p)
870         {
871           *p = 0;
872           p++;                  /* move to next entry and skip white
873                                  * space.
874                                  */
875           while (*p == ' ')
876             p++;
877         }
878     }
879   while (p != NULL && *elements < max_elements);
880 }
881
882 /**
883  * gnutls_set_default_priority:
884  * @session: is a #gnutls_session_t structure.
885  *
886  * Sets some default priority on the ciphers, key exchange methods,
887  * macs and compression methods.
888  *
889  * This is the same as calling:
890  *
891  * gnutls_priority_set_direct (session, "NORMAL", NULL);
892  *
893  * This function is kept around for backwards compatibility, but
894  * because of its wide use it is still fully supported.  If you wish
895  * to allow users to provide a string that specify which ciphers to
896  * use (which is recommended), you should use
897  * gnutls_priority_set_direct() or gnutls_priority_set() instead.
898  *
899  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
900  **/
901 int
902 gnutls_set_default_priority (gnutls_session_t session)
903 {
904   return gnutls_priority_set_direct (session, "NORMAL", NULL);
905 }
906
907 /**
908  * gnutls_set_default_export_priority:
909  * @session: is a #gnutls_session_t structure.
910  *
911  * Sets some default priority on the ciphers, key exchange methods, macs
912  * and compression methods.  This function also includes weak algorithms.
913  *
914  * This is the same as calling:
915  *
916  * gnutls_priority_set_direct (session, "EXPORT", NULL);
917  *
918  * This function is kept around for backwards compatibility, but
919  * because of its wide use it is still fully supported.  If you wish
920  * to allow users to provide a string that specify which ciphers to
921  * use (which is recommended), you should use
922  * gnutls_priority_set_direct() or gnutls_priority_set() instead.
923  *
924  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
925  **/
926 int
927 gnutls_set_default_export_priority (gnutls_session_t session)
928 {
929   return gnutls_priority_set_direct (session, "EXPORT", NULL);
930 }