/src/gnutls/lib/priority.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * Copyright (C) 2004-2015 Free Software Foundation, Inc.  | 
3  |  |  * Copyright (C) 2015-2019 Red Hat, Inc.  | 
4  |  |  *  | 
5  |  |  * Author: Nikos Mavrogiannopoulos  | 
6  |  |  *  | 
7  |  |  * This file is part of GnuTLS.  | 
8  |  |  *  | 
9  |  |  * The GnuTLS is free software; you can redistribute it and/or  | 
10  |  |  * modify it under the terms of the GNU Lesser General Public License  | 
11  |  |  * as published by the Free Software Foundation; either version 2.1 of  | 
12  |  |  * the License, or (at your option) any later version.  | 
13  |  |  *  | 
14  |  |  * This library is distributed in the hope that it will be useful, but  | 
15  |  |  * WITHOUT ANY WARRANTY; without even the implied warranty of  | 
16  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  | 
17  |  |  * Lesser General Public License for more details.  | 
18  |  |  *  | 
19  |  |  * You should have received a copy of the GNU Lesser General Public License  | 
20  |  |  * along with this program.  If not, see <https://www.gnu.org/licenses/>  | 
21  |  |  *  | 
22  |  |  */  | 
23  |  |  | 
24  |  | /* Here lies the code of the gnutls_*_set_priority() functions.  | 
25  |  |  */  | 
26  |  |  | 
27  |  | #include "gnutls_int.h"  | 
28  |  | #include "algorithms.h"  | 
29  |  | #include "errors.h"  | 
30  |  | #include "num.h"  | 
31  |  | #include <gnutls/x509.h>  | 
32  |  | #include <c-ctype.h>  | 
33  |  | #include "hello_ext.h"  | 
34  |  | #include <c-strcase.h>  | 
35  |  | #include "fips.h"  | 
36  |  | #include <errno.h>  | 
37  |  | #include "ext/srp.h"  | 
38  |  | #include <gnutls/gnutls.h>  | 
39  |  | #include "profiles.h"  | 
40  |  | #include "c-strcase.h"  | 
41  |  | #include "inih/ini.h"  | 
42  |  | #include "locks.h"  | 
43  |  | #include "profiles.h"  | 
44  |  | #include "name_val_array.h"  | 
45  |  |  | 
46  | 0  | #define MAX_ELEMENTS GNUTLS_MAX_ALGORITHM_NUM  | 
47  |  |  | 
48  |  | #define ENABLE_PROFILE(c, profile)                                \  | 
49  | 0  |   do {                                                      \ | 
50  | 0  |     c->additional_verify_flags &= 0x00ffffff;         \  | 
51  | 0  |     c->additional_verify_flags |=                     \  | 
52  | 0  |       GNUTLS_PROFILE_TO_VFLAGS(profile);        \  | 
53  | 0  |     c->level = _gnutls_profile_to_sec_level(profile); \  | 
54  | 0  |   } while (0)  | 
55  |  |  | 
56  |  | /* This function is used by the test suite */  | 
57  |  | char *_gnutls_resolve_priorities(const char *priorities);  | 
58  |  |  | 
59  |  | /* This variable points to either a constant value (DEFAULT_PRIORITY_STRING or  | 
60  |  |  * externally assigned) or heap-allocated  | 
61  |  |  * system_wide_config.default_priority_string. We can't move this to the  | 
62  |  |  * system_wide_config struct, because this variable is part of (private) ABI  | 
63  |  |  * exported for testing.  | 
64  |  |  */  | 
65  |  | const char *_gnutls_default_priority_string = DEFAULT_PRIORITY_STRING;  | 
66  |  |  | 
67  |  | static void prio_remove(priority_st *priority_list, unsigned int algo);  | 
68  |  | static void prio_add(priority_st *priority_list, unsigned int algo);  | 
69  |  | static void break_list(char *etag, char *broken_etag[MAX_ELEMENTS], int *size);  | 
70  |  |  | 
71  |  | typedef void(bulk_rmadd_func)(priority_st *priority_list, const int *);  | 
72  |  |  | 
73  |  | inline static void _set_priority(priority_st *st, const int *list)  | 
74  | 0  | { | 
75  | 0  |   int num = 0, i;  | 
76  |  | 
  | 
77  | 0  |   while (list[num] != 0)  | 
78  | 0  |     num++;  | 
79  | 0  |   if (num > MAX_ALGOS)  | 
80  | 0  |     num = MAX_ALGOS;  | 
81  | 0  |   st->num_priorities = num;  | 
82  |  | 
  | 
83  | 0  |   for (i = 0; i < num; i++) { | 
84  | 0  |     st->priorities[i] = list[i];  | 
85  | 0  |   }  | 
86  |  | 
  | 
87  | 0  |   return;  | 
88  | 0  | }  | 
89  |  |  | 
90  |  | inline static void _add_priority(priority_st *st, const int *list)  | 
91  | 0  | { | 
92  | 0  |   int num, i, j, init;  | 
93  |  | 
  | 
94  | 0  |   init = i = st->num_priorities;  | 
95  |  | 
  | 
96  | 0  |   for (num = 0; list[num] != 0; ++num) { | 
97  | 0  |     if (i + 1 > MAX_ALGOS) { | 
98  | 0  |       return;  | 
99  | 0  |     }  | 
100  |  |  | 
101  | 0  |     for (j = 0; j < init; j++) { | 
102  | 0  |       if (st->priorities[j] == (unsigned)list[num]) { | 
103  | 0  |         break;  | 
104  | 0  |       }  | 
105  | 0  |     }  | 
106  |  | 
  | 
107  | 0  |     if (j == init) { | 
108  | 0  |       st->priorities[i++] = list[num];  | 
109  | 0  |       st->num_priorities++;  | 
110  | 0  |     }  | 
111  | 0  |   }  | 
112  |  |  | 
113  | 0  |   return;  | 
114  | 0  | }  | 
115  |  |  | 
116  |  | static void _clear_priorities(priority_st *st, const int *list)  | 
117  | 0  | { | 
118  | 0  |   memset(st, 0, sizeof(*st));  | 
119  | 0  | }  | 
120  |  |  | 
121  |  | static void _clear_given_priorities(priority_st *st, const int *list)  | 
122  | 0  | { | 
123  | 0  |   unsigned i;  | 
124  |  | 
  | 
125  | 0  |   for (i = 0; list[i] != 0; i++) { | 
126  | 0  |     prio_remove(st, list[i]);  | 
127  | 0  |   }  | 
128  | 0  | }  | 
129  |  |  | 
130  |  | static const int _supported_groups_dh[] = { | 
131  |  |   GNUTLS_GROUP_FFDHE2048, GNUTLS_GROUP_FFDHE3072, GNUTLS_GROUP_FFDHE4096,  | 
132  |  |   GNUTLS_GROUP_FFDHE6144, GNUTLS_GROUP_FFDHE8192, 0  | 
133  |  | };  | 
134  |  |  | 
135  |  | static const int _supported_groups_ecdh[] = { GNUTLS_GROUP_SECP256R1, | 
136  |  |                 GNUTLS_GROUP_SECP384R1,  | 
137  |  |                 GNUTLS_GROUP_SECP521R1,  | 
138  |  |                 GNUTLS_GROUP_X25519, /* RFC 8422 */  | 
139  |  |                 GNUTLS_GROUP_X448, /* RFC 8422 */  | 
140  |  |                 0 };  | 
141  |  |  | 
142  |  | static const int _supported_groups_gost[] = { | 
143  |  | #ifdef ENABLE_GOST  | 
144  |  |   GNUTLS_GROUP_GC256A,  | 
145  |  |   GNUTLS_GROUP_GC256B,  | 
146  |  |   GNUTLS_GROUP_GC256C,  | 
147  |  |   GNUTLS_GROUP_GC256D,  | 
148  |  |   GNUTLS_GROUP_GC512A,  | 
149  |  |   GNUTLS_GROUP_GC512B,  | 
150  |  |   GNUTLS_GROUP_GC512C,  | 
151  |  | #endif  | 
152  |  |   0  | 
153  |  | };  | 
154  |  |  | 
155  |  | static const int _supported_groups_normal[] = { | 
156  |  |   GNUTLS_GROUP_SECP256R1, GNUTLS_GROUP_SECP384R1, GNUTLS_GROUP_SECP521R1,  | 
157  |  |   GNUTLS_GROUP_X25519, /* RFC 8422 */  | 
158  |  |   GNUTLS_GROUP_X448, /* RFC 8422 */  | 
159  |  |  | 
160  |  |   /* These should stay last as our default behavior  | 
161  |  |    * is to send key shares for two top types (GNUTLS_KEY_SHARE_TOP2)  | 
162  |  |    * and we wouldn't want to have these sent by all clients  | 
163  |  |    * by default as they are quite expensive CPU-wise. */  | 
164  |  |   GNUTLS_GROUP_FFDHE2048, GNUTLS_GROUP_FFDHE3072, GNUTLS_GROUP_FFDHE4096,  | 
165  |  |   GNUTLS_GROUP_FFDHE6144, GNUTLS_GROUP_FFDHE8192, 0  | 
166  |  | };  | 
167  |  |  | 
168  |  | static const int *supported_groups_normal = _supported_groups_normal;  | 
169  |  |  | 
170  |  | static const int _supported_groups_secure128[] = { | 
171  |  |   GNUTLS_GROUP_SECP256R1, GNUTLS_GROUP_SECP384R1, GNUTLS_GROUP_SECP521R1,  | 
172  |  |   GNUTLS_GROUP_X25519, /* RFC 8422 */  | 
173  |  |   GNUTLS_GROUP_X448, /* RFC 8422 */  | 
174  |  |   GNUTLS_GROUP_FFDHE2048, GNUTLS_GROUP_FFDHE3072, GNUTLS_GROUP_FFDHE4096,  | 
175  |  |   GNUTLS_GROUP_FFDHE6144, GNUTLS_GROUP_FFDHE8192, 0  | 
176  |  | };  | 
177  |  |  | 
178  |  | static const int *supported_groups_secure128 = _supported_groups_secure128;  | 
179  |  |  | 
180  |  | static const int _supported_groups_suiteb128[] = { GNUTLS_GROUP_SECP256R1, | 
181  |  |                GNUTLS_GROUP_SECP384R1, 0 };  | 
182  |  |  | 
183  |  | static const int *supported_groups_suiteb128 = _supported_groups_suiteb128;  | 
184  |  |  | 
185  |  | static const int _supported_groups_suiteb192[] = { GNUTLS_GROUP_SECP384R1, 0 }; | 
186  |  |  | 
187  |  | static const int *supported_groups_suiteb192 = _supported_groups_suiteb192;  | 
188  |  |  | 
189  |  | static const int _supported_groups_secure192[] = { GNUTLS_GROUP_SECP384R1, | 
190  |  |                GNUTLS_GROUP_SECP521R1,  | 
191  |  |                GNUTLS_GROUP_FFDHE8192, 0 };  | 
192  |  |  | 
193  |  | static const int *supported_groups_secure192 = _supported_groups_secure192;  | 
194  |  |  | 
195  |  | static const int protocol_priority[] = { GNUTLS_TLS1_3, | 
196  |  |            GNUTLS_TLS1_2,  | 
197  |  |            GNUTLS_TLS1_1,  | 
198  |  |            GNUTLS_TLS1_0,  | 
199  |  |            GNUTLS_DTLS1_2,  | 
200  |  |            GNUTLS_DTLS1_0,  | 
201  |  |            0 };  | 
202  |  |  | 
203  |  | /* contains all the supported TLS protocols, intended to be used for eliminating them  | 
204  |  |  */  | 
205  |  | static const int stream_protocol_priority[] = { GNUTLS_TLS1_3, GNUTLS_TLS1_2, | 
206  |  |             GNUTLS_TLS1_1, GNUTLS_TLS1_0,  | 
207  |  |             0 };  | 
208  |  |  | 
209  |  | /* contains all the supported DTLS protocols, intended to be used for eliminating them  | 
210  |  |  */  | 
211  |  | static const int dgram_protocol_priority[] = { GNUTLS_DTLS1_2, GNUTLS_DTLS1_0, | 
212  |  |                  GNUTLS_DTLS0_9, 0 };  | 
213  |  |  | 
214  |  | static const int dtls_protocol_priority[] = { GNUTLS_DTLS1_2, GNUTLS_DTLS1_0, | 
215  |  |                 0 };  | 
216  |  |  | 
217  |  | static const int _protocol_priority_suiteb[] = { GNUTLS_TLS1_2, 0 }; | 
218  |  |  | 
219  |  | static const int *protocol_priority_suiteb = _protocol_priority_suiteb;  | 
220  |  |  | 
221  |  | static const int _kx_priority_performance[] = { GNUTLS_KX_RSA, | 
222  |  | #ifdef ENABLE_ECDHE  | 
223  |  |             GNUTLS_KX_ECDHE_ECDSA,  | 
224  |  |             GNUTLS_KX_ECDHE_RSA,  | 
225  |  | #endif  | 
226  |  | #ifdef ENABLE_DHE  | 
227  |  |             GNUTLS_KX_DHE_RSA,  | 
228  |  | #endif  | 
229  |  |             0 };  | 
230  |  |  | 
231  |  | static const int *kx_priority_performance = _kx_priority_performance;  | 
232  |  |  | 
233  |  | static const int _kx_priority_pfs[] = { | 
234  |  | #ifdef ENABLE_ECDHE  | 
235  |  |   GNUTLS_KX_ECDHE_ECDSA, GNUTLS_KX_ECDHE_RSA,  | 
236  |  | #endif  | 
237  |  | #ifdef ENABLE_DHE  | 
238  |  |   GNUTLS_KX_DHE_RSA,  | 
239  |  | #endif  | 
240  |  |   0  | 
241  |  | };  | 
242  |  |  | 
243  |  | static const int *kx_priority_pfs = _kx_priority_pfs;  | 
244  |  |  | 
245  |  | static const int _kx_priority_suiteb[] = { GNUTLS_KX_ECDHE_ECDSA, 0 }; | 
246  |  |  | 
247  |  | static const int *kx_priority_suiteb = _kx_priority_suiteb;  | 
248  |  |  | 
249  |  | static const int _kx_priority_secure[] = { | 
250  |  | /* The ciphersuites that offer forward secrecy take  | 
251  |  |    * precedence  | 
252  |  |    */  | 
253  |  | #ifdef ENABLE_ECDHE  | 
254  |  |   GNUTLS_KX_ECDHE_ECDSA, GNUTLS_KX_ECDHE_RSA,  | 
255  |  | #endif  | 
256  |  |   GNUTLS_KX_RSA,  | 
257  |  | /* KX-RSA is now ahead of DHE-RSA and DHE-DSS due to the compatibility  | 
258  |  |    * issues the DHE ciphersuites have. That is, one cannot enforce a specific  | 
259  |  |    * security level without dropping the connection.  | 
260  |  |    */  | 
261  |  | #ifdef ENABLE_DHE  | 
262  |  |   GNUTLS_KX_DHE_RSA,  | 
263  |  | #endif  | 
264  |  |   /* GNUTLS_KX_ANON_DH: Man-in-the-middle prone, don't add!  | 
265  |  |    */  | 
266  |  |   0  | 
267  |  | };  | 
268  |  |  | 
269  |  | static const int *kx_priority_secure = _kx_priority_secure;  | 
270  |  |  | 
271  |  | static const int _kx_priority_gost[] = { | 
272  |  | #ifdef ENABLE_GOST  | 
273  |  |   GNUTLS_KX_VKO_GOST_12,  | 
274  |  | #endif  | 
275  |  |   0,  | 
276  |  | };  | 
277  |  |  | 
278  |  | static const int *kx_priority_gost = _kx_priority_gost;  | 
279  |  |  | 
280  |  | static const int _cipher_priority_performance_default[] = { | 
281  |  |   GNUTLS_CIPHER_AES_128_GCM,   GNUTLS_CIPHER_AES_256_GCM,  | 
282  |  |   GNUTLS_CIPHER_CHACHA20_POLY1305, GNUTLS_CIPHER_AES_128_CCM,  | 
283  |  |   GNUTLS_CIPHER_AES_256_CCM,   GNUTLS_CIPHER_AES_128_CBC,  | 
284  |  |   GNUTLS_CIPHER_AES_256_CBC,   0  | 
285  |  | };  | 
286  |  |  | 
287  |  | static const int _cipher_priority_performance_no_aesni[] = { | 
288  |  |   GNUTLS_CIPHER_CHACHA20_POLY1305, GNUTLS_CIPHER_AES_128_GCM,  | 
289  |  |   GNUTLS_CIPHER_AES_256_GCM,   GNUTLS_CIPHER_AES_128_CCM,  | 
290  |  |   GNUTLS_CIPHER_AES_256_CCM,   GNUTLS_CIPHER_AES_128_CBC,  | 
291  |  |   GNUTLS_CIPHER_AES_256_CBC,   0  | 
292  |  | };  | 
293  |  |  | 
294  |  | /* If GCM and AES acceleration is available then prefer  | 
295  |  |  * them over anything else. Overall we prioritise AEAD  | 
296  |  |  * over legacy ciphers, and 256-bit over 128 (for future  | 
297  |  |  * proof).  | 
298  |  |  */  | 
299  |  | static const int _cipher_priority_normal_default[] = { | 
300  |  |   GNUTLS_CIPHER_AES_256_GCM, GNUTLS_CIPHER_CHACHA20_POLY1305,  | 
301  |  |   GNUTLS_CIPHER_AES_256_CCM,  | 
302  |  |  | 
303  |  |   GNUTLS_CIPHER_AES_256_CBC,  | 
304  |  |  | 
305  |  |   GNUTLS_CIPHER_AES_128_GCM, GNUTLS_CIPHER_AES_128_CCM,  | 
306  |  |  | 
307  |  |   GNUTLS_CIPHER_AES_128_CBC, 0  | 
308  |  | };  | 
309  |  |  | 
310  |  | static const int cipher_priority_performance_fips[] = { | 
311  |  |   GNUTLS_CIPHER_AES_128_GCM,  | 
312  |  |   GNUTLS_CIPHER_AES_128_CCM,  | 
313  |  |   GNUTLS_CIPHER_AES_256_GCM,  | 
314  |  |   GNUTLS_CIPHER_AES_256_CCM,  | 
315  |  |  | 
316  |  |   GNUTLS_CIPHER_AES_128_CBC,  | 
317  |  |   GNUTLS_CIPHER_AES_256_CBC,  | 
318  |  |   0  | 
319  |  | };  | 
320  |  |  | 
321  |  | static const int cipher_priority_normal_fips[] = { | 
322  |  |   GNUTLS_CIPHER_AES_256_GCM, GNUTLS_CIPHER_AES_256_CCM,  | 
323  |  |   GNUTLS_CIPHER_AES_256_CBC,  | 
324  |  |  | 
325  |  |   GNUTLS_CIPHER_AES_128_GCM, GNUTLS_CIPHER_AES_128_CBC,  | 
326  |  |   GNUTLS_CIPHER_AES_128_CCM, 0  | 
327  |  | };  | 
328  |  |  | 
329  |  | static const int _cipher_priority_suiteb128[] = { GNUTLS_CIPHER_AES_256_GCM, | 
330  |  |               GNUTLS_CIPHER_AES_128_GCM,  | 
331  |  |               0 };  | 
332  |  |  | 
333  |  | static const int *cipher_priority_suiteb128 = _cipher_priority_suiteb128;  | 
334  |  |  | 
335  |  | static const int _cipher_priority_suiteb192[] = { GNUTLS_CIPHER_AES_256_GCM, | 
336  |  |               0 };  | 
337  |  |  | 
338  |  | static const int *cipher_priority_suiteb192 = _cipher_priority_suiteb192;  | 
339  |  |  | 
340  |  | static const int _cipher_priority_secure128[] = { | 
341  |  |   GNUTLS_CIPHER_AES_256_GCM, GNUTLS_CIPHER_CHACHA20_POLY1305,  | 
342  |  |   GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_AES_256_CCM,  | 
343  |  |  | 
344  |  |   GNUTLS_CIPHER_AES_128_GCM, GNUTLS_CIPHER_AES_128_CBC,  | 
345  |  |   GNUTLS_CIPHER_AES_128_CCM, 0  | 
346  |  | };  | 
347  |  |  | 
348  |  | static const int *cipher_priority_secure128 = _cipher_priority_secure128;  | 
349  |  |  | 
350  |  | static const int _cipher_priority_secure192[] = { | 
351  |  |   GNUTLS_CIPHER_AES_256_GCM, GNUTLS_CIPHER_CHACHA20_POLY1305,  | 
352  |  |   GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_AES_256_CCM, 0  | 
353  |  | };  | 
354  |  |  | 
355  |  | static const int *cipher_priority_secure192 = _cipher_priority_secure192;  | 
356  |  |  | 
357  |  | static const int _sign_priority_default[] = { | 
358  |  |   GNUTLS_SIGN_RSA_SHA256,  | 
359  |  |   GNUTLS_SIGN_RSA_PSS_SHA256,  | 
360  |  |   GNUTLS_SIGN_RSA_PSS_RSAE_SHA256,  | 
361  |  |   GNUTLS_SIGN_ECDSA_SHA256,  | 
362  |  |   GNUTLS_SIGN_ECDSA_SECP256R1_SHA256,  | 
363  |  |  | 
364  |  |   GNUTLS_SIGN_EDDSA_ED25519,  | 
365  |  |  | 
366  |  |   GNUTLS_SIGN_RSA_SHA384,  | 
367  |  |   GNUTLS_SIGN_RSA_PSS_SHA384,  | 
368  |  |   GNUTLS_SIGN_RSA_PSS_RSAE_SHA384,  | 
369  |  |   GNUTLS_SIGN_ECDSA_SHA384,  | 
370  |  |   GNUTLS_SIGN_ECDSA_SECP384R1_SHA384,  | 
371  |  |  | 
372  |  |   GNUTLS_SIGN_EDDSA_ED448,  | 
373  |  |  | 
374  |  |   GNUTLS_SIGN_RSA_SHA512,  | 
375  |  |   GNUTLS_SIGN_RSA_PSS_SHA512,  | 
376  |  |   GNUTLS_SIGN_RSA_PSS_RSAE_SHA512,  | 
377  |  |  | 
378  |  |   GNUTLS_SIGN_ECDSA_SHA512,  | 
379  |  |   GNUTLS_SIGN_ECDSA_SECP521R1_SHA512,  | 
380  |  |  | 
381  |  |   GNUTLS_SIGN_RSA_SHA1,  | 
382  |  |   GNUTLS_SIGN_ECDSA_SHA1,  | 
383  |  |  | 
384  |  |   0  | 
385  |  | };  | 
386  |  |  | 
387  |  | static const int *sign_priority_default = _sign_priority_default;  | 
388  |  |  | 
389  |  | static const int _sign_priority_suiteb128[] = { | 
390  |  |   GNUTLS_SIGN_ECDSA_SHA256, GNUTLS_SIGN_ECDSA_SECP256R1_SHA256,  | 
391  |  |   GNUTLS_SIGN_ECDSA_SHA384, GNUTLS_SIGN_ECDSA_SECP384R1_SHA384, 0  | 
392  |  | };  | 
393  |  |  | 
394  |  | static const int *sign_priority_suiteb128 = _sign_priority_suiteb128;  | 
395  |  |  | 
396  |  | static const int _sign_priority_suiteb192[] = { | 
397  |  |   GNUTLS_SIGN_ECDSA_SHA384, GNUTLS_SIGN_ECDSA_SECP384R1_SHA384, 0  | 
398  |  | };  | 
399  |  |  | 
400  |  | static const int *sign_priority_suiteb192 = _sign_priority_suiteb192;  | 
401  |  |  | 
402  |  | static const int _sign_priority_secure128[] = { | 
403  |  |   GNUTLS_SIGN_RSA_SHA256,  | 
404  |  |   GNUTLS_SIGN_RSA_PSS_SHA256,  | 
405  |  |   GNUTLS_SIGN_RSA_PSS_RSAE_SHA256,  | 
406  |  |   GNUTLS_SIGN_ECDSA_SHA256,  | 
407  |  |   GNUTLS_SIGN_ECDSA_SECP256R1_SHA256,  | 
408  |  |  | 
409  |  |   GNUTLS_SIGN_EDDSA_ED25519,  | 
410  |  |  | 
411  |  |   GNUTLS_SIGN_RSA_SHA384,  | 
412  |  |   GNUTLS_SIGN_RSA_PSS_SHA384,  | 
413  |  |   GNUTLS_SIGN_RSA_PSS_RSAE_SHA384,  | 
414  |  |   GNUTLS_SIGN_ECDSA_SHA384,  | 
415  |  |   GNUTLS_SIGN_ECDSA_SECP384R1_SHA384,  | 
416  |  |  | 
417  |  |   GNUTLS_SIGN_EDDSA_ED448,  | 
418  |  |  | 
419  |  |   GNUTLS_SIGN_RSA_SHA512,  | 
420  |  |   GNUTLS_SIGN_RSA_PSS_SHA512,  | 
421  |  |   GNUTLS_SIGN_RSA_PSS_RSAE_SHA512,  | 
422  |  |   GNUTLS_SIGN_ECDSA_SHA512,  | 
423  |  |   GNUTLS_SIGN_ECDSA_SECP521R1_SHA512,  | 
424  |  |  | 
425  |  |   0  | 
426  |  | };  | 
427  |  |  | 
428  |  | static const int *sign_priority_secure128 = _sign_priority_secure128;  | 
429  |  |  | 
430  |  | static const int _sign_priority_secure192[] = { | 
431  |  |   GNUTLS_SIGN_RSA_SHA384,  | 
432  |  |   GNUTLS_SIGN_RSA_PSS_SHA384,  | 
433  |  |   GNUTLS_SIGN_RSA_PSS_RSAE_SHA384,  | 
434  |  |   GNUTLS_SIGN_ECDSA_SHA384,  | 
435  |  |   GNUTLS_SIGN_ECDSA_SECP384R1_SHA384,  | 
436  |  |   GNUTLS_SIGN_EDDSA_ED448,  | 
437  |  |   GNUTLS_SIGN_RSA_SHA512,  | 
438  |  |   GNUTLS_SIGN_RSA_PSS_SHA512,  | 
439  |  |   GNUTLS_SIGN_RSA_PSS_RSAE_SHA512,  | 
440  |  |   GNUTLS_SIGN_ECDSA_SHA512,  | 
441  |  |   GNUTLS_SIGN_ECDSA_SECP521R1_SHA512,  | 
442  |  |  | 
443  |  |   0  | 
444  |  | };  | 
445  |  |  | 
446  |  | static const int *sign_priority_secure192 = _sign_priority_secure192;  | 
447  |  |  | 
448  |  | static const int _sign_priority_gost[] = { | 
449  |  | #ifdef ENABLE_GOST  | 
450  |  |   GNUTLS_SIGN_GOST_256, GNUTLS_SIGN_GOST_512,  | 
451  |  | #endif  | 
452  |  |   0  | 
453  |  | };  | 
454  |  |  | 
455  |  | static const int *sign_priority_gost = _sign_priority_gost;  | 
456  |  |  | 
457  |  | static const int mac_priority_normal_default[] = { GNUTLS_MAC_SHA1, | 
458  |  |                GNUTLS_MAC_AEAD, 0 };  | 
459  |  |  | 
460  |  | static const int mac_priority_normal_fips[] = { GNUTLS_MAC_SHA1, | 
461  |  |             GNUTLS_MAC_AEAD, 0 };  | 
462  |  |  | 
463  |  | static const int *cipher_priority_performance =  | 
464  |  |   _cipher_priority_performance_default;  | 
465  |  | static const int *cipher_priority_normal = _cipher_priority_normal_default;  | 
466  |  | static const int *mac_priority_normal = mac_priority_normal_default;  | 
467  |  |  | 
468  |  | static const int _cipher_priority_gost[] = { | 
469  |  | #ifdef ENABLE_GOST  | 
470  |  |   GNUTLS_CIPHER_GOST28147_TC26Z_CNT,  | 
471  |  | #endif  | 
472  |  |   0  | 
473  |  | };  | 
474  |  |  | 
475  |  | static const int *cipher_priority_gost = _cipher_priority_gost;  | 
476  |  |  | 
477  |  | static const int _mac_priority_gost[] = { | 
478  |  | #ifdef ENABLE_GOST  | 
479  |  |   GNUTLS_MAC_GOST28147_TC26Z_IMIT,  | 
480  |  | #endif  | 
481  |  |   0  | 
482  |  | };  | 
483  |  |  | 
484  |  | static const int *mac_priority_gost = _mac_priority_gost;  | 
485  |  |  | 
486  |  | /* if called with replace the default priorities with the FIPS140 ones */  | 
487  |  | void _gnutls_priority_update_fips(void)  | 
488  | 0  | { | 
489  | 0  |   cipher_priority_performance = cipher_priority_performance_fips;  | 
490  | 0  |   cipher_priority_normal = cipher_priority_normal_fips;  | 
491  | 0  |   mac_priority_normal = mac_priority_normal_fips;  | 
492  | 0  | }  | 
493  |  |  | 
494  |  | void _gnutls_priority_update_non_aesni(void)  | 
495  | 0  | { | 
496  |  |   /* if we have no AES acceleration in performance mode  | 
497  |  |    * prefer fast stream ciphers */  | 
498  | 0  |   if (_gnutls_fips_mode_enabled() == 0) { | 
499  | 0  |     cipher_priority_performance =  | 
500  | 0  |       _cipher_priority_performance_no_aesni;  | 
501  | 0  |   }  | 
502  | 0  | }  | 
503  |  |  | 
504  |  | static const int _mac_priority_suiteb[] = { GNUTLS_MAC_AEAD, 0 }; | 
505  |  |  | 
506  |  | static const int *mac_priority_suiteb = _mac_priority_suiteb;  | 
507  |  |  | 
508  |  | static const int _mac_priority_secure128[] = { GNUTLS_MAC_SHA1, GNUTLS_MAC_AEAD, | 
509  |  |                  0 };  | 
510  |  |  | 
511  |  | static const int *mac_priority_secure128 = _mac_priority_secure128;  | 
512  |  |  | 
513  |  | static const int _mac_priority_secure192[] = { GNUTLS_MAC_AEAD, 0 }; | 
514  |  |  | 
515  |  | static const int *mac_priority_secure192 = _mac_priority_secure192;  | 
516  |  |  | 
517  |  | static const int cert_type_priority_default[] = { GNUTLS_CRT_X509, 0 }; | 
518  |  |  | 
519  |  | static const int cert_type_priority_all[] = { GNUTLS_CRT_X509, GNUTLS_CRT_RAWPK, | 
520  |  |                 0 };  | 
521  |  |  | 
522  |  | typedef void(rmadd_func)(priority_st *priority_list, unsigned int alg);  | 
523  |  |  | 
524  |  | static void prio_remove(priority_st *priority_list, unsigned int algo)  | 
525  | 0  | { | 
526  | 0  |   unsigned int i;  | 
527  |  | 
  | 
528  | 0  |   for (i = 0; i < priority_list->num_priorities; i++) { | 
529  | 0  |     if (priority_list->priorities[i] == algo) { | 
530  | 0  |       priority_list->num_priorities--;  | 
531  | 0  |       if ((priority_list->num_priorities - i) > 0)  | 
532  | 0  |         memmove(&priority_list->priorities[i],  | 
533  | 0  |           &priority_list->priorities[i + 1],  | 
534  | 0  |           (priority_list->num_priorities -  | 
535  | 0  |            i) * sizeof(priority_list  | 
536  | 0  |                    ->priorities[0]));  | 
537  | 0  |       priority_list  | 
538  | 0  |         ->priorities[priority_list->num_priorities] = 0;  | 
539  | 0  |       break;  | 
540  | 0  |     }  | 
541  | 0  |   }  | 
542  |  | 
  | 
543  | 0  |   return;  | 
544  | 0  | }  | 
545  |  |  | 
546  |  | static void prio_add(priority_st *priority_list, unsigned int algo)  | 
547  | 0  | { | 
548  | 0  |   unsigned int i, l = priority_list->num_priorities;  | 
549  |  | 
  | 
550  | 0  |   if (l >= MAX_ALGOS)  | 
551  | 0  |     return; /* can't add it anyway */  | 
552  |  |  | 
553  | 0  |   for (i = 0; i < l; ++i) { | 
554  | 0  |     if (algo == priority_list->priorities[i])  | 
555  | 0  |       return; /* if it exists */  | 
556  | 0  |   }  | 
557  |  |  | 
558  | 0  |   priority_list->priorities[l] = algo;  | 
559  | 0  |   priority_list->num_priorities++;  | 
560  |  | 
  | 
561  | 0  |   return;  | 
562  | 0  | }  | 
563  |  |  | 
564  |  | /**  | 
565  |  |  * gnutls_priority_set:  | 
566  |  |  * @session: is a #gnutls_session_t type.  | 
567  |  |  * @priority: is a #gnutls_priority_t type.  | 
568  |  |  *  | 
569  |  |  * Sets the priorities to use on the ciphers, key exchange methods,  | 
570  |  |  * and macs. Note that this function is expected to be called once  | 
571  |  |  * per session; when called multiple times (e.g., before a re-handshake,  | 
572  |  |  * the caller should make sure that any new settings are not incompatible  | 
573  |  |  * with the original session).  | 
574  |  |  *  | 
575  |  |  * Returns: %GNUTLS_E_SUCCESS on success, or an error code on error.  | 
576  |  |  **/  | 
577  |  | int gnutls_priority_set(gnutls_session_t session, gnutls_priority_t priority)  | 
578  | 0  | { | 
579  | 0  |   int ret;  | 
580  |  | 
  | 
581  | 0  |   if (priority == NULL || priority->protocol.num_priorities == 0 ||  | 
582  | 0  |       priority->cs.size == 0)  | 
583  | 0  |     return gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET);  | 
584  |  |  | 
585  |  |   /* set the current version to the first in the chain, if this is  | 
586  |  |    * the call before the initial handshake. During a re-handshake  | 
587  |  |    * we do not set the version to avoid overriding the currently  | 
588  |  |    * negotiated version. */  | 
589  | 0  |   if (!session->internals.handshake_in_progress &&  | 
590  | 0  |       !session->internals.initial_negotiation_completed) { | 
591  | 0  |     ret = _gnutls_set_current_version(  | 
592  | 0  |       session, priority->protocol.priorities[0]);  | 
593  | 0  |     if (ret < 0)  | 
594  | 0  |       return gnutls_assert_val(ret);  | 
595  | 0  |   }  | 
596  |  |  | 
597  |  |   /* At this point the provided priorities passed the sanity tests */  | 
598  |  |  | 
599  | 0  |   if (session->internals.priorities)  | 
600  | 0  |     gnutls_priority_deinit(session->internals.priorities);  | 
601  |  | 
  | 
