FIPS140 mode is detected on run-time.
[gnutls:gnutls.git] / lib / gnutls_priority.c
1 /*
2  * Copyright (C) 2004-2012 Free Software Foundation, Inc.
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
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 2.1 of
11  * the License, or (at your option) any later version.
12  *
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.
17  *
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/>
20  *
21  */
22
23 /* Here lies the code of the gnutls_*_set_priority() functions.
24  */
25
26 #include "gnutls_int.h"
27 #include "algorithms.h"
28 #include "gnutls_errors.h"
29 #include <gnutls_num.h>
30
31 static void
32 break_comma_list(char *etag,
33                  char **broken_etag, int *elements, int max_elements,
34                  char sep);
35
36 /**
37  * gnutls_cipher_set_priority:
38  * @session: is a #gnutls_session_t structure.
39  * @list: is a 0 terminated list of gnutls_cipher_algorithm_t elements.
40  *
41  * Sets the priority on the ciphers supported by gnutls.  Priority is
42  * higher for elements specified before others.  After specifying the
43  * ciphers you want, you must append a 0.  Note that the priority is
44  * set on the client. The server does not use the algorithm's
45  * priority except for disabling algorithms that were not specified.
46  *
47  * Returns: %GNUTLS_E_SUCCESS (0) on success, or a negative error code.
48  **/
49 int gnutls_cipher_set_priority(gnutls_session_t session, const int *list)
50 {
51         int num = 0, i;
52
53         while (list[num] != 0)
54                 num++;
55         if (num > MAX_ALGOS)
56                 num = MAX_ALGOS;
57         session->internals.priorities.cipher.algorithms = num;
58
59         for (i = 0; i < num; i++) {
60                 session->internals.priorities.cipher.priority[i] = list[i];
61         }
62
63         return 0;
64 }
65
66 typedef void (bulk_rmadd_func) (priority_st * priority_list, const int *);
67
68 inline static void _set_priority(priority_st * st, const int *list)
69 {
70         int num = 0, i;
71
72         while (list[num] != 0)
73                 num++;
74         if (num > MAX_ALGOS)
75                 num = MAX_ALGOS;
76         st->algorithms = num;
77
78         for (i = 0; i < num; i++) {
79                 st->priority[i] = list[i];
80         }
81
82         return;
83 }
84
85 inline static void _add_priority(priority_st * st, const int *list)
86 {
87         int num, i, j, init;
88
89         init = i = st->algorithms;
90
91         for (num = 0; list[num] != 0; ++num) {
92                 if (i + 1 > MAX_ALGOS) {
93                         return;
94                 }
95
96                 for (j = 0; j < init; j++) {
97                         if (st->priority[j] == (unsigned) list[num]) {
98                                 break;
99                         }
100                 }
101
102                 if (j == init) {
103                         st->priority[i++] = list[num];
104                         st->algorithms++;
105                 }
106         }
107
108         return;
109 }
110
111 static void _clear_priorities(priority_st * st, const int *list)
112 {
113         memset(st, 0, sizeof(*st));
114 }
115
116 /**
117  * gnutls_kx_set_priority:
118  * @session: is a #gnutls_session_t structure.
119  * @list: is a 0 terminated list of gnutls_kx_algorithm_t elements.
120  *
121  * Sets the priority on the key exchange algorithms supported by
122  * gnutls.  Priority is higher for elements specified before others.
123  * After specifying the algorithms you want, you must append a 0.
124  * Note that the priority is set on the client. The server does not
125  * use the algorithm's priority except for disabling algorithms that
126  * were not specified.
127  *
128  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
129  **/
130 int gnutls_kx_set_priority(gnutls_session_t session, const int *list)
131 {
132         _set_priority(&session->internals.priorities.kx, list);
133         return 0;
134 }
135
136 /**
137  * gnutls_mac_set_priority:
138  * @session: is a #gnutls_session_t structure.
139  * @list: is a 0 terminated list of gnutls_mac_algorithm_t elements.
140  *
141  * Sets the priority on the mac algorithms supported by gnutls.
142  * Priority is higher for elements specified before others.  After
143  * specifying the algorithms you want, you must append a 0.  Note
144  * that the priority is set on the client. The server does not use
145  * the algorithm's priority except for disabling algorithms that were
146  * not specified.
147  *
148  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
149  **/
150 int gnutls_mac_set_priority(gnutls_session_t session, const int *list)
151 {
152         _set_priority(&session->internals.priorities.mac, list);
153         return 0;
154 }
155
156 /**
157  * gnutls_compression_set_priority:
158  * @session: is a #gnutls_session_t structure.
159  * @list: is a 0 terminated list of gnutls_compression_method_t elements.
160  *
161  * Sets the priority on the compression algorithms supported by
162  * gnutls.  Priority is higher for elements specified before others.
163  * After specifying the algorithms you want, you must append a 0.
164  * Note that the priority is set on the client. The server does not
165  * use the algorithm's priority except for disabling algorithms that
166  * were not specified.
167  *
168  * TLS 1.0 does not define any compression algorithms except
169  * NULL. Other compression algorithms are to be considered as gnutls
170  * extensions.
171  *
172  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
173  **/
174 int
175 gnutls_compression_set_priority(gnutls_session_t session, const int *list)
176 {
177         _set_priority(&session->internals.priorities.compression, list);
178         return 0;
179 }
180
181 /**
182  * gnutls_protocol_set_priority:
183  * @session: is a #gnutls_session_t structure.
184  * @list: is a 0 terminated list of gnutls_protocol_t elements.
185  *
186  * Sets the priority on the protocol versions supported by gnutls.
187  * This function actually enables or disables protocols. Newer protocol
188  * versions always have highest priority.
189  *
190  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
191  **/
192 int gnutls_protocol_set_priority(gnutls_session_t session, const int *list)
193 {
194         _set_priority(&session->internals.priorities.protocol, list);
195
196         /* set the current version to the first in the chain.
197          * This will be overridden later.
198          */
199         if (list)
200                 _gnutls_set_current_version(session, list[0]);
201
202         return 0;
203 }
204
205 /**
206  * gnutls_certificate_type_set_priority:
207  * @session: is a #gnutls_session_t structure.
208  * @list: is a 0 terminated list of gnutls_certificate_type_t elements.
209  *
210  * Sets the priority on the certificate types supported by gnutls.
211  * Priority is higher for elements specified before others.
212  * After specifying the types you want, you must append a 0.
213  * Note that the certificate type priority is set on the client.
214  * The server does not use the cert type priority except for disabling
215  * types that were not specified.
216  *
217  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
218  **/
219 int
220 gnutls_certificate_type_set_priority(gnutls_session_t session,
221                                      const int *list)
222 {
223 #ifdef ENABLE_OPENPGP
224         _set_priority(&session->internals.priorities.cert_type, list);
225         return 0;
226 #else
227
228         return GNUTLS_E_UNIMPLEMENTED_FEATURE;
229
230 #endif
231 }
232
233 static const int supported_ecc_normal[] = {
234 #ifdef ENABLE_NON_SUITEB_CURVES
235         GNUTLS_ECC_CURVE_SECP192R1,
236         GNUTLS_ECC_CURVE_SECP224R1,
237 #endif
238         GNUTLS_ECC_CURVE_SECP256R1,
239         GNUTLS_ECC_CURVE_SECP384R1,
240         GNUTLS_ECC_CURVE_SECP521R1,
241         0
242 };
243
244 static const int supported_ecc_secure128[] = {
245         GNUTLS_ECC_CURVE_SECP256R1,
246         GNUTLS_ECC_CURVE_SECP384R1,
247         GNUTLS_ECC_CURVE_SECP521R1,
248         0
249 };
250
251 static const int supported_ecc_suiteb128[] = {
252         GNUTLS_ECC_CURVE_SECP256R1,
253         GNUTLS_ECC_CURVE_SECP384R1,
254         0
255 };
256
257 static const int supported_ecc_suiteb192[] = {
258         GNUTLS_ECC_CURVE_SECP384R1,
259         0
260 };
261
262 static const int supported_ecc_secure192[] = {
263         GNUTLS_ECC_CURVE_SECP384R1,
264         GNUTLS_ECC_CURVE_SECP521R1,
265         0
266 };
267
268 static const int protocol_priority[] = {
269         GNUTLS_TLS1_2,
270         GNUTLS_TLS1_1,
271         GNUTLS_TLS1_0,
272         GNUTLS_SSL3,
273         GNUTLS_DTLS1_2,
274         GNUTLS_DTLS1_0,
275         0
276 };
277
278 static const int dtls_protocol_priority[] = {
279         GNUTLS_DTLS1_2,
280         GNUTLS_DTLS1_0,
281         0
282 };
283
284 static const int protocol_priority_suiteb[] = {
285         GNUTLS_TLS1_2,
286         0
287 };
288
289 static const int kx_priority_performance[] = {
290         GNUTLS_KX_RSA,
291 #ifdef ENABLE_ECDHE
292         GNUTLS_KX_ECDHE_ECDSA,
293         GNUTLS_KX_ECDHE_RSA,
294 #endif
295 #ifdef ENABLE_DHE
296         GNUTLS_KX_DHE_RSA,
297         GNUTLS_KX_DHE_DSS,
298 #endif
299         0
300 };
301
302 static const int kx_priority_pfs[] = {
303 #ifdef ENABLE_ECDHE
304         GNUTLS_KX_ECDHE_ECDSA,
305         GNUTLS_KX_ECDHE_RSA,
306 #endif
307 #ifdef ENABLE_DHE
308         GNUTLS_KX_DHE_RSA,
309         GNUTLS_KX_DHE_DSS,
310 #endif
311         0
312 };
313
314 static const int kx_priority_suiteb[] = {
315         GNUTLS_KX_ECDHE_ECDSA,
316         0
317 };
318
319 static const int kx_priority_secure[] = {
320         /* The ciphersuites that offer forward secrecy take
321          * precedence
322          */
323 #ifdef ENABLE_ECDHE
324         GNUTLS_KX_ECDHE_ECDSA,
325         GNUTLS_KX_ECDHE_RSA,
326 #endif
327         GNUTLS_KX_RSA,
328         /* KX-RSA is now ahead of DHE-RSA and DHE-DSS due to the compatibility
329          * issues the DHE ciphersuites have. That is, one cannot enforce a specific
330          * security level without dropping the connection. 
331          */
332 #ifdef ENABLE_DHE
333         GNUTLS_KX_DHE_RSA,
334         GNUTLS_KX_DHE_DSS,
335 #endif
336         /* GNUTLS_KX_ANON_DH: Man-in-the-middle prone, don't add!
337          */
338         0
339 };
340
341 static const int cipher_priority_performance_default[] = {
342         GNUTLS_CIPHER_ARCFOUR_128,
343         GNUTLS_CIPHER_AES_128_GCM,
344         GNUTLS_CIPHER_AES_256_GCM,
345         GNUTLS_CIPHER_CAMELLIA_128_GCM,
346         GNUTLS_CIPHER_CAMELLIA_256_GCM,
347         GNUTLS_CIPHER_AES_128_CBC,
348         GNUTLS_CIPHER_AES_256_CBC,
349         GNUTLS_CIPHER_CAMELLIA_128_CBC,
350         GNUTLS_CIPHER_CAMELLIA_256_CBC,
351         GNUTLS_CIPHER_3DES_CBC,
352         0
353 };
354
355 /* If GCM and AES acceleration is available then prefer
356  * them over anything else.
357  */
358 static const int cipher_priority_normal_default[] = {
359         GNUTLS_CIPHER_AES_128_GCM,
360         GNUTLS_CIPHER_AES_256_GCM,
361         GNUTLS_CIPHER_CAMELLIA_128_GCM,
362         GNUTLS_CIPHER_CAMELLIA_256_GCM,
363         GNUTLS_CIPHER_AES_128_CBC,
364         GNUTLS_CIPHER_AES_256_CBC,
365         GNUTLS_CIPHER_CAMELLIA_128_CBC,
366         GNUTLS_CIPHER_CAMELLIA_256_CBC,
367         GNUTLS_CIPHER_3DES_CBC,
368         GNUTLS_CIPHER_ARCFOUR_128,
369         0
370 };
371
372 static const int cipher_priority_performance_fips[] = {
373         GNUTLS_CIPHER_AES_128_GCM,
374         GNUTLS_CIPHER_AES_256_GCM,
375         GNUTLS_CIPHER_AES_128_CBC,
376         GNUTLS_CIPHER_AES_256_CBC,
377         GNUTLS_CIPHER_3DES_CBC,
378         0
379 };
380
381 static const int cipher_priority_normal_fips[] = {
382         GNUTLS_CIPHER_AES_128_GCM,
383         GNUTLS_CIPHER_AES_256_GCM,
384         GNUTLS_CIPHER_AES_128_CBC,
385         GNUTLS_CIPHER_AES_256_CBC,
386         GNUTLS_CIPHER_3DES_CBC,
387         0
388 };
389
390
391 static const int cipher_priority_suiteb128[] = {
392         GNUTLS_CIPHER_AES_128_GCM,
393         GNUTLS_CIPHER_AES_256_GCM,
394         0
395 };
396
397 static const int cipher_priority_suiteb192[] = {
398         GNUTLS_CIPHER_AES_256_GCM,
399         0
400 };
401
402
403 static const int cipher_priority_secure128[] = {
404         GNUTLS_CIPHER_AES_128_GCM,
405         GNUTLS_CIPHER_CAMELLIA_128_GCM,
406         GNUTLS_CIPHER_AES_256_GCM,
407         GNUTLS_CIPHER_CAMELLIA_256_GCM,
408
409         GNUTLS_CIPHER_AES_128_CBC,
410         GNUTLS_CIPHER_CAMELLIA_128_CBC,
411         GNUTLS_CIPHER_AES_256_CBC,
412         GNUTLS_CIPHER_CAMELLIA_256_CBC,
413         0
414 };
415
416
417 static const int cipher_priority_secure192[] = {
418         GNUTLS_CIPHER_AES_256_GCM,
419         GNUTLS_CIPHER_CAMELLIA_256_GCM,
420         GNUTLS_CIPHER_AES_256_CBC,
421         GNUTLS_CIPHER_CAMELLIA_256_CBC,
422         0
423 };
424
425 static const int comp_priority[] = {
426         /* compression should be explicitly requested to be enabled */
427         GNUTLS_COMP_NULL,
428         0
429 };
430
431 static const int sign_priority_default[] = {
432         GNUTLS_SIGN_RSA_SHA256,
433         GNUTLS_SIGN_DSA_SHA256,
434         GNUTLS_SIGN_ECDSA_SHA256,
435
436         GNUTLS_SIGN_RSA_SHA384,
437         GNUTLS_SIGN_ECDSA_SHA384,
438
439         GNUTLS_SIGN_RSA_SHA512,
440         GNUTLS_SIGN_ECDSA_SHA512,
441
442         GNUTLS_SIGN_RSA_SHA224,
443         GNUTLS_SIGN_DSA_SHA224,
444         GNUTLS_SIGN_ECDSA_SHA224,
445
446         GNUTLS_SIGN_RSA_SHA1,
447         GNUTLS_SIGN_DSA_SHA1,
448         GNUTLS_SIGN_ECDSA_SHA1,
449         0
450 };
451
452 static const int sign_priority_suiteb128[] = {
453         GNUTLS_SIGN_ECDSA_SHA256,
454         GNUTLS_SIGN_ECDSA_SHA384,
455         0
456 };
457
458 static const int sign_priority_suiteb192[] = {
459         GNUTLS_SIGN_ECDSA_SHA384,
460         0
461 };
462
463 static const int sign_priority_secure128[] = {
464         GNUTLS_SIGN_RSA_SHA256,
465         GNUTLS_SIGN_DSA_SHA256,
466         GNUTLS_SIGN_ECDSA_SHA256,
467         GNUTLS_SIGN_RSA_SHA384,
468         GNUTLS_SIGN_ECDSA_SHA384,
469         GNUTLS_SIGN_RSA_SHA512,
470         GNUTLS_SIGN_ECDSA_SHA512,
471         0
472 };
473
474 static const int sign_priority_secure192[] = {
475         GNUTLS_SIGN_RSA_SHA384,
476         GNUTLS_SIGN_ECDSA_SHA384,
477         GNUTLS_SIGN_RSA_SHA512,
478         GNUTLS_SIGN_ECDSA_SHA512,
479         0
480 };
481
482 static const int mac_priority_normal_default[] = {
483         GNUTLS_MAC_SHA1,
484         GNUTLS_MAC_SHA256,
485         GNUTLS_MAC_SHA384,
486         GNUTLS_MAC_AEAD,
487         GNUTLS_MAC_MD5,
488         0
489 };
490
491 static const int mac_priority_normal_fips[] = {
492         GNUTLS_MAC_SHA1,
493         GNUTLS_MAC_SHA256,
494         GNUTLS_MAC_SHA384,
495         GNUTLS_MAC_AEAD,
496         0
497 };
498
499 static const int * cipher_priority_performance = cipher_priority_performance_default;
500 static const int * cipher_priority_normal = cipher_priority_normal_default;
501 static const int * mac_priority_normal = mac_priority_normal_default;
502
503 /* if called with replace the default priorities with the FIPS140 ones */
504 void _gnutls_priority_update_fips(void)
505 {
506         cipher_priority_performance = cipher_priority_performance_fips;
507         cipher_priority_normal = cipher_priority_normal_fips;
508         mac_priority_normal = mac_priority_normal_fips;
509 }
510
511 static const int mac_priority_suiteb128[] = {
512         GNUTLS_MAC_AEAD,
513         0
514 };
515
516 static const int mac_priority_suiteb192[] = {
517         GNUTLS_MAC_AEAD,
518         0
519 };
520
521 static const int mac_priority_secure128[] = {
522         GNUTLS_MAC_SHA1,
523         GNUTLS_MAC_SHA256,
524         GNUTLS_MAC_SHA384,
525         GNUTLS_MAC_AEAD,
526         0
527 };
528
529 static const int mac_priority_secure192[] = {
530         GNUTLS_MAC_SHA256,
531         GNUTLS_MAC_SHA384,
532         GNUTLS_MAC_AEAD,
533         0
534 };
535
536 static const int cert_type_priority_default[] = {
537         GNUTLS_CRT_X509,
538         0
539 };
540
541 static const int cert_type_priority_all[] = {
542         GNUTLS_CRT_X509,
543         GNUTLS_CRT_OPENPGP,
544         0
545 };
546
547 typedef void (rmadd_func) (priority_st * priority_list, unsigned int alg);
548
549 static void prio_remove(priority_st * priority_list, unsigned int algo)
550 {
551         unsigned int i;
552
553         for (i = 0; i < priority_list->algorithms; i++) {
554                 if (priority_list->priority[i] == algo) {
555                         priority_list->algorithms--;
556                         if ((priority_list->algorithms - i) > 0)
557                                 memmove(&priority_list->priority[i],
558                                         &priority_list->priority[i + 1],
559                                         (priority_list->algorithms -
560                                          i) *
561                                         sizeof(priority_list->
562                                                priority[0]));
563                         priority_list->priority[priority_list->
564                                                 algorithms] = 0;
565                         break;
566                 }
567         }
568
569         return;
570 }
571
572 static void prio_add(priority_st * priority_list, unsigned int algo)
573 {
574         unsigned int i, l = priority_list->algorithms;
575
576         if (l >= MAX_ALGOS)
577                 return;         /* can't add it anyway */
578
579         for (i = 0; i < l; ++i) {
580                 if (algo == priority_list->priority[i])
581                         return; /* if it exists */
582         }
583
584         priority_list->priority[l] = algo;
585         priority_list->algorithms++;
586
587         return;
588 }
589
590
591 /**
592  * gnutls_priority_set:
593  * @session: is a #gnutls_session_t structure.
594  * @priority: is a #gnutls_priority_t structure.
595  *
596  * Sets the priorities to use on the ciphers, key exchange methods,
597  * macs and compression methods.
598  *
599  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
600  **/
601 int
602 gnutls_priority_set(gnutls_session_t session, gnutls_priority_t priority)
603 {
604         if (priority == NULL) {
605                 gnutls_assert();
606                 return GNUTLS_E_NO_CIPHER_SUITES;
607         }
608
609         memcpy(&session->internals.priorities, priority,
610                sizeof(struct gnutls_priority_st));
611
612         /* set the current version to the first in the chain.
613          * This will be overridden later.
614          */
615         if (session->internals.priorities.protocol.algorithms > 0)
616                 _gnutls_set_current_version(session,
617                                             session->internals.priorities.
618                                             protocol.priority[0]);
619
620         if (session->internals.priorities.protocol.algorithms == 0 ||
621             session->internals.priorities.cipher.algorithms == 0 ||
622             session->internals.priorities.mac.algorithms == 0 ||
623             session->internals.priorities.kx.algorithms == 0 ||
624             session->internals.priorities.compression.algorithms == 0)
625                 return gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET);
626
627         return 0;
628 }
629
630
631 #define MAX_ELEMENTS 48
632
633 #define LEVEL_NONE "NONE"
634 #define LEVEL_NORMAL "NORMAL"
635 #define LEVEL_PFS "PFS"
636 #define LEVEL_PERFORMANCE "PERFORMANCE"
637 #define LEVEL_SECURE128 "SECURE128"
638 #define LEVEL_SECURE192 "SECURE192"
639 #define LEVEL_SECURE256 "SECURE256"
640 #define LEVEL_SUITEB128 "SUITEB128"
641 #define LEVEL_SUITEB192 "SUITEB192"
642 #define LEVEL_EXPORT "EXPORT"
643
644 static
645 int check_level(const char *level, gnutls_priority_t priority_cache,
646                 int add)
647 {
648         bulk_rmadd_func *func;
649
650         if (add)
651                 func = _add_priority;
652         else
653                 func = _set_priority;
654
655         if (strcasecmp(level, LEVEL_PERFORMANCE) == 0) {
656                 func(&priority_cache->cipher, cipher_priority_performance);
657                 func(&priority_cache->kx, kx_priority_performance);
658                 func(&priority_cache->mac, mac_priority_normal);
659                 func(&priority_cache->sign_algo, sign_priority_default);
660                 func(&priority_cache->supported_ecc, supported_ecc_normal);
661
662                 if (priority_cache->level == 0)
663                         priority_cache->level = GNUTLS_SEC_PARAM_VERY_WEAK;
664                 return 1;
665         } else if (strcasecmp(level, LEVEL_NORMAL) == 0) {
666                 func(&priority_cache->cipher, cipher_priority_normal);
667                 func(&priority_cache->kx, kx_priority_secure);
668                 func(&priority_cache->mac, mac_priority_normal);
669                 func(&priority_cache->sign_algo, sign_priority_default);
670                 func(&priority_cache->supported_ecc, supported_ecc_normal);
671
672                 if (priority_cache->level == 0)
673                         priority_cache->level = GNUTLS_SEC_PARAM_VERY_WEAK;
674                 return 1;
675         } else if (strcasecmp(level, LEVEL_PFS) == 0) {
676                 func(&priority_cache->cipher, cipher_priority_normal);
677                 func(&priority_cache->kx, kx_priority_pfs);
678                 func(&priority_cache->mac, mac_priority_normal);
679                 func(&priority_cache->sign_algo, sign_priority_default);
680                 func(&priority_cache->supported_ecc, supported_ecc_normal);
681
682                 if (priority_cache->level == 0)
683                         priority_cache->level = GNUTLS_SEC_PARAM_VERY_WEAK;
684                 return 1;
685         } else if (strcasecmp(level, LEVEL_SECURE256) == 0
686                    || strcasecmp(level, LEVEL_SECURE192) == 0) {
687                 func(&priority_cache->cipher, cipher_priority_secure192);
688                 func(&priority_cache->kx, kx_priority_secure);
689                 func(&priority_cache->mac, mac_priority_secure192);
690                 func(&priority_cache->sign_algo, sign_priority_secure192);
691                 func(&priority_cache->supported_ecc,
692                      supported_ecc_secure192);
693
694                 /* be conservative for now. Set the bits to correspond to 96-bit level */
695                 if (priority_cache->level == 0)
696                         priority_cache->level = GNUTLS_SEC_PARAM_LEGACY;
697                 return 1;
698         } else if (strcasecmp(level, LEVEL_SECURE128) == 0
699                    || strcasecmp(level, "SECURE") == 0) {
700                 func(&priority_cache->cipher, cipher_priority_secure128);
701                 func(&priority_cache->kx, kx_priority_secure);
702                 func(&priority_cache->mac, mac_priority_secure128);
703                 func(&priority_cache->sign_algo, sign_priority_secure128);
704                 func(&priority_cache->supported_ecc,
705                      supported_ecc_secure128);
706
707                 /* be conservative for now. Set the bits to correspond to an 72-bit level */
708                 if (priority_cache->level == 0)
709                         priority_cache->level = GNUTLS_SEC_PARAM_WEAK;
710                 return 1;
711         } else if (strcasecmp(level, LEVEL_SUITEB128) == 0) {
712                 func(&priority_cache->protocol, protocol_priority_suiteb);
713                 func(&priority_cache->cipher, cipher_priority_suiteb128);
714                 func(&priority_cache->kx, kx_priority_suiteb);
715                 func(&priority_cache->mac, mac_priority_suiteb128);
716                 func(&priority_cache->sign_algo, sign_priority_suiteb128);
717                 func(&priority_cache->supported_ecc,
718                      supported_ecc_suiteb128);
719
720                 if (priority_cache->level == 0)
721                         priority_cache->level = GNUTLS_SEC_PARAM_HIGH;
722                 return 1;
723         } else if (strcasecmp(level, LEVEL_SUITEB192) == 0) {
724                 func(&priority_cache->protocol, protocol_priority_suiteb);
725                 func(&priority_cache->cipher, cipher_priority_suiteb192);
726                 func(&priority_cache->kx, kx_priority_suiteb);
727                 func(&priority_cache->mac, mac_priority_suiteb192);
728                 func(&priority_cache->sign_algo, sign_priority_suiteb192);
729                 func(&priority_cache->supported_ecc,
730                      supported_ecc_suiteb192);
731
732                 if (priority_cache->level == 0)
733                         priority_cache->level = GNUTLS_SEC_PARAM_ULTRA;
734                 return 1;
735         } else if (strcasecmp(level, LEVEL_EXPORT) == 0) {
736                 func(&priority_cache->cipher, cipher_priority_performance);
737                 func(&priority_cache->kx, kx_priority_performance);
738                 func(&priority_cache->mac, mac_priority_secure128);
739                 func(&priority_cache->sign_algo, sign_priority_default);
740                 func(&priority_cache->supported_ecc, supported_ecc_normal);
741
742                 if (priority_cache->level == 0)
743                         priority_cache->level = GNUTLS_SEC_PARAM_EXPORT;
744                 return 1;
745         }
746         return 0;
747 }
748
749 /**
750  * gnutls_priority_init:
751  * @priority_cache: is a #gnutls_prioritity_t structure.
752  * @priorities: is a string describing priorities
753  * @err_pos: In case of an error this will have the position in the string the error occured
754  *
755  * Sets priorities for the ciphers, key exchange methods, macs and
756  * compression methods.
757  *
758  * The #priorities option allows you to specify a colon
759  * separated list of the cipher priorities to enable.
760  * Some keywords are defined to provide quick access
761  * to common preferences.
762  *
763  * Unless there is a special need, using "NORMAL" or "NORMAL:%COMPAT" for compatibility 
764  * is recommended.
765  *
766  * "PERFORMANCE" means all the "secure" ciphersuites are enabled,
767  * limited to 128 bit ciphers and sorted by terms of speed
768  * performance.
769  *
770  * "NORMAL" means all "secure" ciphersuites. The 256-bit ciphers are
771  * included as a fallback only.  The ciphers are sorted by security
772  * margin.
773  *
774  * "PFS" means all "secure" ciphersuites that support perfect forward secrecy. 
775  * The 256-bit ciphers are included as a fallback only.  
776  * The ciphers are sorted by security margin.
777  *
778  * "SECURE128" means all "secure" ciphersuites of security level 128-bit
779  * or more.
780  *
781  * "SECURE192" means all "secure" ciphersuites of security level 192-bit
782  * or more.
783  *
784  * "SUITEB128" means all the NSA SuiteB ciphersuites with security level
785  * of 128.
786  *
787  * "SUITEB192" means all the NSA SuiteB ciphersuites with security level
788  * of 192.
789  *
790  * "EXPORT" means all ciphersuites are enabled, including the
791  * low-security 40 bit ciphers.
792  *
793  * "NONE" means nothing is enabled.  This disables even protocols and
794  * compression methods.
795  *
796  * Special keywords are "!", "-" and "+".
797  * "!" or "-" appended with an algorithm will remove this algorithm.
798  * "+" appended with an algorithm will add this algorithm.
799  *
800  * Check the GnuTLS manual section "Priority strings" for detailed
801  * information.
802  *
803  * Examples:
804  *
805  * "NONE:+VERS-TLS-ALL:+MAC-ALL:+RSA:+AES-128-CBC:+SIGN-ALL:+COMP-NULL"
806  *
807  * "NORMAL:-ARCFOUR-128" means normal ciphers except for ARCFOUR-128.
808  *
809  * "SECURE128:-VERS-SSL3.0:+COMP-DEFLATE" means that only secure ciphers are
810  * enabled, SSL3.0 is disabled, and libz compression enabled.
811  *
812  * "NONE:+VERS-TLS-ALL:+AES-128-CBC:+RSA:+SHA1:+COMP-NULL:+SIGN-RSA-SHA1", 
813  *
814  * "NONE:+VERS-TLS-ALL:+AES-128-CBC:+ECDHE-RSA:+SHA1:+COMP-NULL:+SIGN-RSA-SHA1:+CURVE-SECP256R1", 
815  *
816  * "SECURE256:+SECURE128",
817  *
818  * Note that "NORMAL:%COMPAT" is the most compatible mode.
819  *
820  * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
821  * %GNUTLS_E_SUCCESS on success, or an error code.
822  **/
823 int
824 gnutls_priority_init(gnutls_priority_t * priority_cache,
825                      const char *priorities, const char **err_pos)
826 {
827         char *broken_list[MAX_ELEMENTS];
828         int broken_list_size = 0, i = 0, j;
829         char *darg = NULL;
830         int algo;
831         rmadd_func *fn;
832         bulk_rmadd_func *bulk_fn;
833
834         *priority_cache =
835             gnutls_calloc(1, sizeof(struct gnutls_priority_st));
836         if (*priority_cache == NULL) {
837                 gnutls_assert();
838                 return GNUTLS_E_MEMORY_ERROR;
839         }
840
841         if (err_pos)
842                 *err_pos = priorities;
843
844         /* for now unsafe renegotiation is default on everyone. To be removed
845          * when we make it the default.
846          */
847         (*priority_cache)->sr = SR_PARTIAL;
848         (*priority_cache)->ssl3_record_version = 1;
849
850
851         (*priority_cache)->max_empty_records = DEFAULT_MAX_EMPTY_RECORDS;
852
853         if (priorities == NULL)
854                 priorities = LEVEL_NORMAL;
855
856         darg = gnutls_strdup(priorities);
857         if (darg == NULL) {
858                 gnutls_assert();
859                 goto error;
860         }
861
862         break_comma_list(darg, broken_list, &broken_list_size,
863                          MAX_ELEMENTS, ':');
864         /* This is our default set of protocol version, certificate types and
865          * compression methods.
866          */
867         if (strcasecmp(broken_list[0], LEVEL_NONE) != 0) {
868                 _set_priority(&(*priority_cache)->protocol,
869                               protocol_priority);
870                 _set_priority(&(*priority_cache)->compression,
871                               comp_priority);
872                 _set_priority(&(*priority_cache)->cert_type,
873                               cert_type_priority_default);
874                 _set_priority(&(*priority_cache)->sign_algo,
875                               sign_priority_default);
876                 _set_priority(&(*priority_cache)->supported_ecc,
877                               supported_ecc_normal);
878                 i = 0;
879         } else {
880                 i = 1;
881         }
882
883         for (; i < broken_list_size; i++) {
884                 if (check_level(broken_list[i], *priority_cache, 0) != 0) {
885                         continue;
886                 } else if (broken_list[i][0] == '!'
887                            || broken_list[i][0] == '+'
888                            || broken_list[i][0] == '-') {
889                         if (broken_list[i][0] == '+') {
890                                 fn = prio_add;
891                                 bulk_fn = _add_priority;
892                         } else {
893                                 fn = prio_remove;
894                                 bulk_fn = _clear_priorities;
895                         }
896
897                         if (broken_list[i][0] == '+'
898                             && check_level(&broken_list[i][1],
899                                            *priority_cache, 1) != 0) {
900                                 continue;
901                         } else if ((algo =
902                                     gnutls_mac_get_id(&broken_list[i][1]))
903                                    != GNUTLS_MAC_UNKNOWN)
904                                 fn(&(*priority_cache)->mac, algo);
905                         else if ((algo =
906                                   gnutls_cipher_get_id(&broken_list[i][1]))
907                                  != GNUTLS_CIPHER_UNKNOWN)
908                                 fn(&(*priority_cache)->cipher, algo);
909                         else if ((algo =
910                                   gnutls_kx_get_id(&broken_list[i][1])) !=
911                                  GNUTLS_KX_UNKNOWN)
912                                 fn(&(*priority_cache)->kx, algo);
913                         else if (strncasecmp
914                                  (&broken_list[i][1], "VERS-", 5) == 0) {
915                                 if (strncasecmp
916                                     (&broken_list[i][1], "VERS-TLS-ALL",
917                                      12) == 0) {
918                                         bulk_fn(&(*priority_cache)->
919                                                 protocol,
920                                                 protocol_priority);
921                                 } else
922                                     if (strncasecmp
923                                         (&broken_list[i][1],
924                                          "VERS-DTLS-ALL", 13) == 0) {
925                                         bulk_fn(&(*priority_cache)->
926                                                 protocol,
927                                                 dtls_protocol_priority);
928                                 } else {
929                                         if ((algo =
930                                              gnutls_protocol_get_id
931                                              (&broken_list[i][6])) !=
932                                             GNUTLS_VERSION_UNKNOWN)
933                                                 fn(&(*priority_cache)->
934                                                    protocol, algo);
935                                         else
936                                                 goto error;
937
938                                 }
939                         } /* now check if the element is something like -ALGO */
940                         else if (strncasecmp
941                                  (&broken_list[i][1], "COMP-", 5) == 0) {
942                                 if (strncasecmp
943                                     (&broken_list[i][1], "COMP-ALL",
944                                      8) == 0) {
945                                         bulk_fn(&(*priority_cache)->
946                                                 compression,
947                                                 comp_priority);
948                                 } else {
949                                         if ((algo =
950                                              gnutls_compression_get_id
951                                              (&broken_list[i][6])) !=
952                                             GNUTLS_COMP_UNKNOWN)
953                                                 fn(&(*priority_cache)->
954                                                    compression, algo);
955                                         else
956                                                 goto error;
957                                 }
958                         } /* now check if the element is something like -ALGO */
959                         else if (strncasecmp
960                                  (&broken_list[i][1], "CURVE-", 6) == 0) {
961                                 if (strncasecmp
962                                     (&broken_list[i][1], "CURVE-ALL",
963                                      9) == 0) {
964                                         bulk_fn(&(*priority_cache)->
965                                                 supported_ecc,
966                                                 supported_ecc_normal);
967                                 } else {
968                                         if ((algo =
969                                              _gnutls_ecc_curve_get_id
970                                              (&broken_list[i][7])) !=
971                                             GNUTLS_ECC_CURVE_INVALID)
972                                                 fn(&(*priority_cache)->
973                                                    supported_ecc, algo);
974                                         else
975                                                 goto error;
976                                 }
977                         } /* now check if the element is something like -ALGO */
978                         else if (strncasecmp
979                                  (&broken_list[i][1], "CTYPE-", 6) == 0) {
980                                 if (strncasecmp
981                                     (&broken_list[i][1], "CTYPE-ALL",
982                                      9) == 0) {
983                                         bulk_fn(&(*priority_cache)->
984                                                 cert_type,
985                                                 cert_type_priority_all);
986                                 } else {
987                                         if ((algo =
988                                              gnutls_certificate_type_get_id
989                                              (&broken_list[i][7])) !=
990                                             GNUTLS_CRT_UNKNOWN)
991                                                 fn(&(*priority_cache)->
992                                                    cert_type, algo);
993                                         else
994                                                 goto error;
995                                 }
996                         } /* now check if the element is something like -ALGO */
997                         else if (strncasecmp
998                                  (&broken_list[i][1], "SIGN-", 5) == 0) {
999                                 if (strncasecmp
1000                                     (&broken_list[i][1], "SIGN-ALL",
1001                                      8) == 0) {
1002                                         bulk_fn(&(*priority_cache)->
1003                                                 sign_algo,
1004                                                 sign_priority_default);
1005                                 } else {
1006                                         if ((algo =
1007                                              gnutls_sign_get_id
1008                                              (&broken_list[i][6])) !=
1009                                             GNUTLS_SIGN_UNKNOWN)
1010                                                 fn(&(*priority_cache)->
1011                                                    sign_algo, algo);
1012                                         else
1013                                                 goto error;
1014                                 }
1015                         } else
1016                             if (strncasecmp
1017                                 (&broken_list[i][1], "MAC-ALL", 7) == 0) {
1018                                 bulk_fn(&(*priority_cache)->mac,
1019                                         mac_priority_normal);
1020                         } else
1021                             if (strncasecmp
1022                                 (&broken_list[i][1], "CIPHER-ALL",
1023                                  10) == 0) {
1024                                 bulk_fn(&(*priority_cache)->cipher,
1025                                         cipher_priority_normal);
1026                         } else
1027                             if (strncasecmp
1028                                 (&broken_list[i][1], "KX-ALL", 6) == 0) {
1029                                 bulk_fn(&(*priority_cache)->kx,
1030                                         kx_priority_secure);
1031                         } else
1032                                 goto error;
1033                 } else if (broken_list[i][0] == '%') {
1034                         if (strcasecmp(&broken_list[i][1], "COMPAT") == 0) {
1035                                 ENABLE_COMPAT((*priority_cache));
1036                         } else
1037                           if (strcasecmp(&broken_list[i][1], "DUMBFW") == 0) {
1038                                 (*priority_cache)->dumbfw = 1;
1039                         } else
1040                             if (strcasecmp
1041                                 (&broken_list[i][1],
1042                                  "NO_EXTENSIONS") == 0) {
1043                                 (*priority_cache)->no_extensions = 1;
1044                         } else
1045                             if (strcasecmp
1046                                 (&broken_list[i][1],
1047                                  "STATELESS_COMPRESSION") == 0) {
1048                                 (*priority_cache)->stateless_compression =
1049                                     1;
1050                         } else
1051                             if (strcasecmp
1052                                 (&broken_list[i][1],
1053                                  "VERIFY_ALLOW_SIGN_RSA_MD5") == 0) {
1054                                 prio_add(&(*priority_cache)->sign_algo,
1055                                          GNUTLS_SIGN_RSA_MD5);
1056                                 (*priority_cache)->
1057                                     additional_verify_flags |=
1058                                     GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5;
1059                         } else
1060                             if (strcasecmp
1061                                 (&broken_list[i][1],
1062                                  "VERIFY_DISABLE_CRL_CHECKS") == 0) {
1063                                 (*priority_cache)->
1064                                     additional_verify_flags |=
1065                                     GNUTLS_VERIFY_DISABLE_CRL_CHECKS;
1066                         } else
1067                             if (strcasecmp
1068                                 (&broken_list[i][1],
1069                                  "SSL3_RECORD_VERSION") == 0)
1070                                 (*priority_cache)->ssl3_record_version = 1;
1071                         else if (strcasecmp(&broken_list[i][1],
1072                                             "LATEST_RECORD_VERSION") == 0)
1073                                 (*priority_cache)->ssl3_record_version = 0;
1074                         else if (strcasecmp(&broken_list[i][1],
1075                                             "VERIFY_ALLOW_X509_V1_CA_CRT")
1076                                  == 0)
1077                                 (*priority_cache)->
1078                                     additional_verify_flags |=
1079                                     GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT;
1080                         else if (strcasecmp
1081                                  (&broken_list[i][1],
1082                                   "UNSAFE_RENEGOTIATION") == 0) {
1083                                 (*priority_cache)->sr = SR_UNSAFE;
1084                         } else
1085                             if (strcasecmp
1086                                 (&broken_list[i][1],
1087                                  "SAFE_RENEGOTIATION") == 0) {
1088                                 (*priority_cache)->sr = SR_SAFE;
1089                         } else if (strcasecmp(&broken_list[i][1],
1090                                               "PARTIAL_RENEGOTIATION") ==
1091                                    0) {
1092                                 (*priority_cache)->sr = SR_PARTIAL;
1093                         } else if (strcasecmp(&broken_list[i][1],
1094                                               "DISABLE_SAFE_RENEGOTIATION")
1095                                    == 0) {
1096                                 (*priority_cache)->sr = SR_DISABLED;
1097                         } else if (strcasecmp(&broken_list[i][1],
1098                                               "SERVER_PRECEDENCE") == 0) {
1099                                 (*priority_cache)->server_precedence = 1;
1100                         } else if (strcasecmp(&broken_list[i][1],
1101                                               "NEW_PADDING") == 0) {
1102                                 (*priority_cache)->new_record_padding = 1;
1103                         } else
1104                                 goto error;
1105                 } else
1106                         goto error;
1107         }
1108
1109         gnutls_free(darg);
1110         return 0;
1111
1112       error:
1113         if (err_pos != NULL && i < broken_list_size) {
1114                 *err_pos = priorities;
1115                 for (j = 0; j < i; j++) {
1116                         (*err_pos) += strlen(broken_list[j]) + 1;
1117                 }
1118         }
1119         gnutls_free(darg);
1120         gnutls_free(*priority_cache);
1121
1122         return GNUTLS_E_INVALID_REQUEST;
1123
1124 }
1125
1126 /**
1127  * gnutls_priority_deinit:
1128  * @priority_cache: is a #gnutls_prioritity_t structure.
1129  *
1130  * Deinitializes the priority cache.
1131  **/
1132 void gnutls_priority_deinit(gnutls_priority_t priority_cache)
1133 {
1134         gnutls_free(priority_cache);
1135 }
1136
1137
1138 /**
1139  * gnutls_priority_set_direct:
1140  * @session: is a #gnutls_session_t structure.
1141  * @priorities: is a string describing priorities
1142  * @err_pos: In case of an error this will have the position in the string the error occured
1143  *
1144  * Sets the priorities to use on the ciphers, key exchange methods,
1145  * macs and compression methods.  This function avoids keeping a
1146  * priority cache and is used to directly set string priorities to a
1147  * TLS session.  For documentation check the gnutls_priority_init().
1148  *
1149  * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
1150  * %GNUTLS_E_SUCCESS on success, or an error code.
1151  **/
1152 int
1153 gnutls_priority_set_direct(gnutls_session_t session,
1154                            const char *priorities, const char **err_pos)
1155 {
1156         gnutls_priority_t prio;
1157         int ret;
1158
1159         ret = gnutls_priority_init(&prio, priorities, err_pos);
1160         if (ret < 0) {
1161                 gnutls_assert();
1162                 return ret;
1163         }
1164
1165         ret = gnutls_priority_set(session, prio);
1166         if (ret < 0) {
1167                 gnutls_assert();
1168                 return ret;
1169         }
1170
1171         gnutls_priority_deinit(prio);
1172
1173         return 0;
1174 }
1175
1176 /* Breaks a list of "xxx", "yyy", to a character array, of
1177  * MAX_COMMA_SEP_ELEMENTS size; Note that the given string is modified.
1178   */
1179 static void
1180 break_comma_list(char *etag,
1181                  char **broken_etag, int *elements, int max_elements,
1182                  char sep)
1183 {
1184         char *p = etag;
1185         if (sep == 0)
1186                 sep = ',';
1187
1188         *elements = 0;
1189
1190         do {
1191                 broken_etag[*elements] = p;
1192
1193                 (*elements)++;
1194
1195                 p = strchr(p, sep);
1196                 if (p) {
1197                         *p = 0;
1198                         p++;    /* move to next entry and skip white
1199                                  * space.
1200                                  */
1201                         while (*p == ' ')
1202                                 p++;
1203                 }
1204         }
1205         while (p != NULL && *elements < max_elements);
1206 }
1207
1208 /**
1209  * gnutls_set_default_priority:
1210  * @session: is a #gnutls_session_t structure.
1211  *
1212  * Sets some default priority on the ciphers, key exchange methods,
1213  * macs and compression methods.
1214  *
1215  * This is the same as calling:
1216  *
1217  * gnutls_priority_set_direct (session, "NORMAL", NULL);
1218  *
1219  * This function is kept around for backwards compatibility, but
1220  * because of its wide use it is still fully supported.  If you wish
1221  * to allow users to provide a string that specify which ciphers to
1222  * use (which is recommended), you should use
1223  * gnutls_priority_set_direct() or gnutls_priority_set() instead.
1224  *
1225  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
1226  **/
1227 int gnutls_set_default_priority(gnutls_session_t session)
1228 {
1229         return gnutls_priority_set_direct(session, "NORMAL", NULL);
1230 }
1231
1232 /**
1233  * gnutls_set_default_export_priority:
1234  * @session: is a #gnutls_session_t structure.
1235  *
1236  * Sets some default priority on the ciphers, key exchange methods, macs
1237  * and compression methods.  This function also includes weak algorithms.
1238  *
1239  * This is the same as calling:
1240  *
1241  * gnutls_priority_set_direct (session, "EXPORT", NULL);
1242  *
1243  * This function is kept around for backwards compatibility, but
1244  * because of its wide use it is still fully supported.  If you wish
1245  * to allow users to provide a string that specify which ciphers to
1246  * use (which is recommended), you should use
1247  * gnutls_priority_set_direct() or gnutls_priority_set() instead.
1248  *
1249  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
1250  **/
1251 int gnutls_set_default_export_priority(gnutls_session_t session)
1252 {
1253         return gnutls_priority_set_direct(session, "EXPORT", NULL);
1254 }
1255
1256 /**
1257  * gnutls_priority_ecc_curve_list:
1258  * @pcache: is a #gnutls_prioritity_t structure.
1259  * @list: will point to an integer list
1260  *
1261  * Get a list of available elliptic curves in the priority
1262  * structure. 
1263  *
1264  * Returns: the number of curves, or an error code.
1265  * Since: 3.0
1266  **/
1267 int
1268 gnutls_priority_ecc_curve_list(gnutls_priority_t pcache,
1269                                const unsigned int **list)
1270 {
1271         if (pcache->supported_ecc.algorithms == 0)
1272                 return 0;
1273
1274         *list = pcache->supported_ecc.priority;
1275         return pcache->supported_ecc.algorithms;
1276 }
1277
1278 /**
1279  * gnutls_priority_kx_list:
1280  * @pcache: is a #gnutls_prioritity_t structure.
1281  * @list: will point to an integer list
1282  *
1283  * Get a list of available key exchange methods in the priority
1284  * structure. 
1285  *
1286  * Returns: the number of curves, or an error code.
1287  * Since: 3.2.3
1288  **/
1289 int
1290 gnutls_priority_kx_list(gnutls_priority_t pcache,
1291                         const unsigned int **list)
1292 {
1293         if (pcache->kx.algorithms == 0)
1294                 return 0;
1295
1296         *list = pcache->kx.priority;
1297         return pcache->kx.algorithms;
1298 }
1299
1300 /**
1301  * gnutls_priority_cipher_list:
1302  * @pcache: is a #gnutls_prioritity_t structure.
1303  * @list: will point to an integer list
1304  *
1305  * Get a list of available ciphers in the priority
1306  * structure. 
1307  *
1308  * Returns: the number of curves, or an error code.
1309  * Since: 3.2.3
1310  **/
1311 int
1312 gnutls_priority_cipher_list(gnutls_priority_t pcache,
1313                             const unsigned int **list)
1314 {
1315         if (pcache->cipher.algorithms == 0)
1316                 return 0;
1317
1318         *list = pcache->cipher.priority;
1319         return pcache->cipher.algorithms;
1320 }
1321
1322 /**
1323  * gnutls_priority_mac_list:
1324  * @pcache: is a #gnutls_prioritity_t structure.
1325  * @list: will point to an integer list
1326  *
1327  * Get a list of available MAC algorithms in the priority
1328  * structure. 
1329  *
1330  * Returns: the number of curves, or an error code.
1331  * Since: 3.2.3
1332  **/
1333 int
1334 gnutls_priority_mac_list(gnutls_priority_t pcache,
1335                          const unsigned int **list)
1336 {
1337         if (pcache->mac.algorithms == 0)
1338                 return 0;
1339
1340         *list = pcache->mac.priority;
1341         return pcache->mac.algorithms;
1342 }
1343
1344 /**
1345  * gnutls_priority_compression_list:
1346  * @pcache: is a #gnutls_prioritity_t structure.
1347  * @list: will point to an integer list
1348  *
1349  * Get a list of available compression method in the priority
1350  * structure. 
1351  *
1352  * Returns: the number of methods, or an error code.
1353  * Since: 3.0
1354  **/
1355 int
1356 gnutls_priority_compression_list(gnutls_priority_t pcache,
1357                                  const unsigned int **list)
1358 {
1359         if (pcache->compression.algorithms == 0)
1360                 return 0;
1361
1362         *list = pcache->compression.priority;
1363         return pcache->compression.algorithms;
1364 }
1365
1366 /**
1367  * gnutls_priority_protocol_list:
1368  * @pcache: is a #gnutls_prioritity_t structure.
1369  * @list: will point to an integer list
1370  *
1371  * Get a list of available TLS version numbers in the priority
1372  * structure. 
1373  *
1374  * Returns: the number of protocols, or an error code.
1375  * Since: 3.0
1376  **/
1377 int
1378 gnutls_priority_protocol_list(gnutls_priority_t pcache,
1379                               const unsigned int **list)
1380 {
1381         if (pcache->protocol.algorithms == 0)
1382                 return 0;
1383
1384         *list = pcache->protocol.priority;
1385         return pcache->protocol.algorithms;
1386 }
1387
1388 /**
1389  * gnutls_priority_sign_list:
1390  * @pcache: is a #gnutls_prioritity_t structure.
1391  * @list: will point to an integer list
1392  *
1393  * Get a list of available signature algorithms in the priority
1394  * structure. 
1395  *
1396  * Returns: the number of algorithms, or an error code.
1397  * Since: 3.0
1398  **/
1399 int
1400 gnutls_priority_sign_list(gnutls_priority_t pcache,
1401                           const unsigned int **list)
1402 {
1403         if (pcache->sign_algo.algorithms == 0)
1404                 return 0;
1405
1406         *list = pcache->sign_algo.priority;
1407         return pcache->sign_algo.algorithms;
1408 }
1409
1410 /**
1411  * gnutls_priority_certificate_type_list:
1412  * @pcache: is a #gnutls_prioritity_t structure.
1413  * @list: will point to an integer list
1414  *
1415  * Get a list of available certificate types in the priority
1416  * structure. 
1417  *
1418  * Returns: the number of certificate types, or an error code.
1419  * Since: 3.0
1420  **/
1421 int
1422 gnutls_priority_certificate_type_list(gnutls_priority_t pcache,
1423                                       const unsigned int **list)
1424 {
1425         if (pcache->cert_type.algorithms == 0)
1426                 return 0;
1427
1428         *list = pcache->cert_type.priority;
1429         return pcache->cert_type.algorithms;
1430 }