remove unnecessary assert
[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 #include <gnutls/x509.h>
31 #include <c-ctype.h>
32 #include <gnutls_extensions.h>
33
34 #define MAX_ELEMENTS 64
35
36 static void prio_remove(priority_st * priority_list, unsigned int algo);
37 static void prio_add(priority_st * priority_list, unsigned int algo);
38 static void
39 break_list(char *etag,
40                  char *broken_etag[MAX_ELEMENTS], int *size);
41
42 typedef void (bulk_rmadd_func) (priority_st * priority_list, const int *);
43
44 inline static void _set_priority(priority_st * st, const int *list)
45 {
46         int num = 0, i;
47
48         while (list[num] != 0)
49                 num++;
50         if (num > MAX_ALGOS)
51                 num = MAX_ALGOS;
52         st->algorithms = num;
53
54         for (i = 0; i < num; i++) {
55                 st->priority[i] = list[i];
56         }
57
58         return;
59 }
60
61 inline static void _add_priority(priority_st * st, const int *list)
62 {
63         int num, i, j, init;
64
65         init = i = st->algorithms;
66
67         for (num = 0; list[num] != 0; ++num) {
68                 if (i + 1 > MAX_ALGOS) {
69                         return;
70                 }
71
72                 for (j = 0; j < init; j++) {
73                         if (st->priority[j] == (unsigned) list[num]) {
74                                 break;
75                         }
76                 }
77
78                 if (j == init) {
79                         st->priority[i++] = list[num];
80                         st->algorithms++;
81                 }
82         }
83
84         return;
85 }
86
87 static void _clear_priorities(priority_st * st, const int *list)
88 {
89         memset(st, 0, sizeof(*st));
90 }
91
92 static void _clear_given_priorities(priority_st * st, const int *list)
93 {
94         unsigned i;
95
96         for (i=0;list[i]!=0;i++) {
97                 prio_remove(st, list[i]);
98         }
99 }
100
101 static const int _supported_ecc_normal[] = {
102         GNUTLS_ECC_CURVE_SECP256R1,
103         GNUTLS_ECC_CURVE_SECP384R1,
104         GNUTLS_ECC_CURVE_SECP521R1,
105 #ifdef ENABLE_NON_SUITEB_CURVES
106         GNUTLS_ECC_CURVE_SECP224R1,
107         GNUTLS_ECC_CURVE_SECP192R1,
108 #endif
109         0
110 };
111 static const int* supported_ecc_normal = _supported_ecc_normal;
112
113 static const int _supported_ecc_secure128[] = {
114         GNUTLS_ECC_CURVE_SECP256R1,
115         GNUTLS_ECC_CURVE_SECP384R1,
116         GNUTLS_ECC_CURVE_SECP521R1,
117         0
118 };
119 static const int* supported_ecc_secure128 = _supported_ecc_secure128;
120
121 static const int _supported_ecc_suiteb128[] = {
122         GNUTLS_ECC_CURVE_SECP256R1,
123         GNUTLS_ECC_CURVE_SECP384R1,
124         0
125 };
126 static const int* supported_ecc_suiteb128 = _supported_ecc_suiteb128;
127
128 static const int _supported_ecc_suiteb192[] = {
129         GNUTLS_ECC_CURVE_SECP384R1,
130         0
131 };
132 static const int* supported_ecc_suiteb192 = _supported_ecc_suiteb192;
133
134 static const int _supported_ecc_secure192[] = {
135         GNUTLS_ECC_CURVE_SECP384R1,
136         GNUTLS_ECC_CURVE_SECP521R1,
137         0
138 };
139 static const int* supported_ecc_secure192 = _supported_ecc_secure192;
140
141 static const int protocol_priority[] = {
142         GNUTLS_TLS1_2,
143         GNUTLS_TLS1_1,
144         GNUTLS_TLS1_0,
145         GNUTLS_DTLS1_2,
146         GNUTLS_DTLS1_0,
147         0
148 };
149
150 static const int stream_protocol_priority[] = {
151         GNUTLS_TLS1_2,
152         GNUTLS_TLS1_1,
153         GNUTLS_TLS1_0,
154         0
155 };
156
157 static const int dgram_protocol_priority[] = {
158         GNUTLS_DTLS1_2,
159         GNUTLS_DTLS1_0,
160         GNUTLS_DTLS0_9,
161         0
162 };
163
164 static const int dtls_protocol_priority[] = {
165         GNUTLS_DTLS1_2,
166         GNUTLS_DTLS1_0,
167         0
168 };
169
170 static const int _protocol_priority_suiteb[] = {
171         GNUTLS_TLS1_2,
172         0
173 };
174 static const int* protocol_priority_suiteb = _protocol_priority_suiteb;
175
176 static const int _kx_priority_performance[] = {
177         GNUTLS_KX_RSA,
178 #ifdef ENABLE_ECDHE
179         GNUTLS_KX_ECDHE_ECDSA,
180         GNUTLS_KX_ECDHE_RSA,
181 #endif
182 #ifdef ENABLE_DHE
183         GNUTLS_KX_DHE_RSA,
184         GNUTLS_KX_DHE_DSS,
185 #endif
186         0
187 };
188 static const int* kx_priority_performance = _kx_priority_performance;
189
190 static const int _kx_priority_pfs[] = {
191 #ifdef ENABLE_ECDHE
192         GNUTLS_KX_ECDHE_ECDSA,
193         GNUTLS_KX_ECDHE_RSA,
194 #endif
195 #ifdef ENABLE_DHE
196         GNUTLS_KX_DHE_RSA,
197         GNUTLS_KX_DHE_DSS,
198 #endif
199         0
200 };
201 static const int* kx_priority_pfs = _kx_priority_pfs;
202
203 static const int _kx_priority_suiteb[] = {
204         GNUTLS_KX_ECDHE_ECDSA,
205         0
206 };
207 static const int* kx_priority_suiteb = _kx_priority_suiteb;
208
209 static const int _kx_priority_secure[] = {
210         /* The ciphersuites that offer forward secrecy take
211          * precedence
212          */
213 #ifdef ENABLE_ECDHE
214         GNUTLS_KX_ECDHE_ECDSA,
215         GNUTLS_KX_ECDHE_RSA,
216 #endif
217         GNUTLS_KX_RSA,
218         /* KX-RSA is now ahead of DHE-RSA and DHE-DSS due to the compatibility
219          * issues the DHE ciphersuites have. That is, one cannot enforce a specific
220          * security level without dropping the connection. 
221          */
222 #ifdef ENABLE_DHE
223         GNUTLS_KX_DHE_RSA,
224         GNUTLS_KX_DHE_DSS,
225 #endif
226         /* GNUTLS_KX_ANON_DH: Man-in-the-middle prone, don't add!
227          */
228         0
229 };
230 static const int* kx_priority_secure = _kx_priority_secure;
231
232 static const int _cipher_priority_performance_default[] = {
233         GNUTLS_CIPHER_AES_128_GCM,
234         GNUTLS_CIPHER_AES_256_GCM,
235         GNUTLS_CIPHER_CAMELLIA_128_GCM,
236         GNUTLS_CIPHER_CAMELLIA_256_GCM,
237         GNUTLS_CIPHER_AES_128_CBC,
238         GNUTLS_CIPHER_AES_256_CBC,
239         GNUTLS_CIPHER_CAMELLIA_128_CBC,
240         GNUTLS_CIPHER_CAMELLIA_256_CBC,
241         GNUTLS_CIPHER_AES_128_CCM,
242         GNUTLS_CIPHER_AES_256_CCM,
243         GNUTLS_CIPHER_3DES_CBC,
244         0
245 };
246
247 /* If GCM and AES acceleration is available then prefer
248  * them over anything else.
249  */
250 static const int _cipher_priority_normal_default[] = {
251         GNUTLS_CIPHER_AES_128_GCM,
252         GNUTLS_CIPHER_AES_256_GCM,
253         GNUTLS_CIPHER_CAMELLIA_128_GCM,
254         GNUTLS_CIPHER_CAMELLIA_256_GCM,
255         GNUTLS_CIPHER_AES_128_CBC,
256         GNUTLS_CIPHER_AES_256_CBC,
257         GNUTLS_CIPHER_CAMELLIA_128_CBC,
258         GNUTLS_CIPHER_CAMELLIA_256_CBC,
259         GNUTLS_CIPHER_AES_128_CCM,
260         GNUTLS_CIPHER_AES_256_CCM,
261         GNUTLS_CIPHER_3DES_CBC,
262         0
263 };
264
265 static const int cipher_priority_performance_fips[] = {
266         GNUTLS_CIPHER_AES_128_GCM,
267         GNUTLS_CIPHER_AES_256_GCM,
268         GNUTLS_CIPHER_AES_128_CBC,
269         GNUTLS_CIPHER_AES_256_CBC,
270         GNUTLS_CIPHER_AES_128_CCM,
271         GNUTLS_CIPHER_AES_256_CCM,
272         GNUTLS_CIPHER_3DES_CBC,
273         0
274 };
275
276 static const int cipher_priority_normal_fips[] = {
277         GNUTLS_CIPHER_AES_128_GCM,
278         GNUTLS_CIPHER_AES_256_GCM,
279         GNUTLS_CIPHER_AES_128_CBC,
280         GNUTLS_CIPHER_AES_256_CBC,
281         GNUTLS_CIPHER_AES_128_CCM,
282         GNUTLS_CIPHER_AES_256_CCM,
283         GNUTLS_CIPHER_3DES_CBC,
284         0
285 };
286
287
288 static const int _cipher_priority_suiteb128[] = {
289         GNUTLS_CIPHER_AES_128_GCM,
290         GNUTLS_CIPHER_AES_256_GCM,
291         0
292 };
293 static const int* cipher_priority_suiteb128 = _cipher_priority_suiteb128;
294
295 static const int _cipher_priority_suiteb192[] = {
296         GNUTLS_CIPHER_AES_256_GCM,
297         0
298 };
299 static const int* cipher_priority_suiteb192 = _cipher_priority_suiteb192;
300
301
302 static const int _cipher_priority_secure128[] = {
303         GNUTLS_CIPHER_AES_128_GCM,
304         GNUTLS_CIPHER_CAMELLIA_128_GCM,
305
306         GNUTLS_CIPHER_AES_256_GCM,
307         GNUTLS_CIPHER_CAMELLIA_256_GCM,
308
309         GNUTLS_CIPHER_AES_128_CBC,
310         GNUTLS_CIPHER_CAMELLIA_128_CBC,
311         GNUTLS_CIPHER_AES_256_CBC,
312         GNUTLS_CIPHER_CAMELLIA_256_CBC,
313
314         GNUTLS_CIPHER_AES_128_CCM,
315         GNUTLS_CIPHER_AES_256_CCM,
316         0
317 };
318 static const int *cipher_priority_secure128 = _cipher_priority_secure128;
319
320
321 static const int _cipher_priority_secure192[] = {
322         GNUTLS_CIPHER_AES_256_GCM,
323         GNUTLS_CIPHER_CAMELLIA_256_GCM,
324         GNUTLS_CIPHER_AES_256_CBC,
325         GNUTLS_CIPHER_CAMELLIA_256_CBC,
326         GNUTLS_CIPHER_AES_256_CCM,
327         0
328 };
329 static const int* cipher_priority_secure192 = _cipher_priority_secure192;
330
331 static const int comp_priority[] = {
332         /* compression should be explicitly requested to be enabled */
333         GNUTLS_COMP_NULL,
334         0
335 };
336
337 static const int _sign_priority_default[] = {
338         GNUTLS_SIGN_RSA_SHA256,
339         GNUTLS_SIGN_DSA_SHA256,
340         GNUTLS_SIGN_ECDSA_SHA256,
341
342         GNUTLS_SIGN_RSA_SHA384,
343         GNUTLS_SIGN_ECDSA_SHA384,
344
345         GNUTLS_SIGN_RSA_SHA512,
346         GNUTLS_SIGN_ECDSA_SHA512,
347
348         GNUTLS_SIGN_RSA_SHA224,
349         GNUTLS_SIGN_DSA_SHA224,
350         GNUTLS_SIGN_ECDSA_SHA224,
351
352         GNUTLS_SIGN_RSA_SHA1,
353         GNUTLS_SIGN_DSA_SHA1,
354         GNUTLS_SIGN_ECDSA_SHA1,
355         0
356 };
357 static const int* sign_priority_default = _sign_priority_default;
358
359 static const int _sign_priority_suiteb128[] = {
360         GNUTLS_SIGN_ECDSA_SHA256,
361         GNUTLS_SIGN_ECDSA_SHA384,
362         0
363 };
364 static const int* sign_priority_suiteb128 = _sign_priority_suiteb128;
365
366 static const int _sign_priority_suiteb192[] = {
367         GNUTLS_SIGN_ECDSA_SHA384,
368         0
369 };
370 static const int* sign_priority_suiteb192 = _sign_priority_suiteb192;
371
372 static const int _sign_priority_secure128[] = {
373         GNUTLS_SIGN_RSA_SHA256,
374         GNUTLS_SIGN_DSA_SHA256,
375         GNUTLS_SIGN_ECDSA_SHA256,
376         GNUTLS_SIGN_RSA_SHA384,
377         GNUTLS_SIGN_ECDSA_SHA384,
378         GNUTLS_SIGN_RSA_SHA512,
379         GNUTLS_SIGN_ECDSA_SHA512,
380         0
381 };
382 static const int* sign_priority_secure128 = _sign_priority_secure128;
383
384 static const int _sign_priority_secure192[] = {
385         GNUTLS_SIGN_RSA_SHA384,
386         GNUTLS_SIGN_ECDSA_SHA384,
387         GNUTLS_SIGN_RSA_SHA512,
388         GNUTLS_SIGN_ECDSA_SHA512,
389         0
390 };
391 static const int* sign_priority_secure192 = _sign_priority_secure192;
392
393 static const int mac_priority_normal_default[] = {
394         GNUTLS_MAC_SHA1,
395         GNUTLS_MAC_SHA256,
396         GNUTLS_MAC_SHA384,
397         GNUTLS_MAC_AEAD,
398         GNUTLS_MAC_MD5,
399         0
400 };
401
402 static const int mac_priority_normal_fips[] = {
403         GNUTLS_MAC_SHA1,
404         GNUTLS_MAC_SHA256,
405         GNUTLS_MAC_SHA384,
406         GNUTLS_MAC_AEAD,
407         0
408 };
409
410 static const int *cipher_priority_performance = _cipher_priority_performance_default;
411 static const int *cipher_priority_normal = _cipher_priority_normal_default;
412 static const int *mac_priority_normal = mac_priority_normal_default;
413
414 /* if called with replace the default priorities with the FIPS140 ones */
415 void _gnutls_priority_update_fips(void)
416 {
417         cipher_priority_performance = cipher_priority_performance_fips;
418         cipher_priority_normal = cipher_priority_normal_fips;
419         mac_priority_normal = mac_priority_normal_fips;
420 }
421
422 static const int _mac_priority_suiteb[] = {
423         GNUTLS_MAC_AEAD,
424         0
425 };
426 static const int* mac_priority_suiteb = _mac_priority_suiteb;
427
428 static const int _mac_priority_secure128[] = {
429         GNUTLS_MAC_SHA1,
430         GNUTLS_MAC_SHA256,
431         GNUTLS_MAC_SHA384,
432         GNUTLS_MAC_AEAD,
433         0
434 };
435 static const int* mac_priority_secure128 = _mac_priority_secure128;
436
437 static const int _mac_priority_secure192[] = {
438         GNUTLS_MAC_SHA256,
439         GNUTLS_MAC_SHA384,
440         GNUTLS_MAC_AEAD,
441         0
442 };
443 static const int* mac_priority_secure192 = _mac_priority_secure192;
444
445 static const int cert_type_priority_default[] = {
446         GNUTLS_CRT_X509,
447         0
448 };
449
450 static const int cert_type_priority_all[] = {
451         GNUTLS_CRT_X509,
452         GNUTLS_CRT_OPENPGP,
453         0
454 };
455
456 typedef void (rmadd_func) (priority_st * priority_list, unsigned int alg);
457
458 static void prio_remove(priority_st * priority_list, unsigned int algo)
459 {
460         unsigned int i;
461
462         for (i = 0; i < priority_list->algorithms; i++) {
463                 if (priority_list->priority[i] == algo) {
464                         priority_list->algorithms--;
465                         if ((priority_list->algorithms - i) > 0)
466                                 memmove(&priority_list->priority[i],
467                                         &priority_list->priority[i + 1],
468                                         (priority_list->algorithms -
469                                          i) *
470                                         sizeof(priority_list->
471                                                priority[0]));
472                         priority_list->priority[priority_list->
473                                                 algorithms] = 0;
474                         break;
475                 }
476         }
477
478         return;
479 }
480
481 static void prio_add(priority_st * priority_list, unsigned int algo)
482 {
483         unsigned int i, l = priority_list->algorithms;
484
485         if (l >= MAX_ALGOS)
486                 return;         /* can't add it anyway */
487
488         for (i = 0; i < l; ++i) {
489                 if (algo == priority_list->priority[i])
490                         return; /* if it exists */
491         }
492
493         priority_list->priority[l] = algo;
494         priority_list->algorithms++;
495
496         return;
497 }
498
499
500 /**
501  * gnutls_priority_set:
502  * @session: is a #gnutls_session_t structure.
503  * @priority: is a #gnutls_priority_t structure.
504  *
505  * Sets the priorities to use on the ciphers, key exchange methods,
506  * macs and compression methods.
507  *
508  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
509  **/
510 int
511 gnutls_priority_set(gnutls_session_t session, gnutls_priority_t priority)
512 {
513         if (priority == NULL) {
514                 gnutls_assert();
515                 return GNUTLS_E_NO_CIPHER_SUITES;
516         }
517
518         memcpy(&session->internals.priorities, priority,
519                sizeof(struct gnutls_priority_st));
520
521         /* set the current version to the first in the chain.
522          * This will be overridden later.
523          */
524         if (session->internals.priorities.protocol.algorithms > 0) {
525                 if (_gnutls_set_current_version(session,
526                                             session->internals.priorities.
527                                             protocol.priority[0]) < 0) {
528                         return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
529                 }
530         }
531
532         if (priority->no_tickets != 0) {
533                 /* when PFS is explicitly requested, disable session tickets */
534                 _gnutls_ext_unset_session_data(session, GNUTLS_EXTENSION_SESSION_TICKET);
535         }
536
537         if (session->internals.priorities.protocol.algorithms == 0 ||
538             session->internals.priorities.cipher.algorithms == 0 ||
539             session->internals.priorities.mac.algorithms == 0 ||
540             session->internals.priorities.kx.algorithms == 0 ||
541             session->internals.priorities.compression.algorithms == 0)
542                 return gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET);
543
544         return 0;
545 }
546
547
548 #define LEVEL_NONE "NONE"
549 #define LEVEL_NORMAL "NORMAL"
550 #define LEVEL_PFS "PFS"
551 #define LEVEL_PERFORMANCE "PERFORMANCE"
552 #define LEVEL_SECURE128 "SECURE128"
553 #define LEVEL_SECURE192 "SECURE192"
554 #define LEVEL_SECURE256 "SECURE256"
555 #define LEVEL_SUITEB128 "SUITEB128"
556 #define LEVEL_SUITEB192 "SUITEB192"
557 #define LEVEL_LEGACY "LEGACY"
558
559 struct priority_groups_st {
560         const char *name;
561         const char *alias;
562         const int **proto_list;
563         const int **cipher_list;
564         const int **mac_list;
565         const int **kx_list;
566         const int **sign_list;
567         const int **ecc_list;
568         unsigned profile;
569         int sec_param;
570         bool no_tickets;
571 };
572
573 static const struct priority_groups_st pgroups[] = 
574 {
575         {.name = LEVEL_NORMAL,
576          .cipher_list = &cipher_priority_normal,
577          .mac_list = &mac_priority_normal,
578          .kx_list = &kx_priority_secure,
579          .sign_list = &sign_priority_default,
580          .ecc_list = &supported_ecc_normal,
581          .profile = GNUTLS_PROFILE_LOW,
582          .sec_param = GNUTLS_SEC_PARAM_WEAK
583         },
584         {.name = LEVEL_PFS,
585          .cipher_list = &cipher_priority_normal,
586          .mac_list = &mac_priority_secure128,
587          .kx_list = &kx_priority_pfs,
588          .sign_list = &sign_priority_default,
589          .ecc_list = &supported_ecc_normal,
590          .profile = GNUTLS_PROFILE_LOW,
591          .sec_param = GNUTLS_SEC_PARAM_WEAK,
592          .no_tickets = 1
593         },
594         {.name = LEVEL_SECURE128,
595          .alias = "SECURE",
596          .cipher_list = &cipher_priority_secure128,
597          .mac_list = &mac_priority_secure128,
598          .kx_list = &kx_priority_secure,
599          .sign_list = &sign_priority_secure128,
600          .ecc_list = &supported_ecc_secure128,
601                 /* The profile should have been HIGH but if we don't allow
602                  * SHA-1 (80-bits) as signature algorithm we are not able
603                  * to connect anywhere with this level */
604          .profile = GNUTLS_PROFILE_LOW,
605          .sec_param = GNUTLS_SEC_PARAM_LOW
606         },
607         {.name = LEVEL_SECURE192,
608          .alias = LEVEL_SECURE256,
609          .cipher_list = &cipher_priority_secure192,
610          .mac_list = &mac_priority_secure192,
611          .kx_list = &kx_priority_secure,
612          .sign_list = &sign_priority_secure192,
613          .ecc_list = &supported_ecc_secure192,
614          .profile = GNUTLS_PROFILE_HIGH,
615          .sec_param = GNUTLS_SEC_PARAM_HIGH
616         },
617         {.name = LEVEL_SUITEB128,
618          .proto_list = &protocol_priority_suiteb,
619          .cipher_list = &cipher_priority_suiteb128,
620          .mac_list = &mac_priority_suiteb,
621          .kx_list = &kx_priority_suiteb,
622          .sign_list = &sign_priority_suiteb128,
623          .ecc_list = &supported_ecc_suiteb128,
624          .profile = GNUTLS_PROFILE_SUITEB128,
625          .sec_param = GNUTLS_SEC_PARAM_HIGH
626         },
627         {.name = LEVEL_SUITEB192,
628          .proto_list = &protocol_priority_suiteb,
629          .cipher_list = &cipher_priority_suiteb192,
630          .mac_list = &mac_priority_suiteb,
631          .kx_list = &kx_priority_suiteb,
632          .sign_list = &sign_priority_suiteb192,
633          .ecc_list = &supported_ecc_suiteb192,
634          .profile = GNUTLS_PROFILE_SUITEB192,
635          .sec_param = GNUTLS_SEC_PARAM_ULTRA
636         },
637         {.name = LEVEL_LEGACY,
638          .cipher_list = &cipher_priority_normal,
639          .mac_list = &mac_priority_normal,
640          .kx_list = &kx_priority_secure,
641          .sign_list = &sign_priority_default,
642          .ecc_list = &supported_ecc_normal,
643          .sec_param = GNUTLS_SEC_PARAM_VERY_WEAK
644         },
645         {.name = LEVEL_PERFORMANCE,
646          .cipher_list = &cipher_priority_performance,
647          .mac_list = &mac_priority_normal,
648          .kx_list = &kx_priority_performance,
649          .sign_list = &sign_priority_default,
650          .ecc_list = &supported_ecc_normal,
651          .profile = GNUTLS_PROFILE_LOW,
652          .sec_param = GNUTLS_SEC_PARAM_WEAK
653         },
654         {
655          .name = NULL,
656         }
657 };
658
659 #define SET_PROFILE(to_set) \
660         profile = GNUTLS_VFLAGS_TO_PROFILE(priority_cache->additional_verify_flags); \
661         if (profile == 0 || profile > to_set) { \
662                 priority_cache->additional_verify_flags &= ~GNUTLS_VFLAGS_PROFILE_MASK; \
663                 priority_cache->additional_verify_flags |= GNUTLS_PROFILE_TO_VFLAGS(to_set); \
664         }
665
666 #define SET_LEVEL(to_set) \
667                 if (priority_cache->level == 0 || (unsigned)priority_cache->level > (unsigned)to_set) \
668                         priority_cache->level = to_set
669
670 static
671 int check_level(const char *level, gnutls_priority_t priority_cache,
672                 int add)
673 {
674         bulk_rmadd_func *func;
675         unsigned profile = 0;
676         unsigned i;
677
678         if (add)
679                 func = _add_priority;
680         else
681                 func = _set_priority;
682
683         for (i=0;;i++) {
684                 if (pgroups[i].name == NULL)
685                         return 0;
686
687                 if (strcasecmp(level, pgroups[i].name) == 0 ||
688                         (pgroups[i].alias != NULL && strcasecmp(level, pgroups[i].alias) == 0)) {
689                         if (pgroups[i].proto_list != NULL)
690                                 func(&priority_cache->protocol, *pgroups[i].proto_list);
691                         func(&priority_cache->cipher, *pgroups[i].cipher_list);
692                         func(&priority_cache->kx, *pgroups[i].kx_list);
693                         func(&priority_cache->mac, *pgroups[i].mac_list);
694                         func(&priority_cache->sign_algo, *pgroups[i].sign_list);
695                         func(&priority_cache->supported_ecc, *pgroups[i].ecc_list);
696
697                         if (pgroups[i].profile != 0) {
698                                 SET_PROFILE(pgroups[i].profile); /* set certificate level */
699                         }
700                         SET_LEVEL(pgroups[i].sec_param); /* set DH params level */
701                         priority_cache->no_tickets = pgroups[i].no_tickets;
702                         return 1;
703                 }
704         }
705 }
706
707 static void enable_compat(gnutls_priority_t c)
708 {
709         ENABLE_COMPAT(c);
710 }
711 static void enable_dumbfw(gnutls_priority_t c)
712 {
713         c->dumbfw = 1;
714 }
715 static void enable_no_extensions(gnutls_priority_t c)
716 {
717         c->no_extensions = 1;
718 }
719 static void enable_no_ext_master_secret(gnutls_priority_t c)
720 {
721         c->no_ext_master_secret = 1;
722 }
723 static void enable_no_etm(gnutls_priority_t c)
724 {
725         c->no_etm = 1;
726 }
727 static void enable_no_tickets(gnutls_priority_t c)
728 {
729         c->no_tickets = 1;
730 }
731 static void enable_stateless_compression(gnutls_priority_t c)
732 {
733         c->stateless_compression = 1;
734 }
735 static void disable_wildcards(gnutls_priority_t c)
736 {
737         c->additional_verify_flags |= GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS;
738 }
739 static void enable_profile_very_weak(gnutls_priority_t c)
740 {
741         c->additional_verify_flags &= 0x00ffffff;
742         c->additional_verify_flags |= GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_VERY_WEAK);
743         c->level = GNUTLS_SEC_PARAM_VERY_WEAK;
744 }
745 static void enable_profile_low(gnutls_priority_t c)
746 {
747         c->additional_verify_flags &= 0x00ffffff;
748         c->additional_verify_flags |= GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_LOW);
749         c->level = GNUTLS_SEC_PARAM_LOW;
750 }
751 static void enable_profile_legacy(gnutls_priority_t c)
752 {
753         c->additional_verify_flags &= 0x00ffffff;
754         c->additional_verify_flags |= GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_LEGACY);
755         c->level = GNUTLS_SEC_PARAM_LEGACY;
756 }
757 static void enable_profile_high(gnutls_priority_t c)
758 {
759         c->additional_verify_flags &= 0x00ffffff;
760         c->additional_verify_flags |= GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_HIGH);
761         c->level = GNUTLS_SEC_PARAM_HIGH;
762 }
763 static void enable_profile_ultra(gnutls_priority_t c)
764 {
765         c->additional_verify_flags &= 0x00ffffff;
766         c->additional_verify_flags |= GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_ULTRA);
767         c->level = GNUTLS_SEC_PARAM_ULTRA;
768 }
769 static void enable_profile_medium(gnutls_priority_t c)
770 {
771         c->additional_verify_flags &= 0x00ffffff;
772         c->additional_verify_flags |= GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_MEDIUM);
773         c->level = GNUTLS_SEC_PARAM_MEDIUM;
774 }
775 static void enable_profile_suiteb128(gnutls_priority_t c)
776 {
777         c->additional_verify_flags &= 0x00ffffff;
778         c->additional_verify_flags |= GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_SUITEB128);
779         c->level = GNUTLS_SEC_PARAM_HIGH;
780 }
781 static void enable_profile_suiteb192(gnutls_priority_t c)
782 {
783         c->additional_verify_flags &= 0x00ffffff;
784         c->additional_verify_flags |= GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_SUITEB192);
785         c->level = GNUTLS_SEC_PARAM_ULTRA;
786 }
787 static void enable_safe_renegotiation(gnutls_priority_t c)
788 {
789         c->sr = SR_SAFE;
790
791 }
792 static void enable_unsafe_renegotiation(gnutls_priority_t c)
793 {
794         c->sr = SR_UNSAFE;
795 }
796 static void enable_partial_safe_renegotiation(gnutls_priority_t c)
797 {
798         c->sr = SR_PARTIAL;
799 }
800 static void disable_safe_renegotiation(gnutls_priority_t c)
801 {
802         c->sr = SR_DISABLED;
803 }
804 static void enable_latest_record_version(gnutls_priority_t c)
805 {
806         c->min_record_version = 0;
807 }
808 static void enable_ssl3_record_version(gnutls_priority_t c)
809 {
810         c->min_record_version = 1;
811 }
812 static void enable_verify_allow_rsa_md5(gnutls_priority_t c)
813 {
814         c->additional_verify_flags |=
815             GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5;
816 }
817 static void disable_crl_checks(gnutls_priority_t c)
818 {
819         c->additional_verify_flags |=
820                 GNUTLS_VERIFY_DISABLE_CRL_CHECKS;
821 }
822 static void enable_server_precedence(gnutls_priority_t c)
823 {
824         c->server_precedence = 1;
825 }
826 static void dummy_func(gnutls_priority_t c)
827 {
828 }
829
830 #include <priority_options.h>
831
832 static char *check_str(char *line, size_t line_size, const char *needle, size_t needle_size)
833 {
834         char *p;
835         unsigned n;
836
837         while (c_isspace(*line)) {
838                 line++;
839                 line_size--;
840         }
841
842         if (line[0] == '#' || needle_size >= line_size)
843                 return NULL;
844
845         if (memcmp(line, needle, needle_size) == 0) {
846                 p = &line[needle_size];
847                 while (c_isspace(*p)) {
848                         p++;
849                 }
850                 if (*p != '=') {
851                         return NULL;
852                 } else
853                         p++;
854
855                 while (c_isspace(*p)) {
856                         p++;
857                 }
858
859                 n = strlen(p);
860
861                 if (n > 1 && p[n-1] == '\n') {
862                         n--;
863                         p[n] = 0;
864                 }
865
866                 if (n > 1 && p[n-1] == '\r') {
867                         n--;
868                         p[n] = 0;
869                 }
870                 return p;
871         }
872
873         return NULL;
874 }
875
876 /* Returns the new priorities if SYSTEM is specified in
877  * an allocated string, or just a copy of the provided
878  * priorities, appended with any additional present in
879  * the priorities string.
880  *
881  * The returned string must be released using free().
882  */
883 static char *resolve_priorities(const char* priorities)
884 {
885 char *p = (char*)priorities;
886 char *additional = NULL;
887 char *ret = NULL;
888 char *ss, *line = NULL;
889 unsigned ss_len;
890 int l;
891 FILE* fp = NULL;
892 size_t n, n2 = 0, line_size;
893
894         while (c_isspace(*p))
895                 p++;
896
897         if (*p == '@') {
898                 ss = p+1;
899
900                 additional = strchr(p, ':');
901                 if (additional != NULL) {
902                         ss_len = additional - ss;
903                         additional++;
904                 } else {
905                         ss_len = strlen(ss);
906                 }
907
908                 fp = fopen(SYSTEM_PRIORITY_FILE, "r");
909                 if (fp == NULL) {/* fail */
910                         ret = NULL;
911                         goto finish;
912                 }
913
914                 do {
915                         l = getline(&line, &line_size, fp);
916                         if (l > 0) {
917                                 p = check_str(line, line_size, ss, ss_len);
918                                 if (p != NULL)
919                                         break;
920                         }
921                 } while (l>0);
922
923                 if (p == NULL) {
924                         ret = NULL;
925                         goto finish;
926                 }
927
928                 n = strlen(p);
929                 if (additional)
930                         n2 = strlen(additional);
931
932                 ret = malloc(n+n2+1+1);
933                 if (ret == NULL) {
934                         goto finish;
935                 }
936
937                 memcpy(ret, p, n);
938                 if (additional != NULL) {
939                         ret[n] = ':';
940                         memcpy(&ret[n+1], additional, n2);
941                         ret[n+n2+1] = 0;
942                 } else {
943                         ret[n] = 0;
944                 }
945         } else {
946                 return strdup(p);
947         }
948
949 finish:
950         if (ret != NULL) {
951                 _gnutls_debug_log("selected priority string: %s\n", ret);
952         }
953         free(line);
954         if (fp != NULL)
955                 fclose(fp);
956
957         return ret;
958 }
959
960 /**
961  * gnutls_priority_init:
962  * @priority_cache: is a #gnutls_prioritity_t structure.
963  * @priorities: is a string describing priorities
964  * @err_pos: In case of an error this will have the position in the string the error occurred
965  *
966  * Sets priorities for the ciphers, key exchange methods, macs and
967  * compression methods.
968  *
969  * The #priorities option allows you to specify a colon
970  * separated list of the cipher priorities to enable.
971  * Some keywords are defined to provide quick access
972  * to common preferences.
973  *
974  * Unless there is a special need, use the "NORMAL" keyword to
975  * apply a reasonable security level, or "NORMAL:%COMPAT" for compatibility.
976  *
977  * "PERFORMANCE" means all the "secure" ciphersuites are enabled,
978  * limited to 128 bit ciphers and sorted by terms of speed
979  * performance.
980  *
981  * "LEGACY" the NORMAL settings for GnuTLS 3.2.x or earlier. There is
982  * no verification profile set, and the allowed DH primes are considered
983  * weak today.
984  *
985  * "NORMAL" means all "secure" ciphersuites. The 256-bit ciphers are
986  * included as a fallback only.  The ciphers are sorted by security
987  * margin.
988  *
989  * "PFS" means all "secure" ciphersuites that support perfect forward secrecy. 
990  * The 256-bit ciphers are included as a fallback only.  
991  * The ciphers are sorted by security margin.
992  *
993  * "SECURE128" means all "secure" ciphersuites of security level 128-bit
994  * or more.
995  *
996  * "SECURE192" means all "secure" ciphersuites of security level 192-bit
997  * or more.
998  *
999  * "SUITEB128" means all the NSA SuiteB ciphersuites with security level
1000  * of 128.
1001  *
1002  * "SUITEB192" means all the NSA SuiteB ciphersuites with security level
1003  * of 192.
1004  *
1005  * "NONE" means nothing is enabled.  This disables even protocols and
1006  * compression methods.
1007  *
1008  * "@KEYWORD" The system administrator imposed settings. The provided keywords
1009  * will be expanded from a configuration-time provided file - default is:
1010  * /etc/gnutls/default-priorities. Any keywords that follow it, will 
1011  * be appended to the expanded string. If there is no system string,
1012  * then the function will fail. The system file should be formatted
1013  * as "KEYWORD=VALUE", e.g., "SYSTEM=NORMAL:+ARCFOUR-128".
1014  *
1015  * Special keywords are "!", "-" and "+".
1016  * "!" or "-" appended with an algorithm will remove this algorithm.
1017  * "+" appended with an algorithm will add this algorithm.
1018  *
1019  * Check the GnuTLS manual section "Priority strings" for detailed
1020  * information.
1021  *
1022  * Examples:
1023  *
1024  * "NONE:+VERS-TLS-ALL:+MAC-ALL:+RSA:+AES-128-CBC:+SIGN-ALL:+COMP-NULL"
1025  *
1026  * "NORMAL:+ARCFOUR-128" means normal ciphers plus ARCFOUR-128.
1027  *
1028  * "SECURE128:-VERS-SSL3.0:+COMP-DEFLATE" means that only secure ciphers are
1029  * enabled, SSL3.0 is disabled, and libz compression enabled.
1030  *
1031  * "NONE:+VERS-TLS-ALL:+AES-128-CBC:+RSA:+SHA1:+COMP-NULL:+SIGN-RSA-SHA1", 
1032  *
1033  * "NONE:+VERS-TLS-ALL:+AES-128-CBC:+ECDHE-RSA:+SHA1:+COMP-NULL:+SIGN-RSA-SHA1:+CURVE-SECP256R1", 
1034  *
1035  * "SECURE256:+SECURE128",
1036  *
1037  * Note that "NORMAL:%COMPAT" is the most compatible mode.
1038  *
1039  * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
1040  * %GNUTLS_E_SUCCESS on success, or an error code.
1041  **/
1042 int
1043 gnutls_priority_init(gnutls_priority_t * priority_cache,
1044                      const char *priorities, const char **err_pos)
1045 {
1046         char *broken_list[MAX_ELEMENTS];
1047         int broken_list_size = 0, i = 0, j;
1048         char *darg = NULL;
1049         unsigned ikeyword_set = 0;
1050         int algo;
1051         rmadd_func *fn;
1052         bulk_rmadd_func *bulk_fn;
1053         bulk_rmadd_func *bulk_given_fn;
1054
1055         if (err_pos)
1056                 *err_pos = priorities;
1057
1058         *priority_cache =
1059             gnutls_calloc(1, sizeof(struct gnutls_priority_st));
1060         if (*priority_cache == NULL) {
1061                 gnutls_assert();
1062                 return GNUTLS_E_MEMORY_ERROR;
1063         }
1064
1065         /* for now unsafe renegotiation is default on everyone. To be removed
1066          * when we make it the default.
1067          */
1068         (*priority_cache)->sr = SR_PARTIAL;
1069         (*priority_cache)->min_record_version = 1;
1070
1071         (*priority_cache)->max_empty_records = DEFAULT_MAX_EMPTY_RECORDS;
1072
1073         if (priorities == NULL)
1074                 priorities = "NORMAL";
1075
1076         darg = resolve_priorities(priorities);
1077         if (darg == NULL) {
1078                 gnutls_assert();
1079                 goto error;
1080         }
1081
1082         break_list(darg, broken_list, &broken_list_size);
1083         /* This is our default set of protocol version, certificate types and
1084          * compression methods.
1085          */
1086         if (strcasecmp(broken_list[0], LEVEL_NONE) != 0) {
1087                 _set_priority(&(*priority_cache)->protocol,
1088                               protocol_priority);
1089                 _set_priority(&(*priority_cache)->compression,
1090                               comp_priority);
1091                 _set_priority(&(*priority_cache)->cert_type,
1092                               cert_type_priority_default);
1093                 _set_priority(&(*priority_cache)->sign_algo,
1094                               sign_priority_default);
1095                 _set_priority(&(*priority_cache)->supported_ecc,
1096                               supported_ecc_normal);
1097                 i = 0;
1098         } else {
1099                 ikeyword_set = 1;
1100                 i = 1;
1101         }
1102
1103         for (; i < broken_list_size; i++) {
1104                 if (check_level(broken_list[i], *priority_cache, ikeyword_set) != 0) {
1105                         ikeyword_set = 1;
1106                         continue;
1107                 } else if (broken_list[i][0] == '!'
1108                            || broken_list[i][0] == '+'
1109                            || broken_list[i][0] == '-') {
1110                         if (broken_list[i][0] == '+') {
1111                                 fn = prio_add;
1112                                 bulk_fn = _add_priority;
1113                                 bulk_given_fn = _add_priority;
1114                         } else {
1115                                 fn = prio_remove;
1116                                 bulk_fn = _clear_priorities;
1117                                 bulk_given_fn = _clear_given_priorities;
1118                         }
1119
1120                         if (broken_list[i][0] == '+'
1121                             && check_level(&broken_list[i][1],
1122                                            *priority_cache, 1) != 0) {
1123                                 continue;
1124                         } else if ((algo =
1125                                     gnutls_mac_get_id(&broken_list[i][1]))
1126                                    != GNUTLS_MAC_UNKNOWN)
1127                                 fn(&(*priority_cache)->mac, algo);
1128                         else if ((algo =
1129                                   gnutls_cipher_get_id(&broken_list[i][1]))
1130                                  != GNUTLS_CIPHER_UNKNOWN)
1131                                 fn(&(*priority_cache)->cipher, algo);
1132                         else if ((algo =
1133                                   gnutls_kx_get_id(&broken_list[i][1])) !=
1134                                  GNUTLS_KX_UNKNOWN)
1135                                 fn(&(*priority_cache)->kx, algo);
1136                         else if (strncasecmp
1137                                  (&broken_list[i][1], "VERS-", 5) == 0) {
1138                                 if (strncasecmp
1139                                     (&broken_list[i][1], "VERS-TLS-ALL",
1140                                      12) == 0) {
1141                                         bulk_given_fn(&(*priority_cache)->
1142                                                 protocol,
1143                                                 stream_protocol_priority);
1144                                 } else if (strncasecmp
1145                                         (&broken_list[i][1],
1146                                          "VERS-DTLS-ALL", 13) == 0) {
1147                                         bulk_given_fn(&(*priority_cache)->
1148                                                 protocol,
1149                                                 (bulk_given_fn==_add_priority)?dtls_protocol_priority:dgram_protocol_priority);
1150                                 } else if (strncasecmp
1151                                         (&broken_list[i][1],
1152                                          "VERS-ALL", 8) == 0) {
1153                                         bulk_fn(&(*priority_cache)->
1154                                                 protocol,
1155                                                 protocol_priority);
1156                                 } else {
1157                                         if ((algo =
1158                                              gnutls_protocol_get_id
1159                                              (&broken_list[i][6])) !=
1160                                             GNUTLS_VERSION_UNKNOWN)
1161                                                 fn(&(*priority_cache)->
1162                                                    protocol, algo);
1163                                         else
1164                                                 goto error;
1165
1166                                 }
1167                         } /* now check if the element is something like -ALGO */
1168                         else if (strncasecmp
1169                                  (&broken_list[i][1], "COMP-", 5) == 0) {
1170                                 if (strncasecmp
1171                                     (&broken_list[i][1], "COMP-ALL",
1172                                      8) == 0) {
1173                                         bulk_fn(&(*priority_cache)->
1174                                                 compression,
1175                                                 comp_priority);
1176                                 } else {
1177                                         if ((algo =
1178                                              gnutls_compression_get_id
1179                                              (&broken_list[i][6])) !=
1180                                             GNUTLS_COMP_UNKNOWN)
1181                                                 fn(&(*priority_cache)->
1182                                                    compression, algo);
1183                                         else
1184                                                 goto error;
1185                                 }
1186                         } /* now check if the element is something like -ALGO */
1187                         else if (strncasecmp
1188                                  (&broken_list[i][1], "CURVE-", 6) == 0) {
1189                                 if (strncasecmp
1190                                     (&broken_list[i][1], "CURVE-ALL",
1191                                      9) == 0) {
1192                                         bulk_fn(&(*priority_cache)->
1193                                                 supported_ecc,
1194                                                 supported_ecc_normal);
1195                                 } else {
1196                                         if ((algo =
1197                                              _gnutls_ecc_curve_get_id
1198                                              (&broken_list[i][7])) !=
1199                                             GNUTLS_ECC_CURVE_INVALID)
1200                                                 fn(&(*priority_cache)->
1201                                                    supported_ecc, algo);
1202                                         else
1203                                                 goto error;
1204                                 }
1205                         } /* now check if the element is something like -ALGO */
1206                         else if (strncasecmp
1207                                  (&broken_list[i][1], "CTYPE-", 6) == 0) {
1208                                 if (strncasecmp
1209                                     (&broken_list[i][1], "CTYPE-ALL",
1210                                      9) == 0) {
1211                                         bulk_fn(&(*priority_cache)->
1212                                                 cert_type,
1213                                                 cert_type_priority_all);
1214                                 } else {
1215                                         if ((algo =
1216                                              gnutls_certificate_type_get_id
1217                                              (&broken_list[i][7])) !=
1218                                             GNUTLS_CRT_UNKNOWN)
1219                                                 fn(&(*priority_cache)->
1220                                                    cert_type, algo);
1221                                         else
1222                                                 goto error;
1223                                 }
1224                         } /* now check if the element is something like -ALGO */
1225                         else if (strncasecmp
1226                                  (&broken_list[i][1], "SIGN-", 5) == 0) {
1227                                 if (strncasecmp
1228                                     (&broken_list[i][1], "SIGN-ALL",
1229                                      8) == 0) {
1230                                         bulk_fn(&(*priority_cache)->
1231                                                 sign_algo,
1232                                                 sign_priority_default);
1233                                 } else {
1234                                         if ((algo =
1235                                              gnutls_sign_get_id
1236                                              (&broken_list[i][6])) !=
1237                                             GNUTLS_SIGN_UNKNOWN)
1238                                                 fn(&(*priority_cache)->
1239                                                    sign_algo, algo);
1240                                         else
1241                                                 goto error;
1242                                 }
1243                         } else
1244                             if (strncasecmp
1245                                 (&broken_list[i][1], "MAC-ALL", 7) == 0) {
1246                                 bulk_fn(&(*priority_cache)->mac,
1247                                         mac_priority_normal);
1248                         } else
1249                             if (strncasecmp
1250                                 (&broken_list[i][1], "CIPHER-ALL",
1251                                  10) == 0) {
1252                                 bulk_fn(&(*priority_cache)->cipher,
1253                                         cipher_priority_normal);
1254                         } else
1255                             if (strncasecmp
1256                                 (&broken_list[i][1], "KX-ALL", 6) == 0) {
1257                                 bulk_fn(&(*priority_cache)->kx,
1258                                         kx_priority_secure);
1259                         } else
1260                                 goto error;
1261                 } else if (broken_list[i][0] == '%') {
1262                         const struct priority_options_st * o;
1263                         /* to add a new option modify
1264                          * priority_options.gperf */
1265                         o = in_word_set(&broken_list[i][1], strlen(&broken_list[i][1]));
1266                         if (o == NULL) {
1267                                 goto error;
1268                         }
1269                         o->func(*priority_cache);
1270                 } else
1271                         goto error;
1272         }
1273
1274         free(darg);
1275         return 0;
1276
1277       error:
1278         if (err_pos != NULL && i < broken_list_size) {
1279                 *err_pos = priorities;
1280                 for (j = 0; j < i; j++) {
1281                         (*err_pos) += strlen(broken_list[j]) + 1;
1282                 }
1283         }
1284         free(darg);
1285         gnutls_free(*priority_cache);
1286         *priority_cache = NULL;
1287
1288         return GNUTLS_E_INVALID_REQUEST;
1289
1290 }
1291
1292 /**
1293  * gnutls_priority_deinit:
1294  * @priority_cache: is a #gnutls_prioritity_t structure.
1295  *
1296  * Deinitializes the priority cache.
1297  **/
1298 void gnutls_priority_deinit(gnutls_priority_t priority_cache)
1299 {
1300         gnutls_free(priority_cache);
1301 }
1302
1303
1304 /**
1305  * gnutls_priority_set_direct:
1306  * @session: is a #gnutls_session_t structure.
1307  * @priorities: is a string describing priorities
1308  * @err_pos: In case of an error this will have the position in the string the error occured
1309  *
1310  * Sets the priorities to use on the ciphers, key exchange methods,
1311  * macs and compression methods.  This function avoids keeping a
1312  * priority cache and is used to directly set string priorities to a
1313  * TLS session.  For documentation check the gnutls_priority_init().
1314  *
1315  * To simply use a reasonable default, consider using gnutls_set_default_priority().
1316  *
1317  * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
1318  * %GNUTLS_E_SUCCESS on success, or an error code.
1319  **/
1320 int
1321 gnutls_priority_set_direct(gnutls_session_t session,
1322                            const char *priorities, const char **err_pos)
1323 {
1324         gnutls_priority_t prio;
1325         int ret;
1326
1327         ret = gnutls_priority_init(&prio, priorities, err_pos);
1328         if (ret < 0) {
1329                 gnutls_assert();
1330                 return ret;
1331         }
1332
1333         ret = gnutls_priority_set(session, prio);
1334         if (ret < 0) {
1335                 gnutls_assert();
1336                 return ret;
1337         }
1338
1339         gnutls_priority_deinit(prio);
1340
1341         return 0;
1342 }
1343
1344 /* Breaks a list of "xxx", "yyy", to a character array, of
1345  * MAX_COMMA_SEP_ELEMENTS size; Note that the given string is modified.
1346   */
1347 static void
1348 break_list(char *list,
1349                  char *broken_list[MAX_ELEMENTS], int *size)
1350 {
1351         char *p = list;
1352
1353         *size = 0;
1354
1355         do {
1356                 broken_list[*size] = p;
1357
1358                 (*size)++;
1359
1360                 p = strchr(p, ':');
1361                 if (p) {
1362                         *p = 0;
1363                         p++;    /* move to next entry and skip white
1364                                  * space.
1365                                  */
1366                         while (*p == ' ')
1367                                 p++;
1368                 }
1369         }
1370         while (p != NULL && *size < MAX_ELEMENTS);
1371 }
1372
1373 /**
1374  * gnutls_set_default_priority:
1375  * @session: is a #gnutls_session_t structure.
1376  *
1377  * Sets some default priority on the ciphers, key exchange methods,
1378  * macs and compression methods.
1379  *
1380  * This typically sets a default priority that is considered
1381  * sufficiently secure to establish encrypted sessions.
1382  *
1383  * This function is kept around for backwards compatibility, but
1384  * because of its wide use it is still fully supported.  If you wish
1385  * to allow users to provide a string that specify which ciphers to
1386  * use (which is recommended), you should use
1387  * gnutls_priority_set_direct() or gnutls_priority_set() instead.
1388  *
1389  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
1390  **/
1391 int gnutls_set_default_priority(gnutls_session_t session)
1392 {
1393         return gnutls_priority_set_direct(session, NULL, NULL);
1394 }
1395
1396 /**
1397  * gnutls_priority_ecc_curve_list:
1398  * @pcache: is a #gnutls_prioritity_t structure.
1399  * @list: will point to an integer list
1400  *
1401  * Get a list of available elliptic curves in the priority
1402  * structure. 
1403  *
1404  * Returns: the number of curves, or an error code.
1405  * Since: 3.0
1406  **/
1407 int
1408 gnutls_priority_ecc_curve_list(gnutls_priority_t pcache,
1409                                const unsigned int **list)
1410 {
1411         if (pcache->supported_ecc.algorithms == 0)
1412                 return 0;
1413
1414         *list = pcache->supported_ecc.priority;
1415         return pcache->supported_ecc.algorithms;
1416 }
1417
1418 /**
1419  * gnutls_priority_kx_list:
1420  * @pcache: is a #gnutls_prioritity_t structure.
1421  * @list: will point to an integer list
1422  *
1423  * Get a list of available key exchange methods in the priority
1424  * structure. 
1425  *
1426  * Returns: the number of curves, or an error code.
1427  * Since: 3.2.3
1428  **/
1429 int
1430 gnutls_priority_kx_list(gnutls_priority_t pcache,
1431                         const unsigned int **list)
1432 {
1433         if (pcache->kx.algorithms == 0)
1434                 return 0;
1435
1436         *list = pcache->kx.priority;
1437         return pcache->kx.algorithms;
1438 }
1439
1440 /**
1441  * gnutls_priority_cipher_list:
1442  * @pcache: is a #gnutls_prioritity_t structure.
1443  * @list: will point to an integer list
1444  *
1445  * Get a list of available ciphers in the priority
1446  * structure. 
1447  *
1448  * Returns: the number of curves, or an error code.
1449  * Since: 3.2.3
1450  **/
1451 int
1452 gnutls_priority_cipher_list(gnutls_priority_t pcache,
1453                             const unsigned int **list)
1454 {
1455         if (pcache->cipher.algorithms == 0)
1456                 return 0;
1457
1458         *list = pcache->cipher.priority;
1459         return pcache->cipher.algorithms;
1460 }
1461
1462 /**
1463  * gnutls_priority_mac_list:
1464  * @pcache: is a #gnutls_prioritity_t structure.
1465  * @list: will point to an integer list
1466  *
1467  * Get a list of available MAC algorithms in the priority
1468  * structure. 
1469  *
1470  * Returns: the number of curves, or an error code.
1471  * Since: 3.2.3
1472  **/
1473 int
1474 gnutls_priority_mac_list(gnutls_priority_t pcache,
1475                          const unsigned int **list)
1476 {
1477         if (pcache->mac.algorithms == 0)
1478                 return 0;
1479
1480         *list = pcache->mac.priority;
1481         return pcache->mac.algorithms;
1482 }
1483
1484 /**
1485  * gnutls_priority_compression_list:
1486  * @pcache: is a #gnutls_prioritity_t structure.
1487  * @list: will point to an integer list
1488  *
1489  * Get a list of available compression method in the priority
1490  * structure. 
1491  *
1492  * Returns: the number of methods, or an error code.
1493  * Since: 3.0
1494  **/
1495 int
1496 gnutls_priority_compression_list(gnutls_priority_t pcache,
1497                                  const unsigned int **list)
1498 {
1499         if (pcache->compression.algorithms == 0)
1500                 return 0;
1501
1502         *list = pcache->compression.priority;
1503         return pcache->compression.algorithms;
1504 }
1505
1506 /**
1507  * gnutls_priority_protocol_list:
1508  * @pcache: is a #gnutls_prioritity_t structure.
1509  * @list: will point to an integer list
1510  *
1511  * Get a list of available TLS version numbers in the priority
1512  * structure. 
1513  *
1514  * Returns: the number of protocols, or an error code.
1515  * Since: 3.0
1516  **/
1517 int
1518 gnutls_priority_protocol_list(gnutls_priority_t pcache,
1519                               const unsigned int **list)
1520 {
1521         if (pcache->protocol.algorithms == 0)
1522                 return 0;
1523
1524         *list = pcache->protocol.priority;
1525         return pcache->protocol.algorithms;
1526 }
1527
1528 /**
1529  * gnutls_priority_sign_list:
1530  * @pcache: is a #gnutls_prioritity_t structure.
1531  * @list: will point to an integer list
1532  *
1533  * Get a list of available signature algorithms in the priority
1534  * structure. 
1535  *
1536  * Returns: the number of algorithms, or an error code.
1537  * Since: 3.0
1538  **/
1539 int
1540 gnutls_priority_sign_list(gnutls_priority_t pcache,
1541                           const unsigned int **list)
1542 {
1543         if (pcache->sign_algo.algorithms == 0)
1544                 return 0;
1545
1546         *list = pcache->sign_algo.priority;
1547         return pcache->sign_algo.algorithms;
1548 }
1549
1550 /**
1551  * gnutls_priority_certificate_type_list:
1552  * @pcache: is a #gnutls_prioritity_t structure.
1553  * @list: will point to an integer list
1554  *
1555  * Get a list of available certificate types in the priority
1556  * structure. 
1557  *
1558  * Returns: the number of certificate types, or an error code.
1559  * Since: 3.0
1560  **/
1561 int
1562 gnutls_priority_certificate_type_list(gnutls_priority_t pcache,
1563                                       const unsigned int **list)
1564 {
1565         if (pcache->cert_type.algorithms == 0)
1566                 return 0;
1567
1568         *list = pcache->cert_type.priority;
1569         return pcache->cert_type.algorithms;
1570 }
1571
1572 /**
1573  * gnutls_priority_string_list:
1574  * @iter: an integer counter starting from zero
1575  * @flags: one of %GNUTLS_PRIORITY_LIST_INIT_KEYWORDS, %GNUTLS_PRIORITY_LIST_SPECIAL
1576  *
1577  * Can be used to iterate all available priority strings.
1578  * Due to internal implementation details, there are cases where this
1579  * function can return the empty string. In that case that string should be ignored.
1580  * When no strings are available it returns %NULL.
1581  *
1582  * Returns: a priority string
1583  * Since: 3.4.0
1584  **/
1585 const char *
1586 gnutls_priority_string_list(unsigned iter, unsigned int flags)
1587 {
1588         if (flags & GNUTLS_PRIORITY_LIST_INIT_KEYWORDS) {
1589                 if (iter >= (sizeof(pgroups)/sizeof(pgroups[0]))-1)
1590                         return NULL;
1591                 return pgroups[iter].name;
1592         } else if (flags & GNUTLS_PRIORITY_LIST_SPECIAL) {
1593                 if (iter >= (sizeof(wordlist)/sizeof(wordlist[0]))-1)
1594                         return NULL;
1595                 return wordlist[iter].name;
1596         }
1597         return NULL;
1598 }