1 /*
2  * Copyright (C) 2017 Nikos Mavrogiannopoulos
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
8  * GnuTLS is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * GnuTLS is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>
20  */
21 
22 /* This tests TLS negotiation using the gnutls_privkey_import_ext2() APIs */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #ifndef _WIN32
33 # include <netinet/in.h>
34 # include <sys/socket.h>
35 # include <arpa/inet.h>
36 #endif
37 #include <unistd.h>
38 #include <gnutls/gnutls.h>
39 #include <gnutls/x509.h>
40 #include <gnutls/abstract.h>
41 #include <assert.h>
42 #include "cert-common.h"
43 #include "eagain-common.h"
44 #include "utils.h"
45 #include "softhsm.h"
46 
tls_log_func(int level,const char * str)47 static void tls_log_func(int level, const char *str)
48 {
49 	fprintf(stderr, "<%d> %s", level, str);
50 }
51 
52 #define CONFIG_NAME "softhsm-neg"
53 #define CONFIG CONFIG_NAME".config"
54 #define PIN "1234"
55 
56 #define testfail(fmt, ...) \
57 	fail("%s: "fmt, name, ##__VA_ARGS__)
58 
verify_eddsa_presence(void)59 static unsigned verify_eddsa_presence(void)
60 {
61 	unsigned i;
62 	unsigned long mechanism;
63 	int ret;
64 
65 	i = 0;
66 	do {
67 		ret = gnutls_pkcs11_token_get_mechanism("pkcs11:", i++, &mechanism);
68 		if (ret >= 0 && mechanism == 0x1057 /* CKM_EDDSA */)
69 			return 1;
70 	} while(ret>=0);
71 
72 	return 0;
73 }
74 
load_virt_privkey(const char * name,const gnutls_datum_t * txtkey,int exp_key_err,unsigned needs_decryption)75 static gnutls_privkey_t load_virt_privkey(const char *name, const gnutls_datum_t *txtkey,
76 					  int exp_key_err, unsigned needs_decryption)
77 {
78 	unsigned flags;
79 	gnutls_privkey_t privkey;
80 	gnutls_x509_privkey_t tmp;
81 	int ret;
82 
83 	ret = gnutls_x509_privkey_init(&tmp);
84 	if (ret < 0)
85 		testfail("gnutls_privkey_init\n");
86 
87 	ret = gnutls_x509_privkey_import(tmp, txtkey, GNUTLS_X509_FMT_PEM);
88 	if (ret < 0)
89 		testfail("gnutls_privkey_import: %s\n", gnutls_strerror(ret));
90 
91 	if (needs_decryption)
92 		flags = GNUTLS_KEY_KEY_ENCIPHERMENT;
93 	else
94 		flags = GNUTLS_KEY_DIGITAL_SIGNATURE;
95 
96 	ret = gnutls_pkcs11_copy_x509_privkey(SOFTHSM_URL, tmp, "key", flags,
97 					      GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE|GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE|GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
98 	gnutls_x509_privkey_deinit(tmp);
99 
100 	if (ret < 0) {
101 		if (ret == exp_key_err) {
102 			return NULL;
103 		}
104 		fail("gnutls_pkcs11_copy_x509_privkey: %s\n", gnutls_strerror(ret));
105 	}
106 
107 	ret = gnutls_privkey_init(&privkey);
108 	if (ret < 0)
109 		testfail("gnutls_privkey_init\n");
110 
111 	ret =
112 	    gnutls_privkey_import_url(privkey, SOFTHSM_URL";object=key", 0);
113 	if (ret < 0) {
114 		if (ret == exp_key_err) {
115 			gnutls_privkey_deinit(privkey);
116 			return NULL;
117 		}
118 		testfail("gnutls_privkey_import: %s\n", gnutls_strerror(ret));
119 	}
120 
121 	if (exp_key_err) {
122 		testfail("did not fail in key import, although expected\n");
123 	}
124 
125 	return privkey;
126 }
127 
128 static
try_with_key(const char * name,const char * client_prio,gnutls_kx_algorithm_t client_kx,gnutls_sign_algorithm_t server_sign_algo,gnutls_sign_algorithm_t client_sign_algo,const gnutls_datum_t * serv_cert,gnutls_privkey_t key,int exp_serv_err)129 void try_with_key(const char *name, const char *client_prio,
130 		 gnutls_kx_algorithm_t client_kx,
131 		 gnutls_sign_algorithm_t server_sign_algo,
132 		 gnutls_sign_algorithm_t client_sign_algo,
133 		 const gnutls_datum_t *serv_cert,
134 		 gnutls_privkey_t key,
135 		 int exp_serv_err)
136 {
137 	int ret;
138 	gnutls_pcert_st pcert_list[4];
139 	unsigned pcert_list_size;
140 	/* Server stuff. */
141 	gnutls_certificate_credentials_t s_xcred;
142 	gnutls_session_t server;
143 	int sret = GNUTLS_E_AGAIN;
144 	/* Client stuff. */
145 	gnutls_certificate_credentials_t c_xcred;
146 	gnutls_session_t client;
147 	int cret = GNUTLS_E_AGAIN, version;
148 	const char *err;
149 
150 	/* General init. */
151 	gnutls_global_set_log_function(tls_log_func);
152 	if (debug)
153 		gnutls_global_set_log_level(6);
154 
155 	reset_buffers();
156 	/* Init server */
157 	gnutls_certificate_allocate_credentials(&s_xcred);
158 
159 	pcert_list_size = sizeof(pcert_list)/sizeof(pcert_list[0]);
160 	ret = gnutls_pcert_list_import_x509_raw(pcert_list, &pcert_list_size,
161 		serv_cert, GNUTLS_X509_FMT_PEM, 0);
162 	if (ret < 0) {
163 		testfail("error in gnutls_pcert_list_import_x509_raw: %s\n", gnutls_strerror(ret));
164 	}
165 
166 	ret = gnutls_certificate_set_key(s_xcred, NULL, 0, pcert_list,
167 				pcert_list_size, key);
168 	if (ret < 0) {
169 		testfail("Could not set key/cert: %s\n", gnutls_strerror(ret));
170 	}
171 
172 	gnutls_init(&server, GNUTLS_SERVER);
173 	gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE,
174 				s_xcred);
175 
176 	assert(gnutls_priority_set_direct(server,
177 					  "NORMAL:+VERS-SSL3.0:+ANON-ECDH:+ANON-DH:+ECDHE-RSA:+DHE-RSA:+RSA:+ECDHE-ECDSA:+CURVE-X25519:+SIGN-EDDSA-ED25519",
178 					  NULL) >= 0);
179 	gnutls_transport_set_push_function(server, server_push);
180 	gnutls_transport_set_pull_function(server, server_pull);
181 	gnutls_transport_set_ptr(server, server);
182 
183 	/* Init client */
184 
185 	ret = gnutls_certificate_allocate_credentials(&c_xcred);
186 	if (ret < 0)
187 		exit(1);
188 
189 	ret = gnutls_init(&client, GNUTLS_CLIENT);
190 	if (ret < 0)
191 		exit(1);
192 
193 	ret = gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE,
194 				c_xcred);
195 	if (ret < 0)
196 		exit(1);
197 
198 	gnutls_transport_set_push_function(client, client_push);
199 	gnutls_transport_set_pull_function(client, client_pull);
200 	gnutls_transport_set_ptr(client, client);
201 
202 	ret = gnutls_priority_set_direct(client, client_prio, &err);
203 	if (ret < 0) {
204 		if (ret == GNUTLS_E_INVALID_REQUEST)
205 			fprintf(stderr, "Error in %s\n", err);
206 		exit(1);
207 	}
208 	if (exp_serv_err) {
209 		HANDSHAKE_EXPECT(client, server, GNUTLS_E_AGAIN, exp_serv_err);
210 		goto cleanup;
211 	} else {
212 		HANDSHAKE(client, server);
213 	}
214 
215 	if (gnutls_kx_get(client) != client_kx) {
216 		testfail("%s: got unexpected key exchange algorithm: %s (expected %s)\n", name, gnutls_kx_get_name(gnutls_kx_get(client)),
217 			gnutls_kx_get_name(client_kx));
218 		exit(1);
219 	}
220 
221 	/* test signature algorithm match */
222 	version = gnutls_protocol_get_version(client);
223 	if (version >= GNUTLS_TLS1_2) {
224 		ret = gnutls_sign_algorithm_get(server);
225 		if (ret != (int)server_sign_algo && server_sign_algo != 0) {
226 			testfail("%s: got unexpected server signature algorithm: %d/%s\n", name, ret, gnutls_sign_get_name(ret));
227 			exit(1);
228 		}
229 
230 		ret = gnutls_sign_algorithm_get_client(server);
231 		if (ret != (int)client_sign_algo && client_sign_algo != 0) {
232 			testfail("%s: got unexpected client signature algorithm: %d/%s\n", name, ret, gnutls_sign_get_name(ret));
233 			exit(1);
234 		}
235 
236 		ret = gnutls_sign_algorithm_get(client);
237 		if (ret != (int)server_sign_algo && server_sign_algo != 0) {
238 			testfail("%s: cl: got unexpected server signature algorithm: %d/%s\n", name, ret, gnutls_sign_get_name(ret));
239 			exit(1);
240 		}
241 
242 		ret = gnutls_sign_algorithm_get_client(client);
243 		if (ret != (int)client_sign_algo && client_sign_algo != 0) {
244 			testfail("%s: cl: got unexpected client signature algorithm: %d/%s\n", name, ret, gnutls_sign_get_name(ret));
245 			exit(1);
246 		}
247 	}
248 
249 	gnutls_bye(client, GNUTLS_SHUT_RDWR);
250 	gnutls_bye(server, GNUTLS_SHUT_RDWR);
251 
252  cleanup:
253 	gnutls_deinit(client);
254 	gnutls_deinit(server);
255 
256 	gnutls_certificate_free_credentials(s_xcred);
257 	gnutls_certificate_free_credentials(c_xcred);
258 }
259 
260 typedef struct test_st {
261 	const char *name;
262 	gnutls_pk_algorithm_t pk;
263 	const char *prio;
264 	const gnutls_datum_t *cert;
265 	const gnutls_datum_t *key;
266 	gnutls_kx_algorithm_t exp_kx;
267 	int exp_key_err;
268 	int exp_serv_err;
269 	int needs_eddsa;
270 	int needs_decryption;
271 	unsigned requires_pkcs11_pss;
272 } test_st;
273 
274 static const test_st tests[] = {
275 	{.name = "tls1.2: rsa-decryption key",
276 	 .pk = GNUTLS_PK_RSA,
277 	 .prio = "NORMAL:-KX-ALL:+RSA:-VERS-TLS-ALL:+VERS-TLS1.2",
278 	 .cert = &server_ca3_localhost_rsa_decrypt_cert,
279 	 .key = &server_ca3_key,
280 	 .exp_kx = GNUTLS_KX_RSA,
281 	 .needs_decryption = 1
282 	},
283 	{.name = "tls1.2: rsa-decryption key, signatures prioritized",
284 	 .pk = GNUTLS_PK_RSA,
285 	 .prio = "NORMAL:-KX-ALL:+ECDHE-RSA:+RSA:-VERS-TLS-ALL:+VERS-TLS1.2:-SIGN-ALL:+SIGN-RSA-PSS-RSAE-SHA256",
286 	 .cert = &server_ca3_localhost_cert,
287 	 .key = &server_ca3_key,
288 	 .exp_kx = GNUTLS_KX_RSA,
289 	 .needs_decryption = 1
290 	},
291 	{.name = "tls1.2: ecc key",
292 	 .pk = GNUTLS_PK_ECDSA,
293 	 .prio = "NORMAL:-KX-ALL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.2",
294 	 .cert = &server_ca3_localhost_ecc_cert,
295 	 .key = &server_ca3_ecc_key,
296 	 .exp_kx = GNUTLS_KX_ECDHE_ECDSA
297 	},
298 	{.name = "tls1.2: rsa-sign key",
299 	 .pk = GNUTLS_PK_RSA,
300 	 .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.2",
301 	 .cert = &server_ca3_localhost_cert,
302 	 .key = &server_ca3_key,
303 	 .exp_kx = GNUTLS_KX_ECDHE_RSA
304 	},
305 	{.name = "tls1.2: rsa-sign key with rsa-pss sigs prioritized",
306 	 .pk = GNUTLS_PK_RSA,
307 	 .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512:+SIGN-RSA-SHA256:+SIGN-RSA-SHA384:+SIGN-RSA-SHA512:-VERS-TLS-ALL:+VERS-TLS1.2",
308 	 .cert = &server_ca3_localhost_cert,
309 	 .key = &server_ca3_key,
310 	 .exp_kx = GNUTLS_KX_ECDHE_RSA
311 	},
312 	{.name = "tls1.2: rsa-pss-sign key",
313 	 .pk = GNUTLS_PK_RSA_PSS,
314 	 .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.2",
315 	 .cert = &server_ca3_rsa_pss2_cert,
316 	 .key = &server_ca3_rsa_pss2_key,
317 	 .exp_kx = GNUTLS_KX_ECDHE_RSA,
318 	 .requires_pkcs11_pss = 1,
319 	},
320 	{.name = "tls1.2: rsa-pss cert, rsa-sign key",
321 	 .pk = GNUTLS_PK_RSA,
322 	 .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.2",
323 	 .cert = &server_ca3_rsa_pss_cert,
324 	 .key = &server_ca3_rsa_pss_key,
325 	 .exp_kx = GNUTLS_KX_ECDHE_RSA,
326 	 .requires_pkcs11_pss = 1,
327 	},
328 	{.name = "tls1.2: rsa-pss cert, rsa-sign key no PSS signatures",
329 	 .pk = GNUTLS_PK_RSA,
330 	 .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.2:-SIGN-RSA-PSS-SHA256:-SIGN-RSA-PSS-SHA384:-SIGN-RSA-PSS-SHA512:-SIGN-RSA-PSS-RSAE-SHA256:-SIGN-RSA-PSS-RSAE-SHA384:-SIGN-RSA-PSS-RSAE-SHA512",
331 	 .cert = &server_ca3_rsa_pss_cert,
332 	 .key = &server_ca3_rsa_pss_key,
333 	 .exp_kx = GNUTLS_KX_ECDHE_RSA,
334 	 .exp_serv_err = GNUTLS_E_NO_CIPHER_SUITES
335 	},
336 	{.name = "tls1.2: ed25519 cert, ed25519 key",
337 	 .pk = GNUTLS_PK_EDDSA_ED25519,
338 	 .needs_eddsa = 1,
339 	 .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA",
340 	 .cert = &server_ca3_eddsa_cert,
341 	 .key = &server_ca3_eddsa_key,
342 	 .exp_kx = GNUTLS_KX_ECDHE_RSA,
343 	},
344 	{.name = "tls1.3: ecc key",
345 	 .pk = GNUTLS_PK_ECDSA,
346 	 .prio = "NORMAL:-KX-ALL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.3",
347 	 .cert = &server_ca3_localhost_ecc_cert,
348 	 .key = &server_ca3_ecc_key,
349 	 .exp_kx = GNUTLS_KX_ECDHE_RSA
350 	},
351 	{.name = "tls1.3: rsa-sign key",
352 	 .pk = GNUTLS_PK_RSA,
353 	 .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.3",
354 	 .cert = &server_ca3_localhost_cert,
355 	 .key = &server_ca3_key,
356 	 .exp_kx = GNUTLS_KX_ECDHE_RSA
357 	},
358 	{.name = "tls1.3: rsa-sign key with rsa-pss sigs prioritized",
359 	 .pk = GNUTLS_PK_RSA,
360 	 .prio = "NORMAL:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512:+SIGN-RSA-PSS-RSAE-SHA256:+SIGN-RSA-PSS-RSAE-SHA384:+SIGN-RSA-PSS-RSAE-SHA512:-VERS-TLS-ALL:+VERS-TLS1.3",
361 	 .cert = &server_ca3_localhost_cert,
362 	 .key = &server_ca3_key,
363 	 .exp_kx = GNUTLS_KX_ECDHE_RSA
364 	},
365 	{.name = "tls1.3: rsa-pss-sign key",
366 	 .pk = GNUTLS_PK_RSA_PSS,
367 	 .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.3",
368 	 .cert = &server_ca3_rsa_pss2_cert,
369 	 .key = &server_ca3_rsa_pss2_key,
370 	 .exp_kx = GNUTLS_KX_ECDHE_RSA,
371 	 .requires_pkcs11_pss = 1,
372 	},
373 	{.name = "tls1.3: rsa-pss cert, rsa-sign key",
374 	 .pk = GNUTLS_PK_RSA,
375 	 .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.3",
376 	 .cert = &server_ca3_rsa_pss_cert,
377 	 .key = &server_ca3_rsa_pss_key,
378 	 .exp_kx = GNUTLS_KX_ECDHE_RSA,
379 	 .requires_pkcs11_pss = 1,
380 	},
381 	{.name = "tls1.3: rsa-pss cert, rsa-sign key no PSS signatures",
382 	 .pk = GNUTLS_PK_RSA,
383 	 .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA:-VERS-TLS-ALL:+VERS-TLS1.3:-SIGN-RSA-PSS-SHA256:-SIGN-RSA-PSS-SHA384:-SIGN-RSA-PSS-SHA512:-SIGN-RSA-PSS-RSAE-SHA256:-SIGN-RSA-PSS-RSAE-SHA384:-SIGN-RSA-PSS-RSAE-SHA512",
384 	 .cert = &server_ca3_rsa_pss_cert,
385 	 .key = &server_ca3_rsa_pss_key,
386 	 .exp_kx = GNUTLS_KX_ECDHE_RSA,
387 	 .exp_serv_err = GNUTLS_E_NO_CIPHER_SUITES
388 	},
389 	{.name = "tls1.3: ed25519 cert, ed25519 key",
390 	 .needs_eddsa = 1,
391 	 .pk = GNUTLS_PK_EDDSA_ED25519,
392 	 .prio = "NORMAL:+ECDHE-RSA:+ECDHE-ECDSA",
393 	 .cert = &server_ca3_eddsa_cert,
394 	 .key = &server_ca3_eddsa_key,
395 	 .exp_kx = GNUTLS_KX_ECDHE_RSA
396 	}
397 };
398 
399 static
pin_func(void * userdata,int attempt,const char * url,const char * label,unsigned flags,char * pin,size_t pin_max)400 int pin_func(void* userdata, int attempt, const char* url, const char *label,
401 		unsigned flags, char *pin, size_t pin_max)
402 {
403 	if (attempt == 0) {
404 		strcpy(pin, PIN);
405 		return 0;
406 	}
407 	return -1;
408 }
409 
410 #ifndef CKM_RSA_PKCS_PSS
411 # define CKM_RSA_PKCS_PSS (0xdUL)
412 #endif
413 
doit(void)414 void doit(void)
415 {
416 	gnutls_privkey_t privkey;
417 	const char *bin, *lib;
418 	char buf[512];
419 	unsigned int i, have_eddsa;
420 	int ret;
421 
422 #ifdef _WIN32
423 	exit(77);
424 #endif
425 	bin = softhsm_bin();
426 
427 	lib = softhsm_lib();
428 
429 	global_init();
430 
431 	gnutls_global_set_log_function(tls_log_func);
432 	if (debug)
433 		gnutls_global_set_log_level(6);
434 
435 
436 	/* initialize token */
437 	gnutls_pkcs11_set_pin_function(pin_func, NULL);
438 	set_softhsm_conf(CONFIG);
439 	snprintf(buf, sizeof(buf), "%s --init-token --slot 0 --label test --so-pin "PIN" --pin "PIN, bin);
440 	system(buf);
441 
442 	ret = gnutls_pkcs11_add_provider(lib, NULL);
443 	if (ret < 0) {
444 		fail("gnutls_pkcs11_add_provider: %s\n",
445 			gnutls_strerror(ret));
446 	}
447 
448 	have_eddsa = verify_eddsa_presence();
449 
450 	for (i=0;i<sizeof(tests)/sizeof(tests[0]);i++) {
451 		if (tests[i].needs_eddsa && !have_eddsa)
452 			continue;
453 
454 		success("checking: %s\n", tests[i].name);
455 
456 		if (tests[i].requires_pkcs11_pss) {
457 			ret = gnutls_pkcs11_token_check_mechanism("pkcs11:", CKM_RSA_PKCS_PSS, NULL, 0, 0);
458 			if (ret == 0) {
459 				fprintf(stderr, "softhsm2 doesn't support CKM_RSA_PKCS_PSS; skipping test\n");
460 				continue;
461 			}
462 		}
463 
464 		privkey = load_virt_privkey(tests[i].name, tests[i].key, tests[i].exp_key_err, tests[i].needs_decryption);
465 		if (privkey == NULL && tests[i].exp_key_err < 0)
466 			continue;
467 		assert(privkey != 0);
468 
469 		try_with_key(tests[i].name, tests[i].prio,
470 			     tests[i].exp_kx, 0, 0,
471 			     tests[i].cert, privkey,
472 			     tests[i].exp_serv_err);
473 
474 		gnutls_pkcs11_delete_url(SOFTHSM_URL";object=key", GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
475 		remove(CONFIG);
476 	}
477 
478 	gnutls_global_deinit();
479 }
480