diff options
-rw-r--r-- | src/cli-gaa.c | 127 | ||||
-rw-r--r-- | src/cli-gaa.h | 58 | ||||
-rw-r--r-- | src/cli.c | 432 | ||||
-rw-r--r-- | src/cli.gaa | 5 |
4 files changed, 366 insertions, 256 deletions
diff --git a/src/cli-gaa.c b/src/cli-gaa.c index 33136f98e5..114dbded8c 100644 --- a/src/cli-gaa.c +++ b/src/cli-gaa.c @@ -128,6 +128,7 @@ void gaa_help(void) { printf("GNU TLS test client\nUsage: gnutls-cli [options] hostname\n\n\n"); __gaa_helpsingle('r', "resume", "", "Connect, establish a session. Connect again and resume this session."); + __gaa_helpsingle('s', "starttls", "", "Connect, establish a plain session and start TLS when EOF is sent."); __gaa_helpsingle(0, "crlf", "", "Send CR LF instead of LF."); __gaa_helpsingle(0, "x509fmtder", "", "Use DER format for certificates"); __gaa_helpsingle('f', "fingerprint", "", "Send the openpgp fingerprint, instead of the key."); @@ -166,62 +167,64 @@ typedef struct _gaainfo gaainfo; struct _gaainfo { -#line 92 "cli.gaa" +#line 95 "cli.gaa" char **rest_args; -#line 91 "cli.gaa" +#line 94 "cli.gaa" int nrest_args; -#line 81 "cli.gaa" +#line 84 "cli.gaa" char *srp_passwd; -#line 78 "cli.gaa" +#line 81 "cli.gaa" char *srp_username; -#line 75 "cli.gaa" +#line 78 "cli.gaa" char *x509_certfile; -#line 72 "cli.gaa" +#line 75 "cli.gaa" char *x509_keyfile; -#line 69 "cli.gaa" +#line 72 "cli.gaa" char *pgp_certfile; -#line 66 "cli.gaa" +#line 69 "cli.gaa" char *pgp_trustdb; -#line 63 "cli.gaa" +#line 66 "cli.gaa" char *pgp_keyring; -#line 60 "cli.gaa" +#line 63 "cli.gaa" char *pgp_keyfile; -#line 57 "cli.gaa" +#line 60 "cli.gaa" char *x509_cafile; -#line 54 "cli.gaa" +#line 57 "cli.gaa" char **ctype; -#line 53 "cli.gaa" +#line 56 "cli.gaa" int nctype; -#line 50 "cli.gaa" +#line 53 "cli.gaa" char **kx; -#line 49 "cli.gaa" +#line 52 "cli.gaa" int nkx; -#line 46 "cli.gaa" +#line 49 "cli.gaa" char **macs; -#line 45 "cli.gaa" +#line 48 "cli.gaa" int nmacs; -#line 42 "cli.gaa" +#line 45 "cli.gaa" char **comp; -#line 41 "cli.gaa" +#line 44 "cli.gaa" int ncomp; -#line 38 "cli.gaa" +#line 41 "cli.gaa" char **proto; -#line 37 "cli.gaa" +#line 40 "cli.gaa" int nproto; -#line 34 "cli.gaa" +#line 37 "cli.gaa" char **ciphers; -#line 33 "cli.gaa" +#line 36 "cli.gaa" int nciphers; -#line 29 "cli.gaa" +#line 32 "cli.gaa" int record_size; -#line 26 "cli.gaa" +#line 29 "cli.gaa" int port; -#line 23 "cli.gaa" +#line 26 "cli.gaa" int fingerprint; -#line 20 "cli.gaa" +#line 23 "cli.gaa" int fmtder; -#line 17 "cli.gaa" +#line 20 "cli.gaa" int crlf; +#line 17 "cli.gaa" + int starttls; #line 14 "cli.gaa" int resume; @@ -278,7 +281,7 @@ int gaa_error = 0; #define GAA_MULTIPLE_OPTION 3 #define GAA_REST 0 -#define GAA_NB_OPTION 25 +#define GAA_NB_OPTION 26 #define GAAOPTID_copyright 1 #define GAAOPTID_version 2 #define GAAOPTID_help 3 @@ -303,7 +306,8 @@ int gaa_error = 0; #define GAAOPTID_fingerprint 22 #define GAAOPTID_x509fmtder 23 #define GAAOPTID_crlf 24 -#define GAAOPTID_resume 25 +#define GAAOPTID_starttls 25 +#define GAAOPTID_resume 26 #line 168 "gaa.skel" @@ -654,6 +658,7 @@ int gaa_get_option_num(char *str, int status) GAA_CHECK1STR("f", GAAOPTID_fingerprint); GAA_CHECK1STR("", GAAOPTID_x509fmtder); GAA_CHECK1STR("", GAAOPTID_crlf); + GAA_CHECK1STR("s", GAAOPTID_starttls); GAA_CHECK1STR("r", GAAOPTID_resume); #line 277 "gaa.skel" @@ -683,6 +688,7 @@ int gaa_get_option_num(char *str, int status) GAA_CHECKSTR("fingerprint", GAAOPTID_fingerprint); GAA_CHECKSTR("x509fmtder", GAAOPTID_x509fmtder); GAA_CHECKSTR("crlf", GAAOPTID_crlf); + GAA_CHECKSTR("starttls", GAAOPTID_starttls); GAA_CHECKSTR("resume", GAAOPTID_resume); #line 281 "gaa.skel" @@ -735,28 +741,28 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) { case GAAOPTID_copyright: OK = 0; -#line 89 "cli.gaa" +#line 92 "cli.gaa" { print_license(); exit(0); ;}; return GAA_OK; break; case GAAOPTID_version: OK = 0; -#line 88 "cli.gaa" +#line 91 "cli.gaa" { cli_version(); exit(0); ;}; return GAA_OK; break; case GAAOPTID_help: OK = 0; -#line 86 "cli.gaa" +#line 89 "cli.gaa" { gaa_help(); exit(0); ;}; return GAA_OK; break; case GAAOPTID_list: OK = 0; -#line 85 "cli.gaa" +#line 88 "cli.gaa" { print_list(); exit(0); ;}; return GAA_OK; @@ -766,7 +772,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_srppasswd.arg1, gaa_getstr, GAATMP_srppasswd.size1); gaa_index++; -#line 82 "cli.gaa" +#line 85 "cli.gaa" { gaaval->srp_passwd = GAATMP_srppasswd.arg1 ;}; return GAA_OK; @@ -776,7 +782,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_srpusername.arg1, gaa_getstr, GAATMP_srpusername.size1); gaa_index++; -#line 79 "cli.gaa" +#line 82 "cli.gaa" { gaaval->srp_username = GAATMP_srpusername.arg1 ;}; return GAA_OK; @@ -786,7 +792,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_x509certfile.arg1, gaa_getstr, GAATMP_x509certfile.size1); gaa_index++; -#line 76 "cli.gaa" +#line 79 "cli.gaa" { gaaval->x509_certfile = GAATMP_x509certfile.arg1 ;}; return GAA_OK; @@ -796,7 +802,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_x509keyfile.arg1, gaa_getstr, GAATMP_x509keyfile.size1); gaa_index++; -#line 73 "cli.gaa" +#line 76 "cli.gaa" { gaaval->x509_keyfile = GAATMP_x509keyfile.arg1 ;}; return GAA_OK; @@ -806,7 +812,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_pgpcertfile.arg1, gaa_getstr, GAATMP_pgpcertfile.size1); gaa_index++; -#line 70 "cli.gaa" +#line 73 "cli.gaa" { gaaval->pgp_certfile = GAATMP_pgpcertfile.arg1 ;}; return GAA_OK; @@ -816,7 +822,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_pgptrustdb.arg1, gaa_getstr, GAATMP_pgptrustdb.size1); gaa_index++; -#line 67 "cli.gaa" +#line 70 "cli.gaa" { gaaval->pgp_trustdb = GAATMP_pgptrustdb.arg1 ;}; return GAA_OK; @@ -826,7 +832,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_pgpkeyring.arg1, gaa_getstr, GAATMP_pgpkeyring.size1); gaa_index++; -#line 64 "cli.gaa" +#line 67 "cli.gaa" { gaaval->pgp_keyring = GAATMP_pgpkeyring.arg1 ;}; return GAA_OK; @@ -836,7 +842,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_pgpkeyfile.arg1, gaa_getstr, GAATMP_pgpkeyfile.size1); gaa_index++; -#line 61 "cli.gaa" +#line 64 "cli.gaa" { gaaval->pgp_keyfile = GAATMP_pgpkeyfile.arg1 ;}; return GAA_OK; @@ -846,7 +852,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_x509cafile.arg1, gaa_getstr, GAATMP_x509cafile.size1); gaa_index++; -#line 58 "cli.gaa" +#line 61 "cli.gaa" { gaaval->x509_cafile = GAATMP_x509cafile.arg1 ;}; return GAA_OK; @@ -854,7 +860,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) case GAAOPTID_ctypes: OK = 0; GAA_LIST_FILL(GAATMP_ctypes.arg1, gaa_getstr, char*, GAATMP_ctypes.size1); -#line 55 "cli.gaa" +#line 58 "cli.gaa" { gaaval->ctype = GAATMP_ctypes.arg1; gaaval->nctype = GAATMP_ctypes.size1 ;}; return GAA_OK; @@ -862,7 +868,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) case GAAOPTID_kx: OK = 0; GAA_LIST_FILL(GAATMP_kx.arg1, gaa_getstr, char*, GAATMP_kx.size1); -#line 51 "cli.gaa" +#line 54 "cli.gaa" { gaaval->kx = GAATMP_kx.arg1; gaaval->nkx = GAATMP_kx.size1 ;}; return GAA_OK; @@ -870,7 +876,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) case GAAOPTID_macs: OK = 0; GAA_LIST_FILL(GAATMP_macs.arg1, gaa_getstr, char*, GAATMP_macs.size1); -#line 47 "cli.gaa" +#line 50 "cli.gaa" { gaaval->macs = GAATMP_macs.arg1; gaaval->nmacs = GAATMP_macs.size1 ;}; return GAA_OK; @@ -878,7 +884,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) case GAAOPTID_comp: OK = 0; GAA_LIST_FILL(GAATMP_comp.arg1, gaa_getstr, char*, GAATMP_comp.size1); -#line 43 "cli.gaa" +#line 46 "cli.gaa" { gaaval->comp = GAATMP_comp.arg1; gaaval->ncomp = GAATMP_comp.size1 ;}; return GAA_OK; @@ -886,7 +892,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) case GAAOPTID_protocols: OK = 0; GAA_LIST_FILL(GAATMP_protocols.arg1, gaa_getstr, char*, GAATMP_protocols.size1); -#line 39 "cli.gaa" +#line 42 "cli.gaa" { gaaval->proto = GAATMP_protocols.arg1; gaaval->nproto = GAATMP_protocols.size1 ;}; return GAA_OK; @@ -894,7 +900,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) case GAAOPTID_ciphers: OK = 0; GAA_LIST_FILL(GAATMP_ciphers.arg1, gaa_getstr, char*, GAATMP_ciphers.size1); -#line 35 "cli.gaa" +#line 38 "cli.gaa" { gaaval->ciphers = GAATMP_ciphers.arg1; gaaval->nciphers = GAATMP_ciphers.size1 ;}; return GAA_OK; @@ -904,7 +910,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_recordsize.arg1, gaa_getint, GAATMP_recordsize.size1); gaa_index++; -#line 30 "cli.gaa" +#line 33 "cli.gaa" { gaaval->record_size = GAATMP_recordsize.arg1 ;}; return GAA_OK; @@ -914,32 +920,39 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) GAA_TESTMOREARGS; GAA_FILL(GAATMP_port.arg1, gaa_getint, GAATMP_port.size1); gaa_index++; -#line 27 "cli.gaa" +#line 30 "cli.gaa" { gaaval->port = GAATMP_port.arg1 ;}; return GAA_OK; break; case GAAOPTID_fingerprint: OK = 0; -#line 24 "cli.gaa" +#line 27 "cli.gaa" { gaaval->fingerprint = 1 ;}; return GAA_OK; break; case GAAOPTID_x509fmtder: OK = 0; -#line 21 "cli.gaa" +#line 24 "cli.gaa" { gaaval->fmtder = 1 ;}; return GAA_OK; break; case GAAOPTID_crlf: OK = 0; -#line 18 "cli.gaa" +#line 21 "cli.gaa" { gaaval->crlf = 1 ;}; return GAA_OK; break; + case GAAOPTID_starttls: + OK = 0; +#line 18 "cli.gaa" +{ gaaval->starttls = 1 ;}; + + return GAA_OK; + break; case GAAOPTID_resume: OK = 0; #line 15 "cli.gaa" @@ -949,7 +962,7 @@ int gaa_try(int gaa_num, int gaa_index, gaainfo *gaaval, char *opt_list) break; case GAA_REST: GAA_LIST_FILL(GAAREST_tmp.arg1, gaa_getstr, char*, GAAREST_tmp.size1); -#line 93 "cli.gaa" +#line 96 "cli.gaa" { gaaval->rest_args = GAAREST_tmp.arg1; gaaval->nrest_args = GAAREST_tmp.size1 ;}; return GAA_OK; @@ -978,14 +991,14 @@ int gaa(int argc, char **argv, gaainfo *gaaval) if(inited == 0) { -#line 95 "cli.gaa" +#line 98 "cli.gaa" { gaaval->resume=0; gaaval->port=443; gaaval->rest_args=NULL; gaaval->nrest_args=0; gaaval->ciphers=NULL; gaaval->kx=NULL; gaaval->comp=NULL; gaaval->macs=NULL; gaaval->ctype=NULL; gaaval->nciphers=0; gaaval->nkx=0; gaaval->ncomp=0; gaaval->nmacs=0; gaaval->nctype = 0; gaaval->record_size=0; gaaval->fingerprint=0; gaaval->pgp_trustdb=NULL; gaaval->pgp_keyring=NULL; gaaval->x509_cafile = NULL; gaaval->pgp_keyfile=NULL; gaaval->pgp_certfile=NULL; gaaval->x509_keyfile=NULL; gaaval->x509_certfile=NULL; gaaval->crlf = 0; - gaaval->srp_username=NULL; gaaval->srp_passwd=NULL; gaaval->fmtder = 0; ;}; + gaaval->srp_username=NULL; gaaval->srp_passwd=NULL; gaaval->fmtder = 0; gaaval->starttls =0; ;}; } inited = 1; diff --git a/src/cli-gaa.h b/src/cli-gaa.h index 16e8012e89..c773815efe 100644 --- a/src/cli-gaa.h +++ b/src/cli-gaa.h @@ -8,62 +8,64 @@ typedef struct _gaainfo gaainfo; struct _gaainfo { -#line 92 "cli.gaa" +#line 95 "cli.gaa" char **rest_args; -#line 91 "cli.gaa" +#line 94 "cli.gaa" int nrest_args; -#line 81 "cli.gaa" +#line 84 "cli.gaa" char *srp_passwd; -#line 78 "cli.gaa" +#line 81 "cli.gaa" char *srp_username; -#line 75 "cli.gaa" +#line 78 "cli.gaa" char *x509_certfile; -#line 72 "cli.gaa" +#line 75 "cli.gaa" char *x509_keyfile; -#line 69 "cli.gaa" +#line 72 "cli.gaa" char *pgp_certfile; -#line 66 "cli.gaa" +#line 69 "cli.gaa" char *pgp_trustdb; -#line 63 "cli.gaa" +#line 66 "cli.gaa" char *pgp_keyring; -#line 60 "cli.gaa" +#line 63 "cli.gaa" char *pgp_keyfile; -#line 57 "cli.gaa" +#line 60 "cli.gaa" char *x509_cafile; -#line 54 "cli.gaa" +#line 57 "cli.gaa" char **ctype; -#line 53 "cli.gaa" +#line 56 "cli.gaa" int nctype; -#line 50 "cli.gaa" +#line 53 "cli.gaa" char **kx; -#line 49 "cli.gaa" +#line 52 "cli.gaa" int nkx; -#line 46 "cli.gaa" +#line 49 "cli.gaa" char **macs; -#line 45 "cli.gaa" +#line 48 "cli.gaa" int nmacs; -#line 42 "cli.gaa" +#line 45 "cli.gaa" char **comp; -#line 41 "cli.gaa" +#line 44 "cli.gaa" int ncomp; -#line 38 "cli.gaa" +#line 41 "cli.gaa" char **proto; -#line 37 "cli.gaa" +#line 40 "cli.gaa" int nproto; -#line 34 "cli.gaa" +#line 37 "cli.gaa" char **ciphers; -#line 33 "cli.gaa" +#line 36 "cli.gaa" int nciphers; -#line 29 "cli.gaa" +#line 32 "cli.gaa" int record_size; -#line 26 "cli.gaa" +#line 29 "cli.gaa" int port; -#line 23 "cli.gaa" +#line 26 "cli.gaa" int fingerprint; -#line 20 "cli.gaa" +#line 23 "cli.gaa" int fmtder; -#line 17 "cli.gaa" +#line 20 "cli.gaa" int crlf; +#line 17 "cli.gaa" + int starttls; #line 14 "cli.gaa" int resume; @@ -49,7 +49,7 @@ #define GERR(ret) fprintf(stderr, "* Error: %s\n", gnutls_strerror(ret)) /* global stuff here */ -int resume; +int resume, starttls; char *hostname = NULL; int port; int record_max_size; @@ -69,15 +69,19 @@ char *x509_cafile; char *x509_crlfile = NULL; static int x509ctype; +static gnutls_srp_client_credentials cred; +static gnutls_anon_client_credentials anon_cred; +static gnutls_certificate_credentials xcred; int protocol_priority[16] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 }; int kx_priority[16] = { GNUTLS_KX_RSA, GNUTLS_KX_DHE_DSS, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, - /* Do not use anonymous authentication, unless you know what that means */ + /* Do not use anonymous authentication, unless you know what that means */ GNUTLS_KX_ANON_DH, GNUTLS_KX_RSA_EXPORT, 0 }; int cipher_priority[16] = - { GNUTLS_CIPHER_ARCFOUR_128, GNUTLS_CIPHER_RIJNDAEL_128_CBC, GNUTLS_CIPHER_3DES_CBC, + { GNUTLS_CIPHER_ARCFOUR_128, GNUTLS_CIPHER_RIJNDAEL_128_CBC, + GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_ARCFOUR_40, 0 }; int comp_priority[16] = { GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 }; @@ -86,6 +90,21 @@ int cert_type_priority[16] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 }; /* end of global stuff */ +/* prototypes */ +typedef struct { + int fd; + gnutls_session session; + int secure; +} socket_st; + +ssize_t socket_recv(socket_st socket, void *buffer, int buffer_size); +ssize_t socket_send(socket_st socket, void *buffer, int buffer_size); +void socket_bye(socket_st socket); +void check_rehandshake(socket_st socket, int ret); +void check_alert(socket_st socket, int ret); +int do_handshake(socket_st *socket); + + #define MAX(X,Y) (X >= Y ? X : Y); #define DEFAULT_X509_CAFILE "x509/ca.pem" #define DEFAULT_X509_KEYFILE2 "x509/clikey-dsa.pem" @@ -101,6 +120,49 @@ int cert_type_priority[16] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 }; #define DEFAULT_SRP_USERNAME "test" #define DEFAULT_SRP_PASSWD "test" +/* initializes a gnutls_session with some defaults. + */ +static gnutls_session init_tls_session(void) +{ + gnutls_session session; + + gnutls_init(&session, GNUTLS_CLIENT); + + /* allow the use of private ciphersuites. + */ + gnutls_handshake_set_private_extensions(session, 1); + + gnutls_cipher_set_priority(session, cipher_priority); + gnutls_compression_set_priority(session, comp_priority); + gnutls_kx_set_priority(session, kx_priority); + gnutls_protocol_set_priority(session, protocol_priority); + gnutls_mac_set_priority(session, mac_priority); + gnutls_certificate_type_set_priority(session, cert_type_priority); + + gnutls_dh_set_prime_bits(session, 512); + + gnutls_cred_set(session, GNUTLS_CRD_ANON, anon_cred); + if (srp_username != NULL) + gnutls_cred_set(session, GNUTLS_CRD_SRP, cred); + gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, xcred); + + /* send the fingerprint */ + if (fingerprint != 0) + gnutls_openpgp_send_key(session, GNUTLS_OPENPGP_KEY_FINGERPRINT); + + /* use the max record size extension */ + if (record_max_size > 0) { + if (gnutls_record_set_max_size(session, record_max_size) < 0) { + fprintf(stderr, + "Cannot set the maximum record size to %d.\n", + record_max_size); + exit(1); + } + } + + return session; +} + static void gaa_parser(int argc, char **argv); @@ -109,22 +171,17 @@ int main(int argc, char **argv) int err, ret; int sd, ii, i; struct sockaddr_in sa; - gnutls_session session; char buffer[MAX_BUF + 1]; char *session_data = NULL; char *session_id = NULL; int session_data_size, alert; int session_id_size; - char *tmp_session_id; - int tmp_session_id_size; fd_set rset; int maxfd; struct timeval tv; int user_term = 0; - gnutls_srp_client_credentials cred; - gnutls_anon_client_credentials anon_cred; - gnutls_certificate_credentials xcred; struct hostent *server_host; + socket_st hd; gaa_parser(argc, argv); @@ -148,31 +205,35 @@ int main(int argc, char **argv) if (x509_cafile != NULL) { ret = - gnutls_certificate_set_x509_trust_file(xcred, x509_cafile, - x509ctype); + gnutls_certificate_set_x509_trust_file(xcred, + x509_cafile, x509ctype); if (ret < 0) { fprintf(stderr, "Error setting the x509 trust file\n"); } else { - printf("Processed %d CA certificate(s).\n", ret); + printf("Processed %d CA certificate(s).\n", ret); } } if (x509_certfile != NULL) { ret = - gnutls_certificate_set_x509_key_file(xcred, x509_certfile, - x509_keyfile, x509ctype); + gnutls_certificate_set_x509_key_file(xcred, + x509_certfile, + x509_keyfile, x509ctype); if (ret < 0) { - fprintf(stderr, "Error setting the x509 key files ('%s', '%s')\n", + fprintf(stderr, + "Error setting the x509 key files ('%s', '%s')\n", x509_certfile, x509_keyfile); } } if (pgp_certfile != NULL) { ret = - gnutls_certificate_set_openpgp_key_file(xcred, pgp_certfile, + gnutls_certificate_set_openpgp_key_file(xcred, + pgp_certfile, pgp_keyfile); if (ret < 0) { - fprintf(stderr, "Error setting the x509 key files ('%s', '%s')\n", + fprintf(stderr, + "Error setting the x509 key files ('%s', '%s')\n", pgp_certfile, pgp_keyfile); } } @@ -194,13 +255,13 @@ int main(int argc, char **argv) /* gnutls_certificate_client_callback_func( xcred, cert_callback); */ /* SRP stuff */ - if (srp_username!=NULL) { + if (srp_username != NULL) { if (gnutls_srp_allocate_client_cred(&cred) < 0) { - fprintf(stderr, "SRP authentication error\n"); + fprintf(stderr, "SRP authentication error\n"); } gnutls_srp_set_client_cred(cred, srp_username, srp_passwd); } - + /* ANON stuff */ if (gnutls_anon_allocate_client_cred(&anon_cred) < 0) { fprintf(stderr, "Anonymous authentication error\n"); @@ -229,110 +290,63 @@ int main(int argc, char **argv) err = connect(sd, (SA *) & sa, sizeof(sa)); ERR(err, "connect"); + hd.secure = 0; + hd.fd = sd; + + hd.session = init_tls_session(); + if (starttls) + goto after_handshake; + for (i = 0; i < 2; i++) { - gnutls_init(&session, GNUTLS_CLIENT); - /* allow the use of private ciphersuites. - */ - gnutls_handshake_set_private_extensions( session, 1); if (i == 1) { - gnutls_session_set_data(session, session_data, session_data_size); + hd.session = init_tls_session(); + gnutls_session_set_data(hd.session, session_data, + session_data_size); free(session_data); } - gnutls_cipher_set_priority(session, cipher_priority); - gnutls_compression_set_priority(session, comp_priority); - gnutls_kx_set_priority(session, kx_priority); - gnutls_protocol_set_priority(session, protocol_priority); - gnutls_mac_set_priority(session, mac_priority); - gnutls_certificate_type_set_priority(session, cert_type_priority); - - gnutls_dh_set_prime_bits(session, 512); - - gnutls_cred_set(session, GNUTLS_CRD_ANON, anon_cred); - if (srp_username!=NULL) - gnutls_cred_set(session, GNUTLS_CRD_SRP, cred); - gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, xcred); - - /* send the fingerprint */ - if (fingerprint != 0) - gnutls_openpgp_send_key(session, GNUTLS_OPENPGP_KEY_FINGERPRINT); - - /* use the max record size extension */ - if (record_max_size > 0) { - if (gnutls_record_set_max_size(session, record_max_size) < 0) { - fprintf(stderr, "Cannot set the maximum record size to %d.\n", - record_max_size); - exit(1); - } - } - /* This TLS extension may break old implementations. */ - gnutls_transport_set_ptr(session, sd); - do { - ret = gnutls_handshake(session); - } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); + + ret = do_handshake(&hd); if (ret < 0) { if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { - alert = gnutls_alert_get(session); + alert = gnutls_alert_get(hd.session); printf("*** Received alert [%d]: %s\n", alert, gnutls_alert_get_name(alert)); } fprintf(stderr, "*** Handshake has failed\n"); gnutls_perror(ret); - gnutls_deinit(session); + gnutls_deinit(hd.session); return 1; } else { printf("- Handshake was completed\n"); - if (gnutls_session_is_resumed( session)!=0) - printf("*** This is a resumed session\n"); - } - - if (i == 1) { /* resume */ - /* check if we actually resumed the previous session */ - - gnutls_session_get_id(session, NULL, &tmp_session_id_size); - tmp_session_id = malloc(tmp_session_id_size); - gnutls_session_get_id(session, tmp_session_id, - &tmp_session_id_size); - - if (memcmp(tmp_session_id, session_id, session_id_size) == 0) { - printf("- Previous session was resumed\n"); - } else { - fprintf(stderr, "*** Previous session was NOT resumed\n"); - } - free(tmp_session_id); - free(session_id); + if (gnutls_session_is_resumed(hd.session) != 0) + printf("*** This is a resumed session\n"); } if (resume != 0 && i == 0) { - gnutls_session_get_data(session, NULL, &session_data_size); + gnutls_session_get_data(hd.session, NULL, &session_data_size); session_data = malloc(session_data_size); - gnutls_session_get_data(session, session_data, &session_data_size); + gnutls_session_get_data(hd.session, session_data, + &session_data_size); - gnutls_session_get_id(session, NULL, &session_id_size); + gnutls_session_get_id(hd.session, NULL, &session_id_size); session_id = malloc(session_id_size); - gnutls_session_get_id(session, session_id, &session_id_size); + gnutls_session_get_id(hd.session, session_id, &session_id_size); /* print some information */ - print_info(session); + print_info(hd.session); printf("- Disconnecting\n"); - do { - ret = gnutls_bye(session, GNUTLS_SHUT_RDWR); - } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); - - shutdown(sd, SHUT_WR); - close(sd); - - gnutls_deinit(session); + socket_bye(hd); printf ("\n\n- Connecting again- trying to resume previous session\n"); @@ -347,7 +361,9 @@ int main(int argc, char **argv) } /* print some information */ - print_info(session); + print_info(hd.session); + + after_handshake: printf("\n- Simple Client Mode:\n\n"); @@ -363,92 +379,68 @@ int main(int argc, char **argv) if (FD_ISSET(sd, &rset)) { bzero(buffer, MAX_BUF + 1); - do { - ret = gnutls_record_recv(session, buffer, MAX_BUF); - } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); - /* remove new line */ - - if (gnutls_error_is_fatal(ret) == 1 || ret == 0) { - if (ret == 0) { - printf("- Peer has closed the GNUTLS connection\n"); - break; - } else { - fprintf(stderr, - "*** Received corrupted data(%d) - server has terminated the connection abnormally\n", - ret); - break; - } - } else { - if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED - || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) - printf("* Received alert [%d]\n", gnutls_alert_get(session)); - if (ret == GNUTLS_E_REHANDSHAKE) { - /* There is a race condition here. If application - * data is sent after the rehandshake request, - * the server thinks we ignored his request. - * This is a bad design of this client. - */ - printf("* Received rehandshake request\n"); - /* gnutls_alert_send( session, GNUTLS_AL_WARNING, GNUTLS_A_NO_RENEGOTIATION); */ - - do { - ret = gnutls_handshake(session); - } while (ret == GNUTLS_E_AGAIN - || ret == GNUTLS_E_INTERRUPTED); - - if (ret == 0) { - printf("* Rehandshake was performed\n"); - } else { - printf("* Rehandshake Failed [%d]\n", ret); - } - } - if (ret > 0) { - if (quiet!=0) printf("- Received[%d]: ", ret); - for (ii = 0; ii < ret; ii++) { - fputc(buffer[ii], stdout); - } - fputs("\n", stdout); + ret = socket_recv(hd, buffer, MAX_BUF); + + if (ret == 0) { + printf("- Peer has closed the GNUTLS connection\n"); + break; + } else if (ret < 0) { + fprintf(stderr, + "*** Received corrupted data(%d) - server has terminated the connection abnormally\n", + ret); + break; + } else if (ret > 0) { + if (quiet != 0) + printf("- Received[%d]: ", ret); + for (ii = 0; ii < ret; ii++) { + fputc(buffer[ii], stdout); } } + if (user_term != 0) break; } if (FD_ISSET(fileno(stdin), &rset)) { if (fgets(buffer, MAX_BUF, stdin) == NULL) { - do { - ret = gnutls_bye(session, GNUTLS_SHUT_WR); - } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); - user_term = 1; - continue; - } - do { - if ( crlf != 0) { - char* b=strchr( buffer, '\n'); - if (b!=NULL) - strcpy( b, "\r\n"); + if (hd.secure == 0) { + fprintf(stderr, "*** Starting TLS handshake\n"); + ret = do_handshake(&hd); + if (ret < 0) { + fprintf(stderr, "*** Handshake has failed\n"); + gnutls_perror(ret); + gnutls_deinit(hd.session); + } + continue; + } else { + socket_bye(hd); + user_term = 1; + continue; } - - ret = gnutls_record_send(session, buffer, strlen(buffer)); - } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + } + + if (crlf != 0) { + char *b = strchr(buffer, '\n'); + if (b != NULL) + strcpy(b, "\r\n"); + } + + ret = socket_send(hd, buffer, strlen(buffer)); + if (ret > 0) { - if (quiet!=0) printf("- Sent: %d bytes\n", ret); + if (quiet != 0) + printf("- Sent: %d bytes\n", ret); } else GERR(ret); } } - if (user_term != 0) - do - ret = gnutls_bye(session, GNUTLS_SHUT_RDWR); - while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); - shutdown(sd, SHUT_RDWR); /* no more receptions */ - close(sd); + if (user_term != 0) + socket_bye(hd); - gnutls_deinit(session); - if (srp_username!=NULL) + if (srp_username != NULL) gnutls_srp_free_client_cred(cred); gnutls_certificate_free_cred(xcred); gnutls_anon_free_client_cred(anon_cred); @@ -471,6 +463,7 @@ void gaa_parser(int argc, char **argv) exit(1); } + starttls = info.starttls; resume = info.resume; port = info.port; record_max_size = info.record_size; @@ -517,19 +510,19 @@ void gaa_parser(int argc, char **argv) else srp_username = DEFAULT_SRP_USERNAME; #else - srp_username = info.srp_username; - srp_passwd = info.srp_passwd; - x509_cafile = info.x509_cafile; - x509_keyfile = info.x509_keyfile; - x509_certfile = info.x509_certfile; - pgp_keyfile = info.pgp_keyfile; - pgp_certfile = info.pgp_certfile; + srp_username = info.srp_username; + srp_passwd = info.srp_passwd; + x509_cafile = info.x509_cafile; + x509_keyfile = info.x509_keyfile; + x509_certfile = info.x509_certfile; + pgp_keyfile = info.pgp_keyfile; + pgp_certfile = info.pgp_certfile; #endif pgp_keyring = info.pgp_keyring; pgp_trustdb = info.pgp_trustdb; - + crlf = info.crlf; if (info.nrest_args == 0) @@ -617,7 +610,106 @@ void gaa_parser(int argc, char **argv) } -void cli_version(void) { - fprintf(stderr, "GNU TLS test client, "); - fprintf(stderr, "version %s.\n", LIBGNUTLS_VERSION); +void cli_version(void) +{ + fprintf(stderr, "GNU TLS test client, "); + fprintf(stderr, "version %s.\n", LIBGNUTLS_VERSION); +} + + + +/* Functions to manipulate sockets + */ + +ssize_t socket_recv(socket_st socket, void *buffer, int buffer_size) +{ + int ret; + + if (socket.secure) + do { + ret = gnutls_record_recv(socket.session, buffer, buffer_size); + } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); + else + do { + ret = recv(socket.fd, buffer, buffer_size, 0); + } while (ret == -1 && errno == EINTR); + + return ret; +} + +ssize_t socket_send(socket_st socket, void *buffer, int buffer_size) +{ + int ret; + + if (socket.secure) + do { + ret = gnutls_record_send(socket.session, buffer, strlen(buffer)); + } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + else + do { + ret = send(socket.fd, buffer, strlen(buffer), 0); + } while (ret == -1 && errno == EINTR); + + + return ret; +} + +void socket_bye(socket_st socket) +{ + int ret; + + if (socket.secure) { + do + ret = gnutls_bye(socket.session, GNUTLS_SHUT_RDWR); + while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); + gnutls_deinit(socket.session); + } + + shutdown(socket.fd, SHUT_RDWR); /* no more receptions */ + close(socket.fd); +} + +void check_rehandshake(socket_st socket, int ret) +{ + if (socket.secure && ret == GNUTLS_E_REHANDSHAKE) { + /* There is a race condition here. If application + * data is sent after the rehandshake request, + * the server thinks we ignored his request. + * This is a bad design of this client. + */ + printf("* Received rehandshake request\n"); + /* gnutls_alert_send( session, GNUTLS_AL_WARNING, GNUTLS_A_NO_RENEGOTIATION); */ + + do { + ret = gnutls_handshake(socket.session); + } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); + + if (ret == 0) { + printf("* Rehandshake was performed\n"); + } else { + printf("* Rehandshake Failed [%d]\n", ret); + } + } +} + +void check_alert(socket_st socket, int ret) +{ + if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED + || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { + printf("* Received alert [%d]\n", gnutls_alert_get(socket.session)); + + check_rehandshake(socket, ret); + } +} + +int do_handshake(socket_st* socket) +{ + int ret; + gnutls_transport_set_ptr(socket->session, socket->fd); + do { + ret = gnutls_handshake(socket->session); + } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); + + socket->secure = 1; + return ret; } diff --git a/src/cli.gaa b/src/cli.gaa index deb557479b..0916057fb0 100644 --- a/src/cli.gaa +++ b/src/cli.gaa @@ -14,6 +14,9 @@ helpnode "GNU TLS test client\nUsage: gnutls-cli [options] hostname\n\n" #int resume; option (r, resume) { $resume = 1 } "Connect, establish a session. Connect again and resume this session." +#int starttls; +option (s, starttls) { $starttls = 1 } "Connect, establish a plain session and start TLS when EOF is sent." + #int crlf; option (crlf) { $crlf = 1 } "Send CR LF instead of LF." @@ -98,6 +101,6 @@ init { $resume=0; $port=443; $rest_args=NULL; $nrest_args=0; $ciphers=NULL; $fingerprint=0; $pgp_trustdb=NULL; $pgp_keyring=NULL; $x509_cafile = NULL; $pgp_keyfile=NULL; $pgp_certfile=NULL; $x509_keyfile=NULL; $x509_certfile=NULL; $crlf = 0; - $srp_username=NULL; $srp_passwd=NULL; $fmtder = 0; } + $srp_username=NULL; $srp_passwd=NULL; $fmtder = 0; $starttls =0; } |