602  | 0  |   gnutls_atomic_increment(&priority->usage_cnt);  | 
603  | 0  |   session->internals.priorities = priority;  | 
604  |  | 
  | 
605  | 0  |   if (priority->no_tickets != 0) { | 
606  | 0  |     session->internals.flags |= GNUTLS_NO_TICKETS;  | 
607  | 0  |   }  | 
608  |  | 
  | 
609  | 0  |   if (priority->no_tickets_tls12 != 0) { | 
610  |  |     /* when PFS is explicitly requested, disable session tickets for TLS 1.2 */  | 
611  | 0  |     session->internals.flags |= GNUTLS_NO_TICKETS_TLS12;  | 
612  | 0  |   }  | 
613  |  | 
  | 
614  | 0  |   if (priority->no_status_request)  | 
615  | 0  |     session->internals.flags |= GNUTLS_NO_STATUS_REQUEST;  | 
616  |  | 
  | 
617  | 0  |   ADD_PROFILE_VFLAGS(session, priority->additional_verify_flags);  | 
618  |  |  | 
619  |  |   /* mirror variables */  | 
620  | 0  | #undef COPY_TO_INTERNALS  | 
621  | 0  | #define COPY_TO_INTERNALS(xx) session->internals.xx = priority->_##xx  | 
622  | 0  |   COPY_TO_INTERNALS(allow_large_records);  | 
623  | 0  |   COPY_TO_INTERNALS(allow_small_records);  | 
624  | 0  |   COPY_TO_INTERNALS(no_etm);  | 
625  | 0  |   COPY_TO_INTERNALS(no_ext_master_secret);  | 
626  | 0  |   COPY_TO_INTERNALS(allow_key_usage_violation);  | 
627  | 0  |   COPY_TO_INTERNALS(dumbfw);  | 
628  | 0  |   COPY_TO_INTERNALS(dh_prime_bits);  | 
629  |  | 
  | 
