X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=apps%2Fs_server.c;h=8883994f8f7622d114f66d40416b5749cb0f07dd;hp=5858278b466fb791312f58cfd7399734adf619d2;hb=0d68367a1279a369146661f4857816b2044116b4;hpb=9998b32cb63b0bdd3d014abfa1d70e9a2c20a283 diff --git a/apps/s_server.c b/apps/s_server.c index 5858278b46..8883994f8f 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -1,5 +1,7 @@ /* - * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2017 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 * this file except in compliance with the License. You can obtain a copy @@ -7,38 +9,6 @@ * 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 @@ -91,13 +61,13 @@ 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); -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); @@ -147,11 +117,12 @@ static long socket_mtu; static int dtlslisten = 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 */ +#ifndef OPENSSL_NO_PSK static unsigned int psk_server_cb(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len) @@ -161,7 +132,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; } @@ -171,12 +142,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); @@ -208,6 +179,59 @@ static unsigned int psk_server_cb(SSL *ssl, const char *identity, } #endif +#define TLS13_AES_128_GCM_SHA256_BYTES ((const unsigned char *)"\x13\x01") +#define TLS13_AES_256_GCM_SHA384_BYTES ((const unsigned char *)"\x13\x02") + +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) + return 0; + + 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; + } + + if (key_len == EVP_MD_size(EVP_sha256())) + cipher = SSL_CIPHER_find(ssl, tls13_aes128gcmsha256_id); + else if(key_len == EVP_MD_size(EVP_sha384())) + cipher = SSL_CIPHER_find(ssl, tls13_aes256gcmsha384_id); + + if (cipher == NULL) { + /* Doesn't look like a suitable TLSv1.3 key. Ignore it */ + 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 { @@ -435,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, + isascii(uc) && 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); } @@ -493,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"); @@ -503,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; @@ -529,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) @@ -715,15 +747,17 @@ 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_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_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_R_ENUM, OPT_S_ENUM, OPT_V_ENUM, OPT_X_ENUM @@ -800,8 +834,7 @@ const OPTIONS s_server_options[] = { {"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"}, + OPT_R_OPTIONS, {"keymatexport", OPT_KEYMATEXPORT, 's', "Export keying material using label"}, {"keymatexportlen", OPT_KEYMATEXPORTLEN, 'p', @@ -856,20 +889,23 @@ 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"}, + {"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', @@ -903,6 +939,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 @@ -943,7 +982,7 @@ int s_server_main(int argc, char *argv[]) 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 *dpassarg = NULL, *dpass = NULL; char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL; char *crl_file = NULL, *prog; #ifdef AF_UNIX @@ -960,7 +999,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); @@ -980,8 +1019,8 @@ 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; @@ -996,10 +1035,12 @@ 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; + char *psksessf = NULL; /* Init of few remaining global variables */ local_argc = argc; @@ -1345,20 +1386,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); goto end; } -#endif + break; + case OPT_PSK_SESS: + psksessf = opt_arg(); break; case OPT_SRPVFILE: #ifndef OPENSSL_NO_SRP @@ -1429,6 +1474,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: @@ -1452,8 +1502,9 @@ int s_server_main(int argc, char *argv[]) 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(); @@ -1489,15 +1540,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()); @@ -1523,6 +1570,12 @@ int s_server_main(int argc, char *argv[]) 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"); @@ -1543,15 +1596,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"); @@ -1570,7 +1624,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; } @@ -1578,20 +1632,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; } @@ -1599,7 +1653,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; } @@ -1619,16 +1673,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); @@ -1636,14 +1690,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; } @@ -1651,11 +1705,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; @@ -1663,19 +1717,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) @@ -1726,7 +1771,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) @@ -1741,11 +1786,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) { @@ -1791,7 +1850,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) @@ -1809,7 +1868,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) @@ -1852,9 +1911,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) { @@ -1864,16 +1923,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) { @@ -1884,9 +1943,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); @@ -1906,7 +1965,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) { @@ -1918,7 +1978,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); } @@ -1935,6 +1995,26 @@ 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, @@ -1949,7 +2029,7 @@ 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) { + 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, @@ -2018,12 +2098,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, + do_server(&accept_socket, host, port, socket_family, socket_type, protocol, server_cb, context, naccept); 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); @@ -2090,7 +2171,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; @@ -2104,6 +2185,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"); @@ -2136,9 +2224,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; @@ -2169,12 +2261,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; @@ -2324,8 +2426,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')) { @@ -2566,6 +2669,16 @@ 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; @@ -2608,7 +2721,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 @@ -2618,7 +2731,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 @@ -2639,7 +2752,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)); @@ -2688,10 +2801,7 @@ 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; } @@ -2704,6 +2814,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) @@ -2728,6 +2839,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); @@ -2766,7 +2880,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; @@ -2808,7 +2922,7 @@ 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))) goto err; @@ -2990,6 +3104,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); @@ -3006,9 +3121,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)) { @@ -3151,7 +3267,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; @@ -3176,7 +3292,7 @@ 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))) { ERR_print_errors(bio_err); @@ -3305,7 +3421,7 @@ static int rev_body(int s, int stype, unsigned char *context) } #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;