X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=apps%2Fs_client.c;h=683169aa687d70d513b881ddde18f980f1cc4111;hp=b5c044bfa710b982304f8069a3b0c10ca13db0f8;hb=4f7a2ab8b15c1d1aed748e3d580a38a93760a517;hpb=b1277b99027dbb086fa01ecfe3c3a36825ca64ac diff --git a/apps/s_client.c b/apps/s_client.c index b5c044bfa7..683169aa68 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -108,8 +108,35 @@ * Hudson (tjh@cryptsoft.com). * */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ #include +#include #include #include #include @@ -134,6 +161,11 @@ typedef unsigned int u_int; #include #include #include +#include +#include +#ifndef OPENSSL_NO_SRP +#include +#endif #include "s_apps.h" #include "timeouts.h" @@ -142,6 +174,10 @@ typedef unsigned int u_int; #undef FIONBIO #endif +#if defined(OPENSSL_SYS_BEOS_R5) +#include +#endif + #undef PROG #define PROG s_client_main @@ -156,21 +192,92 @@ typedef unsigned int u_int; extern int verify_depth; extern int verify_error; +extern int verify_return_error; #ifdef FIONBIO static int c_nbio=0; #endif static int c_Pause=0; static int c_debug=0; +#ifndef OPENSSL_NO_TLSEXT +static int c_tlsextdebug=0; +static int c_status_req=0; +#endif static int c_msg=0; static int c_showcerts=0; static void sc_usage(void); static void print_stuff(BIO *berr,SSL *con,int full); +#ifndef OPENSSL_NO_TLSEXT +static int ocsp_resp_cb(SSL *s, void *arg); +#endif static BIO *bio_c_out=NULL; static int c_quiet=0; static int c_ign_eof=0; +#ifndef OPENSSL_NO_PSK +/* Default PSK identity and key */ +static char *psk_identity="Client_identity"; +/*char *psk_key=NULL; by default PSK is not used */ + +static unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity, + unsigned int max_identity_len, unsigned char *psk, + unsigned int max_psk_len) + { + unsigned int psk_len = 0; + int ret; + BIGNUM *bn=NULL; + + if (c_debug) + BIO_printf(bio_c_out, "psk_client_cb\n"); + if (!hint) + { + /* no ServerKeyExchange message*/ + if (c_debug) + BIO_printf(bio_c_out,"NULL received PSK identity hint, continuing anyway\n"); + } + else if (c_debug) + BIO_printf(bio_c_out, "Received PSK identity hint '%s'\n", hint); + + /* lookup PSK identity and PSK key based on the given identity hint here */ + ret = BIO_snprintf(identity, max_identity_len, "%s", psk_identity); + if (ret < 0 || (unsigned int)ret > max_identity_len) + goto out_err; + if (c_debug) + BIO_printf(bio_c_out, "created identity '%s' len=%d\n", identity, ret); + ret=BN_hex2bn(&bn, psk_key); + if (!ret) + { + BIO_printf(bio_err,"Could not convert PSK key '%s' to BIGNUM\n", psk_key); + if (bn) + BN_free(bn); + return 0; + } + + if ((unsigned int)BN_num_bytes(bn) > max_psk_len) + { + BIO_printf(bio_err,"psk buffer of callback is too small (%d) for key (%d)\n", + max_psk_len, BN_num_bytes(bn)); + BN_free(bn); + return 0; + } + + psk_len=BN_bn2bin(bn, psk); + BN_free(bn); + if (psk_len == 0) + goto out_err; + + if (c_debug) + BIO_printf(bio_c_out, "created PSK len=%d\n", psk_len); + + return psk_len; + out_err: + if (c_debug) + BIO_printf(bio_err, "Error in PSK client callback\n"); + return 0; + } +#endif + static void sc_usage(void) { BIO_printf(bio_err,"usage: s_client args\n"); @@ -204,12 +311,29 @@ static void sc_usage(void) BIO_printf(bio_err," -crlf - convert LF from terminal into CRLF\n"); BIO_printf(bio_err," -quiet - no s_client output\n"); BIO_printf(bio_err," -ign_eof - ignore input eof (default when -quiet)\n"); + BIO_printf(bio_err," -no_ign_eof - don't ignore input eof\n"); +#ifndef OPENSSL_NO_PSK + BIO_printf(bio_err," -psk_identity arg - PSK identity\n"); + BIO_printf(bio_err," -psk arg - PSK in hex (without 0x)\n"); +# ifndef OPENSSL_NO_JPAKE + BIO_printf(bio_err," -jpake arg - JPAKE secret to use\n"); +# endif +#endif +#ifndef OPENSSL_NO_SRP + BIO_printf(bio_err," -srpuser user - SRP authentification for 'user'\n"); + BIO_printf(bio_err," -srppass arg - password for 'user'\n"); + BIO_printf(bio_err," -srp_lateuser - SRP username into second ClientHello message\n"); + BIO_printf(bio_err," -srp_moregroups - Tolerate other than the known g N values.\n"); + BIO_printf(bio_err," -srp_strength int - minimal mength in bits for N (default %d).\n",SRP_MINIMAL_N); +#endif BIO_printf(bio_err," -ssl2 - just use SSLv2\n"); BIO_printf(bio_err," -ssl3 - just use SSLv3\n"); + BIO_printf(bio_err," -tls1_2 - just use TLSv1.2\n"); + BIO_printf(bio_err," -tls1_1 - just use TLSv1.1\n"); BIO_printf(bio_err," -tls1 - just use TLSv1\n"); BIO_printf(bio_err," -dtls1 - just use DTLSv1\n"); - BIO_printf(bio_err," -mtu - set the MTU\n"); - BIO_printf(bio_err," -no_tls1/-no_ssl3/-no_ssl2 - turn off that protocol\n"); + BIO_printf(bio_err," -mtu - set the link layer MTU\n"); + BIO_printf(bio_err," -no_tls1_2/-no_tls1_1/-no_tls1/-no_ssl3/-no_ssl2 - turn off that protocol\n"); BIO_printf(bio_err," -bugs - Switch on all SSL implementation bug workarounds\n"); BIO_printf(bio_err," -serverpref - Use server's cipher preferences (only SSLv2)\n"); BIO_printf(bio_err," -cipher - preferred cipher to use, use the 'openssl ciphers'\n"); @@ -217,14 +341,24 @@ static void sc_usage(void) BIO_printf(bio_err," -starttls prot - use the STARTTLS command before starting TLS\n"); BIO_printf(bio_err," for those protocols that support it, where\n"); BIO_printf(bio_err," 'prot' defines which one to assume. Currently,\n"); - BIO_printf(bio_err," only \"smtp\" and \"pop3\" are supported.\n"); + BIO_printf(bio_err," only \"smtp\", \"pop3\", \"imap\", \"ftp\" and \"xmpp\"\n"); + BIO_printf(bio_err," are supported.\n"); #ifndef OPENSSL_NO_ENGINE BIO_printf(bio_err," -engine id - Initialise and use the specified engine\n"); #endif BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR); + BIO_printf(bio_err," -sess_out arg - file to write SSL session to\n"); + BIO_printf(bio_err," -sess_in arg - file to read SSL session from\n"); #ifndef OPENSSL_NO_TLSEXT BIO_printf(bio_err," -servername host - Set TLS extension servername in ClientHello\n"); + BIO_printf(bio_err," -tlsextdebug - hex dump of all TLS extensions received\n"); + BIO_printf(bio_err," -status - request certificate status from server\n"); + BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n"); +# ifndef OPENSSL_NO_NEXTPROTONEG + BIO_printf(bio_err," -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list)\n"); +# endif #endif + BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n"); } #ifndef OPENSSL_NO_TLSEXT @@ -239,23 +373,175 @@ typedef struct tlsextctx_st { static int MS_CALLBACK ssl_servername_cb(SSL *s, int *ad, void *arg) { tlsextctx * p = (tlsextctx *) arg; - const unsigned char * hn= SSL_get_servername(s, TLSEXT_TYPE_SERVER_host); + const char * hn= SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); if (SSL_get_servername_type(s) != -1) p->ack = !SSL_session_reused(s) && hn != NULL; else - BIO_printf(bio_err,"SSL_get_tlsext_hostname does not work\n"); + BIO_printf(bio_err,"Can't use SSL_get_servername\n"); - return SSL_ERROR_NONE; + return SSL_TLSEXT_ERR_OK; + } + +#ifndef OPENSSL_NO_SRP + +/* This is a context that we pass to all callbacks */ +typedef struct srp_arg_st + { + char *srppassin; + char *srplogin; + int msg; /* copy from c_msg */ + int debug; /* copy from c_debug */ + int amp; /* allow more groups */ + int strength /* minimal size for N */ ; + } SRP_ARG; + +#define SRP_NUMBER_ITERATIONS_FOR_PRIME 64 + +static int SRP_Verify_N_and_g(const BIGNUM *N, const BIGNUM *g) + { + BN_CTX *bn_ctx = BN_CTX_new(); + BIGNUM *p = BN_new(); + BIGNUM *r = BN_new(); + int ret = + g != NULL && N != NULL && bn_ctx != NULL && BN_is_odd(N) && + BN_is_prime_ex(N,SRP_NUMBER_ITERATIONS_FOR_PRIME,bn_ctx,NULL) && + p != NULL && BN_rshift1(p, N) && + + /* p = (N-1)/2 */ + BN_is_prime_ex(p,SRP_NUMBER_ITERATIONS_FOR_PRIME,bn_ctx,NULL) && + r != NULL && + + /* verify g^((N-1)/2) == -1 (mod N) */ + BN_mod_exp(r, g, p, N, bn_ctx) && + BN_add_word(r, 1) && + BN_cmp(r, N) == 0; + + if(r) + BN_free(r); + if(p) + BN_free(p); + if(bn_ctx) + BN_CTX_free(bn_ctx); + return ret; + } + +static int MS_CALLBACK ssl_srp_verify_param_cb(SSL *s, void *arg) + { + SRP_ARG *srp_arg = (SRP_ARG *)arg; + BIGNUM *N = NULL, *g = NULL; + if (!(N = SSL_get_srp_N(s)) || !(g = SSL_get_srp_g(s))) + return 0; + if (srp_arg->debug || srp_arg->msg || srp_arg->amp == 1) + { + BIO_printf(bio_err, "SRP parameters:\n"); + BIO_printf(bio_err,"\tN="); BN_print(bio_err,N); + BIO_printf(bio_err,"\n\tg="); BN_print(bio_err,g); + BIO_printf(bio_err,"\n"); + } + + if (SRP_check_known_gN_param(g,N)) + return 1; + + if (srp_arg->amp == 1) + { + if (srp_arg->debug) + BIO_printf(bio_err, "SRP param N and g are not known params, going to check deeper.\n"); + +/* The srp_moregroups must be used with caution, testing primes costs time. + Implementors should rather add the value to the known ones. + The minimal size has already been tested. +*/ + if (BN_num_bits(g) <= BN_BITS && SRP_Verify_N_and_g(N,g)) + return 1; + } + BIO_printf(bio_err, "SRP param N and g rejected.\n"); + return 0; } + +#define PWD_STRLEN 1024 + +static char * MS_CALLBACK ssl_give_srp_client_pwd_cb(SSL *s, void *arg) + { + SRP_ARG *srp_arg = (SRP_ARG *)arg; + char *pass = (char *)OPENSSL_malloc(PWD_STRLEN+1); + PW_CB_DATA cb_tmp; + int l; + + cb_tmp.password = (char *)srp_arg->srppassin; + cb_tmp.prompt_info = "SRP user"; + if ((l = password_callback(pass, PWD_STRLEN, 0, &cb_tmp))<0) + { + BIO_printf (bio_err, "Can't read Password\n"); + OPENSSL_free(pass); + return NULL; + } + *(pass+l)= '\0'; + + return pass; + } + +static char * MS_CALLBACK missing_srp_username_callback(SSL *s, void *arg) + { + SRP_ARG *srp_arg = (SRP_ARG *)arg; + return BUF_strdup(srp_arg->srplogin); + } + #endif +# ifndef OPENSSL_NO_NEXTPROTONEG +/* This the context that we pass to next_proto_cb */ +typedef struct tlsextnextprotoctx_st { + unsigned char *data; + unsigned short len; + int status; +} tlsextnextprotoctx; + +static tlsextnextprotoctx next_proto; + +static int next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) + { + tlsextnextprotoctx *ctx = arg; + + if (!c_quiet) + { + /* We can assume that |in| is syntactically valid. */ + unsigned i; + BIO_printf(bio_c_out, "Protocols advertised by server: "); + for (i = 0; i < inlen; ) + { + if (i) + BIO_write(bio_c_out, ", ", 2); + BIO_write(bio_c_out, &in[i + 1], in[i]); + i += in[i] + 1; + } + BIO_write(bio_c_out, "\n", 1); + } + + ctx->status = SSL_select_next_proto(out, outlen, in, inlen, ctx->data, ctx->len); + return SSL_TLSEXT_ERR_OK; + } +# endif /* ndef OPENSSL_NO_NEXTPROTONEG */ +#endif + +enum +{ + PROTO_OFF = 0, + PROTO_SMTP, + PROTO_POP3, + PROTO_IMAP, + PROTO_FTP, + PROTO_XMPP +}; + int MAIN(int, char **); int MAIN(int argc, char **argv) { - int off=0; - SSL *con=NULL,*con2=NULL; - X509_STORE *store = NULL; + unsigned int off=0, clr=0; + SSL *con=NULL; +#ifndef OPENSSL_NO_KRB5 + KSSL_CTX *kctx; +#endif int s,k,width,state=0; char *cbuf=NULL,*sbuf=NULL,*mbuf=NULL; int cbuf_len,cbuf_off; @@ -275,29 +561,50 @@ int MAIN(int argc, char **argv) int write_tty,read_tty,write_ssl,read_ssl,tty_on,ssl_pending; SSL_CTX *ctx=NULL; int ret=1,in_init=1,i,nbio_test=0; - int starttls_proto = 0; - int prexit = 0, vflags = 0; + int starttls_proto = PROTO_OFF; + int prexit = 0; + X509_VERIFY_PARAM *vpm = NULL; + int badarg = 0; const SSL_METHOD *meth=NULL; int socket_type=SOCK_STREAM; BIO *sbio; char *inrand=NULL; + int mbuf_len=0; + struct timeval timeout, *timeoutp; #ifndef OPENSSL_NO_ENGINE char *engine_id=NULL; - ENGINE *e=NULL; + char *ssl_client_engine_id=NULL; + ENGINE *ssl_client_engine=NULL; #endif -#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) + ENGINE *e=NULL; +#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_BEOS_R5) struct timeval tv; +#if defined(OPENSSL_SYS_BEOS_R5) + int stdin_set = 0; +#endif #endif - #ifndef OPENSSL_NO_TLSEXT char *servername = NULL; tlsextctx tlsextcbp = {NULL,0}; +# ifndef OPENSSL_NO_NEXTPROTONEG + const char *next_proto_neg_in = NULL; +# endif #endif + char *sess_in = NULL; + char *sess_out = NULL; struct sockaddr peer; int peerlen = sizeof(peer); int enable_timeouts = 0 ; long socket_mtu = 0; +#ifndef OPENSSL_NO_JPAKE + char *jpake_secret = NULL; +#endif +#ifndef OPENSSL_NO_SRP + char * srppass = NULL; + int srp_lateuser = 0; + SRP_ARG srp_arg = {NULL,NULL,0,0,0,1024}; +#endif #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) meth=SSLv23_client_method(); @@ -368,15 +675,29 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; cert_file= *(++argv); } + else if (strcmp(*argv,"-sess_out") == 0) + { + if (--argc < 1) goto bad; + sess_out = *(++argv); + } + else if (strcmp(*argv,"-sess_in") == 0) + { + if (--argc < 1) goto bad; + sess_in = *(++argv); + } else if (strcmp(*argv,"-certform") == 0) { if (--argc < 1) goto bad; cert_format = str2fmt(*(++argv)); } - else if (strcmp(*argv,"-crl_check") == 0) - vflags |= X509_V_FLAG_CRL_CHECK; - else if (strcmp(*argv,"-crl_check_all") == 0) - vflags |= X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL; + else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) + { + if (badarg) + goto bad; + continue; + } + else if (strcmp(*argv,"-verify_return_error") == 0) + verify_return_error = 1; else if (strcmp(*argv,"-prexit") == 0) prexit=1; else if (strcmp(*argv,"-crlf") == 0) @@ -388,10 +709,18 @@ int MAIN(int argc, char **argv) } else if (strcmp(*argv,"-ign_eof") == 0) c_ign_eof=1; + else if (strcmp(*argv,"-no_ign_eof") == 0) + c_ign_eof=0; else if (strcmp(*argv,"-pause") == 0) c_Pause=1; else if (strcmp(*argv,"-debug") == 0) c_debug=1; +#ifndef OPENSSL_NO_TLSEXT + else if (strcmp(*argv,"-tlsextdebug") == 0) + c_tlsextdebug=1; + else if (strcmp(*argv,"-status") == 0) + c_status_req=1; +#endif #ifdef WATT32 else if (strcmp(*argv,"-wdebug") == 0) dbug_init(); @@ -404,6 +733,58 @@ int MAIN(int argc, char **argv) nbio_test=1; else if (strcmp(*argv,"-state") == 0) state=1; +#ifndef OPENSSL_NO_PSK + else if (strcmp(*argv,"-psk_identity") == 0) + { + if (--argc < 1) goto bad; + psk_identity=*(++argv); + } + else if (strcmp(*argv,"-psk") == 0) + { + size_t j; + + if (--argc < 1) goto bad; + psk_key=*(++argv); + for (j = 0; j < strlen(psk_key); j++) + { + if (isxdigit((int)psk_key[j])) + continue; + BIO_printf(bio_err,"Not a hex number '%s'\n",*argv); + goto bad; + } + } +#endif +#ifndef OPENSSL_NO_SRP + else if (strcmp(*argv,"-srpuser") == 0) + { + if (--argc < 1) goto bad; + srp_arg.srplogin= *(++argv); + meth=TLSv1_client_method(); + } + else if (strcmp(*argv,"-srppass") == 0) + { + if (--argc < 1) goto bad; + srppass= *(++argv); + meth=TLSv1_client_method(); + } + else if (strcmp(*argv,"-srp_strength") == 0) + { + if (--argc < 1) goto bad; + srp_arg.strength=atoi(*(++argv)); + BIO_printf(bio_err,"SRP minimal length for N is %d\n",srp_arg.strength); + meth=TLSv1_client_method(); + } + else if (strcmp(*argv,"-srp_lateuser") == 0) + { + srp_lateuser= 1; + meth=TLSv1_client_method(); + } + else if (strcmp(*argv,"-srp_moregroups") == 0) + { + srp_arg.amp=1; + meth=TLSv1_client_method(); + } +#endif #ifndef OPENSSL_NO_SSL2 else if (strcmp(*argv,"-ssl2") == 0) meth=SSLv2_client_method(); @@ -413,6 +794,10 @@ int MAIN(int argc, char **argv) meth=SSLv3_client_method(); #endif #ifndef OPENSSL_NO_TLS1 + else if (strcmp(*argv,"-tls1_2") == 0) + meth=TLSv1_2_client_method(); + else if (strcmp(*argv,"-tls1_1") == 0) + meth=TLSv1_1_client_method(); else if (strcmp(*argv,"-tls1") == 0) meth=TLSv1_client_method(); #endif @@ -461,6 +846,10 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; CAfile= *(++argv); } + else if (strcmp(*argv,"-no_tls1_2") == 0) + off|=SSL_OP_NO_TLSv1_2; + else if (strcmp(*argv,"-no_tls1_1") == 0) + off|=SSL_OP_NO_TLSv1_1; else if (strcmp(*argv,"-no_tls1") == 0) off|=SSL_OP_NO_TLSv1; else if (strcmp(*argv,"-no_ssl3") == 0) @@ -469,8 +858,25 @@ int MAIN(int argc, char **argv) off|=SSL_OP_NO_SSLv2; else if (strcmp(*argv,"-no_comp") == 0) { off|=SSL_OP_NO_COMPRESSION; } +#ifndef OPENSSL_NO_TLSEXT + else if (strcmp(*argv,"-no_ticket") == 0) + { off|=SSL_OP_NO_TICKET; } +# ifndef OPENSSL_NO_NEXTPROTONEG + else if (strcmp(*argv,"-nextprotoneg") == 0) + { + if (--argc < 1) goto bad; + next_proto_neg_in = *(++argv); + } +# endif +#endif else if (strcmp(*argv,"-serverpref") == 0) off|=SSL_OP_CIPHER_SERVER_PREFERENCE; + else if (strcmp(*argv,"-legacy_renegotiation") == 0) + off|=SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; + else if (strcmp(*argv,"-legacy_server_connect") == 0) + { off|=SSL_OP_LEGACY_SERVER_CONNECT; } + else if (strcmp(*argv,"-no_legacy_server_connect") == 0) + { clr|=SSL_OP_LEGACY_SERVER_CONNECT; } else if (strcmp(*argv,"-cipher") == 0) { if (--argc < 1) goto bad; @@ -485,9 +891,15 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; ++argv; if (strcmp(*argv,"smtp") == 0) - starttls_proto = 1; + starttls_proto = PROTO_SMTP; else if (strcmp(*argv,"pop3") == 0) - starttls_proto = 2; + starttls_proto = PROTO_POP3; + else if (strcmp(*argv,"imap") == 0) + starttls_proto = PROTO_IMAP; + else if (strcmp(*argv,"ftp") == 0) + starttls_proto = PROTO_FTP; + else if (strcmp(*argv, "xmpp") == 0) + starttls_proto = PROTO_XMPP; else goto bad; } @@ -497,6 +909,11 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; engine_id = *(++argv); } + else if (strcmp(*argv,"-ssl_client_engine") == 0) + { + if (--argc < 1) goto bad; + ssl_client_engine_id = *(++argv); + } #endif else if (strcmp(*argv,"-rand") == 0) { @@ -510,6 +927,13 @@ int MAIN(int argc, char **argv) servername= *(++argv); /* meth=TLSv1_client_method(); */ } +#endif +#ifndef OPENSSL_NO_JPAKE + else if (strcmp(*argv,"-jpake") == 0) + { + if (--argc < 1) goto bad; + jpake_secret = *++argv; + } #endif else { @@ -527,11 +951,57 @@ bad: goto end; } +#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK) + if (jpake_secret) + { + if (psk_key) + { + BIO_printf(bio_err, + "Can't use JPAKE and PSK together\n"); + goto end; + } + psk_identity = "JPAKE"; + } + + if (cipher) + { + BIO_printf(bio_err, "JPAKE sets cipher to PSK\n"); + goto end; + } + cipher = "PSK"; +#endif + OpenSSL_add_ssl_algorithms(); SSL_load_error_strings(); +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + next_proto.status = -1; + if (next_proto_neg_in) + { + next_proto.data = next_protos_parse(&next_proto.len, next_proto_neg_in); + if (next_proto.data == NULL) + { + BIO_printf(bio_err, "Error parsing -nextprotoneg argument\n"); + goto end; + } + } + else + next_proto.data = NULL; +#endif + #ifndef OPENSSL_NO_ENGINE e = setup_engine(bio_err, engine_id, 1); + if (ssl_client_engine_id) + { + ssl_client_engine = ENGINE_by_id(ssl_client_engine_id); + if (!ssl_client_engine) + { + BIO_printf(bio_err, + "Error getting client auth engine\n"); + goto end; + } + } + #endif if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { @@ -592,6 +1062,14 @@ bad: } } +#ifndef OPENSSL_NO_SRP + if(!app_passwd(bio_err, srppass, NULL, &srp_arg.srppassin, NULL)) + { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } +#endif + ctx=SSL_CTX_new(meth); if (ctx == NULL) { @@ -599,15 +1077,55 @@ bad: goto end; } + if (vpm) + SSL_CTX_set1_param(ctx, vpm); + +#ifndef OPENSSL_NO_ENGINE + if (ssl_client_engine) + { + if (!SSL_CTX_set_client_cert_engine(ctx, ssl_client_engine)) + { + BIO_puts(bio_err, "Error setting client auth engine\n"); + ERR_print_errors(bio_err); + ENGINE_free(ssl_client_engine); + goto end; + } + ENGINE_free(ssl_client_engine); + } +#endif + +#ifndef OPENSSL_NO_PSK +#ifdef OPENSSL_NO_JPAKE + if (psk_key != NULL) +#else + if (psk_key != NULL || jpake_secret) +#endif + { + if (c_debug) + BIO_printf(bio_c_out, "PSK key given or JPAKE in use, setting client callback\n"); + SSL_CTX_set_psk_client_callback(ctx, psk_client_cb); + } +#endif + /* HACK while TLS v1.2 is disabled by default */ + if (!(off & SSL_OP_NO_TLSv1_2)) + SSL_CTX_clear_options(ctx, SSL_OP_NO_TLSv1_2); if (bugs) SSL_CTX_set_options(ctx,SSL_OP_ALL|off); else SSL_CTX_set_options(ctx,off); + + if (clr) + SSL_CTX_clear_options(ctx, clr); /* DTLS: partial reads end up discarding unread UDP bytes :-( * Setting read ahead solves this problem. */ if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1); +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + if (next_proto.data) + SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto); +#endif + if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback); if (cipher != NULL) if(!SSL_CTX_set_cipher_list(ctx,cipher)) { @@ -632,8 +1150,6 @@ bad: /* goto end; */ } - store = SSL_CTX_get_cert_store(ctx); - X509_STORE_set_flags(store, vflags); #ifndef OPENSSL_NO_TLSEXT if (servername != NULL) { @@ -641,13 +1157,56 @@ bad: SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp); } +#ifndef OPENSSL_NO_SRP + if (srp_arg.srplogin) + { + if (srp_lateuser) + SSL_CTX_set_srp_missing_srp_username_callback(ctx,missing_srp_username_callback); + else if (!SSL_CTX_set_srp_username(ctx, srp_arg.srplogin)) + { + BIO_printf(bio_err,"Unable to set SRP username\n"); + goto end; + } + srp_arg.msg = c_msg; + srp_arg.debug = c_debug ; + SSL_CTX_set_srp_cb_arg(ctx,&srp_arg); + SSL_CTX_set_srp_client_pwd_callback(ctx, ssl_give_srp_client_pwd_cb); + SSL_CTX_set_srp_strength(ctx, srp_arg.strength); + if (c_msg || c_debug || srp_arg.amp == 0) + SSL_CTX_set_srp_verify_param_callback(ctx, ssl_srp_verify_param_cb); + } + +#endif #endif con=SSL_new(ctx); + if (sess_in) + { + SSL_SESSION *sess; + BIO *stmp = BIO_new_file(sess_in, "r"); + if (!stmp) + { + BIO_printf(bio_err, "Can't open session file %s\n", + sess_in); + ERR_print_errors(bio_err); + goto end; + } + sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL); + BIO_free(stmp); + if (!sess) + { + BIO_printf(bio_err, "Can't open session file %s\n", + sess_in); + ERR_print_errors(bio_err); + goto end; + } + SSL_set_session(con, sess); + SSL_SESSION_free(sess); + } #ifndef OPENSSL_NO_TLSEXT if (servername != NULL) { - if (!SSL_set_tlsext_hostname(con,servername)) + if (!SSL_set_tlsext_host_name(con,servername)) { BIO_printf(bio_err,"Unable to set TLS servername extension.\n"); ERR_print_errors(bio_err); @@ -656,12 +1215,18 @@ bad: } #endif #ifndef OPENSSL_NO_KRB5 - if (con && (con->kssl_ctx = kssl_ctx_new()) != NULL) + if (con && (kctx = kssl_ctx_new()) != NULL) { - kssl_ctx_setstring(con->kssl_ctx, KSSL_SERVER, host); + SSL_set0_kssl_ctx(con, kctx); + kssl_ctx_setstring(kctx, KSSL_SERVER, host); } #endif /* OPENSSL_NO_KRB5 */ /* SSL_set_cipher_list(con,"RC4-MD5"); */ +#if 0 +#ifdef TLSEXT_TYPE_opaque_prf_input + SSL_set_tlsext_opaque_prf_input(con, "Test client", 11); +#endif +#endif re_start: @@ -685,11 +1250,10 @@ re_start: } } #endif - if (c_Pause & 0x01) con->debug=1; + if (c_Pause & 0x01) SSL_set_debug(con, 1); if ( SSL_version(con) == DTLS1_VERSION) { - struct timeval timeout; sbio=BIO_new_dgram(s,BIO_NOCLOSE); if (getsockname(s, &peer, (void *)&peerlen) < 0) @@ -700,7 +1264,7 @@ re_start: goto end; } - BIO_ctrl_set_connected(sbio, 1, &peer); + (void)BIO_ctrl_set_connected(sbio, 1, &peer); if (enable_timeouts) { @@ -713,10 +1277,10 @@ re_start: BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); } - if (socket_mtu > 0) + if (socket_mtu > 28) { SSL_set_options(con, SSL_OP_NO_QUERY_MTU); - SSL_set_mtu(con, socket_mtu); + SSL_set_mtu(con, socket_mtu - 28); } else /* want to do MTU discovery */ @@ -725,8 +1289,6 @@ re_start: else sbio=BIO_new_socket(s,BIO_NOCLOSE); - - if (nbio_test) { BIO *test; @@ -737,15 +1299,43 @@ re_start: if (c_debug) { - con->debug=1; + SSL_set_debug(con, 1); BIO_set_callback(sbio,bio_dump_callback); - BIO_set_callback_arg(sbio,bio_c_out); + BIO_set_callback_arg(sbio,(char *)bio_c_out); } if (c_msg) { SSL_set_msg_callback(con, msg_cb); SSL_set_msg_callback_arg(con, bio_c_out); } +#ifndef OPENSSL_NO_TLSEXT + if (c_tlsextdebug) + { + SSL_set_tlsext_debug_callback(con, tlsext_cb); + SSL_set_tlsext_debug_arg(con, bio_c_out); + } + if (c_status_req) + { + SSL_set_tlsext_status_type(con, TLSEXT_STATUSTYPE_ocsp); + SSL_CTX_set_tlsext_status_cb(ctx, ocsp_resp_cb); + SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out); +#if 0 +{ +STACK_OF(OCSP_RESPID) *ids = sk_OCSP_RESPID_new_null(); +OCSP_RESPID *id = OCSP_RESPID_new(); +id->value.byKey = ASN1_OCTET_STRING_new(); +id->type = V_OCSP_RESPID_KEY; +ASN1_STRING_set(id->value.byKey, "Hello World", -1); +sk_OCSP_RESPID_push(ids, id); +SSL_set_tlsext_status_ids(con, ids); +} +#endif + } +#endif +#ifndef OPENSSL_NO_JPAKE + if (jpake_secret) + jpake_client_auth(bio_c_out, sbio, jpake_secret); +#endif SSL_set_bio(con,sbio,sbio); SSL_set_connect_state(con); @@ -765,24 +1355,127 @@ re_start: sbuf_off=0; /* This is an ugly hack that does a lot of assumptions */ - if (starttls_proto == 1) + /* We do have to handle multi-line responses which may come + in a single packet or not. We therefore have to use + BIO_gets() which does need a buffering BIO. So during + the initial chitchat we do push a buffering BIO into the + chain that is removed again later on to not disturb the + rest of the s_client operation. */ + if (starttls_proto == PROTO_SMTP) { - BIO_read(sbio,mbuf,BUFSIZZ); + int foundit=0; + BIO *fbio = BIO_new(BIO_f_buffer()); + BIO_push(fbio, sbio); + /* wait for multi-line response to end from SMTP */ + do + { + mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ); + } + while (mbuf_len>3 && mbuf[3]=='-'); + /* STARTTLS command requires EHLO... */ + BIO_printf(fbio,"EHLO openssl.client.net\r\n"); + (void)BIO_flush(fbio); + /* wait for multi-line response to end EHLO SMTP response */ + do + { + mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ); + if (strstr(mbuf,"STARTTLS")) + foundit=1; + } + while (mbuf_len>3 && mbuf[3]=='-'); + (void)BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + if (!foundit) + BIO_printf(bio_err, + "didn't found starttls in server response," + " try anyway...\n"); BIO_printf(sbio,"STARTTLS\r\n"); BIO_read(sbio,sbuf,BUFSIZZ); } - if (starttls_proto == 2) + else if (starttls_proto == PROTO_POP3) { BIO_read(sbio,mbuf,BUFSIZZ); BIO_printf(sbio,"STLS\r\n"); BIO_read(sbio,sbuf,BUFSIZZ); } + else if (starttls_proto == PROTO_IMAP) + { + int foundit=0; + BIO *fbio = BIO_new(BIO_f_buffer()); + BIO_push(fbio, sbio); + BIO_gets(fbio,mbuf,BUFSIZZ); + /* STARTTLS command requires CAPABILITY... */ + BIO_printf(fbio,". CAPABILITY\r\n"); + (void)BIO_flush(fbio); + /* wait for multi-line CAPABILITY response */ + do + { + mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ); + if (strstr(mbuf,"STARTTLS")) + foundit=1; + } + while (mbuf_len>3 && mbuf[0]!='.'); + (void)BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + if (!foundit) + BIO_printf(bio_err, + "didn't found STARTTLS in server response," + " try anyway...\n"); + BIO_printf(sbio,". STARTTLS\r\n"); + BIO_read(sbio,sbuf,BUFSIZZ); + } + else if (starttls_proto == PROTO_FTP) + { + BIO *fbio = BIO_new(BIO_f_buffer()); + BIO_push(fbio, sbio); + /* wait for multi-line response to end from FTP */ + do + { + mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ); + } + while (mbuf_len>3 && mbuf[3]=='-'); + (void)BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + BIO_printf(sbio,"AUTH TLS\r\n"); + BIO_read(sbio,sbuf,BUFSIZZ); + } + if (starttls_proto == PROTO_XMPP) + { + int seen = 0; + BIO_printf(sbio,"", host); + seen = BIO_read(sbio,mbuf,BUFSIZZ); + mbuf[seen] = 0; + while (!strstr(mbuf, "")) + goto shut; + seen = BIO_read(sbio,mbuf,BUFSIZZ); + mbuf[seen] = 0; + } + BIO_printf(sbio, ""); + seen = BIO_read(sbio,sbuf,BUFSIZZ); + sbuf[seen] = 0; + if (!strstr(sbuf, " 0) full_log--; @@ -807,7 +1513,7 @@ re_start: { BIO_printf(bio_err,"%s",mbuf); /* We don't need to know any more */ - starttls_proto = 0; + starttls_proto = PROTO_OFF; } if (reconnect) @@ -826,22 +1532,22 @@ re_start: if (!ssl_pending) { -#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) +#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) && !defined (OPENSSL_SYS_BEOS_R5) if (tty_on) { - if (read_tty) FD_SET(fileno(stdin),&readfds); - if (write_tty) FD_SET(fileno(stdout),&writefds); + if (read_tty) openssl_fdset(fileno(stdin),&readfds); + if (write_tty) openssl_fdset(fileno(stdout),&writefds); } if (read_ssl) - FD_SET(SSL_get_fd(con),&readfds); + openssl_fdset(SSL_get_fd(con),&readfds); if (write_ssl) - FD_SET(SSL_get_fd(con),&writefds); + openssl_fdset(SSL_get_fd(con),&writefds); #else if(!tty_on || !write_tty) { if (read_ssl) - FD_SET(SSL_get_fd(con),&readfds); + openssl_fdset(SSL_get_fd(con),&readfds); if (write_ssl) - FD_SET(SSL_get_fd(con),&writefds); + openssl_fdset(SSL_get_fd(con),&writefds); } #endif /* printf("mode tty(%d %d%d) ssl(%d%d)\n", @@ -874,7 +1580,7 @@ re_start: if(!i && (!((_kbhit()) || (WAIT_OBJECT_0 == WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0))) || !read_tty) ) continue; #endif } else i=select(width,(void *)&readfds,(void *)&writefds, - NULL,NULL); + NULL,timeoutp); } #elif defined(OPENSSL_SYS_NETWARE) if(!write_tty) { @@ -884,11 +1590,30 @@ re_start: i=select(width,(void *)&readfds,(void *)&writefds, NULL,&tv); } else i=select(width,(void *)&readfds,(void *)&writefds, - NULL,NULL); + NULL,timeoutp); } +#elif defined(OPENSSL_SYS_BEOS_R5) + /* Under BeOS-R5 the situation is similar to DOS */ + i=0; + stdin_set = 0; + (void)fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); + if(!write_tty) { + if(read_tty) { + tv.tv_sec = 1; + tv.tv_usec = 0; + i=select(width,(void *)&readfds,(void *)&writefds, + NULL,&tv); + if (read(fileno(stdin), sbuf, 0) >= 0) + stdin_set = 1; + if (!i && (stdin_set != 1 || !read_tty)) + continue; + } else i=select(width,(void *)&readfds,(void *)&writefds, + NULL,timeoutp); + } + (void)fcntl(fileno(stdin), F_SETFL, 0); #else i=select(width,(void *)&readfds,(void *)&writefds, - NULL,NULL); + NULL,timeoutp); #endif if ( i < 0) { @@ -899,6 +1624,11 @@ re_start: } } + if ((SSL_version(con) == DTLS1_VERSION) && DTLSv1_handle_timeout(con) > 0) + { + BIO_printf(bio_err,"TIMEOUT occured\n"); + } + if (!ssl_pending && FD_ISSET(SSL_get_fd(con),&writefds)) { k=SSL_write(con,&(cbuf[cbuf_off]), @@ -939,6 +1669,7 @@ re_start: if (cbuf_len != 0) { BIO_printf(bio_c_out,"shutdown\n"); + ret = 0; goto shut; } else @@ -966,8 +1697,8 @@ re_start: goto shut; } } -#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) - /* Assume Windows/DOS can always write */ +#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_BEOS_R5) + /* Assume Windows/DOS/BeOS can always write */ else if (!ssl_pending && write_tty) #else else if (!ssl_pending && FD_ISSET(fileno(stdout),&writefds)) @@ -981,6 +1712,7 @@ re_start: if (i <= 0) { BIO_printf(bio_c_out,"DONE\n"); + ret = 0; goto shut; /* goto end; */ } @@ -1035,10 +1767,12 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240 BIO_printf(bio_c_out,"read X BLOCK\n"); break; case SSL_ERROR_SYSCALL: - BIO_printf(bio_err,"read:errno=%d\n",get_last_socket_error()); + ret=get_last_socket_error(); + BIO_printf(bio_err,"read:errno=%d\n",ret); goto shut; case SSL_ERROR_ZERO_RETURN: BIO_printf(bio_c_out,"closed\n"); + ret=0; goto shut; case SSL_ERROR_SSL: ERR_print_errors(bio_err); @@ -1055,6 +1789,8 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240 #endif #elif defined (OPENSSL_SYS_NETWARE) else if (_kbhit()) +#elif defined(OPENSSL_SYS_BEOS_R5) + else if (stdin_set) #else else if (FD_ISSET(fileno(stdin),&readfds)) #endif @@ -1087,6 +1823,7 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240 if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q'))) { BIO_printf(bio_err,"DONE\n"); + ret=0; goto shut; } @@ -1109,14 +1846,20 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240 read_tty=0; } } + + ret=0; shut: + if (in_init) + print_stuff(bio_c_out,con,full_log); SSL_shutdown(con); SHUTDOWN(SSL_get_fd(con)); - ret=0; end: - if(prexit) print_stuff(bio_c_out,con,1); - if (con != NULL) SSL_free(con); - if (con2 != NULL) SSL_free(con2); + if (con != NULL) + { + if (prexit != 0) + print_stuff(bio_c_out,con,1); + SSL_free(con); + } if (ctx != NULL) SSL_CTX_free(ctx); if (cert) X509_free(cert); @@ -1145,7 +1888,7 @@ static void print_stuff(BIO *bio, SSL *s, int full) char buf[BUFSIZ]; STACK_OF(X509) *sk; STACK_OF(X509_NAME) *sk2; - SSL_CIPHER *c; + const SSL_CIPHER *c; X509_NAME *xn; int j,i; #ifndef OPENSSL_NO_COMP @@ -1241,7 +1984,7 @@ static void print_stuff(BIO *bio, SSL *s, int full) BIO_number_read(SSL_get_rbio(s)), BIO_number_written(SSL_get_wbio(s))); } - BIO_printf(bio,((s->hit)?"---\nReused, ":"---\nNew, ")); + BIO_printf(bio,(SSL_cache_hit(s)?"---\nReused, ":"---\nNew, ")); c=SSL_get_current_cipher(s); BIO_printf(bio,"%s, Cipher is %s\n", SSL_CIPHER_get_version(c), @@ -1253,6 +1996,8 @@ static void print_stuff(BIO *bio, SSL *s, int full) EVP_PKEY_bits(pktmp)); EVP_PKEY_free(pktmp); } + BIO_printf(bio, "Secure Renegotiation IS%s supported\n", + SSL_get_secure_renegotiation_support(s) ? "" : " NOT"); #ifndef OPENSSL_NO_COMP comp=SSL_get_current_compression(s); expansion=SSL_get_current_expansion(s); @@ -1261,11 +2006,64 @@ static void print_stuff(BIO *bio, SSL *s, int full) BIO_printf(bio,"Expansion: %s\n", expansion ? SSL_COMP_get_name(expansion) : "NONE"); #endif + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + if (next_proto.status != -1) { + const unsigned char *proto; + unsigned int proto_len; + SSL_get0_next_proto_negotiated(s, &proto, &proto_len); + BIO_printf(bio, "Next protocol: (%d) ", next_proto.status); + BIO_write(bio, proto, proto_len); + BIO_write(bio, "\n", 1); + } +#endif + +#ifdef SSL_DEBUG + { + /* Print out local port of connection: useful for debugging */ + int sock; + struct sockaddr_in ladd; + socklen_t ladd_size = sizeof(ladd); + sock = SSL_get_fd(s); + getsockname(sock, (struct sockaddr *)&ladd, &ladd_size); + BIO_printf(bio_c_out, "LOCAL PORT is %u\n", ntohs(ladd.sin_port)); + } +#endif + SSL_SESSION_print(bio,SSL_get_session(s)); BIO_printf(bio,"---\n"); if (peer != NULL) X509_free(peer); /* flush, or debugging output gets mixed with http response */ - BIO_flush(bio); + (void)BIO_flush(bio); } +#ifndef OPENSSL_NO_TLSEXT + +static int ocsp_resp_cb(SSL *s, void *arg) + { + const unsigned char *p; + int len; + OCSP_RESPONSE *rsp; + len = SSL_get_tlsext_status_ocsp_resp(s, &p); + BIO_puts(arg, "OCSP response: "); + if (!p) + { + BIO_puts(arg, "no response sent\n"); + return 1; + } + rsp = d2i_OCSP_RESPONSE(NULL, &p, len); + if (!rsp) + { + BIO_puts(arg, "response parse error\n"); + BIO_dump_indent(arg, (char *)p, len, 4); + return 0; + } + BIO_puts(arg, "\n======================================\n"); + OCSP_RESPONSE_print(arg, rsp, 0); + BIO_puts(arg, "======================================\n"); + OCSP_RESPONSE_free(rsp); + return 1; + } + +#endif