more cleanups
[gnutls.git] / src / cli.c
blobe98ed34441285b6863b0abbc33967d59cdbeb74d
1 /*
2 * Copyright (C) 2000,2001,2002 Nikos Mavroyanopoulos
4 * This file is part of GNUTLS.
6 * GNUTLS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * GNUTLS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 #include <stdio.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include "../lib/gnutls.h"
31 #include <sys/time.h>
32 #include <signal.h>
33 #include <netdb.h>
34 #include <common.h>
35 #include "cli-gaa.h"
37 #ifndef SHUT_WR
38 # define SHUT_WR 1
39 #endif
41 #ifndef SHUT_RDWR
42 # define SHUT_RDWR 2
43 #endif
45 #define SA struct sockaddr
46 #define ERR(err,s) if (err==-1) {perror(s);return(1);}
47 #define MAX_BUF 4096
48 #define GERR(ret) fprintf(stderr, "* Error: %s\n", gnutls_strerror(ret))
50 /* global stuff here */
51 int resume;
52 char *hostname = NULL;
53 int port;
54 int record_max_size;
55 int fingerprint;
57 char *srp_passwd;
58 char *srp_username;
59 char *pgp_keyfile;
60 char *pgp_certfile;
61 char *pgp_keyring;
62 char *pgp_trustdb;
63 char *x509_keyfile;
64 char *x509_certfile;
65 char *x509_cafile;
66 char *x509_crlfile = NULL;
69 int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
70 int kx_priority[16] =
71 { GNUTLS_KX_RSA, GNUTLS_KX_DHE_DSS, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP,
72 GNUTLS_KX_ANON_DH, 0
74 int cipher_priority[16] =
75 { GNUTLS_CIPHER_RIJNDAEL_128_CBC, GNUTLS_CIPHER_3DES_CBC,
76 GNUTLS_CIPHER_ARCFOUR, 0
78 int comp_priority[16] = { GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 };
79 int mac_priority[16] = { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 };
80 int cert_type_priority[16] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
82 /* end of global stuff */
84 #define MAX(X,Y) (X >= Y ? X : Y);
85 #define DEFAULT_X509_CAFILE "x509/ca.pem"
86 #define DEFAULT_X509_KEYFILE2 "x509/clikey-dsa.pem"
87 #define DEFAULT_X509_CERTFILE2 "x509/clicert-dsa.pem"
89 #define DEFAULT_X509_KEYFILE "x509/clikey.pem"
90 #define DEFAULT_X509_CERTFILE "x509/clicert.pem"
92 #define DEFAULT_PGP_KEYFILE "openpgp/cli_sec.asc"
93 #define DEFAULT_PGP_CERTFILE "openpgp/cli_pub.asc"
94 #define DEFAULT_PGP_KEYRING "openpgp/cli_ring.gpg"
96 #define DEFAULT_SRP_USERNAME "test"
97 #define DEFAULT_SRP_PASSWD "test"
99 static int cert_callback(GNUTLS_STATE state,
100 const gnutls_datum * client_certs, int ncerts,
101 const gnutls_datum * req_ca_cert, int nreqs)
104 if (client_certs == NULL) {
105 return 0; /* means the we will only be called again
106 * if the library cannot determine which
107 * certificate to send
110 #if 0
111 /* here we should prompt the user and ask him
112 * which certificate to choose. Too bored to
113 * implement that. --nmav
115 for (i = 0; i < ncerts; i++) {
116 fprintf(stderr, "%s.", client_cert->common_name);
117 fprintf(stderr, "%s\n", issuer_cert->common_name);
119 for (i = 0; i < nreqs; i++) {
120 fprintf(stderr, "%s.", req_ca_cert->common_name);
122 fprintf(stderr, "\n");
123 return 0;
124 #endif
126 return -1; /* send no certificate to the peer */
130 static void gaa_parser(int argc, char **argv);
132 int main(int argc, char **argv)
134 int err, ret;
135 int sd, ii, i;
136 struct sockaddr_in sa;
137 GNUTLS_STATE state;
138 char buffer[MAX_BUF + 1];
139 char *session;
140 char *session_id;
141 int session_size, alert;
142 int session_id_size;
143 char *tmp_session_id;
144 int tmp_session_id_size;
145 fd_set rset;
146 int maxfd;
147 struct timeval tv;
148 int user_term = 0;
149 GNUTLS_SRP_CLIENT_CREDENTIALS cred;
150 GNUTLS_ANON_CLIENT_CREDENTIALS anon_cred;
151 GNUTLS_CERTIFICATE_CLIENT_CREDENTIALS xcred;
152 struct hostent *server_host;
154 gaa_parser(argc, argv);
156 signal(SIGPIPE, SIG_IGN);
158 if (gnutls_global_init() < 0) {
159 fprintf(stderr, "global state initialization error\n");
160 exit(1);
163 printf("Resolving '%s'...\n", hostname);
164 /* get server name */
165 server_host = gethostbyname(hostname);
166 if (server_host == NULL) {
167 fprintf(stderr, "Cannot resolve %s\n", hostname);
168 exit(1);
171 /* X509 stuff */
172 if (gnutls_certificate_allocate_sc(&xcred) < 0) { /* space for 2 certificates */
173 fprintf(stderr, "memory error\n");
174 exit(1);
177 if (x509_cafile != NULL) {
178 ret =
179 gnutls_certificate_set_x509_trust_file(xcred, x509_cafile,
180 x509_crlfile);
181 if (ret < 0) {
182 fprintf(stderr, "Error setting the x509 trust file\n");
186 if (x509_certfile != NULL) {
187 ret =
188 gnutls_certificate_set_x509_key_file(xcred, x509_certfile,
189 x509_keyfile);
190 if (ret < 0) {
191 fprintf(stderr, "Error setting the x509 key files ('%s', '%s')\n",
192 x509_certfile, x509_keyfile);
196 if (pgp_certfile != NULL) {
197 ret =
198 gnutls_certificate_set_openpgp_key_file(xcred, pgp_certfile,
199 pgp_keyfile);
200 if (ret < 0) {
201 fprintf(stderr, "Error setting the x509 key files ('%s', '%s'\n",
202 pgp_certfile, pgp_keyfile);
206 if (pgp_keyring != NULL) {
207 ret =
208 gnutls_certificate_set_openpgp_keyring_file(xcred, pgp_keyring);
209 if (ret < 0) {
210 fprintf(stderr, "Error setting the OpenPGP keyring file\n");
214 if (pgp_trustdb != NULL) {
215 gnutls_certificate_set_openpgp_trustdb(xcred, pgp_trustdb);
217 /* gnutls_certificate_client_callback_func( xcred, cert_callback); */
219 /* SRP stuff */
220 if (srp_username!=NULL) {
221 if (gnutls_srp_allocate_client_sc(&cred) < 0) {
222 fprintf(stderr, "memory error\n");
223 exit(1);
225 gnutls_srp_set_client_cred(cred, srp_username, srp_passwd);
228 /* ANON stuff */
229 if (gnutls_anon_allocate_client_sc(&anon_cred) < 0) {
230 fprintf(stderr, "memory error\n");
231 exit(1);
234 sd = socket(AF_INET, SOCK_STREAM, 0);
235 ERR(sd, "socket");
237 memset(&sa, '\0', sizeof(sa));
238 sa.sin_family = AF_INET;
239 sa.sin_port = htons(port);
241 sa.sin_addr.s_addr = *((unsigned int *) server_host->h_addr);
243 inet_ntop(AF_INET, &sa.sin_addr, buffer, MAX_BUF);
244 fprintf(stderr, "Connecting to '%s:%d'...\n", buffer, port);
246 err = connect(sd, (SA *) & sa, sizeof(sa));
247 ERR(err, "connect");
249 for (i = 0; i < 2; i++) {
250 gnutls_init(&state, GNUTLS_CLIENT);
252 if (i == 1) {
253 gnutls_session_set_data(state, session, session_size);
254 free(session);
257 gnutls_cipher_set_priority(state, cipher_priority);
258 gnutls_compression_set_priority(state, comp_priority);
259 gnutls_kx_set_priority(state, kx_priority);
260 gnutls_protocol_set_priority(state, protocol_priority);
261 gnutls_mac_set_priority(state, mac_priority);
262 gnutls_cert_type_set_priority(state, cert_type_priority);
264 gnutls_dh_set_prime_bits(state, 1024);
266 gnutls_cred_set(state, GNUTLS_CRD_ANON, anon_cred);
267 if (srp_username!=NULL)
268 gnutls_cred_set(state, GNUTLS_CRD_SRP, cred);
269 gnutls_cred_set(state, GNUTLS_CRD_CERTIFICATE, xcred);
271 /* send the fingerprint */
272 if (fingerprint != 0)
273 gnutls_openpgp_send_key(state, GNUTLS_OPENPGP_KEY_FINGERPRINT);
275 /* use the max record size extension */
276 if (record_max_size > 0) {
277 if (gnutls_record_set_max_size(state, record_max_size) < 0) {
278 fprintf(stderr, "Cannot set the maximum record size to %d.\n",
279 record_max_size);
280 exit(1);
284 /* This TLS extension may break old implementations.
286 gnutls_transport_set_ptr(state, sd);
287 do {
288 ret = gnutls_handshake(state);
289 } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
291 if (ret < 0) {
292 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
293 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
294 alert = gnutls_alert_get(state);
295 printf("*** Received alert [%d]: %s\n",
296 alert, gnutls_alert_get_name(alert));
298 fprintf(stderr, "*** Handshake has failed\n");
299 gnutls_perror(ret);
300 gnutls_deinit(state);
301 return 1;
302 } else {
303 printf("- Handshake was completed\n");
306 if (i == 1) { /* resume */
307 /* check if we actually resumed the previous session */
309 gnutls_session_get_id(state, NULL, &tmp_session_id_size);
310 tmp_session_id = malloc(tmp_session_id_size);
311 gnutls_session_get_id(state, tmp_session_id,
312 &tmp_session_id_size);
314 if (memcmp(tmp_session_id, session_id, session_id_size) == 0) {
315 printf("- Previous session was resumed\n");
316 } else {
317 fprintf(stderr, "*** Previous session was NOT resumed\n");
319 free(tmp_session_id);
320 free(session_id);
325 if (resume != 0 && i == 0) {
327 gnutls_session_get_data(state, NULL, &session_size);
328 session = malloc(session_size);
329 gnutls_session_get_data(state, session, &session_size);
331 gnutls_session_get_id(state, NULL, &session_id_size);
332 session_id = malloc(session_id_size);
333 gnutls_session_get_id(state, session_id, &session_id_size);
335 /* print some information */
336 print_info(state);
338 printf("- Disconnecting\n");
339 do {
340 ret = gnutls_bye(state, GNUTLS_SHUT_RDWR);
341 } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
343 shutdown(sd, SHUT_WR);
344 close(sd);
346 gnutls_deinit(state);
348 printf
349 ("\n\n- Connecting again- trying to resume previous session\n");
350 sd = socket(AF_INET, SOCK_STREAM, 0);
351 ERR(sd, "socket");
353 err = connect(sd, (SA *) & sa, sizeof(sa));
354 ERR(err, "connect");
355 } else {
356 break;
361 /* print some information */
362 print_info(state);
364 printf("\n- Simple Client Mode:\n\n");
366 FD_ZERO(&rset);
367 for (;;) {
368 FD_SET(fileno(stdin), &rset);
369 FD_SET(sd, &rset);
371 maxfd = MAX(fileno(stdin), sd);
372 tv.tv_sec = 3;
373 tv.tv_usec = 0;
374 select(maxfd + 1, &rset, NULL, NULL, &tv);
376 if (FD_ISSET(sd, &rset)) {
377 bzero(buffer, MAX_BUF + 1);
378 do {
379 ret = gnutls_record_recv(state, buffer, MAX_BUF);
380 } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
381 /* remove new line */
383 if (gnutls_error_is_fatal(ret) == 1 || ret == 0) {
384 if (ret == 0) {
385 printf("- Peer has closed the GNUTLS connection\n");
386 break;
387 } else {
388 fprintf(stderr,
389 "*** Received corrupted data(%d) - server has terminated the connection abnormally\n",
390 ret);
391 break;
393 } else {
394 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
395 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
396 printf("* Received alert [%d]\n", gnutls_alert_get(state));
397 if (ret == GNUTLS_E_REHANDSHAKE) {
398 /* There is a race condition here. If application
399 * data is sent after the rehandshake request,
400 * the server thinks we ignored his request.
401 * This is a bad design of this client.
403 printf("* Received rehandshake request\n");
404 /* gnutls_alert_send( state, GNUTLS_AL_WARNING, GNUTLS_A_NO_RENEGOTIATION); */
406 do {
407 ret = gnutls_handshake(state);
408 } while (ret == GNUTLS_E_AGAIN
409 || ret == GNUTLS_E_INTERRUPTED);
411 if (ret == 0) {
412 printf("* Rehandshake was performed\n");
413 } else {
414 printf("* Rehandshake Failed [%d]\n", ret);
417 if (ret > 0) {
418 printf("- Received[%d]: ", ret);
419 for (ii = 0; ii < ret; ii++) {
420 fputc(buffer[ii], stdout);
422 fputs("\n", stdout);
425 if (user_term != 0)
426 break;
429 if (FD_ISSET(fileno(stdin), &rset)) {
430 if (fgets(buffer, MAX_BUF, stdin) == NULL) {
431 do {
432 ret = gnutls_bye(state, GNUTLS_SHUT_WR);
433 } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
434 user_term = 1;
435 continue;
437 do {
438 ret = gnutls_record_send(state, buffer, strlen(buffer));
439 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
440 if (ret > 0)
441 printf("- Sent: %d bytes\n", ret);
442 else
443 GERR(ret);
447 if (user_term != 0)
449 ret = gnutls_bye(state, GNUTLS_SHUT_RDWR);
450 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
452 shutdown(sd, SHUT_RDWR); /* no more receptions */
453 close(sd);
455 gnutls_deinit(state);
457 if (srp_username!=NULL)
458 gnutls_srp_free_client_sc(cred);
459 gnutls_certificate_free_sc(xcred);
460 gnutls_anon_free_client_sc(anon_cred);
462 gnutls_global_deinit();
464 return 0;
467 #undef DEBUG
469 static gaainfo info;
470 void gaa_parser(int argc, char **argv)
472 int i, j;
474 if (gaa(argc, argv, &info) != -1) {
475 fprintf(stderr,
476 "Error in the arguments. Use the --help or -h parameters to get more information.\n");
477 exit(1);
480 resume = info.resume;
481 port = info.port;
482 record_max_size = info.record_size;
483 fingerprint = info.fingerprint;
485 #ifdef DEBUG
486 if (info.x509_certfile != NULL)
487 x509_certfile = info.x509_certfile;
488 else
489 x509_certfile = DEFAULT_X509_CERTFILE;
491 if (info.x509_keyfile != NULL)
492 x509_keyfile = info.x509_keyfile;
493 else
494 x509_keyfile = DEFAULT_X509_KEYFILE;
496 if (info.x509_cafile != NULL)
497 x509_cafile = info.x509_certfile;
498 else
499 x509_cafile = DEFAULT_X509_CAFILE;
501 if (info.pgp_certfile != NULL)
502 pgp_certfile = info.pgp_certfile;
503 else
504 pgp_certfile = DEFAULT_PGP_CERTFILE;
506 if (info.pgp_keyfile != NULL)
507 pgp_keyfile = info.pgp_keyfile;
508 else
509 pgp_keyfile = DEFAULT_PGP_KEYFILE;
511 if (info.srp_passwd != NULL)
512 srp_passwd = info.srp_passwd;
513 else
514 srp_passwd = DEFAULT_SRP_PASSWD;
516 if (info.srp_username != NULL)
517 srp_username = info.srp_username;
518 else
519 srp_username = DEFAULT_SRP_USERNAME;
520 #else
521 srp_username = info.srp_username;
522 srp_passwd = info.srp_passwd;
523 x509_cafile = info.x509_certfile;
524 x509_keyfile = info.x509_keyfile;
525 x509_certfile = info.x509_certfile;
526 pgp_keyfile = info.pgp_keyfile;
527 pgp_certfile = info.pgp_certfile;
529 #endif
531 pgp_keyring = info.pgp_keyring;
532 pgp_trustdb = info.pgp_trustdb;
534 if (info.nrest_args == 0)
535 hostname = "localhost";
536 else
537 hostname = info.rest_args[0];
539 if (info.proto != NULL && info.nproto > 0) {
540 for (j = i = 0; i < info.nproto; i++) {
541 if (strncasecmp(info.proto[i], "SSL", 3) == 0)
542 protocol_priority[j++] = GNUTLS_SSL3;
543 if (strncasecmp(info.proto[i], "TLS", 3) == 0)
544 protocol_priority[j++] = GNUTLS_TLS1;
546 protocol_priority[j] = 0;
549 if (info.ciphers != NULL && info.nciphers > 0) {
550 for (j = i = 0; i < info.nciphers; i++) {
551 if (strncasecmp(info.ciphers[i], "RIJ", 3) == 0)
552 cipher_priority[j++] = GNUTLS_CIPHER_RIJNDAEL_128_CBC;
553 if (strncasecmp(info.ciphers[i], "TWO", 3) == 0)
554 cipher_priority[j++] = GNUTLS_CIPHER_TWOFISH_128_CBC;
555 if (strncasecmp(info.ciphers[i], "3DE", 3) == 0)
556 cipher_priority[j++] = GNUTLS_CIPHER_3DES_CBC;
557 if (strncasecmp(info.ciphers[i], "ARC", 3) == 0)
558 cipher_priority[j++] = GNUTLS_CIPHER_ARCFOUR;
560 cipher_priority[j] = 0;
563 if (info.macs != NULL && info.nmacs > 0) {
564 for (j = i = 0; i < info.nmacs; i++) {
565 if (strncasecmp(info.macs[i], "MD5", 3) == 0)
566 mac_priority[j++] = GNUTLS_MAC_MD5;
567 if (strncasecmp(info.macs[i], "SHA", 3) == 0)
568 mac_priority[j++] = GNUTLS_MAC_SHA;
570 mac_priority[j] = 0;
573 if (info.ctype != NULL && info.nctype > 0) {
574 for (j = i = 0; i < info.nctype; i++) {
575 if (strncasecmp(info.ctype[i], "OPE", 3) == 0)
576 cert_type_priority[j++] = GNUTLS_CRT_OPENPGP;
577 if (strncasecmp(info.ctype[i], "X", 1) == 0)
578 cert_type_priority[j++] = GNUTLS_CRT_X509;
580 cert_type_priority[j] = 0;
583 if (info.kx != NULL && info.nkx > 0) {
584 for (j = i = 0; i < info.nkx; i++) {
585 if (strncasecmp(info.kx[i], "SRP", 3) == 0)
586 kx_priority[j++] = GNUTLS_KX_SRP;
587 if (strncasecmp(info.kx[i], "RSA", 3) == 0)
588 kx_priority[j++] = GNUTLS_KX_RSA;
589 if (strncasecmp(info.kx[i], "DHE_RSA", 7) == 0)
590 kx_priority[j++] = GNUTLS_KX_DHE_RSA;
591 if (strncasecmp(info.kx[i], "DHE_DSS", 7) == 0)
592 kx_priority[j++] = GNUTLS_KX_DHE_DSS;
593 if (strncasecmp(info.kx[i], "ANON", 4) == 0)
594 kx_priority[j++] = GNUTLS_KX_ANON_DH;
596 kx_priority[j] = 0;
599 if (info.comp != NULL && info.ncomp > 0) {
600 for (j = i = 0; i < info.ncomp; i++) {
601 if (strncasecmp(info.comp[i], "NUL", 3) == 0)
602 comp_priority[j++] = GNUTLS_COMP_NULL;
603 if (strncasecmp(info.comp[i], "ZLI", 1) == 0)
604 comp_priority[j++] = GNUTLS_COMP_ZLIB;
606 comp_priority[j] = 0;