diff options
Diffstat (limited to 'main/openssl/apps/s_client.c')
-rw-r--r-- | main/openssl/apps/s_client.c | 399 |
1 files changed, 366 insertions, 33 deletions
diff --git a/main/openssl/apps/s_client.c b/main/openssl/apps/s_client.c index b951513d..0c705803 100644 --- a/main/openssl/apps/s_client.c +++ b/main/openssl/apps/s_client.c @@ -163,6 +163,9 @@ typedef unsigned int u_int; #include <openssl/rand.h> #include <openssl/ocsp.h> #include <openssl/bn.h> +#ifndef OPENSSL_NO_SRP +#include <openssl/srp.h> +#endif #include "s_apps.h" #include "timeouts.h" @@ -203,6 +206,9 @@ static int c_status_req=0; static int c_msg=0; static int c_showcerts=0; +static char *keymatexportlabel=NULL; +static int keymatexportlen=20; + static void sc_usage(void); static void print_stuff(BIO *berr,SSL *con,int full); #ifndef OPENSSL_NO_TLSEXT @@ -316,12 +322,21 @@ static void sc_usage(void) 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 link layer MTU\n"); - BIO_printf(bio_err," -no_tls1/-no_ssl3/-no_ssl2 - turn off that protocol\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"); @@ -344,10 +359,17 @@ static void sc_usage(void) 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"); + BIO_printf(bio_err," -alpn arg - enable ALPN extension, considering named protocols supported (comma-separated list)\n"); # endif - BIO_printf(bio_err," -cutthrough - enable 1-RTT full-handshake for strong ciphers\n"); #endif + BIO_printf(bio_err," -cutthrough - enable 1-RTT full-handshake for strong ciphers\n"); + BIO_printf(bio_err," -no_record_splitting - disable 1/n-1 record splitting in CBC mode\n"); BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n"); +#ifndef OPENSSL_NO_SRTP + BIO_printf(bio_err," -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); +#endif + BIO_printf(bio_err," -keymatexport label - Export keying material using label\n"); + BIO_printf(bio_err," -keymatexportlen len - Export len bytes of keying material (default 20)\n"); } #ifndef OPENSSL_NO_TLSEXT @@ -371,6 +393,124 @@ static int MS_CALLBACK ssl_servername_cb(SSL *s, int *ad, void *arg) 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(BIGNUM *N, 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; + } + +/* This callback is used here for two purposes: + - extended debugging + - making some primality tests for unknown groups + The callback is only called for a non default group. + + An application does not need the call back at all if + only the stanard groups are used. In real life situations, + client and server already share well known groups, + thus there is no need to verify them. + Furthermore, in case that a server actually proposes a group that + is not one of those defined in RFC 5054, it is more appropriate + to add the group to a static list and then compare since + primality tests are rather cpu consuming. +*/ + +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 is a real debugging feature. + 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; + } + +#endif +#ifndef OPENSSL_NO_SRTP + char *srtp_profiles = NULL; +#endif + # ifndef OPENSSL_NO_NEXTPROTONEG /* This the context that we pass to next_proto_cb */ typedef struct tlsextnextprotoctx_st { @@ -422,6 +562,9 @@ int MAIN(int argc, char **argv) { 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; @@ -437,7 +580,7 @@ int MAIN(int argc, char **argv) EVP_PKEY *key = NULL; char *CApath=NULL,*CAfile=NULL,*cipher=NULL; int reconnect=0,badop=0,verify=SSL_VERIFY_NONE,bugs=0; - int cutthrough=0; + int cutthrough=0, no_record_splitting=0; int crlf=0; int write_tty,read_tty,write_ssl,read_ssl,tty_on,ssl_pending; SSL_CTX *ctx=NULL; @@ -452,6 +595,7 @@ int MAIN(int argc, char **argv) char *inrand=NULL; int mbuf_len=0; struct timeval timeout, *timeoutp; + int ssl_mode; #ifndef OPENSSL_NO_ENGINE char *engine_id=NULL; char *ssl_client_engine_id=NULL; @@ -470,6 +614,7 @@ int MAIN(int argc, char **argv) {NULL,0}; # ifndef OPENSSL_NO_NEXTPROTONEG const char *next_proto_neg_in = NULL; + const char *alpn_in = NULL; # endif #endif char *sess_in = NULL; @@ -481,14 +626,13 @@ int MAIN(int argc, char **argv) #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(); -#elif !defined(OPENSSL_NO_SSL3) - meth=SSLv3_client_method(); -#elif !defined(OPENSSL_NO_SSL2) - meth=SSLv2_client_method(); -#endif apps_startup(); c_Pause=0; @@ -623,13 +767,44 @@ int MAIN(int argc, char **argv) psk_key=*(++argv); for (j = 0; j < strlen(psk_key); j++) { - if (isxdigit((int)psk_key[j])) + if (isxdigit((unsigned char)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(); @@ -639,6 +814,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 @@ -687,6 +866,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) @@ -704,10 +887,17 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; next_proto_neg_in = *(++argv); } + else if (strcmp(*argv,"-alpn") == 0) + { + if (--argc < 1) goto bad; + alpn_in = *(++argv); + } # endif #endif else if (strcmp(*argv,"-cutthrough") == 0) cutthrough=1; + else if (strcmp(*argv,"-no_record_splitting") == 0) + no_record_splitting=1; else if (strcmp(*argv,"-serverpref") == 0) off|=SSL_OP_CIPHER_SERVER_PREFERENCE; else if (strcmp(*argv,"-legacy_renegotiation") == 0) @@ -774,7 +964,25 @@ int MAIN(int argc, char **argv) jpake_secret = *++argv; } #endif - else +#ifndef OPENSSL_NO_SRTP + else if (strcmp(*argv,"-use_srtp") == 0) + { + if (--argc < 1) goto bad; + srtp_profiles = *(++argv); + } +#endif + else if (strcmp(*argv,"-keymatexport") == 0) + { + if (--argc < 1) goto bad; + keymatexportlabel= *(++argv); + } + else if (strcmp(*argv,"-keymatexportlen") == 0) + { + if (--argc < 1) goto bad; + keymatexportlen=atoi(*(++argv)); + if (keymatexportlen == 0) goto bad; + } + else { BIO_printf(bio_err,"unknown option %s\n",*argv); badop=1; @@ -800,14 +1008,13 @@ bad: goto end; } psk_identity = "JPAKE"; + if (cipher) + { + BIO_printf(bio_err, "JPAKE sets cipher to PSK\n"); + goto end; + } + cipher = "PSK"; } - - if (cipher) - { - BIO_printf(bio_err, "JPAKE sets cipher to PSK\n"); - goto end; - } - cipher = "PSK"; #endif OpenSSL_add_ssl_algorithms(); @@ -901,6 +1108,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) { @@ -937,6 +1152,10 @@ bad: SSL_CTX_set_psk_client_callback(ctx, psk_client_cb); } #endif +#ifndef OPENSSL_NO_SRTP + if (srtp_profiles != NULL) + SSL_CTX_set_tlsext_use_srtp(ctx, srtp_profiles); +#endif if (bugs) SSL_CTX_set_options(ctx,SSL_OP_ALL|off); else @@ -949,19 +1168,35 @@ bad: */ if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1); - /* Enable handshake cutthrough for client connections using - * strong ciphers. */ +#if !defined(OPENSSL_NO_TLSEXT) +# if !defined(OPENSSL_NO_NEXTPROTONEG) + if (next_proto.data) + SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto); +# endif + if (alpn_in) + { + unsigned short alpn_len; + unsigned char *alpn = next_protos_parse(&alpn_len, alpn_in); + + if (alpn == NULL) + { + BIO_printf(bio_err, "Error parsing -alpn argument\n"); + goto end; + } + SSL_CTX_set_alpn_protos(ctx, alpn, alpn_len); + } +#endif + + ssl_mode = SSL_CTX_get_mode(ctx); + if (!no_record_splitting) + ssl_mode |= SSL_MODE_CBC_RECORD_SPLITTING; if (cutthrough) { - int ssl_mode = SSL_CTX_get_mode(ctx); + /* Enable handshake cutthrough for client connections using + * strong ciphers. */ ssl_mode |= SSL_MODE_HANDSHAKE_CUTTHROUGH; - SSL_CTX_set_mode(ctx, ssl_mode); } - -#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 + SSL_CTX_set_mode(ctx, ssl_mode); if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback); if (cipher != NULL) @@ -994,6 +1229,24 @@ 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_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); @@ -1032,9 +1285,10 @@ 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"); */ @@ -1066,7 +1320,7 @@ 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) { @@ -1115,7 +1369,7 @@ 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,(char *)bio_c_out); } @@ -1649,6 +1903,14 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240 SSL_renegotiate(con); cbuf_len=0; } +#ifndef OPENSSL_NO_HEARTBEATS + else if ((!c_ign_eof) && (cbuf[0] == 'B')) + { + BIO_printf(bio_err,"HEARTBEATING\n"); + SSL_heartbeat(con); + cbuf_len=0; + } +#endif else { cbuf_len=i; @@ -1676,6 +1938,10 @@ end: print_stuff(bio_c_out,con,1); SSL_free(con); } +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + if (next_proto.data) + OPENSSL_free(next_proto.data); +#endif if (ctx != NULL) SSL_CTX_free(ctx); if (cert) X509_free(cert); @@ -1683,6 +1949,8 @@ end: EVP_PKEY_free(key); if (pass) OPENSSL_free(pass); + if (vpm) + X509_VERIFY_PARAM_free(vpm); if (cbuf != NULL) { OPENSSL_cleanse(cbuf,BUFSIZZ); OPENSSL_free(cbuf); } if (sbuf != NULL) { OPENSSL_cleanse(sbuf,BUFSIZZ); OPENSSL_free(sbuf); } if (mbuf != NULL) { OPENSSL_cleanse(mbuf,BUFSIZZ); OPENSSL_free(mbuf); } @@ -1710,6 +1978,7 @@ static void print_stuff(BIO *bio, SSL *s, int full) #ifndef OPENSSL_NO_COMP const COMP_METHOD *comp, *expansion; #endif + unsigned char *exportedkeymat; if (full) { @@ -1800,7 +2069,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), @@ -1822,8 +2091,21 @@ static void print_stuff(BIO *bio, SSL *s, int full) BIO_printf(bio,"Expansion: %s\n", expansion ? SSL_COMP_get_name(expansion) : "NONE"); #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 -#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +#if !defined(OPENSSL_NO_TLSEXT) +# if !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto.status != -1) { const unsigned char *proto; unsigned int proto_len; @@ -1832,9 +2114,60 @@ static void print_stuff(BIO *bio, SSL *s, int full) BIO_write(bio, proto, proto_len); BIO_write(bio, "\n", 1); } + { + const unsigned char *proto; + unsigned int proto_len; + SSL_get0_alpn_selected(s, &proto, &proto_len); + if (proto_len > 0) + { + BIO_printf(bio, "ALPN protocol: "); + BIO_write(bio, proto, proto_len); + BIO_write(bio, "\n", 1); + } + else + BIO_printf(bio, "No ALPN negotiated\n"); + } +# endif #endif +#ifndef OPENSSL_NO_SRTP + { + SRTP_PROTECTION_PROFILE *srtp_profile=SSL_get_selected_srtp_profile(s); + + if(srtp_profile) + BIO_printf(bio,"SRTP Extension negotiated, profile=%s\n", + srtp_profile->name); + } +#endif + SSL_SESSION_print(bio,SSL_get_session(s)); + if (keymatexportlabel != NULL) + { + BIO_printf(bio, "Keying material exporter:\n"); + BIO_printf(bio, " Label: '%s'\n", keymatexportlabel); + BIO_printf(bio, " Length: %i bytes\n", keymatexportlen); + exportedkeymat = OPENSSL_malloc(keymatexportlen); + if (exportedkeymat != NULL) + { + if (!SSL_export_keying_material(s, exportedkeymat, + keymatexportlen, + keymatexportlabel, + strlen(keymatexportlabel), + NULL, 0, 0)) + { + BIO_printf(bio, " Error\n"); + } + else + { + BIO_printf(bio, " Keying material: "); + for (i=0; i<keymatexportlen; i++) + BIO_printf(bio, "%02X", + exportedkeymat[i]); + BIO_printf(bio, "\n"); + } + OPENSSL_free(exportedkeymat); + } + } BIO_printf(bio,"---\n"); if (peer != NULL) X509_free(peer); |