1 /*
2  * Copyright (C) 2008-2012 Free Software Foundation, Inc.
3  * Copyright (C) 2018 Red Hat, Inc.
4  *
5  * Author: Simon Josefsson, Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * GnuTLS is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * GnuTLS 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  * 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 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <assert.h>
32 #include <gnutls/gnutls.h>
33 #include "utils.h"
34 #include "eagain-common.h"
35 #include "cert-common.h"
36 
37 const char *side;
38 extern const char *_gnutls_default_priority_string;
39 
tls_log_func(int level,const char * str)40 static void tls_log_func(int level, const char *str)
41 {
42 	fprintf(stderr, "%s|<%d>| %s", side, level, str);
43 }
44 
45 struct test_st {
46 	const char *name;
47 	const char *add_prio;
48 	const char *def_prio;
49 	int exp_err;
50 	int exp_etm;
51 	unsigned err_pos;
52 	unsigned exp_vers;
53 };
54 
start(struct test_st * test)55 static void start(struct test_st *test)
56 {
57 	int ret;
58 	/* Server stuff. */
59 	gnutls_priority_t cache;
60 	gnutls_certificate_credentials_t serverx509cred;
61 	gnutls_session_t server;
62 	int sret = GNUTLS_E_AGAIN;
63 	/* Client stuff. */
64 	gnutls_certificate_credentials_t clientx509cred;
65 	gnutls_session_t client;
66 	const char *ep;
67 	int cret = GNUTLS_E_AGAIN;
68 
69 	if (test == NULL)
70 		success("running gnutls_set_default_priority test\n");
71 	else
72 		success("running %s\n", test->name);
73 
74 	if (test && test->def_prio)
75 		_gnutls_default_priority_string = test->def_prio;
76 	else
77 		_gnutls_default_priority_string = "NORMAL";
78 
79 	/* General init. */
80 	global_init();
81 	gnutls_global_set_log_function(tls_log_func);
82 	if (debug)
83 		gnutls_global_set_log_level(6);
84 
85 	assert(gnutls_certificate_allocate_credentials(&serverx509cred)>=0);
86 	assert(gnutls_certificate_set_x509_key_mem(serverx509cred,
87 					    &server_cert, &server_key,
88 					    GNUTLS_X509_FMT_PEM)>=0);
89 
90 	assert(gnutls_init(&server, GNUTLS_SERVER) >= 0);
91 	gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE,
92 				serverx509cred);
93 	if (test == NULL) {
94 		ret = gnutls_priority_init(&cache, NULL, NULL);
95 		if (ret < 0)
96 			fail("error: %s\n", gnutls_strerror(ret));
97 	} else {
98 		ret = gnutls_priority_init2(&cache, test->add_prio, &ep, GNUTLS_PRIORITY_INIT_DEF_APPEND);
99 		if (ret < 0) {
100 			if (test->exp_err == ret) {
101 				if (strchr(_gnutls_default_priority_string, '@') != 0) {
102 					if (ep != test->add_prio) {
103 						fail("error expected error on start of string[%d]: %s\n",
104 							test->err_pos, test->add_prio);
105 					}
106 				} else {
107 					if (ep-test->add_prio != test->err_pos) {
108 						fprintf(stderr, "diff: %d\n", (int)(ep-test->add_prio));
109 						fail("error expected error on different position[%d]: %s\n",
110 							test->err_pos, test->add_prio);
111 					}
112 				}
113 				goto cleanup;
114 			}
115 			fail("error: %s\n", gnutls_strerror(ret));
116 		}
117 	}
118 	gnutls_priority_set(server, cache);
119 
120 	gnutls_transport_set_push_function(server, server_push);
121 	gnutls_transport_set_pull_function(server, server_pull);
122 	gnutls_transport_set_ptr(server, server);
123 
124 	/* Init client */
125 	ret = gnutls_certificate_allocate_credentials(&clientx509cred);
126 	if (ret < 0)
127 		exit(1);
128 
129 	ret = gnutls_certificate_set_x509_trust_mem(clientx509cred, &ca_cert, GNUTLS_X509_FMT_PEM);
130 	if (ret < 0)
131 		exit(1);
132 
133 	ret = gnutls_init(&client, GNUTLS_CLIENT);
134 	if (ret < 0)
135 		exit(1);
136 
137 	ret = gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE,
138 				clientx509cred);
139 	if (ret < 0)
140 		exit(1);
141 
142 	ret = gnutls_set_default_priority(client);
143 	if (ret < 0)
144 		exit(1);
145 
146 	gnutls_transport_set_push_function(client, client_push);
147 	gnutls_transport_set_pull_function(client, client_pull);
148 	gnutls_transport_set_ptr(client, client);
149 
150 	HANDSHAKE(client, server);
151 
152 	/* check gnutls_certificate_get_ours() - client side */
153 	{
154 		const gnutls_datum_t *mcert;
155 
156 		mcert = gnutls_certificate_get_ours(client);
157 		if (mcert != NULL) {
158 			fail("gnutls_certificate_get_ours(): failed\n");
159 			exit(1);
160 		}
161 	}
162 
163 	if (test && test->exp_vers != 0) {
164 		if (test->exp_vers != gnutls_protocol_get_version(server)) {
165 			fail("expected version %s, got %s\n",
166 			     gnutls_protocol_get_name(test->exp_vers),
167 			     gnutls_protocol_get_name(gnutls_protocol_get_version(server)));
168 		}
169 	}
170 
171 	/* check the number of certificates received */
172 	{
173 		unsigned cert_list_size = 0;
174 		gnutls_typed_vdata_st data[2];
175 		unsigned status;
176 
177 		memset(data, 0, sizeof(data));
178 
179 		data[0].type = GNUTLS_DT_DNS_HOSTNAME;
180 		data[0].data = (void*)"localhost1";
181 
182 		data[1].type = GNUTLS_DT_KEY_PURPOSE_OID;
183 		data[1].data = (void*)GNUTLS_KP_TLS_WWW_SERVER;
184 
185 		gnutls_certificate_get_peers(client, &cert_list_size);
186 		if (cert_list_size < 2) {
187 			fprintf(stderr, "received a certificate list of %d!\n", cert_list_size);
188 			exit(1);
189 		}
190 
191 		ret = gnutls_certificate_verify_peers(client, data, 2, &status);
192 		if (ret < 0) {
193 			fprintf(stderr, "could not verify certificate: %s\n", gnutls_strerror(ret));
194 			exit(1);
195 		}
196 
197 		if (status == 0) {
198 			fprintf(stderr, "should not have accepted!\n");
199 			exit(1);
200 		}
201 
202 		data[0].type = GNUTLS_DT_DNS_HOSTNAME;
203 		data[0].data = (void*)"localhost";
204 
205 		ret = gnutls_certificate_verify_peers(client, data, 2, &status);
206 		if (ret < 0) {
207 			fprintf(stderr, "could not verify certificate: %s\n", gnutls_strerror(ret));
208 			exit(1);
209 		}
210 
211 		if (status != 0) {
212 			fprintf(stderr, "could not verify certificate: %.4x\n", status);
213 			exit(1);
214 		}
215 	}
216 
217 	if (test && test->exp_etm) {
218 		ret = gnutls_session_ext_master_secret_status(client);
219 		if (ret != 1) {
220 			fprintf(stderr, "Extended master secret wasn't negotiated by default (client ret: %d)\n", ret);
221 			exit(1);
222 		}
223 
224 		ret = gnutls_session_ext_master_secret_status(server);
225 		if (ret != 1) {
226 			fprintf(stderr, "Extended master secret wasn't negotiated by default (server ret: %d)\n", ret);
227 			exit(1);
228 		}
229 	}
230 
231 	gnutls_bye(client, GNUTLS_SHUT_RDWR);
232 	gnutls_bye(server, GNUTLS_SHUT_RDWR);
233 
234 	gnutls_deinit(client);
235 	gnutls_certificate_free_credentials(clientx509cred);
236  cleanup:
237 	gnutls_priority_deinit(cache);
238 	gnutls_deinit(server);
239 
240 	gnutls_certificate_free_credentials(serverx509cred);
241 
242 	gnutls_global_deinit();
243 	reset_buffers();
244 }
245 
246 struct test_st tests[] = {
247 	{
248 		.name = "additional flag",
249 		.def_prio = "NORMAL",
250 		.add_prio = "%FORCE_ETM",
251 		.exp_err = 0
252 	},
253 	{
254 		.name = "additional flag typo1",
255 		.def_prio = "NORMAL",
256 		.add_prio = ":%FORCE_ETM",
257 		.exp_err = GNUTLS_E_INVALID_REQUEST,
258 		.err_pos = 0
259 	},
260 	{
261 		.name = "additional flag typo2",
262 		.def_prio = "NORMAL",
263 		.add_prio = "%FORCE_ETM::%NO_TICKETS",
264 		.exp_err = GNUTLS_E_INVALID_REQUEST,
265 		.err_pos = 11
266 	},
267 	{
268 		.name = "additional flag typo3",
269 		.def_prio = "NORMAL",
270 		.add_prio = "%FORCE_ETM:%%NO_TICKETS",
271 		.exp_err = GNUTLS_E_INVALID_REQUEST,
272 		.err_pos = 11
273 	},
274 	{
275 		.name = "additional flag typo3 (with resolved def prio)",
276 		.def_prio = "@HELLO",
277 		.add_prio = "%FORCE_ETM:%%NO_TICKETS",
278 		.exp_err = GNUTLS_E_INVALID_REQUEST,
279 		.err_pos = 0
280 	},
281 	{
282 		.name = "additional flag for version (functional)",
283 		.def_prio = "NORMAL",
284 		.add_prio = "-VERS-ALL:+VERS-TLS1.1",
285 		.exp_etm = 1,
286 		.exp_err = 0,
287 		.exp_vers = GNUTLS_TLS1_1
288 	}
289 };
290 
291 
doit(void)292 void doit(void)
293 {
294 	start(NULL);
295 	for (unsigned i=0;i<sizeof(tests)/sizeof(tests[0]);i++) {
296 		start(&tests[i]);
297 	}
298 }
299