1 /*
2 * Copyright (C) 2000-2012 Free Software Foundation, Inc.
3 * Author: Nikos Mavrogiannopoulos
4 *
5 * This file is part of GnuTLS.
6 *
7 * GnuTLS is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * GnuTLS is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23 /* Work around problem reported in
24 <https://permalink.gmane.org/gmane.comp.lib.gnulib.bugs/15755>.*/
25 #if GETTIMEOFDAY_CLOBBERS_LOCALTIME
26 #undef localtime
27 #endif
28
29 #include <getpass.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <gnutls/gnutls.h>
35 #include <gnutls/x509.h>
36 #include <gnutls/crypto.h>
37 #include <time.h>
38 #include <common.h>
39 #include <unistd.h>
40
41 #ifndef _WIN32
42 # include <signal.h>
43 #else
44 #include <ws2tcpip.h>
45 #endif
46
47 #ifdef ENABLE_PKCS11
48 #include <gnutls/pkcs11.h>
49 #endif
50
51 #define SU(x) (x!=NULL?x:"Unknown")
52
53 const char str_unknown[] = "(unknown)";
54
55 static FILE *logfile = NULL;
56 /* Hex encodes the given data adding a semicolon between hex bytes.
57 */
raw_to_string(const unsigned char * raw,size_t raw_size)58 const char *raw_to_string(const unsigned char *raw, size_t raw_size)
59 {
60 static char buf[1024];
61 size_t i;
62 if (raw_size == 0)
63 return "(empty)";
64
65 if (raw_size * 3 + 1 >= sizeof(buf))
66 return "(too large)";
67
68 for (i = 0; i < raw_size; i++) {
69 sprintf(&(buf[i * 3]), "%02X%s", raw[i],
70 (i == raw_size - 1) ? "" : ":");
71 }
72 buf[sizeof(buf) - 1] = '\0';
73
74 return buf;
75 }
76
77 /* Hex encodes the given data.
78 */
raw_to_hex(const unsigned char * raw,size_t raw_size)79 const char *raw_to_hex(const unsigned char *raw, size_t raw_size)
80 {
81 static char buf[1024];
82 size_t i;
83 if (raw_size == 0)
84 return "(empty)";
85
86 if (raw_size * 2 + 1 >= sizeof(buf))
87 return "(too large)";
88
89 for (i = 0; i < raw_size; i++) {
90 sprintf(&(buf[i * 2]), "%02x", raw[i]);
91 }
92 buf[sizeof(buf) - 1] = '\0';
93
94 return buf;
95 }
96
raw_to_base64(const unsigned char * raw,size_t raw_size)97 const char *raw_to_base64(const unsigned char *raw, size_t raw_size)
98 {
99 static char buf[1024];
100 gnutls_datum_t data = {(unsigned char*)raw, raw_size};
101 size_t buf_size;
102 int ret;
103
104 if (raw_size == 0)
105 return "(empty)";
106
107 buf_size = sizeof(buf);
108 ret = gnutls_pem_base64_encode(NULL, &data, buf, &buf_size);
109 if (ret < 0)
110 return "(error)";
111
112 buf[sizeof(buf) - 1] = '\0';
113
114 return buf;
115 }
116
117 static void
print_x509_info(gnutls_session_t session,FILE * out,int flag,int print_cert,int print_crt_status)118 print_x509_info(gnutls_session_t session, FILE *out, int flag, int print_cert, int print_crt_status)
119 {
120 gnutls_x509_crt_t crt;
121 const gnutls_datum_t *cert_list;
122 unsigned int cert_list_size = 0, j;
123 int ret;
124
125 cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
126 if (cert_list_size == 0) {
127 if (print_crt_status)
128 fprintf(stderr, "No certificates found!\n");
129 return;
130 }
131
132 log_msg(out, "- Certificate type: X.509\n");
133 log_msg(out, "- Got a certificate list of %d certificates.\n",
134 cert_list_size);
135
136 for (j = 0; j < cert_list_size; j++) {
137 gnutls_datum_t cinfo;
138
139 ret = gnutls_x509_crt_init(&crt);
140 if (ret < 0) {
141 fprintf(stderr, "Memory error\n");
142 return;
143 }
144
145 ret =
146 gnutls_x509_crt_import(crt, &cert_list[j],
147 GNUTLS_X509_FMT_DER);
148 if (ret < 0) {
149 fprintf(stderr, "Decoding error: %s\n",
150 gnutls_strerror(ret));
151 return;
152 }
153
154 log_msg(out, "- Certificate[%d] info:\n - ", j);
155 if (flag == GNUTLS_CRT_PRINT_COMPACT && j > 0)
156 flag = GNUTLS_CRT_PRINT_ONELINE;
157
158 ret = gnutls_x509_crt_print(crt, flag, &cinfo);
159 if (ret == 0) {
160 log_msg(out, "%s\n", cinfo.data);
161 gnutls_free(cinfo.data);
162 }
163
164 if (print_cert) {
165 gnutls_datum_t pem;
166
167 ret =
168 gnutls_x509_crt_export2(crt,
169 GNUTLS_X509_FMT_PEM, &pem);
170 if (ret < 0) {
171 fprintf(stderr, "Encoding error: %s\n",
172 gnutls_strerror(ret));
173 return;
174 }
175
176 log_msg(out, "\n%s\n", (char*)pem.data);
177
178 gnutls_free(pem.data);
179 }
180
181 gnutls_x509_crt_deinit(crt);
182 }
183 }
184
185 static void
print_rawpk_info(gnutls_session_t session,FILE * out,int flag,int print_cert,int print_crt_status)186 print_rawpk_info(gnutls_session_t session, FILE *out, int flag, int print_cert, int print_crt_status)
187 {
188 gnutls_pcert_st pk_cert;
189 gnutls_pk_algorithm_t pk_algo;
190 const gnutls_datum_t *cert_list;
191 unsigned int cert_list_size = 0;
192 int ret;
193
194 cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
195 if (cert_list_size == 0) {
196 if (print_crt_status)
197 fprintf(stderr, "No certificates found!\n");
198 return;
199 }
200
201 log_msg(out, "- Certificate type: Raw Public Key\n");
202 log_msg(out, "- Got %d Raw public-key(s).\n",
203 cert_list_size);
204
205
206 ret = gnutls_pcert_import_rawpk_raw(&pk_cert, cert_list, GNUTLS_X509_FMT_DER, 0, 0);
207 if (ret < 0) {
208 fprintf(stderr, "Decoding error: %s\n",
209 gnutls_strerror(ret));
210 return;
211 }
212
213 pk_algo = gnutls_pubkey_get_pk_algorithm(pk_cert.pubkey, NULL);
214
215 log_msg(out, "- Raw pk info:\n");
216 log_msg(out, " - PK algo: %s\n", gnutls_pk_algorithm_get_name(pk_algo));
217
218 if (print_cert) {
219 gnutls_datum_t pem;
220
221 ret = gnutls_pubkey_export2(pk_cert.pubkey, GNUTLS_X509_FMT_PEM, &pem);
222 if (ret < 0) {
223 fprintf(stderr, "Encoding error: %s\n",
224 gnutls_strerror(ret));
225 return;
226 }
227
228 log_msg(out, "\n%s\n", (char*)pem.data);
229
230 gnutls_free(pem.data);
231 }
232
233 }
234
235 /* returns false (0) if not verified, or true (1) otherwise
236 */
cert_verify(gnutls_session_t session,const char * hostname,const char * purpose)237 int cert_verify(gnutls_session_t session, const char *hostname, const char *purpose)
238 {
239 int rc;
240 unsigned int status = 0;
241 gnutls_datum_t out;
242 int type;
243 gnutls_typed_vdata_st data[2];
244 unsigned elements = 0;
245
246 memset(data, 0, sizeof(data));
247
248 if (hostname) {
249 data[elements].type = GNUTLS_DT_DNS_HOSTNAME;
250 data[elements].data = (void*)hostname;
251 elements++;
252 }
253
254 if (purpose) {
255 data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
256 data[elements].data = (void*)purpose;
257 elements++;
258 }
259
260 rc = gnutls_certificate_verify_peers(session, data, elements, &status);
261 if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND) {
262 log_msg(stdout, "- Peer did not send any certificate.\n");
263 return 0;
264 }
265
266 if (rc < 0) {
267 log_msg(stdout, "- Could not verify certificate (err: %s)\n",
268 gnutls_strerror(rc));
269 return 0;
270 }
271
272 type = gnutls_certificate_type_get(session);
273 rc = gnutls_certificate_verification_status_print(status, type,
274 &out, 0);
275 if (rc < 0) {
276 log_msg(stdout, "- Could not print verification flags (err: %s)\n",
277 gnutls_strerror(rc));
278 return 0;
279 }
280
281 log_msg(stdout, "- Status: %s\n", out.data);
282
283 gnutls_free(out.data);
284
285 if (status) {
286 if (!(status & GNUTLS_CERT_INVALID))
287 abort();
288 return 0;
289 }
290
291 return 1;
292 }
293
294 static void
print_dh_info(gnutls_session_t session,const char * str,int print)295 print_dh_info(gnutls_session_t session, const char *str, int print)
296 {
297 #if defined(ENABLE_DHE) || defined(ENABLE_ANON)
298 unsigned group;
299 int ret;
300 gnutls_datum_t raw_gen = { NULL, 0 };
301 gnutls_datum_t raw_prime = { NULL, 0 };
302 gnutls_dh_params_t dh_params = NULL;
303 unsigned char *params_data = NULL;
304 size_t params_data_size = 0;
305
306 if (!print)
307 return;
308
309 group = gnutls_group_get(session);
310 if (group != 0) {
311 return;
312 }
313
314 log_msg(stdout, "- %sDiffie-Hellman parameters\n", str);
315 log_msg(stdout, " - Using prime: %d bits\n",
316 gnutls_dh_get_prime_bits(session));
317 log_msg(stdout, " - Secret key: %d bits\n",
318 gnutls_dh_get_secret_bits(session));
319 log_msg(stdout, " - Peer's public key: %d bits\n",
320 gnutls_dh_get_peers_public_bits(session));
321
322 ret = gnutls_dh_get_group(session, &raw_gen, &raw_prime);
323 if (ret) {
324 fprintf(stderr, "gnutls_dh_get_group %d\n", ret);
325 goto out;
326 }
327
328 ret = gnutls_dh_params_init(&dh_params);
329 if (ret) {
330 fprintf(stderr, "gnutls_dh_params_init %d\n", ret);
331 goto out;
332 }
333
334 ret =
335 gnutls_dh_params_import_raw(dh_params, &raw_prime,
336 &raw_gen);
337 if (ret) {
338 fprintf(stderr, "gnutls_dh_params_import_raw %d\n",
339 ret);
340 goto out;
341 }
342
343 ret = gnutls_dh_params_export_pkcs3(dh_params,
344 GNUTLS_X509_FMT_PEM,
345 params_data,
346 ¶ms_data_size);
347 if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
348 fprintf(stderr,
349 "gnutls_dh_params_export_pkcs3 %d\n", ret);
350 goto out;
351 }
352
353 params_data = gnutls_malloc(params_data_size);
354 if (!params_data) {
355 fprintf(stderr, "gnutls_malloc %d\n", ret);
356 goto out;
357 }
358
359 ret = gnutls_dh_params_export_pkcs3(dh_params,
360 GNUTLS_X509_FMT_PEM,
361 params_data,
362 ¶ms_data_size);
363 if (ret) {
364 fprintf(stderr,
365 "gnutls_dh_params_export_pkcs3-2 %d\n",
366 ret);
367 goto out;
368 }
369
370 log_msg(stdout, " - PKCS#3 format:\n\n%.*s\n",
371 (int) params_data_size, params_data);
372
373 out:
374 gnutls_free(params_data);
375 gnutls_free(raw_prime.data);
376 gnutls_free(raw_gen.data);
377 gnutls_dh_params_deinit(dh_params);
378 #endif
379 }
380
print_ecdh_info(gnutls_session_t session,const char * str,int print)381 static void print_ecdh_info(gnutls_session_t session, const char *str, int print)
382 {
383 int curve;
384
385 if (!print)
386 return;
387
388 log_msg(stdout, "- %sEC Diffie-Hellman parameters\n", str);
389
390 curve = gnutls_ecc_curve_get(session);
391
392 log_msg(stdout, " - Using curve: %s\n", gnutls_ecc_curve_get_name(curve));
393 log_msg(stdout, " - Curve size: %d bits\n",
394 gnutls_ecc_curve_get_size(curve) * 8);
395
396 }
397
print_info(gnutls_session_t session,int verbose,int flags)398 int print_info(gnutls_session_t session, int verbose, int flags)
399 {
400 const char *tmp;
401 gnutls_credentials_type_t cred;
402 gnutls_kx_algorithm_t kx;
403 unsigned char session_id[33];
404 size_t session_id_size = sizeof(session_id);
405 gnutls_srtp_profile_t srtp_profile;
406 gnutls_datum_t p;
407 char *desc;
408 gnutls_protocol_t version;
409 int rc;
410
411 desc = gnutls_session_get_desc(session);
412 log_msg(stdout, "- Description: %s\n", desc);
413 gnutls_free(desc);
414
415 /* print session ID */
416 gnutls_session_get_id(session, session_id, &session_id_size);
417 if (session_id_size > 0) {
418 log_msg(stdout, "- Session ID: %s\n",
419 raw_to_string(session_id, session_id_size));
420 }
421
422 /* print the key exchange's algorithm name
423 */
424 kx = gnutls_kx_get(session);
425
426 cred = gnutls_auth_get_type(session);
427 switch (cred) {
428 #ifdef ENABLE_ANON
429 case GNUTLS_CRD_ANON:
430 if (kx == GNUTLS_KX_ANON_ECDH)
431 print_ecdh_info(session, "Anonymous ", verbose);
432 else
433 print_dh_info(session, "Anonymous ", verbose);
434 break;
435 #endif
436 #ifdef ENABLE_SRP
437 case GNUTLS_CRD_SRP:
438 /* This should be only called in server
439 * side.
440 */
441 if (gnutls_srp_server_get_username(session) != NULL)
442 log_msg(stdout, "- SRP authentication. Connected as '%s'\n",
443 gnutls_srp_server_get_username(session));
444 break;
445 #endif
446 #ifdef ENABLE_PSK
447 case GNUTLS_CRD_PSK:
448 /* This returns NULL in server side.
449 */
450 if (gnutls_psk_client_get_hint(session) != NULL)
451 log_msg(stdout, "- PSK authentication. PSK hint '%s'\n",
452 gnutls_psk_client_get_hint(session));
453 /* This returns NULL in client side.
454 */
455 if (gnutls_psk_server_get_username(session) != NULL)
456 log_msg(stdout, "- PSK authentication. Connected as '%s'\n",
457 gnutls_psk_server_get_username(session));
458 if (kx == GNUTLS_KX_DHE_PSK)
459 print_dh_info(session, "Ephemeral ", verbose);
460 if (kx == GNUTLS_KX_ECDHE_PSK)
461 print_ecdh_info(session, "Ephemeral ", verbose);
462 break;
463 #endif
464 case GNUTLS_CRD_IA:
465 log_msg(stdout, "- TLS/IA authentication\n");
466 break;
467 case GNUTLS_CRD_CERTIFICATE:
468 {
469 char dns[256];
470 size_t dns_size = sizeof(dns);
471 unsigned int type;
472
473 /* This fails in client side */
474 if (gnutls_server_name_get
475 (session, dns, &dns_size, &type, 0) == 0) {
476 log_msg(stdout, "- Given server name[%d]: %s\n",
477 type, dns);
478 }
479 }
480
481 if ((flags & P_WAIT_FOR_CERT) && gnutls_certificate_get_ours(session) == 0)
482 log_msg(stdout, "- No certificate was sent to peer\n");
483
484 if (flags& P_PRINT_CERT)
485 print_cert_info(session, verbose, (flags&P_PRINT_CERT));
486
487 if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS)
488 print_dh_info(session, "Ephemeral ", verbose);
489 else if (kx == GNUTLS_KX_ECDHE_RSA
490 || kx == GNUTLS_KX_ECDHE_ECDSA)
491 print_ecdh_info(session, "Ephemeral ", verbose);
492 }
493
494
495 if (verbose) {
496 version = gnutls_protocol_get_version(session);
497 tmp =
498 SU(gnutls_protocol_get_name(version));
499 log_msg(stdout, "- Version: %s\n", tmp);
500
501 if (version < GNUTLS_TLS1_3) {
502 tmp = SU(gnutls_kx_get_name(kx));
503 log_msg(stdout, "- Key Exchange: %s\n", tmp);
504 }
505
506 if (gnutls_sign_algorithm_get(session) != GNUTLS_SIGN_UNKNOWN) {
507 tmp =
508 SU(gnutls_sign_get_name
509 (gnutls_sign_algorithm_get(session)));
510 log_msg(stdout, "- Server Signature: %s\n", tmp);
511 }
512
513 if (gnutls_sign_algorithm_get_client(session) !=
514 GNUTLS_SIGN_UNKNOWN) {
515 tmp =
516 SU(gnutls_sign_get_name
517 (gnutls_sign_algorithm_get_client(session)));
518 log_msg(stdout, "- Client Signature: %s\n", tmp);
519 }
520
521 tmp = SU(gnutls_cipher_get_name(gnutls_cipher_get(session)));
522 log_msg(stdout, "- Cipher: %s\n", tmp);
523
524 tmp = SU(gnutls_mac_get_name(gnutls_mac_get(session)));
525 log_msg(stdout, "- MAC: %s\n", tmp);
526 }
527
528 log_msg(stdout, "- Options:");
529 if (gnutls_session_ext_master_secret_status(session)!=0)
530 log_msg(stdout, " extended master secret,");
531 if (gnutls_safe_renegotiation_status(session)!=0)
532 log_msg(stdout, " safe renegotiation,");
533 if (gnutls_session_etm_status(session)!=0)
534 log_msg(stdout, " EtM,");
535 #ifdef ENABLE_OCSP
536 if (gnutls_ocsp_status_request_is_checked(session, GNUTLS_OCSP_SR_IS_AVAIL)!=0) {
537 log_msg(stdout, " OCSP status request%s,", gnutls_ocsp_status_request_is_checked(session,0)!=0?"":"[ignored]");
538 }
539 #endif
540 log_msg(stdout, "\n");
541
542 #ifdef ENABLE_DTLS_SRTP
543 rc = gnutls_srtp_get_selected_profile(session, &srtp_profile);
544 if (rc == 0)
545 log_msg(stdout, "- SRTP profile: %s\n",
546 gnutls_srtp_get_profile_name(srtp_profile));
547 #endif
548
549 #ifdef ENABLE_ALPN
550 rc = gnutls_alpn_get_selected_protocol(session, &p);
551 if (rc == 0)
552 log_msg(stdout, "- Application protocol: %.*s\n", p.size, p.data);
553 #endif
554
555 if (verbose) {
556 gnutls_datum_t cb;
557
558 rc = gnutls_session_channel_binding(session,
559 GNUTLS_CB_TLS_UNIQUE,
560 &cb);
561 if (rc)
562 fprintf(stderr, "Channel binding error: %s\n",
563 gnutls_strerror(rc));
564 else {
565 size_t i;
566
567 log_msg(stdout, "- Channel binding 'tls-unique': ");
568 for (i = 0; i < cb.size; i++)
569 log_msg(stdout, "%02x", cb.data[i]);
570 log_msg(stdout, "\n");
571 gnutls_free(cb.data);
572 }
573 }
574
575 fflush(stdout);
576
577 return 0;
578 }
579
print_cert_info(gnutls_session_t session,int verbose,int print_cert)580 void print_cert_info(gnutls_session_t session, int verbose, int print_cert)
581 {
582 print_cert_info2(session, verbose, stdout, print_cert);
583 }
584
print_cert_info2(gnutls_session_t session,int verbose,FILE * out,int print_cert)585 void print_cert_info2(gnutls_session_t session, int verbose, FILE *out, int print_cert)
586 {
587 int flag, print_crt_status = 0;
588
589 if (verbose)
590 flag = GNUTLS_CRT_PRINT_FULL;
591 else
592 flag = GNUTLS_CRT_PRINT_COMPACT;
593
594 if (gnutls_certificate_client_get_request_status(session) != 0) {
595 log_msg(stdout, "- Server has requested a certificate.\n");
596 print_crt_status = 1;
597 }
598
599 switch (gnutls_certificate_type_get2(session, GNUTLS_CTYPE_PEERS)) {
600 case GNUTLS_CRT_X509:
601 print_x509_info(session, out, flag, print_cert, print_crt_status);
602 break;
603 case GNUTLS_CRT_RAWPK:
604 print_rawpk_info(session, out, flag, print_cert, print_crt_status);
605 break;
606 default:
607 break;
608 }
609 }
610
print_list(const char * priorities,int verbose)611 void print_list(const char *priorities, int verbose)
612 {
613 size_t i;
614 int ret;
615 unsigned int idx;
616 const char *name;
617 const char *err;
618 unsigned char id[2];
619 gnutls_kx_algorithm_t kx;
620 gnutls_cipher_algorithm_t cipher;
621 gnutls_mac_algorithm_t mac;
622 gnutls_protocol_t version;
623 gnutls_priority_t pcache;
624 const unsigned int *list;
625
626 if (priorities != NULL) {
627 log_msg(stdout, "Cipher suites for %s\n", priorities);
628
629 ret = gnutls_priority_init(&pcache, priorities, &err);
630 if (ret < 0) {
631 if (ret == GNUTLS_E_INVALID_REQUEST)
632 fprintf(stderr, "Syntax error at: %s\n", err);
633 else
634 fprintf(stderr, "Error in priorities: %s\n", gnutls_strerror(ret));
635 exit(1);
636 }
637
638 for (i = 0;; i++) {
639 ret =
640 gnutls_priority_get_cipher_suite_index(pcache,
641 i,
642 &idx);
643 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
644 break;
645 if (ret == GNUTLS_E_UNKNOWN_CIPHER_SUITE)
646 continue;
647
648 name =
649 gnutls_cipher_suite_info(idx, id, NULL, NULL,
650 NULL, &version);
651
652 if (name != NULL)
653 log_msg(stdout, "%-50s\t0x%02x, 0x%02x\t%s\n",
654 name, (unsigned char) id[0],
655 (unsigned char) id[1],
656 gnutls_protocol_get_name(version));
657 }
658
659 log_msg(stdout, "\n");
660 #if 0
661 {
662 ret =
663 gnutls_priority_certificate_type_list2(pcache,
664 &list,
665 GNUTLS_CTYPE_CLIENT);
666
667 log_msg(stdout, "Certificate types: ");
668 if (ret == 0)
669 log_msg(stdout, "none\n");
670 for (i = 0; i < (unsigned) ret; i++) {
671 log_msg(stdout, "CTYPE-%s",
672 gnutls_certificate_type_get_name
673 (list[i]));
674 if (i + 1 != (unsigned) ret)
675 log_msg(stdout, ", ");
676 else
677 log_msg(stdout, "\n");
678 }
679 }
680 #endif
681
682 {
683 ret = gnutls_priority_protocol_list(pcache, &list);
684
685 log_msg(stdout, "Protocols: ");
686 if (ret == 0)
687 log_msg(stdout, "none\n");
688 for (i = 0; i < (unsigned) ret; i++) {
689 log_msg(stdout, "VERS-%s",
690 gnutls_protocol_get_name(list[i]));
691 if (i + 1 != (unsigned) ret)
692 log_msg(stdout, ", ");
693 else
694 log_msg(stdout, "\n");
695 }
696 }
697
698 {
699 ret = gnutls_priority_cipher_list(pcache, &list);
700
701 log_msg(stdout, "Ciphers: ");
702 if (ret == 0)
703 log_msg(stdout, "none\n");
704 for (i = 0; i < (unsigned) ret; i++) {
705 log_msg(stdout, "%s",
706 gnutls_cipher_get_name(list[i]));
707 if (i + 1 != (unsigned) ret)
708 log_msg(stdout, ", ");
709 else
710 log_msg(stdout, "\n");
711 }
712 }
713
714 {
715 ret = gnutls_priority_mac_list(pcache, &list);
716
717 log_msg(stdout, "MACs: ");
718 if (ret == 0)
719 log_msg(stdout, "none\n");
720 for (i = 0; i < (unsigned) ret; i++) {
721 log_msg(stdout, "%s",
722 gnutls_mac_get_name(list[i]));
723 if (i + 1 != (unsigned) ret)
724 log_msg(stdout, ", ");
725 else
726 log_msg(stdout, "\n");
727 }
728 }
729
730 {
731 ret = gnutls_priority_kx_list(pcache, &list);
732
733 log_msg(stdout, "Key Exchange Algorithms: ");
734 if (ret == 0)
735 log_msg(stdout, "none\n");
736 for (i = 0; i < (unsigned) ret; i++) {
737 log_msg(stdout, "%s",
738 gnutls_kx_get_name(list[i]));
739 if (i + 1 != (unsigned) ret)
740 log_msg(stdout, ", ");
741 else
742 log_msg(stdout, "\n");
743 }
744 }
745
746 {
747 ret =
748 gnutls_priority_group_list(pcache, &list);
749
750 log_msg(stdout, "Groups: ");
751 if (ret == 0)
752 log_msg(stdout, "none\n");
753 for (i = 0; i < (unsigned) ret; i++) {
754 log_msg(stdout, "GROUP-%s",
755 gnutls_group_get_name(list[i]));
756 if (i + 1 != (unsigned) ret)
757 log_msg(stdout, ", ");
758 else
759 log_msg(stdout, "\n");
760 }
761 }
762
763 {
764 ret = gnutls_priority_sign_list(pcache, &list);
765
766 log_msg(stdout, "PK-signatures: ");
767 if (ret == 0)
768 log_msg(stdout, "none\n");
769 for (i = 0; i < (unsigned) ret; i++) {
770 log_msg(stdout, "SIGN-%s",
771 gnutls_sign_algorithm_get_name(list
772 [i]));
773 if (i + 1 != (unsigned) ret)
774 log_msg(stdout, ", ");
775 else
776 log_msg(stdout, "\n");
777 }
778 }
779
780 gnutls_priority_deinit(pcache);
781 return;
782 }
783
784 log_msg(stdout, "Cipher suites:\n");
785 for (i = 0; (name = gnutls_cipher_suite_info
786 (i, id, &kx, &cipher, &mac, &version)); i++) {
787 log_msg(stdout, "%-50s\t0x%02x, 0x%02x\t%s\n",
788 name,
789 (unsigned char) id[0], (unsigned char) id[1],
790 gnutls_protocol_get_name(version));
791 if (verbose)
792 log_msg
793 (stdout, "\tKey exchange: %s\n\tCipher: %s\n\tMAC: %s\n\n",
794 gnutls_kx_get_name(kx),
795 gnutls_cipher_get_name(cipher),
796 gnutls_mac_get_name(mac));
797 }
798
799 log_msg(stdout, "\n");
800 {
801 const gnutls_certificate_type_t *p =
802 gnutls_certificate_type_list();
803
804 log_msg(stdout, "Certificate types: ");
805 for (; *p; p++) {
806 log_msg(stdout, "CTYPE-%s",
807 gnutls_certificate_type_get_name(*p));
808 if (*(p + 1))
809 log_msg(stdout, ", ");
810 else
811 log_msg(stdout, "\n");
812 }
813 }
814
815 {
816 const gnutls_protocol_t *p = gnutls_protocol_list();
817
818 log_msg(stdout, "Protocols: ");
819 for (; *p; p++) {
820 log_msg(stdout, "VERS-%s", gnutls_protocol_get_name(*p));
821 if (*(p + 1))
822 log_msg(stdout, ", ");
823 else
824 log_msg(stdout, "\n");
825 }
826 }
827
828 {
829 const gnutls_cipher_algorithm_t *p = gnutls_cipher_list();
830
831 log_msg(stdout, "Ciphers: ");
832 for (; *p; p++) {
833 log_msg(stdout, "%s", gnutls_cipher_get_name(*p));
834 if (*(p + 1))
835 log_msg(stdout, ", ");
836 else
837 log_msg(stdout, "\n");
838 }
839 }
840
841 {
842 const gnutls_mac_algorithm_t *p = gnutls_mac_list();
843
844 log_msg(stdout, "MACs: ");
845 for (; *p; p++) {
846 log_msg(stdout, "%s", gnutls_mac_get_name(*p));
847 if (*(p + 1))
848 log_msg(stdout, ", ");
849 else
850 log_msg(stdout, "\n");
851 }
852 }
853
854 {
855 const gnutls_digest_algorithm_t *p = gnutls_digest_list();
856
857 log_msg(stdout, "Digests: ");
858 for (; *p; p++) {
859 log_msg(stdout, "%s", gnutls_digest_get_name(*p));
860 if (*(p + 1))
861 log_msg(stdout, ", ");
862 else
863 log_msg(stdout, "\n");
864 }
865 }
866
867 {
868 const gnutls_kx_algorithm_t *p = gnutls_kx_list();
869
870 log_msg(stdout, "Key exchange algorithms: ");
871 for (; *p; p++) {
872 log_msg(stdout, "%s", gnutls_kx_get_name(*p));
873 if (*(p + 1))
874 log_msg(stdout, ", ");
875 else
876 log_msg(stdout, "\n");
877 }
878 }
879
880 {
881 const gnutls_compression_method_t *p =
882 gnutls_compression_list();
883
884 log_msg(stdout, "Compression: ");
885 for (; *p; p++) {
886 log_msg(stdout, "COMP-%s", gnutls_compression_get_name(*p));
887 if (*(p + 1))
888 log_msg(stdout, ", ");
889 else
890 log_msg(stdout, "\n");
891 }
892 }
893
894 {
895 const gnutls_group_t *p = gnutls_group_list();
896
897 log_msg(stdout, "Groups: ");
898 for (; *p; p++) {
899 log_msg(stdout, "GROUP-%s", gnutls_group_get_name(*p));
900 if (*(p + 1))
901 log_msg(stdout, ", ");
902 else
903 log_msg(stdout, "\n");
904 }
905 }
906
907 {
908 const gnutls_pk_algorithm_t *p = gnutls_pk_list();
909
910 log_msg(stdout, "Public Key Systems: ");
911 for (; *p; p++) {
912 log_msg(stdout, "%s", gnutls_pk_algorithm_get_name(*p));
913 if (*(p + 1))
914 log_msg(stdout, ", ");
915 else
916 log_msg(stdout, "\n");
917 }
918 }
919
920 {
921 const gnutls_sign_algorithm_t *p = gnutls_sign_list();
922
923 log_msg(stdout, "PK-signatures: ");
924 for (; *p; p++) {
925 log_msg(stdout, "SIGN-%s",
926 gnutls_sign_algorithm_get_name(*p));
927 if (*(p + 1))
928 log_msg(stdout, ", ");
929 else
930 log_msg(stdout, "\n");
931 }
932 }
933 }
934
935 void
print_key_material(gnutls_session_t session,const char * label,size_t size)936 print_key_material(gnutls_session_t session, const char *label, size_t size)
937 {
938 gnutls_datum_t bin = { NULL, 0 }, hex = { NULL, 0 };
939 int ret;
940
941 bin.data = gnutls_malloc(size);
942 if (!bin.data) {
943 fprintf(stderr, "Error in gnutls_malloc: %s\n",
944 gnutls_strerror(GNUTLS_E_MEMORY_ERROR));
945 goto out;
946 }
947
948 bin.size = size;
949
950 ret = gnutls_prf_rfc5705(session, strlen(label), label,
951 0, NULL, size, (char *)bin.data);
952 if (ret < 0) {
953 fprintf(stderr, "Error in gnutls_prf_rfc5705: %s\n",
954 gnutls_strerror(ret));
955 goto out;
956 }
957
958 ret = gnutls_hex_encode2(&bin, &hex);
959 if (ret < 0) {
960 fprintf(stderr, "Error in hex encoding: %s\n",
961 gnutls_strerror(ret));
962 goto out;
963 }
964 log_msg(stdout, "- Key material: %s\n", hex.data);
965 fflush(stdout);
966
967 out:
968 gnutls_free(bin.data);
969 gnutls_free(hex.data);
970 }
971
check_command(gnutls_session_t session,const char * str,unsigned no_cli_cert)972 int check_command(gnutls_session_t session, const char *str, unsigned no_cli_cert)
973 {
974 size_t len = strnlen(str, 128);
975 int ret;
976
977 fprintf(stderr, "*** Processing %u bytes command: %s\n", (unsigned)len,
978 str);
979 if (len > 2 && str[0] == str[1] && str[0] == '*') {
980 if (strncmp
981 (str, "**REHANDSHAKE**",
982 sizeof("**REHANDSHAKE**") - 1) == 0) {
983 fprintf(stderr,
984 "*** Sending rehandshake request\n");
985 gnutls_rehandshake(session);
986 return 1;
987 } else if (strncmp
988 (str, "**REAUTH**",
989 sizeof("**REAUTH**") - 1) == 0) {
990 /* in case we have a re-auth cmd prepare for it */
991 if (no_cli_cert)
992 gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUIRE);
993
994 fprintf(stderr,
995 "*** Sending re-auth request\n");
996 do {
997 ret = gnutls_reauth(session, 0);
998 } while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
999 if (ret < 0) {
1000 fprintf(stderr, "reauth: %s\n",
1001 gnutls_strerror(ret));
1002 return ret;
1003 }
1004 return 1;
1005 } else
1006 if (strncmp
1007 (str, "**HEARTBEAT**",
1008 sizeof("**HEARTBEAT**") - 1) == 0) {
1009 ret =
1010 gnutls_heartbeat_ping(session, 300, 5,
1011 GNUTLS_HEARTBEAT_WAIT);
1012 if (ret < 0) {
1013 if (ret == GNUTLS_E_INVALID_REQUEST) {
1014 fprintf(stderr,
1015 "No heartbeat in this session\n");
1016 } else {
1017 fprintf(stderr, "ping: %s\n",
1018 gnutls_strerror(ret));
1019 return ret;
1020 }
1021 }
1022 return 2;
1023 }
1024 }
1025 return 0;
1026 }
1027
1028 /* error is indicated by returning an empty string */
getpass_copy(char * pass,size_t max_pass_size,const char * prompt)1029 void getpass_copy(char *pass, size_t max_pass_size, const char *prompt)
1030 {
1031 char *tmp;
1032 size_t len;
1033
1034 tmp = getpass(prompt);
1035 if (tmp == NULL) {
1036 pass[0] = 0;
1037 return;
1038 }
1039
1040 len = strlen(tmp);
1041 if (len >= max_pass_size) {
1042 gnutls_memset(tmp, 0, len);
1043 pass[0] = 0;
1044 return;
1045 }
1046
1047 strcpy(pass, tmp);
1048 gnutls_memset(tmp, 0, len);
1049
1050 return;
1051 }
1052
1053 /* error is indicated by returning an empty string */
getenv_copy(char * str,size_t max_str_size,const char * envvar)1054 void getenv_copy(char *str, size_t max_str_size, const char *envvar)
1055 {
1056 char *tmp;
1057 size_t len;
1058
1059 tmp = getenv(envvar);
1060 if (tmp == NULL) {
1061 str[0] = 0;
1062 return;
1063 }
1064
1065 len = strlen(tmp);
1066 if (len >= max_str_size) {
1067 str[0] = 0;
1068 return;
1069 }
1070
1071 strcpy(str, tmp);
1072
1073 return;
1074 }
1075
1076 #define MIN(x,y) ((x)<(y))?(x):(y)
1077 #define MAX_CACHE_TRIES 5
1078 int
pin_callback(void * user,int attempt,const char * token_url,const char * token_label,unsigned int flags,char * pin,size_t pin_max)1079 pin_callback(void *user, int attempt, const char *token_url,
1080 const char *token_label, unsigned int flags, char *pin,
1081 size_t pin_max)
1082 {
1083 char password[MAX_PIN_LEN] = "";
1084 common_info_st *info = user;
1085 const char *desc;
1086 int cache = MAX_CACHE_TRIES;
1087 unsigned len;
1088 /* allow caching of PIN */
1089 static char *cached_url = NULL;
1090 static char cached_pin[MAX_PIN_LEN] = "";
1091 const char *env;
1092
1093 if (flags & GNUTLS_PIN_SO) {
1094 env = "GNUTLS_SO_PIN";
1095 desc = "security officer";
1096 if (info && info->so_pin)
1097 snprintf(password, sizeof(password), "%s", info->so_pin);
1098 } else {
1099 env = "GNUTLS_PIN";
1100 desc = "user";
1101 if (info && info->pin)
1102 snprintf(password, sizeof(password), "%s", info->pin);
1103 }
1104
1105 if (flags & GNUTLS_PIN_FINAL_TRY) {
1106 cache = 0;
1107 log_msg(stdout, "*** This is the final try before locking!\n");
1108 }
1109 if (flags & GNUTLS_PIN_COUNT_LOW) {
1110 cache = 0;
1111 log_msg(stdout, "*** Only few tries left before locking!\n");
1112 }
1113
1114 if (flags & GNUTLS_PIN_WRONG) {
1115 cache = 0;
1116 log_msg(stdout, "*** Wrong PIN has been provided!\n");
1117 }
1118
1119 if (cache > 0 && cached_url != NULL) {
1120 if (token_url != NULL
1121 && strcmp(cached_url, token_url) == 0) {
1122 if (strlen(cached_pin) >= pin_max) {
1123 fprintf(stderr, "Too long PIN given\n");
1124 exit(1);
1125 }
1126
1127 if (info && info->verbose) {
1128 fprintf(stderr,
1129 "Re-using cached PIN for token '%s'\n",
1130 token_label);
1131 }
1132 strcpy(pin, cached_pin);
1133 cache--;
1134 return 0;
1135 }
1136 }
1137
1138 if (password[0] == 0) {
1139 getenv_copy(password, sizeof(password), env);
1140 if (password[0] == 0) /* compatibility */
1141 getenv_copy(password, sizeof(password), "GNUTLS_PIN");
1142 }
1143
1144 if (password[0] == 0 && (info == NULL || info->batch == 0 || info->ask_pass != 0)) {
1145 if (token_label && token_label[0] != 0) {
1146 fprintf(stderr, "Token '%s' with URL '%s' ", token_label, token_url);
1147 fprintf(stderr, "requires %s PIN\n", desc);
1148 getpass_copy(password, sizeof(password), "Enter PIN: ");
1149 } else {
1150 getpass_copy(password, sizeof(password), "Enter password: ");
1151 }
1152
1153 } else {
1154 if (flags & GNUTLS_PIN_WRONG) {
1155 if (token_label && token_label[0] != 0) {
1156 fprintf(stderr, "Token '%s' with URL '%s' ", token_label, token_url);
1157 fprintf(stderr, "requires %s PIN\n", desc);
1158 }
1159 fprintf(stderr, "Cannot continue with a wrong password in the environment.\n");
1160 exit(1);
1161 }
1162 }
1163
1164 if (password[0] == 0 || password[0] == '\n') {
1165 fprintf(stderr, "No PIN given.\n");
1166 if (info != NULL && info->batch != 0) {
1167 fprintf(stderr, "note: when operating in batch mode, set the GNUTLS_PIN or GNUTLS_SO_PIN environment variables\n");
1168 }
1169 exit(1);
1170 }
1171
1172 len = MIN(pin_max - 1, strlen(password));
1173 memcpy(pin, password, len);
1174 pin[len] = 0;
1175
1176 /* cache */
1177 if (len < sizeof(cached_pin)) {
1178 memcpy(cached_pin, pin, len);
1179 cached_pin[len] = 0;
1180 } else
1181 cached_pin[0] = 0;
1182
1183 free(cached_url);
1184 if (token_url)
1185 cached_url = strdup(token_url);
1186 else
1187 cached_url = NULL;
1188
1189 return 0;
1190 }
1191
1192 #ifdef ENABLE_PKCS11
1193
1194 static int
token_callback(void * user,const char * label,const unsigned retry)1195 token_callback(void *user, const char *label, const unsigned retry)
1196 {
1197 char buf[32];
1198 common_info_st *info = user;
1199
1200 if (retry > 0 || (info != NULL && info->batch != 0)) {
1201 fprintf(stderr, "Could not find token %s\n", label);
1202 return -1;
1203 }
1204 log_msg(stdout, "Please insert token '%s' in slot and press enter\n",
1205 label);
1206 if (fgets(buf, sizeof(buf), stdin) == NULL) {
1207 fprintf(stderr, "error reading input\n");
1208 return -1;
1209 }
1210
1211 return 0;
1212 }
1213
pkcs11_common(common_info_st * c)1214 void pkcs11_common(common_info_st *c)
1215 {
1216
1217 gnutls_pkcs11_set_pin_function(pin_callback, c);
1218 gnutls_pkcs11_set_token_function(token_callback, c);
1219
1220 }
1221
1222 #endif
1223
sockets_init(void)1224 void sockets_init(void)
1225 {
1226 #ifdef _WIN32
1227 WORD wVersionRequested;
1228 WSADATA wsaData;
1229
1230 wVersionRequested = MAKEWORD(1, 1);
1231 if (WSAStartup(wVersionRequested, &wsaData) != 0) {
1232 perror("WSA_STARTUP_ERROR");
1233 }
1234 #else
1235 signal(SIGPIPE, SIG_IGN);
1236 #endif
1237 }
1238
1239
log_msg(FILE * file,const char * message,...)1240 int log_msg(FILE *file, const char *message, ...)
1241 {
1242 va_list args;
1243 int rv;
1244
1245 va_start(args, message);
1246
1247 rv = vfprintf(logfile ? logfile : file, message, args);
1248
1249 va_end(args);
1250
1251 return rv;
1252 }
1253
log_set(FILE * file)1254 void log_set(FILE *file)
1255 {
1256 logfile = file;
1257 }
1258
1259 /* This is very similar to ctime() but it does not force a newline.
1260 */
simple_ctime(const time_t * t,char out[SIMPLE_CTIME_BUF_SIZE])1261 char *simple_ctime(const time_t *t, char out[SIMPLE_CTIME_BUF_SIZE])
1262 {
1263 struct tm tm;
1264
1265 if (localtime_r(t, &tm) == NULL)
1266 goto error;
1267
1268 if (!strftime(out, SIMPLE_CTIME_BUF_SIZE, "%c", &tm))
1269 goto error;
1270
1271 return out;
1272
1273 error:
1274 snprintf(out, SIMPLE_CTIME_BUF_SIZE, "[error]");
1275 return out;
1276 }
1277