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