630  | 0  |   return 0;  | 
631  | 0  | }  | 
632  |  |  | 
633  | 0  | #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_LEGACY "LEGACY"  | 
643  | 0  | #define LEVEL_SYSTEM "SYSTEM"  | 
644  |  |  | 
645  |  | struct priority_groups_st { | 
646  |  |   const char *name;  | 
647  |  |   const char *alias;  | 
648  |  |   const int **proto_list;  | 
649  |  |   const int **cipher_list;  | 
650  |  |   const int **mac_list;  | 
651  |  |   const int **kx_list;  | 
652  |  |   const int **sign_list;  | 
653  |  |   const int **group_list;  | 
654  |  |   unsigned profile;  | 
655  |  |   int sec_param;  | 
656  |  |   bool no_tickets;  | 
657  |  |   bool no_tickets_tls12;  | 
658  |  | };  | 
659  |  |  | 
660  |  | static const struct priority_groups_st pgroups[] = { | 
661  |  |   { .name = LEVEL_NORMAL, | 
662  |  |     .cipher_list = &cipher_priority_normal,  | 
663  |  |     .mac_list = &mac_priority_normal,  | 
664  |  |     .kx_list = &kx_priority_secure,  | 
665  |  |     .sign_list = &sign_priority_default,  | 
666  |  |     .group_list = &supported_groups_normal,  | 
667  |  |     .profile = GNUTLS_PROFILE_LOW,  | 
668  |  |     .sec_param = GNUTLS_SEC_PARAM_WEAK },  | 
669  |  |   { .name = LEVEL_PFS, | 
670  |  |     .cipher_list = &cipher_priority_normal,  | 
671  |  |     .mac_list = &mac_priority_secure128,  | 
672  |  |     .kx_list = &kx_priority_pfs,  | 
673  |  |     .sign_list = &sign_priority_default,  | 
674  |  |     .group_list = &supported_groups_normal,  | 
675  |  |     .profile = GNUTLS_PROFILE_LOW,  | 
676  |  |     .sec_param = GNUTLS_SEC_PARAM_WEAK,  | 
677  |  |     .no_tickets_tls12 = 1 },  | 
678  |  |   { .name = LEVEL_SECURE128, | 
679  |  |     .alias = "SECURE",  | 
680  |  |     .cipher_list = &cipher_priority_secure128,  | 
681  |  |     .mac_list = &mac_priority_secure128,  | 
682  |  |     .kx_list = &kx_priority_secure,  | 
683  |  |     .sign_list = &sign_priority_secure128,  | 
684  |  |     .group_list = &supported_groups_secure128,  | 
685  |  |     /* The profile should have been HIGH but if we don't allow  | 
686  |  |     * SHA-1 (80-bits) as signature algorithm we are not able  | 
687  |  |     * to connect anywhere with this level */  | 
688  |  |     .profile = GNUTLS_PROFILE_LOW,  | 
689  |  |     .sec_param = GNUTLS_SEC_PARAM_LOW },  | 
690  |  |   { .name = LEVEL_SECURE192, | 
691  |  |     .alias = LEVEL_SECURE256,  | 
692  |  |     .cipher_list = &cipher_priority_secure192,  | 
693  |  |     .mac_list = &mac_priority_secure192,  | 
694  |  |     .kx_list = &kx_priority_secure,  | 
695  |  |     .sign_list = &sign_priority_secure192,  | 
696  |  |     .group_list = &supported_groups_secure192,  | 
697  |  |     .profile = GNUTLS_PROFILE_HIGH,  | 
698  |  |     .sec_param = GNUTLS_SEC_PARAM_HIGH },  | 
699  |  |   { .name = LEVEL_SUITEB128, | 
700  |  |     .proto_list = &protocol_priority_suiteb,  | 
701  |  |     .cipher_list = &cipher_priority_suiteb128,  | 
702  |  |     .mac_list = &mac_priority_suiteb,  | 
703  |  |     .kx_list = &kx_priority_suiteb,  | 
704  |  |     .sign_list = &sign_priority_suiteb128,  | 
705  |  |     .group_list = &supported_groups_suiteb128,  | 
706  |  |     .profile = GNUTLS_PROFILE_SUITEB128,  | 
707  |  |     .sec_param = GNUTLS_SEC_PARAM_HIGH },  | 
708  |  |   { .name = LEVEL_SUITEB192, | 
709  |  |     .proto_list = &protocol_priority_suiteb,  | 
710  |  |     .cipher_list = &cipher_priority_suiteb192,  | 
711  |  |     .mac_list = &mac_priority_suiteb,  | 
712  |  |     .kx_list = &kx_priority_suiteb,  | 
713  |  |     .sign_list = &sign_priority_suiteb192,  | 
714  |  |     .group_list = &supported_groups_suiteb192,  | 
715  |  |     .profile = GNUTLS_PROFILE_SUITEB192,  | 
716  |  |     .sec_param = GNUTLS_SEC_PARAM_ULTRA },  | 
717  |  |   { .name = LEVEL_LEGACY, | 
718  |  |     .cipher_list = &cipher_priority_normal,  | 
719  |  |     .mac_list = &mac_priority_normal,  | 
720  |  |     .kx_list = &kx_priority_secure,  | 
721  |  |     .sign_list = &sign_priority_default,  | 
722  |  |     .group_list = &supported_groups_normal,  | 
723  |  |     .sec_param = GNUTLS_SEC_PARAM_VERY_WEAK },  | 
724  |  |   { .name = LEVEL_PERFORMANCE, | 
725  |  |     .cipher_list = &cipher_priority_performance,  | 
726  |  |     .mac_list = &mac_priority_normal,  | 
727  |  |     .kx_list = &kx_priority_performance,  | 
728  |  |     .sign_list = &sign_priority_default,  | 
729  |  |     .group_list = &supported_groups_normal,  | 
730  |  |     .profile = GNUTLS_PROFILE_LOW,  | 
731  |  |     .sec_param = GNUTLS_SEC_PARAM_WEAK },  | 
732  |  |   { | 
733  |  |     .name = NULL,  | 
734  |  |   }  | 
735  |  | };  | 
736  |  |  | 
737  |  | #define SET_PROFILE(to_set)                                \  | 
738  | 0  |   profile = GNUTLS_VFLAGS_TO_PROFILE(                \  | 
739  | 0  |     priority_cache->additional_verify_flags);  \  | 
740  | 0  |   if (profile == 0 || profile > to_set) {            \ | 
741  | 0  |     priority_cache->additional_verify_flags &= \  | 
742  | 0  |       ~GNUTLS_VFLAGS_PROFILE_MASK;       \  | 
743  | 0  |     priority_cache->additional_verify_flags |= \  | 
744  | 0  |       GNUTLS_PROFILE_TO_VFLAGS(to_set);  \  | 
745  | 0  |   }  | 
746  |  |  | 
747  |  | #define SET_LEVEL(to_set)                                       \  | 
748  | 0  |   if (priority_cache->level == 0 ||                       \  | 
749  | 0  |       (unsigned)priority_cache->level > (unsigned)to_set) \  | 
750  | 0  |   priority_cache->level = to_set  | 
751  |  |  | 
752  |  | static int check_level(const char *level, gnutls_priority_t priority_cache,  | 
753  |  |            int add)  | 
754  | 0  | { | 
755  | 0  |   bulk_rmadd_func *func;  | 
756  | 0  |   unsigned profile = 0;  | 
757  | 0  |   unsigned i;  | 
758  | 0  |   int j;  | 
759  | 0  |   const cipher_entry_st *centry;  | 
760  |  | 
  | 
761  | 0  |   if (add)  | 
762  | 0  |     func = _add_priority;  | 
763  | 0  |   else  | 
764  | 0  |     func = _set_priority;  | 
765  |  | 
  | 
766  | 0  |   for (i = 0;; i++) { | 
767  | 0  |     if (pgroups[i].name == NULL)  | 
768  | 0  |       return 0;  | 
769  |  |  | 
770  | 0  |     if (c_strcasecmp(level, pgroups[i].name) == 0 ||  | 
771  | 0  |         (pgroups[i].alias != NULL &&  | 
772  | 0  |          c_strcasecmp(level, pgroups[i].alias) == 0)) { | 
773  | 0  |       if (pgroups[i].proto_list != NULL)  | 
774  | 0  |         func(&priority_cache->protocol,  | 
775  | 0  |              *pgroups[i].proto_list);  | 
776  | 0  |       func(&priority_cache->_cipher, *pgroups[i].cipher_list);  | 
777  | 0  |       func(&priority_cache->_kx, *pgroups[i].kx_list);  | 
778  | 0  |       func(&priority_cache->_mac, *pgroups[i].mac_list);  | 
779  | 0  |       func(&priority_cache->_sign_algo,  | 
780  | 0  |            *pgroups[i].sign_list);  | 
781  | 0  |       func(&priority_cache->_supported_ecc,  | 
782  | 0  |            *pgroups[i].group_list);  | 
783  |  | 
  | 
784  | 0  |       if (pgroups[i].profile != 0) { | 
785  | 0  |         SET_PROFILE(  | 
786  | 0  |           pgroups[i].profile); /* set certificate level */  | 
787  | 0  |       }  | 
788  | 0  |       SET_LEVEL(  | 
789  | 0  |         pgroups[i].sec_param); /* set DH params level */  | 
790  | 0  |       priority_cache->no_tickets = pgroups[i].no_tickets;  | 
791  | 0  |       priority_cache->no_tickets_tls12 =  | 
792  | 0  |         pgroups[i].no_tickets_tls12;  | 
793  | 0  |       if (priority_cache->have_cbc == 0) { | 
794  | 0  |         for (j = 0; (*pgroups[i].cipher_list)[j] != 0;  | 
795  | 0  |              j++) { | 
796  | 0  |           centry = cipher_to_entry(  | 
797  | 0  |             (*pgroups[i].cipher_list)[j]);  | 
798  | 0  |           if (centry != NULL &&  | 
799  | 0  |               centry->type == CIPHER_BLOCK) { | 
800  | 0  |             priority_cache->have_cbc = 1;  | 
801  | 0  |             break;  | 
802  | 0  |           }  | 
803  | 0  |         }  | 
804  | 0  |       }  | 
805  | 0  |       return 1;  | 
806  | 0  |     }  | 
807  | 0  |   }  | 
808  | 0  | }  | 
809  |  |  | 
810  |  | static void enable_compat(gnutls_priority_t c)  | 
811  | 0  | { | 
812  | 0  |   ENABLE_PRIO_COMPAT(c);  | 
813  | 0  | }  | 
814  |  |  | 
815  |  | static void enable_server_key_usage_violations(gnutls_priority_t c)  | 
816  | 0  | { | 
817  | 0  |   c->allow_server_key_usage_violation = 1;  | 
818  | 0  | }  | 
819  |  |  | 
820  |  | static void enable_allow_small_records(gnutls_priority_t c)  | 
821  | 0  | { | 
822  | 0  |   c->_allow_small_records = 1;  | 
823  | 0  | }  | 
824  |  |  | 
825  |  | static void enable_dumbfw(gnutls_priority_t c)  | 
826  | 0  | { | 
827  | 0  |   c->_dumbfw = 1;  | 
828  | 0  | }  | 
829  |  |  | 
830  |  | static void enable_no_extensions(gnutls_priority_t c)  | 
831  | 0  | { | 
832  | 0  |   c->no_extensions = 1;  | 
833  | 0  | }  | 
834  |  |  | 
835  |  | static void enable_no_status_request(gnutls_priority_t c)  | 
836  | 0  | { | 
837  | 0  |   c->no_status_request = 1;  | 
838  | 0  | }  | 
839  |  |  | 
840  |  | static void enable_no_ext_master_secret(gnutls_priority_t c)  | 
841  | 0  | { | 
842  | 0  |   c->_no_ext_master_secret = 1;  | 
843  | 0  | }  | 
844  |  |  | 
845  |  | static void enable_force_ext_master_secret(gnutls_priority_t c)  | 
846  | 0  | { | 
847  | 0  |   c->force_ext_master_secret = EMS_REQUIRE;  | 
848  | 0  | }  | 
849  |  |  | 
850  |  | static void enable_no_etm(gnutls_priority_t c)  | 
851  | 0  | { | 
852  | 0  |   c->_no_etm = 1;  | 
853  | 0  | }  | 
854  |  |  | 
855  |  | static void enable_force_etm(gnutls_priority_t c)  | 
856  | 0  | { | 
857  | 0  |   c->force_etm = 1;  | 
858  | 0  | }  | 
859  |  |  | 
860  |  | static void enable_no_tickets(gnutls_priority_t c)  | 
861  | 0  | { | 
862  | 0  |   c->no_tickets = 1;  | 
863  | 0  | }  | 
864  |  |  | 
865  |  | static void enable_no_tickets_tls12(gnutls_priority_t c)  | 
866  | 0  | { | 
867  | 0  |   c->no_tickets_tls12 = 1;  | 
868  | 0  | }  | 
869  |  |  | 
870  |  | static void disable_wildcards(gnutls_priority_t c)  | 
871  | 0  | { | 
872  | 0  |   c->additional_verify_flags |= GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS;  | 
873  | 0  | }  | 
874  |  |  | 
875  |  | static void enable_profile_very_weak(gnutls_priority_t c)  | 
876  | 0  | { | 
877  | 0  |   ENABLE_PROFILE(c, GNUTLS_PROFILE_VERY_WEAK);  | 
878  | 0  | }  | 
879  |  |  | 
880  |  | static void enable_profile_low(gnutls_priority_t c)  | 
881  | 0  | { | 
882  | 0  |   ENABLE_PROFILE(c, GNUTLS_PROFILE_LOW);  | 
883  | 0  | }  | 
884  |  |  | 
885  |  | static void enable_profile_legacy(gnutls_priority_t c)  | 
886  | 0  | { | 
887  | 0  |   ENABLE_PROFILE(c, GNUTLS_PROFILE_LEGACY);  | 
888  | 0  | }  | 
889  |  |  | 
890  |  | static void enable_profile_medium(gnutls_priority_t c)  | 
891  | 0  | { | 
892  | 0  |   ENABLE_PROFILE(c, GNUTLS_PROFILE_MEDIUM);  | 
893  | 0  | }  | 
894  |  |  | 
895  |  | static void enable_profile_high(gnutls_priority_t c)  | 
896  | 0  | { | 
897  | 0  |   ENABLE_PROFILE(c, GNUTLS_PROFILE_HIGH);  | 
898  | 0  | }  | 
899  |  |  | 
900  |  | static void enable_profile_ultra(gnutls_priority_t c)  | 
901  | 0  | { | 
902  | 0  |   ENABLE_PROFILE(c, GNUTLS_PROFILE_ULTRA);  | 
903  | 0  | }  | 
904  |  |  | 
905  |  | static void enable_profile_future(gnutls_priority_t c)  | 
906  | 0  | { | 
907  | 0  |   ENABLE_PROFILE(c, GNUTLS_PROFILE_FUTURE);  | 
908  | 0  | }  | 
909  |  |  | 
910  |  | static void enable_profile_suiteb128(gnutls_priority_t c)  | 
911  | 0  | { | 
912  | 0  |   ENABLE_PROFILE(c, GNUTLS_PROFILE_SUITEB128);  | 
913  | 0  | }  | 
914  |  |  | 
915  |  | static void enable_profile_suiteb192(gnutls_priority_t c)  | 
916  | 0  | { | 
917  | 0  |   ENABLE_PROFILE(c, GNUTLS_PROFILE_SUITEB128);  | 
918  | 0  | }  | 
919  |  |  | 
920  |  | static void enable_safe_renegotiation(gnutls_priority_t c)  | 
921  | 0  | { | 
922  | 0  |   c->sr = SR_SAFE;  | 
923  | 0  | }  | 
924  |  |  | 
925  |  | static void enable_unsafe_renegotiation(gnutls_priority_t c)  | 
926  | 0  | { | 
927  | 0  |   c->sr = SR_UNSAFE;  | 
928  | 0  | }  | 
929  |  |  | 
930  |  | static void enable_partial_safe_renegotiation(gnutls_priority_t c)  | 
931  | 0  | { | 
932  | 0  |   c->sr = SR_PARTIAL;  | 
933  | 0  | }  | 
934  |  |  | 
935  |  | static void disable_safe_renegotiation(gnutls_priority_t c)  | 
936  | 0  | { | 
937  | 0  |   c->sr = SR_DISABLED;  | 
938  | 0  | }  | 
939  |  |  | 
940  |  | static void enable_fallback_scsv(gnutls_priority_t c)  | 
941  | 0  | { | 
942  | 0  |   c->fallback = 1;  | 
943  | 0  | }  | 
944  |  |  | 
945  |  | static void enable_latest_record_version(gnutls_priority_t c)  | 
946  | 0  | { | 
947  | 0  |   c->min_record_version = 0;  | 
948  | 0  | }  | 
949  |  |  | 
950  |  | static void enable_ssl3_record_version(gnutls_priority_t c)  | 
951  | 0  | { | 
952  | 0  |   c->min_record_version = 1;  | 
953  | 0  | }  | 
954  |  |  | 
955  |  | static void enable_verify_allow_rsa_md5(gnutls_priority_t c)  | 
956  | 0  | { | 
957  | 0  |   c->additional_verify_flags |= GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5;  | 
958  | 0  | }  | 
959  |  |  | 
960  |  | static void enable_verify_allow_sha1(gnutls_priority_t c)  | 
961  | 0  | { | 
962  | 0  |   c->additional_verify_flags |= GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1;  | 
963  | 0  | }  | 
964  |  |  | 
965  |  | static void enable_verify_allow_broken(gnutls_priority_t c)  | 
966  | 0  | { | 
967  | 0  |   c->additional_verify_flags |= GNUTLS_VERIFY_ALLOW_BROKEN;  | 
968  | 0  | }  | 
969  |  |  | 
970  |  | static void disable_crl_checks(gnutls_priority_t c)  | 
971  | 0  | { | 
972  | 0  |   c->additional_verify_flags |= GNUTLS_VERIFY_DISABLE_CRL_CHECKS;  | 
973  | 0  | }  | 
974  |  |  | 
975  |  | static void enable_server_precedence(gnutls_priority_t c)  | 
976  | 0  | { | 
977  | 0  |   c->server_precedence = 1;  | 
978  | 0  | }  | 
979  |  |  | 
980  |  | static void disable_tls13_compat_mode(gnutls_priority_t c)  | 
981  | 0  | { | 
982  | 0  |   c->tls13_compat_mode = false;  | 
983  | 0  | }  | 
984  |  |  | 
985  |  | static void enable_no_shuffle_extensions(gnutls_priority_t c)  | 
986  | 0  | { | 
987  | 0  |   c->no_shuffle_extensions = 1;  | 
988  | 0  | }  | 
989  |  |  | 
990  |  | static void dummy_func(gnutls_priority_t c)  | 
991  | 0  | { | 
992  | 0  | }  | 
993  |  |  | 
994  |  | #include <priority_options.h>  | 
995  |  |  | 
996  |  | struct cfg { | 
997  |  |   bool allowlisting;  | 
998  |  |   bool ktls_enabled;  | 
999  |  |   bool allow_rsa_pkcs1_encrypt;  | 
1000  |  |  | 
1001  |  |   name_val_array_t priority_strings;  | 
1002  |  |   char *priority_string;  | 
1003  |  |   char *default_priority_string;  | 
1004  |  |   gnutls_certificate_verification_profiles_t verification_profile;  | 
1005  |  |  | 
1006  |  |   gnutls_cipher_algorithm_t ciphers[MAX_ALGOS + 1];  | 
1007  |  |   gnutls_mac_algorithm_t macs[MAX_ALGOS + 1];  | 
1008  |  |   gnutls_group_t groups[MAX_ALGOS + 1];  | 
1009  |  |   gnutls_kx_algorithm_t kxs[MAX_ALGOS + 1];  | 
1010  |  |   gnutls_sign_algorithm_t sigs[MAX_ALGOS + 1];  | 
1011  |  |   gnutls_protocol_t versions[MAX_ALGOS + 1];  | 
1012  |  |  | 
1013  |  |   gnutls_digest_algorithm_t hashes[MAX_ALGOS + 1];  | 
1014  |  |   gnutls_ecc_curve_t ecc_curves[MAX_ALGOS + 1];  | 
1015  |  |   gnutls_sign_algorithm_t sigs_for_cert[MAX_ALGOS + 1];  | 
1016  |  |  | 
1017  |  |   ext_master_secret_t force_ext_master_secret;  | 
1018  |  |   bool force_ext_master_secret_set;  | 
1019  |  | };  | 
1020  |  |  | 
1021  |  | static inline void cfg_init(struct cfg *cfg)  | 
1022  | 20  | { | 
1023  | 20  |   memset(cfg, 0, sizeof(*cfg));  | 
1024  | 20  |   cfg->allow_rsa_pkcs1_encrypt = true;  | 
1025  | 20  | }  | 
1026  |  |  | 
1027  |  | static inline void cfg_deinit(struct cfg *cfg)  | 
1028  | 0  | { | 
1029  | 0  |   if (cfg->priority_strings) { | 
1030  | 0  |     _name_val_array_clear(&cfg->priority_strings);  | 
1031  | 0  |   }  | 
1032  | 0  |   gnutls_free(cfg->priority_string);  | 
1033  | 0  |   gnutls_free(cfg->default_priority_string);  | 
1034  | 0  | }  | 
1035  |  |  | 
1036  |  | /* Lock for reading and writing system_wide_config */  | 
1037  |  | GNUTLS_RWLOCK(system_wide_config_rwlock);  | 
1038  |  | static struct cfg system_wide_config;  | 
1039  |  |  | 
1040  |  | static unsigned fail_on_invalid_config = 0;  | 
1041  |  | static const char *system_priority_file = SYSTEM_PRIORITY_FILE;  | 
1042  |  | static time_t system_priority_last_mod = 0;  | 
1043  |  | static unsigned system_priority_file_loaded = 0;  | 
1044  |  |  | 
1045  | 0  | #define GLOBAL_SECTION "global"  | 
1046  | 0  | #define CUSTOM_PRIORITY_SECTION "priorities"  | 
1047  | 0  | #define OVERRIDES_SECTION "overrides"  | 
1048  | 0  | #define MAX_ALGO_NAME 2048  | 
1049  |  |  | 
1050  |  | bool _gnutls_allowlisting_mode(void)  | 
1051  | 0  | { | 
1052  | 0  |   return system_wide_config.allowlisting;  | 
1053  | 0  | }  | 
1054  |  |  | 
1055  |  | static void _clear_default_system_priority(void)  | 
1056  | 0  | { | 
1057  | 0  |   gnutls_free(system_wide_config.default_priority_string);  | 
1058  | 0  |   system_wide_config.default_priority_string = NULL;  | 
1059  |  | 
  | 
1060  | 0  |   _gnutls_default_priority_string = DEFAULT_PRIORITY_STRING;  | 
1061  | 0  | }  | 
1062  |  |  | 
1063  |  | gnutls_certificate_verification_profiles_t  | 
1064  |  | _gnutls_get_system_wide_verification_profile(void)  | 
1065  | 0  | { | 
1066  | 0  |   return system_wide_config.verification_profile;  | 
1067  | 0  | }  | 
1068  |  |  | 
1069  |  | /* removes spaces */  | 
1070  |  | static char *clear_spaces(const char *str, char out[MAX_ALGO_NAME])  | 
1071  | 0  | { | 
1072  | 0  |   const char *p = str;  | 
1073  | 0  |   unsigned i = 0;  | 
1074  |  | 
  | 
1075  | 0  |   while (c_isspace(*p))  | 
1076  | 0  |     p++;  | 
1077  |  | 
  | 
1078  | 0  |   while (!c_isspace(*p) && *p != 0) { | 
1079  | 0  |     out[i++] = *p;  | 
1080  | 0  |     p++;  | 
1081  |  | 
  | 
1082  | 0  |     if (i >= MAX_ALGO_NAME - 1)  | 
1083  | 0  |       break;  | 
1084  | 0  |   }  | 
1085  | 0  |   out[i] = 0;  | 
1086  | 0  |   return out;  | 
1087  | 0  | }  | 
1088  |  |  | 
1089  |  | struct ini_ctx { | 
1090  |  |   struct cfg cfg;  | 
1091  |  |  | 
1092  |  |   gnutls_digest_algorithm_t *hashes;  | 
1093  |  |   size_t hashes_size;  | 
1094  |  |   gnutls_sign_algorithm_t *sigs;  | 
1095  |  |   size_t sigs_size;  | 
1096  |  |   gnutls_sign_algorithm_t *sigs_for_cert;  | 
1097  |  |   size_t sigs_for_cert_size;  | 
1098  |  |   gnutls_protocol_t *versions;  | 
1099  |  |   size_t versions_size;  | 
1100  |  |   gnutls_ecc_curve_t *curves;  | 
1101  |  |   size_t curves_size;  | 
1102  |  | };  | 
1103  |  |  | 
1104  |  | static inline void ini_ctx_init(struct ini_ctx *ctx)  | 
1105  | 0  | { | 
1106  | 0  |   memset(ctx, 0, sizeof(*ctx));  | 
1107  | 0  |   cfg_init(&ctx->cfg);  | 
1108  | 0  | }  | 
1109  |  |  | 
1110  |  | static inline void ini_ctx_deinit(struct ini_ctx *ctx)  | 
1111  | 0  | { | 
1112  | 0  |   cfg_deinit(&ctx->cfg);  | 
1113  | 0  |   gnutls_free(ctx->hashes);  | 
1114  | 0  |   gnutls_free(ctx->sigs);  | 
1115  | 0  |   gnutls_free(ctx->sigs_for_cert);  | 
1116  | 0  |   gnutls_free(ctx->versions);  | 
1117  | 0  |   gnutls_free(ctx->curves);  | 
1118  | 0  | }  | 
1119  |  |  | 
1120  |  | static inline void cfg_steal(struct cfg *dst, struct cfg *src)  | 
1121  | 0  | { | 
1122  | 0  |   dst->verification_profile = src->verification_profile;  | 
1123  |  | 
  | 
1124  | 0  |   dst->priority_strings = src->priority_strings;  | 
1125  | 0  |   src->priority_strings = NULL;  | 
1126  |  | 
  | 
1127  | 0  |   dst->priority_string = src->priority_string;  | 
1128  | 0  |   src->priority_string = NULL;  | 
1129  |  | 
  | 
1130  | 0  |   dst->default_priority_string = src->default_priority_string;  | 
1131  | 0  |   src->default_priority_string = NULL;  | 
1132  |  | 
  | 
1133  | 0  |   dst->allowlisting = src->allowlisting;  | 
1134  | 0  |   dst->ktls_enabled = src->ktls_enabled;  | 
1135  | 0  |   dst->allow_rsa_pkcs1_encrypt = src->allow_rsa_pkcs1_encrypt;  | 
1136  | 0  |   dst->force_ext_master_secret = src->force_ext_master_secret;  | 
1137  | 0  |   dst->force_ext_master_secret_set = src->force_ext_master_secret_set;  | 
1138  | 0  |   memcpy(dst->ciphers, src->ciphers, sizeof(src->ciphers));  | 
1139  | 0  |   memcpy(dst->macs, src->macs, sizeof(src->macs));  | 
1140  | 0  |   memcpy(dst->groups, src->groups, sizeof(src->groups));  | 
1141  | 0  |   memcpy(dst->kxs, src->kxs, sizeof(src->kxs));  | 
1142  | 0  |   memcpy(dst->hashes, src->hashes, sizeof(src->hashes));  | 
1143  | 0  |   memcpy(dst->ecc_curves, src->ecc_curves, sizeof(src->ecc_curves));  | 
1144  | 0  |   memcpy(dst->sigs, src->sigs, sizeof(src->sigs));  | 
1145  | 0  |   memcpy(dst->sigs_for_cert, src->sigs_for_cert,  | 
1146  | 0  |          sizeof(src->sigs_for_cert));  | 
1147  | 0  | }  | 
1148  |  |  | 
1149  |  | /*  | 
1150  |  |  * synchronizing changes from struct cfg to global `lib/algorithms` arrays  | 
1151  |  |  */  | 
1152  |  |  | 
1153  |  | /* global side-effect! modifies `flags` in `hash_algorithms[]` */  | 
1154  |  | static inline int /* allowlisting-only */ _cfg_hashes_remark(struct cfg *cfg)  | 
1155  | 0  | { | 
1156  | 0  |   size_t i;  | 
1157  | 0  |   _gnutls_digest_mark_insecure_all();  | 
1158  | 0  |   for (i = 0; cfg->hashes[i] != 0; i++) { | 
1159  | 0  |     int ret = _gnutls_digest_set_secure(cfg->hashes[i], 1);  | 
1160  | 0  |     if (unlikely(ret < 0)) { | 
1161  | 0  |       return gnutls_assert_val(ret);  | 
1162  | 0  |     }  | 
1163  | 0  |   }  | 
1164  | 0  |   return 0;  | 
1165  | 0  | }  | 
1166  |  |  | 
1167  |  | /* global side-effect! modifies `flags` in `sign_algorithms[]` */  | 
1168  |  | static inline int /* allowlisting-only */ _cfg_sigs_remark(struct cfg *cfg)  | 
1169  | 0  | { | 
1170  | 0  |   size_t i;  | 
1171  | 0  |   _gnutls_sign_mark_insecure_all(_INSECURE);  | 
1172  | 0  |   for (i = 0; cfg->sigs[i] != 0; i++) { | 
1173  | 0  |     int ret = _gnutls_sign_set_secure(cfg->sigs[i],  | 
1174  | 0  |               _INSECURE_FOR_CERTS);  | 
1175  | 0  |     if (unlikely(ret < 0)) { | 
1176  | 0  |       return gnutls_assert_val(ret);  | 
1177  | 0  |     }  | 
1178  | 0  |   }  | 
1179  | 0  |   for (i = 0; cfg->sigs_for_cert[i] != 0; i++) { | 
1180  | 0  |     int ret =  | 
1181  | 0  |       _gnutls_sign_set_secure(cfg->sigs_for_cert[i], _SECURE);  | 
1182  | 0  |     if (unlikely(ret < 0)) { | 
1183  | 0  |       return gnutls_assert_val(ret);  | 
1184  | 0  |     }  | 
1185  | 0  |   }  | 
1186  | 0  |   return 0;  | 
1187  | 0  | }  | 
1188  |  |  | 
1189  |  | /* global side-effect! modifies `supported` in `sup_versions[]` */  | 
1190  |  | static inline int /* allowlisting-only */ _cfg_versions_remark(struct cfg *cfg)  | 
1191  | 0  | { | 
1192  | 0  |   size_t i;  | 
1193  | 0  |   _gnutls_version_mark_disabled_all();  | 
1194  | 0  |   for (i = 0; cfg->versions[i] != 0; i++) { | 
1195  | 0  |     int ret = _gnutls_protocol_set_enabled(cfg->versions[i], 1);  | 
1196  | 0  |     if (unlikely(ret < 0)) { | 
1197  | 0  |       return gnutls_assert_val(ret);  | 
1198  | 0  |     }  | 
1199  | 0  |   }  | 
1200  | 0  |   return 0;  | 
1201  | 0  | }  | 
1202  |  |  | 
1203  |  | /* global side-effect! modifies `supported` in `ecc_curves[]` */  | 
1204  |  | static inline int /* allowlisting-only */  | 
1205  |  | _cfg_ecc_curves_remark(struct cfg *cfg)  | 
1206  | 0  | { | 
1207  | 0  |   size_t i;  | 
1208  | 0  |   _gnutls_ecc_curve_mark_disabled_all();  | 
1209  | 0  |   for (i = 0; cfg->ecc_curves[i] != 0; i++) { | 
1210  | 0  |     int ret = _gnutls_ecc_curve_set_enabled(cfg->ecc_curves[i], 1);  | 
1211  | 0  |     if (unlikely(ret < 0)) { | 
1212  | 0  |       return gnutls_assert_val(ret);  | 
1213  | 0  |     }  | 
1214  | 0  |   }  | 
1215  | 0  |   return 0;  | 
1216  | 0  | }  | 
1217  |  |  | 
1218  |  | /*  | 
1219  |  |  * setting arrays of struct cfg: from other arrays  | 
1220  |  |  */  | 
1221  |  |  | 
1222  |  | static inline int /* allowlisting-only */  | 
1223  |  | cfg_hashes_set_array(struct cfg *cfg, gnutls_digest_algorithm_t *src,  | 
1224  |  |          size_t len)  | 
1225  | 0  | { | 
1226  | 0  |   if (unlikely(len >= MAX_ALGOS)) { | 
1227  | 0  |     return gnutls_assert_val(GNUTLS_A_INTERNAL_ERROR);  | 
1228  | 0  |   }  | 
1229  | 0  |   if (len) { | 
1230  | 0  |     memcpy(cfg->hashes, src,  | 
1231  | 0  |            sizeof(gnutls_digest_algorithm_t) * len);  | 
1232  | 0  |   }  | 
1233  | 0  |   cfg->hashes[len] = 0;  | 
1234  | 0  |   return _cfg_hashes_remark(cfg);  | 
1235  | 0  | }  | 
1236  |  |  | 
1237  |  | static inline int /* allowlisting-only */  | 
1238  |  | cfg_sigs_set_arrays(struct cfg *cfg, gnutls_sign_algorithm_t *src, size_t len,  | 
1239  |  |         gnutls_sign_algorithm_t *src_for_cert, size_t len_for_cert)  | 
1240  | 0  | { | 
1241  | 0  |   if (unlikely(len >= MAX_ALGOS)) { | 
1242  | 0  |     return gnutls_assert_val(GNUTLS_A_INTERNAL_ERROR);  | 
1243  | 0  |   }  | 
1244  | 0  |   if (unlikely(len_for_cert >= MAX_ALGOS)) { | 
1245  | 0  |     return gnutls_assert_val(GNUTLS_A_INTERNAL_ERROR);  | 
1246  | 0  |   }  | 
1247  | 0  |   if (len) { | 
1248  | 0  |     memcpy(cfg->sigs, src, sizeof(gnutls_sign_algorithm_t) * len);  | 
1249  | 0  |   }  | 
1250  | 0  |   if (len_for_cert) { | 
1251  | 0  |     memcpy(cfg->sigs_for_cert, src_for_cert,  | 
1252  | 0  |            sizeof(gnutls_sign_algorithm_t) * len_for_cert);  | 
1253  | 0  |   }  | 
1254  | 0  |   cfg->sigs[len] = 0;  | 
1255  | 0  |   cfg->sigs_for_cert[len_for_cert] = 0;  | 
1256  | 0  |   return _cfg_sigs_remark(cfg);  | 
1257  | 0  | }  | 
1258  |  |  | 
1259  |  | static inline int /* allowlisting-only */  | 
1260  |  | cfg_versions_set_array(struct cfg *cfg, gnutls_protocol_t *src, size_t len)  | 
1261  | 0  | { | 
1262  | 0  |   if (unlikely(len >= MAX_ALGOS)) { | 
1263  | 0  |     return gnutls_assert_val(GNUTLS_A_INTERNAL_ERROR);  | 
1264  | 0  |   }  | 
1265  | 0  |   if (len) { | 
1266  | 0  |     memcpy(cfg->versions, src, sizeof(gnutls_protocol_t) * len);  | 
1267  | 0  |   }  | 
1268  | 0  |   cfg->versions[len] = 0;  | 
1269  | 0  |   return _cfg_versions_remark(cfg);  | 
1270  | 0  | }  | 
1271  |  |  | 
1272  |  | static inline int /* allowlisting-only */  | 
1273  |  | cfg_ecc_curves_set_array(struct cfg *cfg, gnutls_ecc_curve_t *src, size_t len)  | 
1274  | 0  | { | 
1275  | 0  |   if (unlikely(len >= MAX_ALGOS)) { | 
1276  | 0  |     return gnutls_assert_val(GNUTLS_A_INTERNAL_ERROR);  | 
1277  | 0  |   }  | 
1278  | 0  |   if (len) { | 
1279  | 0  |     memcpy(cfg->ecc_curves, src, sizeof(gnutls_ecc_curve_t) * len);  | 
1280  | 0  |   }  | 
1281  | 0  |   cfg->ecc_curves[len] = 0;  | 
1282  | 0  |   return _cfg_ecc_curves_remark(cfg);  | 
1283  | 0  | }  | 
1284  |  |  | 
1285  |  | /*  | 
1286  |  |  * appending to arrays of struct cfg  | 
1287  |  |  */  | 
1288  |  |  | 
1289  |  | /* polymorphic way to DRY this operation. other possible approaches:  | 
1290  |  |  * 1. just unmacro (long)  | 
1291  |  |  * 2. cast to ints and write a function operating on ints  | 
1292  |  |  *    (hacky, every call is +4 lines, needs a portable static assert)  | 
1293  |  |  * 3. macro whole functions, not just this operation (harder to find/read)  | 
1294  |  |  */  | 
1295  |  | #define APPEND_TO_NULL_TERMINATED_ARRAY(dst, element)                      \  | 
1296  | 0  |   do {                                                               \ | 
1297  | 0  |     size_t i;                                                  \  | 
1298  | 0  |     for (i = 0; dst[i] != 0; i++) {                            \ | 
1299  | 0  |       if (dst[i] == element) {                           \ | 
1300  | 0  |         return 0;                                  \  | 
1301  | 0  |       }                                                  \  | 
1302  | 0  |     }                                                          \  | 
1303  | 0  |     if (unlikely(i >= MAX_ALGOS)) {                            \ | 
1304  | 0  |       return gnutls_assert_val(GNUTLS_A_INTERNAL_ERROR); \  | 
1305  | 0  |     }                                                          \  | 
1306  | 0  |     dst[i] = element;                                          \  | 
1307  | 0  |     dst[i + 1] = 0;                                            \  | 
1308  | 0  |   } while (0)  | 
1309  |  |  | 
1310  |  | static inline int /* allowlisting-only */  | 
1311  |  | cfg_hashes_add(struct cfg *cfg, gnutls_digest_algorithm_t dig)  | 
1312  | 0  | { | 
1313  | 0  |   _gnutls_debug_log("cfg: enabling digest algorithm %s\n", | 
1314  | 0  |         gnutls_digest_get_name(dig));  | 
1315  | 0  |   APPEND_TO_NULL_TERMINATED_ARRAY(cfg->hashes, dig);  | 
1316  | 0  |   return _cfg_hashes_remark(cfg);  | 
1317  | 0  | }  | 
1318  |  |  | 
1319  |  | static inline int /* allowlisting-only */  | 
1320  |  | cfg_sigs_add(struct cfg *cfg, gnutls_sign_algorithm_t sig)  | 
1321  | 0  | { | 
1322  | 0  |   _gnutls_debug_log("cfg: enabling signature algorithm " | 
1323  | 0  |         "(for non-certificate usage) "  | 
1324  | 0  |         "%s\n",  | 
1325  | 0  |         gnutls_sign_get_name(sig));  | 
1326  | 0  |   APPEND_TO_NULL_TERMINATED_ARRAY(cfg->sigs, sig);  | 
1327  | 0  |   return _cfg_sigs_remark(cfg);  | 
1328  | 0  | }  | 
1329  |  |  | 
1330  |  | static inline int /* allowlisting-only */  | 
1331  |  | cfg_sigs_for_cert_add(struct cfg *cfg, gnutls_sign_algorithm_t sig)  | 
1332  | 0  | { | 
1333  | 0  |   _gnutls_debug_log("cfg: enabling signature algorithm" | 
1334  | 0  |         "(for certificate usage) "  | 
1335  | 0  |         "%s\n",  | 
1336  | 0  |         gnutls_sign_get_name(sig));  | 
1337  | 0  |   APPEND_TO_NULL_TERMINATED_ARRAY(cfg->sigs_for_cert, sig);  | 
1338  | 0  |   return _cfg_sigs_remark(cfg);  | 
1339  | 0  | }  | 
1340  |  |  | 
1341  |  | static inline int /* allowlisting-only */  | 
1342  |  | cfg_versions_add(struct cfg *cfg, gnutls_protocol_t prot)  | 
1343  | 0  | { | 
1344  | 0  |   _gnutls_debug_log("cfg: enabling version %s\n", | 
1345  | 0  |         gnutls_protocol_get_name(prot));  | 
1346  | 0  |   APPEND_TO_NULL_TERMINATED_ARRAY(cfg->versions, prot);  | 
1347  | 0  |   return _cfg_versions_remark(cfg);  | 
1348  | 0  | }  | 
1349  |  |  | 
1350  |  | static inline int /* allowlisting-only */  | 
1351  |  | cfg_ecc_curves_add(struct cfg *cfg, gnutls_ecc_curve_t curve)  | 
1352  | 0  | { | 
1353  | 0  |   _gnutls_debug_log("cfg: enabling curve %s\n", | 
1354  | 0  |         gnutls_ecc_curve_get_name(curve));  | 
1355  | 0  |   APPEND_TO_NULL_TERMINATED_ARRAY(cfg->ecc_curves, curve);  | 
1356  | 0  |   return _cfg_ecc_curves_remark(cfg);  | 
1357  | 0  | }  | 
1358  |  |  | 
1359  |  | #undef APPEND_TO_NULL_TERMINATED_ARRAY  | 
1360  |  |  | 
1361  |  | /*  | 
1362  |  |  * removing from arrays of struct cfg  | 
1363  |  |  */  | 
1364  |  |  | 
1365  |  | /* polymorphic way to DRY this removal, see APPEND_TO_NULL_TERMINATED_ARRAY */  | 
1366  |  | #define REMOVE_FROM_NULL_TERMINATED_ARRAY(dst, element)         \  | 
1367  | 0  |   do {                                                    \ | 
1368  | 0  |     size_t i, j;                                    \  | 
1369  | 0  |     for (i = 0; dst[i] != 0; i++) {                 \ | 
1370  | 0  |       if (dst[i] == element) {                \ | 
1371  | 0  |         for (j = i; dst[j] != 0; j++) { \ | 
1372  | 0  |           dst[j] = dst[j + 1];    \  | 
1373  | 0  |         }                               \  | 
1374  | 0  |       }                                       \  | 
1375  | 0  |     }                                               \  | 
1376  | 0  |   } while (0)  | 
1377  |  |  | 
1378  |  | static inline int /* allowlisting-only */  | 
1379  |  | cfg_hashes_remove(struct cfg *cfg, gnutls_digest_algorithm_t dig)  | 
1380  | 0  | { | 
1381  | 0  |   _gnutls_debug_log("cfg: disabling digest algorithm %s\n", | 
1382  | 0  |         gnutls_digest_get_name(dig));  | 
1383  | 0  |   REMOVE_FROM_NULL_TERMINATED_ARRAY(cfg->hashes, dig);  | 
1384  | 0  |   return _cfg_hashes_remark(cfg);  | 
1385  | 0  | }  | 
1386  |  |  | 
1387  |  | static inline int /* allowlisting-only */  | 
1388  |  | cfg_sigs_remove(struct cfg *cfg, gnutls_sign_algorithm_t sig)  | 
1389  | 0  | { | 
1390  | 0  |   _gnutls_debug_log("cfg: disabling signature algorithm " | 
1391  | 0  |         "(for non-certificate usage) "  | 
1392  | 0  |         "%s\n",  | 
1393  | 0  |         gnutls_sign_get_name(sig));  | 
1394  | 0  |   REMOVE_FROM_NULL_TERMINATED_ARRAY(cfg->sigs, sig);  | 
1395  | 0  |   return _cfg_sigs_remark(cfg);  | 
1396  | 0  | }  | 
1397  |  |  | 
1398  |  | static inline int /* allowlisting-only */  | 
1399  |  | cfg_sigs_for_cert_remove(struct cfg *cfg, gnutls_sign_algorithm_t sig)  | 
1400  | 0  | { | 
1401  | 0  |   _gnutls_debug_log("cfg: disabling signature algorithm" | 
1402  | 0  |         "(for certificate usage) "  | 
1403  | 0  |         "%s\n",  | 
1404  | 0  |         gnutls_sign_get_name(sig));  | 
1405  | 0  |   REMOVE_FROM_NULL_TERMINATED_ARRAY(cfg->sigs_for_cert, sig);  | 
1406  | 0  |   return _cfg_sigs_remark(cfg);  | 
1407  | 0  | }  | 
1408  |  |  | 
1409  |  | static inline int /* allowlisting-only */  | 
1410  |  | cfg_versions_remove(struct cfg *cfg, gnutls_protocol_t prot)  | 
1411  | 0  | { | 
1412  | 0  |   _gnutls_debug_log("cfg: disabling version %s\n", | 
1413  | 0  |         gnutls_protocol_get_name(prot));  | 
1414  | 0  |   REMOVE_FROM_NULL_TERMINATED_ARRAY(cfg->versions, prot);  | 
1415  | 0  |   return _cfg_versions_remark(cfg);  | 
1416  | 0  | }  | 
1417  |  |  | 
1418  |  | static inline int /* allowlisting-only */  | 
1419  |  | cfg_ecc_curves_remove(struct cfg *cfg, gnutls_ecc_curve_t curve)  | 
1420  | 0  | { | 
1421  | 0  |   _gnutls_debug_log("cfg: disabling curve %s\n", | 
1422  | 0  |         gnutls_ecc_curve_get_name(curve));  | 
1423  | 0  |   REMOVE_FROM_NULL_TERMINATED_ARRAY(cfg->ecc_curves, curve);  | 
1424  | 0  |   return _cfg_ecc_curves_remark(cfg);  | 
1425  | 0  | }  | 
1426  |  |  | 
1427  |  | static inline int cfg_apply(struct cfg *cfg, struct ini_ctx *ctx)  | 
1428  | 0  | { | 
1429  | 0  |   size_t i;  | 
1430  | 0  |   int ret;  | 
1431  |  | 
  | 
1432  | 0  |   cfg_steal(cfg, &ctx->cfg);  | 
1433  |  | 
  | 
1434  | 0  |   if (cfg->default_priority_string) { | 
1435  | 0  |     _gnutls_default_priority_string = cfg->default_priority_string;  | 
1436  | 0  |   }  | 
1437  |  | 
  | 
1438  | 0  |   if (cfg->allowlisting) { | 
1439  |  |     /* also updates `flags` of global `hash_algorithms[]` */  | 
1440  | 0  |     ret = cfg_hashes_set_array(cfg, ctx->hashes, ctx->hashes_size);  | 
1441  | 0  |     if (unlikely(ret < 0)) { | 
1442  | 0  |       return gnutls_assert_val(ret);  | 
1443  | 0  |     }  | 
1444  |  |     /* also updates `flags` of global `sign_algorithms[]` */  | 
1445  | 0  |     ret = cfg_sigs_set_arrays(cfg, ctx->sigs, ctx->sigs_size,  | 
1446  | 0  |             ctx->sigs_for_cert,  | 
1447  | 0  |             ctx->sigs_for_cert_size);  | 
1448  | 0  |     if (unlikely(ret < 0)) { | 
1449  | 0  |       return gnutls_assert_val(ret);  | 
1450  | 0  |     }  | 
1451  |  |     /* also updates `supported` field of global `sup_versions[]` */  | 
1452  | 0  |     ret = cfg_versions_set_array(cfg, ctx->versions,  | 
1453  | 0  |                ctx->versions_size);  | 
1454  | 0  |     if (unlikely(ret < 0)) { | 
1455  | 0  |       return gnutls_assert_val(ret);  | 
1456  | 0  |     }  | 
1457  |  |     /* also updates `supported` field of global `ecc_curves[]` */  | 
1458  | 0  |     ret = cfg_ecc_curves_set_array(cfg, ctx->curves,  | 
1459  | 0  |                  ctx->curves_size);  | 
1460  | 0  |     if (unlikely(ret < 0)) { | 
1461  | 0  |       return gnutls_assert_val(ret);  | 
1462  | 0  |     }  | 
1463  | 0  |   } else { | 
1464  |  |     /* updates same global arrays as above, but doesn't store  | 
1465  |  |      * the algorithms into the `struct cfg` as allowlisting does.  | 
1466  |  |      * blocklisting doesn't allow relaxing the restrictions */  | 
1467  | 0  |     for (i = 0; i < ctx->hashes_size; i++) { | 
1468  | 0  |       ret = _gnutls_digest_mark_insecure(ctx->hashes[i]);  | 
1469  | 0  |       if (unlikely(ret < 0)) { | 
1470  | 0  |         return ret;  | 
1471  | 0  |       }  | 
1472  | 0  |     }  | 
1473  | 0  |     for (i = 0; i < ctx->sigs_size; i++) { | 
1474  | 0  |       ret = _gnutls_sign_mark_insecure(ctx->sigs[i],  | 
1475  | 0  |                _INSECURE);  | 
1476  | 0  |       if (unlikely(ret < 0)) { | 
1477  | 0  |         return ret;  | 
1478  | 0  |       }  | 
1479  | 0  |     }  | 
1480  | 0  |     for (i = 0; i < ctx->sigs_for_cert_size; i++) { | 
1481  | 0  |       ret = _gnutls_sign_mark_insecure(ctx->sigs_for_cert[i],  | 
1482  | 0  |                _INSECURE_FOR_CERTS);  | 
1483  | 0  |       if (unlikely(ret < 0)) { | 
1484  | 0  |         return ret;  | 
1485  | 0  |       }  | 
1486  | 0  |     }  | 
1487  | 0  |     for (i = 0; i < ctx->versions_size; i++) { | 
1488  | 0  |       ret = _gnutls_version_mark_disabled(ctx->versions[i]);  | 
1489  | 0  |       if (unlikely(ret < 0)) { | 
1490  | 0  |         return ret;  | 
1491  | 0  |       }  | 
1492  | 0  |     }  | 
1493  | 0  |     for (i = 0; i < ctx->curves_size; i++) { | 
1494  | 0  |       ret = _gnutls_ecc_curve_mark_disabled(ctx->curves[i]);  | 
1495  | 0  |       if (unlikely(ret < 0)) { | 
1496  | 0  |         return ret;  | 
1497  | 0  |       }  | 
1498  | 0  |     }  | 
1499  | 0  |   }  | 
1500  |  |  | 
1501  | 0  |   return 0;  | 
1502  | 0  | }  | 
1503  |  |  | 
1504  |  | /* This function parses the global section of the configuration file.  | 
1505  |  |  */  | 
1506  |  | static int global_ini_handler(void *ctx, const char *section, const char *name,  | 
1507  |  |             const char *value)  | 
1508  | 0  | { | 
1509  | 0  |   char *p;  | 
1510  | 0  |   char str[MAX_ALGO_NAME];  | 
1511  | 0  |   struct cfg *cfg = ctx;  | 
1512  |  | 
  | 
1513  | 0  |   if (section != NULL && c_strcasecmp(section, GLOBAL_SECTION) == 0) { | 
1514  | 0  |     if (c_strcasecmp(name, "override-mode") == 0) { | 
1515  | 0  |       p = clear_spaces(value, str);  | 
1516  | 0  |       if (c_strcasecmp(p, "allowlist") == 0) { | 
1517  | 0  |         cfg->allowlisting = true;  | 
1518  | 0  |       } else if (c_strcasecmp(p, "blocklist") == 0) { | 
1519  | 0  |         cfg->allowlisting = false;  | 
1520  | 0  |       } else { | 
1521  | 0  |         _gnutls_debug_log(  | 
1522  | 0  |           "cfg: unknown override mode %s\n", p);  | 
1523  | 0  |         if (fail_on_invalid_config)  | 
1524  | 0  |           return 0;  | 
1525  | 0  |       }  | 
1526  | 0  |     } else if (c_strcasecmp(name, "ktls") == 0) { | 
1527  | 0  |       p = clear_spaces(value, str);  | 
1528  | 0  |       if (c_strcasecmp(p, "true") == 0) { | 
1529  | 0  |         cfg->ktls_enabled = true;  | 
1530  | 0  |       } else if (c_strcasecmp(p, "false") == 0) { | 
1531  | 0  |         cfg->ktls_enabled = false;  | 
1532  | 0  |       } else { | 
1533  | 0  |         _gnutls_debug_log("cfg: unknown ktls mode %s\n", | 
1534  | 0  |               p);  | 
1535  | 0  |         if (fail_on_invalid_config)  | 
1536  | 0  |           return 0;  | 
1537  | 0  |       }  | 
1538  | 0  |     } else { | 
1539  | 0  |       _gnutls_debug_log("unknown parameter %s\n", name); | 
1540  | 0  |       if (fail_on_invalid_config)  | 
1541  | 0  |         return 0;  | 
1542  | 0  |     }  | 
1543  | 0  |   }  | 
1544  |  |  | 
1545  | 0  |   return 1;  | 
1546  | 0  | }  | 
1547  |  |  | 
1548  |  | static bool override_allowed(bool allowlisting, const char *name)  | 
1549  | 0  | { | 
1550  | 0  |   static const struct { | 
1551  | 0  |     const char *allowlist_name;  | 
1552  | 0  |     const char *blocklist_name;  | 
1553  | 0  |   } names[] = { { "secure-hash", "insecure-hash" }, | 
1554  | 0  |           { "secure-sig", "insecure-sig" }, | 
1555  | 0  |           { "secure-sig-for-cert", "insecure-sig-for-cert" }, | 
1556  | 0  |           { "enabled-version", "disabled-version" }, | 
1557  | 0  |           { "enabled-curve", "disabled-curve" }, | 
1558  | 0  |           { "tls-enabled-cipher", "tls-disabled-cipher" }, | 
1559  | 0  |           { "tls-enabled-group", "tls-disabled-group" }, | 
1560  | 0  |           { "tls-enabled-kx", "tls-disabled-kx" }, | 
1561  | 0  |           { "tls-enabled-mac", "tls-disabled-mac" } }; | 
1562  | 0  |   size_t i;  | 
1563  |  | 
  | 
1564  | 0  |   for (i = 0; i < sizeof(names) / sizeof(names[0]); i++) { | 
1565  | 0  |     if (c_strcasecmp(name, allowlisting ?  | 
1566  | 0  |                  names[i].blocklist_name :  | 
1567  | 0  |                  names[i].allowlist_name) == 0)  | 
1568  | 0  |       return false;  | 
1569  | 0  |   }  | 
1570  |  |  | 
1571  | 0  |   return true;  | 
1572  | 0  | }  | 
1573  |  |  | 
1574  |  | /* This function parses a gnutls configuration file.  Updating internal settings  | 
1575  |  |  * according to the parsed configuration is done by cfg_apply.  | 
1576  |  |  */  | 
1577  |  | static int cfg_ini_handler(void *_ctx, const char *section, const char *name,  | 
1578  |  |          const char *value)  | 
1579  | 0  | { | 
1580  | 0  |   char *p;  | 
1581  | 0  |   int ret;  | 
1582  | 0  |   unsigned i;  | 
1583  | 0  |   char str[MAX_ALGO_NAME];  | 
1584  | 0  |   struct ini_ctx *ctx = _ctx;  | 
1585  | 0  |   struct cfg *cfg = &ctx->cfg;  | 
1586  |  |  | 
1587  |  |   /* Note that we intentionally overwrite the value above; inih does  | 
1588  |  |    * not use that value after we handle it. */  | 
1589  |  |  | 
1590  |  |   /* Parse sections */  | 
1591  | 0  |   if (section == NULL || section[0] == 0 ||  | 
1592  | 0  |       c_strcasecmp(section, CUSTOM_PRIORITY_SECTION) == 0) { | 
1593  | 0  |     _gnutls_debug_log("cfg: adding priority: %s -> %s\n", name, | 
1594  | 0  |           value);  | 
1595  |  | 
  | 
1596  | 0  |     ret = _name_val_array_append(&cfg->priority_strings, name,  | 
1597  | 0  |                value);  | 
1598  | 0  |     if (ret < 0)  | 
1599  | 0  |       return 0;  | 
1600  | 0  |   } else if (c_strcasecmp(section, OVERRIDES_SECTION) == 0) { | 
1601  | 0  |     if (!override_allowed(cfg->allowlisting, name)) { | 
1602  | 0  |       _gnutls_debug_log(  | 
1603  | 0  |         "cfg: %s is not allowed in this mode\n", name);  | 
1604  | 0  |       if (fail_on_invalid_config)  | 
1605  | 0  |         return 0;  | 
1606  | 0  |     } else if (c_strcasecmp(name, "default-priority-string") == 0) { | 
1607  | 0  |       if (cfg->default_priority_string) { | 
1608  | 0  |         gnutls_free(cfg->default_priority_string);  | 
1609  | 0  |         cfg->default_priority_string = NULL;  | 
1610  | 0  |       }  | 
1611  | 0  |       p = clear_spaces(value, str);  | 
1612  | 0  |       _gnutls_debug_log(  | 
1613  | 0  |         "cfg: setting default-priority-string to %s\n",  | 
1614  | 0  |         p);  | 
1615  | 0  |       if (strlen(p) > 0) { | 
1616  | 0  |         cfg->default_priority_string = gnutls_strdup(p);  | 
1617  | 0  |         if (!cfg->default_priority_string) { | 
1618  | 0  |           _gnutls_debug_log(  | 
1619  | 0  |             "cfg: failed setting default-priority-string\n");  | 
1620  | 0  |           return 0;  | 
1621  | 0  |         }  | 
1622  | 0  |       } else { | 
1623  | 0  |         _gnutls_debug_log(  | 
1624  | 0  |           "cfg: empty default-priority-string, using default\n");  | 
1625  | 0  |         if (fail_on_invalid_config)  | 
1626  | 0  |           return 0;  | 
1627  | 0  |       }  | 
1628  | 0  |     } else if (c_strcasecmp(name, "insecure-hash") == 0 ||  | 
1629  | 0  |          c_strcasecmp(name, "secure-hash") == 0) { | 
1630  | 0  |       gnutls_digest_algorithm_t dig, *tmp;  | 
1631  |  | 
  | 
1632  | 0  |       p = clear_spaces(value, str);  | 
1633  |  | 
  | 
1634  | 0  |       if (cfg->allowlisting) { | 
1635  | 0  |         _gnutls_debug_log(  | 
1636  | 0  |           "cfg: marking hash %s as secure\n", p);  | 
1637  | 0  |       } else { | 
1638  | 0  |         _gnutls_debug_log(  | 
1639  | 0  |           "cfg: marking hash %s as insecure\n",  | 
1640  | 0  |           p);  | 
1641  | 0  |       }  | 
1642  |  | 
  | 
1643  | 0  |       dig = gnutls_digest_get_id(p);  | 
1644  | 0  |       if (dig == GNUTLS_DIG_UNKNOWN) { | 
1645  | 0  |         _gnutls_debug_log(  | 
1646  | 0  |           "cfg: found unknown hash %s in %s\n", p,  | 
1647  | 0  |           name);  | 
1648  | 0  |         if (fail_on_invalid_config)  | 
1649  | 0  |           return 0;  | 
1650  | 0  |         goto exit;  | 
1651  | 0  |       }  | 
1652  | 0  |       tmp = _gnutls_reallocarray(  | 
1653  | 0  |         ctx->hashes, ctx->hashes_size + 1,  | 
1654  | 0  |         sizeof(gnutls_digest_algorithm_t));  | 
1655  | 0  |       if (!tmp) { | 
1656  | 0  |         if (cfg->allowlisting) { | 
1657  | 0  |           _gnutls_debug_log(  | 
1658  | 0  |             "cfg: failed marking hash %s as secure\n",  | 
1659  | 0  |             p);  | 
1660  | 0  |         } else { | 
1661  | 0  |           _gnutls_debug_log(  | 
1662  | 0  |             "cfg: failed marking hash %s as insecure\n",  | 
1663  | 0  |             p);  | 
1664  | 0  |         }  | 
1665  | 0  |         if (fail_on_invalid_config)  | 
1666  | 0  |           return 0;  | 
1667  | 0  |         goto exit;  | 
1668  | 0  |       }  | 
1669  |  |  | 
1670  | 0  |       ctx->hashes = tmp;  | 
1671  | 0  |       ctx->hashes[ctx->hashes_size] = dig;  | 
1672  | 0  |       ctx->hashes_size++;  | 
1673  | 0  |     } else if (c_strcasecmp(name, "insecure-sig") == 0 ||  | 
1674  | 0  |          c_strcasecmp(name, "secure-sig") == 0) { | 
1675  | 0  |       gnutls_sign_algorithm_t sig, *tmp;  | 
1676  |  | 
  | 
1677  | 0  |       p = clear_spaces(value, str);  | 
1678  |  | 
  | 
1679  | 0  |       if (cfg->allowlisting) { | 
1680  | 0  |         _gnutls_debug_log(  | 
1681  | 0  |           "cfg: marking signature %s as secure\n",  | 
1682  | 0  |           p);  | 
1683  | 0  |       } else { | 
1684  | 0  |         _gnutls_debug_log(  | 
1685  | 0  |           "cfg: marking signature %s as insecure\n",  | 
1686  | 0  |           p);  | 
1687  | 0  |       }  | 
1688  |  | 
  | 
1689  | 0  |       sig = gnutls_sign_get_id(p);  | 
1690  | 0  |       if (sig == GNUTLS_SIGN_UNKNOWN) { | 
1691  | 0  |         _gnutls_debug_log(  | 
1692  | 0  |           "cfg: found unknown signature algorithm %s in %s\n",  | 
1693  | 0  |           p, name);  | 
1694  | 0  |         if (fail_on_invalid_config)  | 
1695  | 0  |           return 0;  | 
1696  | 0  |         goto exit;  | 
1697  | 0  |       }  | 
1698  | 0  |       tmp = _gnutls_reallocarray(  | 
1699  | 0  |         ctx->sigs, ctx->sigs_size + 1,  | 
1700  | 0  |         sizeof(gnutls_sign_algorithm_t));  | 
1701  | 0  |       if (!tmp) { | 
1702  | 0  |         if (cfg->allowlisting) { | 
1703  | 0  |           _gnutls_debug_log(  | 
1704  | 0  |             "cfg: failed marking signature %s as secure\n",  | 
1705  | 0  |             p);  | 
1706  | 0  |         } else { | 
1707  | 0  |           _gnutls_debug_log(  | 
1708  | 0  |             "cfg: failed marking signature %s as insecure\n",  | 
1709  | 0  |             p);  | 
1710  | 0  |         }  | 
1711  | 0  |         if (fail_on_invalid_config)  | 
1712  | 0  |           return 0;  | 
1713  | 0  |         goto exit;  | 
1714  | 0  |       }  | 
1715  |  |  | 
1716  | 0  |       ctx->sigs = tmp;  | 
1717  | 0  |       ctx->sigs[ctx->sigs_size] = sig;  | 
1718  | 0  |       ctx->sigs_size++;  | 
1719  | 0  |     } else if (c_strcasecmp(name, "insecure-sig-for-cert") == 0 ||  | 
1720  | 0  |          c_strcasecmp(name, "secure-sig-for-cert") == 0) { | 
1721  | 0  |       gnutls_sign_algorithm_t sig, *tmp;  | 
1722  |  | 
  | 
1723  | 0  |       p = clear_spaces(value, str);  | 
1724  |  | 
  | 
1725  | 0  |       if (cfg->allowlisting) { | 
1726  | 0  |         _gnutls_debug_log(  | 
1727  | 0  |           "cfg: marking signature %s as secure for certs\n",  | 
1728  | 0  |           p);  | 
1729  | 0  |       } else { | 
1730  | 0  |         _gnutls_debug_log(  | 
1731  | 0  |           "cfg: marking signature %s as insecure for certs\n",  | 
1732  | 0  |           p);  | 
1733  | 0  |       }  | 
1734  |  | 
  | 
1735  | 0  |       sig = gnutls_sign_get_id(p);  | 
1736  | 0  |       if (sig == GNUTLS_SIGN_UNKNOWN) { | 
1737  | 0  |         _gnutls_debug_log(  | 
1738  | 0  |           "cfg: found unknown signature algorithm %s in %s\n",  | 
1739  | 0  |           p, name);  | 
1740  | 0  |         if (fail_on_invalid_config)  | 
1741  | 0  |           return 0;  | 
1742  | 0  |         goto exit;  | 
1743  | 0  |       }  | 
1744  | 0  |       tmp = _gnutls_reallocarray(  | 
1745  | 0  |         ctx->sigs_for_cert, ctx->sigs_for_cert_size + 1,  | 
1746  | 0  |         sizeof(gnutls_sign_algorithm_t));  | 
1747  | 0  |       if (!tmp) { | 
1748  | 0  |         if (cfg->allowlisting) { | 
1749  | 0  |           _gnutls_debug_log(  | 
1750  | 0  |             "cfg: failed marking signature %s as secure for certs\n",  | 
1751  | 0  |             p);  | 
1752  | 0  |         } else { | 
1753  | 0  |           _gnutls_debug_log(  | 
1754  | 0  |             "cfg: failed marking signature %s as insecure for certs\n",  | 
1755  | 0  |             p);  | 
1756  | 0  |         }  | 
1757  | 0  |         if (fail_on_invalid_config)  | 
1758  | 0  |           return 0;  | 
1759  | 0  |         goto exit;  | 
1760  | 0  |       }  | 
1761  |  |  | 
1762  | 0  |       ctx->sigs_for_cert = tmp;  | 
1763  | 0  |       ctx->sigs_for_cert[ctx->sigs_for_cert_size] = sig;  | 
1764  | 0  |       ctx->sigs_for_cert_size++;  | 
1765  | 0  |     } else if (c_strcasecmp(name, "disabled-version") == 0 ||  | 
1766  | 0  |          c_strcasecmp(name, "enabled-version") == 0) { | 
1767  | 0  |       gnutls_protocol_t prot, *tmp;  | 
1768  |  | 
  | 
1769  | 0  |       p = clear_spaces(value, str);  | 
1770  |  | 
  | 
1771  | 0  |       if (cfg->allowlisting) { | 
1772  | 0  |         _gnutls_debug_log("cfg: enabling version %s\n", | 
1773  | 0  |               p);  | 
1774  | 0  |       } else { | 
1775  | 0  |         _gnutls_debug_log("cfg: disabling version %s\n", | 
1776  | 0  |               p);  | 
1777  | 0  |       }  | 
1778  |  | 
  | 
1779  | 0  |       prot = gnutls_protocol_get_id(p);  | 
1780  | 0  |       if (prot == GNUTLS_VERSION_UNKNOWN) { | 
1781  | 0  |         _gnutls_debug_log(  | 
1782  | 0  |           "cfg: found unknown version %s in %s\n",  | 
1783  | 0  |           p, name);  | 
1784  | 0  |         if (fail_on_invalid_config)  | 
1785  | 0  |           return 0;  | 
1786  | 0  |         goto exit;  | 
1787  | 0  |       }  | 
1788  | 0  |       tmp = _gnutls_reallocarray(ctx->versions,  | 
1789  | 0  |                ctx->versions_size + 1,  | 
1790  | 0  |                sizeof(gnutls_protocol_t));  | 
1791  | 0  |       if (!tmp) { | 
1792  | 0  |         if (cfg->allowlisting) { | 
1793  | 0  |           _gnutls_debug_log(  | 
1794  | 0  |             "cfg: failed enabling version %s\n",  | 
1795  | 0  |             p);  | 
1796  | 0  |         } else { | 
1797  | 0  |           _gnutls_debug_log(  | 
1798  | 0  |             "cfg: failed disabling version %s\n",  | 
1799  | 0  |             p);  | 
1800  | 0  |         }  | 
1801  | 0  |         if (fail_on_invalid_config)  | 
1802  | 0  |           return 0;  | 
1803  | 0  |         goto exit;  | 
1804  | 0  |       }  | 
1805  |  |  | 
1806  | 0  |       ctx->versions = tmp;  | 
1807  | 0  |       ctx->versions[ctx->versions_size] = prot;  | 
1808  | 0  |       ctx->versions_size++;  | 
1809  | 0  |     } else if (c_strcasecmp(name, "disabled-curve") == 0 ||  | 
1810  | 0  |          c_strcasecmp(name, "enabled-curve") == 0) { | 
1811  | 0  |       gnutls_ecc_curve_t curve, *tmp;  | 
1812  |  | 
  | 
1813  | 0  |       p = clear_spaces(value, str);  | 
1814  |  | 
  | 
1815  | 0  |       if (cfg->allowlisting) { | 
1816  | 0  |         _gnutls_debug_log("cfg: enabling curve %s\n", | 
1817  | 0  |               p);  | 
1818  | 0  |       } else { | 
1819  | 0  |         _gnutls_debug_log("cfg: disabling curve %s\n", | 
1820  | 0  |               p);  | 
1821  | 0  |       }  | 
1822  |  | 
  | 
1823  | 0  |       curve = gnutls_ecc_curve_get_id(p);  | 
1824  | 0  |       if (curve == GNUTLS_ECC_CURVE_INVALID) { | 
1825  | 0  |         _gnutls_debug_log(  | 
1826  | 0  |           "cfg: found unknown curve %s in %s\n",  | 
1827  | 0  |           p, name);  | 
1828  | 0  |         if (fail_on_invalid_config)  | 
1829  | 0  |           return 0;  | 
1830  | 0  |         goto exit;  | 
1831  | 0  |       }  | 
1832  | 0  |       tmp = _gnutls_reallocarray(ctx->curves,  | 
1833  | 0  |                ctx->curves_size + 1,  | 
1834  | 0  |                sizeof(gnutls_ecc_curve_t));  | 
1835  | 0  |       if (!tmp) { | 
1836  | 0  |         if (cfg->allowlisting) { | 
1837  | 0  |           _gnutls_debug_log(  | 
1838  | 0  |             "cfg: failed enabling curve %s\n",  | 
1839  | 0  |             p);  | 
1840  | 0  |         } else { | 
1841  | 0  |           _gnutls_debug_log(  | 
1842  | 0  |             "cfg: failed disabling curve %s\n",  | 
1843  | 0  |             p);  | 
1844  | 0  |         }  | 
1845  | 0  |         if (fail_on_invalid_config)  | 
1846  | 0  |           return 0;  | 
1847  | 0  |         goto exit;  | 
1848  | 0  |       }  | 
1849  |  |  | 
1850  | 0  |       ctx->curves = tmp;  | 
1851  | 0  |       ctx->curves[ctx->curves_size] = curve;  | 
1852  | 0  |       ctx->curves_size++;  | 
1853  | 0  |     } else if (c_strcasecmp(name, "min-verification-profile") ==  | 
1854  | 0  |          0) { | 
1855  | 0  |       gnutls_certificate_verification_profiles_t profile;  | 
1856  | 0  |       profile =  | 
1857  | 0  |         gnutls_certificate_verification_profile_get_id(  | 
1858  | 0  |           value);  | 
1859  |  | 
  | 
1860  | 0  |       if (profile == GNUTLS_PROFILE_UNKNOWN) { | 
1861  | 0  |         _gnutls_debug_log(  | 
1862  | 0  |           "cfg: found unknown profile %s in %s\n",  | 
1863  | 0  |           value, name);  | 
1864  | 0  |         if (fail_on_invalid_config)  | 
1865  | 0  |           return 0;  | 
1866  | 0  |         goto exit;  | 
1867  | 0  |       }  | 
1868  |  |  | 
1869  | 0  |       cfg->verification_profile = profile;  | 
1870  | 0  |     } else if (c_strcasecmp(name, "tls-disabled-cipher") == 0 ||  | 
1871  | 0  |          c_strcasecmp(name, "tls-enabled-cipher") == 0) { | 
1872  | 0  |       gnutls_cipher_algorithm_t algo;  | 
1873  |  | 
  | 
1874  | 0  |       p = clear_spaces(value, str);  | 
1875  |  | 
  | 
1876  | 0  |       if (cfg->allowlisting) { | 
1877  | 0  |         _gnutls_debug_log(  | 
1878  | 0  |           "cfg: enabling cipher %s for TLS\n", p);  | 
1879  | 0  |       } else { | 
1880  | 0  |         _gnutls_debug_log(  | 
1881  | 0  |           "cfg: disabling cipher %s for TLS\n",  | 
1882  | 0  |           p);  | 
1883  | 0  |       }  | 
1884  |  | 
  | 
1885  | 0  |       algo = gnutls_cipher_get_id(p);  | 
1886  | 0  |       if (algo == GNUTLS_CIPHER_UNKNOWN) { | 
1887  | 0  |         _gnutls_debug_log(  | 
1888  | 0  |           "cfg: unknown algorithm %s listed at %s\n",  | 
1889  | 0  |           p, name);  | 
1890  | 0  |         if (fail_on_invalid_config)  | 
1891  | 0  |           return 0;  | 
1892  | 0  |         goto exit;  | 
1893  | 0  |       }  | 
1894  |  |  | 
1895  | 0  |       i = 0;  | 
1896  | 0  |       while (cfg->ciphers[i] != 0)  | 
1897  | 0  |         i++;  | 
1898  |  | 
  | 
1899  | 0  |       if (i > MAX_ALGOS - 1) { | 
1900  | 0  |         if (cfg->allowlisting) { | 
1901  | 0  |           _gnutls_debug_log(  | 
1902  | 0  |             "cfg: too many (%d) enabled ciphers from %s\n",  | 
1903  | 0  |             i, name);  | 
1904  | 0  |         } else { | 
1905  | 0  |           _gnutls_debug_log(  | 
1906  | 0  |             "cfg: too many (%d) disabled ciphers from %s\n",  | 
1907  | 0  |             i, name);  | 
1908  | 0  |         }  | 
1909  | 0  |         if (fail_on_invalid_config)  | 
1910  | 0  |           return 0;  | 
1911  | 0  |         goto exit;  | 
1912  | 0  |       }  | 
1913  | 0  |       cfg->ciphers[i] = algo;  | 
1914  | 0  |       cfg->ciphers[i + 1] = 0;  | 
1915  |  | 
  | 
1916  | 0  |     } else if (c_strcasecmp(name, "tls-disabled-mac") == 0 ||  | 
1917  | 0  |          c_strcasecmp(name, "tls-enabled-mac") == 0) { | 
1918  | 0  |       gnutls_mac_algorithm_t algo;  | 
1919  |  | 
  | 
1920  | 0  |       p = clear_spaces(value, str);  | 
1921  |  | 
  | 
1922  | 0  |       if (cfg->allowlisting) { | 
1923  | 0  |         _gnutls_debug_log(  | 
1924  | 0  |           "cfg: enabling MAC %s for TLS\n", p);  | 
1925  | 0  |       } else { | 
1926  | 0  |         _gnutls_debug_log(  | 
1927  | 0  |           "cfg: disabling MAC %s for TLS\n", p);  | 
1928  | 0  |       }  | 
1929  |  | 
  | 
1930  | 0  |       algo = gnutls_mac_get_id(p);  | 
1931  | 0  |       if (algo == 0) { | 
1932  | 0  |         _gnutls_debug_log(  | 
1933  | 0  |           "cfg: unknown algorithm %s listed at %s\n",  | 
1934  | 0  |           p, name);  | 
1935  | 0  |         if (fail_on_invalid_config)  | 
1936  | 0  |           return 0;  | 
1937  | 0  |         goto exit;  | 
1938  | 0  |       }  | 
1939  |  |  | 
1940  | 0  |       i = 0;  | 
1941  | 0  |       while (cfg->macs[i] != 0)  | 
1942  | 0  |         i++;  | 
1943  |  | 
  | 
1944  | 0  |       if (i > MAX_ALGOS - 1) { | 
1945  | 0  |         if (cfg->allowlisting) { | 
1946  | 0  |           _gnutls_debug_log(  | 
1947  | 0  |             "cfg: too many (%d) enabled MACs from %s\n",  | 
1948  | 0  |             i, name);  | 
1949  | 0  |         } else { | 
1950  | 0  |           _gnutls_debug_log(  | 
1951  | 0  |             "cfg: too many (%d) disabled MACs from %s\n",  | 
1952  | 0  |             i, name);  | 
1953  | 0  |         }  | 
1954  | 0  |         if (fail_on_invalid_config)  | 
1955  | 0  |           return 0;  | 
1956  | 0  |         goto exit;  | 
1957  | 0  |       }  | 
1958  | 0  |       cfg->macs[i] = algo;  | 
1959  | 0  |       cfg->macs[i + 1] = 0;  | 
1960  | 0  |     } else if (c_strcasecmp(name, "tls-disabled-group") == 0 ||  | 
1961  | 0  |          c_strcasecmp(name, "tls-enabled-group") == 0) { | 
1962  | 0  |       gnutls_group_t algo;  | 
1963  |  | 
  | 
1964  | 0  |       p = clear_spaces(value, str);  | 
1965  |  | 
  | 
1966  | 0  |       if (c_strncasecmp(p, "GROUP-", 6) == 0)  | 
1967  | 0  |         p += 6;  | 
1968  |  | 
  | 
1969  | 0  |       if (cfg->allowlisting) { | 
1970  | 0  |         _gnutls_debug_log(  | 
1971  | 0  |           "cfg: enabling group %s for TLS\n", p);  | 
1972  | 0  |       } else { | 
1973  | 0  |         _gnutls_debug_log(  | 
1974  | 0  |           "cfg: disabling group %s for TLS\n", p);  | 
1975  | 0  |       }  | 
1976  |  | 
  | 
1977  | 0  |       algo = _gnutls_group_get_id(p);  | 
1978  | 0  |       if (algo == 0) { | 
1979  | 0  |         _gnutls_debug_log(  | 
1980  | 0  |           "cfg: unknown group %s listed at %s\n",  | 
1981  | 0  |           p, name);  | 
1982  | 0  |         if (fail_on_invalid_config)  | 
1983  | 0  |           return 0;  | 
1984  | 0  |         goto exit;  | 
1985  | 0  |       }  | 
1986  |  |  | 
1987  | 0  |       i = 0;  | 
1988  | 0  |       while (cfg->groups[i] != 0)  | 
1989  | 0  |         i++;  | 
1990  |  | 
  | 
1991  | 0  |       if (i > MAX_ALGOS - 1) { | 
1992  | 0  |         if (cfg->allowlisting) { | 
1993  | 0  |           _gnutls_debug_log(  | 
1994  | 0  |             "cfg: too many (%d) enabled groups from %s\n",  | 
1995  | 0  |             i, name);  | 
1996  | 0  |         } else { | 
1997  | 0  |           _gnutls_debug_log(  | 
1998  | 0  |             "cfg: too many (%d) disabled groups from %s\n",  | 
1999  | 0  |             i, name);  | 
2000  | 0  |         }  | 
2001  | 0  |         if (fail_on_invalid_config)  | 
2002  | 0  |           return 0;  | 
2003  | 0  |         goto exit;  | 
2004  | 0  |       }  | 
2005  | 0  |       cfg->groups[i] = algo;  | 
2006  | 0  |       cfg->groups[i + 1] = 0;  | 
2007  | 0  |     } else if (c_strcasecmp(name, "tls-disabled-kx") == 0 ||  | 
2008  | 0  |          c_strcasecmp(name, "tls-enabled-kx") == 0) { | 
2009  | 0  |       unsigned algo;  | 
2010  |  | 
  | 
2011  | 0  |       p = clear_spaces(value, str);  | 
2012  |  | 
  | 
2013  | 0  |       if (cfg->allowlisting) { | 
2014  | 0  |         _gnutls_debug_log(  | 
2015  | 0  |           "cfg: enabling key exchange %s for TLS\n",  | 
2016  | 0  |           p);  | 
2017  | 0  |       } else { | 
2018  | 0  |         _gnutls_debug_log(  | 
2019  | 0  |           "cfg: disabling key exchange %s for TLS\n",  | 
2020  | 0  |           p);  | 
2021  | 0  |       }  | 
2022  |  | 
  | 
2023  | 0  |       algo = gnutls_kx_get_id(p);  | 
2024  | 0  |       if (algo == 0) { | 
2025  | 0  |         _gnutls_debug_log(  | 
2026  | 0  |           "cfg: unknown key exchange %s listed at %s\n",  | 
2027  | 0  |           p, name);  | 
2028  | 0  |         if (fail_on_invalid_config)  | 
2029  | 0  |           return 0;  | 
2030  | 0  |         goto exit;  | 
2031  | 0  |       }  | 
2032  |  |  | 
2033  | 0  |       i = 0;  | 
2034  | 0  |       while (cfg->kxs[i] != 0)  | 
2035  | 0  |         i++;  | 
2036  |  | 
  | 
2037  | 0  |       if (i > MAX_ALGOS - 1) { | 
2038  | 0  |         if (cfg->allowlisting) { | 
2039  | 0  |           _gnutls_debug_log(  | 
2040  | 0  |             "cfg: too many (%d) enabled key exchanges from %s\n",  | 
2041  | 0  |             i, name);  | 
2042  | 0  |         } else { | 
2043  | 0  |           _gnutls_debug_log(  | 
2044  | 0  |             "cfg: too many (%d) disabled key exchanges from %s\n",  | 
2045  | 0  |             i, name);  | 
2046  | 0  |         }  | 
2047  | 0  |         if (fail_on_invalid_config)  | 
2048  | 0  |           return 0;  | 
2049  | 0  |         goto exit;  | 
2050  | 0  |       }  | 
2051  | 0  |       cfg->kxs[i] = algo;  | 
2052  | 0  |       cfg->kxs[i + 1] = 0;  | 
2053  | 0  |     } else if (c_strcasecmp(name, "tls-session-hash") == 0) { | 
2054  | 0  |       if (c_strcasecmp(value, "request") == 0) { | 
2055  | 0  |         cfg->force_ext_master_secret = EMS_REQUEST;  | 
2056  | 0  |         cfg->force_ext_master_secret_set = true;  | 
2057  | 0  |       } else if (c_strcasecmp(value, "require") == 0) { | 
2058  | 0  |         cfg->force_ext_master_secret = EMS_REQUIRE;  | 
2059  | 0  |         cfg->force_ext_master_secret_set = true;  | 
2060  | 0  |       } else { | 
2061  | 0  |         _gnutls_debug_log(  | 
2062  | 0  |           "cfg: unknown value for %s: %s\n", name,  | 
2063  | 0  |           value);  | 
2064  | 0  |         if (fail_on_invalid_config)  | 
2065  | 0  |           return 0;  | 
2066  | 0  |         goto exit;  | 
2067  | 0  |       }  | 
2068  | 0  |     } else if (c_strcasecmp(name, "allow-rsa-pkcs1-encrypt") == 0) { | 
2069  | 0  |       p = clear_spaces(value, str);  | 
2070  | 0  |       if (c_strcasecmp(p, "true") == 0) { | 
2071  | 0  |         cfg->allow_rsa_pkcs1_encrypt = true;  | 
2072  | 0  |       } else if (c_strcasecmp(p, "false") == 0) { | 
2073  | 0  |         cfg->allow_rsa_pkcs1_encrypt = false;  | 
2074  | 0  |       } else { | 
2075  | 0  |         _gnutls_debug_log(  | 
2076  | 0  |           "cfg: unknown RSA PKCS1 encryption mode %s\n",  | 
2077  | 0  |           p);  | 
2078  | 0  |         if (fail_on_invalid_config)  | 
2079  | 0  |           return 0;  | 
2080  | 0  |         goto exit;  | 
2081  | 0  |       }  | 
2082  | 0  |     } else { | 
2083  | 0  |       _gnutls_debug_log("unknown parameter %s\n", name); | 
2084  | 0  |       if (fail_on_invalid_config)  | 
2085  | 0  |         return 0;  | 
2086  | 0  |     }  | 
2087  | 0  |   } else if (c_strcasecmp(section, GLOBAL_SECTION) != 0) { | 
2088  | 0  |     _gnutls_debug_log("cfg: unknown section %s\n", section); | 
2089  | 0  |     if (fail_on_invalid_config)  | 
2090  | 0  |       return 0;  | 
2091  | 0  |   }  | 
2092  |  |  | 
2093  | 0  | exit:  | 
2094  | 0  |   return 1;  | 
2095  | 0  | }  | 
2096  |  |  | 
2097  |  | static int /* not locking system_wide_config */  | 
2098  |  | construct_system_wide_priority_string(gnutls_buffer_st *buf)  | 
2099  | 0  | { | 
2100  | 0  |   int ret;  | 
2101  | 0  |   size_t i;  | 
2102  |  | 
  | 
2103  | 0  |   _gnutls_buffer_init(buf);  | 
2104  |  | 
  | 
2105  | 0  |   ret = _gnutls_buffer_append_str(buf, "NONE");  | 
2106  | 0  |   if (ret < 0) { | 
2107  | 0  |     _gnutls_buffer_clear(buf);  | 
2108  | 0  |     return ret;  | 
2109  | 0  |   }  | 
2110  |  |  | 
2111  | 0  |   for (i = 0; system_wide_config.kxs[i] != 0; i++) { | 
2112  | 0  |     ret = _gnutls_buffer_append_str(buf, ":+");  | 
2113  | 0  |     if (ret < 0) { | 
2114  | 0  |       _gnutls_buffer_clear(buf);  | 
2115  | 0  |       return ret;  | 
2116  | 0  |     }  | 
2117  |  |  | 
2118  | 0  |     ret = _gnutls_buffer_append_str(  | 
2119  | 0  |       buf, gnutls_kx_get_name(system_wide_config.kxs[i]));  | 
2120  | 0  |     if (ret < 0) { | 
2121  | 0  |       _gnutls_buffer_clear(buf);  | 
2122  | 0  |       return ret;  | 
2123  | 0  |     }  | 
2124  | 0  |   }  | 
2125  |  |  | 
2126  | 0  |   for (i = 0; system_wide_config.groups[i] != 0; i++) { | 
2127  | 0  |     ret = _gnutls_buffer_append_str(buf, ":+GROUP-");  | 
2128  | 0  |     if (ret < 0) { | 
2129  | 0  |       _gnutls_buffer_clear(buf);  | 
2130  | 0  |       return ret;  | 
2131  | 0  |     }  | 
2132  |  |  | 
2133  | 0  |     ret = _gnutls_buffer_append_str(  | 
2134  | 0  |       buf,  | 
2135  | 0  |       gnutls_group_get_name(system_wide_config.groups[i]));  | 
2136  | 0  |     if (ret < 0) { | 
2137  | 0  |       _gnutls_buffer_clear(buf);  | 
2138  | 0  |       return ret;  | 
2139  | 0  |     }  | 
2140  | 0  |   }  | 
2141  |  |  | 
2142  | 0  |   for (i = 0; system_wide_config.ciphers[i] != 0; i++) { | 
2143  | 0  |     ret = _gnutls_buffer_append_str(buf, ":+");  | 
2144  | 0  |     if (ret < 0) { | 
2145  | 0  |       _gnutls_buffer_clear(buf);  | 
2146  | 0  |       return ret;  | 
2147  | 0  |     }  | 
2148  |  |  | 
2149  | 0  |     ret = _gnutls_buffer_append_str(  | 
2150  | 0  |       buf,  | 
2151  | 0  |       gnutls_cipher_get_name(system_wide_config.ciphers[i]));  | 
2152  | 0  |     if (ret < 0) { | 
2153  | 0  |       _gnutls_buffer_clear(buf);  | 
2154  | 0  |       return ret;  | 
2155  | 0  |     }  | 
2156  | 0  |   }  | 
2157  |  |  | 
2158  | 0  |   for (i = 0; system_wide_config.macs[i] != 0; i++) { | 
2159  | 0  |     ret = _gnutls_buffer_append_str(buf, ":+");  | 
2160  | 0  |     if (ret < 0) { | 
2161  | 0  |       _gnutls_buffer_clear(buf);  | 
2162  | 0  |       return ret;  | 
2163  | 0  |     }  | 
2164  |  |  | 
2165  | 0  |     ret = _gnutls_buffer_append_str(  | 
2166  | 0  |       buf, gnutls_mac_get_name(system_wide_config.macs[i]));  | 
2167  | 0  |     if (ret < 0) { | 
2168  | 0  |       _gnutls_buffer_clear(buf);  | 
2169  | 0  |       return ret;  | 
2170  | 0  |     }  | 
2171  | 0  |   }  | 
2172  |  |  | 
2173  | 0  |   for (i = 0; system_wide_config.sigs[i] != 0; i++) { | 
2174  | 0  |     ret = _gnutls_buffer_append_str(buf, ":+SIGN-");  | 
2175  | 0  |     if (ret < 0) { | 
2176  | 0  |       _gnutls_buffer_clear(buf);  | 
2177  | 0  |       return ret;  | 
2178  | 0  |     }  | 
2179  |  |  | 
2180  | 0  |     ret = _gnutls_buffer_append_str(  | 
2181  | 0  |       buf, gnutls_sign_get_name(system_wide_config.sigs[i]));  | 
2182  | 0  |     if (ret < 0) { | 
2183  | 0  |       _gnutls_buffer_clear(buf);  | 
2184  | 0  |       return ret;  | 
2185  | 0  |     }  | 
2186  | 0  |   }  | 
2187  |  |  | 
2188  | 0  |   for (i = 0; system_wide_config.versions[i] != 0; i++) { | 
2189  | 0  |     ret = _gnutls_buffer_append_str(buf, ":+VERS-");  | 
2190  | 0  |     if (ret < 0) { | 
2191  | 0  |       _gnutls_buffer_clear(buf);  | 
2192  | 0  |       return ret;  | 
2193  | 0  |     }  | 
2194  |  |  | 
2195  | 0  |     ret = _gnutls_buffer_append_str(  | 
2196  | 0  |       buf, gnutls_protocol_get_name(  | 
2197  | 0  |              system_wide_config.versions[i]));  | 
2198  | 0  |     if (ret < 0) { | 
2199  | 0  |       _gnutls_buffer_clear(buf);  | 
2200  | 0  |       return ret;  | 
2201  | 0  |     }  | 
2202  | 0  |   }  | 
2203  | 0  |   return 0;  | 
2204  | 0  | }  | 
2205  |  |  | 
2206  |  | static int /* not locking system_wide_config */  | 
2207  |  | update_system_wide_priority_string(void)  | 
2208  | 0  | { | 
2209  |  |   /* doesn't do locking, _gnutls_update_system_priorities does */  | 
2210  | 0  |   gnutls_buffer_st buf;  | 
2211  | 0  |   int ret;  | 
2212  |  | 
  | 
2213  | 0  |   ret = construct_system_wide_priority_string(&buf);  | 
2214  | 0  |   if (ret < 0) { | 
2215  | 0  |     _gnutls_debug_log("cfg: unable to construct " | 
2216  | 0  |           "system-wide priority string: %s",  | 
2217  | 0  |           gnutls_strerror(ret));  | 
2218  | 0  |     _gnutls_buffer_clear(&buf);  | 
2219  | 0  |     return ret;  | 
2220  | 0  |   }  | 
2221  |  |  | 
2222  | 0  |   gnutls_free(system_wide_config.priority_string);  | 
2223  | 0  |   system_wide_config.priority_string = gnutls_strdup((char *)buf.data);  | 
2224  | 0  |   _gnutls_buffer_clear(&buf);  | 
2225  |  | 
  | 
2226  | 0  |   return 0;  | 
2227  | 0  | }  | 
2228  |  |  | 
2229  |  | /* Returns false on parse error, otherwise true.  | 
2230  |  |  * The system_wide_config must be locked for writing.  | 
2231  |  |  */  | 
2232  |  | static inline bool load_system_priority_file(void)  | 
2233  | 0  | { | 
2234  | 0  |   int err;  | 
2235  | 0  |   FILE *fp;  | 
2236  | 0  |   struct ini_ctx ctx;  | 
2237  |  | 
  | 
2238  | 0  |   cfg_init(&system_wide_config);  | 
2239  |  | 
  | 
2240  | 0  |   fp = fopen(system_priority_file, "re");  | 
2241  | 0  |   if (fp == NULL) { | 
2242  | 0  |     _gnutls_debug_log("cfg: unable to open: %s: %d\n", | 
2243  | 0  |           system_priority_file, errno);  | 
2244  | 0  |     return true;  | 
2245  | 0  |   }  | 
2246  |  |  | 
2247  |  |   /* Parsing the configuration file needs to be done in 2 phases:  | 
2248  |  |    * first parsing the [global] section  | 
2249  |  |    * and then the other sections,  | 
2250  |  |    * because the [global] section modifies the parsing behavior.  | 
2251  |  |    */  | 
2252  | 0  |   ini_ctx_init(&ctx);  | 
2253  | 0  |   err = ini_parse_file(fp, global_ini_handler, &ctx);  | 
2254  | 0  |   if (!err) { | 
2255  | 0  |     if (fseek(fp, 0L, SEEK_SET) < 0) { | 
2256  | 0  |       _gnutls_debug_log("cfg: unable to rewind: %s\n", | 
2257  | 0  |             system_priority_file);  | 
2258  | 0  |       if (fail_on_invalid_config)  | 
2259  | 0  |         exit(1);  | 
2260  | 0  |     }  | 
2261  | 0  |     err = ini_parse_file(fp, cfg_ini_handler, &ctx);  | 
2262  | 0  |   }  | 
2263  | 0  |   fclose(fp);  | 
2264  | 0  |   if (err) { | 
2265  | 0  |     ini_ctx_deinit(&ctx);  | 
2266  | 0  |     _gnutls_debug_log("cfg: unable to parse: %s: %d\n", | 
2267  | 0  |           system_priority_file, err);  | 
2268  | 0  |     return false;  | 
2269  | 0  |   }  | 
2270  | 0  |   cfg_apply(&system_wide_config, &ctx);  | 
2271  | 0  |   ini_ctx_deinit(&ctx);  | 
2272  | 0  |   return true;  | 
2273  | 0  | }  | 
2274  |  |  | 
2275  |  | static int _gnutls_update_system_priorities(bool defer_system_wide)  | 
2276  | 20  | { | 
2277  | 20  |   int ret;  | 
2278  | 20  |   bool config_parse_error = false;  | 
2279  | 20  |   struct stat sb;  | 
2280  | 20  |   gnutls_buffer_st buf;  | 
2281  |  |  | 
2282  | 20  |   ret = gnutls_rwlock_rdlock(&system_wide_config_rwlock);  | 
2283  | 20  |   if (ret < 0)  | 
2284  | 0  |     return gnutls_assert_val(ret);  | 
2285  |  |  | 
2286  | 20  |   if (stat(system_priority_file, &sb) < 0) { | 
2287  | 20  |     _gnutls_debug_log("cfg: unable to access: %s: %d\n", | 
2288  | 20  |           system_priority_file, errno);  | 
2289  |  |  | 
2290  | 20  |     (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
2291  | 20  |     ret = gnutls_rwlock_wrlock(&system_wide_config_rwlock);  | 
2292  | 20  |     if (ret < 0)  | 
2293  | 0  |       goto out;  | 
2294  |  |     /* If system-wide config is unavailable, apply the defaults */  | 
2295  | 20  |     cfg_init(&system_wide_config);  | 
2296  | 20  |     goto out;  | 
2297  | 20  |   }  | 
2298  |  |  | 
2299  | 0  |   if (system_priority_file_loaded &&  | 
2300  | 0  |       system_priority_last_mod == sb.st_mtime) { | 
2301  | 0  |     _gnutls_debug_log("cfg: system priority %s has not changed\n", | 
2302  | 0  |           system_priority_file);  | 
2303  | 0  |     if (system_wide_config.priority_string)  | 
2304  | 0  |       goto out; /* nothing to do */  | 
2305  | 0  |   }  | 
2306  |  |  | 
2307  | 0  |   (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
2308  |  | 
  | 
2309  | 0  |   ret = gnutls_rwlock_wrlock(&system_wide_config_rwlock);  | 
2310  | 0  |   if (ret < 0)  | 
2311  | 0  |     return gnutls_assert_val(ret);  | 
2312  |  |  | 
2313  |  |   /* Another thread could have successfully re-read system-wide config,  | 
2314  |  |    * skip re-reading if the mtime it has used is exactly the same.  | 
2315  |  |    */  | 
2316  | 0  |   if (system_priority_file_loaded)  | 
2317  | 0  |     system_priority_file_loaded =  | 
2318  | 0  |       (system_priority_last_mod == sb.st_mtime);  | 
2319  |  | 
  | 
2320  | 0  |   if (!system_priority_file_loaded) { | 
2321  | 0  |     config_parse_error = !load_system_priority_file();  | 
2322  | 0  |     if (config_parse_error)  | 
2323  | 0  |       goto out;  | 
2324  | 0  |     _gnutls_debug_log("cfg: loaded system config %s mtime %lld\n", | 
2325  | 0  |           system_priority_file,  | 
2326  | 0  |           (unsigned long long)sb.st_mtime);  | 
2327  | 0  |   }  | 
2328  |  |  | 
2329  | 0  |   if (system_wide_config.allowlisting) { | 
2330  | 0  |     if (defer_system_wide) { | 
2331  |  |       /* try constructing a priority string,  | 
2332  |  |        * but don't apply it yet, at this point  | 
2333  |  |        * we're only interested in whether we can */  | 
2334  | 0  |       ret = construct_system_wide_priority_string(&buf);  | 
2335  | 0  |       _gnutls_buffer_clear(&buf);  | 
2336  | 0  |       _gnutls_debug_log("cfg: deferred setting " | 
2337  | 0  |             "system-wide priority string\n");  | 
2338  | 0  |     } else { | 
2339  | 0  |       ret = update_system_wide_priority_string();  | 
2340  | 0  |       _gnutls_debug_log("cfg: finalized " | 
2341  | 0  |             "system-wide priority string\n");  | 
2342  | 0  |     }  | 
2343  | 0  |     if (ret < 0) { | 
2344  | 0  |       _gnutls_debug_log(  | 
2345  | 0  |         "cfg: unable to build priority string: %s\n",  | 
2346  | 0  |         gnutls_strerror(ret));  | 
2347  | 0  |       if (fail_on_invalid_config)  | 
2348  | 0  |         exit(1);  | 
2349  | 0  |       goto out;  | 
2350  | 0  |     }  | 
2351  | 0  |   }  | 
2352  |  |  | 
2353  | 0  |   system_priority_file_loaded = 1;  | 
2354  | 0  |   system_priority_last_mod = sb.st_mtime;  | 
2355  |  | 
  | 
2356  | 20  | out:  | 
2357  | 20  |   (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
2358  |  |  | 
2359  | 20  |   if (config_parse_error && fail_on_invalid_config)  | 
2360  | 0  |     exit(1);  | 
2361  |  |  | 
2362  | 20  |   return ret;  | 
2363  | 20  | }  | 
2364  |  |  | 
2365  |  | void _gnutls_prepare_to_load_system_priorities(void)  | 
2366  | 20  | { | 
2367  | 20  |   const char *p;  | 
2368  | 20  |   int ret;  | 
2369  |  |  | 
2370  | 20  |   p = secure_getenv("GNUTLS_SYSTEM_PRIORITY_FILE"); | 
2371  | 20  |   if (p != NULL)  | 
2372  | 0  |     system_priority_file = p;  | 
2373  |  |  | 
2374  | 20  |   p = secure_getenv("GNUTLS_SYSTEM_PRIORITY_FAIL_ON_INVALID"); | 
2375  | 20  |   if (p != NULL && p[0] == '1' && p[1] == 0)  | 
2376  | 0  |     fail_on_invalid_config = 1;  | 
2377  |  |  | 
2378  | 20  |   ret = _gnutls_update_system_priorities(true /* defer_system_wide */);  | 
2379  | 20  |   if (ret < 0) { | 
2380  | 0  |     _gnutls_debug_log("failed to update system priorities: %s\n", | 
2381  | 0  |           gnutls_strerror(ret));  | 
2382  | 0  |   }  | 
2383  | 20  | }  | 
2384  |  |  | 
2385  |  | void _gnutls_unload_system_priorities(void)  | 
2386  | 0  | { | 
2387  | 0  |   _name_val_array_clear(&system_wide_config.priority_strings);  | 
2388  | 0  |   gnutls_free(system_wide_config.priority_string);  | 
2389  | 0  |   _clear_default_system_priority();  | 
2390  | 0  |   system_priority_last_mod = 0;  | 
2391  | 0  | }  | 
2392  |  |  | 
2393  |  | /**  | 
2394  |  |  * gnutls_get_system_config_file:  | 
2395  |  |  *  | 
2396  |  |  * Returns the filename of the system wide configuration  | 
2397  |  |  * file to be loaded by the library.  | 
2398  |  |  *  | 
2399  |  |  * Returns: a constant pointer to the config file path  | 
2400  |  |  *  | 
2401  |  |  * Since: 3.6.9  | 
2402  |  |  **/  | 
2403  |  | const char *gnutls_get_system_config_file(void)  | 
2404  | 0  | { | 
2405  | 0  |   return system_priority_file;  | 
2406  | 0  | }  | 
2407  |  |  | 
2408  |  | #define S(str) ((str != NULL) ? str : "")  | 
2409  |  |  | 
2410  |  | /* Returns the new priorities if a priority string prefixed  | 
2411  |  |  * with '@' is provided, or just a copy of the provided  | 
2412  |  |  * priorities, appended with any additional present in  | 
2413  |  |  * the priorities string.  | 
2414  |  |  *  | 
2415  |  |  * The returned string must be released using gnutls_free().  | 
2416  |  |  */  | 
2417  |  | char *_gnutls_resolve_priorities(const char *priorities)  | 
2418  | 0  | { | 
2419  | 0  |   const char *p = priorities;  | 
2420  | 0  |   char *additional = NULL;  | 
2421  | 0  |   char *resolved = NULL;  | 
2422  | 0  |   const char *ss, *ss_next;  | 
2423  | 0  |   unsigned ss_len, ss_next_len;  | 
2424  | 0  |   size_t n, n2 = 0;  | 
2425  | 0  |   int ret;  | 
2426  |  | 
  | 
2427  | 0  |   while (c_isspace(*p)) { | 
2428  | 0  |     p++;  | 
2429  | 0  |   }  | 
2430  |  |  | 
2431  |  |   /* Cannot reduce further. */  | 
2432  | 0  |   if (*p != '@') { | 
2433  | 0  |     return gnutls_strdup(p);  | 
2434  | 0  |   }  | 
2435  |  |  | 
2436  | 0  |   ss = p + 1;  | 
2437  | 0  |   additional = strchr(ss, ':');  | 
2438  | 0  |   if (additional) { | 
2439  | 0  |     additional++;  | 
2440  | 0  |   }  | 
2441  |  |  | 
2442  |  |   /* Always try to refresh the cached data, to allow it to be  | 
2443  |  |    * updated without restarting all applications.  | 
2444  |  |    */  | 
2445  | 0  |   ret = _gnutls_update_system_priorities(false /* defer_system_wide */);  | 
2446  | 0  |   if (ret < 0) { | 
2447  | 0  |     _gnutls_debug_log("failed to update system priorities: %s\n", | 
2448  | 0  |           gnutls_strerror(ret));  | 
2449  | 0  |   }  | 
2450  |  | 
  | 
2451  | 0  |   do { | 
2452  | 0  |     ss_next = strchr(ss, ',');  | 
2453  | 0  |     if (ss_next) { | 
2454  | 0  |       if (additional && ss_next > additional) { | 
2455  | 0  |         ss_next = NULL;  | 
2456  | 0  |       } else { | 
2457  | 0  |         ss_next++;  | 
2458  | 0  |       }  | 
2459  | 0  |     }  | 
2460  |  | 
  | 
2461  | 0  |     if (ss_next) { | 
2462  | 0  |       ss_len = ss_next - ss - 1;  | 
2463  | 0  |       ss_next_len = additional - ss_next - 1;  | 
2464  | 0  |     } else if (additional) { | 
2465  | 0  |       ss_len = additional - ss - 1;  | 
2466  | 0  |       ss_next_len = 0;  | 
2467  | 0  |     } else { | 
2468  | 0  |       ss_len = strlen(ss);  | 
2469  | 0  |       ss_next_len = 0;  | 
2470  | 0  |     }  | 
2471  |  | 
  | 
2472  | 0  |     ret = gnutls_rwlock_rdlock(&system_wide_config_rwlock);  | 
2473  | 0  |     if (ret < 0) { | 
2474  | 0  |       _gnutls_debug_log(  | 
2475  | 0  |         "cannot read system priority strings: %s\n",  | 
2476  | 0  |         gnutls_strerror(ret));  | 
2477  | 0  |       break;  | 
2478  | 0  |     }  | 
2479  | 0  |     if (system_wide_config.allowlisting &&  | 
2480  | 0  |         ss_len == sizeof(LEVEL_SYSTEM) - 1 &&  | 
2481  | 0  |         strncmp(LEVEL_SYSTEM, ss, ss_len) == 0) { | 
2482  | 0  |       p = system_wide_config.priority_string;  | 
2483  | 0  |     } else { | 
2484  | 0  |       p = _name_val_array_value(  | 
2485  | 0  |         system_wide_config.priority_strings, ss,  | 
2486  | 0  |         ss_len);  | 
2487  | 0  |     }  | 
2488  |  | 
  | 
2489  | 0  |     _gnutls_debug_log("resolved '%.*s' to '%s', next '%.*s'\n", | 
2490  | 0  |           ss_len, ss, S(p), ss_next_len, S(ss_next));  | 
2491  |  | 
  | 
2492  | 0  |     if (p) { | 
2493  | 0  |       n = strlen(p);  | 
2494  | 0  |       if (additional) { | 
2495  | 0  |         n2 = strlen(additional);  | 
2496  | 0  |       }  | 
2497  |  | 
  | 
2498  | 0  |       resolved = gnutls_malloc(n + n2 + 1 + 1);  | 
2499  | 0  |       if (resolved) { | 
2500  | 0  |         memcpy(resolved, p, n);  | 
2501  | 0  |         if (additional) { | 
2502  | 0  |           resolved[n] = ':';  | 
2503  | 0  |           memcpy(&resolved[n + 1], additional,  | 
2504  | 0  |                  n2);  | 
2505  | 0  |           resolved[n + n2 + 1] = 0;  | 
2506  | 0  |         } else { | 
2507  | 0  |           resolved[n] = 0;  | 
2508  | 0  |         }  | 
2509  | 0  |       }  | 
2510  | 0  |     }  | 
2511  |  | 
  | 
2512  | 0  |     (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
2513  |  | 
  | 
2514  | 0  |     ss = ss_next;  | 
2515  | 0  |   } while (ss && !resolved);  | 
2516  |  |  | 
2517  | 0  |   if (resolved) { | 
2518  | 0  |     _gnutls_debug_log("selected priority string: %s\n", resolved); | 
2519  | 0  |   } else { | 
2520  | 0  |     _gnutls_debug_log("unable to resolve %s\n", priorities); | 
2521  | 0  |   }  | 
2522  |  | 
  | 
2523  | 0  |   return resolved;  | 
2524  | 0  | }  | 
2525  |  |  | 
2526  |  | static void add_ec(gnutls_priority_t priority_cache)  | 
2527  | 0  | { | 
2528  | 0  |   const gnutls_group_entry_st *ge;  | 
2529  | 0  |   unsigned i;  | 
2530  |  | 
  | 
2531  | 0  |   for (i = 0; i < priority_cache->_supported_ecc.num_priorities; i++) { | 
2532  | 0  |     ge = _gnutls_id_to_group(  | 
2533  | 0  |       priority_cache->_supported_ecc.priorities[i]);  | 
2534  | 0  |     if (ge != NULL &&  | 
2535  | 0  |         priority_cache->groups.size <  | 
2536  | 0  |           sizeof(priority_cache->groups.entry) /  | 
2537  | 0  |             sizeof(priority_cache->groups.entry[0])) { | 
2538  |  |       /* do not add groups which do not correspond to enabled ciphersuites */  | 
2539  | 0  |       if (!ge->curve)  | 
2540  | 0  |         continue;  | 
2541  | 0  |       priority_cache->groups  | 
2542  | 0  |         .entry[priority_cache->groups.size++] = ge;  | 
2543  | 0  |     }  | 
2544  | 0  |   }  | 
2545  | 0  | }  | 
2546  |  |  | 
2547  |  | static void add_dh(gnutls_priority_t priority_cache)  | 
2548  | 0  | { | 
2549  | 0  |   const gnutls_group_entry_st *ge;  | 
2550  | 0  |   unsigned i;  | 
2551  |  | 
  | 
2552  | 0  |   for (i = 0; i < priority_cache->_supported_ecc.num_priorities; i++) { | 
2553  | 0  |     ge = _gnutls_id_to_group(  | 
2554  | 0  |       priority_cache->_supported_ecc.priorities[i]);  | 
2555  | 0  |     if (ge != NULL &&  | 
2556  | 0  |         priority_cache->groups.size <  | 
2557  | 0  |           sizeof(priority_cache->groups.entry) /  | 
2558  | 0  |             sizeof(priority_cache->groups.entry[0])) { | 
2559  |  |       /* do not add groups which do not correspond to enabled ciphersuites */  | 
2560  | 0  |       if (!ge->prime)  | 
2561  | 0  |         continue;  | 
2562  | 0  |       priority_cache->groups  | 
2563  | 0  |         .entry[priority_cache->groups.size++] = ge;  | 
2564  | 0  |       priority_cache->groups.have_ffdhe = 1;  | 
2565  | 0  |     }  | 
2566  | 0  |   }  | 
2567  | 0  | }  | 
2568  |  |  | 
2569  |  | static void add_hybrid(gnutls_priority_t priority_cache)  | 
2570  | 0  | { | 
2571  | 0  |   const gnutls_group_entry_st *ge;  | 
2572  | 0  |   unsigned i;  | 
2573  |  | 
  | 
2574  | 0  |   for (i = 0; i < priority_cache->_supported_ecc.num_priorities; i++) { | 
2575  | 0  |     ge = _gnutls_id_to_group(  | 
2576  | 0  |       priority_cache->_supported_ecc.priorities[i]);  | 
2577  | 0  |     if (ge != NULL &&  | 
2578  | 0  |         priority_cache->groups.size <  | 
2579  | 0  |           sizeof(priority_cache->groups.entry) /  | 
2580  | 0  |             sizeof(priority_cache->groups.entry[0])) { | 
2581  |  |       /* do not add groups which do not correspond to enabled ciphersuites */  | 
2582  | 0  |       if (!IS_GROUP_HYBRID(ge))  | 
2583  | 0  |         continue;  | 
2584  | 0  |       priority_cache->groups  | 
2585  | 0  |         .entry[priority_cache->groups.size++] = ge;  | 
2586  | 0  |     }  | 
2587  | 0  |   }  | 
2588  | 0  | }  | 
2589  |  |  | 
2590  |  | /* This function was originally precalculating ciphersuite-specific items, however  | 
2591  |  |  * it has now extended to much more than that. It provides a consistency check to  | 
2592  |  |  * set parameters, and in cases it applies policy specific items.  | 
2593  |  |  */  | 
2594  |  | static int set_ciphersuite_list(gnutls_priority_t priority_cache)  | 
2595  | 0  | { | 
2596  | 0  |   unsigned i, j, z;  | 
2597  | 0  |   const gnutls_cipher_suite_entry_st *ce;  | 
2598  | 0  |   const gnutls_sign_entry_st *se;  | 
2599  | 0  |   unsigned have_ec = 0;  | 
2600  | 0  |   unsigned have_dh = 0;  | 
2601  | 0  |   unsigned have_hybrid = 0;  | 
2602  | 0  |   unsigned tls_sig_sem = 0;  | 
2603  | 0  |   const version_entry_st *tlsmax = NULL, *vers;  | 
2604  | 0  |   const version_entry_st *dtlsmax = NULL;  | 
2605  | 0  |   const version_entry_st *tlsmin = NULL;  | 
2606  | 0  |   const version_entry_st *dtlsmin = NULL;  | 
2607  | 0  |   unsigned have_tls13 = 0, have_srp = 0;  | 
2608  | 0  |   unsigned have_pre_tls12 = 0, have_tls12 = 0;  | 
2609  | 0  |   unsigned have_psk = 0, have_null = 0, have_rsa_psk = 0;  | 
2610  | 0  |   gnutls_digest_algorithm_t prf_digest;  | 
2611  | 0  |   int ret = 0;  | 
2612  |  |  | 
2613  |  |   /* have_psk indicates that a PSK key exchange compatible  | 
2614  |  |    * with TLS1.3 is enabled. */  | 
2615  |  | 
  | 
2616  | 0  |   priority_cache->cs.size = 0;  | 
2617  | 0  |   priority_cache->sigalg.size = 0;  | 
2618  | 0  |   priority_cache->groups.size = 0;  | 
2619  | 0  |   priority_cache->groups.have_ffdhe = 0;  | 
2620  |  |  | 
2621  |  |   /* The following requires a lock so there are no inconsistencies in the  | 
2622  |  |    * members of system_wide_config loaded from the config file. */  | 
2623  | 0  |   ret = gnutls_rwlock_rdlock(&system_wide_config_rwlock);  | 
2624  | 0  |   if (ret < 0) { | 
2625  | 0  |     return gnutls_assert_val(ret);  | 
2626  | 0  |   }  | 
2627  |  |  | 
2628  |  |   /* in blocklisting mode, apply system wide disablement of key exchanges,  | 
2629  |  |    * groups, MACs, and ciphers. */  | 
2630  | 0  |   if (!system_wide_config.allowlisting) { | 
2631  |  |     /* disable key exchanges which are globally disabled */  | 
2632  | 0  |     z = 0;  | 
2633  | 0  |     while (system_wide_config.kxs[z] != 0) { | 
2634  | 0  |       for (i = j = 0; i < priority_cache->_kx.num_priorities;  | 
2635  | 0  |            i++) { | 
2636  | 0  |         if (priority_cache->_kx.priorities[i] !=  | 
2637  | 0  |             system_wide_config.kxs[z])  | 
2638  | 0  |           priority_cache->_kx.priorities[j++] =  | 
2639  | 0  |             priority_cache->_kx  | 
2640  | 0  |               .priorities[i];  | 
2641  | 0  |       }  | 
2642  | 0  |       priority_cache->_kx.num_priorities = j;  | 
2643  | 0  |       z++;  | 
2644  | 0  |     }  | 
2645  |  |  | 
2646  |  |     /* disable groups which are globally disabled */  | 
2647  | 0  |     z = 0;  | 
2648  | 0  |     while (system_wide_config.groups[z] != 0) { | 
2649  | 0  |       for (i = j = 0;  | 
2650  | 0  |            i < priority_cache->_supported_ecc.num_priorities;  | 
2651  | 0  |            i++) { | 
2652  | 0  |         if (priority_cache->_supported_ecc  | 
2653  | 0  |               .priorities[i] !=  | 
2654  | 0  |             system_wide_config.groups[z])  | 
2655  | 0  |           priority_cache->_supported_ecc  | 
2656  | 0  |             .priorities[j++] =  | 
2657  | 0  |             priority_cache->_supported_ecc  | 
2658  | 0  |               .priorities[i];  | 
2659  | 0  |       }  | 
2660  | 0  |       priority_cache->_supported_ecc.num_priorities = j;  | 
2661  | 0  |       z++;  | 
2662  | 0  |     }  | 
2663  |  |  | 
2664  |  |     /* disable ciphers which are globally disabled */  | 
2665  | 0  |     z = 0;  | 
2666  | 0  |     while (system_wide_config.ciphers[z] != 0) { | 
2667  | 0  |       for (i = j = 0;  | 
2668  | 0  |            i < priority_cache->_cipher.num_priorities; i++) { | 
2669  | 0  |         if (priority_cache->_cipher.priorities[i] !=  | 
2670  | 0  |             system_wide_config.ciphers[z])  | 
2671  | 0  |           priority_cache->_cipher.priorities[j++] =  | 
2672  | 0  |             priority_cache->_cipher  | 
2673  | 0  |               .priorities[i];  | 
2674  | 0  |       }  | 
2675  | 0  |       priority_cache->_cipher.num_priorities = j;  | 
2676  | 0  |       z++;  | 
2677  | 0  |     }  | 
2678  |  |  | 
2679  |  |     /* disable MACs which are globally disabled */  | 
2680  | 0  |     z = 0;  | 
2681  | 0  |     while (system_wide_config.macs[z] != 0) { | 
2682  | 0  |       for (i = j = 0; i < priority_cache->_mac.num_priorities;  | 
2683  | 0  |            i++) { | 
2684  | 0  |         if (priority_cache->_mac.priorities[i] !=  | 
2685  | 0  |             system_wide_config.macs[z])  | 
2686  | 0  |           priority_cache->_mac.priorities[j++] =  | 
2687  | 0  |             priority_cache->_mac  | 
2688  | 0  |               .priorities[i];  | 
2689  | 0  |       }  | 
2690  | 0  |       priority_cache->_mac.num_priorities = j;  | 
2691  | 0  |       z++;  | 
2692  | 0  |     }  | 
2693  | 0  |   }  | 
2694  |  | 
  | 
2695  | 0  |   for (j = 0; j < priority_cache->_cipher.num_priorities; j++) { | 
2696  | 0  |     if (priority_cache->_cipher.priorities[j] ==  | 
2697  | 0  |         GNUTLS_CIPHER_NULL) { | 
2698  | 0  |       have_null = 1;  | 
2699  | 0  |       break;  | 
2700  | 0  |     }  | 
2701  | 0  |   }  | 
2702  |  | 
  | 
2703  | 0  |   for (i = 0; i < priority_cache->_kx.num_priorities; i++) { | 
2704  | 0  |     if (IS_SRP_KX(priority_cache->_kx.priorities[i])) { | 
2705  | 0  |       have_srp = 1;  | 
2706  | 0  |     } else if (_gnutls_kx_is_psk(  | 
2707  | 0  |            priority_cache->_kx.priorities[i])) { | 
2708  | 0  |       if (priority_cache->_kx.priorities[i] ==  | 
2709  | 0  |           GNUTLS_KX_RSA_PSK)  | 
2710  | 0  |         have_rsa_psk = 1;  | 
2711  | 0  |       else  | 
2712  | 0  |         have_psk = 1;  | 
2713  | 0  |     }  | 
2714  | 0  |   }  | 
2715  |  |  | 
2716  |  |   /* disable TLS versions which are added but are unsupported */  | 
2717  | 0  |   for (i = j = 0; i < priority_cache->protocol.num_priorities; i++) { | 
2718  | 0  |     vers = version_to_entry(priority_cache->protocol.priorities[i]);  | 
2719  | 0  |     if (!vers || vers->supported ||  | 
2720  | 0  |         (system_wide_config.allowlisting &&  | 
2721  | 0  |          vers->supported_revertible))  | 
2722  | 0  |       priority_cache->protocol.priorities[j++] =  | 
2723  | 0  |         priority_cache->protocol.priorities[i];  | 
2724  | 0  |   }  | 
2725  | 0  |   priority_cache->protocol.num_priorities = j;  | 
2726  |  |  | 
2727  |  |   /* if we have NULL ciphersuites, SRP, or RSA-PSK enabled remove TLS1.3+  | 
2728  |  |    * protocol versions; they cannot be negotiated under TLS1.3. */  | 
2729  | 0  |   if (have_null || have_srp || have_rsa_psk ||  | 
2730  | 0  |       priority_cache->no_extensions) { | 
2731  | 0  |     for (i = j = 0; i < priority_cache->protocol.num_priorities;  | 
2732  | 0  |          i++) { | 
2733  | 0  |       vers = version_to_entry(  | 
2734  | 0  |         priority_cache->protocol.priorities[i]);  | 
2735  | 0  |       if (!vers || !vers->tls13_sem)  | 
2736  | 0  |         priority_cache->protocol.priorities[j++] =  | 
2737  | 0  |           priority_cache->protocol.priorities[i];  | 
2738  | 0  |     }  | 
2739  | 0  |     priority_cache->protocol.num_priorities = j;  | 
2740  | 0  |   }  | 
2741  |  | 
  | 
2742  | 0  |   for (i = 0; i < priority_cache->protocol.num_priorities; i++) { | 
2743  | 0  |     vers = version_to_entry(priority_cache->protocol.priorities[i]);  | 
2744  | 0  |     if (!vers)  | 
2745  | 0  |       continue;  | 
2746  |  |  | 
2747  | 0  |     if (vers->transport == GNUTLS_STREAM) { /* TLS */ | 
2748  | 0  |       tls_sig_sem |= vers->tls_sig_sem;  | 
2749  | 0  |       if (vers->tls13_sem)  | 
2750  | 0  |         have_tls13 = 1;  | 
2751  |  | 
  | 
2752  | 0  |       if (vers->id == GNUTLS_TLS1_2)  | 
2753  | 0  |         have_tls12 = 1;  | 
2754  | 0  |       else if (vers->id < GNUTLS_TLS1_2)  | 
2755  | 0  |         have_pre_tls12 = 1;  | 
2756  |  | 
  | 
2757  | 0  |       if (tlsmax == NULL || vers->age > tlsmax->age)  | 
2758  | 0  |         tlsmax = vers;  | 
2759  | 0  |       if (tlsmin == NULL || vers->age < tlsmin->age)  | 
2760  | 0  |         tlsmin = vers;  | 
2761  | 0  |     } else { /* dtls */ | 
2762  | 0  |       tls_sig_sem |= vers->tls_sig_sem;  | 
2763  |  |  | 
2764  |  |       /* we need to introduce similar handling to above  | 
2765  |  |        * when DTLS1.3 is supported */  | 
2766  |  | 
  | 
2767  | 0  |       if (dtlsmax == NULL || vers->age > dtlsmax->age)  | 
2768  | 0  |         dtlsmax = vers;  | 
2769  | 0  |       if (dtlsmin == NULL || vers->age < dtlsmin->age)  | 
2770  | 0  |         dtlsmin = vers;  | 
2771  | 0  |     }  | 
2772  | 0  |   }  | 
2773  |  |  | 
2774  |  |   /* DTLS or TLS protocols must be present */  | 
2775  | 0  |   if ((!tlsmax || !tlsmin) && (!dtlsmax || !dtlsmin)) { | 
2776  | 0  |     ret = gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET);  | 
2777  | 0  |     goto out;  | 
2778  | 0  |   }  | 
2779  |  |  | 
2780  | 0  |   priority_cache->have_psk = have_psk;  | 
2781  |  |  | 
2782  |  |   /* if we are have TLS1.3+ do not enable any key exchange algorithms,  | 
2783  |  |    * the protocol doesn't require any. */  | 
2784  | 0  |   if (tlsmin && tlsmin->tls13_sem && !have_psk) { | 
2785  | 0  |     if (!dtlsmin || (dtlsmin && dtlsmin->tls13_sem))  | 
2786  | 0  |       priority_cache->_kx.num_priorities = 0;  | 
2787  | 0  |   }  | 
2788  |  |  | 
2789  |  |   /* Add TLS 1.3 ciphersuites (no KX) */  | 
2790  | 0  |   for (j = 0; j < priority_cache->_cipher.num_priorities; j++) { | 
2791  | 0  |     for (z = 0; z < priority_cache->_mac.num_priorities; z++) { | 
2792  | 0  |       ce = cipher_suite_get(  | 
2793  | 0  |         0, priority_cache->_cipher.priorities[j],  | 
2794  | 0  |         priority_cache->_mac.priorities[z]);  | 
2795  | 0  |       if (ce == NULL)  | 
2796  | 0  |         continue;  | 
2797  |  |  | 
2798  | 0  |       prf_digest = MAC_TO_DIG(ce->prf);  | 
2799  | 0  |       if (prf_digest == GNUTLS_DIG_UNKNOWN)  | 
2800  | 0  |         continue;  | 
2801  | 0  |       if (_gnutls_digest_is_insecure(prf_digest))  | 
2802  | 0  |         continue;  | 
2803  |  |  | 
2804  | 0  |       if (priority_cache->cs.size == MAX_CIPHERSUITE_SIZE)  | 
2805  | 0  |         continue;  | 
2806  |  |  | 
2807  | 0  |       priority_cache->cs.entry[priority_cache->cs.size++] =  | 
2808  | 0  |         ce;  | 
2809  |  | 
  | 
2810  | 0  |       if (!have_hybrid) { | 
2811  | 0  |         have_hybrid = 1;  | 
2812  | 0  |         add_hybrid(priority_cache);  | 
2813  | 0  |       }  | 
2814  | 0  |     }  | 
2815  | 0  |   }  | 
2816  |  | 
  | 
2817  | 0  |   for (i = 0; i < priority_cache->_kx.num_priorities; i++) { | 
2818  | 0  |     for (j = 0; j < priority_cache->_cipher.num_priorities; j++) { | 
2819  | 0  |       for (z = 0; z < priority_cache->_mac.num_priorities;  | 
2820  | 0  |            z++) { | 
2821  | 0  |         ce = cipher_suite_get(  | 
2822  | 0  |           priority_cache->_kx.priorities[i],  | 
2823  | 0  |           priority_cache->_cipher.priorities[j],  | 
2824  | 0  |           priority_cache->_mac.priorities[z]);  | 
2825  | 0  |         if (ce == NULL)  | 
2826  | 0  |           continue;  | 
2827  |  |  | 
2828  | 0  |         prf_digest = MAC_TO_DIG(ce->prf);  | 
2829  | 0  |         if (prf_digest == GNUTLS_DIG_UNKNOWN)  | 
2830  | 0  |           continue;  | 
2831  | 0  |         if (_gnutls_digest_is_insecure(prf_digest))  | 
2832  | 0  |           continue;  | 
2833  |  |  | 
2834  | 0  |         if (priority_cache->cs.size ==  | 
2835  | 0  |             MAX_CIPHERSUITE_SIZE)  | 
2836  | 0  |           continue;  | 
2837  | 0  |         priority_cache->cs  | 
2838  | 0  |           .entry[priority_cache->cs.size++] = ce;  | 
2839  | 0  |         if (!have_ec &&  | 
2840  | 0  |             (_gnutls_kx_is_ecc(ce->kx_algorithm) ||  | 
2841  | 0  |              _gnutls_kx_is_vko_gost(ce->kx_algorithm))) { | 
2842  | 0  |           have_ec = 1;  | 
2843  | 0  |           add_ec(priority_cache);  | 
2844  | 0  |         }  | 
2845  | 0  |         if (!have_dh &&  | 
2846  | 0  |             _gnutls_kx_is_dhe(ce->kx_algorithm)) { | 
2847  | 0  |           have_dh = 1;  | 
2848  | 0  |           add_dh(priority_cache);  | 
2849  | 0  |         }  | 
2850  | 0  |       }  | 
2851  | 0  |     }  | 
2852  | 0  |   }  | 
2853  |  | 
  | 
2854  | 0  |   if (have_tls13 && (!have_ec || !have_dh || !have_hybrid)) { | 
2855  |  |     /* scan groups to determine have_{ec,dh,hybrid} */ | 
2856  | 0  |     for (i = 0; i < priority_cache->_supported_ecc.num_priorities;  | 
2857  | 0  |          i++) { | 
2858  | 0  |       const gnutls_group_entry_st *ge;  | 
2859  | 0  |       ge = _gnutls_id_to_group(  | 
2860  | 0  |         priority_cache->_supported_ecc.priorities[i]);  | 
2861  | 0  |       if (ge) { | 
2862  | 0  |         if (ge->curve && !have_ec) { | 
2863  | 0  |           add_ec(priority_cache);  | 
2864  | 0  |           have_ec = 1;  | 
2865  | 0  |         } else if (ge->prime && !have_dh) { | 
2866  | 0  |           add_dh(priority_cache);  | 
2867  | 0  |           have_dh = 1;  | 
2868  | 0  |         } else if (IS_GROUP_HYBRID(ge) &&  | 
2869  | 0  |              !have_hybrid) { | 
2870  | 0  |           add_hybrid(priority_cache);  | 
2871  | 0  |           have_hybrid = 1;  | 
2872  | 0  |         }  | 
2873  |  | 
  | 
2874  | 0  |         if (have_dh && have_ec && have_hybrid)  | 
2875  | 0  |           break;  | 
2876  | 0  |       }  | 
2877  | 0  |     }  | 
2878  | 0  |   }  | 
2879  |  | 
  | 
2880  | 0  |   for (i = 0; i < priority_cache->_sign_algo.num_priorities; i++) { | 
2881  | 0  |     se = _gnutls_sign_to_entry(  | 
2882  | 0  |       priority_cache->_sign_algo.priorities[i]);  | 
2883  | 0  |     if (se != NULL &&  | 
2884  | 0  |         priority_cache->sigalg.size <  | 
2885  | 0  |           sizeof(priority_cache->sigalg.entry) /  | 
2886  | 0  |             sizeof(priority_cache->sigalg.entry[0])) { | 
2887  |  |       /* if the signature algorithm semantics is not  | 
2888  |  |        * compatible with the protocol's, or the algorithm is  | 
2889  |  |        * marked as insecure, then skip. */  | 
2890  | 0  |       if ((se->aid.tls_sem & tls_sig_sem) == 0 ||  | 
2891  | 0  |           !_gnutls_sign_is_secure2(  | 
2892  | 0  |             se,  | 
2893  | 0  |             system_wide_config.allowlisting ?  | 
2894  | 0  |               GNUTLS_SIGN_FLAG_ALLOW_INSECURE_REVERTIBLE :  | 
2895  | 0  |               0)) { | 
2896  | 0  |         continue;  | 
2897  | 0  |       }  | 
2898  | 0  |       priority_cache->sigalg  | 
2899  | 0  |         .entry[priority_cache->sigalg.size++] = se;  | 
2900  | 0  |     }  | 
2901  | 0  |   }  | 
2902  |  | 
  | 
2903  | 0  |   _gnutls_debug_log(  | 
2904  | 0  |     "added %d protocols, %d ciphersuites, %d sig algos and %d groups into priority list\n",  | 
2905  | 0  |     priority_cache->protocol.num_priorities,  | 
2906  | 0  |     priority_cache->cs.size, priority_cache->sigalg.size,  | 
2907  | 0  |     priority_cache->groups.size);  | 
2908  |  | 
  | 
2909  | 0  |   if (priority_cache->sigalg.size == 0) { | 
2910  |  |     /* no signature algorithms; eliminate TLS 1.2 or DTLS 1.2 and later */  | 
2911  | 0  |     priority_st newp;  | 
2912  | 0  |     newp.num_priorities = 0;  | 
2913  |  |  | 
2914  |  |     /* we need to eliminate TLS 1.2 or DTLS 1.2 and later protocols */  | 
2915  | 0  |     for (i = 0; i < priority_cache->protocol.num_priorities; i++) { | 
2916  | 0  |       if (priority_cache->protocol.priorities[i] <  | 
2917  | 0  |           GNUTLS_TLS1_2) { | 
2918  | 0  |         newp.priorities[newp.num_priorities++] =  | 
2919  | 0  |           priority_cache->protocol.priorities[i];  | 
2920  | 0  |       } else if (priority_cache->protocol.priorities[i] >=  | 
2921  | 0  |              GNUTLS_DTLS_VERSION_MIN &&  | 
2922  | 0  |            priority_cache->protocol.priorities[i] <  | 
2923  | 0  |              GNUTLS_DTLS1_2) { | 
2924  | 0  |         newp.priorities[newp.num_priorities++] =  | 
2925  | 0  |           priority_cache->protocol.priorities[i];  | 
2926  | 0  |       }  | 
2927  | 0  |     }  | 
2928  | 0  |     memcpy(&priority_cache->protocol, &newp, sizeof(newp));  | 
2929  | 0  |   }  | 
2930  |  | 
  | 
2931  | 0  |   if (unlikely(priority_cache->protocol.num_priorities == 0)) { | 
2932  | 0  |     ret = gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET);  | 
2933  | 0  |     goto out;  | 
2934  | 0  |   }  | 
2935  | 0  | #ifndef ENABLE_SSL3  | 
2936  | 0  |   else if (unlikely(priority_cache->protocol.num_priorities == 1 &&  | 
2937  | 0  |         priority_cache->protocol.priorities[0] ==  | 
2938  | 0  |           GNUTLS_SSL3)) { | 
2939  | 0  |     ret = gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET);  | 
2940  | 0  |     goto out;  | 
2941  | 0  |   }  | 
2942  | 0  | #endif  | 
2943  |  |  | 
2944  | 0  |   if (unlikely(priority_cache->cs.size == 0)) { | 
2945  | 0  |     ret = gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET);  | 
2946  | 0  |     goto out;  | 
2947  | 0  |   }  | 
2948  |  |  | 
2949  |  |   /* when TLS 1.3 is available we must have groups set; additionally  | 
2950  |  |    * we require TLS1.2 to be enabled if TLS1.3 is asked for, and  | 
2951  |  |    * a pre-TLS1.2 protocol is there; that is because servers which  | 
2952  |  |    * do not support TLS1.3 will negotiate TLS1.2 if seen a TLS1.3 handshake */  | 
2953  | 0  |   if (unlikely((!have_psk && tlsmax && tlsmax->id >= GNUTLS_TLS1_3 &&  | 
2954  | 0  |           priority_cache->groups.size == 0)) ||  | 
2955  | 0  |       (!have_tls12 && have_pre_tls12 && have_tls13)) { | 
2956  | 0  |     for (i = j = 0; i < priority_cache->protocol.num_priorities;  | 
2957  | 0  |          i++) { | 
2958  | 0  |       vers = version_to_entry(  | 
2959  | 0  |         priority_cache->protocol.priorities[i]);  | 
2960  | 0  |       if (!vers || vers->transport != GNUTLS_STREAM ||  | 
2961  | 0  |           !vers->tls13_sem)  | 
2962  | 0  |         priority_cache->protocol.priorities[j++] =  | 
2963  | 0  |           priority_cache->protocol.priorities[i];  | 
2964  | 0  |     }  | 
2965  | 0  |     priority_cache->protocol.num_priorities = j;  | 
2966  | 0  |   }  | 
2967  |  |  | 
2968  |  |   /* ensure that the verification profile is not lower from the configured */  | 
2969  | 0  |   if (system_wide_config.verification_profile) { | 
2970  | 0  |     gnutls_sec_param_t level = priority_cache->level;  | 
2971  | 0  |     gnutls_sec_param_t system_wide_level =  | 
2972  | 0  |       _gnutls_profile_to_sec_level(  | 
2973  | 0  |         system_wide_config.verification_profile);  | 
2974  |  | 
  | 
2975  | 0  |     if (level < system_wide_level) { | 
2976  | 0  |       ENABLE_PROFILE(priority_cache,  | 
2977  | 0  |                system_wide_config.verification_profile);  | 
2978  | 0  |     }  | 
2979  | 0  |   }  | 
2980  |  | 
  | 
2981  | 0  | out:  | 
2982  | 0  |   (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
2983  | 0  |   return ret;  | 
2984  | 0  | }  | 
2985  |  |  | 
2986  |  | /**  | 
2987  |  |  * gnutls_priority_init2:  | 
2988  |  |  * @priority_cache: is a #gnutls_priority_t type.  | 
2989  |  |  * @priorities: is a string describing priorities (may be %NULL)  | 
2990  |  |  * @err_pos: In case of an error this will have the position in the string the error occurred  | 
2991  |  |  * @flags: zero or %GNUTLS_PRIORITY_INIT_DEF_APPEND  | 
2992  |  |  *  | 
2993  |  |  * Sets priorities for the ciphers, key exchange methods, and macs.  | 
2994  |  |  * The @priority_cache should be deinitialized  | 
2995  |  |  * using gnutls_priority_deinit().  | 
2996  |  |  *  | 
2997  |  |  * The #priorities option allows you to specify a colon  | 
2998  |  |  * separated list of the cipher priorities to enable.  | 
2999  |  |  * Some keywords are defined to provide quick access  | 
3000  |  |  * to common preferences.  | 
3001  |  |  *  | 
3002  |  |  * When @flags is set to %GNUTLS_PRIORITY_INIT_DEF_APPEND then the @priorities  | 
3003  |  |  * specified will be appended to the default options.  | 
3004  |  |  *  | 
3005  |  |  * Unless there is a special need, use the "NORMAL" keyword to  | 
3006  |  |  * apply a reasonable security level, or "NORMAL:%%COMPAT" for compatibility.  | 
3007  |  |  *  | 
3008  |  |  * "PERFORMANCE" means all the "secure" ciphersuites are enabled,  | 
3009  |  |  * limited to 128 bit ciphers and sorted by terms of speed  | 
3010  |  |  * performance.  | 
3011  |  |  *  | 
3012  |  |  * "LEGACY" the NORMAL settings for GnuTLS 3.2.x or earlier. There is  | 
3013  |  |  * no verification profile set, and the allowed DH primes are considered  | 
3014  |  |  * weak today.  | 
3015  |  |  *  | 
3016  |  |  * "NORMAL" means all "secure" ciphersuites. The 256-bit ciphers are  | 
3017  |  |  * included as a fallback only.  The ciphers are sorted by security  | 
3018  |  |  * margin.  | 
3019  |  |  *  | 
3020  |  |  * "PFS" means all "secure" ciphersuites that support perfect forward secrecy.  | 
3021  |  |  * The 256-bit ciphers are included as a fallback only.  | 
3022  |  |  * The ciphers are sorted by security margin.  | 
3023  |  |  *  | 
3024  |  |  * "SECURE128" means all "secure" ciphersuites of security level 128-bit  | 
3025  |  |  * or more.  | 
3026  |  |  *  | 
3027  |  |  * "SECURE192" means all "secure" ciphersuites of security level 192-bit  | 
3028  |  |  * or more.  | 
3029  |  |  *  | 
3030  |  |  * "SUITEB128" means all the NSA SuiteB ciphersuites with security level  | 
3031  |  |  * of 128.  | 
3032  |  |  *  | 
3033  |  |  * "SUITEB192" means all the NSA SuiteB ciphersuites with security level  | 
3034  |  |  * of 192.  | 
3035  |  |  *  | 
3036  |  |  * "NONE" means nothing is enabled.  This disables everything, including protocols.  | 
3037  |  |  *  | 
3038  |  |  * "@@KEYWORD1,KEYWORD2,..." The system administrator imposed settings.  | 
3039  |  |  * The provided keyword(s) will be expanded from a configuration-time  | 
3040  |  |  * provided file - default is: /etc/gnutls/config.  | 
3041  |  |  * Any attributes that follow it, will be appended to the expanded  | 
3042  |  |  * string. If multiple keywords are provided, separated by commas,  | 
3043  |  |  * then the first keyword that exists in the configuration file  | 
3044  |  |  * will be used. At least one of the keywords must exist, or this  | 
3045  |  |  * function will return an error. Typical usage would be to specify  | 
3046  |  |  * an application specified keyword first, followed by "SYSTEM" as  | 
3047  |  |  * a default fallback. e.g., "@LIBVIRT,SYSTEM:!-VERS-SSL3.0" will  | 
3048  |  |  * first try to find a config file entry matching "LIBVIRT", but if  | 
3049  |  |  * that does not exist will use the entry for "SYSTEM". If "SYSTEM"  | 
3050  |  |  * does not exist either, an error will be returned. In all cases,  | 
3051  |  |  * the SSL3.0 protocol will be disabled. The system priority file  | 
3052  |  |  * entries should be formatted as "KEYWORD=VALUE", e.g.,  | 
3053  |  |  * "SYSTEM=NORMAL:+ARCFOUR-128".  | 
3054  |  |  *  | 
3055  |  |  * Special keywords are "!", "-" and "+".  | 
3056  |  |  * "!" or "-" appended with an algorithm will remove this algorithm.  | 
3057  |  |  * "+" appended with an algorithm will add this algorithm.  | 
3058  |  |  *  | 
3059  |  |  * Check the GnuTLS manual section "Priority strings" for detailed  | 
3060  |  |  * information.  | 
3061  |  |  *  | 
3062  |  |  * Examples:  | 
3063  |  |  *  | 
3064  |  |  * "NONE:+VERS-TLS-ALL:+MAC-ALL:+RSA:+AES-128-CBC:+SIGN-ALL:+COMP-NULL"  | 
3065  |  |  *  | 
3066  |  |  * "NORMAL:+ARCFOUR-128" means normal ciphers plus ARCFOUR-128.  | 
3067  |  |  *  | 
3068  |  |  * "SECURE128:-VERS-SSL3.0" means that only secure ciphers are  | 
3069  |  |  * and enabled, SSL3.0 is disabled.  | 
3070  |  |  *  | 
3071  |  |  * "NONE:+VERS-TLS-ALL:+AES-128-CBC:+RSA:+SHA1:+COMP-NULL:+SIGN-RSA-SHA1",  | 
3072  |  |  *  | 
3073  |  |  * "NONE:+VERS-TLS-ALL:+AES-128-CBC:+ECDHE-RSA:+SHA1:+COMP-NULL:+SIGN-RSA-SHA1:+CURVE-SECP256R1",  | 
3074  |  |  *  | 
3075  |  |  * "SECURE256:+SECURE128",  | 
3076  |  |  *  | 
3077  |  |  * Note that "NORMAL:%%COMPAT" is the most compatible mode.  | 
3078  |  |  *  | 
3079  |  |  * A %NULL @priorities string indicates the default priorities to be  | 
3080  |  |  * used (this is available since GnuTLS 3.3.0).  | 
3081  |  |  *  | 
3082  |  |  * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,  | 
3083  |  |  * %GNUTLS_E_SUCCESS on success, or an error code.  | 
3084  |  |  *  | 
3085  |  |  * Since: 3.6.3  | 
3086  |  |  **/  | 
3087  |  | int gnutls_priority_init2(gnutls_priority_t *priority_cache,  | 
3088  |  |         const char *priorities, const char **err_pos,  | 
3089  |  |         unsigned flags)  | 
3090  | 0  | { | 
3091  | 0  |   gnutls_buffer_st buf;  | 
3092  | 0  |   const char *ep;  | 
3093  | 0  |   int ret;  | 
3094  |  | 
  | 
3095  | 0  |   *priority_cache = NULL;  | 
3096  | 0  |   if (flags & GNUTLS_PRIORITY_INIT_DEF_APPEND) { | 
3097  | 0  |     if (priorities == NULL)  | 
3098  | 0  |       return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
3099  |  |  | 
3100  | 0  |     if (err_pos)  | 
3101  | 0  |       *err_pos = priorities;  | 
3102  |  | 
  | 
3103  | 0  |     _gnutls_buffer_init(&buf);  | 
3104  |  | 
  | 
3105  | 0  |     ret = _gnutls_buffer_append_str(  | 
3106  | 0  |       &buf, _gnutls_default_priority_string);  | 
3107  | 0  |     if (ret < 0) { | 
3108  | 0  |       _gnutls_buffer_clear(&buf);  | 
3109  | 0  |       return gnutls_assert_val(ret);  | 
3110  | 0  |     }  | 
3111  |  |  | 
3112  | 0  |     ret = _gnutls_buffer_append_str(&buf, ":");  | 
3113  | 0  |     if (ret < 0) { | 
3114  | 0  |       _gnutls_buffer_clear(&buf);  | 
3115  | 0  |       return gnutls_assert_val(ret);  | 
3116  | 0  |     }  | 
3117  |  |  | 
3118  | 0  |     ret = _gnutls_buffer_append_str(&buf, priorities);  | 
3119  | 0  |     if (ret < 0) { | 
3120  | 0  |       _gnutls_buffer_clear(&buf);  | 
3121  | 0  |       return gnutls_assert_val(ret);  | 
3122  | 0  |     }  | 
3123  |  |  | 
3124  | 0  |     ret = gnutls_priority_init(priority_cache,  | 
3125  | 0  |              (const char *)buf.data, &ep);  | 
3126  | 0  |     if (ret < 0 && ep != (const char *)buf.data && ep != NULL) { | 
3127  | 0  |       ptrdiff_t diff = (ptrdiff_t)ep - (ptrdiff_t)buf.data;  | 
3128  | 0  |       unsigned hlen =  | 
3129  | 0  |         strlen(_gnutls_default_priority_string) + 1;  | 
3130  |  | 
  | 
3131  | 0  |       if (err_pos && diff > hlen) { | 
3132  | 0  |         *err_pos = priorities + diff - hlen;  | 
3133  | 0  |       }  | 
3134  | 0  |     }  | 
3135  | 0  |     _gnutls_buffer_clear(&buf);  | 
3136  | 0  |     return ret;  | 
3137  | 0  |   } else { | 
3138  | 0  |     return gnutls_priority_init(priority_cache, priorities,  | 
3139  | 0  |               err_pos);  | 
3140  | 0  |   }  | 
3141  | 0  | }  | 
3142  |  |  | 
3143  |  | #define PRIO_MATCH(name) \  | 
3144  | 0  |   c_strncasecmp(&broken_list[i][1], name, sizeof(name) - 1)  | 
3145  |  |  | 
3146  |  | /**  | 
3147  |  |  * gnutls_priority_init:  | 
3148  |  |  * @priority_cache: is a #gnutls_priority_t type.  | 
3149  |  |  * @priorities: is a string describing priorities (may be %NULL)  | 
3150  |  |  * @err_pos: In case of an error this will have the position in the string the error occurred  | 
3151  |  |  *  | 
3152  |  |  * For applications that do not modify their crypto settings per release, consider  | 
3153  |  |  * using gnutls_priority_init2() with %GNUTLS_PRIORITY_INIT_DEF_APPEND flag  | 
3154  |  |  * instead. We suggest to use centralized crypto settings handled by the GnuTLS  | 
3155  |  |  * library, and applications modifying the default settings to their needs.  | 
3156  |  |  *  | 
3157  |  |  * This function is identical to gnutls_priority_init2() with zero  | 
3158  |  |  * flags.  | 
3159  |  |  *  | 
3160  |  |  * A %NULL @priorities string indicates the default priorities to be  | 
3161  |  |  * used (this is available since GnuTLS 3.3.0).  | 
3162  |  |  *  | 
3163  |  |  * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,  | 
3164  |  |  * %GNUTLS_E_SUCCESS on success, or an error code.  | 
3165  |  |  **/  | 
3166  |  | int gnutls_priority_init(gnutls_priority_t *priority_cache,  | 
3167  |  |        const char *priorities, const char **err_pos)  | 
3168  | 0  | { | 
3169  | 0  |   char *broken_list[MAX_ELEMENTS];  | 
3170  | 0  |   int broken_list_size = 0, i = 0, j;  | 
3171  | 0  |   char *darg = NULL;  | 
3172  | 0  |   unsigned ikeyword_set = 0;  | 
3173  | 0  |   int algo;  | 
3174  | 0  |   int ret;  | 
3175  | 0  |   rmadd_func *fn;  | 
3176  | 0  |   bulk_rmadd_func *bulk_fn;  | 
3177  | 0  |   bulk_rmadd_func *bulk_given_fn;  | 
3178  | 0  |   const cipher_entry_st *centry;  | 
3179  | 0  |   unsigned resolved_match = 1;  | 
3180  |  | 
  | 
3181  | 0  |   if (err_pos)  | 
3182  | 0  |     *err_pos = priorities;  | 
3183  |  | 
  | 
3184  | 0  |   *priority_cache = gnutls_calloc(1, sizeof(struct gnutls_priority_st));  | 
3185  | 0  |   if (*priority_cache == NULL) { | 
3186  | 0  |     gnutls_assert();  | 
3187  | 0  |     return GNUTLS_E_MEMORY_ERROR;  | 
3188  | 0  |   }  | 
3189  |  |  | 
3190  |  |   /* for now unsafe renegotiation is default on everyone. To be removed  | 
3191  |  |    * when we make it the default.  | 
3192  |  |    */  | 
3193  | 0  |   (*priority_cache)->sr = SR_PARTIAL;  | 
3194  |  |   /* For now TLS 1.3 middlebox compatibility mode is enabled by default.  | 
3195  |  |    * This will eventually be disabled by default and moved to the %COMPAT  | 
3196  |  |    * setting.  | 
3197  |  |    */  | 
3198  | 0  |   (*priority_cache)->tls13_compat_mode = true;  | 
3199  | 0  |   (*priority_cache)->min_record_version = 1;  | 
3200  | 0  |   gnutls_atomic_init(&(*priority_cache)->usage_cnt);  | 
3201  |  | 
  | 
3202  | 0  |   if (_gnutls_fips_mode_enabled()) { | 
3203  | 0  |     (*priority_cache)->force_ext_master_secret = EMS_REQUIRE;  | 
3204  | 0  |   } else { | 
3205  | 0  |     (*priority_cache)->force_ext_master_secret = EMS_REQUEST;  | 
3206  | 0  |   }  | 
3207  |  | 
  | 
3208  | 0  |   if (system_wide_config.allowlisting && !priorities) { | 
3209  | 0  |     priorities = "@" LEVEL_SYSTEM;  | 
3210  | 0  |   }  | 
3211  | 0  |   if (priorities == NULL) { | 
3212  | 0  |     priorities = _gnutls_default_priority_string;  | 
3213  | 0  |     resolved_match = 0;  | 
3214  | 0  |   }  | 
3215  |  | 
  | 
3216  | 0  |   darg = _gnutls_resolve_priorities(priorities);  | 
3217  | 0  |   if (darg == NULL) { | 
3218  | 0  |     gnutls_assert();  | 
3219  | 0  |     goto error;  | 
3220  | 0  |   }  | 
3221  |  |  | 
3222  | 0  |   if (strcmp(darg, priorities) != 0)  | 
3223  | 0  |     resolved_match = 0;  | 
3224  |  | 
  | 
3225  | 0  |   break_list(darg, broken_list, &broken_list_size);  | 
3226  |  |   /* This is our default set of protocol version, certificate types.  | 
3227  |  |    */  | 
3228  | 0  |   if (c_strcasecmp(broken_list[0], LEVEL_NONE) != 0) { | 
3229  | 0  |     _set_priority(&(*priority_cache)->protocol, protocol_priority);  | 
3230  | 0  |     _set_priority(&(*priority_cache)->client_ctype,  | 
3231  | 0  |             cert_type_priority_default);  | 
3232  | 0  |     _set_priority(&(*priority_cache)->server_ctype,  | 
3233  | 0  |             cert_type_priority_default);  | 
3234  | 0  |     _set_priority(&(*priority_cache)->_sign_algo,  | 
3235  | 0  |             sign_priority_default);  | 
3236  | 0  |     _set_priority(&(*priority_cache)->_supported_ecc,  | 
3237  | 0  |             supported_groups_normal);  | 
3238  | 0  |     i = 0;  | 
3239  | 0  |   } else { | 
3240  | 0  |     ikeyword_set = 1;  | 
3241  | 0  |     i = 1;  | 
3242  | 0  |   }  | 
3243  |  | 
  | 
3244  | 0  |   for (; i < broken_list_size; i++) { | 
3245  | 0  |     if (check_level(broken_list[i], *priority_cache,  | 
3246  | 0  |         ikeyword_set) != 0) { | 
3247  | 0  |       ikeyword_set = 1;  | 
3248  | 0  |       continue;  | 
3249  | 0  |     } else if (broken_list[i][0] == '!' ||  | 
3250  | 0  |          broken_list[i][0] == '+' ||  | 
3251  | 0  |          broken_list[i][0] == '-') { | 
3252  | 0  |       if (broken_list[i][0] == '+') { | 
3253  | 0  |         fn = prio_add;  | 
3254  | 0  |         bulk_fn = _add_priority;  | 
3255  | 0  |         bulk_given_fn = _add_priority;  | 
3256  | 0  |       } else { | 
3257  | 0  |         fn = prio_remove;  | 
3258  | 0  |         bulk_fn = _clear_priorities;  | 
3259  | 0  |         bulk_given_fn = _clear_given_priorities;  | 
3260  | 0  |       }  | 
3261  |  | 
  | 
3262  | 0  |       if (broken_list[i][0] == '+' &&  | 
3263  | 0  |           check_level(&broken_list[i][1], *priority_cache,  | 
3264  | 0  |           1) != 0) { | 
3265  | 0  |         continue;  | 
3266  | 0  |       } else if ((algo = gnutls_mac_get_id(  | 
3267  | 0  |               &broken_list[i][1])) !=  | 
3268  | 0  |            GNUTLS_MAC_UNKNOWN) { | 
3269  | 0  |         fn(&(*priority_cache)->_mac, algo);  | 
3270  | 0  |       } else if ((centry = cipher_name_to_entry(  | 
3271  | 0  |               &broken_list[i][1])) != NULL) { | 
3272  | 0  |         if (_gnutls_cipher_exists(centry->id)) { | 
3273  | 0  |           fn(&(*priority_cache)->_cipher,  | 
3274  | 0  |              centry->id);  | 
3275  | 0  |           if (centry->type == CIPHER_BLOCK)  | 
3276  | 0  |             (*priority_cache)->have_cbc = 1;  | 
3277  | 0  |         }  | 
3278  | 0  |       } else if ((algo = _gnutls_kx_get_id(  | 
3279  | 0  |               &broken_list[i][1])) !=  | 
3280  | 0  |            GNUTLS_KX_UNKNOWN) { | 
3281  | 0  |         if (algo != GNUTLS_KX_INVALID)  | 
3282  | 0  |           fn(&(*priority_cache)->_kx, algo);  | 
3283  | 0  |       } else if (PRIO_MATCH("VERS-") == 0) { | 
3284  | 0  |         if (PRIO_MATCH("VERS-TLS-ALL") == 0) { | 
3285  | 0  |           bulk_given_fn(  | 
3286  | 0  |             &(*priority_cache)->protocol,  | 
3287  | 0  |             stream_protocol_priority);  | 
3288  | 0  |         } else if (PRIO_MATCH("VERS-DTLS-ALL") == 0) { | 
3289  | 0  |           bulk_given_fn(  | 
3290  | 0  |             &(*priority_cache)->protocol,  | 
3291  | 0  |             (bulk_given_fn ==  | 
3292  | 0  |              _add_priority) ?  | 
3293  | 0  |               dtls_protocol_priority :  | 
3294  | 0  |               dgram_protocol_priority);  | 
3295  | 0  |         } else if (PRIO_MATCH("VERS-ALL") == 0) { | 
3296  | 0  |           bulk_fn(&(*priority_cache)->protocol,  | 
3297  | 0  |             protocol_priority);  | 
3298  | 0  |         } else { | 
3299  | 0  |           if ((algo = gnutls_protocol_get_id(  | 
3300  | 0  |                  &broken_list[i][6])) !=  | 
3301  | 0  |               GNUTLS_VERSION_UNKNOWN) { | 
3302  | 0  |             fn(&(*priority_cache)->protocol,  | 
3303  | 0  |                algo);  | 
3304  | 0  |           } else  | 
3305  | 0  |             goto error;  | 
3306  | 0  |         }  | 
3307  | 0  |       } /* now check if the element is something like -ALGO */  | 
3308  | 0  |       else if (PRIO_MATCH("COMP-") == 0) { | 
3309  |  |         /* ignore all compression methods */  | 
3310  | 0  |         continue;  | 
3311  | 0  |       } /* now check if the element is something like -ALGO */  | 
3312  | 0  |       else if (PRIO_MATCH("CURVE-") == 0) { | 
3313  | 0  |         if (PRIO_MATCH("CURVE-ALL") == 0) { | 
3314  | 0  |           bulk_fn(&(*priority_cache)  | 
3315  | 0  |                ->_supported_ecc,  | 
3316  | 0  |             supported_groups_normal);  | 
3317  | 0  |         } else { | 
3318  | 0  |           if ((algo = gnutls_ecc_curve_get_id(  | 
3319  | 0  |                  &broken_list[i][7])) !=  | 
3320  | 0  |               GNUTLS_ECC_CURVE_INVALID)  | 
3321  | 0  |             fn(&(*priority_cache)  | 
3322  | 0  |                   ->_supported_ecc,  | 
3323  | 0  |                algo);  | 
3324  | 0  |           else  | 
3325  | 0  |             goto error;  | 
3326  | 0  |         }  | 
3327  | 0  |       } else if (PRIO_MATCH("GROUP-") == 0) { | 
3328  | 0  |         if (PRIO_MATCH("GROUP-ALL") == 0) { | 
3329  | 0  |           bulk_fn(&(*priority_cache)  | 
3330  | 0  |                ->_supported_ecc,  | 
3331  | 0  |             supported_groups_normal);  | 
3332  | 0  |         } else if (PRIO_MATCH("GROUP-DH-ALL") == 0) { | 
3333  | 0  |           bulk_given_fn(&(*priority_cache)  | 
3334  | 0  |                      ->_supported_ecc,  | 
3335  | 0  |                   _supported_groups_dh);  | 
3336  | 0  |         } else if (PRIO_MATCH("GROUP-EC-ALL") == 0) { | 
3337  | 0  |           bulk_given_fn(&(*priority_cache)  | 
3338  | 0  |                      ->_supported_ecc,  | 
3339  | 0  |                   _supported_groups_ecdh);  | 
3340  | 0  |         } else if (PRIO_MATCH("GROUP-GOST-ALL") == 0) { | 
3341  | 0  |           bulk_given_fn(&(*priority_cache)  | 
3342  | 0  |                      ->_supported_ecc,  | 
3343  | 0  |                   _supported_groups_gost);  | 
3344  | 0  |         } else { | 
3345  | 0  |           if ((algo = _gnutls_group_get_id(  | 
3346  | 0  |                  &broken_list[i][7])) !=  | 
3347  | 0  |               GNUTLS_GROUP_INVALID)  | 
3348  | 0  |             fn(&(*priority_cache)  | 
3349  | 0  |                   ->_supported_ecc,  | 
3350  | 0  |                algo);  | 
3351  | 0  |           else  | 
3352  | 0  |             goto error;  | 
3353  | 0  |         }  | 
3354  | 0  |       } else if (PRIO_MATCH("CTYPE-") == 0) { | 
3355  |  |         // Certificate types  | 
3356  | 0  |         if (PRIO_MATCH("CTYPE-ALL") == 0) { | 
3357  |  |           // Symmetric cert types, all types allowed  | 
3358  | 0  |           bulk_fn(&(*priority_cache)->client_ctype,  | 
3359  | 0  |             cert_type_priority_all);  | 
3360  | 0  |           bulk_fn(&(*priority_cache)->server_ctype,  | 
3361  | 0  |             cert_type_priority_all);  | 
3362  | 0  |         } else if (PRIO_MATCH("CTYPE-CLI-") == 0) { | 
3363  |  |           // Client certificate types  | 
3364  | 0  |           if (PRIO_MATCH("CTYPE-CLI-ALL") == 0) { | 
3365  |  |             // All client cert types allowed  | 
3366  | 0  |             bulk_fn(&(*priority_cache)  | 
3367  | 0  |                  ->client_ctype,  | 
3368  | 0  |               cert_type_priority_all);  | 
3369  | 0  |           } else if ((algo = gnutls_certificate_type_get_id(  | 
3370  | 0  |                   &broken_list[i]  | 
3371  | 0  |                   [11])) !=  | 
3372  | 0  |                GNUTLS_CRT_UNKNOWN) { | 
3373  |  |             // Specific client cert type allowed  | 
3374  | 0  |             fn(&(*priority_cache)  | 
3375  | 0  |                   ->client_ctype,  | 
3376  | 0  |                algo);  | 
3377  | 0  |           } else  | 
3378  | 0  |             goto error;  | 
3379  | 0  |         } else if (PRIO_MATCH("CTYPE-SRV-") == 0) { | 
3380  |  |           // Server certificate types  | 
3381  | 0  |           if (PRIO_MATCH("CTYPE-SRV-ALL") == 0) { | 
3382  |  |             // All server cert types allowed  | 
3383  | 0  |             bulk_fn(&(*priority_cache)  | 
3384  | 0  |                  ->server_ctype,  | 
3385  | 0  |               cert_type_priority_all);  | 
3386  | 0  |           } else if ((algo = gnutls_certificate_type_get_id(  | 
3387  | 0  |                   &broken_list[i]  | 
3388  | 0  |                   [11])) !=  | 
3389  | 0  |                GNUTLS_CRT_UNKNOWN) { | 
3390  |  |             // Specific server cert type allowed  | 
3391  | 0  |             fn(&(*priority_cache)  | 
3392  | 0  |                   ->server_ctype,  | 
3393  | 0  |                algo);  | 
3394  | 0  |           } else  | 
3395  | 0  |             goto error;  | 
3396  | 0  |         } else { // Symmetric certificate type | 
3397  | 0  |           if ((algo = gnutls_certificate_type_get_id(  | 
3398  | 0  |                  &broken_list[i][7])) !=  | 
3399  | 0  |               GNUTLS_CRT_UNKNOWN) { | 
3400  | 0  |             fn(&(*priority_cache)  | 
3401  | 0  |                   ->client_ctype,  | 
3402  | 0  |                algo);  | 
3403  | 0  |             fn(&(*priority_cache)  | 
3404  | 0  |                   ->server_ctype,  | 
3405  | 0  |                algo);  | 
3406  | 0  |           } else if (PRIO_MATCH(  | 
3407  | 0  |                  "CTYPE-OPENPGP") ==  | 
3408  | 0  |                0) { | 
3409  |  |             /* legacy openpgp option - ignore */  | 
3410  | 0  |             continue;  | 
3411  | 0  |           } else  | 
3412  | 0  |             goto error;  | 
3413  | 0  |         }  | 
3414  | 0  |       } else if (PRIO_MATCH("SIGN-") == 0) { | 
3415  | 0  |         if (PRIO_MATCH("SIGN-ALL") == 0) { | 
3416  | 0  |           bulk_fn(&(*priority_cache)->_sign_algo,  | 
3417  | 0  |             sign_priority_default);  | 
3418  | 0  |         } else if (PRIO_MATCH("SIGN-GOST-ALL") == 0) { | 
3419  | 0  |           bulk_fn(&(*priority_cache)->_sign_algo,  | 
3420  | 0  |             sign_priority_gost);  | 
3421  | 0  |         } else { | 
3422  | 0  |           if ((algo = gnutls_sign_get_id(  | 
3423  | 0  |                  &broken_list[i][6])) !=  | 
3424  | 0  |               GNUTLS_SIGN_UNKNOWN)  | 
3425  | 0  |             fn(&(*priority_cache)  | 
3426  | 0  |                   ->_sign_algo,  | 
3427  | 0  |                algo);  | 
3428  | 0  |           else  | 
3429  | 0  |             goto error;  | 
3430  | 0  |         }  | 
3431  | 0  |       } else if (PRIO_MATCH("MAC-") == 0) { | 
3432  | 0  |         if (PRIO_MATCH("MAC-ALL") == 0) { | 
3433  | 0  |           bulk_fn(&(*priority_cache)->_mac,  | 
3434  | 0  |             mac_priority_normal);  | 
3435  | 0  |         } else if (PRIO_MATCH("MAC-GOST-ALL") == 0) { | 
3436  | 0  |           bulk_fn(&(*priority_cache)->_mac,  | 
3437  | 0  |             mac_priority_gost);  | 
3438  | 0  |         }  | 
3439  | 0  |       } else if (PRIO_MATCH("CIPHER-") == 0) { | 
3440  | 0  |         if (PRIO_MATCH("CIPHER-ALL") == 0) { | 
3441  | 0  |           bulk_fn(&(*priority_cache)->_cipher,  | 
3442  | 0  |             cipher_priority_normal);  | 
3443  | 0  |         } else if (PRIO_MATCH("CIPHER-GOST-ALL") == 0) { | 
3444  | 0  |           bulk_fn(&(*priority_cache)->_cipher,  | 
3445  | 0  |             cipher_priority_gost);  | 
3446  | 0  |         }  | 
3447  | 0  |       } else if (PRIO_MATCH("KX-") == 0) { | 
3448  | 0  |         if (PRIO_MATCH("KX-ALL") == 0) { | 
3449  | 0  |           bulk_fn(&(*priority_cache)->_kx,  | 
3450  | 0  |             kx_priority_secure);  | 
3451  | 0  |         } else if (PRIO_MATCH("KX-GOST-ALL") == 0) { | 
3452  | 0  |           bulk_fn(&(*priority_cache)->_kx,  | 
3453  | 0  |             kx_priority_gost);  | 
3454  | 0  |         }  | 
3455  | 0  |       } else if (PRIO_MATCH("GOST") == 0) { | 
3456  | 0  |         bulk_given_fn(  | 
3457  | 0  |           &(*priority_cache)->_supported_ecc,  | 
3458  | 0  |           _supported_groups_gost);  | 
3459  | 0  |         bulk_fn(&(*priority_cache)->_sign_algo,  | 
3460  | 0  |           sign_priority_gost);  | 
3461  | 0  |         bulk_fn(&(*priority_cache)->_mac,  | 
3462  | 0  |           mac_priority_gost);  | 
3463  | 0  |         bulk_fn(&(*priority_cache)->_cipher,  | 
3464  | 0  |           cipher_priority_gost);  | 
3465  | 0  |         bulk_fn(&(*priority_cache)->_kx,  | 
3466  | 0  |           kx_priority_gost);  | 
3467  | 0  |       } else  | 
3468  | 0  |         goto error;  | 
3469  | 0  |     } else if (broken_list[i][0] == '%') { | 
3470  | 0  |       const struct priority_options_st *o;  | 
3471  |  |       /* to add a new option modify  | 
3472  |  |        * priority_options.gperf */  | 
3473  | 0  |       o = in_word_set(&broken_list[i][1],  | 
3474  | 0  |           strlen(&broken_list[i][1]));  | 
3475  | 0  |       if (o == NULL) { | 
3476  | 0  |         goto error;  | 
3477  | 0  |       }  | 
3478  | 0  |       o->func(*priority_cache);  | 
3479  | 0  |     } else  | 
3480  | 0  |       goto error;  | 
3481  | 0  |   }  | 
3482  |  |  | 
3483  |  |   /* This needs to be done after parsing modifiers, as  | 
3484  |  |    * tls-session-hash has precedence over modifiers.  | 
3485  |  |    */  | 
3486  | 0  |   if (system_wide_config.force_ext_master_secret_set) { | 
3487  | 0  |     (*priority_cache)->force_ext_master_secret =  | 
3488  | 0  |       system_wide_config.force_ext_master_secret;  | 
3489  | 0  |     (*priority_cache)->_no_ext_master_secret = false;  | 
3490  | 0  |   }  | 
3491  |  | 
  | 
3492  | 0  |   ret = set_ciphersuite_list(*priority_cache);  | 
3493  | 0  |   if (ret < 0) { | 
3494  | 0  |     if (err_pos)  | 
3495  | 0  |       *err_pos = priorities;  | 
3496  | 0  |     goto error_cleanup;  | 
3497  | 0  |   }  | 
3498  |  |  | 
3499  | 0  |   gnutls_free(darg);  | 
3500  |  | 
  | 
3501  | 0  |   return 0;  | 
3502  |  |  | 
3503  | 0  | error:  | 
3504  | 0  |   if (err_pos != NULL && i < broken_list_size && resolved_match) { | 
3505  | 0  |     *err_pos = priorities;  | 
3506  | 0  |     for (j = 0; j < i; j++) { | 
3507  | 0  |       (*err_pos) += strlen(broken_list[j]) + 1;  | 
3508  | 0  |     }  | 
3509  | 0  |   }  | 
3510  | 0  |   ret = GNUTLS_E_INVALID_REQUEST;  | 
3511  |  | 
  | 
3512  | 0  | error_cleanup:  | 
3513  | 0  |   gnutls_free(darg);  | 
3514  | 0  |   gnutls_priority_deinit(*priority_cache);  | 
3515  | 0  |   *priority_cache = NULL;  | 
3516  |  | 
  | 
3517  | 0  |   return ret;  | 
3518  | 0  | }  | 
3519  |  |  | 
3520  |  | /**  | 
3521  |  |  * gnutls_priority_deinit:  | 
3522  |  |  * @priority_cache: is a #gnutls_priority_t type.  | 
3523  |  |  *  | 
3524  |  |  * Deinitializes the priority cache.  | 
3525  |  |  **/  | 
3526  |  | void gnutls_priority_deinit(gnutls_priority_t priority_cache)  | 
3527  | 0  | { | 
3528  | 0  |   if (priority_cache == NULL)  | 
3529  | 0  |     return;  | 
3530  |  |  | 
3531  |  |   /* Note that here we care about the following two cases:  | 
3532  |  |    * 1. Multiple sessions or different threads holding a reference + a global reference  | 
3533  |  |    * 2. One session holding a reference with a possible global reference  | 
3534  |  |    *  | 
3535  |  |    * As such, it will never be that two threads reach the  | 
3536  |  |    * zero state at the same time, unless the global reference  | 
3537  |  |    * is cleared too, which is invalid state.  | 
3538  |  |    */  | 
3539  | 0  |   if (gnutls_atomic_val(&priority_cache->usage_cnt) == 0) { | 
3540  | 0  |     gnutls_atomic_deinit(&priority_cache->usage_cnt);  | 
3541  | 0  |     gnutls_free(priority_cache);  | 
3542  | 0  |     return;  | 
3543  | 0  |   } else { | 
3544  | 0  |     gnutls_atomic_decrement(&priority_cache->usage_cnt);  | 
3545  | 0  |   }  | 
3546  | 0  | }  | 
3547  |  |  | 
3548  |  | /**  | 
3549  |  |  * gnutls_priority_set_direct:  | 
3550  |  |  * @session: is a #gnutls_session_t type.  | 
3551  |  |  * @priorities: is a string describing priorities  | 
3552  |  |  * @err_pos: In case of an error this will have the position in the string the error occurred  | 
3553  |  |  *  | 
3554  |  |  * Sets the priorities to use on the ciphers, key exchange methods,  | 
3555  |  |  * and macs.  This function avoids keeping a  | 
3556  |  |  * priority cache and is used to directly set string priorities to a  | 
3557  |  |  * TLS session.  For documentation check the gnutls_priority_init().  | 
3558  |  |  *  | 
3559  |  |  * To use a reasonable default, consider using gnutls_set_default_priority(),  | 
3560  |  |  * or gnutls_set_default_priority_append() instead of this function.  | 
3561  |  |  *  | 
3562  |  |  * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,  | 
3563  |  |  * %GNUTLS_E_SUCCESS on success, or an error code.  | 
3564  |  |  **/  | 
3565  |  | int gnutls_priority_set_direct(gnutls_session_t session, const char *priorities,  | 
3566  |  |              const char **err_pos)  | 
3567  | 0  | { | 
3568  | 0  |   gnutls_priority_t prio;  | 
3569  | 0  |   int ret;  | 
3570  |  | 
  | 
3571  | 0  |   ret = gnutls_priority_init(&prio, priorities, err_pos);  | 
3572  | 0  |   if (ret < 0) { | 
3573  | 0  |     gnutls_assert();  | 
3574  | 0  |     return ret;  | 
3575  | 0  |   }  | 
3576  |  |  | 
3577  | 0  |   ret = gnutls_priority_set(session, prio);  | 
3578  | 0  |   if (ret < 0) { | 
3579  | 0  |     gnutls_assert();  | 
3580  | 0  |     return ret;  | 
3581  | 0  |   }  | 
3582  |  |  | 
3583  |  |   /* ensure that the session holds the only reference for the struct */  | 
3584  | 0  |   gnutls_priority_deinit(prio);  | 
3585  |  | 
  | 
3586  | 0  |   return 0;  | 
3587  | 0  | }  | 
3588  |  |  | 
3589  |  | /* Breaks a list of "xxx", "yyy", to a character array, of  | 
3590  |  |  * MAX_COMMA_SEP_ELEMENTS size; Note that the given string is modified.  | 
3591  |  |   */  | 
3592  |  | static void break_list(char *list, char *broken_list[MAX_ELEMENTS], int *size)  | 
3593  | 0  | { | 
3594  | 0  |   char *p = list;  | 
3595  |  | 
  | 
3596  | 0  |   *size = 0;  | 
3597  |  | 
  | 
3598  | 0  |   do { | 
3599  | 0  |     broken_list[*size] = p;  | 
3600  |  | 
  | 
3601  | 0  |     (*size)++;  | 
3602  |  | 
  | 
3603  | 0  |     p = strchr(p, ':');  | 
3604  | 0  |     if (p) { | 
3605  | 0  |       *p = 0;  | 
3606  | 0  |       p++; /* move to next entry and skip white  | 
3607  |  |          * space.  | 
3608  |  |          */  | 
3609  | 0  |       while (*p == ' ')  | 
3610  | 0  |         p++;  | 
3611  | 0  |     }  | 
3612  | 0  |   } while (p != NULL && *size < MAX_ELEMENTS);  | 
3613  | 0  | }  | 
3614  |  |  | 
3615  |  | /**  | 
3616  |  |  * gnutls_set_default_priority:  | 
3617  |  |  * @session: is a #gnutls_session_t type.  | 
3618  |  |  *  | 
3619  |  |  * Sets the default priority on the ciphers, key exchange methods,  | 
3620  |  |  * and macs. This is the recommended method of  | 
3621  |  |  * setting the defaults, in order to promote consistency between applications  | 
3622  |  |  * using GnuTLS, and to allow GnuTLS using applications to update settings  | 
3623  |  |  * in par with the library. For client applications which require  | 
3624  |  |  * maximum compatibility consider calling gnutls_session_enable_compatibility_mode()  | 
3625  |  |  * after this function.  | 
3626  |  |  *  | 
3627  |  |  * For an application to specify additional options to priority string  | 
3628  |  |  * consider using gnutls_set_default_priority_append().  | 
3629  |  |  *  | 
3630  |  |  * To allow a user to override the defaults (e.g., when a user interface  | 
3631  |  |  * or configuration file is available), the functions  | 
3632  |  |  * gnutls_priority_set_direct() or gnutls_priority_set() can  | 
3633  |  |  * be used.  | 
3634  |  |  *  | 
3635  |  |  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.  | 
3636  |  |  *  | 
3637  |  |  * Since: 2.1.4  | 
3638  |  |  **/  | 
3639  |  | int gnutls_set_default_priority(gnutls_session_t session)  | 
3640  | 0  | { | 
3641  | 0  |   return gnutls_priority_set_direct(session, NULL, NULL);  | 
3642  | 0  | }  | 
3643  |  |  | 
3644  |  | /**  | 
3645  |  |  * gnutls_set_default_priority_append:  | 
3646  |  |  * @session: is a #gnutls_session_t type.  | 
3647  |  |  * @add_prio: is a string describing priorities to be appended to default  | 
3648  |  |  * @err_pos: In case of an error this will have the position in the string the error occurred  | 
3649  |  |  * @flags: must be zero  | 
3650  |  |  *  | 
3651  |  |  * Sets the default priority on the ciphers, key exchange methods,  | 
3652  |  |  * and macs with the additional options in @add_prio. This is the recommended method of  | 
3653  |  |  * setting the defaults when only few additional options are to be added. This promotes  | 
3654  |  |  * consistency between applications using GnuTLS, and allows GnuTLS using applications  | 
3655  |  |  * to update settings in par with the library.  | 
3656  |  |  *  | 
3657  |  |  * The @add_prio string should start as a normal priority string, e.g.,  | 
3658  |  |  * '-VERS-TLS-ALL:+VERS-TLS1.3:%%COMPAT' or '%%FORCE_ETM'. That is, it must not start  | 
3659  |  |  * with ':'.  | 
3660  |  |  *  | 
3661  |  |  * To allow a user to override the defaults (e.g., when a user interface  | 
3662  |  |  * or configuration file is available), the functions  | 
3663  |  |  * gnutls_priority_set_direct() or gnutls_priority_set() can  | 
3664  |  |  * be used.  | 
3665  |  |  *  | 
3666  |  |  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.  | 
3667  |  |  *  | 
3668  |  |  * Since: 3.6.3  | 
3669  |  |  **/  | 
3670  |  | int gnutls_set_default_priority_append(gnutls_session_t session,  | 
3671  |  |                const char *add_prio,  | 
3672  |  |                const char **err_pos, unsigned flags)  | 
3673  | 0  | { | 
3674  | 0  |   gnutls_priority_t prio;  | 
3675  | 0  |   int ret;  | 
3676  |  | 
  | 
3677  | 0  |   ret = gnutls_priority_init2(&prio, add_prio, err_pos,  | 
3678  | 0  |             GNUTLS_PRIORITY_INIT_DEF_APPEND);  | 
3679  | 0  |   if (ret < 0) { | 
3680  | 0  |     gnutls_assert();  | 
3681  | 0  |     return ret;  | 
3682  | 0  |   }  | 
3683  |  |  | 
3684  | 0  |   ret = gnutls_priority_set(session, prio);  | 
3685  | 0  |   if (ret < 0) { | 
3686  | 0  |     gnutls_assert();  | 
3687  | 0  |     return ret;  | 
3688  | 0  |   }  | 
3689  |  |  | 
3690  |  |   /* ensure that the session holds the only reference for the struct */  | 
3691  | 0  |   gnutls_priority_deinit(prio);  | 
3692  |  | 
  | 
3693  | 0  |   return 0;  | 
3694  | 0  | }  | 
3695  |  |  | 
3696  |  | /**  | 
3697  |  |  * gnutls_priority_ecc_curve_list:  | 
3698  |  |  * @pcache: is a #gnutls_priority_t type.  | 
3699  |  |  * @list: will point to an integer list  | 
3700  |  |  *  | 
3701  |  |  * Get a list of available elliptic curves in the priority  | 
3702  |  |  * structure.  | 
3703  |  |  *  | 
3704  |  |  * Deprecated: This function has been replaced by  | 
3705  |  |  * gnutls_priority_group_list() since 3.6.0.  | 
3706  |  |  *  | 
3707  |  |  * Returns: the number of items, or an error code.  | 
3708  |  |  *  | 
3709  |  |  * Since: 3.0  | 
3710  |  |  **/  | 
3711  |  | int gnutls_priority_ecc_curve_list(gnutls_priority_t pcache,  | 
3712  |  |            const unsigned int **list)  | 
3713  | 0  | { | 
3714  | 0  |   unsigned i;  | 
3715  |  | 
  | 
3716  | 0  |   if (pcache->_supported_ecc.num_priorities == 0)  | 
3717  | 0  |     return 0;  | 
3718  |  |  | 
3719  | 0  |   *list = pcache->_supported_ecc.priorities;  | 
3720  |  |  | 
3721  |  |   /* to ensure we don't confuse the caller, we do not include  | 
3722  |  |    * any FFDHE groups. This may return an incomplete list. */  | 
3723  | 0  |   for (i = 0; i < pcache->_supported_ecc.num_priorities; i++)  | 
3724  | 0  |     if (pcache->_supported_ecc.priorities[i] > GNUTLS_ECC_CURVE_MAX)  | 
3725  | 0  |       return i;  | 
3726  |  |  | 
3727  | 0  |   return pcache->_supported_ecc.num_priorities;  | 
3728  | 0  | }  | 
3729  |  |  | 
3730  |  | /**  | 
3731  |  |  * gnutls_priority_group_list:  | 
3732  |  |  * @pcache: is a #gnutls_priority_t type.  | 
3733  |  |  * @list: will point to an integer list  | 
3734  |  |  *  | 
3735  |  |  * Get a list of available groups in the priority  | 
3736  |  |  * structure.  | 
3737  |  |  *  | 
3738  |  |  * Returns: the number of items, or an error code.  | 
3739  |  |  *  | 
3740  |  |  * Since: 3.6.0  | 
3741  |  |  **/  | 
3742  |  | int gnutls_priority_group_list(gnutls_priority_t pcache,  | 
3743  |  |              const unsigned int **list)  | 
3744  | 0  | { | 
3745  | 0  |   if (pcache->_supported_ecc.num_priorities == 0)  | 
3746  | 0  |     return 0;  | 
3747  |  |  | 
3748  | 0  |   *list = pcache->_supported_ecc.priorities;  | 
3749  | 0  |   return pcache->_supported_ecc.num_priorities;  | 
3750  | 0  | }  | 
3751  |  |  | 
3752  |  | /**  | 
3753  |  |  * gnutls_priority_kx_list:  | 
3754  |  |  * @pcache: is a #gnutls_priority_t type.  | 
3755  |  |  * @list: will point to an integer list  | 
3756  |  |  *  | 
3757  |  |  * Get a list of available key exchange methods in the priority  | 
3758  |  |  * structure.  | 
3759  |  |  *  | 
3760  |  |  * Returns: the number of items, or an error code.  | 
3761  |  |  * Since: 3.2.3  | 
3762  |  |  **/  | 
3763  |  | int gnutls_priority_kx_list(gnutls_priority_t pcache, const unsigned int **list)  | 
3764  | 0  | { | 
3765  | 0  |   if (pcache->_kx.num_priorities == 0)  | 
3766  | 0  |     return 0;  | 
3767  |  |  | 
3768  | 0  |   *list = pcache->_kx.priorities;  | 
3769  | 0  |   return pcache->_kx.num_priorities;  | 
3770  | 0  | }  | 
3771  |  |  | 
3772  |  | /**  | 
3773  |  |  * gnutls_priority_cipher_list:  | 
3774  |  |  * @pcache: is a #gnutls_priority_t type.  | 
3775  |  |  * @list: will point to an integer list  | 
3776  |  |  *  | 
3777  |  |  * Get a list of available ciphers in the priority  | 
3778  |  |  * structure.  | 
3779  |  |  *  | 
3780  |  |  * Returns: the number of items, or an error code.  | 
3781  |  |  * Since: 3.2.3  | 
3782  |  |  **/  | 
3783  |  | int gnutls_priority_cipher_list(gnutls_priority_t pcache,  | 
3784  |  |         const unsigned int **list)  | 
3785  | 0  | { | 
3786  | 0  |   if (pcache->_cipher.num_priorities == 0)  | 
3787  | 0  |     return 0;  | 
3788  |  |  | 
3789  | 0  |   *list = pcache->_cipher.priorities;  | 
3790  | 0  |   return pcache->_cipher.num_priorities;  | 
3791  | 0  | }  | 
3792  |  |  | 
3793  |  | /**  | 
3794  |  |  * gnutls_priority_mac_list:  | 
3795  |  |  * @pcache: is a #gnutls_priority_t type.  | 
3796  |  |  * @list: will point to an integer list  | 
3797  |  |  *  | 
3798  |  |  * Get a list of available MAC algorithms in the priority  | 
3799  |  |  * structure.  | 
3800  |  |  *  | 
3801  |  |  * Returns: the number of items, or an error code.  | 
3802  |  |  * Since: 3.2.3  | 
3803  |  |  **/  | 
3804  |  | int gnutls_priority_mac_list(gnutls_priority_t pcache,  | 
3805  |  |            const unsigned int **list)  | 
3806  | 0  | { | 
3807  | 0  |   if (pcache->_mac.num_priorities == 0)  | 
3808  | 0  |     return 0;  | 
3809  |  |  | 
3810  | 0  |   *list = pcache->_mac.priorities;  | 
3811  | 0  |   return pcache->_mac.num_priorities;  | 
3812  | 0  | }  | 
3813  |  |  | 
3814  |  | /**  | 
3815  |  |  * gnutls_priority_compression_list:  | 
3816  |  |  * @pcache: is a #gnutls_priority_t type.  | 
3817  |  |  * @list: will point to an integer list  | 
3818  |  |  *  | 
3819  |  |  * Get a list of available compression method in the priority  | 
3820  |  |  * structure.  | 
3821  |  |  *  | 
3822  |  |  * Returns: the number of methods, or an error code.  | 
3823  |  |  * Since: 3.0  | 
3824  |  |  **/  | 
3825  |  | int gnutls_priority_compression_list(gnutls_priority_t pcache,  | 
3826  |  |              const unsigned int **list)  | 
3827  | 0  | { | 
3828  | 0  |   static const unsigned int priority[1] = { GNUTLS_COMP_NULL }; | 
3829  |  | 
  | 
3830  | 0  |   *list = priority;  | 
3831  | 0  |   return 1;  | 
3832  | 0  | }  | 
3833  |  |  | 
3834  |  | /**  | 
3835  |  |  * gnutls_priority_protocol_list:  | 
3836  |  |  * @pcache: is a #gnutls_priority_t type.  | 
3837  |  |  * @list: will point to an integer list  | 
3838  |  |  *  | 
3839  |  |  * Get a list of available TLS version numbers in the priority  | 
3840  |  |  * structure.  | 
3841  |  |  *  | 
3842  |  |  * Returns: the number of protocols, or an error code.  | 
3843  |  |  * Since: 3.0  | 
3844  |  |  **/  | 
3845  |  | int gnutls_priority_protocol_list(gnutls_priority_t pcache,  | 
3846  |  |           const unsigned int **list)  | 
3847  | 0  | { | 
3848  | 0  |   if (pcache->protocol.num_priorities == 0)  | 
3849  | 0  |     return 0;  | 
3850  |  |  | 
3851  | 0  |   *list = pcache->protocol.priorities;  | 
3852  | 0  |   return pcache->protocol.num_priorities;  | 
3853  | 0  | }  | 
3854  |  |  | 
3855  |  | /**  | 
3856  |  |  * gnutls_priority_sign_list:  | 
3857  |  |  * @pcache: is a #gnutls_priority_t type.  | 
3858  |  |  * @list: will point to an integer list  | 
3859  |  |  *  | 
3860  |  |  * Get a list of available signature algorithms in the priority  | 
3861  |  |  * structure.  | 
3862  |  |  *  | 
3863  |  |  * Returns: the number of algorithms, or an error code.  | 
3864  |  |  * Since: 3.0  | 
3865  |  |  **/  | 
3866  |  | int gnutls_priority_sign_list(gnutls_priority_t pcache,  | 
3867  |  |             const unsigned int **list)  | 
3868  | 0  | { | 
3869  | 0  |   if (pcache->_sign_algo.num_priorities == 0)  | 
3870  | 0  |     return 0;  | 
3871  |  |  | 
3872  | 0  |   *list = pcache->_sign_algo.priorities;  | 
3873  | 0  |   return pcache->_sign_algo.num_priorities;  | 
3874  | 0  | }  | 
3875  |  |  | 
3876  |  | /**  | 
3877  |  |  * gnutls_priority_certificate_type_list:  | 
3878  |  |  * @pcache: is a #gnutls_priority_t type.  | 
3879  |  |  * @list: will point to an integer list  | 
3880  |  |  *  | 
3881  |  |  * Get a list of available certificate types in the priority  | 
3882  |  |  * structure.  | 
3883  |  |  *  | 
3884  |  |  * As of version 3.6.4 this function is an alias for  | 
3885  |  |  * gnutls_priority_certificate_type_list2 with the target parameter  | 
3886  |  |  * set to:  | 
3887  |  |  * - GNUTLS_CTYPE_SERVER, if the %SERVER_PRECEDENCE option is set  | 
3888  |  |  * - GNUTLS_CTYPE_CLIENT, otherwise.  | 
3889  |  |  *  | 
3890  |  |  * Returns: the number of certificate types, or an error code.  | 
3891  |  |  * Since: 3.0  | 
3892  |  |  **/  | 
3893  |  | int gnutls_priority_certificate_type_list(gnutls_priority_t pcache,  | 
3894  |  |             const unsigned int **list)  | 
3895  | 0  | { | 
3896  | 0  |   gnutls_ctype_target_t target = pcache->server_precedence ?  | 
3897  | 0  |                  GNUTLS_CTYPE_SERVER :  | 
3898  | 0  |                  GNUTLS_CTYPE_CLIENT;  | 
3899  |  | 
  | 
3900  | 0  |   return gnutls_priority_certificate_type_list2(pcache, list, target);  | 
3901  | 0  | }  | 
3902  |  |  | 
3903  |  | /**  | 
3904  |  |  * gnutls_priority_certificate_type_list2:  | 
3905  |  |  * @pcache: is a #gnutls_priority_t type.  | 
3906  |  |  * @list: will point to an integer list.  | 
3907  |  |  * @target: is a #gnutls_ctype_target_t type. Valid arguments are  | 
3908  |  |  *   GNUTLS_CTYPE_CLIENT and GNUTLS_CTYPE_SERVER  | 
3909  |  |  *  | 
3910  |  |  * Get a list of available certificate types for the given target  | 
3911  |  |  * in the priority structure.  | 
3912  |  |  *  | 
3913  |  |  * Returns: the number of certificate types, or an error code.  | 
3914  |  |  *  | 
3915  |  |  * Since: 3.6.4  | 
3916  |  |  **/  | 
3917  |  | int gnutls_priority_certificate_type_list2(gnutls_priority_t pcache,  | 
3918  |  |              const unsigned int **list,  | 
3919  |  |              gnutls_ctype_target_t target)  | 
3920  | 0  | { | 
3921  | 0  |   switch (target) { | 
3922  | 0  |   case GNUTLS_CTYPE_CLIENT:  | 
3923  | 0  |     if (pcache->client_ctype.num_priorities > 0) { | 
3924  | 0  |       *list = pcache->client_ctype.priorities;  | 
3925  | 0  |       return pcache->client_ctype.num_priorities;  | 
3926  | 0  |     }  | 
3927  | 0  |     break;  | 
3928  | 0  |   case GNUTLS_CTYPE_SERVER:  | 
3929  | 0  |     if (pcache->server_ctype.num_priorities > 0) { | 
3930  | 0  |       *list = pcache->server_ctype.priorities;  | 
3931  | 0  |       return pcache->server_ctype.num_priorities;  | 
3932  | 0  |     }  | 
3933  | 0  |     break;  | 
3934  | 0  |   default:  | 
3935  |  |     // Invalid target given  | 
3936  | 0  |     gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
3937  | 0  |   }  | 
3938  |  |  | 
3939  |  |   // Found a matching target but non of them had any ctypes set  | 
3940  | 0  |   return 0;  | 
3941  | 0  | }  | 
3942  |  |  | 
3943  |  | /**  | 
3944  |  |  * gnutls_priority_string_list:  | 
3945  |  |  * @iter: an integer counter starting from zero  | 
3946  |  |  * @flags: one of %GNUTLS_PRIORITY_LIST_INIT_KEYWORDS, %GNUTLS_PRIORITY_LIST_SPECIAL  | 
3947  |  |  *  | 
3948  |  |  * Can be used to iterate all available priority strings.  | 
3949  |  |  * Due to internal implementation details, there are cases where this  | 
3950  |  |  * function can return the empty string. In that case that string should be ignored.  | 
3951  |  |  * When no strings are available it returns %NULL.  | 
3952  |  |  *  | 
3953  |  |  * Returns: a priority string  | 
3954  |  |  * Since: 3.4.0  | 
3955  |  |  **/  | 
3956  |  | const char *gnutls_priority_string_list(unsigned iter, unsigned int flags)  | 
3957  | 0  | { | 
3958  | 0  |   if (flags & GNUTLS_PRIORITY_LIST_INIT_KEYWORDS) { | 
3959  | 0  |     if (iter >= (sizeof(pgroups) / sizeof(pgroups[0])) - 1)  | 
3960  | 0  |       return NULL;  | 
3961  | 0  |     return pgroups[iter].name;  | 
3962  | 0  |   } else if (flags & GNUTLS_PRIORITY_LIST_SPECIAL) { | 
3963  | 0  |     if (iter >= (sizeof(wordlist) / sizeof(wordlist[0])) - 1)  | 
3964  | 0  |       return NULL;  | 
3965  | 0  |     return wordlist[iter].name;  | 
3966  | 0  |   }  | 
3967  | 0  |   return NULL;  | 
3968  | 0  | }  | 
3969  |  |  | 
3970  |  | bool _gnutls_config_is_ktls_enabled(void)  | 
3971  | 0  | { | 
3972  | 0  |   return system_wide_config.ktls_enabled;  | 
3973  | 0  | }  | 
3974  |  |  | 
3975  |  | bool _gnutls_config_is_rsa_pkcs1_encrypt_allowed(void)  | 
3976  | 0  | { | 
3977  | 0  |   return system_wide_config.allow_rsa_pkcs1_encrypt;  | 
3978  | 0  | }  | 
3979  |  |  | 
3980  |  | /*  | 
3981  |  |  * high-level interface for overriding configuration files  | 
3982  |  |  */  | 
3983  |  |  | 
3984  |  | static inline bool /* not locking system_wide_config */  | 
3985  |  | system_wide_config_is_malleable(void)  | 
3986  | 0  | { | 
3987  | 0  |   if (!system_wide_config.allowlisting) { | 
3988  | 0  |     _gnutls_audit_log(NULL, "allowlisting is not enabled!\n");  | 
3989  | 0  |     return false;  | 
3990  | 0  |   }  | 
3991  | 0  |   if (system_wide_config.priority_string) { | 
3992  | 0  |     _gnutls_audit_log(NULL, "priority strings have already been "  | 
3993  | 0  |           "initialized!\n");  | 
3994  | 0  |     return false;  | 
3995  | 0  |   }  | 
3996  | 0  |   return true;  | 
3997  | 0  | }  | 
3998  |  |  | 
3999  |  | /**  | 
4000  |  |  * gnutls_digest_set_secure:  | 
4001  |  |  * @dig: is a digest algorithm  | 
4002  |  |  * @secure: whether to mark the digest algorithm secure  | 
4003  |  |  *  | 
4004  |  |  * Modify the previous system wide setting that marked @dig as secure  | 
4005  |  |  * or insecure. This only has effect when the algorithm is enabled  | 
4006  |  |  * through the allowlisting mode in the configuration file, or when  | 
4007  |  |  * the setting is modified with a prior call to this function.  | 
4008  |  |  *  | 
4009  |  |  * Since: 3.7.3  | 
4010  |  |  */  | 
4011  |  | int gnutls_digest_set_secure(gnutls_digest_algorithm_t dig, unsigned int secure)  | 
4012  | 0  | { | 
4013  | 0  | #ifndef DISABLE_SYSTEM_CONFIG  | 
4014  | 0  |   int ret;  | 
4015  | 0  |   ret = gnutls_rwlock_wrlock(&system_wide_config_rwlock);  | 
4016  | 0  |   if (ret < 0) { | 
4017  | 0  |     (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4018  | 0  |     return gnutls_assert_val(ret);  | 
4019  | 0  |   }  | 
4020  | 0  |   if (!system_wide_config_is_malleable()) { | 
4021  | 0  |     (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4022  | 0  |     return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
4023  | 0  |   }  | 
4024  |  |  | 
4025  | 0  |   if (secure) { | 
4026  | 0  |     ret = cfg_hashes_add(&system_wide_config, dig);  | 
4027  | 0  |   } else { | 
4028  | 0  |     ret = cfg_hashes_remove(&system_wide_config, dig);  | 
4029  | 0  |   }  | 
4030  |  | 
  | 
4031  | 0  |   (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4032  | 0  |   return ret;  | 
4033  |  | #else  | 
4034  |  |   return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
4035  |  | #endif  | 
4036  | 0  | }  | 
4037  |  |  | 
4038  |  | /**  | 
4039  |  |  * gnutls_sign_set_secure:  | 
4040  |  |  * @sign: the sign algorithm  | 
4041  |  |  * @secure: whether to mark the sign algorithm secure  | 
4042  |  |  *  | 
4043  |  |  * Modify the previous system wide setting that marked @sign as secure  | 
4044  |  |  * or insecure.  Calling this function is allowed  | 
4045  |  |  * only if allowlisting mode is set in the configuration file,  | 
4046  |  |  * and only if the system-wide TLS priority string  | 
4047  |  |  * has not been initialized yet.  | 
4048  |  |  * The intended usage is to provide applications with a way  | 
4049  |  |  * to expressly deviate from the distribution or site defaults  | 
4050  |  |  * inherited from the configuration file.  | 
4051  |  |  * The modification is composable with further modifications  | 
4052  |  |  * performed through the priority string mechanism.  | 
4053  |  |  *  | 
4054  |  |  * This function is not thread-safe and is intended to be called  | 
4055  |  |  * in the main thread at the beginning of the process execution.  | 
4056  |  |  *  | 
4057  |  |  * Even when @secure is true, @sign is not marked as secure for the  | 
4058  |  |  * use in certificates.  Use gnutls_sign_set_secure_for_certs() to  | 
4059  |  |  * mark it secure as well for certificates.  | 
4060  |  |  *  | 
4061  |  |  * Returns: 0 on success or negative error code otherwise.  | 
4062  |  |  *  | 
4063  |  |  * Since: 3.7.3  | 
4064  |  |  */  | 
4065  |  | int gnutls_sign_set_secure(gnutls_sign_algorithm_t sign, unsigned int secure)  | 
4066  | 0  | { | 
4067  | 0  | #ifndef DISABLE_SYSTEM_CONFIG  | 
4068  | 0  |   int ret;  | 
4069  | 0  |   ret = gnutls_rwlock_wrlock(&system_wide_config_rwlock);  | 
4070  | 0  |   if (ret < 0) { | 
4071  | 0  |     (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4072  | 0  |     return gnutls_assert_val(ret);  | 
4073  | 0  |   }  | 
4074  | 0  |   if (!system_wide_config_is_malleable()) { | 
4075  | 0  |     (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4076  | 0  |     return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
4077  | 0  |   }  | 
4078  |  |  | 
4079  | 0  |   if (secure) { | 
4080  | 0  |     ret = cfg_sigs_add(&system_wide_config, sign);  | 
4081  | 0  |   } else { | 
4082  | 0  |     ret = cfg_sigs_remove(&system_wide_config, sign);  | 
4083  | 0  |     if (ret < 0) { | 
4084  | 0  |       (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4085  | 0  |       return ret;  | 
4086  | 0  |     }  | 
4087  |  |     /* irregularity, distrusting also means distrusting for certs */  | 
4088  | 0  |     ret = cfg_sigs_for_cert_remove(&system_wide_config, sign);  | 
4089  | 0  |   }  | 
4090  |  |  | 
4091  | 0  |   (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4092  | 0  |   return ret;  | 
4093  |  | #else  | 
4094  |  |   return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
4095  |  | #endif  | 
4096  | 0  | }  | 
4097  |  |  | 
4098  |  | /**  | 
4099  |  |  * gnutls_sign_set_secure_for_certs:  | 
4100  |  |  * @sign: the sign algorithm  | 
4101  |  |  * @secure: whether to mark the sign algorithm secure for certificates  | 
4102  |  |  *  | 
4103  |  |  * Modify the previous system wide setting that marked @sign as secure  | 
4104  |  |  * or insecure for the use in certificates.  Calling this function is allowed  | 
4105  |  |  * only if allowlisting mode is set in the configuration file,  | 
4106  |  |  * and only if the system-wide TLS priority string  | 
4107  |  |  * has not been initialized yet.  | 
4108  |  |  * The intended usage is to provide applications with a way  | 
4109  |  |  * to expressly deviate from the distribution or site defaults  | 
4110  |  |  * inherited from the configuration file.  | 
4111  |  |  * The modification is composable with further modifications  | 
4112  |  |  * performed through the priority string mechanism.  | 
4113  |  |  *  | 
4114  |  |  * This function is not thread-safe and is intended to be called  | 
4115  |  |  * in the main thread at the beginning of the process execution.  | 
4116  |  |  | 
4117  |  |  * When @secure is true, @sign is marked as secure for any use unlike  | 
4118  |  |  * gnutls_sign_set_secure().  Otherwise, it is marked as insecure only  | 
4119  |  |  * for the use in certificates.  Use gnutls_sign_set_secure() to mark  | 
4120  |  |  * it insecure for any uses.  | 
4121  |  |  *  | 
4122  |  |  * Returns: 0 on success or negative error code otherwise.  | 
4123  |  |  *  | 
4124  |  |  * Since: 3.7.3  | 
4125  |  |  */  | 
4126  |  | int gnutls_sign_set_secure_for_certs(gnutls_sign_algorithm_t sign,  | 
4127  |  |              unsigned int secure)  | 
4128  | 0  | { | 
4129  | 0  | #ifndef DISABLE_SYSTEM_CONFIG  | 
4130  | 0  |   int ret;  | 
4131  | 0  |   ret = gnutls_rwlock_wrlock(&system_wide_config_rwlock);  | 
4132  | 0  |   if (ret < 0) { | 
4133  | 0  |     (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4134  | 0  |     return gnutls_assert_val(ret);  | 
4135  | 0  |   }  | 
4136  | 0  |   if (!system_wide_config_is_malleable()) { | 
4137  | 0  |     (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4138  | 0  |     return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
4139  | 0  |   }  | 
4140  |  |  | 
4141  | 0  |   if (secure) { | 
4142  |  |     /* irregularity, trusting for certs means trusting in general */  | 
4143  | 0  |     ret = cfg_sigs_add(&system_wide_config, sign);  | 
4144  | 0  |     if (ret < 0) { | 
4145  | 0  |       (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4146  | 0  |       return ret;  | 
4147  | 0  |     }  | 
4148  | 0  |     ret = cfg_sigs_for_cert_add(&system_wide_config, sign);  | 
4149  | 0  |   } else { | 
4150  | 0  |     ret = cfg_sigs_for_cert_remove(&system_wide_config, sign);  | 
4151  | 0  |   }  | 
4152  |  |  | 
4153  | 0  |   (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4154  | 0  |   return ret;  | 
4155  |  | #else  | 
4156  |  |   return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
4157  |  | #endif  | 
4158  | 0  | }  | 
4159  |  |  | 
4160  |  | /**  | 
4161  |  |  * gnutls_protocol_set_enabled:  | 
4162  |  |  * @version: is a (gnutls) version number  | 
4163  |  |  * @enabled: whether to enable the protocol  | 
4164  |  |  *  | 
4165  |  |  * Control the previous system-wide setting that marked @version as  | 
4166  |  |  * enabled or disabled.  Calling this function is allowed  | 
4167  |  |  * only if allowlisting mode is set in the configuration file,  | 
4168  |  |  * and only if the system-wide TLS priority string  | 
4169  |  |  * has not been initialized yet.  | 
4170  |  |  * The intended usage is to provide applications with a way  | 
4171  |  |  * to expressly deviate from the distribution or site defaults  | 
4172  |  |  * inherited from the configuration file.  | 
4173  |  |  * The modification is composable with further modifications  | 
4174  |  |  * performed through the priority string mechanism.  | 
4175  |  |  *  | 
4176  |  |  * This function is not thread-safe and is intended to be called  | 
4177  |  |  * in the main thread at the beginning of the process execution.  | 
4178  |  |  *  | 
4179  |  |  * Returns: 0 on success or negative error code otherwise.  | 
4180  |  |  *  | 
4181  |  |  * Since: 3.7.3  | 
4182  |  |  */  | 
4183  |  | int /* allowlisting-only */  | 
4184  |  | /* not thread-safe */  | 
4185  |  | gnutls_protocol_set_enabled(gnutls_protocol_t version, unsigned int enabled)  | 
4186  | 0  | { | 
4187  | 0  | #ifndef DISABLE_SYSTEM_CONFIG  | 
4188  | 0  |   int ret;  | 
4189  | 0  |   ret = gnutls_rwlock_wrlock(&system_wide_config_rwlock);  | 
4190  | 0  |   if (ret < 0) { | 
4191  | 0  |     (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4192  | 0  |     return gnutls_assert_val(ret);  | 
4193  | 0  |   }  | 
4194  | 0  |   if (!system_wide_config_is_malleable()) { | 
4195  | 0  |     (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4196  | 0  |     return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
4197  | 0  |   }  | 
4198  |  |  | 
4199  | 0  |   if (enabled) { | 
4200  | 0  |     ret = cfg_versions_add(&system_wide_config, version);  | 
4201  | 0  |   } else { | 
4202  | 0  |     ret = cfg_versions_remove(&system_wide_config, version);  | 
4203  | 0  |   }  | 
4204  |  | 
  | 
4205  | 0  |   (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4206  | 0  |   return ret;  | 
4207  |  | #else  | 
4208  |  |   return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
4209  |  | #endif  | 
4210  | 0  | }  | 
4211  |  |  | 
4212  |  | /**  | 
4213  |  |  * gnutls_ecc_curve_set_enabled:  | 
4214  |  |  * @curve: is an ECC curve  | 
4215  |  |  * @enabled: whether to enable the curve  | 
4216  |  |  *  | 
4217  |  |  * Modify the previous system wide setting that marked @curve as  | 
4218  |  |  * enabled or disabled.  Calling this function is allowed  | 
4219  |  |  * only if allowlisting mode is set in the configuration file,  | 
4220  |  |  * and only if the system-wide TLS priority string  | 
4221  |  |  * has not been initialized yet.  | 
4222  |  |  * The intended usage is to provide applications with a way  | 
4223  |  |  * to expressly deviate from the distribution or site defaults  | 
4224  |  |  * inherited from the configuration file.  | 
4225  |  |  * The modification is composable with further modifications  | 
4226  |  |  * performed through the priority string mechanism.  | 
4227  |  |  *  | 
4228  |  |  * This function is not thread-safe and is intended to be called  | 
4229  |  |  * in the main thread at the beginning of the process execution.  | 
4230  |  |  *  | 
4231  |  |  * Returns: 0 on success or negative error code otherwise.  | 
4232  |  |  *  | 
4233  |  |  * Since: 3.7.3  | 
4234  |  |  */  | 
4235  |  | int gnutls_ecc_curve_set_enabled(gnutls_ecc_curve_t curve, unsigned int enabled)  | 
4236  | 0  | { | 
4237  | 0  | #ifndef DISABLE_SYSTEM_CONFIG  | 
4238  | 0  |   int ret;  | 
4239  | 0  |   ret = gnutls_rwlock_wrlock(&system_wide_config_rwlock);  | 
4240  | 0  |   if (ret < 0) { | 
4241  | 0  |     (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4242  | 0  |     return gnutls_assert_val(ret);  | 
4243  | 0  |   }  | 
4244  | 0  |   if (!system_wide_config_is_malleable()) { | 
4245  | 0  |     (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4246  | 0  |     return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
4247  | 0  |   }  | 
4248  |  |  | 
4249  | 0  |   if (enabled) { | 
4250  | 0  |     ret = cfg_ecc_curves_add(&system_wide_config, curve);  | 
4251  | 0  |   } else { | 
4252  | 0  |     ret = cfg_ecc_curves_remove(&system_wide_config, curve);  | 
4253  | 0  |   }  | 
4254  |  | 
  | 
4255  | 0  |   (void)gnutls_rwlock_unlock(&system_wide_config_rwlock);  | 
4256  | 0  |   return ret;  | 
4257  |  | #else  | 
4258  |  |   return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);  | 
4259  |  | #endif  | 
4260  | 0  | }  |