X-Git-Url: https://git.openssl.org/?a=blobdiff_plain;f=apps%2Fs_server.c;h=c81e572267b172d230407dc060c0eb879f2b379f;hb=8baa49aeac0d51504b8bcd0fd5c750c17af6fe62;hp=12792e9643ffc0a4c5f83a36898c10e91b7f78df;hpb=f2ff1432fc50e5033471859dc9899eb219278a7a;p=openssl.git diff --git a/apps/s_server.c b/apps/s_server.c index 12792e9643..c81e572267 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -1,44 +1,14 @@ /* - * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved + * Copyright 2005 Nokia. All rights reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ -/* ==================================================================== - * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. - * ECC cipher suite support in OpenSSL originally developed by - * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. - */ -/* ==================================================================== - * 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 @@ -65,10 +35,9 @@ typedef unsigned int u_int; #endif -#include #include -#define USE_SOCKETS #include "apps.h" +#include "progs.h" #include #include #include @@ -89,15 +58,16 @@ typedef unsigned int u_int; #ifdef CHARSET_EBCDIC #include #endif +#include "internal/sockets.h" 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); -static int generate_session_id(const SSL *ssl, unsigned char *id, +static int generate_session_id(SSL *ssl, unsigned char *id, unsigned int *id_len); static void init_session_cache_ctx(SSL_CTX *sctx); static void free_sessions(void); @@ -138,15 +108,24 @@ static const char *session_id_prefix = NULL; #ifndef OPENSSL_NO_DTLS static int enable_timeouts = 0; static long socket_mtu; -static int dtlslisten = 0; #endif +/* + * We define this but make it always be 0 in no-dtls builds to simplify the + * code. + */ +static int dtlslisten = 0; +static int stateless = 0; + static int early_data = 0; +static SSL_SESSION *psksess = NULL; -#ifndef OPENSSL_NO_PSK -static const char psk_identity[] = "Client_identity"; +static char *psk_identity = "Client_identity"; char *psk_key = NULL; /* by default PSK is not used */ +static char http_server_binmode = 0; /* for now: 0/1 = default/binary */ + +#ifndef OPENSSL_NO_PSK static unsigned int psk_server_cb(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len) @@ -156,7 +135,7 @@ static unsigned int psk_server_cb(SSL *ssl, const char *identity, if (s_debug) BIO_printf(bio_s_out, "psk_server_cb\n"); - if (!identity) { + if (identity == NULL) { BIO_printf(bio_err, "Error: client did not send PSK identity\n"); goto out_err; } @@ -166,12 +145,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); @@ -203,6 +182,55 @@ static unsigned int psk_server_cb(SSL *ssl, const char *identity, } #endif +static int psk_find_session_cb(SSL *ssl, const unsigned char *identity, + size_t identity_len, SSL_SESSION **sess) +{ + SSL_SESSION *tmpsess = NULL; + unsigned char *key; + long key_len; + const SSL_CIPHER *cipher = NULL; + + if (strlen(psk_identity) != identity_len + || memcmp(psk_identity, identity, identity_len) != 0) { + *sess = NULL; + return 1; + } + + if (psksess != NULL) { + SSL_SESSION_up_ref(psksess); + *sess = psksess; + return 1; + } + + key = OPENSSL_hexstr2buf(psk_key, &key_len); + if (key == NULL) { + BIO_printf(bio_err, "Could not convert PSK key '%s' to buffer\n", + psk_key); + return 0; + } + + /* We default to SHA256 */ + cipher = SSL_CIPHER_find(ssl, tls13_aes128gcmsha256_id); + if (cipher == NULL) { + BIO_printf(bio_err, "Error finding suitable ciphersuite\n"); + OPENSSL_free(key); + return 0; + } + + tmpsess = SSL_SESSION_new(); + if (tmpsess == NULL + || !SSL_SESSION_set1_master_key(tmpsess, key, key_len) + || !SSL_SESSION_set_cipher(tmpsess, cipher) + || !SSL_SESSION_set_protocol_version(tmpsess, SSL_version(ssl))) { + OPENSSL_free(key); + return 0; + } + OPENSSL_free(key); + *sess = tmpsess; + + return 1; +} + #ifndef OPENSSL_NO_SRP /* This is a context that we pass to callbacks */ typedef struct srpsrvparm_st { @@ -210,6 +238,7 @@ typedef struct srpsrvparm_st { SRP_VBASE *vb; SRP_user_pwd *user; } srpsrvparm; +static srpsrvparm srp_callback_parm; /* * This callback pretends to require some asynchronous logic in order to @@ -227,7 +256,7 @@ static int ssl_srp_server_param_cb(SSL *s, int *ad, void *arg) if (p->login == NULL && p->user == NULL) { p->login = SSL_get_srp_username(s); BIO_printf(bio_err, "SRP username = \"%s\"\n", p->login); - return (-1); + return -1; } if (p->user == NULL) { @@ -327,9 +356,9 @@ static int ebcdic_read(BIO *b, char *out, int outl) BIO *next = BIO_next(b); if (out == NULL || outl == 0) - return (0); + return 0; if (next == NULL) - return (0); + return 0; ret = BIO_read(next, out, outl); if (ret > 0) @@ -345,7 +374,7 @@ static int ebcdic_write(BIO *b, const char *in, int inl) int num; if ((in == NULL) || (inl <= 0)) - return (0); + return 0; if (next == NULL) return 0; @@ -368,7 +397,7 @@ static int ebcdic_write(BIO *b, const char *in, int inl) ret = BIO_write(next, wbuf->buff, inl); - return (ret); + return ret; } static long ebcdic_ctrl(BIO *b, int cmd, long num, void *ptr) @@ -377,7 +406,7 @@ static long ebcdic_ctrl(BIO *b, int cmd, long num, void *ptr) BIO *next = BIO_next(b); if (next == NULL) - return (0); + return 0; switch (cmd) { case BIO_CTRL_DUP: ret = 0L; @@ -386,7 +415,7 @@ static long ebcdic_ctrl(BIO *b, int cmd, long num, void *ptr) ret = BIO_ctrl(next, cmd, num, ptr); break; } - return (ret); + return ret; } static int ebcdic_gets(BIO *bp, char *buf, int size) @@ -430,17 +459,25 @@ static int ssl_servername_cb(SSL *s, int *ad, void *arg) { tlsextctx *p = (tlsextctx *) arg; const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); - if (servername && p->biodebug) - BIO_printf(p->biodebug, "Hostname in TLS extension: \"%s\"\n", - servername); - if (!p->servername) + if (servername != NULL && p->biodebug != NULL) { + const char *cp = servername; + unsigned char uc; + + BIO_printf(p->biodebug, "Hostname in TLS extension: \""); + while ((uc = *cp++) != 0) + BIO_printf(p->biodebug, + (((uc) & ~127) == 0) && isprint(uc) ? "%c" : "\\x%02x", uc); + BIO_printf(p->biodebug, "\"\n"); + } + + if (p->servername == NULL) return SSL_TLSEXT_ERR_NOACK; - if (servername) { + if (servername != NULL) { if (strcasecmp(servername, p->servername)) return p->extension_error; - if (ctx2) { + if (ctx2 != NULL) { BIO_printf(p->biodebug, "Switching server context.\n"); SSL_set_SSL_CTX(s, ctx2); } @@ -488,7 +525,7 @@ static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, /* Build up OCSP query from server certificate */ x = SSL_get_certificate(s); aia = X509_get1_ocsp(x); - if (aia) { + if (aia != NULL) { if (!OCSP_parse_url(sk_OPENSSL_STRING_value(aia, 0), &host, &port, &path, &use_ssl)) { BIO_puts(bio_err, "cert_status: can't parse AIA URL\n"); @@ -498,7 +535,7 @@ static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, BIO_printf(bio_err, "cert_status: AIA URL: %s\n", sk_OPENSSL_STRING_value(aia, 0)); } else { - if (!srctx->host) { + if (srctx->host == NULL) { BIO_puts(bio_err, "cert_status: no AIA and no default responder URL\n"); goto done; @@ -524,7 +561,7 @@ static int get_ocsp_resp_from_responder(SSL *s, tlsextstatusctx *srctx, } id = OCSP_cert_to_id(NULL, x, X509_OBJECT_get0_X509(obj)); X509_OBJECT_free(obj); - if (!id) + if (id == NULL) goto err; req = OCSP_REQUEST_new(); if (req == NULL) @@ -688,13 +725,6 @@ static int not_resumable_sess_cb(SSL *s, int is_forward_secure) return is_forward_secure; } -#ifndef OPENSSL_NO_SRP -static srpsrvparm srp_callback_parm; -#endif -#ifndef OPENSSL_NO_SRTP -static char *srtp_profiles = NULL; -#endif - typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_ENGINE, OPT_4, OPT_6, OPT_ACCEPT, OPT_PORT, OPT_UNIX, OPT_UNLINK, OPT_NACCEPT, @@ -705,57 +735,88 @@ typedef enum OPTION_choice { OPT_CAPATH, OPT_NOCAPATH, OPT_CHAINCAPATH, OPT_VERIFYCAPATH, OPT_NO_CACHE, OPT_EXT_CACHE, OPT_CRLFORM, OPT_VERIFY_RET_ERROR, OPT_VERIFY_QUIET, OPT_BUILD_CHAIN, OPT_CAFILE, OPT_NOCAFILE, OPT_CHAINCAFILE, - OPT_VERIFYCAFILE, OPT_NBIO, OPT_NBIO_TEST, OPT_IGN_EOF, OPT_NO_IGN_EOF, + OPT_VERIFYCAFILE, + OPT_CASTORE, OPT_NOCASTORE, OPT_CHAINCASTORE, OPT_VERIFYCASTORE, + OPT_NBIO, OPT_NBIO_TEST, OPT_IGN_EOF, OPT_NO_IGN_EOF, OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_STATUS, OPT_STATUS_VERBOSE, 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_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_NO_RESUME_EPHEMERAL, OPT_PSK_IDENTITY, OPT_PSK_HINT, OPT_PSK, + OPT_PSK_SESS, OPT_SRPVFILE, OPT_SRPUSERSEED, OPT_REV, OPT_WWW, + OPT_UPPER_WWW, OPT_HTTP, OPT_ASYNC, 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_ID_PREFIX, OPT_RAND, OPT_SERVERNAME, OPT_SERVERNAME_FATAL, + OPT_DTLS1_2, OPT_SCTP, OPT_TIMEOUT, OPT_MTU, OPT_LISTEN, OPT_STATELESS, + OPT_ID_PREFIX, 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_EARLY_DATA, + OPT_KEYLOG_FILE, OPT_MAX_EARLY, OPT_RECV_MAX_EARLY, OPT_EARLY_DATA, + OPT_S_NUM_TICKETS, OPT_ANTI_REPLAY, OPT_NO_ANTI_REPLAY, OPT_SCTP_LABEL_BUG, + OPT_HTTP_SERVER_BINMODE, + OPT_R_ENUM, OPT_S_ENUM, OPT_V_ENUM, OPT_X_ENUM } OPTION_CHOICE; const OPTIONS s_server_options[] = { + OPT_SECTION("General"), {"help", OPT_HELP, '-', "Display this summary"}, + {"ssl_config", OPT_SSL_CONFIG, 's', + "Configure SSL_CTX using the configuration 'val'"}, +#ifndef OPENSSL_NO_SSL_TRACE + {"trace", OPT_TRACE, '-', "trace protocol messages"}, +#endif +#ifndef OPENSSL_NO_ENGINE + {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, +#endif + + OPT_SECTION("Network"), {"port", OPT_PORT, 'p', "TCP/IP port to listen on for connections (default is " PORT ")"}, {"accept", OPT_ACCEPT, 's', "TCP/IP optional host and port to listen on for connections (default is *:" PORT ")"}, #ifdef AF_UNIX {"unix", OPT_UNIX, 's', "Unix domain socket to accept on"}, + {"unlink", OPT_UNLINK, '-', "For -unix, unlink existing socket first"}, #endif {"4", OPT_4, '-', "Use IPv4 only"}, {"6", OPT_6, '-', "Use IPv6 only"}, -#ifdef AF_UNIX - {"unlink", OPT_UNLINK, '-', "For -unix, unlink existing socket first"}, -#endif + + OPT_SECTION("Identity"), {"context", OPT_CONTEXT, 's', "Set session ID context"}, + {"CAfile", OPT_CAFILE, '<', "PEM format file of CA's"}, + {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"}, + {"CAstore", OPT_CASTORE, ':', "URI to store of CA's"}, + {"no-CAfile", OPT_NOCAFILE, '-', + "Do not load the default certificates file"}, + {"no-CApath", OPT_NOCAPATH, '-', + "Do not load certificates from the default certificates directory"}, + {"no-CAstore", OPT_NOCASTORE, '-', + "Do not load certificates from the default certificates store URI"}, + {"nocert", OPT_NOCERT, '-', "Don't use any certificates (Anon-DH)"}, {"verify", OPT_VERIFY, 'n', "Turn on peer certificate verification"}, {"Verify", OPT_UPPER_V_VERIFY, 'n', "Turn on peer certificate verification, must have a cert"}, {"cert", OPT_CERT, '<', "Certificate file to use; default is " TEST_CERT}, + {"cert2", OPT_CERT2, '<', + "Certificate file to use for servername; default is" TEST_CERT2}, + {"key2", OPT_KEY2, '<', + "-Private Key file to use for servername if not in -cert2"}, {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"}, - {"naccept", OPT_NACCEPT, 'p', "Terminate after #num connections"}, {"serverinfo", OPT_SERVERINFO, 's', "PEM serverinfo file for certificate"}, {"certform", OPT_CERTFORM, 'F', "Certificate format (PEM or DER) PEM default"}, - {"key", OPT_KEY, '<', + {"key", OPT_KEY, 's', "Private Key if not in -cert; default is " TEST_CERT}, {"keyform", OPT_KEYFORM, 'f', "Key format (PEM, DER or ENGINE) PEM default"}, {"pass", OPT_PASS, 's', "Private key file pass phrase source"}, {"dcert", OPT_DCERT, '<', "Second certificate file to use (usually for DSA)"}, + {"dhparam", OPT_DHPARAM, '<', "DH parameters file to use"}, {"dcertform", OPT_DCERTFORM, 'F', "Second certificate format (PEM or DER) PEM default"}, {"dkey", OPT_DKEY, '<', @@ -763,40 +824,24 @@ const OPTIONS s_server_options[] = { {"dkeyform", OPT_DKEYFORM, 'F', "Second key format (PEM, DER or ENGINE) PEM default"}, {"dpass", OPT_DPASS, 's', "Second private key file pass phrase source"}, + {"servername", OPT_SERVERNAME, 's', + "Servername for HostName TLS extension"}, + {"servername_fatal", OPT_SERVERNAME_FATAL, '-', + "mismatch send fatal alert (default warning alert)"}, + {"nbio_test", OPT_NBIO_TEST, '-', "Test with the non-blocking test bio"}, {"crlf", OPT_CRLF, '-', "Convert LF from terminal into CRLF"}, - {"debug", OPT_DEBUG, '-', "Print more output"}, - {"msg", OPT_MSG, '-', "Show protocol messages"}, - {"msgfile", OPT_MSGFILE, '>', - "File to send output of -msg or -trace, instead of stdout"}, - {"state", OPT_STATE, '-', "Print the SSL states"}, - {"CAfile", OPT_CAFILE, '<', "PEM format file of CA's"}, - {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"}, - {"no-CAfile", OPT_NOCAFILE, '-', - "Do not load the default certificates file"}, - {"no-CApath", OPT_NOCAPATH, '-', - "Do not load certificates from the default certificates directory"}, - {"nocert", OPT_NOCERT, '-', "Don't use any certificates (Anon-DH)"}, + {"quiet", OPT_QUIET, '-', "No server output"}, {"no_resume_ephemeral", OPT_NO_RESUME_EPHEMERAL, '-', "Disable caching and tickets if ephemeral (EC)DH is used"}, {"www", OPT_WWW, '-', "Respond to a 'GET /' with a status page"}, {"WWW", OPT_UPPER_WWW, '-', "Respond to a 'GET with the file ./path"}, - {"servername", OPT_SERVERNAME, 's', - "Servername for HostName TLS extension"}, - {"servername_fatal", OPT_SERVERNAME_FATAL, '-', - "mismatch send fatal alert (default warning alert)"}, - {"cert2", OPT_CERT2, '<', - "Certificate file to use for servername; default is" TEST_CERT2}, - {"key2", OPT_KEY2, '<', - "-Private Key file to use for servername if not in -cert2"}, {"tlsextdebug", OPT_TLSEXTDEBUG, '-', "Hex dump of all TLS extensions received"}, {"HTTP", OPT_HTTP, '-', "Like -WWW but ./path includes HTTP headers"}, {"id_prefix", OPT_ID_PREFIX, 's', "Generate SSL/TLS session IDs prefixed by arg"}, - {"rand", OPT_RAND, 's', - "Load the file(s) into the random number generator"}, {"keymatexport", OPT_KEYMATEXPORT, 's', "Export keying material using label"}, {"keymatexportlen", OPT_KEYMATEXPORTLEN, 'p', @@ -804,14 +849,14 @@ const OPTIONS s_server_options[] = { {"CRL", OPT_CRL, '<', "CRL file to use"}, {"crl_download", OPT_CRL_DOWNLOAD, '-', "Download CRL from distribution points"}, - {"cert_chain", OPT_CERT_CHAIN, '<', - "certificate chain file in PEM format"}, - {"dcert_chain", OPT_DCERT_CHAIN, '<', - "second certificate chain file in PEM format"}, {"chainCApath", OPT_CHAINCAPATH, '/', "use dir as certificate store path to build CA certificate chain"}, + {"chainCAstore", OPT_CHAINCASTORE, ':', + "use URI as certificate store to build CA certificate chain"}, {"verifyCApath", OPT_VERIFYCAPATH, '/', "use dir as certificate store path to verify CA certificate"}, + {"verifyCAstore", OPT_VERIFYCASTORE, ':', + "use URI as certificate store to verify CA certificate"}, {"no_cache", OPT_NO_CACHE, '-', "Disable session cache"}, {"ext_cache", OPT_EXT_CACHE, '-', "Disable internal cache, setup and use external cache"}, @@ -820,14 +865,13 @@ const OPTIONS s_server_options[] = { "Close connection on verification error"}, {"verify_quiet", OPT_VERIFY_QUIET, '-', "No verify output except verify errors"}, - {"build_chain", OPT_BUILD_CHAIN, '-', "Build certificate chain"}, - {"chainCAfile", OPT_CHAINCAFILE, '<', - "CA file for certificate chain (PEM format)"}, {"verifyCAfile", OPT_VERIFYCAFILE, '<', "CA file for certificate verification (PEM format)"}, {"ign_eof", OPT_IGN_EOF, '-', "ignore input eof (default when -quiet)"}, {"no_ign_eof", OPT_NO_IGN_EOF, '-', "Do not ignore input eof"}, + #ifndef OPENSSL_NO_OCSP + OPT_SECTION("OCSP"), {"status", OPT_STATUS, '-', "Request certificate status from server"}, {"status_verbose", OPT_STATUS_VERBOSE, '-', "Print more output in certificate status callback"}, @@ -837,9 +881,8 @@ const OPTIONS s_server_options[] = { {"status_file", OPT_STATUS_FILE, '<', "File containing DER encoded OCSP Response"}, #endif -#ifndef OPENSSL_NO_SSL_TRACE - {"trace", OPT_TRACE, '-', "trace protocol messages"}, -#endif + + OPT_SECTION("Debug"), {"security_debug", OPT_SECURITY_DEBUG, '-', "Print output from SSL/TLS security framework"}, {"security_debug_verbose", OPT_SECURITY_DEBUG_VERBOSE, '-', @@ -848,28 +891,52 @@ const OPTIONS s_server_options[] = { "Restrict output to brief summary of connection parameters"}, {"rev", OPT_REV, '-', "act as a simple test server which just sends back with the received text reversed"}, + {"debug", OPT_DEBUG, '-', "Print more output"}, + {"msg", OPT_MSG, '-', "Show protocol messages"}, + {"msgfile", OPT_MSGFILE, '>', + "File to send output of -msg or -trace, instead of stdout"}, + {"state", OPT_STATE, '-', "Print the SSL states"}, {"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', - "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', - "Default read buffer size to be used for connections"}, - OPT_S_OPTIONS, - OPT_V_OPTIONS, - OPT_X_OPTIONS, + {"naccept", OPT_NACCEPT, 'p', "Terminate after #num connections"}, + {"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"}, + + OPT_SECTION("Network"), {"nbio", OPT_NBIO, '-', "Use non-blocking IO"}, + {"timeout", OPT_TIMEOUT, '-', "Enable timeouts"}, + {"mtu", OPT_MTU, 'p', "Set link layer MTU"}, + {"read_buf", OPT_READ_BUF, 'p', + "Default read buffer size to be used for connections"}, + {"split_send_frag", OPT_SPLIT_SEND_FRAG, 'p', + "Size used to split data for encrypt pipelines"}, + {"max_send_frag", OPT_MAX_SEND_FRAG, 'p', "Maximum Size of send frames "}, + + OPT_SECTION("Server identity"), + {"psk_identity", OPT_PSK_IDENTITY, 's', "PSK identity to expect"}, #ifndef OPENSSL_NO_PSK {"psk_hint", OPT_PSK_HINT, 's', "PSK identity hint to use"}, - {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"}, #endif + {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"}, + {"psk_session", OPT_PSK_SESS, '<', "File to read PSK SSL session from"}, #ifndef OPENSSL_NO_SRP {"srpvfile", OPT_SRPVFILE, '<', "The verifier file for SRP"}, {"srpuserseed", OPT_SRPUSERSEED, 's', "A seed string for a default user salt"}, #endif + + OPT_SECTION("Protocol and version"), + {"max_early_data", OPT_MAX_EARLY, 'n', + "The maximum number of bytes of early data as advertised in tickets"}, + {"recv_max_early_data", OPT_RECV_MAX_EARLY, 'n', + "The maximum number of bytes of early data (hard limit)"}, + {"early_data", OPT_EARLY_DATA, '-', "Attempt to read early data"}, + {"num_tickets", OPT_S_NUM_TICKETS, 'n', + "The number of TLSv1.3 session tickets that a server will automatically issue" }, + {"anti_replay", OPT_ANTI_REPLAY, '-', "Switch on anti-replay protection (default)"}, + {"no_anti_replay", OPT_NO_ANTI_REPLAY, '-', "Switch off anti-replay protection"}, + {"http_server_binmode", OPT_HTTP_SERVER_BINMODE, '-', "opening files in binary mode when acting as http server (-WWW and -HTTP)"}, + {"stateless", OPT_STATELESS, '-', "Require TLSv1.3 cookies"}, #ifndef OPENSSL_NO_SSL3 {"ssl3", OPT_SSL3, '-', "Just talk SSLv3"}, #endif @@ -887,8 +954,6 @@ const OPTIONS s_server_options[] = { #endif #ifndef OPENSSL_NO_DTLS {"dtls", OPT_DTLS, '-', "Use any DTLS version"}, - {"timeout", OPT_TIMEOUT, '-', "Enable timeouts"}, - {"mtu", OPT_MTU, 'p', "Set link layer MTU"}, {"listen", OPT_LISTEN, '-', "Listen for a DTLS ClientHello with a cookie and then connect"}, #endif @@ -898,27 +963,36 @@ 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"}, + {"sctp_label_bug", OPT_SCTP_LABEL_BUG, '-', "Enable SCTP label length bug"}, +#endif +#ifndef OPENSSL_NO_SRTP + {"use_srtp", OPT_SRTP_PROFILES, 's', + "Offer SRTP key management with a colon-separated profile list"}, +#endif #ifndef OPENSSL_NO_DH {"no_dhe", OPT_NO_DHE, '-', "Disable ephemeral DH"}, #endif #ifndef OPENSSL_NO_NEXTPROTONEG {"nextprotoneg", OPT_NEXTPROTONEG, 's', "Set the advertised protocols for the NPN extension (comma-separated list)"}, -#endif -#ifndef OPENSSL_NO_SRTP - {"use_srtp", OPT_SRTP_PROFILES, 's', - "Offer SRTP key management with a colon-separated profile list"}, #endif {"alpn", OPT_ALPN, 's', "Set the advertised protocols for the ALPN extension (comma-separated list)"}, -#ifndef OPENSSL_NO_ENGINE - {"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, 'n', - "The maximum number of bytes of early data"}, - {"early_data", OPT_EARLY_DATA, '-', "Attempt to read early data"}, - {NULL, OPT_EOF, 0, NULL} + + OPT_R_OPTIONS, + OPT_S_OPTIONS, + OPT_V_OPTIONS, + {"cert_chain", OPT_CERT_CHAIN, '<', + "certificate chain file in PEM format"}, + {"dcert_chain", OPT_DCERT_CHAIN, '<', + "second certificate chain file in PEM format"}, + {"build_chain", OPT_BUILD_CHAIN, '-', "Build certificate chain"}, + {"chainCAfile", OPT_CHAINCAFILE, '<', + "CA file for certificate chain (PEM format)"}, + OPT_X_OPTIONS, + {NULL} }; #define IS_PROT_FLAG(o) \ @@ -937,9 +1011,11 @@ int s_server_main(int argc, char *argv[]) STACK_OF(X509_CRL) *crls = NULL; X509 *s_cert = NULL, *s_dcert = NULL; X509_VERIFY_PARAM *vpm = NULL; - const char *CApath = NULL, *CAfile = NULL, *chCApath = NULL, *chCAfile = NULL; - char *dpassarg = NULL, *dpass = NULL, *inrand = NULL; - char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL; + const char *CApath = NULL, *CAfile = NULL, *CAstore = NULL; + const char *chCApath = NULL, *chCAfile = NULL, *chCAstore = NULL; + char *dpassarg = NULL, *dpass = NULL; + char *passarg = NULL, *pass = NULL; + char *vfyCApath = NULL, *vfyCAfile = NULL, *vfyCAstore = NULL; char *crl_file = NULL, *prog; #ifdef AF_UNIX int unlink_unix_path = 0; @@ -951,14 +1027,14 @@ int s_server_main(int argc, char *argv[]) int no_dhe = 0; #endif int nocert = 0, ret = 1; - int noCApath = 0, noCAfile = 0; + int noCApath = 0, noCAfile = 0, noCAstore = 0; 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); + char *port = OPENSSL_strdup(PORT); unsigned char *context = NULL; OPTION_CHOICE o; EVP_PKEY *s_key2 = NULL; @@ -975,11 +1051,14 @@ int s_server_main(int argc, char *argv[]) #ifndef OPENSSL_NO_PSK /* by default do not send a PSK identity hint */ char *psk_identity_hint = NULL; - char *p; #endif + char *p; #ifndef OPENSSL_NO_SRP char *srpuserseed = NULL; char *srp_verifier_file = NULL; +#endif +#ifndef OPENSSL_NO_SRTP + char *srtp_profiles = NULL; #endif int min_version = 0, max_version = 0, prot_opt = 0, no_prot_opt = 0; int s_server_verify = SSL_VERIFY_NONE; @@ -991,10 +1070,15 @@ 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; - int max_early_data = -1; + int max_early_data = -1, recv_max_early_data = -1; + char *psksessf = NULL; +#ifndef OPENSSL_NO_SCTP + int sctp_label_bug = 0; +#endif /* Init of few remaining global variables */ local_argc = argc; @@ -1099,7 +1183,7 @@ int s_server_main(int argc, char *argv[]) #ifdef AF_UNIX case OPT_UNIX: socket_family = AF_UNIX; - OPENSSL_free(host); host = BUF_strdup(opt_arg()); + OPENSSL_free(host); host = OPENSSL_strdup(opt_arg()); OPENSSL_free(port); port = NULL; break; case OPT_UNLINK: @@ -1201,6 +1285,18 @@ int s_server_main(int argc, char *argv[]) case OPT_VERIFYCAPATH: vfyCApath = opt_arg(); break; + case OPT_CASTORE: + CAstore = opt_arg(); + break; + case OPT_NOCASTORE: + noCAstore = 1; + break; + case OPT_CHAINCASTORE: + chCAstore = opt_arg(); + break; + case OPT_VERIFYCASTORE: + vfyCAstore = opt_arg(); + break; case OPT_NO_CACHE: no_cache = 1; break; @@ -1212,6 +1308,9 @@ int s_server_main(int argc, char *argv[]) goto opthelp; break; case OPT_S_CASES: + case OPT_S_NUM_TICKETS: + case OPT_ANTI_REPLAY: + case OPT_NO_ANTI_REPLAY: if (ssl_args == NULL) ssl_args = sk_OPENSSL_STRING_new_null(); if (ssl_args == NULL @@ -1340,20 +1439,24 @@ int s_server_main(int argc, char *argv[]) case OPT_NO_RESUME_EPHEMERAL: no_resume_ephemeral = 1; break; + case OPT_PSK_IDENTITY: + psk_identity = opt_arg(); + break; case OPT_PSK_HINT: #ifndef OPENSSL_NO_PSK psk_identity_hint = opt_arg(); #endif break; case OPT_PSK: -#ifndef OPENSSL_NO_PSK for (p = psk_key = opt_arg(); *p; p++) { if (isxdigit(_UC(*p))) continue; - BIO_printf(bio_err, "Not a hex number '%s'\n", *argv); + BIO_printf(bio_err, "Not a hex number '%s'\n", psk_key); goto end; } -#endif + break; + case OPT_PSK_SESS: + psksessf = opt_arg(); break; case OPT_SRPVFILE: #ifndef OPENSSL_NO_SRP @@ -1424,6 +1527,16 @@ 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_SCTP_LABEL_BUG: +#ifndef OPENSSL_NO_SCTP + sctp_label_bug = 1; #endif break; case OPT_TIMEOUT: @@ -1441,14 +1554,18 @@ int s_server_main(int argc, char *argv[]) dtlslisten = 1; #endif break; + case OPT_STATELESS: + stateless = 1; + break; case OPT_ID_PREFIX: session_id_prefix = opt_arg(); break; case OPT_ENGINE: engine = setup_engine(opt_arg(), 1); break; - case OPT_RAND: - inrand = opt_arg(); + case OPT_R_CASES: + if (!opt_rand(o)) + goto end; break; case OPT_SERVERNAME: tlsextcbp.servername = opt_arg(); @@ -1484,15 +1601,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()); @@ -1510,14 +1623,32 @@ int s_server_main(int argc, char *argv[]) goto end; } break; + case OPT_RECV_MAX_EARLY: + recv_max_early_data = atoi(opt_arg()); + if (recv_max_early_data < 0) { + BIO_printf(bio_err, "Invalid value for recv_max_early_data\n"); + goto end; + } + break; case OPT_EARLY_DATA: early_data = 1; + if (max_early_data == -1) + max_early_data = SSL3_RT_MAX_PLAIN_LENGTH; + break; + case OPT_HTTP_SERVER_BINMODE: + http_server_binmode = 1; break; } } argc = opt_num_rest(); argv = opt_rest(); +#ifndef OPENSSL_NO_NEXTPROTONEG + if (min_version == TLS1_3_VERSION && next_proto_neg_in != NULL) { + BIO_printf(bio_err, "Cannot supply -nextprotoneg with TLSv1.3\n"); + goto opthelp; + } +#endif #ifndef OPENSSL_NO_DTLS if (www && socket_type == SOCK_DGRAM) { BIO_printf(bio_err, "Can't use -HTTP, -www or -WWW with DTLS\n"); @@ -1530,6 +1661,11 @@ int s_server_main(int argc, char *argv[]) } #endif + if (stateless && socket_type != SOCK_STREAM) { + BIO_printf(bio_err, "Can only use --stateless with TLS\n"); + goto end; + } + #ifdef AF_UNIX if (socket_family == AF_UNIX && socket_type != SOCK_STREAM) { BIO_printf(bio_err, @@ -1537,16 +1673,22 @@ int s_server_main(int argc, char *argv[]) goto end; } #endif - - if (split_send_fragment > SSL3_RT_MAX_PLAIN_LENGTH) { - BIO_printf(bio_err, "Bad split send fragment size\n"); + if (early_data && (www > 0 || rev)) { + BIO_printf(bio_err, + "Can't use -early_data in combination with -www, -WWW, -HTTP, or -rev\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"); @@ -1565,7 +1707,7 @@ int s_server_main(int argc, char *argv[]) if (nocert == 0) { s_key = load_key(s_key_file, s_key_format, 0, pass, engine, "server certificate private key file"); - if (!s_key) { + if (s_key == NULL) { ERR_print_errors(bio_err); goto end; } @@ -1573,20 +1715,20 @@ int s_server_main(int argc, char *argv[]) s_cert = load_cert(s_cert_file, s_cert_format, "server certificate file"); - if (!s_cert) { + if (s_cert == NULL) { ERR_print_errors(bio_err); goto end; } - if (s_chain_file) { + if (s_chain_file != NULL) { if (!load_certs(s_chain_file, &s_chain, FORMAT_PEM, NULL, "server certificate chain")) goto end; } - if (tlsextcbp.servername) { + if (tlsextcbp.servername != NULL) { s_key2 = load_key(s_key_file2, s_key_format, 0, pass, engine, "second server certificate private key file"); - if (!s_key2) { + if (s_key2 == NULL) { ERR_print_errors(bio_err); goto end; } @@ -1594,7 +1736,7 @@ int s_server_main(int argc, char *argv[]) s_cert2 = load_cert(s_cert_file2, s_cert_format, "second server certificate file"); - if (!s_cert2) { + if (s_cert2 == NULL) { ERR_print_errors(bio_err); goto end; } @@ -1614,16 +1756,16 @@ int s_server_main(int argc, char *argv[]) goto end; } - if (crl_file) { + if (crl_file != NULL) { X509_CRL *crl; crl = load_crl(crl_file, crl_format); - if (!crl) { + if (crl == NULL) { BIO_puts(bio_err, "Error loading CRL\n"); ERR_print_errors(bio_err); goto end; } crls = sk_X509_CRL_new_null(); - if (!crls || !sk_X509_CRL_push(crls, crl)) { + if (crls == NULL || !sk_X509_CRL_push(crls, crl)) { BIO_puts(bio_err, "Error adding CRL\n"); ERR_print_errors(bio_err); X509_CRL_free(crl); @@ -1631,14 +1773,14 @@ int s_server_main(int argc, char *argv[]) } } - if (s_dcert_file) { + if (s_dcert_file != NULL) { if (s_dkey_file == NULL) s_dkey_file = s_dcert_file; s_dkey = load_key(s_dkey_file, s_dkey_format, 0, dpass, engine, "second certificate private key file"); - if (!s_dkey) { + if (s_dkey == NULL) { ERR_print_errors(bio_err); goto end; } @@ -1646,11 +1788,11 @@ int s_server_main(int argc, char *argv[]) s_dcert = load_cert(s_dcert_file, s_dcert_format, "second server certificate file"); - if (!s_dcert) { + if (s_dcert == NULL) { ERR_print_errors(bio_err); goto end; } - if (s_dchain_file) { + if (s_dchain_file != NULL) { if (!load_certs(s_dchain_file, &s_dchain, FORMAT_PEM, NULL, "second server certificate chain")) goto end; @@ -1658,19 +1800,10 @@ int s_server_main(int argc, char *argv[]) } - if (!app_RAND_load_file(NULL, 1) && inrand == NULL - && !RAND_status()) { - BIO_printf(bio_err, - "warning, not much extra random data, consider using the -rand option\n"); - } - if (inrand != NULL) - BIO_printf(bio_err, "%ld semi-random bytes loaded\n", - app_RAND_load_files(inrand)); - if (bio_s_out == NULL) { if (s_quiet && !s_debug) { bio_s_out = BIO_new(BIO_s_null()); - if (s_msg && !bio_s_msg) + if (s_msg && bio_s_msg == NULL) bio_s_msg = dup_bio_out(FORMAT_TEXT); } else { if (bio_s_out == NULL) @@ -1694,8 +1827,15 @@ int s_server_main(int argc, char *argv[]) ERR_print_errors(bio_err); goto end; } + + SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY); + if (sdebug) ssl_ctx_security_debug(ctx, sdebug); + + if (!config_ctx(cctx, ssl_args, ctx)) + goto end; + if (ssl_config) { if (SSL_CTX_config(ctx, ssl_config) == 0) { BIO_printf(bio_err, "Error using configuration \"%s\"\n", @@ -1704,9 +1844,17 @@ int s_server_main(int argc, char *argv[]) goto end; } } - if (SSL_CTX_set_min_proto_version(ctx, min_version) == 0) + +#ifndef OPENSSL_NO_SCTP + if (protocol == IPPROTO_SCTP && sctp_label_bug == 1) + SSL_CTX_set_mode(ctx, SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG); +#endif + + if (min_version != 0 + && SSL_CTX_set_min_proto_version(ctx, min_version) == 0) goto end; - if (SSL_CTX_set_max_proto_version(ctx, max_version) == 0) + if (max_version != 0 + && SSL_CTX_set_max_proto_version(ctx, max_version) == 0) goto end; if (session_id_prefix) { @@ -1721,7 +1869,7 @@ int s_server_main(int argc, char *argv[]) BIO_printf(bio_err, "id_prefix '%s' set.\n", session_id_prefix); } SSL_CTX_set_quiet_shutdown(ctx, 1); - if (exc) + if (exc != NULL) ssl_ctx_set_excert(ctx, exc); if (state) @@ -1736,11 +1884,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 (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); + 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) { @@ -1757,7 +1919,8 @@ int s_server_main(int argc, char *argv[]) } #endif - if (!ctx_set_verify_locations(ctx, CAfile, CApath, noCAfile, noCApath)) { + if (!ctx_set_verify_locations(ctx, CAfile, noCAfile, CApath, noCApath, + CAstore, noCAstore)) { ERR_print_errors(bio_err); goto end; } @@ -1768,10 +1931,10 @@ int s_server_main(int argc, char *argv[]) } ssl_ctx_add_crls(ctx, crls, 0); - if (!config_ctx(cctx, ssl_args, ctx)) - goto end; - if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile, + if (!ssl_load_stores(ctx, + vfyCApath, vfyCAfile, vfyCAstore, + chCApath, chCAfile, chCAstore, crls, crl_download)) { BIO_printf(bio_err, "Error loading store locations\n"); ERR_print_errors(bio_err); @@ -1786,7 +1949,7 @@ int s_server_main(int argc, char *argv[]) } } - if (ctx2) { + if (ctx2 != NULL) { BIO_printf(bio_s_out, "Setting secondary ctx parameters\n"); if (sdebug) @@ -1804,7 +1967,7 @@ int s_server_main(int argc, char *argv[]) BIO_printf(bio_err, "id_prefix '%s' set.\n", session_id_prefix); } SSL_CTX_set_quiet_shutdown(ctx2, 1); - if (exc) + if (exc != NULL) ssl_ctx_set_excert(ctx2, exc); if (state) @@ -1820,8 +1983,8 @@ int s_server_main(int argc, char *argv[]) if (async) SSL_CTX_set_mode(ctx2, SSL_MODE_ASYNC); - if (!ctx_set_verify_locations(ctx2, CAfile, CApath, noCAfile, - noCApath)) { + if (!ctx_set_verify_locations(ctx2, CAfile, noCAfile, CApath, + noCApath, CAstore, noCAstore)) { ERR_print_errors(bio_err); goto end; } @@ -1847,9 +2010,9 @@ int s_server_main(int argc, char *argv[]) if (!no_dhe) { DH *dh = NULL; - if (dhfile) + if (dhfile != NULL) dh = load_dh_param(dhfile); - else if (s_cert_file) + else if (s_cert_file != NULL) dh = load_dh_param(s_cert_file); if (dh != NULL) { @@ -1859,16 +2022,16 @@ int s_server_main(int argc, char *argv[]) } (void)BIO_flush(bio_s_out); - if (dh == NULL) + if (dh == NULL) { SSL_CTX_set_dh_auto(ctx, 1); - else if (!SSL_CTX_set_tmp_dh(ctx, dh)) { + } else if (!SSL_CTX_set_tmp_dh(ctx, dh)) { BIO_puts(bio_err, "Error setting temp DH parameters\n"); ERR_print_errors(bio_err); DH_free(dh); goto end; } - if (ctx2) { + if (ctx2 != NULL) { if (!dhfile) { DH *dh2 = load_dh_param(s_cert_file2); if (dh2 != NULL) { @@ -1879,9 +2042,9 @@ int s_server_main(int argc, char *argv[]) dh = dh2; } } - if (dh == NULL) + if (dh == NULL) { SSL_CTX_set_dh_auto(ctx2, 1); - else if (!SSL_CTX_set_tmp_dh(ctx2, dh)) { + } else if (!SSL_CTX_set_tmp_dh(ctx2, dh)) { BIO_puts(bio_err, "Error setting temp DH parameters\n"); ERR_print_errors(bio_err); DH_free(dh); @@ -1901,7 +2064,8 @@ int s_server_main(int argc, char *argv[]) goto end; } - if (ctx2 && !set_cert_key_stuff(ctx2, s_cert2, s_key2, NULL, build_chain)) + if (ctx2 != NULL + && !set_cert_key_stuff(ctx2, s_cert2, s_key2, NULL, build_chain)) goto end; if (s_dcert != NULL) { @@ -1913,7 +2077,7 @@ int s_server_main(int argc, char *argv[]) SSL_CTX_set_not_resumable_session_callback(ctx, not_resumable_sess_cb); - if (ctx2) + if (ctx2 != NULL) SSL_CTX_set_not_resumable_session_callback(ctx2, not_resumable_sess_cb); } @@ -1930,11 +2094,31 @@ int s_server_main(int argc, char *argv[]) goto end; } #endif + if (psksessf != NULL) { + BIO *stmp = BIO_new_file(psksessf, "r"); + + if (stmp == NULL) { + BIO_printf(bio_err, "Can't open PSK session file %s\n", psksessf); + ERR_print_errors(bio_err); + goto end; + } + psksess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL); + BIO_free(stmp); + if (psksess == NULL) { + BIO_printf(bio_err, "Can't read PSK session file %s\n", psksessf); + ERR_print_errors(bio_err); + goto end; + } + + } + + if (psk_key != NULL || psksess != NULL) + SSL_CTX_set_psk_find_session_callback(ctx, psk_find_session_cb); SSL_CTX_set_verify(ctx, s_server_verify, verify_callback); if (!SSL_CTX_set_session_id_context(ctx, (void *)&s_server_session_id_context, - sizeof s_server_session_id_context)) { + sizeof(s_server_session_id_context))) { BIO_printf(bio_err, "error setting session id context\n"); ERR_print_errors(bio_err); goto end; @@ -1944,11 +2128,15 @@ int s_server_main(int argc, char *argv[]) SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie_callback); SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie_callback); - if (ctx2) { + /* Set TLS1.3 cookie generation and verification callbacks */ + SSL_CTX_set_stateless_cookie_generate_cb(ctx, generate_stateless_cookie_callback); + SSL_CTX_set_stateless_cookie_verify_cb(ctx, verify_stateless_cookie_callback); + + if (ctx2 != NULL) { SSL_CTX_set_verify(ctx2, s_server_verify, verify_callback); if (!SSL_CTX_set_session_id_context(ctx2, (void *)&s_server_session_id_context, - sizeof s_server_session_id_context)) { + sizeof(s_server_session_id_context))) { BIO_printf(bio_err, "error setting session id context\n"); ERR_print_errors(bio_err); goto end; @@ -1999,9 +2187,9 @@ int s_server_main(int argc, char *argv[]) if (max_early_data >= 0) SSL_CTX_set_max_early_data(ctx, max_early_data); + if (recv_max_early_data >= 0) + SSL_CTX_set_recv_max_early_data(ctx, recv_max_early_data); - BIO_printf(bio_s_out, "ACCEPT\n"); - (void)BIO_flush(bio_s_out); if (rev) server_cb = rev_body; else if (www) @@ -2013,12 +2201,13 @@ int s_server_main(int argc, char *argv[]) && unlink_unix_path) unlink(host); #endif - do_server(&accept_socket, host, port, socket_family, socket_type, - server_cb, context, naccept); + do_server(&accept_socket, host, port, socket_family, socket_type, protocol, + server_cb, context, naccept, bio_s_out); print_stats(bio_s_out, ctx); ret = 0; end: SSL_CTX_free(ctx); + SSL_SESSION_free(psksess); set_keylog_file(NULL, NULL); X509_free(s_cert); sk_X509_CRL_pop_free(crls, X509_CRL_free); @@ -2054,7 +2243,7 @@ int s_server_main(int argc, char *argv[]) #ifdef CHARSET_EBCDIC BIO_meth_free(methods_ebcdic); #endif - return (ret); + return ret; } static void print_stats(BIO *bio, SSL_CTX *ssl_ctx) @@ -2085,7 +2274,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; @@ -2095,10 +2284,15 @@ static int sv_body(int s, int stype, unsigned char *context) SSL *con = NULL; BIO *sbio; struct timeval timeout; -#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) - struct timeval tv; -#else +#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS)) 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"); @@ -2109,31 +2303,38 @@ static int sv_body(int s, int stype, unsigned char *context) BIO_printf(bio_err, "Turned on non blocking io\n"); } + con = SSL_new(ctx); if (con == NULL) { - con = SSL_new(ctx); + ret = -1; + goto err; + } - if (s_tlsextdebug) { - SSL_set_tlsext_debug_callback(con, tlsext_cb); - SSL_set_tlsext_debug_arg(con, bio_s_out); - } + if (s_tlsextdebug) { + SSL_set_tlsext_debug_callback(con, tlsext_cb); + SSL_set_tlsext_debug_arg(con, bio_s_out); + } - if (context - && !SSL_set_session_id_context(con, - context, strlen((char *)context))) { - BIO_printf(bio_err, "Error setting session id context\n"); - ret = -1; - goto err; - } + if (context != NULL + && !SSL_set_session_id_context(con, context, + strlen((char *)context))) { + BIO_printf(bio_err, "Error setting session id context\n"); + ret = -1; + goto err; } + if (!SSL_clear(con)) { BIO_printf(bio_err, "Error clearing SSL connection\n"); ret = -1; 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; @@ -2164,12 +2365,21 @@ 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) +# endif + /* Turn on cookie exchange. Not necessary for SCTP */ + SSL_set_options(con, SSL_OP_COOKIE_EXCHANGE); } 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; @@ -2231,10 +2441,14 @@ static int sv_body(int s, int stype, unsigned char *context) (void)BIO_flush(bio_s_out); } } - if (write_header) - BIO_printf(bio_s_out, "No early data received\n"); - else + if (write_header) { + if (SSL_get_early_data_status(con) == SSL_EARLY_DATA_NOT_SENT) + BIO_printf(bio_s_out, "No early data received\n"); + else + BIO_printf(bio_s_out, "Early data was rejected\n"); + } else { BIO_printf(bio_s_out, "\nEnd of early data\n"); + } if (SSL_is_init_finished(con)) print_connection_info(con); } @@ -2271,26 +2485,23 @@ static int sv_body(int s, int stype, unsigned char *context) * second and check for any keypress. In a proper Windows * application we wouldn't do this because it is inefficient. */ - tv.tv_sec = 1; - tv.tv_usec = 0; - i = select(width, (void *)&readfds, NULL, NULL, &tv); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + i = select(width, (void *)&readfds, NULL, NULL, &timeout); if (has_stdin_waiting()) read_from_terminal = 1; if ((i < 0) || (!i && !read_from_terminal)) continue; #else - if ((SSL_version(con) == DTLS1_VERSION) && - DTLSv1_get_timeout(con, &timeout)) + if (SSL_is_dtls(con) && DTLSv1_get_timeout(con, &timeout)) timeoutp = &timeout; else timeoutp = NULL; i = select(width, (void *)&readfds, NULL, NULL, timeoutp); - if ((SSL_version(con) == DTLS1_VERSION) - && DTLSv1_handle_timeout(con) > 0) { + if ((SSL_is_dtls(con)) && DTLSv1_handle_timeout(con) > 0) BIO_printf(bio_err, "TIMEOUT occurred\n"); - } if (i <= 0) continue; @@ -2319,8 +2530,9 @@ static int sv_body(int s, int stype, unsigned char *context) } } assert(lf_num == 0); - } else + } else { i = raw_read_stdin(buf, bufsize); + } if (!s_quiet && !s_brief) { if ((i <= 0) || (buf[0] == 'Q')) { @@ -2341,23 +2553,12 @@ static int sv_body(int s, int stype, unsigned char *context) */ goto err; } -#ifndef OPENSSL_NO_HEARTBEATS - if ((buf[0] == 'B') && ((buf[1] == '\n') || (buf[1] == '\r'))) { - BIO_printf(bio_err, "HEARTBEATING\n"); - SSL_heartbeat(con); - i = 0; - continue; - } -#endif if ((buf[0] == 'r') && ((buf[1] == '\n') || (buf[1] == '\r'))) { SSL_renegotiate(con); i = SSL_do_handshake(con); printf("SSL_do_handshake -> %d\n", i); i = 0; /* 13; */ continue; - /* - * strcpy(buf,"server side RE-NEGOTIATE\n"); - */ } if ((buf[0] == 'R') && ((buf[1] == '\n') || (buf[1] == '\r'))) { SSL_set_verify(con, @@ -2368,10 +2569,6 @@ static int sv_body(int s, int stype, unsigned char *context) printf("SSL_do_handshake -> %d\n", i); i = 0; /* 13; */ continue; - /* - * strcpy(buf,"server side RE-NEGOTIATE asking for client - * cert\n"); - */ } if ((buf[0] == 'K' || buf[0] == 'k') && ((buf[1] == '\n') || (buf[1] == '\r'))) { @@ -2382,14 +2579,23 @@ static int sv_body(int s, int stype, unsigned char *context) printf("SSL_do_handshake -> %d\n", i); i = 0; continue; - /* - * strcpy(buf,"server side RE-NEGOTIATE asking for client - * cert\n"); - */ + } + if (buf[0] == 'c' && ((buf[1] == '\n') || (buf[1] == '\r'))) { + SSL_set_verify(con, SSL_VERIFY_PEER, NULL); + i = SSL_verify_client_post_handshake(con); + if (i == 0) { + printf("Failed to initiate request\n"); + ERR_print_errors(bio_err); + } else { + i = SSL_do_handshake(con); + printf("SSL_do_handshake -> %d\n", i); + i = 0; + } + continue; } if (buf[0] == 'P') { - static const char *str = "Lets print some clear text\n"; - BIO_write(SSL_get_wbio(con), str, strlen(str)); + static const char str[] = "Lets print some clear text\n"; + BIO_write(SSL_get_wbio(con), str, sizeof(str) -1); } if (buf[0] == 'S') { print_stats(bio_s_out, SSL_get_SSL_CTX(con)); @@ -2547,10 +2753,7 @@ static int sv_body(int s, int stype, unsigned char *context) } BIO_printf(bio_s_out, "CONNECTION CLOSED\n"); OPENSSL_clear_free(buf, bufsize); - if (ret >= 0) - BIO_printf(bio_s_out, "ACCEPT\n"); - (void)BIO_flush(bio_s_out); - return (ret); + return ret; } static void close_accept_socket(void) @@ -2561,89 +2764,107 @@ 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; long verify_err; int retry = 0; -#ifndef OPENSSL_NO_DTLS - if (dtlslisten) { + if (dtlslisten || stateless) { BIO_ADDR *client = NULL; - if ((client = BIO_ADDR_new()) == NULL) { - BIO_printf(bio_err, "ERROR - memory\n"); - return 0; + if (dtlslisten) { + if ((client = BIO_ADDR_new()) == NULL) { + BIO_printf(bio_err, "ERROR - memory\n"); + return 0; + } + i = DTLSv1_listen(con, client); + } else { + i = SSL_stateless(con); } - i = DTLSv1_listen(con, client); if (i > 0) { BIO *wbio; int fd = -1; - wbio = SSL_get_wbio(con); - if (wbio) { - BIO_get_fd(wbio, &fd); - } + if (dtlslisten) { + wbio = SSL_get_wbio(con); + if (wbio) { + BIO_get_fd(wbio, &fd); + } - if (!wbio || BIO_connect(fd, client, 0) == 0) { - BIO_printf(bio_err, "ERROR - unable to connect\n"); + if (!wbio || BIO_connect(fd, client, 0) == 0) { + BIO_printf(bio_err, "ERROR - unable to connect\n"); + BIO_ADDR_free(client); + return 0; + } + + (void)BIO_ctrl_set_connected(wbio, client); BIO_ADDR_free(client); - return 0; + dtlslisten = 0; + } else { + stateless = 0; } - BIO_ADDR_free(client); - dtlslisten = 0; i = SSL_accept(con); } else { BIO_ADDR_free(client); } - } else -#endif - - do { - i = SSL_accept(con); + } else { + do { + i = SSL_accept(con); - if (i <= 0) - retry = BIO_sock_should_retry(i); + if (i <= 0) + retry = is_retryable(con, i); #ifdef CERT_CB_TEST_RETRY - { - while (i <= 0 - && SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP - && SSL_get_state(con) == TLS_ST_SR_CLNT_HELLO) { - BIO_printf(bio_err, - "LOOKUP from certificate callback during accept\n"); - i = SSL_accept(con); - if (i <= 0) - retry = BIO_sock_should_retry(i); + { + while (i <= 0 + && SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP + && SSL_get_state(con) == TLS_ST_SR_CLNT_HELLO) { + BIO_printf(bio_err, + "LOOKUP from certificate callback during accept\n"); + i = SSL_accept(con); + if (i <= 0) + retry = is_retryable(con, i); + } } - } #endif #ifndef OPENSSL_NO_SRP - while (i <= 0 - && SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP) { - BIO_printf(bio_s_out, "LOOKUP during accept %s\n", - srp_callback_parm.login); - SRP_user_pwd_free(srp_callback_parm.user); - srp_callback_parm.user = - SRP_VBASE_get1_by_user(srp_callback_parm.vb, - srp_callback_parm.login); - if (srp_callback_parm.user) - BIO_printf(bio_s_out, "LOOKUP done %s\n", - srp_callback_parm.user->info); - else - BIO_printf(bio_s_out, "LOOKUP not successful\n"); - i = SSL_accept(con); - if (i <= 0) - retry = BIO_sock_should_retry(i); - } + while (i <= 0 + && SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP) { + BIO_printf(bio_s_out, "LOOKUP during accept %s\n", + srp_callback_parm.login); + SRP_user_pwd_free(srp_callback_parm.user); + srp_callback_parm.user = + SRP_VBASE_get1_by_user(srp_callback_parm.vb, + srp_callback_parm.login); + if (srp_callback_parm.user) + BIO_printf(bio_s_out, "LOOKUP done %s\n", + srp_callback_parm.user->info); + else + BIO_printf(bio_s_out, "LOOKUP not successful\n"); + i = SSL_accept(con); + if (i <= 0) + retry = is_retryable(con, i); + } #endif - } while (i < 0 && SSL_waiting_for_async(con)); + } while (i < 0 && SSL_waiting_for_async(con)); + } if (i <= 0) { - if ((dtlslisten && i == 0) - || (!dtlslisten && retry)) { + if (((dtlslisten || stateless) && i == 0) + || (!dtlslisten && !stateless && retry)) { BIO_printf(bio_s_out, "DELAY\n"); - return (1); + return 1; } BIO_printf(bio_err, "ERROR\n"); @@ -2655,7 +2876,7 @@ static int init_ssl_connection(SSL *con) } /* Always print any error messages */ ERR_print_errors(bio_err); - return (0); + return 0; } print_connection_info(con); @@ -2683,15 +2904,12 @@ static void print_connection_info(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; } - if (SSL_get_shared_ciphers(con, buf, sizeof buf) != NULL) + if (SSL_get_shared_ciphers(con, buf, sizeof(buf)) != NULL) BIO_printf(bio_s_out, "Shared ciphers:%s\n", buf); str = SSL_CIPHER_get_name(SSL_get_current_cipher(con)); ssl_print_sigalgs(bio_s_out, con); @@ -2699,6 +2917,7 @@ static void print_connection_info(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) @@ -2723,6 +2942,9 @@ static void print_connection_info(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); @@ -2742,6 +2964,12 @@ static void print_connection_info(SSL *con) } OPENSSL_free(exportedkeymat); } +#ifndef OPENSSL_NO_KTLS + if (BIO_get_ktls_send(SSL_get_wbio(con))) + BIO_printf(bio_err, "Using Kernel TLS for sending\n"); + if (BIO_get_ktls_recv(SSL_get_rbio(con))) + BIO_printf(bio_err, "Using Kernel TLS for receiving\n"); +#endif (void)BIO_flush(bio_s_out); } @@ -2757,11 +2985,11 @@ static DH *load_dh_param(const char *dhfile) ret = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); err: BIO_free(bio); - return (ret); + return ret; } #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; @@ -2774,6 +3002,7 @@ static int www_body(int s, int stype, unsigned char *context) #endif int width; fd_set readfds; + const char *opmode; /* Set width for a select call if needed */ width = s + 1; @@ -2803,10 +3032,12 @@ static int www_body(int s, int stype, unsigned char *context) SSL_set_tlsext_debug_arg(con, bio_s_out); } - if (context + if (context != NULL && !SSL_set_session_id_context(con, context, - strlen((char *)context))) + strlen((char *)context))) { + SSL_free(con); goto err; + } sbio = BIO_new_socket(s, BIO_NOCLOSE); if (s_nbio_test) { @@ -2818,7 +3049,7 @@ static int www_body(int s, int stype, unsigned char *context) SSL_set_bio(con, sbio, sbio); SSL_set_accept_state(con); - /* SSL_set_fd(con,s); */ + /* No need to free |con| after this. Done by BIO_free(ssl_bio) */ BIO_set_ssl(ssl_bio, con, BIO_CLOSE); BIO_push(io, ssl_bio); #ifdef CHARSET_EBCDIC @@ -2985,6 +3216,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); @@ -3001,9 +3233,10 @@ static int www_body(int s, int stype, unsigned char *context) PEM_write_bio_X509(io, peer); X509_free(peer); peer = NULL; - } else + } else { BIO_puts(io, "no client certificate available\n"); - BIO_puts(io, "\r\n\r\n"); + } + BIO_puts(io, "\r\n\r\n"); break; } else if ((www == 2 || www == 3) && (strncmp("GET /", buf, 5) == 0)) { @@ -3020,6 +3253,12 @@ static int www_body(int s, int stype, unsigned char *context) if (e[0] == ' ') break; + if (e[0] == ':') { + /* Windows drive. We treat this the same way as ".." */ + dot = -1; + break; + } + switch (dot) { case 1: dot = (e[0] == '.') ? 2 : 0; @@ -3028,11 +3267,11 @@ static int www_body(int s, int stype, unsigned char *context) dot = (e[0] == '.') ? 3 : 0; break; case 3: - dot = (e[0] == '/') ? -1 : 0; + dot = (e[0] == '/' || e[0] == '\\') ? -1 : 0; break; } if (dot == 0) - dot = (e[0] == '/') ? 1 : 0; + dot = (e[0] == '/' || e[0] == '\\') ? 1 : 0; } dot = (dot == 3) || (dot == -1); /* filename contains ".." * component */ @@ -3046,11 +3285,11 @@ static int www_body(int s, int stype, unsigned char *context) if (dot) { BIO_puts(io, text); - BIO_printf(io, "'%s' contains '..' reference\r\n", p); + BIO_printf(io, "'%s' contains '..' or ':'\r\n", p); break; } - if (*p == '/') { + if (*p == '/' || *p == '\\') { BIO_puts(io, text); BIO_printf(io, "'%s' is an invalid path\r\n", p); break; @@ -3063,9 +3302,10 @@ static int www_body(int s, int stype, unsigned char *context) break; } - if ((file = BIO_new_file(p, "r")) == NULL) { + opmode = (http_server_binmode == 1) ? "rb" : "r"; + if ((file = BIO_new_file(p, opmode)) == NULL) { BIO_puts(io, text); - BIO_printf(io, "Error opening '%s'\r\n", p); + BIO_printf(io, "Error opening '%s' mode='%s'\r\n", p, opmode); ERR_print_errors(io); break; } @@ -3139,14 +3379,12 @@ static int www_body(int s, int stype, unsigned char *context) SSL_set_shutdown(con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); err: - if (ret >= 0) - BIO_printf(bio_s_out, "ACCEPT\n"); OPENSSL_free(buf); BIO_free_all(io); - return (ret); + 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; @@ -3171,9 +3409,10 @@ static int rev_body(int s, int stype, unsigned char *context) SSL_set_tlsext_debug_callback(con, tlsext_cb); SSL_set_tlsext_debug_arg(con, bio_s_out); } - if (context + if (context != NULL && !SSL_set_session_id_context(con, context, strlen((char *)context))) { + SSL_free(con); ERR_print_errors(bio_err); goto err; } @@ -3182,6 +3421,7 @@ static int rev_body(int s, int stype, unsigned char *context) SSL_set_bio(con, sbio, sbio); SSL_set_accept_state(con); + /* No need to free |con| after this. Done by BIO_free(ssl_bio) */ BIO_set_ssl(ssl_bio, con, BIO_CLOSE); BIO_push(io, ssl_bio); #ifdef CHARSET_EBCDIC @@ -3296,14 +3536,16 @@ static int rev_body(int s, int stype, unsigned char *context) OPENSSL_free(buf); BIO_free_all(io); - return (ret); + return ret; } #define MAX_SESSION_ID_ATTEMPTS 10 -static int generate_session_id(const SSL *ssl, unsigned char *id, +static int generate_session_id(SSL *ssl, unsigned char *id, unsigned int *id_len) { unsigned int count = 0; + unsigned int session_id_prefix_len = strlen(session_id_prefix); + do { if (RAND_bytes(id, *id_len) <= 0) return 0; @@ -3315,8 +3557,8 @@ static int generate_session_id(const SSL *ssl, unsigned char *id, * conflicts. */ memcpy(id, session_id_prefix, - (strlen(session_id_prefix) < *id_len) ? - strlen(session_id_prefix) : *id_len); + (session_id_prefix_len < *id_len) ? + session_id_prefix_len : *id_len); } while (SSL_has_matching_session_id(ssl, id, *id_len) && (++count < MAX_SESSION_ID_ATTEMPTS));