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 					    &params_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 					    &params_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