X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Fs_server.c;h=d678e8e2579d5ed92575e80cd8f29e7c50fc1283;hp=cc910bc9a9df45626d0a96103ab91bf4cd1e9c4e;hb=db0f35dda18403accabe98e7780f3dfc516f49de;hpb=048b189336e5703f19e695245ae656513d5f2797 diff --git a/apps/s_server.c b/apps/s_server.c index cc910bc9a9..d678e8e257 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -91,9 +91,9 @@ typedef unsigned int u_int; #endif static int not_resumable_sess_cb(SSL *s, int is_forward_secure); -static int sv_body(int s, int stype, unsigned char *context); -static int www_body(int s, int stype, unsigned char *context); -static int rev_body(int s, int stype, unsigned char *context); +static int sv_body(int s, int stype, int prot, unsigned char *context); +static int www_body(int s, int stype, int prot, unsigned char *context); +static int rev_body(int s, int stype, int prot, unsigned char *context); static void close_accept_socket(void); static int init_ssl_connection(SSL *s); static void print_stats(BIO *bp, SSL_CTX *ctx); @@ -104,8 +104,7 @@ static void free_sessions(void); #ifndef OPENSSL_NO_DH static DH *load_dh_param(const char *dhfile); #endif - -/* static int load_CA(SSL_CTX *ctx, char *file);*/ +static void print_connection_info(SSL *con); static const int bufsize = 16 * 1024; static int accept_socket = -1; @@ -139,10 +138,16 @@ static const char *session_id_prefix = NULL; #ifndef OPENSSL_NO_DTLS static int enable_timeouts = 0; static long socket_mtu; - #endif + +/* + * We define this but make it always be 0 in no-dtls builds to simplify the + * code. + */ static int dtlslisten = 0; +static int early_data = 0; + #ifndef OPENSSL_NO_PSK static char *psk_identity = "Client_identity"; char *psk_key = NULL; /* by default PSK is not used */ @@ -166,12 +171,12 @@ static unsigned int psk_server_cb(SSL *ssl, const char *identity, /* here we could lookup the given identity e.g. from a database */ if (strcmp(identity, psk_identity) != 0) { - BIO_printf(bio_s_out, "PSK error: client identity not found" + BIO_printf(bio_s_out, "PSK warning: client identity not what we expected" " (got '%s' expected '%s')\n", identity, psk_identity); - goto out_err; - } - if (s_debug) + } else { + if (s_debug) BIO_printf(bio_s_out, "PSK client identity found\n"); + } /* convert the PSK key to binary */ key = OPENSSL_hexstr2buf(psk_key, &key_len); @@ -449,7 +454,6 @@ static int ssl_servername_cb(SSL *s, int *ad, void *arg) } /* Structure passed to cert status callback */ - typedef struct tlsextstatusctx_st { int timeout; /* File to load OCSP Response from (or NULL if no file) */ @@ -629,7 +633,7 @@ static int cert_status_cb(SSL *s, void *arg) /* This is the context that we pass to next_proto_cb */ typedef struct tlsextnextprotoctx_st { unsigned char *data; - unsigned int len; + size_t len; } tlsextnextprotoctx; static int next_proto_cb(SSL *s, const unsigned char **data, @@ -711,15 +715,16 @@ typedef enum OPTION_choice { OPT_STATUS_TIMEOUT, OPT_STATUS_URL, OPT_STATUS_FILE, OPT_MSG, OPT_MSGFILE, OPT_TRACE, OPT_SECURITY_DEBUG, OPT_SECURITY_DEBUG_VERBOSE, OPT_STATE, OPT_CRLF, OPT_QUIET, OPT_BRIEF, OPT_NO_DHE, - OPT_NO_RESUME_EPHEMERAL, OPT_PSK_HINT, OPT_PSK, OPT_SRPVFILE, + OPT_NO_RESUME_EPHEMERAL, OPT_PSK_IDENTITY, OPT_PSK_HINT, OPT_PSK, OPT_SRPVFILE, OPT_SRPUSERSEED, OPT_REV, OPT_WWW, OPT_UPPER_WWW, OPT_HTTP, OPT_ASYNC, - OPT_SSL_CONFIG, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF, + OPT_SSL_CONFIG, + OPT_MAX_SEND_FRAG, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF, OPT_SSL3, OPT_TLS1_3, OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1, - OPT_DTLS1_2, OPT_TIMEOUT, OPT_MTU, OPT_LISTEN, + OPT_DTLS1_2, OPT_SCTP, OPT_TIMEOUT, OPT_MTU, OPT_LISTEN, OPT_ID_PREFIX, OPT_RAND, OPT_SERVERNAME, OPT_SERVERNAME_FATAL, OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN, OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, - OPT_KEYLOG_FILE, OPT_MAX_EARLY, + OPT_KEYLOG_FILE, OPT_MAX_EARLY, OPT_EARLY_DATA, OPT_S_ENUM, OPT_V_ENUM, OPT_X_ENUM @@ -852,17 +857,19 @@ const OPTIONS s_server_options[] = { {"async", OPT_ASYNC, '-', "Operate in asynchronous mode"}, {"ssl_config", OPT_SSL_CONFIG, 's', "Configure SSL_CTX using the configuration 'val'"}, - {"split_send_frag", OPT_SPLIT_SEND_FRAG, 'n', + {"max_send_frag", OPT_MAX_SEND_FRAG, 'p', "Maximum Size of send frames "}, + {"split_send_frag", OPT_SPLIT_SEND_FRAG, 'p', "Size used to split data for encrypt pipelines"}, - {"max_pipelines", OPT_MAX_PIPELINES, 'n', + {"max_pipelines", OPT_MAX_PIPELINES, 'p', "Maximum number of encrypt/decrypt pipelines to be used"}, - {"read_buf", OPT_READ_BUF, 'n', + {"read_buf", OPT_READ_BUF, 'p', "Default read buffer size to be used for connections"}, OPT_S_OPTIONS, OPT_V_OPTIONS, OPT_X_OPTIONS, {"nbio", OPT_NBIO, '-', "Use non-blocking IO"}, #ifndef OPENSSL_NO_PSK + {"psk_identity", OPT_PSK_IDENTITY, 's', "PSK identity to expect"}, {"psk_hint", OPT_PSK_HINT, 's', "PSK identity hint to use"}, {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"}, #endif @@ -899,6 +906,9 @@ const OPTIONS s_server_options[] = { #ifndef OPENSSL_NO_DTLS1_2 {"dtls1_2", OPT_DTLS1_2, '-', "Just talk DTLSv1.2"}, #endif +#ifndef OPENSSL_NO_SCTP + {"sctp", OPT_SCTP, '-', "Use SCTP"}, +#endif #ifndef OPENSSL_NO_DH {"no_dhe", OPT_NO_DHE, '-', "Disable ephemeral DH"}, #endif @@ -916,8 +926,9 @@ const OPTIONS s_server_options[] = { {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, #endif {"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"}, - {"max_early_data", OPT_MAX_EARLY, 'p', + {"max_early_data", OPT_MAX_EARLY, 'n', "The maximum number of bytes of early data"}, + {"early_data", OPT_EARLY_DATA, '-', "Attempt to read early data"}, {NULL, OPT_EOF, 0, NULL} }; @@ -955,7 +966,7 @@ int s_server_main(int argc, char *argv[]) int s_cert_format = FORMAT_PEM, s_key_format = FORMAT_PEM; int s_dcert_format = FORMAT_PEM, s_dkey_format = FORMAT_PEM; int rev = 0, naccept = -1, sdebug = 0; - int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM; + int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM, protocol = 0; int state = 0, crl_format = FORMAT_PEM, crl_download = 0; char *host = NULL; char *port = BUF_strdup(PORT); @@ -974,7 +985,7 @@ int s_server_main(int argc, char *argv[]) tlsextalpnctx alpn_ctx = { NULL, 0 }; #ifndef OPENSSL_NO_PSK /* by default do not send a PSK identity hint */ - static char *psk_identity_hint = NULL; + char *psk_identity_hint = NULL; char *p; #endif #ifndef OPENSSL_NO_SRP @@ -991,10 +1002,11 @@ int s_server_main(int argc, char *argv[]) int s_tlsextstatus = 0; #endif int no_resume_ephemeral = 0; + unsigned int max_send_fragment = 0; unsigned int split_send_fragment = 0, max_pipelines = 0; const char *s_serverinfo_file = NULL; const char *keylog_file = NULL; - uint32_t max_early_data = 0; + int max_early_data = -1; /* Init of few remaining global variables */ local_argc = argc; @@ -1340,6 +1352,11 @@ int s_server_main(int argc, char *argv[]) case OPT_NO_RESUME_EPHEMERAL: no_resume_ephemeral = 1; break; + case OPT_PSK_IDENTITY: +#ifndef OPENSSL_NO_PSK + psk_identity = opt_arg(); +#endif + break; case OPT_PSK_HINT: #ifndef OPENSSL_NO_PSK psk_identity_hint = opt_arg(); @@ -1424,6 +1441,11 @@ int s_server_main(int argc, char *argv[]) min_version = DTLS1_2_VERSION; max_version = DTLS1_2_VERSION; socket_type = SOCK_DGRAM; +#endif + break; + case OPT_SCTP: +#ifndef OPENSSL_NO_SCTP + protocol = IPPROTO_SCTP; #endif break; case OPT_TIMEOUT: @@ -1484,15 +1506,11 @@ int s_server_main(int argc, char *argv[]) case OPT_ASYNC: async = 1; break; + case OPT_MAX_SEND_FRAG: + max_send_fragment = atoi(opt_arg()); + break; case OPT_SPLIT_SEND_FRAG: split_send_fragment = atoi(opt_arg()); - if (split_send_fragment == 0) { - /* - * Not allowed - set to a deliberately bad value so we get an - * error message below - */ - split_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH + 1; - } break; case OPT_MAX_PIPELINES: max_pipelines = atoi(opt_arg()); @@ -1505,6 +1523,13 @@ int s_server_main(int argc, char *argv[]) break; case OPT_MAX_EARLY: max_early_data = atoi(opt_arg()); + if (max_early_data < 0) { + BIO_printf(bio_err, "Invalid value for max_early_data\n"); + goto end; + } + break; + case OPT_EARLY_DATA: + early_data = 1; break; } } @@ -1531,15 +1556,16 @@ int s_server_main(int argc, char *argv[]) } #endif - if (split_send_fragment > SSL3_RT_MAX_PLAIN_LENGTH) { - BIO_printf(bio_err, "Bad split send fragment size\n"); - goto end; - } - - if (max_pipelines > SSL_MAX_PIPELINES) { - BIO_printf(bio_err, "Bad max pipelines value\n"); - goto end; +#ifndef OPENSSL_NO_SCTP + if (protocol == IPPROTO_SCTP) { + if (socket_type != SOCK_DGRAM) { + BIO_printf(bio_err, "Can't use -sctp without DTLS\n"); + goto end; + } + /* SCTP is unusual. It uses DTLS over a SOCK_STREAM protocol */ + socket_type = SOCK_STREAM; } +#endif if (!app_passwd(passarg, dpassarg, &pass, &dpass)) { BIO_printf(bio_err, "Error getting password\n"); @@ -1595,22 +1621,16 @@ int s_server_main(int argc, char *argv[]) } #if !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto_neg_in) { - size_t len; - next_proto.data = next_protos_parse(&len, next_proto_neg_in); + next_proto.data = next_protos_parse(&next_proto.len, next_proto_neg_in); if (next_proto.data == NULL) goto end; - next_proto.len = len; - } else { - next_proto.data = NULL; } #endif alpn_ctx.data = NULL; if (alpn_in) { - size_t len; - alpn_ctx.data = next_protos_parse(&len, alpn_in); + alpn_ctx.data = next_protos_parse(&alpn_ctx.len, alpn_in); if (alpn_ctx.data == NULL) goto end; - alpn_ctx.len = len; } if (crl_file) { @@ -1735,11 +1755,25 @@ int s_server_main(int argc, char *argv[]) if (async) { SSL_CTX_set_mode(ctx, SSL_MODE_ASYNC); } - if (split_send_fragment > 0) { - SSL_CTX_set_split_send_fragment(ctx, split_send_fragment); + + if (max_send_fragment > 0 + && !SSL_CTX_set_max_send_fragment(ctx, max_send_fragment)) { + BIO_printf(bio_err, "%s: Max send fragment size %u is out of permitted range\n", + prog, max_send_fragment); + goto end; } - if (max_pipelines > 0) { - SSL_CTX_set_max_pipelines(ctx, max_pipelines); + + if (split_send_fragment > 0 + && !SSL_CTX_set_split_send_fragment(ctx, split_send_fragment)) { + BIO_printf(bio_err, "%s: Split send fragment size %u is out of permitted range\n", + prog, split_send_fragment); + goto end; + } + if (max_pipelines > 0 + && !SSL_CTX_set_max_pipelines(ctx, max_pipelines)) { + BIO_printf(bio_err, "%s: Max pipelines %u is out of permitted range\n", + prog, max_pipelines); + goto end; } if (read_buf_len > 0) { @@ -1996,7 +2030,7 @@ int s_server_main(int argc, char *argv[]) if (set_keylog_file(ctx, keylog_file)) goto end; - if (max_early_data > 0) + if (max_early_data >= 0) SSL_CTX_set_max_early_data(ctx, max_early_data); BIO_printf(bio_s_out, "ACCEPT\n"); @@ -2012,7 +2046,7 @@ int s_server_main(int argc, char *argv[]) && unlink_unix_path) unlink(host); #endif - do_server(&accept_socket, host, port, socket_family, socket_type, + do_server(&accept_socket, host, port, socket_family, socket_type, protocol, server_cb, context, naccept); print_stats(bio_s_out, ctx); ret = 0; @@ -2084,7 +2118,7 @@ static void print_stats(BIO *bio, SSL_CTX *ssl_ctx) SSL_CTX_sess_get_cache_size(ssl_ctx)); } -static int sv_body(int s, int stype, unsigned char *context) +static int sv_body(int s, int stype, int prot, unsigned char *context) { char *buf = NULL; fd_set readfds; @@ -2098,6 +2132,13 @@ static int sv_body(int s, int stype, unsigned char *context) struct timeval tv; #else struct timeval *timeoutp; +#endif +#ifndef OPENSSL_NO_DTLS +# ifndef OPENSSL_NO_SCTP + int isdtls = (stype == SOCK_DGRAM || prot == IPPROTO_SCTP); +# else + int isdtls = (stype == SOCK_DGRAM); +# endif #endif buf = app_malloc(bufsize, "server buffer"); @@ -2130,9 +2171,13 @@ static int sv_body(int s, int stype, unsigned char *context) goto err; } #ifndef OPENSSL_NO_DTLS - if (stype == SOCK_DGRAM) { - - sbio = BIO_new_dgram(s, BIO_NOCLOSE); + if (isdtls) { +# ifndef OPENSSL_NO_SCTP + if (prot == IPPROTO_SCTP) + sbio = BIO_new_dgram_sctp(s, BIO_NOCLOSE); + else +# endif + sbio = BIO_new_dgram(s, BIO_NOCLOSE); if (enable_timeouts) { timeout.tv_sec = 0; @@ -2163,12 +2208,22 @@ static int sv_body(int s, int stype, unsigned char *context) /* want to do MTU discovery */ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); - /* turn on cookie exchange */ - SSL_set_options(con, SSL_OP_COOKIE_EXCHANGE); +# ifndef OPENSSL_NO_SCTP + if (prot != IPPROTO_SCTP) { + /* Turn on cookie exchange. Not necessary for SCTP */ + SSL_set_options(con, SSL_OP_COOKIE_EXCHANGE); + } +# endif } else #endif sbio = BIO_new_socket(s, BIO_NOCLOSE); + if (sbio == NULL) { + BIO_printf(bio_err, "Unable to create BIO\n"); + ERR_print_errors(bio_err); + goto err; + } + if (s_nbio_test) { BIO *test; @@ -2199,6 +2254,45 @@ static int sv_body(int s, int stype, unsigned char *context) SSL_set_tlsext_debug_arg(con, bio_s_out); } + if (early_data) { + int write_header = 1, edret = SSL_READ_EARLY_DATA_ERROR; + size_t readbytes; + + while (edret != SSL_READ_EARLY_DATA_FINISH) { + for (;;) { + edret = SSL_read_early_data(con, buf, bufsize, &readbytes); + if (edret != SSL_READ_EARLY_DATA_ERROR) + break; + + switch (SSL_get_error(con, 0)) { + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_ASYNC: + case SSL_ERROR_WANT_READ: + /* Just keep trying - busy waiting */ + continue; + default: + BIO_printf(bio_err, "Error reading early data\n"); + ERR_print_errors(bio_err); + goto err; + } + } + if (readbytes > 0) { + if (write_header) { + BIO_printf(bio_s_out, "Early data received:\n"); + write_header = 0; + } + raw_write_stdout(buf, (unsigned int)readbytes); + (void)BIO_flush(bio_s_out); + } + } + if (write_header) + BIO_printf(bio_s_out, "No early data received\n"); + else + BIO_printf(bio_s_out, "\nEnd of early data\n"); + if (SSL_is_init_finished(con)) + print_connection_info(con); + } + if (fileno_stdin() > s) width = fileno_stdin() + 1; else @@ -2521,18 +2615,20 @@ static void close_accept_socket(void) } } +static int is_retryable(SSL *con, int i) +{ + int err = SSL_get_error(con, i); + + /* If it's not a fatal error, it must be retryable */ + return (err != SSL_ERROR_SSL) + && (err != SSL_ERROR_SYSCALL) + && (err != SSL_ERROR_ZERO_RETURN); +} + static int init_ssl_connection(SSL *con) { int i; - const char *str; - X509 *peer; long verify_err; - char buf[BUFSIZ]; -#if !defined(OPENSSL_NO_NEXTPROTONEG) - const unsigned char *next_proto_neg; - unsigned next_proto_neg_len; -#endif - unsigned char *exportedkeymat; int retry = 0; #ifndef OPENSSL_NO_DTLS @@ -2571,7 +2667,7 @@ static int init_ssl_connection(SSL *con) i = SSL_accept(con); if (i <= 0) - retry = BIO_sock_should_retry(i); + retry = is_retryable(con, i); #ifdef CERT_CB_TEST_RETRY { while (i <= 0 @@ -2581,7 +2677,7 @@ static int init_ssl_connection(SSL *con) "LOOKUP from certificate callback during accept\n"); i = SSL_accept(con); if (i <= 0) - retry = BIO_sock_should_retry(i); + retry = is_retryable(con, i); } } #endif @@ -2602,7 +2698,7 @@ static int init_ssl_connection(SSL *con) BIO_printf(bio_s_out, "LOOKUP not successful\n"); i = SSL_accept(con); if (i <= 0) - retry = BIO_sock_should_retry(i); + retry = is_retryable(con, i); } #endif } while (i < 0 && SSL_waiting_for_async(con)); @@ -2626,6 +2722,22 @@ static int init_ssl_connection(SSL *con) return (0); } + print_connection_info(con); + return 1; +} + +static void print_connection_info(SSL *con) +{ + const char *str; + X509 *peer; + char buf[BUFSIZ]; +#if !defined(OPENSSL_NO_NEXTPROTONEG) + const unsigned char *next_proto_neg; + unsigned next_proto_neg_len; +#endif + unsigned char *exportedkeymat; + int i; + if (s_brief) print_ssl_summary(con); @@ -2635,10 +2747,7 @@ static int init_ssl_connection(SSL *con) if (peer != NULL) { BIO_printf(bio_s_out, "Client certificate\n"); PEM_write_bio_X509(bio_s_out, peer); - X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof buf); - BIO_printf(bio_s_out, "subject=%s\n", buf); - X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof buf); - BIO_printf(bio_s_out, "issuer=%s\n", buf); + dump_cert_text(bio_s_out, peer); X509_free(peer); peer = NULL; } @@ -2651,6 +2760,7 @@ static int init_ssl_connection(SSL *con) ssl_print_point_formats(bio_s_out, con); ssl_print_groups(bio_s_out, con, 0); #endif + print_ca_names(bio_s_out, con); BIO_printf(bio_s_out, "CIPHER is %s\n", (str != NULL) ? str : "(NONE)"); #if !defined(OPENSSL_NO_NEXTPROTONEG) @@ -2675,6 +2785,9 @@ static int init_ssl_connection(SSL *con) BIO_printf(bio_s_out, "Reused session-id\n"); BIO_printf(bio_s_out, "Secure Renegotiation IS%s supported\n", SSL_get_secure_renegotiation_support(con) ? "" : " NOT"); + if ((SSL_get_options(con) & SSL_OP_NO_RENEGOTIATION)) + BIO_printf(bio_s_out, "Renegotiation is DISABLED\n"); + if (keymatexportlabel != NULL) { BIO_printf(bio_s_out, "Keying material exporter:\n"); BIO_printf(bio_s_out, " Label: '%s'\n", keymatexportlabel); @@ -2696,7 +2809,6 @@ static int init_ssl_connection(SSL *con) } (void)BIO_flush(bio_s_out); - return (1); } #ifndef OPENSSL_NO_DH @@ -2714,7 +2826,7 @@ static DH *load_dh_param(const char *dhfile) } #endif -static int www_body(int s, int stype, unsigned char *context) +static int www_body(int s, int stype, int prot, unsigned char *context) { char *buf = NULL; int ret = 1; @@ -2938,6 +3050,7 @@ static int www_body(int s, int stype, unsigned char *context) #ifndef OPENSSL_NO_EC ssl_print_groups(io, con, 0); #endif + print_ca_names(io, con); BIO_printf(io, (SSL_session_reused(con) ? "---\nReused, " : "---\nNew, ")); c = SSL_get_current_cipher(con); @@ -3099,7 +3212,7 @@ static int www_body(int s, int stype, unsigned char *context) return (ret); } -static int rev_body(int s, int stype, unsigned char *context) +static int rev_body(int s, int stype, int prot, unsigned char *context) { char *buf = NULL; int i;