2015-12-02 13:01:29 -05:00
2012-05-18 09:47:34 -04:00
/*
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
* SSL / TLS transport layer over SOCK_STREAM sockets
2012-05-18 09:47:34 -04:00
*
* Copyright ( C ) 2012 EXCELIANCE , Emeric Brun < ebrun @ exceliance . fr >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
2012-09-10 03:43:09 -04:00
* Acknowledgement :
* We ' d like to specially thank the Stud project authors for a very clean
* and well documented code which helped us understand how the OpenSSL API
* ought to be used in non - blocking mode . This is one difficult part which
* is not easy to get from the OpenSSL doc , and reading the Stud code made
* it much more obvious than the examples in the OpenSSL package . Keep up
* the good works , guys !
*
* Stud is an extremely efficient and scalable SSL / TLS proxy which combines
* particularly well with haproxy . For more info about this project , visit :
* https : //github.com/bumptech/stud
*
2012-05-18 09:47:34 -04:00
*/
# define _GNU_SOURCE
2012-09-07 11:30:07 -04:00
# include <ctype.h>
# include <dirent.h>
2012-05-18 09:47:34 -04:00
# include <errno.h>
# include <fcntl.h>
# include <stdio.h>
# include <stdlib.h>
2012-09-07 11:30:07 -04:00
# include <string.h>
# include <unistd.h>
2012-05-18 09:47:34 -04:00
# include <sys/socket.h>
# include <sys/stat.h>
# include <sys/types.h>
2015-06-09 11:29:50 -04:00
# include <netdb.h>
2012-05-18 09:47:34 -04:00
# include <netinet/tcp.h>
2018-12-14 11:47:02 -05:00
# include <openssl/bn.h>
2016-08-29 07:26:37 -04:00
# include <openssl/crypto.h>
2012-05-18 09:47:34 -04:00
# include <openssl/ssl.h>
2012-09-07 11:30:07 -04:00
# include <openssl/x509.h>
# include <openssl/x509v3.h>
# include <openssl/err.h>
2013-01-24 08:15:43 -05:00
# include <openssl/rand.h>
2017-10-02 11:12:06 -04:00
# include <openssl/hmac.h>
2014-12-09 10:32:51 -05:00
# if (defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP)
2014-06-16 12:36:30 -04:00
# include <openssl/ocsp.h>
# endif
2015-05-28 10:23:00 -04:00
# ifndef OPENSSL_NO_DH
# include <openssl/dh.h>
# endif
2017-05-29 08:36:20 -04:00
# ifndef OPENSSL_NO_ENGINE
2017-01-20 20:10:18 -05:00
# include <openssl/engine.h>
2017-05-29 08:36:20 -04:00
# endif
2012-05-18 09:47:34 -04:00
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-01-13 20:42:15 -05:00
# include <openssl/async.h>
# endif
2018-12-14 11:47:02 -05:00
# ifndef OPENSSL_VERSION
# define OPENSSL_VERSION SSLEAY_VERSION
# define OpenSSL_version(x) SSLeay_version(x)
# define OpenSSL_version_num SSLeay
# endif
# if (OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER < 0x20700000L)
# define X509_getm_notBefore X509_get_notBefore
# define X509_getm_notAfter X509_get_notAfter
# endif
2015-06-09 11:29:50 -04:00
# include <import/lru.h>
# include <import/xxhash.h>
2012-05-18 09:47:34 -04:00
# include <common/buffer.h>
2018-07-13 04:54:26 -04:00
# include <common/chunk.h>
2012-05-18 09:47:34 -04:00
# include <common/compat.h>
# include <common/config.h>
# include <common/debug.h>
2012-09-14 01:53:05 -04:00
# include <common/errors.h>
2018-11-25 13:14:37 -05:00
# include <common/initcall.h>
2012-05-18 09:47:34 -04:00
# include <common/standard.h>
# include <common/ticks.h>
# include <common/time.h>
2014-10-30 10:56:50 -04:00
# include <common/cfgparse.h>
2015-02-27 13:56:49 -05:00
# include <common/base64.h>
2012-05-18 09:47:34 -04:00
2012-09-07 11:30:07 -04:00
# include <ebsttree.h>
2016-10-29 12:09:35 -04:00
# include <types/applet.h>
# include <types/cli.h>
2012-09-07 11:30:07 -04:00
# include <types/global.h>
# include <types/ssl_sock.h>
2016-10-29 12:09:35 -04:00
# include <types/stats.h>
2012-09-07 11:30:07 -04:00
2012-09-10 02:20:03 -04:00
# include <proto/acl.h>
# include <proto/arg.h>
2016-10-29 12:09:35 -04:00
# include <proto/channel.h>
2012-05-18 09:47:34 -04:00
# include <proto/connection.h>
2016-10-29 12:09:35 -04:00
# include <proto/cli.h>
2012-05-18 09:47:34 -04:00
# include <proto/fd.h>
# include <proto/freq_ctr.h>
# include <proto/frontend.h>
2018-10-02 10:43:32 -04:00
# include <proto/http_rules.h>
2012-09-14 01:53:05 -04:00
# include <proto/listener.h>
2016-08-29 07:26:37 -04:00
# include <proto/openssl-compat.h>
2013-11-28 05:05:19 -05:00
# include <proto/pattern.h>
2015-06-09 11:29:50 -04:00
# include <proto/proto_tcp.h>
2017-10-02 05:51:03 -04:00
# include <proto/proto_http.h>
2012-10-10 17:04:25 -04:00
# include <proto/server.h>
2016-10-29 12:09:35 -04:00
# include <proto/stream_interface.h>
2012-05-18 09:47:34 -04:00
# include <proto/log.h>
2012-10-11 08:00:19 -04:00
# include <proto/proxy.h>
2012-09-07 11:30:07 -04:00
# include <proto/shctx.h>
2012-05-18 09:47:34 -04:00
# include <proto/ssl_sock.h>
2015-04-03 13:19:59 -04:00
# include <proto/stream.h>
2012-05-18 09:47:34 -04:00
# include <proto/task.h>
2014-02-17 09:43:01 -05:00
/* Warning, these are bits, not integers! */
2012-09-21 07:15:06 -04:00
# define SSL_SOCK_ST_FL_VERIFY_DONE 0x00000001
2014-01-28 09:43:53 -05:00
# define SSL_SOCK_ST_FL_16K_WBFSIZE 0x00000002
2014-02-17 09:43:01 -05:00
# define SSL_SOCK_SEND_UNLIMITED 0x00000004
2014-04-25 13:05:36 -04:00
# define SSL_SOCK_RECV_HEARTBEAT 0x00000008
2012-09-21 09:27:54 -04:00
/* bits 0xFFFF0000 are reserved to store verify errors */
/* Verify errors macros */
# define SSL_SOCK_CA_ERROR_TO_ST(e) (((e > 63) ? 63 : e) << (16))
# define SSL_SOCK_CAEDEPTH_TO_ST(d) (((d > 15) ? 15 : d) << (6+16))
# define SSL_SOCK_CRTERROR_TO_ST(e) (((e > 63) ? 63 : e) << (4+6+16))
# define SSL_SOCK_ST_TO_CA_ERROR(s) ((s >> (16)) & 63)
# define SSL_SOCK_ST_TO_CAEDEPTH(s) ((s >> (6+16)) & 15)
# define SSL_SOCK_ST_TO_CRTERROR(s) ((s >> (4+6+16)) & 63)
2012-09-21 07:15:06 -04:00
2015-02-27 13:56:49 -05:00
/* Supported hash function for TLS tickets */
# ifdef OPENSSL_NO_SHA256
# define HASH_FUNCT EVP_sha1
# else
# define HASH_FUNCT EVP_sha256
# endif /* OPENSSL_NO_SHA256 */
2017-03-30 13:19:37 -04:00
/* ssl_methods flags for ssl options */
# define MC_SSL_O_ALL 0x0000
# define MC_SSL_O_NO_SSLV3 0x0001 /* disable SSLv3 */
# define MC_SSL_O_NO_TLSV10 0x0002 /* disable TLSv10 */
# define MC_SSL_O_NO_TLSV11 0x0004 /* disable TLSv11 */
# define MC_SSL_O_NO_TLSV12 0x0008 /* disable TLSv12 */
2017-03-30 13:29:39 -04:00
# define MC_SSL_O_NO_TLSV13 0x0010 /* disable TLSv13 */
2017-03-30 13:19:37 -04:00
/* ssl_methods versions */
enum {
CONF_TLSV_NONE = 0 ,
CONF_TLSV_MIN = 1 ,
CONF_SSLV3 = 1 ,
CONF_TLSV10 = 2 ,
CONF_TLSV11 = 3 ,
CONF_TLSV12 = 4 ,
2017-03-30 13:29:39 -04:00
CONF_TLSV13 = 5 ,
CONF_TLSV_MAX = 5 ,
2017-03-30 13:19:37 -04:00
} ;
2014-01-29 06:24:34 -05:00
/* server and bind verify method, it uses a global value as default */
enum {
SSL_SOCK_VERIFY_DEFAULT = 0 ,
SSL_SOCK_VERIFY_REQUIRED = 1 ,
SSL_SOCK_VERIFY_OPTIONAL = 2 ,
SSL_SOCK_VERIFY_NONE = 3 ,
} ;
2017-10-09 10:30:50 -04:00
2014-01-28 09:19:44 -05:00
int sslconns = 0 ;
int totalsslconns = 0 ;
2016-12-22 15:08:52 -05:00
static struct xprt_ops ssl_sock ;
2017-12-06 07:51:49 -05:00
int nb_engines = 0 ;
2012-09-03 14:36:47 -04:00
2016-12-22 17:12:01 -05:00
static struct {
char * crt_base ; /* base directory path for certificates */
char * ca_base ; /* base directory path for CAs and CRLs */
2017-01-13 20:42:15 -05:00
int async ; /* whether we use ssl async mode */
2016-12-22 17:12:01 -05:00
char * listen_default_ciphers ;
char * connect_default_ciphers ;
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
char * listen_default_ciphersuites ;
char * connect_default_ciphersuites ;
# endif
2016-12-22 17:12:01 -05:00
int listen_default_ssloptions ;
int connect_default_ssloptions ;
2017-03-30 13:19:37 -04:00
struct tls_version_filter listen_default_sslmethods ;
struct tls_version_filter connect_default_sslmethods ;
2016-12-22 17:12:01 -05:00
int private_cache ; /* Force to use a private session cache even if nbproc > 1 */
unsigned int life_time ; /* SSL session lifetime in seconds */
unsigned int max_record ; /* SSL max record size */
unsigned int default_dh_param ; /* SSL maximum DH parameter size */
int ctx_cache ; /* max number of entries in the ssl_ctx cache. */
2017-02-25 06:45:22 -05:00
int capture_cipherlist ; /* Size of the cipherlist buffer. */
2016-12-22 17:12:01 -05:00
} global_ssl = {
# ifdef LISTEN_DEFAULT_CIPHERS
. listen_default_ciphers = LISTEN_DEFAULT_CIPHERS ,
# endif
# ifdef CONNECT_DEFAULT_CIPHERS
. connect_default_ciphers = CONNECT_DEFAULT_CIPHERS ,
2018-09-14 05:14:21 -04:00
# endif
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
# ifdef LISTEN_DEFAULT_CIPHERSUITES
. listen_default_ciphersuites = LISTEN_DEFAULT_CIPHERSUITES ,
# endif
# ifdef CONNECT_DEFAULT_CIPHERSUITES
. connect_default_ciphersuites = CONNECT_DEFAULT_CIPHERSUITES ,
# endif
2016-12-22 17:12:01 -05:00
# endif
. listen_default_ssloptions = BC_SSL_O_NONE ,
. connect_default_ssloptions = SRV_SSL_O_NONE ,
2017-03-30 13:19:37 -04:00
. listen_default_sslmethods . flags = MC_SSL_O_ALL ,
. listen_default_sslmethods . min = CONF_TLSV_NONE ,
. listen_default_sslmethods . max = CONF_TLSV_NONE ,
. connect_default_sslmethods . flags = MC_SSL_O_ALL ,
. connect_default_sslmethods . min = CONF_TLSV_NONE ,
. connect_default_sslmethods . max = CONF_TLSV_NONE ,
2016-12-22 17:12:01 -05:00
# ifdef DEFAULT_SSL_MAX_RECORD
. max_record = DEFAULT_SSL_MAX_RECORD ,
# endif
. default_dh_param = SSL_DEFAULT_DH_PARAM ,
. ctx_cache = DEFAULT_SSL_CTX_CACHE ,
2017-02-25 06:45:22 -05:00
. capture_cipherlist = 0 ,
2016-12-22 17:12:01 -05:00
} ;
2018-12-14 11:47:02 -05:00
# if defined(USE_THREAD) && ((OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER))
2017-11-13 04:34:01 -05:00
2017-06-15 10:37:39 -04:00
static HA_RWLOCK_T * ssl_rwlocks ;
unsigned long ssl_id_function ( void )
{
return ( unsigned long ) tid ;
}
void ssl_locking_function ( int mode , int n , const char * file , int line )
{
if ( mode & CRYPTO_LOCK ) {
if ( mode & CRYPTO_READ )
2017-11-07 04:42:54 -05:00
HA_RWLOCK_RDLOCK ( SSL_LOCK , & ssl_rwlocks [ n ] ) ;
2017-06-15 10:37:39 -04:00
else
2017-11-07 04:42:54 -05:00
HA_RWLOCK_WRLOCK ( SSL_LOCK , & ssl_rwlocks [ n ] ) ;
2017-06-15 10:37:39 -04:00
}
else {
if ( mode & CRYPTO_READ )
2017-11-07 04:42:54 -05:00
HA_RWLOCK_RDUNLOCK ( SSL_LOCK , & ssl_rwlocks [ n ] ) ;
2017-06-15 10:37:39 -04:00
else
2017-11-07 04:42:54 -05:00
HA_RWLOCK_WRUNLOCK ( SSL_LOCK , & ssl_rwlocks [ n ] ) ;
2017-06-15 10:37:39 -04:00
}
}
static int ssl_locking_init ( void )
{
int i ;
ssl_rwlocks = malloc ( sizeof ( HA_RWLOCK_T ) * CRYPTO_num_locks ( ) ) ;
if ( ! ssl_rwlocks )
return - 1 ;
for ( i = 0 ; i < CRYPTO_num_locks ( ) ; i + + )
2017-11-07 04:42:54 -05:00
HA_RWLOCK_INIT ( & ssl_rwlocks [ i ] ) ;
2017-06-15 10:37:39 -04:00
CRYPTO_set_id_callback ( ssl_id_function ) ;
CRYPTO_set_locking_callback ( ssl_locking_function ) ;
return 0 ;
}
2017-11-13 04:34:01 -05:00
2017-06-15 10:37:39 -04:00
# endif
2017-03-07 12:34:58 -05:00
/* This memory pool is used for capturing clienthello parameters. */
2017-02-25 06:45:22 -05:00
struct ssl_capture {
unsigned long long int xxh64 ;
unsigned char ciphersuite_len ;
char ciphersuite [ 0 ] ;
} ;
2017-11-24 11:34:44 -05:00
struct pool_head * pool_head_ssl_capture = NULL ;
2017-03-07 12:34:58 -05:00
static int ssl_capture_ptr_index = - 1 ;
BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
We never saw unexplicated crash with SSL, so I suppose that we are
luck, or the slot 0 is always reserved. Anyway the usage of the macro
SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
the deprecated functions SSL_get_app_data() and SSL_set_app_data()
by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
it reserves the slot in the SSL memory space.
For information, this is the two declaration which seems wrong or
incomplete in the OpenSSL ssl.h file. We can see the usage of the
slot 0 whoch is hardcoded, but never reserved.
#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
This patch must be backported at least in 1.8, maybe in other versions.
2018-06-17 15:37:05 -04:00
static int ssl_app_data_index = - 1 ;
2016-12-22 17:12:01 -05:00
2017-10-31 10:46:07 -04:00
static int ssl_pkey_info_index = - 1 ;
2015-05-09 02:46:01 -04:00
# if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
struct list tlskeys_reference = LIST_HEAD_INIT ( tlskeys_reference ) ;
# endif
2017-05-29 08:36:20 -04:00
# ifndef OPENSSL_NO_ENGINE
2017-01-20 20:10:18 -05:00
static unsigned int openssl_engines_initialized ;
struct list openssl_engines = LIST_HEAD_INIT ( openssl_engines ) ;
struct ssl_engine_list {
struct list list ;
ENGINE * e ;
} ;
2017-05-29 08:36:20 -04:00
# endif
2017-01-20 20:10:18 -05:00
2014-07-15 05:36:40 -04:00
# ifndef OPENSSL_NO_DH
2015-05-28 10:23:00 -04:00
static int ssl_dh_ptr_index = - 1 ;
2015-05-29 09:53:22 -04:00
static DH * global_dh = NULL ;
2014-07-15 05:36:40 -04:00
static DH * local_dh_1024 = NULL ;
static DH * local_dh_2048 = NULL ;
static DH * local_dh_4096 = NULL ;
2017-03-03 11:04:14 -05:00
static DH * ssl_get_tmp_dh ( SSL * ssl , int export , int keylen ) ;
2014-07-15 05:36:40 -04:00
# endif /* OPENSSL_NO_DH */
2017-01-13 11:48:18 -05:00
# if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
2015-06-09 11:29:50 -04:00
/* X509V3 Extensions that will be added on generated certificates */
# define X509V3_EXT_SIZE 5
static char * x509v3_ext_names [ X509V3_EXT_SIZE ] = {
" basicConstraints " ,
" nsComment " ,
" subjectKeyIdentifier " ,
" authorityKeyIdentifier " ,
" keyUsage " ,
} ;
static char * x509v3_ext_values [ X509V3_EXT_SIZE ] = {
" CA:FALSE " ,
" \" OpenSSL Generated Certificate \" " ,
" hash " ,
" keyid,issuer:always " ,
" nonRepudiation,digitalSignature,keyEncipherment "
} ;
/* LRU cache to store generated certificate */
static struct lru64_head * ssl_ctx_lru_tree = NULL ;
static unsigned int ssl_ctx_lru_seed = 0 ;
2017-06-15 10:37:39 -04:00
static unsigned int ssl_ctx_serial ;
2018-11-25 14:12:18 -05:00
__decl_rwlock ( ssl_ctx_lru_rwlock ) ;
2017-06-15 10:37:39 -04:00
2015-06-17 09:48:26 -04:00
# endif // SSL_CTRL_SET_TLSEXT_HOSTNAME
2017-01-13 11:48:18 -05:00
static struct ssl_bind_kw ssl_bind_kws [ ] ;
2015-12-10 15:07:30 -05:00
# if OPENSSL_VERSION_NUMBER >= 0x1000200fL
/* The order here matters for picking a default context,
* keep the most common keytype at the bottom of the list
*/
const char * SSL_SOCK_KEYTYPE_NAMES [ ] = {
" dsa " ,
" ecdsa " ,
" rsa "
} ;
# define SSL_SOCK_NUM_KEYTYPES 3
2015-12-14 05:28:33 -05:00
# else
# define SSL_SOCK_NUM_KEYTYPES 1
2015-12-10 15:07:30 -05:00
# endif
2017-11-28 05:04:43 -05:00
static struct shared_context * ssl_shctx = NULL ; /* ssl shared session cache */
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
static struct eb_root * sh_ssl_sess_tree ; /* ssl shared session tree */
# define sh_ssl_sess_tree_delete(s) ebmb_delete(&(s)->key);
# define sh_ssl_sess_tree_insert(s) (struct sh_ssl_sess_hdr *)ebmb_insert(sh_ssl_sess_tree, \
& ( s ) - > key , SSL_MAX_SSL_SESSION_ID_LENGTH ) ;
# define sh_ssl_sess_tree_lookup(k) (struct sh_ssl_sess_hdr *)ebmb_lookup(sh_ssl_sess_tree, \
( k ) , SSL_MAX_SSL_SESSION_ID_LENGTH ) ;
2017-10-09 10:30:50 -04:00
2017-01-13 11:48:18 -05:00
/*
* This function gives the detail of the SSL error . It is used only
* if the debug mode and the verbose mode are activated . It dump all
* the SSL error until the stack was empty .
*/
static forceinline void ssl_sock_dump_errors ( struct connection * conn )
{
unsigned long ret ;
if ( unlikely ( global . mode & MODE_DEBUG ) ) {
while ( 1 ) {
ret = ERR_get_error ( ) ;
if ( ret = = 0 )
return ;
fprintf ( stderr , " fd[%04x] OpenSSL error[0x%lx] %s: %s \n " ,
2017-08-24 08:31:19 -04:00
( unsigned short ) conn - > handle . fd , ret ,
2017-01-13 11:48:18 -05:00
ERR_func_error_string ( ret ) , ERR_reason_error_string ( ret ) ) ;
}
}
}
2015-06-17 09:48:26 -04:00
# if (defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP)
2015-12-10 15:07:30 -05:00
/*
* struct alignment works here such that the key . key is the same as key_data
* Do not change the placement of key_data
*/
2015-06-17 09:48:26 -04:00
struct certificate_ocsp {
struct ebmb_node key ;
unsigned char key_data [ OCSP_MAX_CERTID_ASN1_LENGTH ] ;
2018-07-13 05:56:34 -04:00
struct buffer response ;
2015-06-17 09:48:26 -04:00
long expire ;
} ;
2015-06-09 11:29:50 -04:00
2015-12-10 15:07:30 -05:00
struct ocsp_cbk_arg {
int is_single ;
int single_kt ;
union {
struct certificate_ocsp * s_ocsp ;
/*
* m_ocsp will have multiple entries dependent on key type
* Entry 0 - DSA
* Entry 1 - ECDSA
* Entry 2 - RSA
*/
struct certificate_ocsp * m_ocsp [ SSL_SOCK_NUM_KEYTYPES ] ;
} ;
} ;
2017-05-29 08:36:20 -04:00
# ifndef OPENSSL_NO_ENGINE
2017-01-20 20:10:18 -05:00
static int ssl_init_single_engine ( const char * engine_id , const char * def_algorithms )
{
int err_code = ERR_ABORT ;
ENGINE * engine ;
struct ssl_engine_list * el ;
/* grab the structural reference to the engine */
engine = ENGINE_by_id ( engine_id ) ;
if ( engine = = NULL ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " ssl-engine %s: failed to get structural reference \n " , engine_id ) ;
2017-01-20 20:10:18 -05:00
goto fail_get ;
}
if ( ! ENGINE_init ( engine ) ) {
/* the engine couldn't initialise, release it */
2017-11-24 10:50:31 -05:00
ha_alert ( " ssl-engine %s: failed to initialize \n " , engine_id ) ;
2017-01-20 20:10:18 -05:00
goto fail_init ;
}
if ( ENGINE_set_default_string ( engine , def_algorithms ) = = 0 ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " ssl-engine %s: failed on ENGINE_set_default_string \n " , engine_id ) ;
2017-01-20 20:10:18 -05:00
goto fail_set_method ;
}
el = calloc ( 1 , sizeof ( * el ) ) ;
el - > e = engine ;
LIST_ADD ( & openssl_engines , & el - > list ) ;
2017-12-06 07:51:49 -05:00
nb_engines + + ;
if ( global_ssl . async )
global . ssl_used_async_engines = nb_engines ;
2017-01-20 20:10:18 -05:00
return 0 ;
fail_set_method :
/* release the functional reference from ENGINE_init() */
ENGINE_finish ( engine ) ;
fail_init :
/* release the structural reference from ENGINE_by_id() */
ENGINE_free ( engine ) ;
fail_get :
return err_code ;
}
2017-05-29 08:36:20 -04:00
# endif
2017-01-20 20:10:18 -05:00
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-05-17 14:42:48 -04:00
/*
* openssl async fd handler
*/
static void ssl_async_fd_handler ( int fd )
2017-01-13 20:42:15 -05:00
{
struct connection * conn = fdtab [ fd ] . owner ;
2017-05-17 14:42:48 -04:00
/* fd is an async enfine fd, we must stop
2017-01-13 20:42:15 -05:00
* to poll this fd until it is requested
*/
2017-06-02 11:54:06 -04:00
fd_stop_recv ( fd ) ;
2017-01-13 20:42:15 -05:00
fd_cant_recv ( fd ) ;
/* crypto engine is available, let's notify the associated
* connection that it can pursue its processing .
*/
2017-06-02 11:54:06 -04:00
__conn_sock_want_recv ( conn ) ;
__conn_sock_want_send ( conn ) ;
conn_update_sock_polling ( conn ) ;
2017-01-13 20:42:15 -05:00
}
2017-05-17 14:42:48 -04:00
/*
* openssl async delayed SSL_free handler
*/
static void ssl_async_fd_free ( int fd )
2017-01-13 20:42:15 -05:00
{
SSL * ssl = fdtab [ fd ] . owner ;
2017-05-17 14:42:48 -04:00
OSSL_ASYNC_FD all_fd [ 32 ] ;
size_t num_all_fds = 0 ;
int i ;
/* We suppose that the async job for a same SSL *
* are serialized . So if we are awake it is
* because the running job has just finished
* and we can remove all async fds safely
*/
SSL_get_all_async_fds ( ssl , NULL , & num_all_fds ) ;
if ( num_all_fds > 32 ) {
send_log ( NULL , LOG_EMERG , " haproxy: openssl returns too many async fds. It seems a bug. Process may crash \n " ) ;
return ;
}
2017-01-13 20:42:15 -05:00
2017-05-17 14:42:48 -04:00
SSL_get_all_async_fds ( ssl , all_fd , & num_all_fds ) ;
for ( i = 0 ; i < num_all_fds ; i + + )
fd_remove ( all_fd [ i ] ) ;
/* Now we can safely call SSL_free, no more pending job in engines */
2017-01-13 20:42:15 -05:00
SSL_free ( ssl ) ;
2019-03-08 12:54:43 -05:00
_HA_ATOMIC_SUB ( & sslconns , 1 ) ;
_HA_ATOMIC_SUB ( & jobs , 1 ) ;
2017-01-13 20:42:15 -05:00
}
/*
2017-05-17 14:42:48 -04:00
* function used to manage a returned SSL_ERROR_WANT_ASYNC
* and enable / disable polling for async fds
2017-01-13 20:42:15 -05:00
*/
2017-05-17 14:42:48 -04:00
static void inline ssl_async_process_fds ( struct connection * conn , SSL * ssl )
2017-01-13 20:42:15 -05:00
{
2018-01-25 01:22:13 -05:00
OSSL_ASYNC_FD add_fd [ 32 ] ;
2017-05-17 14:42:48 -04:00
OSSL_ASYNC_FD del_fd [ 32 ] ;
2017-01-13 20:42:15 -05:00
size_t num_add_fds = 0 ;
size_t num_del_fds = 0 ;
2017-05-17 14:42:48 -04:00
int i ;
2017-01-13 20:42:15 -05:00
SSL_get_changed_async_fds ( ssl , NULL , & num_add_fds , NULL ,
& num_del_fds ) ;
2017-05-17 14:42:48 -04:00
if ( num_add_fds > 32 | | num_del_fds > 32 ) {
send_log ( NULL , LOG_EMERG , " haproxy: openssl returns too many async fds. It seems a bug. Process may crash \n " ) ;
2017-01-13 20:42:15 -05:00
return ;
}
2017-05-17 14:42:48 -04:00
SSL_get_changed_async_fds ( ssl , add_fd , & num_add_fds , del_fd , & num_del_fds ) ;
2017-01-13 20:42:15 -05:00
2017-05-17 14:42:48 -04:00
/* We remove unused fds from the fdtab */
for ( i = 0 ; i < num_del_fds ; i + + )
fd_remove ( del_fd [ i ] ) ;
2017-01-13 20:42:15 -05:00
2017-05-17 14:42:48 -04:00
/* We add new fds to the fdtab */
for ( i = 0 ; i < num_add_fds ; i + + ) {
2018-01-25 01:22:13 -05:00
fd_insert ( add_fd [ i ] , conn , ssl_async_fd_handler , tid_bit ) ;
2017-01-13 20:42:15 -05:00
}
2017-05-17 14:42:48 -04:00
num_add_fds = 0 ;
SSL_get_all_async_fds ( ssl , NULL , & num_add_fds ) ;
if ( num_add_fds > 32 ) {
send_log ( NULL , LOG_EMERG , " haproxy: openssl returns too many async fds. It seems a bug. Process may crash \n " ) ;
return ;
2017-01-13 20:42:15 -05:00
}
2017-05-17 14:42:48 -04:00
/* We activate the polling for all known async fds */
SSL_get_all_async_fds ( ssl , add_fd , & num_add_fds ) ;
2017-05-31 06:02:53 -04:00
for ( i = 0 ; i < num_add_fds ; i + + ) {
2017-05-17 14:42:48 -04:00
fd_want_recv ( add_fd [ i ] ) ;
2017-05-31 06:02:53 -04:00
/* To ensure that the fd cache won't be used
* We ' ll prefer to catch a real RD event
* because handling an EAGAIN on this fd will
* result in a context switch and also
* some engines uses a fd in blocking mode .
*/
fd_cant_recv ( add_fd [ i ] ) ;
}
2017-05-17 14:42:48 -04:00
/* We must also prevent the conn_handler
* to be called until a read event was
* polled on an async fd
*/
__conn_sock_stop_both ( conn ) ;
2017-01-13 20:42:15 -05:00
}
# endif
2014-06-20 09:46:13 -04:00
/*
* This function returns the number of seconds elapsed
* since the Epoch , 1970 - 01 - 01 00 : 00 : 00 + 0000 ( UTC ) and the
* date presented un ASN1_GENERALIZEDTIME .
*
* In parsing error case , it returns - 1.
*/
static long asn1_generalizedtime_to_epoch ( ASN1_GENERALIZEDTIME * d )
{
long epoch ;
char * p , * end ;
const unsigned short month_offset [ 12 ] = {
0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334
} ;
int year , month ;
if ( ! d | | ( d - > type ! = V_ASN1_GENERALIZEDTIME ) ) return - 1 ;
p = ( char * ) d - > data ;
end = p + d - > length ;
if ( end - p < 4 ) return - 1 ;
year = 1000 * ( p [ 0 ] - ' 0 ' ) + 100 * ( p [ 1 ] - ' 0 ' ) + 10 * ( p [ 2 ] - ' 0 ' ) + p [ 3 ] - ' 0 ' ;
p + = 4 ;
if ( end - p < 2 ) return - 1 ;
month = 10 * ( p [ 0 ] - ' 0 ' ) + p [ 1 ] - ' 0 ' ;
if ( month < 1 | | month > 12 ) return - 1 ;
/* Compute the number of seconds since 1 jan 1970 and the beginning of current month
We consider leap years and the current month ( < marsh or not ) */
epoch = ( ( ( year - 1970 ) * 365 )
+ ( ( year - ( month < 3 ) ) / 4 - ( year - ( month < 3 ) ) / 100 + ( year - ( month < 3 ) ) / 400 )
- ( ( 1970 - 1 ) / 4 - ( 1970 - 1 ) / 100 + ( 1970 - 1 ) / 400 )
+ month_offset [ month - 1 ]
) * 24 * 60 * 60 ;
p + = 2 ;
if ( end - p < 2 ) return - 1 ;
/* Add the number of seconds of completed days of current month */
epoch + = ( 10 * ( p [ 0 ] - ' 0 ' ) + p [ 1 ] - ' 0 ' - 1 ) * 24 * 60 * 60 ;
p + = 2 ;
if ( end - p < 2 ) return - 1 ;
/* Add the completed hours of the current day */
epoch + = ( 10 * ( p [ 0 ] - ' 0 ' ) + p [ 1 ] - ' 0 ' ) * 60 * 60 ;
p + = 2 ;
if ( end - p < 2 ) return - 1 ;
/* Add the completed minutes of the current hour */
epoch + = ( 10 * ( p [ 0 ] - ' 0 ' ) + p [ 1 ] - ' 0 ' ) * 60 ;
p + = 2 ;
if ( p = = end ) return - 1 ;
/* Test if there is available seconds */
if ( p [ 0 ] < ' 0 ' | | p [ 0 ] > ' 9 ' )
goto nosec ;
if ( end - p < 2 ) return - 1 ;
/* Add the seconds of the current minute */
epoch + = 10 * ( p [ 0 ] - ' 0 ' ) + p [ 1 ] - ' 0 ' ;
p + = 2 ;
if ( p = = end ) return - 1 ;
/* Ignore seconds float part if present */
if ( p [ 0 ] = = ' . ' ) {
do {
if ( + + p = = end ) return - 1 ;
} while ( p [ 0 ] > = ' 0 ' & & p [ 0 ] < = ' 9 ' ) ;
}
nosec :
if ( p [ 0 ] = = ' Z ' ) {
if ( end - p ! = 1 ) return - 1 ;
return epoch ;
}
else if ( p [ 0 ] = = ' + ' ) {
if ( end - p ! = 5 ) return - 1 ;
/* Apply timezone offset */
2017-10-16 10:37:31 -04:00
return epoch - ( ( 10 * ( p [ 1 ] - ' 0 ' ) + p [ 2 ] - ' 0 ' ) * 60 * 60 + ( 10 * ( p [ 3 ] - ' 0 ' ) + p [ 4 ] - ' 0 ' ) ) * 60 ;
2014-06-20 09:46:13 -04:00
}
else if ( p [ 0 ] = = ' - ' ) {
if ( end - p ! = 5 ) return - 1 ;
/* Apply timezone offset */
2017-10-16 10:37:31 -04:00
return epoch + ( ( 10 * ( p [ 1 ] - ' 0 ' ) + p [ 2 ] - ' 0 ' ) * 60 * 60 + ( 10 * ( p [ 3 ] - ' 0 ' ) + p [ 4 ] - ' 0 ' ) ) * 60 ;
2014-06-20 09:46:13 -04:00
}
return - 1 ;
}
2014-06-20 09:37:32 -04:00
static struct eb_root cert_ocsp_tree = EB_ROOT_UNIQUE ;
2014-06-16 12:36:30 -04:00
/* This function starts to check if the OCSP response (in DER format) contained
* in chunk ' ocsp_response ' is valid ( else exits on error ) .
* If ' cid ' is not NULL , it will be compared to the OCSP certificate ID
* contained in the OCSP Response and exits on error if no match .
* If it ' s a valid OCSP Response :
* If ' ocsp ' is not NULL , the chunk is copied in the OCSP response ' s container
* pointed by ' ocsp ' .
* If ' ocsp ' is NULL , the function looks up into the OCSP response ' s
* containers tree ( using as index the ASN1 form of the OCSP Certificate ID extracted
* from the response ) and exits on error if not found . Finally , If an OCSP response is
* already present in the container , it will be overwritten .
*
* Note : OCSP response containing more than one OCSP Single response is not
* considered valid .
*
* Returns 0 on success , 1 in error case .
*/
2018-07-13 05:56:34 -04:00
static int ssl_sock_load_ocsp_response ( struct buffer * ocsp_response ,
struct certificate_ocsp * ocsp ,
OCSP_CERTID * cid , char * * err )
2014-06-16 12:36:30 -04:00
{
OCSP_RESPONSE * resp ;
OCSP_BASICRESP * bs = NULL ;
OCSP_SINGLERESP * sr ;
2016-08-29 07:26:37 -04:00
OCSP_CERTID * id ;
2018-07-13 04:54:26 -04:00
unsigned char * p = ( unsigned char * ) ocsp_response - > area ;
2014-06-16 12:36:30 -04:00
int rc , count_sr ;
2014-06-20 09:44:34 -04:00
ASN1_GENERALIZEDTIME * revtime , * thisupd , * nextupd = NULL ;
2014-06-16 12:36:30 -04:00
int reason ;
int ret = 1 ;
2018-07-13 04:54:26 -04:00
resp = d2i_OCSP_RESPONSE ( NULL , ( const unsigned char * * ) & p ,
ocsp_response - > data ) ;
2014-06-16 12:36:30 -04:00
if ( ! resp ) {
memprintf ( err , " Unable to parse OCSP response " ) ;
goto out ;
}
rc = OCSP_response_status ( resp ) ;
if ( rc ! = OCSP_RESPONSE_STATUS_SUCCESSFUL ) {
memprintf ( err , " OCSP response status not successful " ) ;
goto out ;
}
bs = OCSP_response_get1_basic ( resp ) ;
if ( ! bs ) {
memprintf ( err , " Failed to get basic response from OCSP Response " ) ;
goto out ;
}
count_sr = OCSP_resp_count ( bs ) ;
if ( count_sr > 1 ) {
memprintf ( err , " OCSP response ignored because contains multiple single responses (%d) " , count_sr ) ;
goto out ;
}
sr = OCSP_resp_get0 ( bs , 0 ) ;
if ( ! sr ) {
memprintf ( err , " Failed to get OCSP single response " ) ;
goto out ;
}
2016-08-29 07:26:37 -04:00
id = ( OCSP_CERTID * ) OCSP_SINGLERESP_get0_id ( sr ) ;
2014-06-16 12:36:30 -04:00
rc = OCSP_single_get0_status ( sr , & reason , & revtime , & thisupd , & nextupd ) ;
2017-10-24 08:57:16 -04:00
if ( rc ! = V_OCSP_CERTSTATUS_GOOD & & rc ! = V_OCSP_CERTSTATUS_REVOKED ) {
2017-10-10 09:18:52 -04:00
memprintf ( err , " OCSP single response: certificate status is unknown " ) ;
2014-06-16 12:36:30 -04:00
goto out ;
}
2014-06-20 09:44:34 -04:00
if ( ! nextupd ) {
memprintf ( err , " OCSP single response: missing nextupdate " ) ;
goto out ;
}
2014-06-19 08:16:17 -04:00
rc = OCSP_check_validity ( thisupd , nextupd , OCSP_MAX_RESPONSE_TIME_SKEW , - 1 ) ;
2014-06-16 12:36:30 -04:00
if ( ! rc ) {
memprintf ( err , " OCSP single response: no longer valid. " ) ;
goto out ;
}
if ( cid ) {
2016-08-29 07:26:37 -04:00
if ( OCSP_id_cmp ( id , cid ) ) {
2014-06-16 12:36:30 -04:00
memprintf ( err , " OCSP single response: Certificate ID does not match certificate and issuer " ) ;
goto out ;
}
}
if ( ! ocsp ) {
unsigned char key [ OCSP_MAX_CERTID_ASN1_LENGTH ] ;
unsigned char * p ;
2016-08-29 07:26:37 -04:00
rc = i2d_OCSP_CERTID ( id , NULL ) ;
2014-06-16 12:36:30 -04:00
if ( ! rc ) {
memprintf ( err , " OCSP single response: Unable to encode Certificate ID " ) ;
goto out ;
}
if ( rc > OCSP_MAX_CERTID_ASN1_LENGTH ) {
memprintf ( err , " OCSP single response: Certificate ID too long " ) ;
goto out ;
}
p = key ;
memset ( key , 0 , OCSP_MAX_CERTID_ASN1_LENGTH ) ;
2016-08-29 07:26:37 -04:00
i2d_OCSP_CERTID ( id , & p ) ;
2014-06-16 12:36:30 -04:00
ocsp = ( struct certificate_ocsp * ) ebmb_lookup ( & cert_ocsp_tree , key , OCSP_MAX_CERTID_ASN1_LENGTH ) ;
if ( ! ocsp ) {
memprintf ( err , " OCSP single response: Certificate ID does not match any certificate or issuer " ) ;
goto out ;
}
}
/* According to comments on "chunk_dup", the
previous chunk buffer will be freed */
if ( ! chunk_dup ( & ocsp - > response , ocsp_response ) ) {
memprintf ( err , " OCSP response: Memory allocation error " ) ;
goto out ;
}
2014-06-20 09:46:13 -04:00
ocsp - > expire = asn1_generalizedtime_to_epoch ( nextupd ) - OCSP_MAX_RESPONSE_TIME_SKEW ;
2014-06-16 12:36:30 -04:00
ret = 0 ;
out :
2017-03-08 10:59:41 -05:00
ERR_clear_error ( ) ;
2014-06-16 12:36:30 -04:00
if ( bs )
OCSP_BASICRESP_free ( bs ) ;
if ( resp )
OCSP_RESPONSE_free ( resp ) ;
return ret ;
}
/*
* External function use to update the OCSP response in the OCSP response ' s
* containers tree . The chunk ' ocsp_response ' must contain the OCSP response
* to update in DER format .
*
* Returns 0 on success , 1 in error case .
*/
2018-07-13 05:56:34 -04:00
int ssl_sock_update_ocsp_response ( struct buffer * ocsp_response , char * * err )
2014-06-16 12:36:30 -04:00
{
return ssl_sock_load_ocsp_response ( ocsp_response , NULL , NULL , err ) ;
}
/*
* This function load the OCSP Resonse in DER format contained in file at
* path ' ocsp_path ' and call ' ssl_sock_load_ocsp_response '
*
* Returns 0 on success , 1 in error case .
*/
static int ssl_sock_load_ocsp_response_from_file ( const char * ocsp_path , struct certificate_ocsp * ocsp , OCSP_CERTID * cid , char * * err )
{
int fd = - 1 ;
int r = 0 ;
int ret = 1 ;
fd = open ( ocsp_path , O_RDONLY ) ;
if ( fd = = - 1 ) {
memprintf ( err , " Error opening OCSP response file " ) ;
goto end ;
}
2018-07-13 04:54:26 -04:00
trash . data = 0 ;
while ( trash . data < trash . size ) {
r = read ( fd , trash . area + trash . data , trash . size - trash . data ) ;
2014-06-16 12:36:30 -04:00
if ( r < 0 ) {
if ( errno = = EINTR )
continue ;
memprintf ( err , " Error reading OCSP response from file " ) ;
goto end ;
}
else if ( r = = 0 ) {
break ;
}
2018-07-13 04:54:26 -04:00
trash . data + = r ;
2014-06-16 12:36:30 -04:00
}
close ( fd ) ;
fd = - 1 ;
ret = ssl_sock_load_ocsp_response ( & trash , ocsp , cid , err ) ;
end :
if ( fd ! = - 1 )
close ( fd ) ;
return ret ;
}
2017-01-13 11:48:18 -05:00
# endif
2014-06-16 12:36:30 -04:00
2015-02-27 13:56:49 -05:00
# if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
static int ssl_tlsext_ticket_key_cb ( SSL * s , unsigned char key_name [ 16 ] , unsigned char * iv , EVP_CIPHER_CTX * ectx , HMAC_CTX * hctx , int enc )
{
2018-02-16 05:23:49 -05:00
struct tls_keys_ref * ref ;
2019-01-10 11:51:55 -05:00
union tls_sess_key * keys ;
2015-02-27 13:56:49 -05:00
struct connection * conn ;
int head ;
int i ;
2018-02-16 05:23:49 -05:00
int ret = - 1 ; /* error by default */
2015-02-27 13:56:49 -05:00
BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
We never saw unexplicated crash with SSL, so I suppose that we are
luck, or the slot 0 is always reserved. Anyway the usage of the macro
SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
the deprecated functions SSL_get_app_data() and SSL_set_app_data()
by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
it reserves the slot in the SSL memory space.
For information, this is the two declaration which seems wrong or
incomplete in the OpenSSL ssl.h file. We can see the usage of the
slot 0 whoch is hardcoded, but never reserved.
#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
This patch must be backported at least in 1.8, maybe in other versions.
2018-06-17 15:37:05 -04:00
conn = SSL_get_ex_data ( s , ssl_app_data_index ) ;
2018-09-20 04:57:52 -04:00
ref = __objt_listener ( conn - > target ) - > bind_conf - > keys_ref ;
2018-02-16 05:23:49 -05:00
HA_RWLOCK_RDLOCK ( TLSKEYS_REF_LOCK , & ref - > lock ) ;
keys = ref - > tlskeys ;
head = ref - > tls_ticket_enc_index ;
2015-02-27 13:56:49 -05:00
if ( enc ) {
memcpy ( key_name , keys [ head ] . name , 16 ) ;
if ( ! RAND_pseudo_bytes ( iv , EVP_MAX_IV_LENGTH ) )
2018-02-16 05:23:49 -05:00
goto end ;
2015-02-27 13:56:49 -05:00
2019-01-10 11:51:55 -05:00
if ( ref - > key_size_bits = = 128 ) {
2015-02-27 13:56:49 -05:00
2019-01-10 11:51:55 -05:00
if ( ! EVP_EncryptInit_ex ( ectx , EVP_aes_128_cbc ( ) , NULL , keys [ head ] . key_128 . aes_key , iv ) )
goto end ;
HMAC_Init_ex ( hctx , keys [ head ] . key_128 . hmac_key , 16 , HASH_FUNCT ( ) , NULL ) ;
ret = 1 ;
}
else if ( ref - > key_size_bits = = 256 ) {
if ( ! EVP_EncryptInit_ex ( ectx , EVP_aes_256_cbc ( ) , NULL , keys [ head ] . key_256 . aes_key , iv ) )
goto end ;
HMAC_Init_ex ( hctx , keys [ head ] . key_256 . hmac_key , 32 , HASH_FUNCT ( ) , NULL ) ;
ret = 1 ;
}
2015-02-27 13:56:49 -05:00
} else {
for ( i = 0 ; i < TLS_TICKETS_NO ; i + + ) {
if ( ! memcmp ( key_name , keys [ ( head + i ) % TLS_TICKETS_NO ] . name , 16 ) )
goto found ;
}
2018-02-16 05:23:49 -05:00
ret = 0 ;
goto end ;
2015-02-27 13:56:49 -05:00
2018-02-16 05:23:49 -05:00
found :
2019-01-10 11:51:55 -05:00
if ( ref - > key_size_bits = = 128 ) {
HMAC_Init_ex ( hctx , keys [ ( head + i ) % TLS_TICKETS_NO ] . key_128 . hmac_key , 16 , HASH_FUNCT ( ) , NULL ) ;
if ( ! EVP_DecryptInit_ex ( ectx , EVP_aes_128_cbc ( ) , NULL , keys [ ( head + i ) % TLS_TICKETS_NO ] . key_128 . aes_key , iv ) )
goto end ;
/* 2 for key renewal, 1 if current key is still valid */
ret = i ? 2 : 1 ;
}
else if ( ref - > key_size_bits = = 256 ) {
HMAC_Init_ex ( hctx , keys [ ( head + i ) % TLS_TICKETS_NO ] . key_256 . hmac_key , 32 , HASH_FUNCT ( ) , NULL ) ;
if ( ! EVP_DecryptInit_ex ( ectx , EVP_aes_256_cbc ( ) , NULL , keys [ ( head + i ) % TLS_TICKETS_NO ] . key_256 . aes_key , iv ) )
goto end ;
/* 2 for key renewal, 1 if current key is still valid */
ret = i ? 2 : 1 ;
}
2015-02-27 13:56:49 -05:00
}
2019-01-10 11:51:55 -05:00
2018-02-16 05:23:49 -05:00
end :
HA_RWLOCK_RDUNLOCK ( TLSKEYS_REF_LOCK , & ref - > lock ) ;
return ret ;
2015-02-27 13:56:49 -05:00
}
2015-05-09 02:46:01 -04:00
struct tls_keys_ref * tlskeys_ref_lookup ( const char * filename )
{
struct tls_keys_ref * ref ;
list_for_each_entry ( ref , & tlskeys_reference , list )
if ( ref - > filename & & strcmp ( filename , ref - > filename ) = = 0 )
return ref ;
return NULL ;
}
struct tls_keys_ref * tlskeys_ref_lookupid ( int unique_id )
{
struct tls_keys_ref * ref ;
list_for_each_entry ( ref , & tlskeys_reference , list )
if ( ref - > unique_id = = unique_id )
return ref ;
return NULL ;
}
2019-01-10 11:51:55 -05:00
/* Update the key into ref: if keysize doesnt
* match existing ones , this function returns - 1
* else it returns 0 on success .
*/
int ssl_sock_update_tlskey_ref ( struct tls_keys_ref * ref ,
2018-07-13 05:56:34 -04:00
struct buffer * tlskey )
2018-02-16 05:23:49 -05:00
{
2019-01-10 11:51:55 -05:00
if ( ref - > key_size_bits = = 128 ) {
if ( tlskey - > data ! = sizeof ( struct tls_sess_key_128 ) )
return - 1 ;
}
else if ( ref - > key_size_bits = = 256 ) {
if ( tlskey - > data ! = sizeof ( struct tls_sess_key_256 ) )
return - 1 ;
}
else
return - 1 ;
2018-02-16 05:23:49 -05:00
HA_RWLOCK_WRLOCK ( TLSKEYS_REF_LOCK , & ref - > lock ) ;
2018-07-13 04:54:26 -04:00
memcpy ( ( char * ) ( ref - > tlskeys + ( ( ref - > tls_ticket_enc_index + 2 ) % TLS_TICKETS_NO ) ) ,
tlskey - > area , tlskey - > data ) ;
2018-02-16 05:23:49 -05:00
ref - > tls_ticket_enc_index = ( ref - > tls_ticket_enc_index + 1 ) % TLS_TICKETS_NO ;
HA_RWLOCK_WRUNLOCK ( TLSKEYS_REF_LOCK , & ref - > lock ) ;
2019-01-10 11:51:55 -05:00
return 0 ;
2018-02-16 05:23:49 -05:00
}
2018-07-13 05:56:34 -04:00
int ssl_sock_update_tlskey ( char * filename , struct buffer * tlskey , char * * err )
2018-02-16 05:23:49 -05:00
{
2015-05-09 02:46:01 -04:00
struct tls_keys_ref * ref = tlskeys_ref_lookup ( filename ) ;
if ( ! ref ) {
memprintf ( err , " Unable to locate the referenced filename: %s " , filename ) ;
return 1 ;
}
2019-01-10 11:51:55 -05:00
if ( ssl_sock_update_tlskey_ref ( ref , tlskey ) < 0 ) {
memprintf ( err , " Invalid key size " ) ;
return 1 ;
}
2015-05-09 02:46:01 -04:00
return 0 ;
}
/* This function finalize the configuration parsing. Its set all the
2016-12-22 16:46:15 -05:00
* automatic ids . It ' s called just after the basic checks . It returns
* 0 on success otherwise ERR_ * .
2015-05-09 02:46:01 -04:00
*/
2016-12-22 16:46:15 -05:00
static int tlskeys_finalize_config ( void )
2015-05-09 02:46:01 -04:00
{
int i = 0 ;
struct tls_keys_ref * ref , * ref2 , * ref3 ;
struct list tkr = LIST_HEAD_INIT ( tkr ) ;
list_for_each_entry ( ref , & tlskeys_reference , list ) {
if ( ref - > unique_id = = - 1 ) {
/* Look for the first free id. */
while ( 1 ) {
list_for_each_entry ( ref2 , & tlskeys_reference , list ) {
if ( ref2 - > unique_id = = i ) {
i + + ;
break ;
}
}
if ( & ref2 - > list = = & tlskeys_reference )
break ;
}
/* Uses the unique id and increment it for the next entry. */
ref - > unique_id = i ;
i + + ;
}
}
/* This sort the reference list by id. */
list_for_each_entry_safe ( ref , ref2 , & tlskeys_reference , list ) {
LIST_DEL ( & ref - > list ) ;
list_for_each_entry ( ref3 , & tkr , list ) {
if ( ref - > unique_id < ref3 - > unique_id ) {
LIST_ADDQ ( & ref3 - > list , & ref - > list ) ;
break ;
}
}
if ( & ref3 - > list = = & tkr )
LIST_ADDQ ( & tkr , & ref - > list ) ;
}
/* swap root */
LIST_ADD ( & tkr , & tlskeys_reference ) ;
LIST_DEL ( & tkr ) ;
2016-12-22 16:46:15 -05:00
return 0 ;
2015-05-09 02:46:01 -04:00
}
2015-02-27 13:56:49 -05:00
# endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */
2017-01-13 11:48:18 -05:00
# ifndef OPENSSL_NO_OCSP
2015-12-10 15:07:30 -05:00
int ssl_sock_get_ocsp_arg_kt_index ( int evp_keytype )
{
switch ( evp_keytype ) {
case EVP_PKEY_RSA :
return 2 ;
case EVP_PKEY_DSA :
return 0 ;
case EVP_PKEY_EC :
return 1 ;
}
return - 1 ;
}
2014-06-16 12:36:30 -04:00
/*
* Callback used to set OCSP status extension content in server hello .
*/
int ssl_sock_ocsp_stapling_cbk ( SSL * ssl , void * arg )
{
2015-12-10 15:07:30 -05:00
struct certificate_ocsp * ocsp ;
struct ocsp_cbk_arg * ocsp_arg ;
char * ssl_buf ;
EVP_PKEY * ssl_pkey ;
int key_type ;
int index ;
2016-04-03 07:48:42 -04:00
ocsp_arg = arg ;
2015-12-10 15:07:30 -05:00
ssl_pkey = SSL_get_privatekey ( ssl ) ;
if ( ! ssl_pkey )
return SSL_TLSEXT_ERR_NOACK ;
2016-08-29 07:26:37 -04:00
key_type = EVP_PKEY_base_id ( ssl_pkey ) ;
2015-12-10 15:07:30 -05:00
if ( ocsp_arg - > is_single & & ocsp_arg - > single_kt = = key_type )
ocsp = ocsp_arg - > s_ocsp ;
else {
/* For multiple certs per context, we have to find the correct OCSP response based on
* the certificate type
*/
index = ssl_sock_get_ocsp_arg_kt_index ( key_type ) ;
if ( index < 0 )
return SSL_TLSEXT_ERR_NOACK ;
ocsp = ocsp_arg - > m_ocsp [ index ] ;
}
2014-06-16 12:36:30 -04:00
if ( ! ocsp | |
2018-07-13 04:54:26 -04:00
! ocsp - > response . area | |
! ocsp - > response . data | |
2014-06-20 09:46:13 -04:00
( ocsp - > expire < now . tv_sec ) )
2014-06-16 12:36:30 -04:00
return SSL_TLSEXT_ERR_NOACK ;
2018-07-13 04:54:26 -04:00
ssl_buf = OPENSSL_malloc ( ocsp - > response . data ) ;
2014-06-16 12:36:30 -04:00
if ( ! ssl_buf )
return SSL_TLSEXT_ERR_NOACK ;
2018-07-13 04:54:26 -04:00
memcpy ( ssl_buf , ocsp - > response . area , ocsp - > response . data ) ;
SSL_set_tlsext_status_ocsp_resp ( ssl , ssl_buf , ocsp - > response . data ) ;
2014-06-16 12:36:30 -04:00
return SSL_TLSEXT_ERR_OK ;
}
/*
* This function enables the handling of OCSP status extension on ' ctx ' if a
* file name ' cert_path ' suffixed using " .ocsp " is present .
* To enable OCSP status extension , the issuer ' s certificate is mandatory .
* It should be present in the certificate ' s extra chain builded from file
* ' cert_path ' . If not found , the issuer certificate is loaded from a file
* named ' cert_path ' suffixed using ' . issuer ' .
*
* In addition , " .ocsp " file content is loaded as a DER format of an OCSP
* response . If file is empty or content is not a valid OCSP response ,
* OCSP status extension is enabled but OCSP response is ignored ( a warning
* is displayed ) .
*
* Returns 1 if no " .ocsp " file found , 0 if OCSP status extension is
2018-11-15 12:07:59 -05:00
* successfully enabled , or - 1 in other error case .
2014-06-16 12:36:30 -04:00
*/
static int ssl_sock_load_ocsp ( SSL_CTX * ctx , const char * cert_path )
{
BIO * in = NULL ;
X509 * x , * xi = NULL , * issuer = NULL ;
STACK_OF ( X509 ) * chain = NULL ;
OCSP_CERTID * cid = NULL ;
SSL * ssl ;
char ocsp_path [ MAXPATHLEN + 1 ] ;
int i , ret = - 1 ;
struct stat st ;
struct certificate_ocsp * ocsp = NULL , * iocsp ;
char * warn = NULL ;
unsigned char * p ;
2016-08-29 07:26:37 -04:00
pem_password_cb * passwd_cb ;
void * passwd_cb_userdata ;
void ( * callback ) ( void ) ;
2014-06-16 12:36:30 -04:00
snprintf ( ocsp_path , MAXPATHLEN + 1 , " %s.ocsp " , cert_path ) ;
if ( stat ( ocsp_path , & st ) )
return 1 ;
ssl = SSL_new ( ctx ) ;
if ( ! ssl )
goto out ;
x = SSL_get_certificate ( ssl ) ;
if ( ! x )
goto out ;
/* Try to lookup for issuer in certificate extra chain */
# ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS
SSL_CTX_get_extra_chain_certs ( ctx , & chain ) ;
# else
chain = ctx - > extra_certs ;
# endif
for ( i = 0 ; i < sk_X509_num ( chain ) ; i + + ) {
issuer = sk_X509_value ( chain , i ) ;
if ( X509_check_issued ( issuer , x ) = = X509_V_OK )
break ;
else
issuer = NULL ;
}
/* If not found try to load issuer from a suffixed file */
if ( ! issuer ) {
char issuer_path [ MAXPATHLEN + 1 ] ;
in = BIO_new ( BIO_s_file ( ) ) ;
if ( ! in )
goto out ;
snprintf ( issuer_path , MAXPATHLEN + 1 , " %s.issuer " , cert_path ) ;
if ( BIO_read_filename ( in , issuer_path ) < = 0 )
goto out ;
2016-08-29 07:26:37 -04:00
passwd_cb = SSL_CTX_get_default_passwd_cb ( ctx ) ;
passwd_cb_userdata = SSL_CTX_get_default_passwd_cb_userdata ( ctx ) ;
xi = PEM_read_bio_X509_AUX ( in , NULL , passwd_cb , passwd_cb_userdata ) ;
2014-06-16 12:36:30 -04:00
if ( ! xi )
goto out ;
if ( X509_check_issued ( xi , x ) ! = X509_V_OK )
goto out ;
issuer = xi ;
}
cid = OCSP_cert_to_id ( 0 , x , issuer ) ;
if ( ! cid )
goto out ;
i = i2d_OCSP_CERTID ( cid , NULL ) ;
if ( ! i | | ( i > OCSP_MAX_CERTID_ASN1_LENGTH ) )
goto out ;
2016-04-03 07:48:43 -04:00
ocsp = calloc ( 1 , sizeof ( * ocsp ) ) ;
2014-06-16 12:36:30 -04:00
if ( ! ocsp )
goto out ;
p = ocsp - > key_data ;
i2d_OCSP_CERTID ( cid , & p ) ;
iocsp = ( struct certificate_ocsp * ) ebmb_insert ( & cert_ocsp_tree , & ocsp - > key , OCSP_MAX_CERTID_ASN1_LENGTH ) ;
if ( iocsp = = ocsp )
ocsp = NULL ;
2016-08-29 07:26:37 -04:00
# ifndef SSL_CTX_get_tlsext_status_cb
# define SSL_CTX_get_tlsext_status_cb(ctx, cb) \
* cb = ( void ( * ) ( void ) ) ctx - > tlsext_status_cb ;
# endif
SSL_CTX_get_tlsext_status_cb ( ctx , & callback ) ;
if ( ! callback ) {
2016-04-03 07:48:43 -04:00
struct ocsp_cbk_arg * cb_arg = calloc ( 1 , sizeof ( * cb_arg ) ) ;
2017-01-06 06:57:46 -05:00
EVP_PKEY * pkey ;
2015-12-10 15:07:30 -05:00
cb_arg - > is_single = 1 ;
cb_arg - > s_ocsp = iocsp ;
2016-08-29 07:26:37 -04:00
2017-01-06 06:57:46 -05:00
pkey = X509_get_pubkey ( x ) ;
cb_arg - > single_kt = EVP_PKEY_base_id ( pkey ) ;
EVP_PKEY_free ( pkey ) ;
2015-12-10 15:07:30 -05:00
SSL_CTX_set_tlsext_status_cb ( ctx , ssl_sock_ocsp_stapling_cbk ) ;
SSL_CTX_set_tlsext_status_arg ( ctx , cb_arg ) ;
} else {
/*
* If the ctx has a status CB , then we have previously set an OCSP staple for this ctx
* Update that cb_arg with the new cert ' s staple
*/
2016-08-29 07:26:37 -04:00
struct ocsp_cbk_arg * cb_arg ;
2015-12-10 15:07:30 -05:00
struct certificate_ocsp * tmp_ocsp ;
int index ;
2016-08-29 07:26:37 -04:00
int key_type ;
2017-01-06 06:57:46 -05:00
EVP_PKEY * pkey ;
2016-08-29 07:26:37 -04:00
# ifdef SSL_CTX_get_tlsext_status_arg
SSL_CTX_ctrl ( ctx , SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB_ARG , 0 , & cb_arg ) ;
# else
cb_arg = ctx - > tlsext_status_arg ;
# endif
2015-12-10 15:07:30 -05:00
/*
* The following few lines will convert cb_arg from a single ocsp to multi ocsp
* the order of operations below matter , take care when changing it
*/
tmp_ocsp = cb_arg - > s_ocsp ;
index = ssl_sock_get_ocsp_arg_kt_index ( cb_arg - > single_kt ) ;
cb_arg - > s_ocsp = NULL ;
cb_arg - > m_ocsp [ index ] = tmp_ocsp ;
cb_arg - > is_single = 0 ;
cb_arg - > single_kt = 0 ;
2017-01-06 06:57:46 -05:00
pkey = X509_get_pubkey ( x ) ;
key_type = EVP_PKEY_base_id ( pkey ) ;
EVP_PKEY_free ( pkey ) ;
2016-08-29 07:26:37 -04:00
index = ssl_sock_get_ocsp_arg_kt_index ( key_type ) ;
2015-12-10 15:07:30 -05:00
if ( index > = 0 & & ! cb_arg - > m_ocsp [ index ] )
cb_arg - > m_ocsp [ index ] = iocsp ;
}
2014-06-16 12:36:30 -04:00
ret = 0 ;
warn = NULL ;
if ( ssl_sock_load_ocsp_response_from_file ( ocsp_path , iocsp , cid , & warn ) ) {
memprintf ( & warn , " Loading '%s': %s. Content will be ignored " , ocsp_path , warn ? warn : " failure " ) ;
2017-11-24 10:50:31 -05:00
ha_warning ( " %s. \n " , warn ) ;
2014-06-16 12:36:30 -04:00
}
out :
if ( ssl )
SSL_free ( ssl ) ;
if ( in )
BIO_free ( in ) ;
if ( xi )
X509_free ( xi ) ;
if ( cid )
OCSP_CERTID_free ( cid ) ;
if ( ocsp )
free ( ocsp ) ;
if ( warn )
free ( warn ) ;
return ret ;
}
# endif
2017-05-22 08:58:00 -04:00
# ifdef OPENSSL_IS_BORINGSSL
static int ssl_sock_set_ocsp_response_from_file ( SSL_CTX * ctx , const char * cert_path )
{
char ocsp_path [ MAXPATHLEN + 1 ] ;
struct stat st ;
int fd = - 1 , r = 0 ;
snprintf ( ocsp_path , MAXPATHLEN + 1 , " %s.ocsp " , cert_path ) ;
if ( stat ( ocsp_path , & st ) )
return 0 ;
fd = open ( ocsp_path , O_RDONLY ) ;
if ( fd = = - 1 ) {
2017-11-24 10:50:31 -05:00
ha_warning ( " Error opening OCSP response file %s. \n " , ocsp_path ) ;
2017-05-22 08:58:00 -04:00
return - 1 ;
}
2018-07-13 04:54:26 -04:00
trash . data = 0 ;
while ( trash . data < trash . size ) {
r = read ( fd , trash . area + trash . data , trash . size - trash . data ) ;
2017-05-22 08:58:00 -04:00
if ( r < 0 ) {
if ( errno = = EINTR )
continue ;
2017-11-24 10:50:31 -05:00
ha_warning ( " Error reading OCSP response from file %s. \n " , ocsp_path ) ;
2017-05-22 08:58:00 -04:00
close ( fd ) ;
return - 1 ;
}
else if ( r = = 0 ) {
break ;
}
2018-07-13 04:54:26 -04:00
trash . data + = r ;
2017-05-22 08:58:00 -04:00
}
close ( fd ) ;
2018-07-13 04:54:26 -04:00
return SSL_CTX_set_ocsp_response ( ctx , ( const uint8_t * ) trash . area ,
trash . data ) ;
2017-05-22 08:58:00 -04:00
}
# endif
2015-11-06 14:02:41 -05:00
# if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
2015-03-07 17:03:59 -05:00
# define CT_EXTENSION_TYPE 18
static int sctl_ex_index = - 1 ;
/*
* Try to parse Signed Certificate Timestamp List structure . This function
* makes only basic test if the data seems like SCTL . No signature validation
* is performed .
*/
2018-07-13 05:56:34 -04:00
static int ssl_sock_parse_sctl ( struct buffer * sctl )
2015-03-07 17:03:59 -05:00
{
int ret = 1 ;
int len , pos , sct_len ;
unsigned char * data ;
2018-07-13 04:54:26 -04:00
if ( sctl - > data < 2 )
2015-03-07 17:03:59 -05:00
goto out ;
2018-07-13 04:54:26 -04:00
data = ( unsigned char * ) sctl - > area ;
2015-03-07 17:03:59 -05:00
len = ( data [ 0 ] < < 8 ) | data [ 1 ] ;
2018-07-13 04:54:26 -04:00
if ( len + 2 ! = sctl - > data )
2015-03-07 17:03:59 -05:00
goto out ;
data = data + 2 ;
pos = 0 ;
while ( pos < len ) {
if ( len - pos < 2 )
goto out ;
sct_len = ( data [ pos ] < < 8 ) | data [ pos + 1 ] ;
if ( pos + sct_len + 2 > len )
goto out ;
pos + = sct_len + 2 ;
}
ret = 0 ;
out :
return ret ;
}
2018-07-13 05:56:34 -04:00
static int ssl_sock_load_sctl_from_file ( const char * sctl_path ,
struct buffer * * sctl )
2015-03-07 17:03:59 -05:00
{
int fd = - 1 ;
int r = 0 ;
int ret = 1 ;
* sctl = NULL ;
fd = open ( sctl_path , O_RDONLY ) ;
if ( fd = = - 1 )
goto end ;
2018-07-13 04:54:26 -04:00
trash . data = 0 ;
while ( trash . data < trash . size ) {
r = read ( fd , trash . area + trash . data , trash . size - trash . data ) ;
2015-03-07 17:03:59 -05:00
if ( r < 0 ) {
if ( errno = = EINTR )
continue ;
goto end ;
}
else if ( r = = 0 ) {
break ;
}
2018-07-13 04:54:26 -04:00
trash . data + = r ;
2015-03-07 17:03:59 -05:00
}
ret = ssl_sock_parse_sctl ( & trash ) ;
if ( ret )
goto end ;
2016-04-03 07:48:43 -04:00
* sctl = calloc ( 1 , sizeof ( * * sctl ) ) ;
2015-03-07 17:03:59 -05:00
if ( ! chunk_dup ( * sctl , & trash ) ) {
free ( * sctl ) ;
* sctl = NULL ;
goto end ;
}
end :
if ( fd ! = - 1 )
close ( fd ) ;
return ret ;
}
int ssl_sock_sctl_add_cbk ( SSL * ssl , unsigned ext_type , const unsigned char * * out , size_t * outlen , int * al , void * add_arg )
{
2018-07-13 05:56:34 -04:00
struct buffer * sctl = add_arg ;
2015-03-07 17:03:59 -05:00
2018-07-13 04:54:26 -04:00
* out = ( unsigned char * ) sctl - > area ;
* outlen = sctl - > data ;
2015-03-07 17:03:59 -05:00
return 1 ;
}
int ssl_sock_sctl_parse_cbk ( SSL * s , unsigned int ext_type , const unsigned char * in , size_t inlen , int * al , void * parse_arg )
{
return 1 ;
}
static int ssl_sock_load_sctl ( SSL_CTX * ctx , const char * cert_path )
{
char sctl_path [ MAXPATHLEN + 1 ] ;
int ret = - 1 ;
struct stat st ;
2018-07-13 05:56:34 -04:00
struct buffer * sctl = NULL ;
2015-03-07 17:03:59 -05:00
snprintf ( sctl_path , MAXPATHLEN + 1 , " %s.sctl " , cert_path ) ;
if ( stat ( sctl_path , & st ) )
return 1 ;
if ( ssl_sock_load_sctl_from_file ( sctl_path , & sctl ) )
goto out ;
if ( ! SSL_CTX_add_server_custom_ext ( ctx , CT_EXTENSION_TYPE , ssl_sock_sctl_add_cbk , NULL , sctl , ssl_sock_sctl_parse_cbk , NULL ) ) {
free ( sctl ) ;
goto out ;
}
SSL_CTX_set_ex_data ( ctx , sctl_ex_index , sctl ) ;
ret = 0 ;
out :
return ret ;
}
# endif
2012-09-03 14:36:47 -04:00
void ssl_sock_infocbk ( const SSL * ssl , int where , int ret )
{
BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
We never saw unexplicated crash with SSL, so I suppose that we are
luck, or the slot 0 is always reserved. Anyway the usage of the macro
SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
the deprecated functions SSL_get_app_data() and SSL_set_app_data()
by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
it reserves the slot in the SSL memory space.
For information, this is the two declaration which seems wrong or
incomplete in the OpenSSL ssl.h file. We can see the usage of the
slot 0 whoch is hardcoded, but never reserved.
#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
This patch must be backported at least in 1.8, maybe in other versions.
2018-06-17 15:37:05 -04:00
struct connection * conn = SSL_get_ex_data ( ssl , ssl_app_data_index ) ;
2014-01-28 09:43:53 -05:00
BIO * write_bio ;
2015-02-27 10:36:16 -05:00
( void ) ret ; /* shut gcc stupid warning */
2012-09-03 14:36:47 -04:00
2019-01-21 12:35:03 -05:00
# ifndef SSL_OP_NO_RENEGOTIATION
/* Please note that BoringSSL defines this macro to zero so don't
* change this to # if and do not assign a default value to this macro !
*/
2012-09-03 14:36:47 -04:00
if ( where & SSL_CB_HANDSHAKE_START ) {
/* Disable renegotiation (CVE-2009-3555) */
2017-11-23 12:21:29 -05:00
if ( ( conn - > flags & ( CO_FL_CONNECTED | CO_FL_EARLY_SSL_HS | CO_FL_EARLY_DATA ) ) = = CO_FL_CONNECTED ) {
2012-09-03 14:36:47 -04:00
conn - > flags | = CO_FL_ERROR ;
2012-12-03 10:32:10 -05:00
conn - > err_code = CO_ER_SSL_RENEG ;
}
2012-09-03 14:36:47 -04:00
}
2019-01-21 12:35:03 -05:00
# endif
2014-01-28 09:43:53 -05:00
if ( ( where & SSL_CB_ACCEPT_LOOP ) = = SSL_CB_ACCEPT_LOOP ) {
if ( ! ( conn - > xprt_st & SSL_SOCK_ST_FL_16K_WBFSIZE ) ) {
/* Long certificate chains optimz
If write and read bios are differents , we
consider that the buffering was activated ,
so we rise the output buffer size from 4 k
to 16 k */
write_bio = SSL_get_wbio ( ssl ) ;
if ( write_bio ! = SSL_get_rbio ( ssl ) ) {
BIO_set_write_buffer_size ( write_bio , 16384 ) ;
conn - > xprt_st | = SSL_SOCK_ST_FL_16K_WBFSIZE ;
}
}
}
2012-09-03 14:36:47 -04:00
}
2012-09-21 07:15:06 -04:00
/* Callback is called for each certificate of the chain during a verify
ok is set to 1 if preverify detect no error on current certificate .
Returns 0 to break the handshake , 1 otherwise . */
2013-06-27 03:05:25 -04:00
int ssl_sock_bind_verifycbk ( int ok , X509_STORE_CTX * x_store )
2012-09-21 07:15:06 -04:00
{
SSL * ssl ;
struct connection * conn ;
2012-09-21 08:31:21 -04:00
int err , depth ;
2012-09-21 07:15:06 -04:00
ssl = X509_STORE_CTX_get_ex_data ( x_store , SSL_get_ex_data_X509_STORE_CTX_idx ( ) ) ;
BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
We never saw unexplicated crash with SSL, so I suppose that we are
luck, or the slot 0 is always reserved. Anyway the usage of the macro
SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
the deprecated functions SSL_get_app_data() and SSL_set_app_data()
by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
it reserves the slot in the SSL memory space.
For information, this is the two declaration which seems wrong or
incomplete in the OpenSSL ssl.h file. We can see the usage of the
slot 0 whoch is hardcoded, but never reserved.
#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
This patch must be backported at least in 1.8, maybe in other versions.
2018-06-17 15:37:05 -04:00
conn = SSL_get_ex_data ( ssl , ssl_app_data_index ) ;
2012-09-21 07:15:06 -04:00
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
conn - > xprt_st | = SSL_SOCK_ST_FL_VERIFY_DONE ;
2012-09-21 07:15:06 -04:00
2012-09-21 08:31:21 -04:00
if ( ok ) /* no errors */
return ok ;
depth = X509_STORE_CTX_get_error_depth ( x_store ) ;
err = X509_STORE_CTX_get_error ( x_store ) ;
/* check if CA error needs to be ignored */
if ( depth > 0 ) {
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
if ( ! SSL_SOCK_ST_TO_CA_ERROR ( conn - > xprt_st ) ) {
conn - > xprt_st | = SSL_SOCK_CA_ERROR_TO_ST ( err ) ;
conn - > xprt_st | = SSL_SOCK_CAEDEPTH_TO_ST ( depth ) ;
2012-09-21 09:27:54 -04:00
}
2018-09-20 04:57:52 -04:00
if ( __objt_listener ( conn - > target ) - > bind_conf - > ca_ignerr & ( 1ULL < < err ) ) {
2016-10-10 05:59:50 -04:00
ssl_sock_dump_errors ( conn ) ;
2012-12-03 07:24:29 -05:00
ERR_clear_error ( ) ;
2012-09-21 08:31:21 -04:00
return 1 ;
2012-12-03 07:24:29 -05:00
}
2012-09-21 08:31:21 -04:00
2012-12-03 10:32:10 -05:00
conn - > err_code = CO_ER_SSL_CA_FAIL ;
2012-09-21 08:31:21 -04:00
return 0 ;
}
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
if ( ! SSL_SOCK_ST_TO_CRTERROR ( conn - > xprt_st ) )
conn - > xprt_st | = SSL_SOCK_CRTERROR_TO_ST ( err ) ;
2012-09-21 09:27:54 -04:00
2012-09-21 08:31:21 -04:00
/* check if certificate error needs to be ignored */
2018-09-20 04:57:52 -04:00
if ( __objt_listener ( conn - > target ) - > bind_conf - > crt_ignerr & ( 1ULL < < err ) ) {
2016-10-10 05:59:50 -04:00
ssl_sock_dump_errors ( conn ) ;
2012-12-03 07:24:29 -05:00
ERR_clear_error ( ) ;
2012-09-21 08:31:21 -04:00
return 1 ;
2012-12-03 07:24:29 -05:00
}
2012-09-21 08:31:21 -04:00
2012-12-03 10:32:10 -05:00
conn - > err_code = CO_ER_SSL_CRT_FAIL ;
2012-09-21 08:31:21 -04:00
return 0 ;
2012-09-21 07:15:06 -04:00
}
2017-02-25 06:45:22 -05:00
static inline
void ssl_sock_parse_clienthello ( int write_p , int version , int content_type ,
2017-03-08 05:07:10 -05:00
const void * buf , size_t len , SSL * ssl )
2017-02-25 06:45:22 -05:00
{
2017-03-08 05:07:10 -05:00
struct ssl_capture * capture ;
2017-02-25 06:45:22 -05:00
unsigned char * msg ;
unsigned char * end ;
2017-03-08 05:07:10 -05:00
size_t rec_len ;
2017-02-25 06:45:22 -05:00
/* This function is called for "from client" and "to server"
* connections . The combination of write_p = = 0 and content_type = = 22
2018-11-15 12:07:59 -05:00
* is only available during " from client " connection .
2017-02-25 06:45:22 -05:00
*/
/* "write_p" is set to 0 is the bytes are received messages,
* otherwise it is set to 1.
*/
if ( write_p ! = 0 )
return ;
/* content_type contains the type of message received or sent
* according with the SSL / TLS protocol spec . This message is
* encoded with one byte . The value 256 ( two bytes ) is used
* for designing the SSL / TLS record layer . According with the
* rfc6101 , the expected message ( other than 256 ) are :
* - change_cipher_spec ( 20 )
* - alert ( 21 )
* - handshake ( 22 )
* - application_data ( 23 )
* - ( 255 )
* We are interessed by the handshake and specially the client
* hello .
*/
if ( content_type ! = 22 )
return ;
/* The message length is at least 4 bytes, containing the
* message type and the message length .
*/
if ( len < 4 )
return ;
/* First byte of the handshake message id the type of
* message . The konwn types are :
* - hello_request ( 0 )
* - client_hello ( 1 )
* - server_hello ( 2 )
* - certificate ( 11 )
* - server_key_exchange ( 12 )
* - certificate_request ( 13 )
* - server_hello_done ( 14 )
* We are interested by the client hello .
*/
msg = ( unsigned char * ) buf ;
if ( msg [ 0 ] ! = 1 )
return ;
/* Next three bytes are the length of the message. The total length
* must be this decoded length + 4. If the length given as argument
* is not the same , we abort the protocol dissector .
*/
rec_len = ( msg [ 1 ] < < 16 ) + ( msg [ 2 ] < < 8 ) + msg [ 3 ] ;
if ( len < rec_len + 4 )
return ;
msg + = 4 ;
end = msg + rec_len ;
if ( end < msg )
return ;
/* Expect 2 bytes for protocol version (1 byte for major and 1 byte
* for minor , the random , composed by 4 bytes for the unix time and
2018-11-28 09:20:25 -05:00
* 28 bytes for unix payload . So we jump 1 + 1 + 4 + 28.
2017-02-25 06:45:22 -05:00
*/
2018-11-28 09:20:25 -05:00
msg + = 1 + 1 + 4 + 28 ;
if ( msg > end )
return ;
/* Next, is session id:
* if present , we have to jump by length + 1 for the size information
* if not present , we have to jump by 1 only
*/
if ( msg [ 0 ] > 0 )
msg + = msg [ 0 ] ;
msg + = 1 ;
2017-02-25 06:45:22 -05:00
if ( msg > end )
return ;
/* Next two bytes are the ciphersuite length. */
if ( msg + 2 > end )
return ;
rec_len = ( msg [ 0 ] < < 8 ) + msg [ 1 ] ;
msg + = 2 ;
if ( msg + rec_len > end | | msg + rec_len < msg )
return ;
2017-11-24 11:34:44 -05:00
capture = pool_alloc_dirty ( pool_head_ssl_capture ) ;
2017-03-08 05:07:10 -05:00
if ( ! capture )
return ;
2017-02-25 06:45:22 -05:00
/* Compute the xxh64 of the ciphersuite. */
capture - > xxh64 = XXH64 ( msg , rec_len , 0 ) ;
/* Capture the ciphersuite. */
2017-03-08 05:07:10 -05:00
capture - > ciphersuite_len = ( global_ssl . capture_cipherlist < rec_len ) ?
global_ssl . capture_cipherlist : rec_len ;
2017-02-25 06:45:22 -05:00
memcpy ( capture - > ciphersuite , msg , capture - > ciphersuite_len ) ;
2017-03-08 05:07:10 -05:00
SSL_set_ex_data ( ssl , ssl_capture_ptr_index , capture ) ;
2017-02-25 06:45:22 -05:00
}
2014-04-25 13:05:36 -04:00
/* Callback is called for ssl protocol analyse */
void ssl_sock_msgcbk ( int write_p , int version , int content_type , const void * buf , size_t len , SSL * ssl , void * arg )
{
# ifdef TLS1_RT_HEARTBEAT
/* test heartbeat received (write_p is set to 0
for a received record ) */
2014-04-25 14:02:39 -04:00
if ( ( content_type = = TLS1_RT_HEARTBEAT ) & & ( write_p = = 0 ) ) {
BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
We never saw unexplicated crash with SSL, so I suppose that we are
luck, or the slot 0 is always reserved. Anyway the usage of the macro
SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
the deprecated functions SSL_get_app_data() and SSL_set_app_data()
by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
it reserves the slot in the SSL memory space.
For information, this is the two declaration which seems wrong or
incomplete in the OpenSSL ssl.h file. We can see the usage of the
slot 0 whoch is hardcoded, but never reserved.
#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
This patch must be backported at least in 1.8, maybe in other versions.
2018-06-17 15:37:05 -04:00
struct connection * conn = SSL_get_ex_data ( ssl , ssl_app_data_index ) ;
2014-04-25 14:02:39 -04:00
const unsigned char * p = buf ;
unsigned int payload ;
2014-04-25 13:05:36 -04:00
conn - > xprt_st | = SSL_SOCK_RECV_HEARTBEAT ;
2014-04-25 14:02:39 -04:00
/* Check if this is a CVE-2014-0160 exploitation attempt. */
if ( * p ! = TLS1_HB_REQUEST )
return ;
2014-04-25 17:59:58 -04:00
if ( len < 1 + 2 + 16 ) /* 1 type + 2 size + 0 payload + 16 padding */
2014-04-25 14:02:39 -04:00
goto kill_it ;
payload = ( p [ 1 ] * 256 ) + p [ 2 ] ;
2014-04-25 17:44:22 -04:00
if ( 3 + payload + 16 < = len )
2014-04-25 14:02:39 -04:00
return ; /* OK no problem */
2014-04-25 17:59:58 -04:00
kill_it :
2014-04-25 17:44:22 -04:00
/* We have a clear heartbleed attack (CVE-2014-0160), the
* advertised payload is larger than the advertised packet
* length , so we have garbage in the buffer between the
* payload and the end of the buffer ( p + len ) . We can ' t know
* if the SSL stack is patched , and we don ' t know if we can
* safely wipe out the area between p + 3 + len and payload .
* So instead , we prevent the response from being sent by
* setting the max_send_fragment to 0 and we report an SSL
* error , which will kill this connection . It will be reported
* above as SSL_ERROR_SSL while an other handshake failure with
2014-04-25 14:02:39 -04:00
* a heartbeat message will be reported as SSL_ERROR_SYSCALL .
*/
2014-04-25 17:44:22 -04:00
ssl - > max_send_fragment = 0 ;
2014-04-25 14:02:39 -04:00
SSLerr ( SSL_F_TLS1_HEARTBEAT , SSL_R_SSL_HANDSHAKE_FAILURE ) ;
return ;
}
2014-04-25 13:05:36 -04:00
# endif
2017-03-08 05:07:10 -05:00
if ( global_ssl . capture_cipherlist > 0 )
ssl_sock_parse_clienthello ( write_p , version , content_type , buf , len , ssl ) ;
2014-04-25 13:05:36 -04:00
}
2018-11-20 17:33:50 -05:00
# if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
static int ssl_sock_srv_select_protos ( SSL * s , unsigned char * * out , unsigned char * outlen ,
const unsigned char * in , unsigned int inlen ,
void * arg )
{
struct server * srv = arg ;
if ( SSL_select_next_proto ( out , outlen , in , inlen , ( unsigned char * ) srv - > ssl_ctx . npn_str ,
srv - > ssl_ctx . npn_len ) = = OPENSSL_NPN_NEGOTIATED )
return SSL_TLSEXT_ERR_OK ;
return SSL_TLSEXT_ERR_NOACK ;
}
# endif
2018-02-15 07:34:58 -05:00
# if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2012-10-18 12:57:14 -04:00
/* This callback is used so that the server advertises the list of
* negociable protocols for NPN .
*/
static int ssl_sock_advertise_npn_protos ( SSL * s , const unsigned char * * data ,
unsigned int * len , void * arg )
{
2016-12-29 12:26:15 -05:00
struct ssl_bind_conf * conf = arg ;
2012-10-18 12:57:14 -04:00
* data = ( const unsigned char * ) conf - > npn_str ;
* len = conf - > npn_len ;
return SSL_TLSEXT_ERR_OK ;
}
# endif
2014-02-13 06:29:42 -05:00
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2013-04-01 20:30:41 -04:00
/* This callback is used so that the server advertises the list of
* negociable protocols for ALPN .
*/
2014-02-13 06:29:42 -05:00
static int ssl_sock_advertise_alpn_protos ( SSL * s , const unsigned char * * out ,
unsigned char * outlen ,
const unsigned char * server ,
unsigned int server_len , void * arg )
2013-04-01 20:30:41 -04:00
{
2016-12-29 12:26:15 -05:00
struct ssl_bind_conf * conf = arg ;
2013-04-01 20:30:41 -04:00
2014-02-13 06:29:42 -05:00
if ( SSL_select_next_proto ( ( unsigned char * * ) out , outlen , ( const unsigned char * ) conf - > alpn_str ,
conf - > alpn_len , server , server_len ) ! = OPENSSL_NPN_NEGOTIATED ) {
return SSL_TLSEXT_ERR_NOACK ;
}
2013-04-01 20:30:41 -04:00
return SSL_TLSEXT_ERR_OK ;
}
# endif
2015-06-17 09:48:26 -04:00
# ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
2017-01-13 11:48:18 -05:00
# ifndef SSL_NO_GENERATE_CERTIFICATES
2015-10-09 05:46:32 -04:00
2015-06-11 07:39:32 -04:00
/* Create a X509 certificate with the specified servername and serial. This
* function returns a SSL_CTX object or NULL if an error occurs . */
2015-10-09 05:15:03 -04:00
static SSL_CTX *
2015-11-12 05:35:51 -05:00
ssl_sock_do_create_cert ( const char * servername , struct bind_conf * bind_conf , SSL * ssl )
2015-06-09 11:29:50 -04:00
{
2015-10-09 05:15:03 -04:00
X509 * cacert = bind_conf - > ca_sign_cert ;
EVP_PKEY * capkey = bind_conf - > ca_sign_pkey ;
2015-06-09 11:29:50 -04:00
SSL_CTX * ssl_ctx = NULL ;
X509 * newcrt = NULL ;
EVP_PKEY * pkey = NULL ;
2017-08-11 04:56:00 -04:00
SSL * tmp_ssl = NULL ;
2018-10-01 12:41:36 -04:00
CONF * ctmp = NULL ;
2015-06-09 11:29:50 -04:00
X509_NAME * name ;
const EVP_MD * digest ;
X509V3_CTX ctx ;
unsigned int i ;
2016-08-29 07:26:37 -04:00
int key_type ;
2015-06-09 11:29:50 -04:00
2017-07-28 10:56:09 -04:00
/* Get the private key of the default certificate and use it */
2017-08-11 04:56:00 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined LIBRESSL_VERSION_NUMBER)
pkey = SSL_CTX_get0_privatekey ( bind_conf - > default_ctx ) ;
# else
tmp_ssl = SSL_new ( bind_conf - > default_ctx ) ;
if ( tmp_ssl )
pkey = SSL_get_privatekey ( tmp_ssl ) ;
# endif
if ( ! pkey )
2015-06-09 11:29:50 -04:00
goto mkcert_error ;
/* Create the certificate */
if ( ! ( newcrt = X509_new ( ) ) )
goto mkcert_error ;
/* Set version number for the certificate (X509v3) and the serial
* number */
if ( X509_set_version ( newcrt , 2L ) ! = 1 )
goto mkcert_error ;
2019-03-08 12:54:43 -05:00
ASN1_INTEGER_set ( X509_get_serialNumber ( newcrt ) , _HA_ATOMIC_ADD ( & ssl_ctx_serial , 1 ) ) ;
2015-06-09 11:29:50 -04:00
/* Set duration for the certificate */
2018-12-14 11:47:02 -05:00
if ( ! X509_gmtime_adj ( X509_getm_notBefore ( newcrt ) , ( long ) - 60 * 60 * 24 ) | |
! X509_gmtime_adj ( X509_getm_notAfter ( newcrt ) , ( long ) 60 * 60 * 24 * 365 ) )
2015-06-09 11:29:50 -04:00
goto mkcert_error ;
/* set public key in the certificate */
if ( X509_set_pubkey ( newcrt , pkey ) ! = 1 )
goto mkcert_error ;
/* Set issuer name from the CA */
if ( ! ( name = X509_get_subject_name ( cacert ) ) )
goto mkcert_error ;
if ( X509_set_issuer_name ( newcrt , name ) ! = 1 )
goto mkcert_error ;
/* Set the subject name using the same, but the CN */
name = X509_NAME_dup ( name ) ;
if ( X509_NAME_add_entry_by_txt ( name , " CN " , MBSTRING_ASC ,
( const unsigned char * ) servername ,
- 1 , - 1 , 0 ) ! = 1 ) {
X509_NAME_free ( name ) ;
goto mkcert_error ;
}
if ( X509_set_subject_name ( newcrt , name ) ! = 1 ) {
X509_NAME_free ( name ) ;
goto mkcert_error ;
}
X509_NAME_free ( name ) ;
/* Add x509v3 extensions as specified */
2018-10-01 12:41:36 -04:00
ctmp = NCONF_new ( NULL ) ;
2015-06-09 11:29:50 -04:00
X509V3_set_ctx ( & ctx , cacert , newcrt , NULL , NULL , 0 ) ;
for ( i = 0 ; i < X509V3_EXT_SIZE ; i + + ) {
X509_EXTENSION * ext ;
2018-10-01 12:41:36 -04:00
if ( ! ( ext = X509V3_EXT_nconf ( ctmp , & ctx , x509v3_ext_names [ i ] , x509v3_ext_values [ i ] ) ) )
2015-06-09 11:29:50 -04:00
goto mkcert_error ;
if ( ! X509_add_ext ( newcrt , ext , - 1 ) ) {
X509_EXTENSION_free ( ext ) ;
goto mkcert_error ;
}
X509_EXTENSION_free ( ext ) ;
}
/* Sign the certificate with the CA private key */
2016-08-29 07:26:37 -04:00
key_type = EVP_PKEY_base_id ( capkey ) ;
if ( key_type = = EVP_PKEY_DSA )
digest = EVP_sha1 ( ) ;
else if ( key_type = = EVP_PKEY_RSA )
2015-06-09 11:29:50 -04:00
digest = EVP_sha256 ( ) ;
2016-08-29 07:26:37 -04:00
else if ( key_type = = EVP_PKEY_EC )
2015-10-09 05:15:03 -04:00
digest = EVP_sha256 ( ) ;
else {
2018-10-01 12:45:19 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1000000fL) && !defined(OPENSSL_IS_BORINGSSL)
2015-10-09 05:15:03 -04:00
int nid ;
if ( EVP_PKEY_get_default_digest_nid ( capkey , & nid ) < = 0 )
goto mkcert_error ;
if ( ! ( digest = EVP_get_digestbynid ( nid ) ) )
goto mkcert_error ;
2015-10-19 07:59:24 -04:00
# else
goto mkcert_error ;
# endif
2015-10-09 05:15:03 -04:00
}
2015-06-09 11:29:50 -04:00
if ( ! ( X509_sign ( newcrt , capkey , digest ) ) )
goto mkcert_error ;
/* Create and set the new SSL_CTX */
if ( ! ( ssl_ctx = SSL_CTX_new ( SSLv23_server_method ( ) ) ) )
goto mkcert_error ;
if ( ! SSL_CTX_use_PrivateKey ( ssl_ctx , pkey ) )
goto mkcert_error ;
if ( ! SSL_CTX_use_certificate ( ssl_ctx , newcrt ) )
goto mkcert_error ;
if ( ! SSL_CTX_check_private_key ( ssl_ctx ) )
goto mkcert_error ;
if ( newcrt ) X509_free ( newcrt ) ;
2015-10-09 05:15:03 -04:00
2017-03-03 11:04:14 -05:00
# ifndef OPENSSL_NO_DH
2015-10-09 05:46:32 -04:00
SSL_CTX_set_tmp_dh_callback ( ssl_ctx , ssl_get_tmp_dh ) ;
2017-03-03 11:04:14 -05:00
# endif
2015-10-09 05:46:32 -04:00
# if defined(SSL_CTX_set_tmp_ecdh) && !defined(OPENSSL_NO_ECDH)
{
2016-12-29 12:26:15 -05:00
const char * ecdhe = ( bind_conf - > ssl_conf . ecdhe ? bind_conf - > ssl_conf . ecdhe : ECDHE_DEFAULT_CURVE ) ;
2015-10-09 05:46:32 -04:00
EC_KEY * ecc ;
int nid ;
if ( ( nid = OBJ_sn2nid ( ecdhe ) ) = = NID_undef )
goto end ;
if ( ! ( ecc = EC_KEY_new_by_curve_name ( nid ) ) )
goto end ;
SSL_CTX_set_tmp_ecdh ( ssl_ctx , ecc ) ;
EC_KEY_free ( ecc ) ;
}
# endif
end :
2015-06-09 11:29:50 -04:00
return ssl_ctx ;
mkcert_error :
2018-10-01 12:41:36 -04:00
if ( ctmp ) NCONF_free ( ctmp ) ;
2017-08-11 04:56:00 -04:00
if ( tmp_ssl ) SSL_free ( tmp_ssl ) ;
2015-06-09 11:29:50 -04:00
if ( ssl_ctx ) SSL_CTX_free ( ssl_ctx ) ;
if ( newcrt ) X509_free ( newcrt ) ;
return NULL ;
}
2015-10-09 05:15:03 -04:00
SSL_CTX *
2015-11-12 05:35:51 -05:00
ssl_sock_create_cert ( struct connection * conn , const char * servername , unsigned int key )
2015-10-09 05:15:03 -04:00
{
2018-09-20 04:57:52 -04:00
struct bind_conf * bind_conf = __objt_listener ( conn - > target ) - > bind_conf ;
2015-11-12 05:35:51 -05:00
return ssl_sock_do_create_cert ( servername , bind_conf , conn - > xprt_ctx ) ;
2015-10-09 05:15:03 -04:00
}
2015-06-11 07:39:32 -04:00
/* Do a lookup for a certificate in the LRU cache used to store generated
2017-06-15 10:37:39 -04:00
* certificates and immediately assign it to the SSL session if not null . */
2015-06-11 07:39:32 -04:00
SSL_CTX *
2017-06-15 10:37:39 -04:00
ssl_sock_assign_generated_cert ( unsigned int key , struct bind_conf * bind_conf , SSL * ssl )
2015-06-11 07:39:32 -04:00
{
struct lru64 * lru = NULL ;
if ( ssl_ctx_lru_tree ) {
2018-05-17 04:56:47 -04:00
HA_RWLOCK_WRLOCK ( SSL_GEN_CERTS_LOCK , & ssl_ctx_lru_rwlock ) ;
2015-11-12 05:35:51 -05:00
lru = lru64_lookup ( key , ssl_ctx_lru_tree , bind_conf - > ca_sign_cert , 0 ) ;
2017-06-15 10:37:39 -04:00
if ( lru & & lru - > domain ) {
if ( ssl )
SSL_set_SSL_CTX ( ssl , ( SSL_CTX * ) lru - > data ) ;
2018-05-17 04:56:47 -04:00
HA_RWLOCK_WRUNLOCK ( SSL_GEN_CERTS_LOCK , & ssl_ctx_lru_rwlock ) ;
2015-06-11 07:39:32 -04:00
return ( SSL_CTX * ) lru - > data ;
2017-06-15 10:37:39 -04:00
}
2018-05-17 04:56:47 -04:00
HA_RWLOCK_WRUNLOCK ( SSL_GEN_CERTS_LOCK , & ssl_ctx_lru_rwlock ) ;
2015-06-11 07:39:32 -04:00
}
return NULL ;
}
2017-06-15 10:37:39 -04:00
/* Same as <ssl_sock_assign_generated_cert> but without SSL session. This
* function is not thread - safe , it should only be used to check if a certificate
* exists in the lru cache ( with no warranty it will not be removed by another
* thread ) . It is kept for backward compatibility . */
SSL_CTX *
ssl_sock_get_generated_cert ( unsigned int key , struct bind_conf * bind_conf )
{
return ssl_sock_assign_generated_cert ( key , bind_conf , NULL ) ;
}
2015-07-28 10:03:47 -04:00
/* Set a certificate int the LRU cache used to store generated
* certificate . Return 0 on success , otherwise - 1 */
int
2015-11-12 05:35:51 -05:00
ssl_sock_set_generated_cert ( SSL_CTX * ssl_ctx , unsigned int key , struct bind_conf * bind_conf )
2015-06-11 07:39:32 -04:00
{
struct lru64 * lru = NULL ;
if ( ssl_ctx_lru_tree ) {
2017-11-07 04:42:54 -05:00
HA_RWLOCK_WRLOCK ( SSL_GEN_CERTS_LOCK , & ssl_ctx_lru_rwlock ) ;
2015-11-12 05:35:51 -05:00
lru = lru64_get ( key , ssl_ctx_lru_tree , bind_conf - > ca_sign_cert , 0 ) ;
2017-06-15 10:37:39 -04:00
if ( ! lru ) {
2017-11-07 04:42:54 -05:00
HA_RWLOCK_WRUNLOCK ( SSL_GEN_CERTS_LOCK , & ssl_ctx_lru_rwlock ) ;
2015-07-28 10:03:47 -04:00
return - 1 ;
2017-06-15 10:37:39 -04:00
}
2015-06-11 07:39:32 -04:00
if ( lru - > domain & & lru - > data )
lru - > free ( ( SSL_CTX * ) lru - > data ) ;
2015-10-09 05:15:03 -04:00
lru64_commit ( lru , ssl_ctx , bind_conf - > ca_sign_cert , 0 , ( void ( * ) ( void * ) ) SSL_CTX_free ) ;
2017-11-07 04:42:54 -05:00
HA_RWLOCK_WRUNLOCK ( SSL_GEN_CERTS_LOCK , & ssl_ctx_lru_rwlock ) ;
2015-07-28 10:03:47 -04:00
return 0 ;
2015-06-11 07:39:32 -04:00
}
2015-07-28 10:03:47 -04:00
return - 1 ;
2015-06-11 07:39:32 -04:00
}
2015-11-12 05:35:51 -05:00
/* Compute the key of the certificate. */
2015-06-11 07:39:32 -04:00
unsigned int
2015-11-12 05:35:51 -05:00
ssl_sock_generated_cert_key ( const void * data , size_t len )
2015-06-11 07:39:32 -04:00
{
return XXH32 ( data , len , ssl_ctx_lru_seed ) ;
}
BUG/MAJOR: ssl: free the generated SSL_CTX if the LRU cache is disabled
Kim Seri reported that haproxy 1.6.0 crashes after a few requests
when a bind line has SSL enabled with more than one certificate. This
was caused by an insufficient condition to free generated certs during
ssl_sock_close() which can also catch other certs.
Christopher Faulet analysed the situation like this :
-------
First the LRU tree is only initialized when the SSL certs generation is
configured on a bind line. So, in the most of cases, it is NULL (it is
not the same thing than empty).
When the SSL certs generation is used, if the cache is not NULL, a such
certificate is pushed in the cache and there is no need to release it
when the connection is closed.
But it can be disabled in the configuration. So in that case, we must
free the generated certificate when the connection is closed.
Then here, we have really a bug. Here is the buggy part:
3125) if (conn->xprt_ctx) {
3126) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
3127) if (!ssl_ctx_lru_tree && objt_listener(conn->target)) {
3128) SSL_CTX *ctx = SSL_get_SSL_CTX(conn->xprt_ctx);
3129) if (ctx != 3130)
SSL_CTX_free(ctx);
3131) }
3133) SSL_free(conn->xprt_ctx);
3134) conn->xprt_ctx = NULL;
3135) sslconns--;
3136) }
The check on the line 3127 is not enough to determine if this is a
generated certificate or not. Because ssl_ctx_lru_tree is NULL,
generated certificates, if any, must be freed. But here ctx should also
be compared to all SNI certificates and not only to default_ctx. Because
of this bug, when a SNI certificate is used for a connection, it is
erroneously freed when this connection is closed.
-------
Christopher provided this reliable reproducer :
----------
global
tune.ssl.default-dh-param 2048
daemon
listen ssl_server
mode tcp
bind 127.0.0.1:4443 ssl crt srv1.test.com.pem crt srv2.test.com.pem
timeout connect 5000
timeout client 30000
timeout server 30000
server srv A.B.C.D:80
You just need to generate 2 SSL certificates with 2 CN (here
srv1.test.com and srv2.test.com).
Then, by doing SSL requests with the first CN, there is no problem. But
with the second CN, it should segfault on the 2nd request.
openssl s_client -connect 127.0.0.1:4443 -servername srv1.test.com // OK
openssl s_client -connect 127.0.0.1:4443 -servername srv1.test.com // OK
But,
openssl s_client -connect 127.0.0.1:4443 -servername srv2.test.com // OK
openssl s_client -connect 127.0.0.1:4443 -servername srv2.test.com // KO
-----------
A long discussion led to the following proposal which this patch implements :
- the cert is generated. It gets a refcount = 1.
- we assign it to the SSL. Its refcount becomes two.
- we try to insert it into the tree. The tree will handle its freeing
using SSL_CTX_free() during eviction.
- if we can't insert into the tree because the tree is disabled, then
we have to call SSL_CTX_free() ourselves, then we'd rather do it
immediately. It will more closely mimmick the case where the cert
is added to the tree and immediately evicted by concurrent activity
on the cache.
- we never have to call SSL_CTX_free() during ssl_sock_close() because
the SSL session only relies on openssl doing the right thing based on
the refcount only.
- thus we never need to know how the cert was created since the
SSL_CTX_free() is either guaranteed or already done for generated
certs, and this protects other ones against any accidental call to
SSL_CTX_free() without having to track where the cert comes from.
This patch also reduces the inter-dependence between the LRU tree and
the SSL stack, so it should cause less sweating to migrate to threads
later.
This bug is specific to 1.6.0, as it was introduced after dev7 by
this fix :
d2cab92 ("BUG/MINOR: ssl: fix management of the cache where forged certificates are stored")
Thus a backport to 1.6 is required, but not to 1.5.
2015-10-20 09:16:01 -04:00
/* Generate a cert and immediately assign it to the SSL session so that the cert's
* refcount is maintained regardless of the cert ' s presence in the LRU cache .
*/
2017-08-14 05:01:25 -04:00
static int
2015-10-09 05:15:03 -04:00
ssl_sock_generate_certificate ( const char * servername , struct bind_conf * bind_conf , SSL * ssl )
2015-06-09 11:29:50 -04:00
{
X509 * cacert = bind_conf - > ca_sign_cert ;
SSL_CTX * ssl_ctx = NULL ;
struct lru64 * lru = NULL ;
2015-11-12 05:35:51 -05:00
unsigned int key ;
2015-06-09 11:29:50 -04:00
2015-11-12 05:35:51 -05:00
key = ssl_sock_generated_cert_key ( servername , strlen ( servername ) ) ;
2015-06-09 11:29:50 -04:00
if ( ssl_ctx_lru_tree ) {
2017-11-07 04:42:54 -05:00
HA_RWLOCK_WRLOCK ( SSL_GEN_CERTS_LOCK , & ssl_ctx_lru_rwlock ) ;
2015-11-12 05:35:51 -05:00
lru = lru64_get ( key , ssl_ctx_lru_tree , cacert , 0 ) ;
2015-06-09 11:29:50 -04:00
if ( lru & & lru - > domain )
ssl_ctx = ( SSL_CTX * ) lru - > data ;
2015-07-28 10:03:47 -04:00
if ( ! ssl_ctx & & lru ) {
2015-11-12 05:35:51 -05:00
ssl_ctx = ssl_sock_do_create_cert ( servername , bind_conf , ssl ) ;
2015-06-09 11:29:50 -04:00
lru64_commit ( lru , ssl_ctx , cacert , 0 , ( void ( * ) ( void * ) ) SSL_CTX_free ) ;
2015-07-28 10:03:47 -04:00
}
BUG/MAJOR: ssl: free the generated SSL_CTX if the LRU cache is disabled
Kim Seri reported that haproxy 1.6.0 crashes after a few requests
when a bind line has SSL enabled with more than one certificate. This
was caused by an insufficient condition to free generated certs during
ssl_sock_close() which can also catch other certs.
Christopher Faulet analysed the situation like this :
-------
First the LRU tree is only initialized when the SSL certs generation is
configured on a bind line. So, in the most of cases, it is NULL (it is
not the same thing than empty).
When the SSL certs generation is used, if the cache is not NULL, a such
certificate is pushed in the cache and there is no need to release it
when the connection is closed.
But it can be disabled in the configuration. So in that case, we must
free the generated certificate when the connection is closed.
Then here, we have really a bug. Here is the buggy part:
3125) if (conn->xprt_ctx) {
3126) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
3127) if (!ssl_ctx_lru_tree && objt_listener(conn->target)) {
3128) SSL_CTX *ctx = SSL_get_SSL_CTX(conn->xprt_ctx);
3129) if (ctx != 3130)
SSL_CTX_free(ctx);
3131) }
3133) SSL_free(conn->xprt_ctx);
3134) conn->xprt_ctx = NULL;
3135) sslconns--;
3136) }
The check on the line 3127 is not enough to determine if this is a
generated certificate or not. Because ssl_ctx_lru_tree is NULL,
generated certificates, if any, must be freed. But here ctx should also
be compared to all SNI certificates and not only to default_ctx. Because
of this bug, when a SNI certificate is used for a connection, it is
erroneously freed when this connection is closed.
-------
Christopher provided this reliable reproducer :
----------
global
tune.ssl.default-dh-param 2048
daemon
listen ssl_server
mode tcp
bind 127.0.0.1:4443 ssl crt srv1.test.com.pem crt srv2.test.com.pem
timeout connect 5000
timeout client 30000
timeout server 30000
server srv A.B.C.D:80
You just need to generate 2 SSL certificates with 2 CN (here
srv1.test.com and srv2.test.com).
Then, by doing SSL requests with the first CN, there is no problem. But
with the second CN, it should segfault on the 2nd request.
openssl s_client -connect 127.0.0.1:4443 -servername srv1.test.com // OK
openssl s_client -connect 127.0.0.1:4443 -servername srv1.test.com // OK
But,
openssl s_client -connect 127.0.0.1:4443 -servername srv2.test.com // OK
openssl s_client -connect 127.0.0.1:4443 -servername srv2.test.com // KO
-----------
A long discussion led to the following proposal which this patch implements :
- the cert is generated. It gets a refcount = 1.
- we assign it to the SSL. Its refcount becomes two.
- we try to insert it into the tree. The tree will handle its freeing
using SSL_CTX_free() during eviction.
- if we can't insert into the tree because the tree is disabled, then
we have to call SSL_CTX_free() ourselves, then we'd rather do it
immediately. It will more closely mimmick the case where the cert
is added to the tree and immediately evicted by concurrent activity
on the cache.
- we never have to call SSL_CTX_free() during ssl_sock_close() because
the SSL session only relies on openssl doing the right thing based on
the refcount only.
- thus we never need to know how the cert was created since the
SSL_CTX_free() is either guaranteed or already done for generated
certs, and this protects other ones against any accidental call to
SSL_CTX_free() without having to track where the cert comes from.
This patch also reduces the inter-dependence between the LRU tree and
the SSL stack, so it should cause less sweating to migrate to threads
later.
This bug is specific to 1.6.0, as it was introduced after dev7 by
this fix :
d2cab92 ("BUG/MINOR: ssl: fix management of the cache where forged certificates are stored")
Thus a backport to 1.6 is required, but not to 1.5.
2015-10-20 09:16:01 -04:00
SSL_set_SSL_CTX ( ssl , ssl_ctx ) ;
2017-11-07 04:42:54 -05:00
HA_RWLOCK_WRUNLOCK ( SSL_GEN_CERTS_LOCK , & ssl_ctx_lru_rwlock ) ;
2017-08-14 05:01:25 -04:00
return 1 ;
2015-06-09 11:29:50 -04:00
}
BUG/MAJOR: ssl: free the generated SSL_CTX if the LRU cache is disabled
Kim Seri reported that haproxy 1.6.0 crashes after a few requests
when a bind line has SSL enabled with more than one certificate. This
was caused by an insufficient condition to free generated certs during
ssl_sock_close() which can also catch other certs.
Christopher Faulet analysed the situation like this :
-------
First the LRU tree is only initialized when the SSL certs generation is
configured on a bind line. So, in the most of cases, it is NULL (it is
not the same thing than empty).
When the SSL certs generation is used, if the cache is not NULL, a such
certificate is pushed in the cache and there is no need to release it
when the connection is closed.
But it can be disabled in the configuration. So in that case, we must
free the generated certificate when the connection is closed.
Then here, we have really a bug. Here is the buggy part:
3125) if (conn->xprt_ctx) {
3126) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
3127) if (!ssl_ctx_lru_tree && objt_listener(conn->target)) {
3128) SSL_CTX *ctx = SSL_get_SSL_CTX(conn->xprt_ctx);
3129) if (ctx != 3130)
SSL_CTX_free(ctx);
3131) }
3133) SSL_free(conn->xprt_ctx);
3134) conn->xprt_ctx = NULL;
3135) sslconns--;
3136) }
The check on the line 3127 is not enough to determine if this is a
generated certificate or not. Because ssl_ctx_lru_tree is NULL,
generated certificates, if any, must be freed. But here ctx should also
be compared to all SNI certificates and not only to default_ctx. Because
of this bug, when a SNI certificate is used for a connection, it is
erroneously freed when this connection is closed.
-------
Christopher provided this reliable reproducer :
----------
global
tune.ssl.default-dh-param 2048
daemon
listen ssl_server
mode tcp
bind 127.0.0.1:4443 ssl crt srv1.test.com.pem crt srv2.test.com.pem
timeout connect 5000
timeout client 30000
timeout server 30000
server srv A.B.C.D:80
You just need to generate 2 SSL certificates with 2 CN (here
srv1.test.com and srv2.test.com).
Then, by doing SSL requests with the first CN, there is no problem. But
with the second CN, it should segfault on the 2nd request.
openssl s_client -connect 127.0.0.1:4443 -servername srv1.test.com // OK
openssl s_client -connect 127.0.0.1:4443 -servername srv1.test.com // OK
But,
openssl s_client -connect 127.0.0.1:4443 -servername srv2.test.com // OK
openssl s_client -connect 127.0.0.1:4443 -servername srv2.test.com // KO
-----------
A long discussion led to the following proposal which this patch implements :
- the cert is generated. It gets a refcount = 1.
- we assign it to the SSL. Its refcount becomes two.
- we try to insert it into the tree. The tree will handle its freeing
using SSL_CTX_free() during eviction.
- if we can't insert into the tree because the tree is disabled, then
we have to call SSL_CTX_free() ourselves, then we'd rather do it
immediately. It will more closely mimmick the case where the cert
is added to the tree and immediately evicted by concurrent activity
on the cache.
- we never have to call SSL_CTX_free() during ssl_sock_close() because
the SSL session only relies on openssl doing the right thing based on
the refcount only.
- thus we never need to know how the cert was created since the
SSL_CTX_free() is either guaranteed or already done for generated
certs, and this protects other ones against any accidental call to
SSL_CTX_free() without having to track where the cert comes from.
This patch also reduces the inter-dependence between the LRU tree and
the SSL stack, so it should cause less sweating to migrate to threads
later.
This bug is specific to 1.6.0, as it was introduced after dev7 by
this fix :
d2cab92 ("BUG/MINOR: ssl: fix management of the cache where forged certificates are stored")
Thus a backport to 1.6 is required, but not to 1.5.
2015-10-20 09:16:01 -04:00
else {
2015-11-12 05:35:51 -05:00
ssl_ctx = ssl_sock_do_create_cert ( servername , bind_conf , ssl ) ;
BUG/MAJOR: ssl: free the generated SSL_CTX if the LRU cache is disabled
Kim Seri reported that haproxy 1.6.0 crashes after a few requests
when a bind line has SSL enabled with more than one certificate. This
was caused by an insufficient condition to free generated certs during
ssl_sock_close() which can also catch other certs.
Christopher Faulet analysed the situation like this :
-------
First the LRU tree is only initialized when the SSL certs generation is
configured on a bind line. So, in the most of cases, it is NULL (it is
not the same thing than empty).
When the SSL certs generation is used, if the cache is not NULL, a such
certificate is pushed in the cache and there is no need to release it
when the connection is closed.
But it can be disabled in the configuration. So in that case, we must
free the generated certificate when the connection is closed.
Then here, we have really a bug. Here is the buggy part:
3125) if (conn->xprt_ctx) {
3126) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
3127) if (!ssl_ctx_lru_tree && objt_listener(conn->target)) {
3128) SSL_CTX *ctx = SSL_get_SSL_CTX(conn->xprt_ctx);
3129) if (ctx != 3130)
SSL_CTX_free(ctx);
3131) }
3133) SSL_free(conn->xprt_ctx);
3134) conn->xprt_ctx = NULL;
3135) sslconns--;
3136) }
The check on the line 3127 is not enough to determine if this is a
generated certificate or not. Because ssl_ctx_lru_tree is NULL,
generated certificates, if any, must be freed. But here ctx should also
be compared to all SNI certificates and not only to default_ctx. Because
of this bug, when a SNI certificate is used for a connection, it is
erroneously freed when this connection is closed.
-------
Christopher provided this reliable reproducer :
----------
global
tune.ssl.default-dh-param 2048
daemon
listen ssl_server
mode tcp
bind 127.0.0.1:4443 ssl crt srv1.test.com.pem crt srv2.test.com.pem
timeout connect 5000
timeout client 30000
timeout server 30000
server srv A.B.C.D:80
You just need to generate 2 SSL certificates with 2 CN (here
srv1.test.com and srv2.test.com).
Then, by doing SSL requests with the first CN, there is no problem. But
with the second CN, it should segfault on the 2nd request.
openssl s_client -connect 127.0.0.1:4443 -servername srv1.test.com // OK
openssl s_client -connect 127.0.0.1:4443 -servername srv1.test.com // OK
But,
openssl s_client -connect 127.0.0.1:4443 -servername srv2.test.com // OK
openssl s_client -connect 127.0.0.1:4443 -servername srv2.test.com // KO
-----------
A long discussion led to the following proposal which this patch implements :
- the cert is generated. It gets a refcount = 1.
- we assign it to the SSL. Its refcount becomes two.
- we try to insert it into the tree. The tree will handle its freeing
using SSL_CTX_free() during eviction.
- if we can't insert into the tree because the tree is disabled, then
we have to call SSL_CTX_free() ourselves, then we'd rather do it
immediately. It will more closely mimmick the case where the cert
is added to the tree and immediately evicted by concurrent activity
on the cache.
- we never have to call SSL_CTX_free() during ssl_sock_close() because
the SSL session only relies on openssl doing the right thing based on
the refcount only.
- thus we never need to know how the cert was created since the
SSL_CTX_free() is either guaranteed or already done for generated
certs, and this protects other ones against any accidental call to
SSL_CTX_free() without having to track where the cert comes from.
This patch also reduces the inter-dependence between the LRU tree and
the SSL stack, so it should cause less sweating to migrate to threads
later.
This bug is specific to 1.6.0, as it was introduced after dev7 by
this fix :
d2cab92 ("BUG/MINOR: ssl: fix management of the cache where forged certificates are stored")
Thus a backport to 1.6 is required, but not to 1.5.
2015-10-20 09:16:01 -04:00
SSL_set_SSL_CTX ( ssl , ssl_ctx ) ;
/* No LRU cache, this CTX will be released as soon as the session dies */
SSL_CTX_free ( ssl_ctx ) ;
2017-08-14 05:01:25 -04:00
return 1 ;
BUG/MAJOR: ssl: free the generated SSL_CTX if the LRU cache is disabled
Kim Seri reported that haproxy 1.6.0 crashes after a few requests
when a bind line has SSL enabled with more than one certificate. This
was caused by an insufficient condition to free generated certs during
ssl_sock_close() which can also catch other certs.
Christopher Faulet analysed the situation like this :
-------
First the LRU tree is only initialized when the SSL certs generation is
configured on a bind line. So, in the most of cases, it is NULL (it is
not the same thing than empty).
When the SSL certs generation is used, if the cache is not NULL, a such
certificate is pushed in the cache and there is no need to release it
when the connection is closed.
But it can be disabled in the configuration. So in that case, we must
free the generated certificate when the connection is closed.
Then here, we have really a bug. Here is the buggy part:
3125) if (conn->xprt_ctx) {
3126) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
3127) if (!ssl_ctx_lru_tree && objt_listener(conn->target)) {
3128) SSL_CTX *ctx = SSL_get_SSL_CTX(conn->xprt_ctx);
3129) if (ctx != 3130)
SSL_CTX_free(ctx);
3131) }
3133) SSL_free(conn->xprt_ctx);
3134) conn->xprt_ctx = NULL;
3135) sslconns--;
3136) }
The check on the line 3127 is not enough to determine if this is a
generated certificate or not. Because ssl_ctx_lru_tree is NULL,
generated certificates, if any, must be freed. But here ctx should also
be compared to all SNI certificates and not only to default_ctx. Because
of this bug, when a SNI certificate is used for a connection, it is
erroneously freed when this connection is closed.
-------
Christopher provided this reliable reproducer :
----------
global
tune.ssl.default-dh-param 2048
daemon
listen ssl_server
mode tcp
bind 127.0.0.1:4443 ssl crt srv1.test.com.pem crt srv2.test.com.pem
timeout connect 5000
timeout client 30000
timeout server 30000
server srv A.B.C.D:80
You just need to generate 2 SSL certificates with 2 CN (here
srv1.test.com and srv2.test.com).
Then, by doing SSL requests with the first CN, there is no problem. But
with the second CN, it should segfault on the 2nd request.
openssl s_client -connect 127.0.0.1:4443 -servername srv1.test.com // OK
openssl s_client -connect 127.0.0.1:4443 -servername srv1.test.com // OK
But,
openssl s_client -connect 127.0.0.1:4443 -servername srv2.test.com // OK
openssl s_client -connect 127.0.0.1:4443 -servername srv2.test.com // KO
-----------
A long discussion led to the following proposal which this patch implements :
- the cert is generated. It gets a refcount = 1.
- we assign it to the SSL. Its refcount becomes two.
- we try to insert it into the tree. The tree will handle its freeing
using SSL_CTX_free() during eviction.
- if we can't insert into the tree because the tree is disabled, then
we have to call SSL_CTX_free() ourselves, then we'd rather do it
immediately. It will more closely mimmick the case where the cert
is added to the tree and immediately evicted by concurrent activity
on the cache.
- we never have to call SSL_CTX_free() during ssl_sock_close() because
the SSL session only relies on openssl doing the right thing based on
the refcount only.
- thus we never need to know how the cert was created since the
SSL_CTX_free() is either guaranteed or already done for generated
certs, and this protects other ones against any accidental call to
SSL_CTX_free() without having to track where the cert comes from.
This patch also reduces the inter-dependence between the LRU tree and
the SSL stack, so it should cause less sweating to migrate to threads
later.
This bug is specific to 1.6.0, as it was introduced after dev7 by
this fix :
d2cab92 ("BUG/MINOR: ssl: fix management of the cache where forged certificates are stored")
Thus a backport to 1.6 is required, but not to 1.5.
2015-10-20 09:16:01 -04:00
}
2017-08-14 05:01:25 -04:00
return 0 ;
}
static int
ssl_sock_generate_certificate_from_conn ( struct bind_conf * bind_conf , SSL * ssl )
{
unsigned int key ;
BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
We never saw unexplicated crash with SSL, so I suppose that we are
luck, or the slot 0 is always reserved. Anyway the usage of the macro
SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
the deprecated functions SSL_get_app_data() and SSL_set_app_data()
by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
it reserves the slot in the SSL memory space.
For information, this is the two declaration which seems wrong or
incomplete in the OpenSSL ssl.h file. We can see the usage of the
slot 0 whoch is hardcoded, but never reserved.
#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
This patch must be backported at least in 1.8, maybe in other versions.
2018-06-17 15:37:05 -04:00
struct connection * conn = SSL_get_ex_data ( ssl , ssl_app_data_index ) ;
2017-08-14 05:01:25 -04:00
conn_get_to_addr ( conn ) ;
if ( conn - > flags & CO_FL_ADDR_TO_SET ) {
key = ssl_sock_generated_cert_key ( & conn - > addr . to , get_addr_len ( & conn - > addr . to ) ) ;
2017-06-15 10:37:39 -04:00
if ( ssl_sock_assign_generated_cert ( key , bind_conf , ssl ) )
2017-08-14 05:01:25 -04:00
return 1 ;
}
return 0 ;
2015-06-09 11:29:50 -04:00
}
2017-01-13 11:48:18 -05:00
# endif /* !defined SSL_NO_GENERATE_CERTIFICATES */
2015-06-09 11:29:50 -04:00
2017-05-18 05:56:58 -04:00
# ifndef SSL_OP_CIPHER_SERVER_PREFERENCE /* needs OpenSSL >= 0.9.7 */
# define SSL_OP_CIPHER_SERVER_PREFERENCE 0
# endif
# ifndef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION /* needs OpenSSL >= 0.9.7 */
# define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0
# define SSL_renegotiate_pending(arg) 0
# endif
# ifndef SSL_OP_SINGLE_ECDH_USE /* needs OpenSSL >= 0.9.8 */
# define SSL_OP_SINGLE_ECDH_USE 0
# endif
# ifndef SSL_OP_NO_TICKET /* needs OpenSSL >= 0.9.8 */
# define SSL_OP_NO_TICKET 0
# endif
# ifndef SSL_OP_NO_COMPRESSION /* needs OpenSSL >= 0.9.9 */
# define SSL_OP_NO_COMPRESSION 0
# endif
2017-07-12 06:53:02 -04:00
# ifdef OPENSSL_NO_SSL3 /* SSLv3 support removed */
# undef SSL_OP_NO_SSLv3
# define SSL_OP_NO_SSLv3 0
# endif
2017-05-18 05:56:58 -04:00
# ifndef SSL_OP_NO_TLSv1_1 /* needs OpenSSL >= 1.0.1 */
# define SSL_OP_NO_TLSv1_1 0
# endif
# ifndef SSL_OP_NO_TLSv1_2 /* needs OpenSSL >= 1.0.1 */
# define SSL_OP_NO_TLSv1_2 0
# endif
2017-08-16 05:33:17 -04:00
# ifndef SSL_OP_NO_TLSv1_3 /* needs OpenSSL >= 1.1.1 */
2017-05-18 05:56:58 -04:00
# define SSL_OP_NO_TLSv1_3 0
# endif
# ifndef SSL_OP_SINGLE_DH_USE /* needs OpenSSL >= 0.9.6 */
# define SSL_OP_SINGLE_DH_USE 0
# endif
# ifndef SSL_OP_SINGLE_ECDH_USE /* needs OpenSSL >= 1.0.0 */
# define SSL_OP_SINGLE_ECDH_USE 0
# endif
# ifndef SSL_MODE_RELEASE_BUFFERS /* needs OpenSSL >= 1.0.0 */
# define SSL_MODE_RELEASE_BUFFERS 0
# endif
# ifndef SSL_MODE_SMALL_BUFFERS /* needs small_records.patch */
# define SSL_MODE_SMALL_BUFFERS 0
# endif
2018-05-18 11:55:57 -04:00
# ifndef SSL_OP_PRIORITIZE_CHACHA /* needs OpenSSL >= 1.1.1 */
# define SSL_OP_PRIORITIZE_CHACHA 0
# endif
2017-05-18 05:56:58 -04:00
2017-10-02 11:12:06 -04:00
# if (OPENSSL_VERSION_NUMBER < 0x1010000fL)
2017-05-18 06:33:19 -04:00
typedef enum { SET_CLIENT , SET_SERVER } set_context_func ;
static void ctx_set_SSLv3_func ( SSL_CTX * ctx , set_context_func c )
2017-05-18 05:56:58 -04:00
{
2017-07-12 06:53:02 -04:00
# if SSL_OP_NO_SSLv3
2017-05-18 06:33:19 -04:00
c = = SET_SERVER ? SSL_CTX_set_ssl_version ( ctx , SSLv3_server_method ( ) )
2017-05-18 05:56:58 -04:00
: SSL_CTX_set_ssl_version ( ctx , SSLv3_client_method ( ) ) ;
# endif
}
2017-05-18 06:33:19 -04:00
static void ctx_set_TLSv10_func ( SSL_CTX * ctx , set_context_func c ) {
c = = SET_SERVER ? SSL_CTX_set_ssl_version ( ctx , TLSv1_server_method ( ) )
2017-05-18 05:56:58 -04:00
: SSL_CTX_set_ssl_version ( ctx , TLSv1_client_method ( ) ) ;
}
2017-05-18 06:33:19 -04:00
static void ctx_set_TLSv11_func ( SSL_CTX * ctx , set_context_func c ) {
2017-05-18 05:56:58 -04:00
# if SSL_OP_NO_TLSv1_1
2017-05-18 06:33:19 -04:00
c = = SET_SERVER ? SSL_CTX_set_ssl_version ( ctx , TLSv1_1_server_method ( ) )
2017-05-18 05:56:58 -04:00
: SSL_CTX_set_ssl_version ( ctx , TLSv1_1_client_method ( ) ) ;
# endif
}
2017-05-18 06:33:19 -04:00
static void ctx_set_TLSv12_func ( SSL_CTX * ctx , set_context_func c ) {
2017-05-18 05:56:58 -04:00
# if SSL_OP_NO_TLSv1_2
2017-05-18 06:33:19 -04:00
c = = SET_SERVER ? SSL_CTX_set_ssl_version ( ctx , TLSv1_2_server_method ( ) )
2017-05-18 05:56:58 -04:00
: SSL_CTX_set_ssl_version ( ctx , TLSv1_2_client_method ( ) ) ;
# endif
}
2018-08-13 19:56:13 -04:00
/* TLSv1.2 is the last supported version in this context. */
2017-05-18 06:33:19 -04:00
static void ctx_set_TLSv13_func ( SSL_CTX * ctx , set_context_func c ) { }
/* Unusable in this context. */
static void ssl_set_SSLv3_func ( SSL * ssl , set_context_func c ) { }
static void ssl_set_TLSv10_func ( SSL * ssl , set_context_func c ) { }
static void ssl_set_TLSv11_func ( SSL * ssl , set_context_func c ) { }
static void ssl_set_TLSv12_func ( SSL * ssl , set_context_func c ) { }
static void ssl_set_TLSv13_func ( SSL * ssl , set_context_func c ) { }
2017-05-18 05:56:58 -04:00
# else /* openssl >= 1.1.0 */
2017-05-18 06:33:19 -04:00
typedef enum { SET_MIN , SET_MAX } set_context_func ;
static void ctx_set_SSLv3_func ( SSL_CTX * ctx , set_context_func c ) {
c = = SET_MAX ? SSL_CTX_set_max_proto_version ( ctx , SSL3_VERSION )
2017-05-18 05:56:58 -04:00
: SSL_CTX_set_min_proto_version ( ctx , SSL3_VERSION ) ;
}
2017-05-18 06:33:19 -04:00
static void ssl_set_SSLv3_func ( SSL * ssl , set_context_func c ) {
c = = SET_MAX ? SSL_set_max_proto_version ( ssl , SSL3_VERSION )
: SSL_set_min_proto_version ( ssl , SSL3_VERSION ) ;
}
static void ctx_set_TLSv10_func ( SSL_CTX * ctx , set_context_func c ) {
c = = SET_MAX ? SSL_CTX_set_max_proto_version ( ctx , TLS1_VERSION )
2017-05-18 05:56:58 -04:00
: SSL_CTX_set_min_proto_version ( ctx , TLS1_VERSION ) ;
}
2017-05-18 06:33:19 -04:00
static void ssl_set_TLSv10_func ( SSL * ssl , set_context_func c ) {
c = = SET_MAX ? SSL_set_max_proto_version ( ssl , TLS1_VERSION )
: SSL_set_min_proto_version ( ssl , TLS1_VERSION ) ;
}
static void ctx_set_TLSv11_func ( SSL_CTX * ctx , set_context_func c ) {
c = = SET_MAX ? SSL_CTX_set_max_proto_version ( ctx , TLS1_1_VERSION )
2017-05-18 05:56:58 -04:00
: SSL_CTX_set_min_proto_version ( ctx , TLS1_1_VERSION ) ;
}
2017-05-18 06:33:19 -04:00
static void ssl_set_TLSv11_func ( SSL * ssl , set_context_func c ) {
c = = SET_MAX ? SSL_set_max_proto_version ( ssl , TLS1_1_VERSION )
: SSL_set_min_proto_version ( ssl , TLS1_1_VERSION ) ;
}
static void ctx_set_TLSv12_func ( SSL_CTX * ctx , set_context_func c ) {
c = = SET_MAX ? SSL_CTX_set_max_proto_version ( ctx , TLS1_2_VERSION )
2017-05-18 05:56:58 -04:00
: SSL_CTX_set_min_proto_version ( ctx , TLS1_2_VERSION ) ;
}
2017-05-18 06:33:19 -04:00
static void ssl_set_TLSv12_func ( SSL * ssl , set_context_func c ) {
c = = SET_MAX ? SSL_set_max_proto_version ( ssl , TLS1_2_VERSION )
: SSL_set_min_proto_version ( ssl , TLS1_2_VERSION ) ;
}
static void ctx_set_TLSv13_func ( SSL_CTX * ctx , set_context_func c ) {
2017-05-18 05:56:58 -04:00
# if SSL_OP_NO_TLSv1_3
2017-05-18 06:33:19 -04:00
c = = SET_MAX ? SSL_CTX_set_max_proto_version ( ctx , TLS1_3_VERSION )
2017-05-18 05:56:58 -04:00
: SSL_CTX_set_min_proto_version ( ctx , TLS1_3_VERSION ) ;
# endif
}
2017-05-18 06:33:19 -04:00
static void ssl_set_TLSv13_func ( SSL * ssl , set_context_func c ) {
# if SSL_OP_NO_TLSv1_3
c = = SET_MAX ? SSL_set_max_proto_version ( ssl , TLS1_3_VERSION )
: SSL_set_min_proto_version ( ssl , TLS1_3_VERSION ) ;
2017-05-18 05:56:58 -04:00
# endif
}
2017-05-18 06:33:19 -04:00
# endif
static void ctx_set_None_func ( SSL_CTX * ctx , set_context_func c ) { }
static void ssl_set_None_func ( SSL * ssl , set_context_func c ) { }
2017-05-18 05:56:58 -04:00
static struct {
int option ;
uint16_t flag ;
2017-05-18 06:33:19 -04:00
void ( * ctx_set_version ) ( SSL_CTX * , set_context_func ) ;
void ( * ssl_set_version ) ( SSL * , set_context_func ) ;
2017-05-18 05:56:58 -04:00
const char * name ;
} methodVersions [ ] = {
2017-05-18 06:33:19 -04:00
{ 0 , 0 , ctx_set_None_func , ssl_set_None_func , " NONE " } , /* CONF_TLSV_NONE */
{ SSL_OP_NO_SSLv3 , MC_SSL_O_NO_SSLV3 , ctx_set_SSLv3_func , ssl_set_SSLv3_func , " SSLv3 " } , /* CONF_SSLV3 */
{ SSL_OP_NO_TLSv1 , MC_SSL_O_NO_TLSV10 , ctx_set_TLSv10_func , ssl_set_TLSv10_func , " TLSv1.0 " } , /* CONF_TLSV10 */
{ SSL_OP_NO_TLSv1_1 , MC_SSL_O_NO_TLSV11 , ctx_set_TLSv11_func , ssl_set_TLSv11_func , " TLSv1.1 " } , /* CONF_TLSV11 */
{ SSL_OP_NO_TLSv1_2 , MC_SSL_O_NO_TLSV12 , ctx_set_TLSv12_func , ssl_set_TLSv12_func , " TLSv1.2 " } , /* CONF_TLSV12 */
{ SSL_OP_NO_TLSv1_3 , MC_SSL_O_NO_TLSV13 , ctx_set_TLSv13_func , ssl_set_TLSv13_func , " TLSv1.3 " } , /* CONF_TLSV13 */
2017-05-18 05:56:58 -04:00
} ;
2017-03-01 12:54:56 -05:00
static void ssl_sock_switchctx_set ( SSL * ssl , SSL_CTX * ctx )
{
SSL_set_verify ( ssl , SSL_CTX_get_verify_mode ( ctx ) , ssl_sock_bind_verifycbk ) ;
SSL_set_client_CA_list ( ssl , SSL_dup_CA_list ( SSL_CTX_get_client_CA_list ( ctx ) ) ) ;
SSL_set_SSL_CTX ( ssl , ctx ) ;
}
2017-08-16 05:33:17 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L) || defined(OPENSSL_IS_BORINGSSL)
2017-02-20 10:11:50 -05:00
static int ssl_sock_switchctx_err_cbk ( SSL * ssl , int * al , void * priv )
{
2017-08-14 05:01:25 -04:00
struct bind_conf * s = priv ;
2017-02-20 10:11:50 -05:00
( void ) al ; /* shut gcc stupid warning */
2017-08-14 05:01:25 -04:00
if ( SSL_get_servername ( ssl , TLSEXT_NAMETYPE_host_name ) | | s - > generate_certs )
return SSL_TLSEXT_ERR_OK ;
return SSL_TLSEXT_ERR_NOACK ;
2017-02-20 10:11:50 -05:00
}
2017-08-16 05:33:17 -04:00
# ifdef OPENSSL_IS_BORINGSSL
2017-02-20 10:11:50 -05:00
static int ssl_sock_switchctx_cbk ( const struct ssl_early_callback_ctx * ctx )
{
2017-08-16 05:28:44 -04:00
SSL * ssl = ctx - > ssl ;
2017-08-16 05:33:17 -04:00
# else
static int ssl_sock_switchctx_cbk ( SSL * ssl , int * al , void * arg )
{
# endif
2017-02-20 10:11:50 -05:00
struct connection * conn ;
struct bind_conf * s ;
const uint8_t * extension_data ;
size_t extension_len ;
2018-09-03 10:29:16 -04:00
int has_rsa_sig = 0 , has_ecdsa_sig = 0 ;
2017-02-20 10:11:50 -05:00
char * wildp = NULL ;
const uint8_t * servername ;
2017-08-16 05:28:44 -04:00
size_t servername_len ;
2017-02-20 10:11:50 -05:00
struct ebmb_node * node , * n , * node_ecdsa = NULL , * node_rsa = NULL , * node_anonymous = NULL ;
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
int allow_early = 0 ;
2017-02-20 10:11:50 -05:00
int i ;
BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
We never saw unexplicated crash with SSL, so I suppose that we are
luck, or the slot 0 is always reserved. Anyway the usage of the macro
SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
the deprecated functions SSL_get_app_data() and SSL_set_app_data()
by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
it reserves the slot in the SSL memory space.
For information, this is the two declaration which seems wrong or
incomplete in the OpenSSL ssl.h file. We can see the usage of the
slot 0 whoch is hardcoded, but never reserved.
#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
This patch must be backported at least in 1.8, maybe in other versions.
2018-06-17 15:37:05 -04:00
conn = SSL_get_ex_data ( ssl , ssl_app_data_index ) ;
2018-10-15 07:20:07 -04:00
s = __objt_listener ( conn - > target ) - > bind_conf ;
2017-02-20 10:11:50 -05:00
2017-10-27 08:58:08 -04:00
if ( s - > ssl_conf . early_data )
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
allow_early = 1 ;
2017-08-16 05:33:17 -04:00
# ifdef OPENSSL_IS_BORINGSSL
2017-02-20 10:11:50 -05:00
if ( SSL_early_callback_ctx_extension_get ( ctx , TLSEXT_TYPE_server_name ,
& extension_data , & extension_len ) ) {
2017-08-16 05:33:17 -04:00
# else
if ( SSL_client_hello_get0_ext ( ssl , TLSEXT_TYPE_server_name , & extension_data , & extension_len ) ) {
# endif
2017-08-16 05:28:44 -04:00
/*
* The server_name extension was given too much extensibility when it
* was written , so parsing the normal case is a bit complex .
*/
size_t len ;
if ( extension_len < = 2 )
2017-02-20 10:11:50 -05:00
goto abort ;
2017-08-16 05:28:44 -04:00
/* Extract the length of the supplied list of names. */
len = ( * extension_data + + ) < < 8 ;
len | = * extension_data + + ;
if ( len + 2 ! = extension_len )
goto abort ;
/*
* The list in practice only has a single element , so we only consider
* the first one .
*/
if ( len = = 0 | | * extension_data + + ! = TLSEXT_NAMETYPE_host_name )
goto abort ;
extension_len = len - 1 ;
/* Now we can finally pull out the byte array with the actual hostname. */
if ( extension_len < = 2 )
goto abort ;
len = ( * extension_data + + ) < < 8 ;
len | = * extension_data + + ;
if ( len = = 0 | | len + 2 > extension_len | | len > TLSEXT_MAXLEN_host_name
| | memchr ( extension_data , 0 , len ) ! = NULL )
goto abort ;
servername = extension_data ;
servername_len = len ;
2017-02-20 10:11:50 -05:00
} else {
2017-08-14 05:01:25 -04:00
# if (!defined SSL_NO_GENERATE_CERTIFICATES)
if ( s - > generate_certs & & ssl_sock_generate_certificate_from_conn ( s , ssl ) ) {
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
goto allow_early ;
2017-08-14 05:01:25 -04:00
}
# endif
2017-02-20 10:11:50 -05:00
/* without SNI extension, is the default_ctx (need SSL_TLSEXT_ERR_NOACK) */
2017-03-06 09:34:44 -05:00
if ( ! s - > strict_sni ) {
2017-08-16 05:28:44 -04:00
ssl_sock_switchctx_set ( ssl , s - > default_ctx ) ;
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
goto allow_early ;
2017-03-06 09:34:44 -05:00
}
2017-02-20 10:11:50 -05:00
goto abort ;
}
/* extract/check clientHello informations */
2017-08-16 05:33:17 -04:00
# ifdef OPENSSL_IS_BORINGSSL
2017-02-20 10:11:50 -05:00
if ( SSL_early_callback_ctx_extension_get ( ctx , TLSEXT_TYPE_signature_algorithms , & extension_data , & extension_len ) ) {
2017-08-16 05:33:17 -04:00
# else
if ( SSL_client_hello_get0_ext ( ssl , TLSEXT_TYPE_signature_algorithms , & extension_data , & extension_len ) ) {
# endif
2017-08-16 05:28:44 -04:00
uint8_t sign ;
size_t len ;
if ( extension_len < 2 )
2017-02-20 10:11:50 -05:00
goto abort ;
2017-08-16 05:28:44 -04:00
len = ( * extension_data + + ) < < 8 ;
len | = * extension_data + + ;
if ( len + 2 ! = extension_len )
2017-02-20 10:11:50 -05:00
goto abort ;
2017-08-16 05:28:44 -04:00
if ( len % 2 ! = 0 )
goto abort ;
for ( ; len > 0 ; len - = 2 ) {
extension_data + + ; /* hash */
sign = * extension_data + + ;
2017-02-20 10:11:50 -05:00
switch ( sign ) {
case TLSEXT_signature_rsa :
2018-09-03 10:29:16 -04:00
has_rsa_sig = 1 ;
2017-02-20 10:11:50 -05:00
break ;
case TLSEXT_signature_ecdsa :
has_ecdsa_sig = 1 ;
break ;
default :
continue ;
}
2018-09-03 10:29:16 -04:00
if ( has_ecdsa_sig & & has_rsa_sig )
2017-02-20 10:11:50 -05:00
break ;
}
} else {
2018-08-13 19:56:13 -04:00
/* without TLSEXT_TYPE_signature_algorithms extension (< TLSv1.2) */
2018-09-03 10:29:16 -04:00
has_rsa_sig = 1 ;
2017-02-20 10:11:50 -05:00
}
if ( has_ecdsa_sig ) { /* in very rare case: has ecdsa sign but not a ECDSA cipher */
2017-08-16 05:28:44 -04:00
const SSL_CIPHER * cipher ;
size_t len ;
const uint8_t * cipher_suites ;
2018-09-03 10:29:16 -04:00
has_ecdsa_sig = 0 ;
2017-08-16 05:33:17 -04:00
# ifdef OPENSSL_IS_BORINGSSL
2017-08-16 05:28:44 -04:00
len = ctx - > cipher_suites_len ;
cipher_suites = ctx - > cipher_suites ;
2017-08-16 05:33:17 -04:00
# else
len = SSL_client_hello_get0_ciphers ( ssl , & cipher_suites ) ;
# endif
2017-08-16 05:28:44 -04:00
if ( len % 2 ! = 0 )
goto abort ;
for ( ; len ! = 0 ; len - = 2 , cipher_suites + = 2 ) {
2017-08-16 05:33:17 -04:00
# ifdef OPENSSL_IS_BORINGSSL
2017-08-16 05:28:44 -04:00
uint16_t cipher_suite = ( cipher_suites [ 0 ] < < 8 ) | cipher_suites [ 1 ] ;
2017-02-20 10:11:50 -05:00
cipher = SSL_get_cipher_by_value ( cipher_suite ) ;
2017-08-16 05:33:17 -04:00
# else
cipher = SSL_CIPHER_find ( ssl , cipher_suites ) ;
# endif
2017-10-02 11:12:06 -04:00
if ( cipher & & SSL_CIPHER_get_auth_nid ( cipher ) = = NID_auth_ecdsa ) {
2018-09-03 10:29:16 -04:00
has_ecdsa_sig = 1 ;
2017-02-20 10:11:50 -05:00
break ;
}
}
}
2017-08-16 05:28:44 -04:00
for ( i = 0 ; i < trash . size & & i < servername_len ; i + + ) {
2018-07-13 04:54:26 -04:00
trash . area [ i ] = tolower ( servername [ i ] ) ;
if ( ! wildp & & ( trash . area [ i ] = = ' . ' ) )
wildp = & trash . area [ i ] ;
2017-02-20 10:11:50 -05:00
}
2018-07-13 04:54:26 -04:00
trash . area [ i ] = 0 ;
2017-02-20 10:11:50 -05:00
/* lookup in full qualified names */
2018-07-13 04:54:26 -04:00
node = ebst_lookup ( & s - > sni_ctx , trash . area ) ;
2017-02-20 10:11:50 -05:00
/* lookup a not neg filter */
for ( n = node ; n ; n = ebmb_next_dup ( n ) ) {
if ( ! container_of ( n , struct sni_ctx , name ) - > neg ) {
2017-10-27 12:43:29 -04:00
switch ( container_of ( n , struct sni_ctx , name ) - > kinfo . sig ) {
2017-02-20 10:11:50 -05:00
case TLSEXT_signature_ecdsa :
2018-09-03 10:29:16 -04:00
if ( ! node_ecdsa )
2017-02-20 10:11:50 -05:00
node_ecdsa = n ;
break ;
case TLSEXT_signature_rsa :
2018-09-03 10:29:16 -04:00
if ( ! node_rsa )
2017-02-20 10:11:50 -05:00
node_rsa = n ;
break ;
2017-10-27 12:43:29 -04:00
default : /* TLSEXT_signature_anonymous|dsa */
2017-02-20 10:11:50 -05:00
if ( ! node_anonymous )
node_anonymous = n ;
break ;
}
}
}
if ( wildp ) {
/* lookup in wildcards names */
node = ebst_lookup ( & s - > sni_w_ctx , wildp ) ;
for ( n = node ; n ; n = ebmb_next_dup ( n ) ) {
if ( ! container_of ( n , struct sni_ctx , name ) - > neg ) {
2017-10-27 12:43:29 -04:00
switch ( container_of ( n , struct sni_ctx , name ) - > kinfo . sig ) {
2017-02-20 10:11:50 -05:00
case TLSEXT_signature_ecdsa :
2018-09-03 10:29:16 -04:00
if ( ! node_ecdsa )
2017-02-20 10:11:50 -05:00
node_ecdsa = n ;
break ;
case TLSEXT_signature_rsa :
2018-09-03 10:29:16 -04:00
if ( ! node_rsa )
2017-02-20 10:11:50 -05:00
node_rsa = n ;
break ;
2017-10-27 12:43:29 -04:00
default : /* TLSEXT_signature_anonymous|dsa */
2017-02-20 10:11:50 -05:00
if ( ! node_anonymous )
node_anonymous = n ;
break ;
}
}
}
}
/* select by key_signature priority order */
2018-09-03 10:29:16 -04:00
node = ( has_ecdsa_sig & & node_ecdsa ) ? node_ecdsa
: ( ( has_rsa_sig & & node_rsa ) ? node_rsa
: ( node_anonymous ? node_anonymous
: ( node_ecdsa ? node_ecdsa /* no ecdsa signature case (< TLSv1.2) */
: node_rsa /* no rsa signature case (far far away) */
) ) ) ;
2017-02-20 10:11:50 -05:00
if ( node ) {
/* switch ctx */
2017-08-09 12:26:20 -04:00
struct ssl_bind_conf * conf = container_of ( node , struct sni_ctx , name ) - > conf ;
2017-08-16 05:28:44 -04:00
ssl_sock_switchctx_set ( ssl , container_of ( node , struct sni_ctx , name ) - > ctx ) ;
2017-11-02 14:04:38 -04:00
if ( conf ) {
methodVersions [ conf - > ssl_methods . min ] . ssl_set_version ( ssl , SET_MIN ) ;
methodVersions [ conf - > ssl_methods . max ] . ssl_set_version ( ssl , SET_MAX ) ;
if ( conf - > early_data )
allow_early = 1 ;
}
goto allow_early ;
2017-02-20 10:11:50 -05:00
}
2017-08-14 05:01:25 -04:00
# if (!defined SSL_NO_GENERATE_CERTIFICATES)
2018-07-13 04:54:26 -04:00
if ( s - > generate_certs & & ssl_sock_generate_certificate ( trash . area , s , ssl ) ) {
2017-08-14 05:01:25 -04:00
/* switch ctx done in ssl_sock_generate_certificate */
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
goto allow_early ;
2017-08-14 05:01:25 -04:00
}
# endif
2017-03-06 09:34:44 -05:00
if ( ! s - > strict_sni ) {
2017-02-20 10:11:50 -05:00
/* no certificate match, is the default_ctx */
2017-08-16 05:28:44 -04:00
ssl_sock_switchctx_set ( ssl , s - > default_ctx ) ;
2017-03-06 09:34:44 -05:00
}
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
allow_early :
# ifdef OPENSSL_IS_BORINGSSL
if ( allow_early )
SSL_set_early_data_enabled ( ssl , 1 ) ;
# else
if ( ! allow_early )
SSL_set_max_early_data ( ssl , 0 ) ;
# endif
return 1 ;
2017-02-20 10:11:50 -05:00
abort :
/* abort handshake (was SSL_TLSEXT_ERR_ALERT_FATAL) */
conn - > err_code = CO_ER_SSL_HANDSHAKE ;
2017-08-16 05:33:17 -04:00
# ifdef OPENSSL_IS_BORINGSSL
2017-08-16 05:28:44 -04:00
return ssl_select_cert_error ;
2017-08-16 05:33:17 -04:00
# else
* al = SSL_AD_UNRECOGNIZED_NAME ;
return 0 ;
# endif
2017-02-20 10:11:50 -05:00
}
# else /* OPENSSL_IS_BORINGSSL */
2012-09-07 11:30:07 -04:00
/* Sets the SSL ctx of <ssl> to match the advertised server name. Returns a
* warning when no match is found , which implies the default ( first ) cert
* will keep being used .
*/
2017-01-13 11:48:18 -05:00
static int ssl_sock_switchctx_cbk ( SSL * ssl , int * al , void * priv )
2012-09-07 11:30:07 -04:00
{
const char * servername ;
const char * wildp = NULL ;
2013-05-07 14:20:06 -04:00
struct ebmb_node * node , * n ;
2017-01-13 11:48:18 -05:00
struct bind_conf * s = priv ;
2012-09-07 11:30:07 -04:00
int i ;
( void ) al ; /* shut gcc stupid warning */
servername = SSL_get_servername ( ssl , TLSEXT_NAMETYPE_host_name ) ;
2013-01-24 11:17:15 -05:00
if ( ! servername ) {
2017-01-13 11:48:18 -05:00
# if (!defined SSL_NO_GENERATE_CERTIFICATES)
2017-08-14 05:01:25 -04:00
if ( s - > generate_certs & & ssl_sock_generate_certificate_from_conn ( s , ssl ) )
return SSL_TLSEXT_ERR_OK ;
2017-01-13 11:48:18 -05:00
# endif
2017-03-06 09:34:44 -05:00
if ( s - > strict_sni )
return SSL_TLSEXT_ERR_ALERT_FATAL ;
ssl_sock_switchctx_set ( ssl , s - > default_ctx ) ;
return SSL_TLSEXT_ERR_NOACK ;
2013-01-24 11:17:15 -05:00
}
2012-09-07 11:30:07 -04:00
2012-10-29 11:51:55 -04:00
for ( i = 0 ; i < trash . size ; i + + ) {
2012-09-07 11:30:07 -04:00
if ( ! servername [ i ] )
break ;
2018-07-13 04:54:26 -04:00
trash . area [ i ] = tolower ( servername [ i ] ) ;
if ( ! wildp & & ( trash . area [ i ] = = ' . ' ) )
wildp = & trash . area [ i ] ;
2012-09-07 11:30:07 -04:00
}
2018-07-13 04:54:26 -04:00
trash . area [ i ] = 0 ;
2012-09-07 11:30:07 -04:00
/* lookup in full qualified names */
2018-07-13 04:54:26 -04:00
node = ebst_lookup ( & s - > sni_ctx , trash . area ) ;
2013-05-07 14:20:06 -04:00
/* lookup a not neg filter */
for ( n = node ; n ; n = ebmb_next_dup ( n ) ) {
if ( ! container_of ( n , struct sni_ctx , name ) - > neg ) {
node = n ;
break ;
2013-01-24 11:17:15 -05:00
}
2013-05-07 14:20:06 -04:00
}
if ( ! node & & wildp ) {
/* lookup in wildcards names */
2012-09-07 11:30:07 -04:00
node = ebst_lookup ( & s - > sni_w_ctx , wildp ) ;
2013-05-07 14:20:06 -04:00
}
if ( ! node | | container_of ( node , struct sni_ctx , name ) - > neg ) {
2017-01-13 11:48:18 -05:00
# if (!defined SSL_NO_GENERATE_CERTIFICATES)
2017-08-14 05:01:25 -04:00
if ( s - > generate_certs & & ssl_sock_generate_certificate ( servername , s , ssl ) ) {
/* switch ctx done in ssl_sock_generate_certificate */
2015-06-09 11:29:50 -04:00
return SSL_TLSEXT_ERR_OK ;
}
2017-01-13 11:48:18 -05:00
# endif
2017-03-06 09:34:44 -05:00
if ( s - > strict_sni )
return SSL_TLSEXT_ERR_ALERT_FATAL ;
ssl_sock_switchctx_set ( ssl , s - > default_ctx ) ;
return SSL_TLSEXT_ERR_OK ;
2012-09-07 11:30:07 -04:00
}
/* switch ctx */
2017-03-01 12:54:56 -05:00
ssl_sock_switchctx_set ( ssl , container_of ( node , struct sni_ctx , name ) - > ctx ) ;
2012-09-07 11:30:07 -04:00
return SSL_TLSEXT_ERR_OK ;
}
2017-02-20 10:11:50 -05:00
# endif /* (!) OPENSSL_IS_BORINGSSL */
2012-09-07 11:30:07 -04:00
# endif /* SSL_CTRL_SET_TLSEXT_HOSTNAME */
2012-09-20 10:19:02 -04:00
# ifndef OPENSSL_NO_DH
2014-06-12 08:58:40 -04:00
static DH * ssl_get_dh_1024 ( void )
{
2015-05-29 10:26:17 -04:00
static unsigned char dh1024_p [ ] = {
0xFA , 0xF9 , 0x2A , 0x22 , 0x2A , 0xA7 , 0x7F , 0xE1 , 0x67 , 0x4E , 0x53 , 0xF7 ,
0x56 , 0x13 , 0xC3 , 0xB1 , 0xE3 , 0x29 , 0x6B , 0x66 , 0x31 , 0x6A , 0x7F , 0xB3 ,
0xC2 , 0x68 , 0x6B , 0xCB , 0x1D , 0x57 , 0x39 , 0x1D , 0x1F , 0xFF , 0x1C , 0xC9 ,
0xA6 , 0xA4 , 0x98 , 0x82 , 0x31 , 0x5D , 0x25 , 0xFF , 0x8A , 0xE0 , 0x73 , 0x96 ,
0x81 , 0xC8 , 0x83 , 0x79 , 0xC1 , 0x5A , 0x04 , 0xF8 , 0x37 , 0x0D , 0xA8 , 0x3D ,
0xAE , 0x74 , 0xBC , 0xDB , 0xB6 , 0xA4 , 0x75 , 0xD9 , 0x71 , 0x8A , 0xA0 , 0x17 ,
0x9E , 0x2D , 0xC8 , 0xA8 , 0xDF , 0x2C , 0x5F , 0x82 , 0x95 , 0xF8 , 0x92 , 0x9B ,
0xA7 , 0x33 , 0x5F , 0x89 , 0x71 , 0xC8 , 0x2D , 0x6B , 0x18 , 0x86 , 0xC4 , 0x94 ,
0x22 , 0xA5 , 0x52 , 0x8D , 0xF6 , 0xF6 , 0xD2 , 0x37 , 0x92 , 0x0F , 0xA5 , 0xCC ,
0xDB , 0x7B , 0x1D , 0x3D , 0xA1 , 0x31 , 0xB7 , 0x80 , 0x8F , 0x0B , 0x67 , 0x5E ,
0x36 , 0xA5 , 0x60 , 0x0C , 0xF1 , 0x95 , 0x33 , 0x8B ,
} ;
static unsigned char dh1024_g [ ] = {
0x02 ,
} ;
2016-08-29 07:26:37 -04:00
BIGNUM * p ;
BIGNUM * g ;
2014-06-12 08:58:40 -04:00
DH * dh = DH_new ( ) ;
if ( dh ) {
2016-08-29 07:26:37 -04:00
p = BN_bin2bn ( dh1024_p , sizeof dh1024_p , NULL ) ;
g = BN_bin2bn ( dh1024_g , sizeof dh1024_g , NULL ) ;
2015-05-29 10:26:17 -04:00
2016-08-29 07:26:37 -04:00
if ( ! p | | ! g ) {
2014-06-12 08:58:40 -04:00
DH_free ( dh ) ;
dh = NULL ;
2016-08-29 07:26:37 -04:00
} else {
DH_set0_pqg ( dh , p , NULL , g ) ;
2014-06-12 08:58:40 -04:00
}
}
return dh ;
}
static DH * ssl_get_dh_2048 ( void )
{
2015-05-29 10:26:17 -04:00
static unsigned char dh2048_p [ ] = {
0xEC , 0x86 , 0xF8 , 0x70 , 0xA0 , 0x33 , 0x16 , 0xEC , 0x05 , 0x1A , 0x73 , 0x59 ,
0xCD , 0x1F , 0x8B , 0xF8 , 0x29 , 0xE4 , 0xD2 , 0xCF , 0x52 , 0xDD , 0xC2 , 0x24 ,
0x8D , 0xB5 , 0x38 , 0x9A , 0xFB , 0x5C , 0xA4 , 0xE4 , 0xB2 , 0xDA , 0xCE , 0x66 ,
0x50 , 0x74 , 0xA6 , 0x85 , 0x4D , 0x4B , 0x1D , 0x30 , 0xB8 , 0x2B , 0xF3 , 0x10 ,
0xE9 , 0xA7 , 0x2D , 0x05 , 0x71 , 0xE7 , 0x81 , 0xDF , 0x8B , 0x59 , 0x52 , 0x3B ,
0x5F , 0x43 , 0x0B , 0x68 , 0xF1 , 0xDB , 0x07 , 0xBE , 0x08 , 0x6B , 0x1B , 0x23 ,
0xEE , 0x4D , 0xCC , 0x9E , 0x0E , 0x43 , 0xA0 , 0x1E , 0xDF , 0x43 , 0x8C , 0xEC ,
0xBE , 0xBE , 0x90 , 0xB4 , 0x51 , 0x54 , 0xB9 , 0x2F , 0x7B , 0x64 , 0x76 , 0x4E ,
0x5D , 0xD4 , 0x2E , 0xAE , 0xC2 , 0x9E , 0xAE , 0x51 , 0x43 , 0x59 , 0xC7 , 0x77 ,
0x9C , 0x50 , 0x3C , 0x0E , 0xED , 0x73 , 0x04 , 0x5F , 0xF1 , 0x4C , 0x76 , 0x2A ,
0xD8 , 0xF8 , 0xCF , 0xFC , 0x34 , 0x40 , 0xD1 , 0xB4 , 0x42 , 0x61 , 0x84 , 0x66 ,
0x42 , 0x39 , 0x04 , 0xF8 , 0x68 , 0xB2 , 0x62 , 0xD7 , 0x55 , 0xED , 0x1B , 0x74 ,
0x75 , 0x91 , 0xE0 , 0xC5 , 0x69 , 0xC1 , 0x31 , 0x5C , 0xDB , 0x7B , 0x44 , 0x2E ,
0xCE , 0x84 , 0x58 , 0x0D , 0x1E , 0x66 , 0x0C , 0xC8 , 0x44 , 0x9E , 0xFD , 0x40 ,
0x08 , 0x67 , 0x5D , 0xFB , 0xA7 , 0x76 , 0x8F , 0x00 , 0x11 , 0x87 , 0xE9 , 0x93 ,
0xF9 , 0x7D , 0xC4 , 0xBC , 0x74 , 0x55 , 0x20 , 0xD4 , 0x4A , 0x41 , 0x2F , 0x43 ,
0x42 , 0x1A , 0xC1 , 0xF2 , 0x97 , 0x17 , 0x49 , 0x27 , 0x37 , 0x6B , 0x2F , 0x88 ,
0x7E , 0x1C , 0xA0 , 0xA1 , 0x89 , 0x92 , 0x27 , 0xD9 , 0x56 , 0x5A , 0x71 , 0xC1 ,
0x56 , 0x37 , 0x7E , 0x3A , 0x9D , 0x05 , 0xE7 , 0xEE , 0x5D , 0x8F , 0x82 , 0x17 ,
0xBC , 0xE9 , 0xC2 , 0x93 , 0x30 , 0x82 , 0xF9 , 0xF4 , 0xC9 , 0xAE , 0x49 , 0xDB ,
0xD0 , 0x54 , 0xB4 , 0xD9 , 0x75 , 0x4D , 0xFA , 0x06 , 0xB8 , 0xD6 , 0x38 , 0x41 ,
0xB7 , 0x1F , 0x77 , 0xF3 ,
} ;
static unsigned char dh2048_g [ ] = {
0x02 ,
} ;
2016-08-29 07:26:37 -04:00
BIGNUM * p ;
BIGNUM * g ;
2014-06-12 08:58:40 -04:00
DH * dh = DH_new ( ) ;
if ( dh ) {
2016-08-29 07:26:37 -04:00
p = BN_bin2bn ( dh2048_p , sizeof dh2048_p , NULL ) ;
g = BN_bin2bn ( dh2048_g , sizeof dh2048_g , NULL ) ;
2015-05-29 10:26:17 -04:00
2016-08-29 07:26:37 -04:00
if ( ! p | | ! g ) {
2014-06-12 08:58:40 -04:00
DH_free ( dh ) ;
dh = NULL ;
2016-08-29 07:26:37 -04:00
} else {
DH_set0_pqg ( dh , p , NULL , g ) ;
2014-06-12 08:58:40 -04:00
}
}
return dh ;
}
static DH * ssl_get_dh_4096 ( void )
{
2015-05-29 10:26:17 -04:00
static unsigned char dh4096_p [ ] = {
0xDE , 0x16 , 0x94 , 0xCD , 0x99 , 0x58 , 0x07 , 0xF1 , 0xF7 , 0x32 , 0x96 , 0x11 ,
0x04 , 0x82 , 0xD4 , 0x84 , 0x72 , 0x80 , 0x99 , 0x06 , 0xCA , 0xF0 , 0xA3 , 0x68 ,
0x07 , 0xCE , 0x64 , 0x50 , 0xE7 , 0x74 , 0x45 , 0x20 , 0x80 , 0x5E , 0x4D , 0xAD ,
0xA5 , 0xB6 , 0xED , 0xFA , 0x80 , 0x6C , 0x3B , 0x35 , 0xC4 , 0x9A , 0x14 , 0x6B ,
0x32 , 0xBB , 0xFD , 0x1F , 0x17 , 0x8E , 0xB7 , 0x1F , 0xD6 , 0xFA , 0x3F , 0x7B ,
0xEE , 0x16 , 0xA5 , 0x62 , 0x33 , 0x0D , 0xED , 0xBC , 0x4E , 0x58 , 0xE5 , 0x47 ,
0x4D , 0xE9 , 0xAB , 0x8E , 0x38 , 0xD3 , 0x6E , 0x90 , 0x57 , 0xE3 , 0x22 , 0x15 ,
0x33 , 0xBD , 0xF6 , 0x43 , 0x45 , 0xB5 , 0x10 , 0x0A , 0xBE , 0x2C , 0xB4 , 0x35 ,
0xB8 , 0x53 , 0x8D , 0xAD , 0xFB , 0xA7 , 0x1F , 0x85 , 0x58 , 0x41 , 0x7A , 0x79 ,
0x20 , 0x68 , 0xB3 , 0xE1 , 0x3D , 0x08 , 0x76 , 0xBF , 0x86 , 0x0D , 0x49 , 0xE3 ,
0x82 , 0x71 , 0x8C , 0xB4 , 0x8D , 0x81 , 0x84 , 0xD4 , 0xE7 , 0xBE , 0x91 , 0xDC ,
0x26 , 0x39 , 0x48 , 0x0F , 0x35 , 0xC4 , 0xCA , 0x65 , 0xE3 , 0x40 , 0x93 , 0x52 ,
0x76 , 0x58 , 0x7D , 0xDD , 0x51 , 0x75 , 0xDC , 0x69 , 0x61 , 0xBF , 0x47 , 0x2C ,
0x16 , 0x68 , 0x2D , 0xC9 , 0x29 , 0xD3 , 0xE6 , 0xC0 , 0x99 , 0x48 , 0xA0 , 0x9A ,
0xC8 , 0x78 , 0xC0 , 0x6D , 0x81 , 0x67 , 0x12 , 0x61 , 0x3F , 0x71 , 0xBA , 0x41 ,
0x1F , 0x6C , 0x89 , 0x44 , 0x03 , 0xBA , 0x3B , 0x39 , 0x60 , 0xAA , 0x28 , 0x55 ,
0x59 , 0xAE , 0xB8 , 0xFA , 0xCB , 0x6F , 0xA5 , 0x1A , 0xF7 , 0x2B , 0xDD , 0x52 ,
0x8A , 0x8B , 0xE2 , 0x71 , 0xA6 , 0x5E , 0x7E , 0xD8 , 0x2E , 0x18 , 0xE0 , 0x66 ,
0xDF , 0xDD , 0x22 , 0x21 , 0x99 , 0x52 , 0x73 , 0xA6 , 0x33 , 0x20 , 0x65 , 0x0E ,
0x53 , 0xE7 , 0x6B , 0x9B , 0xC5 , 0xA3 , 0x2F , 0x97 , 0x65 , 0x76 , 0xD3 , 0x47 ,
0x23 , 0x77 , 0x12 , 0xB6 , 0x11 , 0x7B , 0x24 , 0xED , 0xF1 , 0xEF , 0xC0 , 0xE2 ,
0xA3 , 0x7E , 0x67 , 0x05 , 0x3E , 0x96 , 0x4D , 0x45 , 0xC2 , 0x18 , 0xD1 , 0x73 ,
0x9E , 0x07 , 0xF3 , 0x81 , 0x6E , 0x52 , 0x63 , 0xF6 , 0x20 , 0x76 , 0xB9 , 0x13 ,
0xD2 , 0x65 , 0x30 , 0x18 , 0x16 , 0x09 , 0x16 , 0x9E , 0x8F , 0xF1 , 0xD2 , 0x10 ,
0x5A , 0xD3 , 0xD4 , 0xAF , 0x16 , 0x61 , 0xDA , 0x55 , 0x2E , 0x18 , 0x5E , 0x14 ,
0x08 , 0x54 , 0x2E , 0x2A , 0x25 , 0xA2 , 0x1A , 0x9B , 0x8B , 0x32 , 0xA9 , 0xFD ,
0xC2 , 0x48 , 0x96 , 0xE1 , 0x80 , 0xCA , 0xE9 , 0x22 , 0x17 , 0xBB , 0xCE , 0x3E ,
0x9E , 0xED , 0xC7 , 0xF1 , 0x1F , 0xEC , 0x17 , 0x21 , 0xDC , 0x7B , 0x82 , 0x48 ,
0x8E , 0xBB , 0x4B , 0x9D , 0x5B , 0x04 , 0x04 , 0xDA , 0xDB , 0x39 , 0xDF , 0x01 ,
0x40 , 0xC3 , 0xAA , 0x26 , 0x23 , 0x89 , 0x75 , 0xC6 , 0x0B , 0xD0 , 0xA2 , 0x60 ,
0x6A , 0xF1 , 0xCC , 0x65 , 0x18 , 0x98 , 0x1B , 0x52 , 0xD2 , 0x74 , 0x61 , 0xCC ,
0xBD , 0x60 , 0xAE , 0xA3 , 0xA0 , 0x66 , 0x6A , 0x16 , 0x34 , 0x92 , 0x3F , 0x41 ,
0x40 , 0x31 , 0x29 , 0xC0 , 0x2C , 0x63 , 0xB2 , 0x07 , 0x8D , 0xEB , 0x94 , 0xB8 ,
0xE8 , 0x47 , 0x92 , 0x52 , 0x93 , 0x6A , 0x1B , 0x7E , 0x1A , 0x61 , 0xB3 , 0x1B ,
0xF0 , 0xD6 , 0x72 , 0x9B , 0xF1 , 0xB0 , 0xAF , 0xBF , 0x3E , 0x65 , 0xEF , 0x23 ,
0x1D , 0x6F , 0xFF , 0x70 , 0xCD , 0x8A , 0x4C , 0x8A , 0xA0 , 0x72 , 0x9D , 0xBE ,
0xD4 , 0xBB , 0x24 , 0x47 , 0x4A , 0x68 , 0xB5 , 0xF5 , 0xC6 , 0xD5 , 0x7A , 0xCD ,
0xCA , 0x06 , 0x41 , 0x07 , 0xAD , 0xC2 , 0x1E , 0xE6 , 0x54 , 0xA7 , 0xAD , 0x03 ,
0xD9 , 0x12 , 0xC1 , 0x9C , 0x13 , 0xB1 , 0xC9 , 0x0A , 0x43 , 0x8E , 0x1E , 0x08 ,
0xCE , 0x50 , 0x82 , 0x73 , 0x5F , 0xA7 , 0x55 , 0x1D , 0xD9 , 0x59 , 0xAC , 0xB5 ,
0xEA , 0x02 , 0x7F , 0x6C , 0x5B , 0x74 , 0x96 , 0x98 , 0x67 , 0x24 , 0xA3 , 0x0F ,
0x15 , 0xFC , 0xA9 , 0x7D , 0x3E , 0x67 , 0xD1 , 0x70 , 0xF8 , 0x97 , 0xF3 , 0x67 ,
0xC5 , 0x8C , 0x88 , 0x44 , 0x08 , 0x02 , 0xC7 , 0x2B ,
2014-06-12 08:58:40 -04:00
} ;
2015-05-29 10:26:17 -04:00
static unsigned char dh4096_g [ ] = {
0x02 ,
} ;
2014-06-12 08:58:40 -04:00
2016-08-29 07:26:37 -04:00
BIGNUM * p ;
BIGNUM * g ;
2014-06-12 08:58:40 -04:00
DH * dh = DH_new ( ) ;
if ( dh ) {
2016-08-29 07:26:37 -04:00
p = BN_bin2bn ( dh4096_p , sizeof dh4096_p , NULL ) ;
g = BN_bin2bn ( dh4096_g , sizeof dh4096_g , NULL ) ;
2015-05-29 10:26:17 -04:00
2016-08-29 07:26:37 -04:00
if ( ! p | | ! g ) {
2014-06-12 08:58:40 -04:00
DH_free ( dh ) ;
dh = NULL ;
2016-08-29 07:26:37 -04:00
} else {
DH_set0_pqg ( dh , p , NULL , g ) ;
2014-06-12 08:58:40 -04:00
}
}
return dh ;
}
/* Returns Diffie-Hellman parameters matching the private key length
2016-12-22 17:12:01 -05:00
but not exceeding global_ssl . default_dh_param */
2014-06-12 08:58:40 -04:00
static DH * ssl_get_tmp_dh ( SSL * ssl , int export , int keylen )
{
DH * dh = NULL ;
EVP_PKEY * pkey = SSL_get_privatekey ( ssl ) ;
2016-08-29 07:26:37 -04:00
int type ;
type = pkey ? EVP_PKEY_base_id ( pkey ) : EVP_PKEY_NONE ;
2014-06-12 08:58:40 -04:00
/* The keylen supplied by OpenSSL can only be 512 or 1024.
See ssl3_send_server_key_exchange ( ) in ssl / s3_srvr . c
*/
if ( type = = EVP_PKEY_RSA | | type = = EVP_PKEY_DSA ) {
keylen = EVP_PKEY_bits ( pkey ) ;
}
2016-12-22 17:12:01 -05:00
if ( keylen > global_ssl . default_dh_param ) {
keylen = global_ssl . default_dh_param ;
2014-06-12 08:58:40 -04:00
}
2015-05-29 10:26:17 -04:00
if ( keylen > = 4096 ) {
2014-07-15 05:36:40 -04:00
dh = local_dh_4096 ;
2014-06-12 08:58:40 -04:00
}
else if ( keylen > = 2048 ) {
2014-07-15 05:36:40 -04:00
dh = local_dh_2048 ;
2014-06-12 08:58:40 -04:00
}
else {
2014-07-15 05:36:40 -04:00
dh = local_dh_1024 ;
2014-06-12 08:58:40 -04:00
}
return dh ;
}
2015-05-29 09:53:22 -04:00
static DH * ssl_sock_get_dh_from_file ( const char * filename )
2012-09-20 10:19:02 -04:00
{
DH * dh = NULL ;
2015-05-29 09:53:22 -04:00
BIO * in = BIO_new ( BIO_s_file ( ) ) ;
2012-09-20 10:19:02 -04:00
if ( in = = NULL )
goto end ;
2015-05-29 09:53:22 -04:00
if ( BIO_read_filename ( in , filename ) < = 0 )
2012-09-20 10:19:02 -04:00
goto end ;
2015-05-29 09:53:22 -04:00
dh = PEM_read_bio_DHparams ( in , NULL , NULL , NULL ) ;
end :
if ( in )
BIO_free ( in ) ;
2018-08-16 09:14:12 -04:00
ERR_clear_error ( ) ;
2015-05-29 09:53:22 -04:00
return dh ;
}
int ssl_sock_load_global_dh_param_from_file ( const char * filename )
{
global_dh = ssl_sock_get_dh_from_file ( filename ) ;
if ( global_dh ) {
return 0 ;
}
return - 1 ;
}
/* Loads Diffie-Hellman parameter from a file. Returns 1 if loaded, else -1
2018-11-15 12:07:59 -05:00
if an error occurred , and 0 if parameter not found . */
2015-05-29 09:53:22 -04:00
int ssl_sock_load_dh_params ( SSL_CTX * ctx , const char * file )
{
int ret = - 1 ;
DH * dh = ssl_sock_get_dh_from_file ( file ) ;
2014-06-12 08:58:40 -04:00
if ( dh ) {
ret = 1 ;
SSL_CTX_set_tmp_dh ( ctx , dh ) ;
2015-05-28 10:23:00 -04:00
if ( ssl_dh_ptr_index > = 0 ) {
/* store a pointer to the DH params to avoid complaining about
ssl - default - dh - param not being set for this SSL_CTX */
SSL_CTX_set_ex_data ( ctx , ssl_dh_ptr_index , dh ) ;
}
2014-06-12 08:58:40 -04:00
}
2015-05-29 09:53:22 -04:00
else if ( global_dh ) {
SSL_CTX_set_tmp_dh ( ctx , global_dh ) ;
ret = 0 ; /* DH params not found */
}
2014-06-12 08:58:40 -04:00
else {
2013-04-26 05:05:44 -04:00
/* Clear openssl global errors stack */
ERR_clear_error ( ) ;
2016-12-22 17:12:01 -05:00
if ( global_ssl . default_dh_param < = 1024 ) {
2014-06-12 08:58:40 -04:00
/* we are limited to DH parameter of 1024 bits anyway */
2016-07-02 10:26:10 -04:00
if ( local_dh_1024 = = NULL )
local_dh_1024 = ssl_get_dh_1024 ( ) ;
2014-07-15 05:36:40 -04:00
if ( local_dh_1024 = = NULL )
2014-06-12 08:58:40 -04:00
goto end ;
2014-04-25 15:35:23 -04:00
2014-07-15 05:36:40 -04:00
SSL_CTX_set_tmp_dh ( ctx , local_dh_1024 ) ;
2014-06-12 08:58:40 -04:00
}
else {
SSL_CTX_set_tmp_dh_callback ( ctx , ssl_get_tmp_dh ) ;
}
2014-04-25 15:35:23 -04:00
2013-04-26 05:05:44 -04:00
ret = 0 ; /* DH params not found */
2012-09-20 10:19:02 -04:00
}
2012-12-14 05:21:13 -05:00
2012-09-20 10:19:02 -04:00
end :
if ( dh )
DH_free ( dh ) ;
return ret ;
}
# endif
2017-02-20 10:11:50 -05:00
static int ssl_sock_add_cert_sni ( SSL_CTX * ctx , struct bind_conf * s , struct ssl_bind_conf * conf ,
2017-10-27 12:43:29 -04:00
struct pkey_info kinfo , char * name , int order )
2013-01-22 09:31:15 -05:00
{
struct sni_ctx * sc ;
2013-05-07 14:20:06 -04:00
int wild = 0 , neg = 0 ;
2016-10-06 04:56:48 -04:00
struct ebmb_node * node ;
2013-05-07 14:20:06 -04:00
if ( * name = = ' ! ' ) {
neg = 1 ;
name + + ;
}
if ( * name = = ' * ' ) {
wild = 1 ;
name + + ;
}
/* !* filter is a nop */
if ( neg & & wild )
return order ;
if ( * name ) {
int j , len ;
len = strlen ( name ) ;
2016-10-06 04:56:48 -04:00
for ( j = 0 ; j < len & & j < trash . size ; j + + )
2018-07-13 04:54:26 -04:00
trash . area [ j ] = tolower ( name [ j ] ) ;
2016-10-06 04:56:48 -04:00
if ( j > = trash . size )
return order ;
2018-07-13 04:54:26 -04:00
trash . area [ j ] = 0 ;
2016-10-06 04:56:48 -04:00
/* Check for duplicates. */
if ( wild )
2018-07-13 04:54:26 -04:00
node = ebst_lookup ( & s - > sni_w_ctx , trash . area ) ;
2016-10-06 04:56:48 -04:00
else
2018-07-13 04:54:26 -04:00
node = ebst_lookup ( & s - > sni_ctx , trash . area ) ;
2016-10-06 04:56:48 -04:00
for ( ; node ; node = ebmb_next_dup ( node ) ) {
sc = ebmb_entry ( node , struct sni_ctx , name ) ;
2017-10-27 12:43:29 -04:00
if ( sc - > ctx = = ctx & & sc - > conf = = conf & & sc - > neg = = neg )
2016-10-06 04:56:48 -04:00
return order ;
}
2013-01-22 09:31:15 -05:00
sc = malloc ( sizeof ( struct sni_ctx ) + len + 1 ) ;
2016-10-06 04:35:29 -04:00
if ( ! sc )
return order ;
2018-07-13 04:54:26 -04:00
memcpy ( sc - > name . key , trash . area , len + 1 ) ;
2013-01-22 09:31:15 -05:00
sc - > ctx = ctx ;
2016-12-29 12:26:15 -05:00
sc - > conf = conf ;
2017-10-27 12:43:29 -04:00
sc - > kinfo = kinfo ;
2013-05-07 14:20:06 -04:00
sc - > order = order + + ;
sc - > neg = neg ;
2017-10-31 10:46:07 -04:00
if ( kinfo . sig ! = TLSEXT_signature_anonymous )
SSL_CTX_set_ex_data ( ctx , ssl_pkey_info_index , & sc - > kinfo ) ;
2013-01-22 09:31:15 -05:00
if ( wild )
ebst_insert ( & s - > sni_w_ctx , & sc - > name ) ;
else
ebst_insert ( & s - > sni_ctx , & sc - > name ) ;
}
return order ;
}
2015-12-01 15:16:07 -05:00
/* The following code is used for loading multiple crt files into
* SSL_CTX ' s based on CN / SAN
*/
2016-12-12 04:56:56 -05:00
# if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(LIBRESSL_VERSION_NUMBER)
2015-12-01 15:16:07 -05:00
/* This is used to preload the certifcate, private key
* and Cert Chain of a file passed in via the crt
* argument
*
* This way , we do not have to read the file multiple times
*/
struct cert_key_and_chain {
X509 * cert ;
EVP_PKEY * key ;
unsigned int num_chain_certs ;
/* This is an array of X509 pointers */
X509 * * chain_certs ;
} ;
2015-12-02 13:01:29 -05:00
# define SSL_SOCK_POSSIBLE_KT_COMBOS (1<<(SSL_SOCK_NUM_KEYTYPES))
struct key_combo_ctx {
SSL_CTX * ctx ;
int order ;
} ;
/* Map used for processing multiple keypairs for a single purpose
*
* This maps CN / SNI name to certificate type
*/
struct sni_keytype {
int keytypes ; /* BITMASK for keytypes */
struct ebmb_node name ; /* node holding the servername value */
} ;
2015-12-01 15:16:07 -05:00
/* Frees the contents of a cert_key_and_chain
*/
static void ssl_sock_free_cert_key_and_chain_contents ( struct cert_key_and_chain * ckch )
{
int i ;
if ( ! ckch )
return ;
/* Free the certificate and set pointer to NULL */
if ( ckch - > cert )
X509_free ( ckch - > cert ) ;
ckch - > cert = NULL ;
/* Free the key and set pointer to NULL */
if ( ckch - > key )
EVP_PKEY_free ( ckch - > key ) ;
ckch - > key = NULL ;
/* Free each certificate in the chain */
for ( i = 0 ; i < ckch - > num_chain_certs ; i + + ) {
if ( ckch - > chain_certs [ i ] )
X509_free ( ckch - > chain_certs [ i ] ) ;
}
/* Free the chain obj itself and set to NULL */
if ( ckch - > num_chain_certs > 0 ) {
free ( ckch - > chain_certs ) ;
ckch - > num_chain_certs = 0 ;
ckch - > chain_certs = NULL ;
}
}
/* checks if a key and cert exists in the ckch
*/
static int ssl_sock_is_ckch_valid ( struct cert_key_and_chain * ckch )
{
return ( ckch - > cert ! = NULL & & ckch - > key ! = NULL ) ;
}
/* Loads the contents of a crt file (path) into a cert_key_and_chain
* This allows us to carry the contents of the file without having to
* read the file multiple times .
*
* returns :
* 0 on Success
* 1 on SSL Failure
* 2 on file not found
*/
static int ssl_sock_load_crt_file_into_ckch ( const char * path , struct cert_key_and_chain * ckch , char * * err )
{
BIO * in ;
X509 * ca = NULL ;
int ret = 1 ;
ssl_sock_free_cert_key_and_chain_contents ( ckch ) ;
in = BIO_new ( BIO_s_file ( ) ) ;
if ( in = = NULL )
goto end ;
if ( BIO_read_filename ( in , path ) < = 0 )
goto end ;
/* Read Private Key */
ckch - > key = PEM_read_bio_PrivateKey ( in , NULL , NULL , NULL ) ;
if ( ckch - > key = = NULL ) {
memprintf ( err , " %sunable to load private key from file '%s'. \n " ,
err & & * err ? * err : " " , path ) ;
goto end ;
}
2016-04-06 13:02:38 -04:00
/* Seek back to beginning of file */
2016-10-13 18:49:21 -04:00
if ( BIO_reset ( in ) = = - 1 ) {
memprintf ( err , " %san error occurred while reading the file '%s'. \n " ,
err & & * err ? * err : " " , path ) ;
goto end ;
}
2016-04-06 13:02:38 -04:00
/* Read Certificate */
ckch - > cert = PEM_read_bio_X509_AUX ( in , NULL , NULL , NULL ) ;
if ( ckch - > cert = = NULL ) {
memprintf ( err , " %sunable to load certificate from file '%s'. \n " ,
err & & * err ? * err : " " , path ) ;
goto end ;
}
2015-12-01 15:16:07 -05:00
/* Read Certificate Chain */
while ( ( ca = PEM_read_bio_X509 ( in , NULL , NULL , NULL ) ) ) {
/* Grow the chain certs */
ckch - > num_chain_certs + + ;
ckch - > chain_certs = realloc ( ckch - > chain_certs , ( ckch - > num_chain_certs * sizeof ( X509 * ) ) ) ;
/* use - 1 here since we just incremented it above */
ckch - > chain_certs [ ckch - > num_chain_certs - 1 ] = ca ;
}
ret = ERR_get_error ( ) ;
if ( ret & & ( ERR_GET_LIB ( ret ) ! = ERR_LIB_PEM & & ERR_GET_REASON ( ret ) ! = PEM_R_NO_START_LINE ) ) {
memprintf ( err , " %sunable to load certificate chain from file '%s'. \n " ,
err & & * err ? * err : " " , path ) ;
ret = 1 ;
goto end ;
}
ret = 0 ;
end :
ERR_clear_error ( ) ;
if ( in )
BIO_free ( in ) ;
/* Something went wrong in one of the reads */
if ( ret ! = 0 )
ssl_sock_free_cert_key_and_chain_contents ( ckch ) ;
return ret ;
}
/* Loads the info in ckch into ctx
* Currently , this does not process any information about ocsp , dhparams or
* sctl
* Returns
* 0 on success
* 1 on failure
*/
static int ssl_sock_put_ckch_into_ctx ( const char * path , const struct cert_key_and_chain * ckch , SSL_CTX * ctx , char * * err )
{
int i = 0 ;
if ( SSL_CTX_use_PrivateKey ( ctx , ckch - > key ) < = 0 ) {
memprintf ( err , " %sunable to load SSL private key into SSL Context '%s'. \n " ,
err & & * err ? * err : " " , path ) ;
return 1 ;
}
if ( ! SSL_CTX_use_certificate ( ctx , ckch - > cert ) ) {
memprintf ( err , " %sunable to load SSL certificate into SSL Context '%s'. \n " ,
err & & * err ? * err : " " , path ) ;
return 1 ;
}
/* Load all certs in the ckch into the ctx_chain for the ssl_ctx */
for ( i = 0 ; i < ckch - > num_chain_certs ; i + + ) {
if ( ! SSL_CTX_add1_chain_cert ( ctx , ckch - > chain_certs [ i ] ) ) {
2015-12-02 13:01:29 -05:00
memprintf ( err , " %sunable to load chain certificate #%d into SSL Context '%s'. Make sure you are linking against Openssl >= 1.0.2. \n " ,
err & & * err ? * err : " " , ( i + 1 ) , path ) ;
2015-12-01 15:16:07 -05:00
return 1 ;
}
}
if ( SSL_CTX_check_private_key ( ctx ) < = 0 ) {
memprintf ( err , " %sinconsistencies between private key and certificate loaded from PEM file '%s'. \n " ,
err & & * err ? * err : " " , path ) ;
return 1 ;
}
return 0 ;
}
2015-12-02 13:01:29 -05:00
static void ssl_sock_populate_sni_keytypes_hplr ( const char * str , struct eb_root * sni_keytypes , int key_index )
{
struct sni_keytype * s_kt = NULL ;
struct ebmb_node * node ;
int i ;
for ( i = 0 ; i < trash . size ; i + + ) {
if ( ! str [ i ] )
break ;
2018-07-13 04:54:26 -04:00
trash . area [ i ] = tolower ( str [ i ] ) ;
2015-12-02 13:01:29 -05:00
}
2018-07-13 04:54:26 -04:00
trash . area [ i ] = 0 ;
node = ebst_lookup ( sni_keytypes , trash . area ) ;
2015-12-02 13:01:29 -05:00
if ( ! node ) {
/* CN not found in tree */
s_kt = malloc ( sizeof ( struct sni_keytype ) + i + 1 ) ;
/* Using memcpy here instead of strncpy.
* strncpy will cause sig_abrt errors under certain versions of gcc with - O2
* See : https : //gcc.gnu.org/bugzilla/show_bug.cgi?id=60792
*/
2018-07-13 04:54:26 -04:00
memcpy ( s_kt - > name . key , trash . area , i + 1 ) ;
2015-12-02 13:01:29 -05:00
s_kt - > keytypes = 0 ;
ebst_insert ( sni_keytypes , & s_kt - > name ) ;
} else {
/* CN found in tree */
s_kt = container_of ( node , struct sni_keytype , name ) ;
}
/* Mark that this CN has the keytype of key_index via keytypes mask */
s_kt - > keytypes | = 1 < < key_index ;
}
/* Given a path that does not exist, try to check for path.rsa, path.dsa and path.ecdsa files.
* If any are found , group these files into a set of SSL_CTX *
* based on shared and unique CN and SAN entries . Add these SSL_CTX * to the SNI tree .
*
2018-11-15 12:07:59 -05:00
* This will allow the user to explicitly group multiple cert / keys for a single purpose
2015-12-02 13:01:29 -05:00
*
* Returns
* 0 on success
* 1 on failure
*/
2016-12-29 12:26:15 -05:00
static int ssl_sock_load_multi_cert ( const char * path , struct bind_conf * bind_conf , struct ssl_bind_conf * ssl_conf ,
char * * sni_filter , int fcount , char * * err )
2015-12-02 13:01:29 -05:00
{
char fp [ MAXPATHLEN + 1 ] = { 0 } ;
int n = 0 ;
int i = 0 ;
struct cert_key_and_chain certs_and_keys [ SSL_SOCK_NUM_KEYTYPES ] = { { 0 } } ;
struct eb_root sni_keytypes_map = { { 0 } } ;
struct ebmb_node * node ;
struct ebmb_node * next ;
/* Array of SSL_CTX pointers corresponding to each possible combo
* of keytypes
*/
struct key_combo_ctx key_combos [ SSL_SOCK_POSSIBLE_KT_COMBOS ] = { { 0 } } ;
int rv = 0 ;
X509_NAME * xname = NULL ;
char * str = NULL ;
# ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
STACK_OF ( GENERAL_NAME ) * names = NULL ;
# endif
/* Load all possible certs and keys */
for ( n = 0 ; n < SSL_SOCK_NUM_KEYTYPES ; n + + ) {
struct stat buf ;
snprintf ( fp , sizeof ( fp ) , " %s.%s " , path , SSL_SOCK_KEYTYPE_NAMES [ n ] ) ;
if ( stat ( fp , & buf ) = = 0 ) {
if ( ssl_sock_load_crt_file_into_ckch ( fp , & certs_and_keys [ n ] , err ) = = 1 ) {
rv = 1 ;
goto end ;
}
}
}
/* Process each ckch and update keytypes for each CN/SAN
* for example , if CN / SAN www . a . com is associated with
* certs with keytype 0 and 2 , then at the end of the loop ,
* www . a . com will have :
* keyindex = 0 | 1 | 4 = 5
*/
for ( n = 0 ; n < SSL_SOCK_NUM_KEYTYPES ; n + + ) {
if ( ! ssl_sock_is_ckch_valid ( & certs_and_keys [ n ] ) )
continue ;
2016-05-13 05:14:06 -04:00
if ( fcount ) {
2016-06-20 17:01:57 -04:00
for ( i = 0 ; i < fcount ; i + + )
2016-05-13 05:14:06 -04:00
ssl_sock_populate_sni_keytypes_hplr ( sni_filter [ i ] , & sni_keytypes_map , n ) ;
} else {
/* A lot of the following code is OpenSSL boilerplate for processing CN's and SAN's,
* so the line that contains logic is marked via comments
*/
xname = X509_get_subject_name ( certs_and_keys [ n ] . cert ) ;
i = - 1 ;
while ( ( i = X509_NAME_get_index_by_NID ( xname , NID_commonName , i ) ) ! = - 1 ) {
X509_NAME_ENTRY * entry = X509_NAME_get_entry ( xname , i ) ;
2016-08-29 07:26:37 -04:00
ASN1_STRING * value ;
value = X509_NAME_ENTRY_get_data ( entry ) ;
if ( ASN1_STRING_to_UTF8 ( ( unsigned char * * ) & str , value ) > = 0 ) {
2016-05-13 05:14:06 -04:00
/* Important line is here */
ssl_sock_populate_sni_keytypes_hplr ( str , & sni_keytypes_map , n ) ;
2015-12-02 13:01:29 -05:00
2016-05-13 05:14:06 -04:00
OPENSSL_free ( str ) ;
str = NULL ;
}
2015-12-02 13:01:29 -05:00
}
2016-05-13 05:14:06 -04:00
/* Do the above logic for each SAN */
2015-12-02 13:01:29 -05:00
# ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
2016-05-13 05:14:06 -04:00
names = X509_get_ext_d2i ( certs_and_keys [ n ] . cert , NID_subject_alt_name , NULL , NULL ) ;
if ( names ) {
for ( i = 0 ; i < sk_GENERAL_NAME_num ( names ) ; i + + ) {
GENERAL_NAME * name = sk_GENERAL_NAME_value ( names , i ) ;
if ( name - > type = = GEN_DNS ) {
if ( ASN1_STRING_to_UTF8 ( ( unsigned char * * ) & str , name - > d . dNSName ) > = 0 ) {
/* Important line is here */
ssl_sock_populate_sni_keytypes_hplr ( str , & sni_keytypes_map , n ) ;
OPENSSL_free ( str ) ;
str = NULL ;
}
2015-12-02 13:01:29 -05:00
}
}
}
}
# endif /* SSL_CTRL_SET_TLSEXT_HOSTNAME */
}
/* If no files found, return error */
if ( eb_is_empty ( & sni_keytypes_map ) ) {
memprintf ( err , " %sunable to load SSL certificate file '%s' file does not exist. \n " ,
err & & * err ? * err : " " , path ) ;
rv = 1 ;
goto end ;
}
/* We now have a map of CN/SAN to keytypes that are loaded in
* Iterate through the map to create the SSL_CTX ' s ( if needed )
* and add each CTX to the SNI tree
*
* Some math here :
2018-11-15 12:07:59 -05:00
* There are 2 ^ n - 1 possible combinations , each unique
2015-12-02 13:01:29 -05:00
* combination is denoted by the key in the map . Each key
* has a value between 1 and 2 ^ n - 1. Conveniently , the array
* of SSL_CTX * is sized 2 ^ n . So , we can simply use the i ' th
* entry in the array to correspond to the unique combo ( key )
* associated with i . This unique key combo ( i ) will be associated
* with combos [ i - 1 ]
*/
node = ebmb_first ( & sni_keytypes_map ) ;
while ( node ) {
SSL_CTX * cur_ctx ;
2016-11-13 11:37:13 -05:00
char cur_file [ MAXPATHLEN + 1 ] ;
2017-10-27 12:43:29 -04:00
const struct pkey_info kinfo = { . sig = TLSEXT_signature_anonymous , . bits = 0 } ;
2015-12-02 13:01:29 -05:00
str = ( char * ) container_of ( node , struct sni_keytype , name ) - > name . key ;
i = container_of ( node , struct sni_keytype , name ) - > keytypes ;
cur_ctx = key_combos [ i - 1 ] . ctx ;
if ( cur_ctx = = NULL ) {
/* need to create SSL_CTX */
2017-03-06 09:34:44 -05:00
cur_ctx = SSL_CTX_new ( SSLv23_server_method ( ) ) ;
2015-12-02 13:01:29 -05:00
if ( cur_ctx = = NULL ) {
memprintf ( err , " %sunable to allocate SSL context. \n " ,
err & & * err ? * err : " " ) ;
rv = 1 ;
goto end ;
}
2015-12-10 15:07:30 -05:00
/* Load all required certs/keys/chains/OCSPs info into SSL_CTX */
2015-12-02 13:01:29 -05:00
for ( n = 0 ; n < SSL_SOCK_NUM_KEYTYPES ; n + + ) {
if ( i & ( 1 < < n ) ) {
/* Key combo contains ckch[n] */
2016-11-13 11:37:13 -05:00
snprintf ( cur_file , MAXPATHLEN + 1 , " %s.%s " , path , SSL_SOCK_KEYTYPE_NAMES [ n ] ) ;
if ( ssl_sock_put_ckch_into_ctx ( cur_file , & certs_and_keys [ n ] , cur_ctx , err ) ! = 0 ) {
2015-12-02 13:01:29 -05:00
SSL_CTX_free ( cur_ctx ) ;
rv = 1 ;
goto end ;
}
2015-12-10 15:07:30 -05:00
# if (defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP)
/* Load OCSP Info into context */
2016-11-13 11:37:13 -05:00
if ( ssl_sock_load_ocsp ( cur_ctx , cur_file ) < 0 ) {
2015-12-10 15:07:30 -05:00
if ( err )
memprintf ( err , " %s '%s.ocsp' is present and activates OCSP but it is impossible to compute the OCSP certificate ID (maybe the issuer could not be found)'. \n " ,
2016-11-13 11:37:14 -05:00
* err ? * err : " " , cur_file ) ;
2015-12-10 15:07:30 -05:00
SSL_CTX_free ( cur_ctx ) ;
rv = 1 ;
goto end ;
}
2017-05-22 08:58:00 -04:00
# elif (defined OPENSSL_IS_BORINGSSL)
ssl_sock_set_ocsp_response_from_file ( cur_ctx , cur_file ) ;
2015-12-10 15:07:30 -05:00
# endif
2015-12-02 13:01:29 -05:00
}
}
/* Load DH params into the ctx to support DHE keys */
# ifndef OPENSSL_NO_DH
if ( ssl_dh_ptr_index > = 0 )
SSL_CTX_set_ex_data ( cur_ctx , ssl_dh_ptr_index , NULL ) ;
rv = ssl_sock_load_dh_params ( cur_ctx , NULL ) ;
if ( rv < 0 ) {
if ( err )
memprintf ( err , " %sunable to load DH parameters from file '%s'. \n " ,
* err ? * err : " " , path ) ;
rv = 1 ;
goto end ;
}
# endif
/* Update key_combos */
key_combos [ i - 1 ] . ctx = cur_ctx ;
}
/* Update SNI Tree */
2017-02-20 10:11:50 -05:00
key_combos [ i - 1 ] . order = ssl_sock_add_cert_sni ( cur_ctx , bind_conf , ssl_conf ,
2017-10-27 12:43:29 -04:00
kinfo , str , key_combos [ i - 1 ] . order ) ;
2015-12-02 13:01:29 -05:00
node = ebmb_next ( node ) ;
}
/* Mark a default context if none exists, using the ctx that has the most shared keys */
if ( ! bind_conf - > default_ctx ) {
for ( i = SSL_SOCK_POSSIBLE_KT_COMBOS - 1 ; i > = 0 ; i - - ) {
if ( key_combos [ i ] . ctx ) {
bind_conf - > default_ctx = key_combos [ i ] . ctx ;
2016-12-29 12:26:15 -05:00
bind_conf - > default_ssl_conf = ssl_conf ;
2015-12-02 13:01:29 -05:00
break ;
}
}
}
end :
if ( names )
sk_GENERAL_NAME_pop_free ( names , GENERAL_NAME_free ) ;
for ( n = 0 ; n < SSL_SOCK_NUM_KEYTYPES ; n + + )
ssl_sock_free_cert_key_and_chain_contents ( & certs_and_keys [ n ] ) ;
node = ebmb_first ( & sni_keytypes_map ) ;
while ( node ) {
next = ebmb_next ( node ) ;
ebmb_delete ( node ) ;
node = next ;
}
return rv ;
}
# else
/* This is a dummy, that just logs an error and returns error */
2016-12-29 12:26:15 -05:00
static int ssl_sock_load_multi_cert ( const char * path , struct bind_conf * bind_conf , struct ssl_bind_conf * ssl_conf ,
char * * sni_filter , int fcount , char * * err )
2015-12-02 13:01:29 -05:00
{
memprintf ( err , " %sunable to stat SSL certificate from file '%s' : %s. \n " ,
err & & * err ? * err : " " , path , strerror ( errno ) ) ;
return 1 ;
}
2015-12-01 15:16:07 -05:00
# endif /* #if OPENSSL_VERSION_NUMBER >= 0x1000200fL: Support for loading multiple certs into a single SSL_CTX */
2012-09-07 11:30:07 -04:00
/* Loads a certificate key and CA chain from a file. Returns 0 on error, -1 if
* an early error happens and the caller must call SSL_CTX_free ( ) by itelf .
*/
2016-12-29 12:26:15 -05:00
static int ssl_sock_load_cert_chain_file ( SSL_CTX * ctx , const char * file , struct bind_conf * s ,
struct ssl_bind_conf * ssl_conf , char * * sni_filter , int fcount )
2012-09-07 11:30:07 -04:00
{
BIO * in ;
X509 * x = NULL , * ca ;
2013-05-07 14:20:06 -04:00
int i , err ;
2012-09-07 11:30:07 -04:00
int ret = - 1 ;
int order = 0 ;
X509_NAME * xname ;
char * str ;
2016-08-29 07:26:37 -04:00
pem_password_cb * passwd_cb ;
void * passwd_cb_userdata ;
2017-02-20 10:11:50 -05:00
EVP_PKEY * pkey ;
2017-10-27 12:43:29 -04:00
struct pkey_info kinfo = { . sig = TLSEXT_signature_anonymous , . bits = 0 } ;
2016-08-29 07:26:37 -04:00
2012-09-07 11:30:07 -04:00
# ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
STACK_OF ( GENERAL_NAME ) * names ;
# endif
in = BIO_new ( BIO_s_file ( ) ) ;
if ( in = = NULL )
goto end ;
if ( BIO_read_filename ( in , file ) < = 0 )
goto end ;
2016-08-29 07:26:37 -04:00
passwd_cb = SSL_CTX_get_default_passwd_cb ( ctx ) ;
passwd_cb_userdata = SSL_CTX_get_default_passwd_cb_userdata ( ctx ) ;
x = PEM_read_bio_X509_AUX ( in , NULL , passwd_cb , passwd_cb_userdata ) ;
2012-09-07 11:30:07 -04:00
if ( x = = NULL )
goto end ;
2017-02-20 10:11:50 -05:00
pkey = X509_get_pubkey ( x ) ;
if ( pkey ) {
2017-10-27 12:43:29 -04:00
kinfo . bits = EVP_PKEY_bits ( pkey ) ;
2017-02-20 10:11:50 -05:00
switch ( EVP_PKEY_base_id ( pkey ) ) {
case EVP_PKEY_RSA :
2017-10-27 12:43:29 -04:00
kinfo . sig = TLSEXT_signature_rsa ;
2017-02-20 10:11:50 -05:00
break ;
case EVP_PKEY_EC :
2017-10-27 12:43:29 -04:00
kinfo . sig = TLSEXT_signature_ecdsa ;
break ;
case EVP_PKEY_DSA :
kinfo . sig = TLSEXT_signature_dsa ;
2017-02-20 10:11:50 -05:00
break ;
}
EVP_PKEY_free ( pkey ) ;
}
2013-04-22 07:05:23 -04:00
if ( fcount ) {
while ( fcount - - )
2017-10-27 12:43:29 -04:00
order = ssl_sock_add_cert_sni ( ctx , s , ssl_conf , kinfo , sni_filter [ fcount ] , order ) ;
2013-01-22 09:31:15 -05:00
}
else {
2012-09-07 11:30:07 -04:00
# ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
2013-01-22 09:31:15 -05:00
names = X509_get_ext_d2i ( x , NID_subject_alt_name , NULL , NULL ) ;
if ( names ) {
for ( i = 0 ; i < sk_GENERAL_NAME_num ( names ) ; i + + ) {
GENERAL_NAME * name = sk_GENERAL_NAME_value ( names , i ) ;
if ( name - > type = = GEN_DNS ) {
if ( ASN1_STRING_to_UTF8 ( ( unsigned char * * ) & str , name - > d . dNSName ) > = 0 ) {
2017-10-27 12:43:29 -04:00
order = ssl_sock_add_cert_sni ( ctx , s , ssl_conf , kinfo , str , order ) ;
2013-01-22 09:31:15 -05:00
OPENSSL_free ( str ) ;
2012-09-07 11:30:07 -04:00
}
}
}
2013-01-22 09:31:15 -05:00
sk_GENERAL_NAME_pop_free ( names , GENERAL_NAME_free ) ;
2012-09-07 11:30:07 -04:00
}
# endif /* SSL_CTRL_SET_TLSEXT_HOSTNAME */
2013-01-22 09:31:15 -05:00
xname = X509_get_subject_name ( x ) ;
i = - 1 ;
while ( ( i = X509_NAME_get_index_by_NID ( xname , NID_commonName , i ) ) ! = - 1 ) {
X509_NAME_ENTRY * entry = X509_NAME_get_entry ( xname , i ) ;
2016-08-29 07:26:37 -04:00
ASN1_STRING * value ;
value = X509_NAME_ENTRY_get_data ( entry ) ;
if ( ASN1_STRING_to_UTF8 ( ( unsigned char * * ) & str , value ) > = 0 ) {
2017-10-27 12:43:29 -04:00
order = ssl_sock_add_cert_sni ( ctx , s , ssl_conf , kinfo , str , order ) ;
2013-01-22 09:31:15 -05:00
OPENSSL_free ( str ) ;
2012-09-07 11:30:07 -04:00
}
}
}
ret = 0 ; /* the caller must not free the SSL_CTX argument anymore */
if ( ! SSL_CTX_use_certificate ( ctx , x ) )
goto end ;
2016-08-29 07:26:37 -04:00
# ifdef SSL_CTX_clear_extra_chain_certs
SSL_CTX_clear_extra_chain_certs ( ctx ) ;
# else
2012-09-07 11:30:07 -04:00
if ( ctx - > extra_certs ! = NULL ) {
sk_X509_pop_free ( ctx - > extra_certs , X509_free ) ;
ctx - > extra_certs = NULL ;
}
2016-08-29 07:26:37 -04:00
# endif
2012-09-07 11:30:07 -04:00
2016-08-29 07:26:37 -04:00
while ( ( ca = PEM_read_bio_X509 ( in , NULL , passwd_cb , passwd_cb_userdata ) ) ) {
2012-09-07 11:30:07 -04:00
if ( ! SSL_CTX_add_extra_chain_cert ( ctx , ca ) ) {
X509_free ( ca ) ;
goto end ;
}
}
err = ERR_get_error ( ) ;
if ( ! err | | ( ERR_GET_LIB ( err ) = = ERR_LIB_PEM & & ERR_GET_REASON ( err ) = = PEM_R_NO_START_LINE ) ) {
/* we successfully reached the last cert in the file */
ret = 1 ;
}
ERR_clear_error ( ) ;
end :
if ( x )
X509_free ( x ) ;
if ( in )
BIO_free ( in ) ;
return ret ;
}
2016-12-29 12:26:15 -05:00
static int ssl_sock_load_cert_file ( const char * path , struct bind_conf * bind_conf , struct ssl_bind_conf * ssl_conf ,
char * * sni_filter , int fcount , char * * err )
2012-09-07 11:30:07 -04:00
{
int ret ;
SSL_CTX * ctx ;
2017-03-06 09:34:44 -05:00
ctx = SSL_CTX_new ( SSLv23_server_method ( ) ) ;
2012-09-07 11:30:07 -04:00
if ( ! ctx ) {
2012-09-20 13:43:14 -04:00
memprintf ( err , " %sunable to allocate SSL context for cert '%s'. \n " ,
err & & * err ? * err : " " , path ) ;
2012-09-07 11:30:07 -04:00
return 1 ;
}
if ( SSL_CTX_use_PrivateKey_file ( ctx , path , SSL_FILETYPE_PEM ) < = 0 ) {
2012-09-20 13:43:14 -04:00
memprintf ( err , " %sunable to load SSL private key from PEM file '%s'. \n " ,
err & & * err ? * err : " " , path ) ;
2012-09-07 11:30:07 -04:00
SSL_CTX_free ( ctx ) ;
return 1 ;
}
2016-12-29 12:26:15 -05:00
ret = ssl_sock_load_cert_chain_file ( ctx , path , bind_conf , ssl_conf , sni_filter , fcount ) ;
2012-09-07 11:30:07 -04:00
if ( ret < = 0 ) {
2012-09-20 13:43:14 -04:00
memprintf ( err , " %sunable to load SSL certificate from PEM file '%s'. \n " ,
err & & * err ? * err : " " , path ) ;
2012-09-07 11:30:07 -04:00
if ( ret < 0 ) /* serious error, must do that ourselves */
SSL_CTX_free ( ctx ) ;
return 1 ;
}
2012-10-26 07:35:33 -04:00
if ( SSL_CTX_check_private_key ( ctx ) < = 0 ) {
memprintf ( err , " %sinconsistencies between private key and certificate loaded from PEM file '%s'. \n " ,
err & & * err ? * err : " " , path ) ;
return 1 ;
}
2012-09-07 11:30:07 -04:00
/* we must not free the SSL_CTX anymore below, since it's already in
* the tree , so it will be discovered and cleaned in time .
*/
2012-09-20 10:19:02 -04:00
# ifndef OPENSSL_NO_DH
2015-05-28 10:23:00 -04:00
/* store a NULL pointer to indicate we have not yet loaded
a custom DH param file */
if ( ssl_dh_ptr_index > = 0 ) {
SSL_CTX_set_ex_data ( ctx , ssl_dh_ptr_index , NULL ) ;
}
2012-09-20 10:19:02 -04:00
ret = ssl_sock_load_dh_params ( ctx , path ) ;
if ( ret < 0 ) {
if ( err )
memprintf ( err , " %sunable to load DH parameters from file '%s'. \n " ,
* err ? * err : " " , path ) ;
return 1 ;
}
# endif
2014-12-09 10:32:51 -05:00
# if (defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP)
2014-06-16 12:36:30 -04:00
ret = ssl_sock_load_ocsp ( ctx , path ) ;
if ( ret < 0 ) {
if ( err )
memprintf ( err , " %s '%s.ocsp' is present and activates OCSP but it is impossible to compute the OCSP certificate ID (maybe the issuer could not be found)'. \n " ,
* err ? * err : " " , path ) ;
return 1 ;
}
2017-05-22 08:58:00 -04:00
# elif (defined OPENSSL_IS_BORINGSSL)
ssl_sock_set_ocsp_response_from_file ( ctx , path ) ;
2014-06-16 12:36:30 -04:00
# endif
2015-11-06 14:02:41 -05:00
# if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
2015-03-07 17:03:59 -05:00
if ( sctl_ex_index > = 0 ) {
ret = ssl_sock_load_sctl ( ctx , path ) ;
if ( ret < 0 ) {
if ( err )
memprintf ( err , " %s '%s.sctl' is present but cannot be read or parsed'. \n " ,
* err ? * err : " " , path ) ;
return 1 ;
}
}
# endif
2012-09-07 11:30:07 -04:00
# ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
2012-09-13 11:54:29 -04:00
if ( bind_conf - > default_ctx ) {
2012-09-20 13:43:14 -04:00
memprintf ( err , " %sthis version of openssl cannot load multiple SSL certificates. \n " ,
err & & * err ? * err : " " ) ;
2012-09-07 11:30:07 -04:00
return 1 ;
}
# endif
2016-12-29 12:26:15 -05:00
if ( ! bind_conf - > default_ctx ) {
2012-09-13 11:54:29 -04:00
bind_conf - > default_ctx = ctx ;
2016-12-29 12:26:15 -05:00
bind_conf - > default_ssl_conf = ssl_conf ;
}
2012-09-07 11:30:07 -04:00
return 0 ;
}
2016-12-22 11:08:28 -05:00
int ssl_sock_load_cert ( char * path , struct bind_conf * bind_conf , char * * err )
2012-09-07 11:30:07 -04:00
{
2015-01-24 18:16:08 -05:00
struct dirent * * de_list ;
int i , n ;
2012-09-07 11:30:07 -04:00
DIR * dir ;
struct stat buf ;
2012-12-06 05:36:59 -05:00
char * end ;
char fp [ MAXPATHLEN + 1 ] ;
2012-09-07 11:30:07 -04:00
int cfgerr = 0 ;
2015-12-09 13:35:14 -05:00
# if OPENSSL_VERSION_NUMBER >= 0x1000200fL
int is_bundle ;
int j ;
# endif
2012-09-07 11:30:07 -04:00
2015-12-02 13:01:29 -05:00
if ( stat ( path , & buf ) = = 0 ) {
dir = opendir ( path ) ;
if ( ! dir )
2016-12-29 12:26:15 -05:00
return ssl_sock_load_cert_file ( path , bind_conf , NULL , NULL , 0 , err ) ;
2012-09-07 11:30:07 -04:00
2015-12-02 13:01:29 -05:00
/* strip trailing slashes, including first one */
for ( end = path + strlen ( path ) - 1 ; end > = path & & * end = = ' / ' ; end - - )
* end = 0 ;
2012-09-07 11:30:07 -04:00
2015-12-02 13:01:29 -05:00
n = scandir ( path , & de_list , 0 , alphasort ) ;
if ( n < 0 ) {
memprintf ( err , " %sunable to scan directory '%s' : %s. \n " ,
err & & * err ? * err : " " , path , strerror ( errno ) ) ;
cfgerr + + ;
}
else {
for ( i = 0 ; i < n ; i + + ) {
struct dirent * de = de_list [ i ] ;
end = strrchr ( de - > d_name , ' . ' ) ;
if ( end & & ( ! strcmp ( end , " .issuer " ) | | ! strcmp ( end , " .ocsp " ) | | ! strcmp ( end , " .sctl " ) ) )
goto ignore_entry ;
snprintf ( fp , sizeof ( fp ) , " %s/%s " , path , de - > d_name ) ;
if ( stat ( fp , & buf ) ! = 0 ) {
memprintf ( err , " %sunable to stat SSL certificate from file '%s' : %s. \n " ,
err & & * err ? * err : " " , fp , strerror ( errno ) ) ;
cfgerr + + ;
goto ignore_entry ;
}
if ( ! S_ISREG ( buf . st_mode ) )
goto ignore_entry ;
2015-12-09 13:35:14 -05:00
# if OPENSSL_VERSION_NUMBER >= 0x1000200fL
is_bundle = 0 ;
/* Check if current entry in directory is part of a multi-cert bundle */
if ( end ) {
for ( j = 0 ; j < SSL_SOCK_NUM_KEYTYPES ; j + + ) {
if ( ! strcmp ( end + 1 , SSL_SOCK_KEYTYPE_NAMES [ j ] ) ) {
is_bundle = 1 ;
break ;
}
}
if ( is_bundle ) {
char dp [ MAXPATHLEN + 1 ] = { 0 } ; /* this will be the filename w/o the keytype */
int dp_len ;
dp_len = end - de - > d_name ;
snprintf ( dp , dp_len + 1 , " %s " , de - > d_name ) ;
/* increment i and free de until we get to a non-bundle cert
* Note here that we look at de_list [ i + 1 ] before freeing de
* this is important since ignore_entry will free de
*/
while ( i + 1 < n & & ! strncmp ( de_list [ i + 1 ] - > d_name , dp , dp_len ) ) {
free ( de ) ;
i + + ;
de = de_list [ i ] ;
}
snprintf ( fp , sizeof ( fp ) , " %s/%s " , path , dp ) ;
2018-08-16 09:11:12 -04:00
cfgerr + = ssl_sock_load_multi_cert ( fp , bind_conf , NULL , NULL , 0 , err ) ;
2015-12-09 13:35:14 -05:00
/* Successfully processed the bundle */
goto ignore_entry ;
}
}
# endif
2016-12-29 12:26:15 -05:00
cfgerr + = ssl_sock_load_cert_file ( fp , bind_conf , NULL , NULL , 0 , err ) ;
2015-12-02 13:01:29 -05:00
ignore_entry :
free ( de ) ;
2015-01-24 18:16:08 -05:00
}
2015-12-02 13:01:29 -05:00
free ( de_list ) ;
2012-09-07 11:30:07 -04:00
}
2015-12-02 13:01:29 -05:00
closedir ( dir ) ;
return cfgerr ;
2012-09-07 11:30:07 -04:00
}
2015-12-02 13:01:29 -05:00
2016-12-29 12:26:15 -05:00
cfgerr = ssl_sock_load_multi_cert ( path , bind_conf , NULL , NULL , 0 , err ) ;
2015-12-02 13:01:29 -05:00
2012-09-07 11:30:07 -04:00
return cfgerr ;
}
2013-01-24 08:15:43 -05:00
/* Make sure openssl opens /dev/urandom before the chroot. The work is only
* done once . Zero is returned if the operation fails . No error is returned
* if the random is said as not implemented , because we expect that openssl
* will use another method once needed .
*/
static int ssl_initialize_random ( )
{
unsigned char random ;
static int random_initialized = 0 ;
if ( ! random_initialized & & RAND_bytes ( & random , 1 ) ! = 0 )
random_initialized = 1 ;
return random_initialized ;
}
2016-12-29 12:26:15 -05:00
/* release ssl bind conf */
void ssl_sock_free_ssl_conf ( struct ssl_bind_conf * conf )
2013-01-22 09:31:15 -05:00
{
2016-12-29 12:26:15 -05:00
if ( conf ) {
2018-02-15 07:34:58 -05:00
# if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2016-12-29 12:26:15 -05:00
free ( conf - > npn_str ) ;
conf - > npn_str = NULL ;
# endif
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
free ( conf - > alpn_str ) ;
conf - > alpn_str = NULL ;
# endif
free ( conf - > ca_file ) ;
conf - > ca_file = NULL ;
free ( conf - > crl_file ) ;
conf - > crl_file = NULL ;
free ( conf - > ciphers ) ;
conf - > ciphers = NULL ;
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
free ( conf - > ciphersuites ) ;
conf - > ciphersuites = NULL ;
# endif
2017-01-09 10:15:54 -05:00
free ( conf - > curves ) ;
conf - > curves = NULL ;
2016-12-29 12:26:15 -05:00
free ( conf - > ecdhe ) ;
conf - > ecdhe = NULL ;
}
}
int ssl_sock_load_cert_list_file ( char * file , struct bind_conf * bind_conf , struct proxy * curproxy , char * * err )
{
char thisline [ CRT_LINESIZE ] ;
char path [ MAXPATHLEN + 1 ] ;
2013-01-22 09:31:15 -05:00
FILE * f ;
2015-12-02 13:54:14 -05:00
struct stat buf ;
2013-01-22 09:31:15 -05:00
int linenum = 0 ;
int cfgerr = 0 ;
2013-04-02 11:35:58 -04:00
if ( ( f = fopen ( file , " r " ) ) = = NULL ) {
memprintf ( err , " cannot open file '%s' : %s " , file , strerror ( errno ) ) ;
2013-01-22 09:31:15 -05:00
return 1 ;
2013-04-02 11:35:58 -04:00
}
2013-01-22 09:31:15 -05:00
while ( fgets ( thisline , sizeof ( thisline ) , f ) ! = NULL ) {
2016-12-29 12:26:15 -05:00
int arg , newarg , cur_arg , i , ssl_b = 0 , ssl_e = 0 ;
2013-01-22 09:31:15 -05:00
char * end ;
2016-12-29 12:26:15 -05:00
char * args [ MAX_CRT_ARGS + 1 ] ;
2013-01-22 09:31:15 -05:00
char * line = thisline ;
2016-12-29 12:26:15 -05:00
char * crt_path ;
struct ssl_bind_conf * ssl_conf = NULL ;
2013-01-22 09:31:15 -05:00
linenum + + ;
end = line + strlen ( line ) ;
if ( end - line = = sizeof ( thisline ) - 1 & & * ( end - 1 ) ! = ' \n ' ) {
/* Check if we reached the limit and the last char is not \n.
* Watch out for the last line without the terminating ' \n ' !
*/
2013-04-02 11:35:58 -04:00
memprintf ( err , " line %d too long in file '%s', limit is %d characters " ,
linenum , file , ( int ) sizeof ( thisline ) - 1 ) ;
2013-01-22 09:31:15 -05:00
cfgerr = 1 ;
2013-04-02 11:35:58 -04:00
break ;
2013-01-22 09:31:15 -05:00
}
arg = 0 ;
2013-04-22 07:05:23 -04:00
newarg = 1 ;
while ( * line ) {
2013-01-22 09:31:15 -05:00
if ( * line = = ' # ' | | * line = = ' \n ' | | * line = = ' \r ' ) {
/* end of string, end of loop */
* line = 0 ;
break ;
2016-12-29 12:26:15 -05:00
} else if ( isspace ( * line ) ) {
2013-04-22 07:05:23 -04:00
newarg = 1 ;
* line = 0 ;
2016-12-29 12:26:15 -05:00
} else if ( * line = = ' [ ' ) {
if ( ssl_b ) {
memprintf ( err , " too many '[' on line %d in file '%s'. " , linenum , file ) ;
cfgerr = 1 ;
break ;
}
if ( ! arg ) {
memprintf ( err , " file must start with a cert on line %d in file '%s' " , linenum , file ) ;
cfgerr = 1 ;
break ;
}
ssl_b = arg ;
newarg = 1 ;
* line = 0 ;
} else if ( * line = = ' ] ' ) {
if ( ssl_e ) {
memprintf ( err , " too many ']' on line %d in file '%s'. " , linenum , file ) ;
cfgerr = 1 ;
break ;
}
if ( ! ssl_b ) {
memprintf ( err , " missing '[' in line %d in file '%s'. " , linenum , file ) ;
cfgerr = 1 ;
break ;
}
ssl_e = arg ;
newarg = 1 ;
* line = 0 ;
} else if ( newarg ) {
if ( arg = = MAX_CRT_ARGS ) {
memprintf ( err , " too many args on line %d in file '%s'. " , linenum , file ) ;
2013-04-22 07:05:23 -04:00
cfgerr = 1 ;
break ;
}
newarg = 0 ;
args [ arg + + ] = line ;
2013-01-22 09:31:15 -05:00
}
2013-04-22 07:05:23 -04:00
line + + ;
2013-01-22 09:31:15 -05:00
}
2013-05-07 14:20:06 -04:00
if ( cfgerr )
break ;
2016-12-29 12:26:15 -05:00
args [ arg + + ] = line ;
2013-04-02 11:35:58 -04:00
2013-01-22 09:31:15 -05:00
/* empty line */
2016-12-29 12:26:15 -05:00
if ( ! * args [ 0 ] )
2013-01-22 09:31:15 -05:00
continue ;
2016-12-29 12:26:15 -05:00
crt_path = args [ 0 ] ;
if ( * crt_path ! = ' / ' & & global_ssl . crt_base ) {
if ( ( strlen ( global_ssl . crt_base ) + 1 + strlen ( crt_path ) ) > MAXPATHLEN ) {
memprintf ( err , " '%s' : path too long on line %d in file '%s' " ,
crt_path , linenum , file ) ;
cfgerr = 1 ;
break ;
}
snprintf ( path , sizeof ( path ) , " %s/%s " , global_ssl . crt_base , crt_path ) ;
crt_path = path ;
}
ssl_conf = calloc ( 1 , sizeof * ssl_conf ) ;
cur_arg = ssl_b ? ssl_b : 1 ;
while ( cur_arg < ssl_e ) {
newarg = 0 ;
for ( i = 0 ; ssl_bind_kws [ i ] . kw ! = NULL ; i + + ) {
if ( strcmp ( ssl_bind_kws [ i ] . kw , args [ cur_arg ] ) = = 0 ) {
newarg = 1 ;
cfgerr = ssl_bind_kws [ i ] . parse ( args , cur_arg , curproxy , ssl_conf , err ) ;
if ( cur_arg + 1 + ssl_bind_kws [ i ] . skip > ssl_e ) {
memprintf ( err , " ssl args out of '[]' for %s on line %d in file '%s' " ,
args [ cur_arg ] , linenum , file ) ;
cfgerr = 1 ;
}
cur_arg + = 1 + ssl_bind_kws [ i ] . skip ;
break ;
}
}
if ( ! cfgerr & & ! newarg ) {
memprintf ( err , " unknown ssl keyword %s on line %d in file '%s'. " ,
args [ cur_arg ] , linenum , file ) ;
cfgerr = 1 ;
break ;
}
}
if ( cfgerr ) {
ssl_sock_free_ssl_conf ( ssl_conf ) ;
free ( ssl_conf ) ;
ssl_conf = NULL ;
break ;
}
if ( stat ( crt_path , & buf ) = = 0 ) {
cfgerr = ssl_sock_load_cert_file ( crt_path , bind_conf , ssl_conf ,
& args [ cur_arg ] , arg - cur_arg - 1 , err ) ;
2015-12-02 13:54:14 -05:00
} else {
2016-12-29 12:26:15 -05:00
cfgerr = ssl_sock_load_multi_cert ( crt_path , bind_conf , ssl_conf ,
& args [ cur_arg ] , arg - cur_arg - 1 , err ) ;
2015-12-02 13:54:14 -05:00
}
2013-04-02 11:35:58 -04:00
if ( cfgerr ) {
memprintf ( err , " error processing line %d in file '%s' : %s " , linenum , file , * err ) ;
2013-01-22 09:31:15 -05:00
break ;
2013-04-02 11:35:58 -04:00
}
2013-01-22 09:31:15 -05:00
}
fclose ( f ) ;
return cfgerr ;
}
2017-03-06 09:34:44 -05:00
/* Create an initial CTX used to start the SSL connection before switchctx */
2017-05-05 12:06:12 -04:00
static int
2017-03-06 09:34:44 -05:00
ssl_sock_initial_ctx ( struct bind_conf * bind_conf )
2012-09-07 11:30:07 -04:00
{
2017-03-03 06:21:32 -05:00
SSL_CTX * ctx = NULL ;
2017-03-30 13:19:37 -04:00
long options =
2012-09-07 11:30:07 -04:00
SSL_OP_ALL | /* all known workarounds for bugs */
SSL_OP_NO_SSLv2 |
SSL_OP_NO_COMPRESSION |
2012-09-20 10:19:02 -04:00
SSL_OP_SINGLE_DH_USE |
2012-09-20 11:10:03 -04:00
SSL_OP_SINGLE_ECDH_USE |
2012-10-04 12:44:19 -04:00
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
2018-05-18 11:55:57 -04:00
SSL_OP_PRIORITIZE_CHACHA |
2012-10-04 12:44:19 -04:00
SSL_OP_CIPHER_SERVER_PREFERENCE ;
2017-03-30 13:19:37 -04:00
long mode =
2012-09-07 11:30:07 -04:00
SSL_MODE_ENABLE_PARTIAL_WRITE |
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
2014-11-13 08:06:52 -05:00
SSL_MODE_RELEASE_BUFFERS |
SSL_MODE_SMALL_BUFFERS ;
2017-08-09 12:26:20 -04:00
struct tls_version_filter * conf_ssl_methods = & bind_conf - > ssl_conf . ssl_methods ;
2017-03-30 13:25:07 -04:00
int i , min , max , hole ;
2017-05-05 12:06:12 -04:00
int flags = MC_SSL_O_ALL ;
int cfgerr = 0 ;
2017-03-03 06:21:32 -05:00
2017-03-30 13:19:37 -04:00
ctx = SSL_CTX_new ( SSLv23_server_method ( ) ) ;
2017-05-05 12:06:12 -04:00
bind_conf - > initial_ctx = ctx ;
if ( conf_ssl_methods - > flags & & ( conf_ssl_methods - > min | | conf_ssl_methods - > max ) )
2017-11-24 10:50:31 -05:00
ha_warning ( " Proxy '%s': no-sslv3/no-tlsv1x are ignored for bind '%s' at [%s:%d]. "
" Use only 'ssl-min-ver' and 'ssl-max-ver' to fix. \n " ,
bind_conf - > frontend - > id , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2017-05-05 12:06:12 -04:00
else
flags = conf_ssl_methods - > flags ;
2017-03-30 13:19:37 -04:00
2017-05-15 09:53:41 -04:00
min = conf_ssl_methods - > min ;
max = conf_ssl_methods - > max ;
/* start with TLSv10 to remove SSLv3 per default */
if ( ! min & & ( ! max | | max > = CONF_TLSV10 ) )
min = CONF_TLSV10 ;
2017-05-18 06:33:19 -04:00
/* Real min and max should be determinate with configuration and openssl's capabilities */
2017-05-15 09:53:41 -04:00
if ( min )
flags | = ( methodVersions [ min ] . flag - 1 ) ;
if ( max )
flags | = ~ ( ( methodVersions [ max ] . flag < < 1 ) - 1 ) ;
2017-05-18 06:33:19 -04:00
/* find min, max and holes */
2017-03-30 13:25:07 -04:00
min = max = CONF_TLSV_NONE ;
hole = 0 ;
2017-03-30 13:19:37 -04:00
for ( i = CONF_TLSV_MIN ; i < = CONF_TLSV_MAX ; i + + )
2017-03-30 13:25:07 -04:00
/* version is in openssl && version not disable in configuration */
2017-05-05 12:06:12 -04:00
if ( methodVersions [ i ] . option & & ! ( flags & methodVersions [ i ] . flag ) ) {
2017-03-30 13:25:07 -04:00
if ( min ) {
if ( hole ) {
2017-11-24 10:50:31 -05:00
ha_warning ( " Proxy '%s': SSL/TLS versions range not contiguous for bind '%s' at [%s:%d]. "
" Hole find for %s. Use only 'ssl-min-ver' and 'ssl-max-ver' to fix. \n " ,
bind_conf - > frontend - > id , bind_conf - > arg , bind_conf - > file , bind_conf - > line ,
methodVersions [ hole ] . name ) ;
2017-03-30 13:25:07 -04:00
hole = 0 ;
}
max = i ;
}
else {
min = max = i ;
}
}
else {
if ( min )
hole = i ;
}
2017-05-05 12:06:12 -04:00
if ( ! min ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': all SSL/TLS versions are disabled for bind '%s' at [%s:%d]. \n " ,
bind_conf - > frontend - > id , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2017-05-05 12:06:12 -04:00
cfgerr + = 1 ;
}
2017-05-18 06:46:50 -04:00
/* save real min/max in bind_conf */
conf_ssl_methods - > min = min ;
conf_ssl_methods - > max = max ;
2017-03-30 13:19:37 -04:00
2017-10-02 11:12:06 -04:00
# if (OPENSSL_VERSION_NUMBER < 0x1010000fL)
2017-03-30 13:19:37 -04:00
/* Keep force-xxx implementation as it is in older haproxy. It's a
2018-11-15 12:07:59 -05:00
precautionary measure to avoid any surprise with older openssl version . */
2017-03-30 13:19:37 -04:00
if ( min = = max )
2017-05-18 06:33:19 -04:00
methodVersions [ min ] . ctx_set_version ( ctx , SET_SERVER ) ;
2017-05-05 12:06:12 -04:00
else
for ( i = CONF_TLSV_MIN ; i < = CONF_TLSV_MAX ; i + + )
if ( flags & methodVersions [ i ] . flag )
options | = methodVersions [ i ] . option ;
2017-03-30 13:19:37 -04:00
# else /* openssl >= 1.1.0 */
2017-03-30 13:25:07 -04:00
/* set the max_version is required to cap TLS version or activate new TLS (v1.3) */
2017-05-18 06:33:19 -04:00
methodVersions [ min ] . ctx_set_version ( ctx , SET_MIN ) ;
methodVersions [ max ] . ctx_set_version ( ctx , SET_MAX ) ;
2017-03-03 06:21:32 -05:00
# endif
2017-03-30 13:19:37 -04:00
if ( bind_conf - > ssl_options & BC_SSL_O_NO_TLS_TICKETS )
options | = SSL_OP_NO_TICKET ;
if ( bind_conf - > ssl_options & BC_SSL_O_PREF_CLIE_CIPH )
options & = ~ SSL_OP_CIPHER_SERVER_PREFERENCE ;
2019-01-21 12:35:03 -05:00
# ifdef SSL_OP_NO_RENEGOTIATION
options | = SSL_OP_NO_RENEGOTIATION ;
# endif
2017-03-30 13:19:37 -04:00
SSL_CTX_set_options ( ctx , options ) ;
2017-01-13 20:42:15 -05:00
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-01-13 20:42:15 -05:00
if ( global_ssl . async )
mode | = SSL_MODE_ASYNC ;
# endif
2017-03-30 13:19:37 -04:00
SSL_CTX_set_mode ( ctx , mode ) ;
2017-03-03 06:21:32 -05:00
if ( global_ssl . life_time )
SSL_CTX_set_timeout ( ctx , global_ssl . life_time ) ;
2017-03-06 09:34:44 -05:00
# ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
# ifdef OPENSSL_IS_BORINGSSL
SSL_CTX_set_select_certificate_cb ( ctx , ssl_sock_switchctx_cbk ) ;
SSL_CTX_set_tlsext_servername_callback ( ctx , ssl_sock_switchctx_err_cbk ) ;
2017-08-16 05:33:17 -04:00
# elif (OPENSSL_VERSION_NUMBER >= 0x10101000L)
2019-01-02 12:46:41 -05:00
if ( bind_conf - > ssl_conf . early_data ) {
SSL_CTX_set_options ( ctx , SSL_OP_NO_ANTI_REPLAY ) ;
SSL_CTX_set_max_early_data ( ctx , global . tune . bufsize - global . tune . maxrewrite ) ;
}
2017-08-16 05:33:17 -04:00
SSL_CTX_set_client_hello_cb ( ctx , ssl_sock_switchctx_cbk , NULL ) ;
SSL_CTX_set_tlsext_servername_callback ( ctx , ssl_sock_switchctx_err_cbk ) ;
2017-03-06 09:34:44 -05:00
# else
SSL_CTX_set_tlsext_servername_callback ( ctx , ssl_sock_switchctx_cbk ) ;
# endif
2017-08-14 05:01:25 -04:00
SSL_CTX_set_tlsext_servername_arg ( ctx , bind_conf ) ;
2017-03-06 09:34:44 -05:00
# endif
2017-05-05 12:06:12 -04:00
return cfgerr ;
2017-03-03 06:21:32 -05:00
}
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
static inline void sh_ssl_sess_free_blocks ( struct shared_block * first , struct shared_block * block )
{
if ( first = = block ) {
struct sh_ssl_sess_hdr * sh_ssl_sess = ( struct sh_ssl_sess_hdr * ) first - > data ;
if ( first - > len > 0 )
sh_ssl_sess_tree_delete ( sh_ssl_sess ) ;
}
}
/* return first block from sh_ssl_sess */
static inline struct shared_block * sh_ssl_sess_first_block ( struct sh_ssl_sess_hdr * sh_ssl_sess )
{
return ( struct shared_block * ) ( ( unsigned char * ) sh_ssl_sess - ( ( struct shared_block * ) NULL ) - > data ) ;
}
/* store a session into the cache
* s_id : session id padded with zero to SSL_MAX_SSL_SESSION_ID_LENGTH
* data : asn1 encoded session
* data_len : asn1 encoded session length
* Returns 1 id session was stored ( else 0 )
*/
static int sh_ssl_sess_store ( unsigned char * s_id , unsigned char * data , int data_len )
{
struct shared_block * first ;
struct sh_ssl_sess_hdr * sh_ssl_sess , * oldsh_ssl_sess ;
2018-10-22 11:55:57 -04:00
first = shctx_row_reserve_hot ( ssl_shctx , NULL , data_len + sizeof ( struct sh_ssl_sess_hdr ) ) ;
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
if ( ! first ) {
/* Could not retrieve enough free blocks to store that session */
return 0 ;
}
/* STORE the key in the first elem */
sh_ssl_sess = ( struct sh_ssl_sess_hdr * ) first - > data ;
memcpy ( sh_ssl_sess - > key_data , s_id , SSL_MAX_SSL_SESSION_ID_LENGTH ) ;
first - > len = sizeof ( struct sh_ssl_sess_hdr ) ;
/* it returns the already existing node
or current node if none , never returns null */
oldsh_ssl_sess = sh_ssl_sess_tree_insert ( sh_ssl_sess ) ;
if ( oldsh_ssl_sess ! = sh_ssl_sess ) {
/* NOTE: Row couldn't be in use because we lock read & write function */
/* release the reserved row */
shctx_row_dec_hot ( ssl_shctx , first ) ;
/* replace the previous session already in the tree */
sh_ssl_sess = oldsh_ssl_sess ;
/* ignore the previous session data, only use the header */
first = sh_ssl_sess_first_block ( sh_ssl_sess ) ;
shctx_row_inc_hot ( ssl_shctx , first ) ;
first - > len = sizeof ( struct sh_ssl_sess_hdr ) ;
}
2018-10-22 11:55:57 -04:00
if ( shctx_row_data_append ( ssl_shctx , first , NULL , data , data_len ) < 0 ) {
2018-01-03 13:15:51 -05:00
shctx_row_dec_hot ( ssl_shctx , first ) ;
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
return 0 ;
2018-01-03 13:15:51 -05:00
}
shctx_row_dec_hot ( ssl_shctx , first ) ;
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
return 1 ;
}
2017-10-30 14:36:36 -04:00
2017-11-03 08:43:35 -04:00
/* SSL callback used when a new session is created while connecting to a server */
static int ssl_sess_new_srv_cb ( SSL * ssl , SSL_SESSION * sess )
{
BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
We never saw unexplicated crash with SSL, so I suppose that we are
luck, or the slot 0 is always reserved. Anyway the usage of the macro
SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
the deprecated functions SSL_get_app_data() and SSL_set_app_data()
by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
it reserves the slot in the SSL memory space.
For information, this is the two declaration which seems wrong or
incomplete in the OpenSSL ssl.h file. We can see the usage of the
slot 0 whoch is hardcoded, but never reserved.
#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
This patch must be backported at least in 1.8, maybe in other versions.
2018-06-17 15:37:05 -04:00
struct connection * conn = SSL_get_ex_data ( ssl , ssl_app_data_index ) ;
2017-11-16 11:42:52 -05:00
struct server * s ;
2017-11-03 08:43:35 -04:00
2018-09-20 04:57:52 -04:00
s = __objt_server ( conn - > target ) ;
2017-11-03 08:43:35 -04:00
2017-11-16 11:42:52 -05:00
if ( ! ( s - > ssl_ctx . options & SRV_SSL_O_NO_REUSE ) ) {
int len ;
unsigned char * ptr ;
2017-11-03 08:43:35 -04:00
2017-11-16 11:42:52 -05:00
len = i2d_SSL_SESSION ( sess , NULL ) ;
if ( s - > ssl_ctx . reused_sess [ tid ] . ptr & & s - > ssl_ctx . reused_sess [ tid ] . allocated_size > = len ) {
ptr = s - > ssl_ctx . reused_sess [ tid ] . ptr ;
} else {
free ( s - > ssl_ctx . reused_sess [ tid ] . ptr ) ;
ptr = s - > ssl_ctx . reused_sess [ tid ] . ptr = malloc ( len ) ;
s - > ssl_ctx . reused_sess [ tid ] . allocated_size = len ;
}
if ( s - > ssl_ctx . reused_sess [ tid ] . ptr ) {
s - > ssl_ctx . reused_sess [ tid ] . size = i2d_SSL_SESSION ( sess ,
& ptr ) ;
}
} else {
free ( s - > ssl_ctx . reused_sess [ tid ] . ptr ) ;
s - > ssl_ctx . reused_sess [ tid ] . ptr = NULL ;
}
return 0 ;
2017-11-03 08:43:35 -04:00
}
2017-11-16 11:42:52 -05:00
2017-10-30 14:36:36 -04:00
/* SSL callback used on new session creation */
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
int sh_ssl_sess_new_cb ( SSL * ssl , SSL_SESSION * sess )
2017-10-30 14:36:36 -04:00
{
unsigned char encsess [ SHSESS_MAX_DATA_LEN ] ; /* encoded session */
unsigned char encid [ SSL_MAX_SSL_SESSION_ID_LENGTH ] ; /* encoded id */
unsigned char * p ;
int data_len ;
unsigned int sid_length , sid_ctx_length ;
const unsigned char * sid_data ;
const unsigned char * sid_ctx_data ;
/* Session id is already stored in to key and session id is known
* so we dont store it to keep size .
*/
sid_data = SSL_SESSION_get_id ( sess , & sid_length ) ;
sid_ctx_data = SSL_SESSION_get0_id_context ( sess , & sid_ctx_length ) ;
SSL_SESSION_set1_id ( sess , sid_data , 0 ) ;
SSL_SESSION_set1_id_context ( sess , sid_ctx_data , 0 ) ;
/* check if buffer is large enough for the ASN1 encoded session */
data_len = i2d_SSL_SESSION ( sess , NULL ) ;
if ( data_len > SHSESS_MAX_DATA_LEN )
goto err ;
p = encsess ;
/* process ASN1 session encoding before the lock */
i2d_SSL_SESSION ( sess , & p ) ;
memcpy ( encid , sid_data , sid_length ) ;
if ( sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH )
memset ( encid + sid_length , 0 , SSL_MAX_SSL_SESSION_ID_LENGTH - sid_length ) ;
2017-10-30 18:44:40 -04:00
shctx_lock ( ssl_shctx ) ;
2017-10-30 14:36:36 -04:00
/* store to cache */
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
sh_ssl_sess_store ( encid , encsess , data_len ) ;
2017-10-30 18:44:40 -04:00
shctx_unlock ( ssl_shctx ) ;
2017-10-30 14:36:36 -04:00
err :
/* reset original length values */
SSL_SESSION_set1_id ( sess , sid_data , sid_length ) ;
SSL_SESSION_set1_id_context ( sess , sid_ctx_data , sid_ctx_length ) ;
return 0 ; /* do not increment session reference count */
}
/* SSL callback used on lookup an existing session cause none found in internal cache */
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
SSL_SESSION * sh_ssl_sess_get_cb ( SSL * ssl , __OPENSSL_110_CONST__ unsigned char * key , int key_len , int * do_copy )
2017-10-30 14:36:36 -04:00
{
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
struct sh_ssl_sess_hdr * sh_ssl_sess ;
2017-10-30 14:36:36 -04:00
unsigned char data [ SHSESS_MAX_DATA_LEN ] , * p ;
unsigned char tmpkey [ SSL_MAX_SSL_SESSION_ID_LENGTH ] ;
SSL_SESSION * sess ;
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
struct shared_block * first ;
2017-10-30 14:36:36 -04:00
global . shctx_lookups + + ;
/* allow the session to be freed automatically by openssl */
* do_copy = 0 ;
/* tree key is zeros padded sessionid */
if ( key_len < SSL_MAX_SSL_SESSION_ID_LENGTH ) {
memcpy ( tmpkey , key , key_len ) ;
memset ( tmpkey + key_len , 0 , SSL_MAX_SSL_SESSION_ID_LENGTH - key_len ) ;
key = tmpkey ;
}
/* lock cache */
2017-10-30 18:44:40 -04:00
shctx_lock ( ssl_shctx ) ;
2017-10-30 14:36:36 -04:00
/* lookup for session */
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
sh_ssl_sess = sh_ssl_sess_tree_lookup ( key ) ;
if ( ! sh_ssl_sess ) {
2017-10-30 14:36:36 -04:00
/* no session found: unlock cache and exit */
2017-10-30 18:44:40 -04:00
shctx_unlock ( ssl_shctx ) ;
2017-10-30 14:36:36 -04:00
global . shctx_misses + + ;
return NULL ;
}
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
/* sh_ssl_sess (shared_block->data) is at the end of shared_block */
first = sh_ssl_sess_first_block ( sh_ssl_sess ) ;
shctx_row_data_get ( ssl_shctx , first , data , sizeof ( struct sh_ssl_sess_hdr ) , first - > len - sizeof ( struct sh_ssl_sess_hdr ) ) ;
2017-10-30 14:36:36 -04:00
2017-10-30 18:44:40 -04:00
shctx_unlock ( ssl_shctx ) ;
2017-10-30 14:36:36 -04:00
/* decode ASN1 session */
p = data ;
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
sess = d2i_SSL_SESSION ( NULL , ( const unsigned char * * ) & p , first - > len - sizeof ( struct sh_ssl_sess_hdr ) ) ;
2017-10-30 14:36:36 -04:00
/* Reset session id and session id contenxt */
if ( sess ) {
SSL_SESSION_set1_id ( sess , key , key_len ) ;
SSL_SESSION_set1_id_context ( sess , ( const unsigned char * ) SHCTX_APPNAME , strlen ( SHCTX_APPNAME ) ) ;
}
return sess ;
}
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
2017-10-30 14:36:36 -04:00
/* SSL callback used to signal session is no more used in internal cache */
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
void sh_ssl_sess_remove_cb ( SSL_CTX * ctx , SSL_SESSION * sess )
2017-10-30 14:36:36 -04:00
{
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
struct sh_ssl_sess_hdr * sh_ssl_sess ;
2017-10-30 14:36:36 -04:00
unsigned char tmpkey [ SSL_MAX_SSL_SESSION_ID_LENGTH ] ;
unsigned int sid_length ;
const unsigned char * sid_data ;
( void ) ctx ;
sid_data = SSL_SESSION_get_id ( sess , & sid_length ) ;
/* tree key is zeros padded sessionid */
if ( sid_length < SSL_MAX_SSL_SESSION_ID_LENGTH ) {
memcpy ( tmpkey , sid_data , sid_length ) ;
memset ( tmpkey + sid_length , 0 , SSL_MAX_SSL_SESSION_ID_LENGTH - sid_length ) ;
sid_data = tmpkey ;
}
2017-10-30 18:44:40 -04:00
shctx_lock ( ssl_shctx ) ;
2017-10-30 14:36:36 -04:00
/* lookup for session */
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
sh_ssl_sess = sh_ssl_sess_tree_lookup ( sid_data ) ;
if ( sh_ssl_sess ) {
2017-10-30 14:36:36 -04:00
/* free session */
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
sh_ssl_sess_tree_delete ( sh_ssl_sess ) ;
2017-10-30 14:36:36 -04:00
}
/* unlock cache */
2017-10-30 18:44:40 -04:00
shctx_unlock ( ssl_shctx ) ;
2017-10-30 14:36:36 -04:00
}
/* Set session cache mode to server and disable openssl internal cache.
* Set shared cache callbacks on an ssl context .
* Shared context MUST be firstly initialized */
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
void ssl_set_shctx ( SSL_CTX * ctx )
2017-10-30 14:36:36 -04:00
{
SSL_CTX_set_session_id_context ( ctx , ( const unsigned char * ) SHCTX_APPNAME , strlen ( SHCTX_APPNAME ) ) ;
if ( ! ssl_shctx ) {
SSL_CTX_set_session_cache_mode ( ctx , SSL_SESS_CACHE_OFF ) ;
return ;
}
SSL_CTX_set_session_cache_mode ( ctx , SSL_SESS_CACHE_SERVER |
SSL_SESS_CACHE_NO_INTERNAL |
SSL_SESS_CACHE_NO_AUTO_CLEAR ) ;
/* Set callbacks */
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
SSL_CTX_sess_set_new_cb ( ctx , sh_ssl_sess_new_cb ) ;
SSL_CTX_sess_set_get_cb ( ctx , sh_ssl_sess_get_cb ) ;
SSL_CTX_sess_set_remove_cb ( ctx , sh_ssl_sess_remove_cb ) ;
2017-10-30 14:36:36 -04:00
}
2017-03-03 06:21:32 -05:00
int ssl_sock_prepare_ctx ( struct bind_conf * bind_conf , struct ssl_bind_conf * ssl_conf , SSL_CTX * ctx )
{
struct proxy * curproxy = bind_conf - > frontend ;
int cfgerr = 0 ;
int verify = SSL_VERIFY_NONE ;
2018-01-04 12:55:19 -05:00
struct ssl_bind_conf __maybe_unused * ssl_conf_cur ;
2016-12-29 12:26:15 -05:00
const char * conf_ciphers ;
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
const char * conf_ciphersuites ;
# endif
2017-01-09 10:15:54 -05:00
const char * conf_curves = NULL ;
2012-09-07 11:30:07 -04:00
2017-05-18 06:46:50 -04:00
if ( ssl_conf ) {
struct tls_version_filter * conf_ssl_methods = & ssl_conf - > ssl_methods ;
int i , min , max ;
int flags = MC_SSL_O_ALL ;
/* Real min and max should be determinate with configuration and openssl's capabilities */
2017-08-09 12:26:20 -04:00
min = conf_ssl_methods - > min ? conf_ssl_methods - > min : bind_conf - > ssl_conf . ssl_methods . min ;
max = conf_ssl_methods - > max ? conf_ssl_methods - > max : bind_conf - > ssl_conf . ssl_methods . max ;
2017-05-18 06:46:50 -04:00
if ( min )
flags | = ( methodVersions [ min ] . flag - 1 ) ;
if ( max )
flags | = ~ ( ( methodVersions [ max ] . flag < < 1 ) - 1 ) ;
min = max = CONF_TLSV_NONE ;
for ( i = CONF_TLSV_MIN ; i < = CONF_TLSV_MAX ; i + + )
if ( methodVersions [ i ] . option & & ! ( flags & methodVersions [ i ] . flag ) ) {
if ( min )
max = i ;
else
min = max = i ;
}
/* save real min/max */
conf_ssl_methods - > min = min ;
conf_ssl_methods - > max = max ;
if ( ! min ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': all SSL/TLS versions are disabled for bind '%s' at [%s:%d]. \n " ,
bind_conf - > frontend - > id , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2017-05-18 06:46:50 -04:00
cfgerr + = 1 ;
}
}
2016-12-29 12:26:15 -05:00
switch ( ( ssl_conf & & ssl_conf - > verify ) ? ssl_conf - > verify : bind_conf - > ssl_conf . verify ) {
2014-01-29 06:24:34 -05:00
case SSL_SOCK_VERIFY_NONE :
verify = SSL_VERIFY_NONE ;
break ;
case SSL_SOCK_VERIFY_OPTIONAL :
verify = SSL_VERIFY_PEER ;
break ;
case SSL_SOCK_VERIFY_REQUIRED :
verify = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT ;
break ;
}
SSL_CTX_set_verify ( ctx , verify , ssl_sock_bind_verifycbk ) ;
if ( verify & SSL_VERIFY_PEER ) {
2016-12-29 12:26:15 -05:00
char * ca_file = ( ssl_conf & & ssl_conf - > ca_file ) ? ssl_conf - > ca_file : bind_conf - > ssl_conf . ca_file ;
char * crl_file = ( ssl_conf & & ssl_conf - > crl_file ) ? ssl_conf - > crl_file : bind_conf - > ssl_conf . crl_file ;
if ( ca_file ) {
2012-09-20 12:23:56 -04:00
/* load CAfile to verify */
2016-12-29 12:26:15 -05:00
if ( ! SSL_CTX_load_verify_locations ( ctx , ca_file , NULL ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': unable to load CA file '%s' for bind '%s' at [%s:%d]. \n " ,
curproxy - > id , ca_file , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2012-09-20 12:23:56 -04:00
cfgerr + + ;
}
2017-07-28 09:01:05 -04:00
if ( ! ( ( ssl_conf & & ssl_conf - > no_ca_names ) | | bind_conf - > ssl_conf . no_ca_names ) ) {
/* set CA names for client cert request, function returns void */
SSL_CTX_set_client_CA_list ( ctx , SSL_load_client_CA_file ( ca_file ) ) ;
}
2012-09-20 12:23:56 -04:00
}
2014-01-29 06:24:34 -05:00
else {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': verify is enabled but no CA file specified for bind '%s' at [%s:%d]. \n " ,
curproxy - > id , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2014-01-29 06:24:34 -05:00
cfgerr + + ;
}
2012-10-02 13:25:50 -04:00
# ifdef X509_V_FLAG_CRL_CHECK
2016-12-29 12:26:15 -05:00
if ( crl_file ) {
2012-09-20 12:23:56 -04:00
X509_STORE * store = SSL_CTX_get_cert_store ( ctx ) ;
2016-12-29 12:26:15 -05:00
if ( ! store | | ! X509_STORE_load_locations ( store , crl_file , NULL ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': unable to configure CRL file '%s' for bind '%s' at [%s:%d]. \n " ,
curproxy - > id , crl_file , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2012-09-20 12:23:56 -04:00
cfgerr + + ;
}
2012-10-02 09:20:55 -04:00
else {
X509_STORE_set_flags ( store , X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ) ;
}
2012-09-20 12:23:56 -04:00
}
2012-10-02 13:25:50 -04:00
# endif
2012-12-14 05:21:13 -05:00
ERR_clear_error ( ) ;
2012-09-20 12:23:56 -04:00
}
2015-02-27 13:56:49 -05:00
# if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
2015-05-09 02:46:00 -04:00
if ( bind_conf - > keys_ref ) {
2015-02-27 13:56:49 -05:00
if ( ! SSL_CTX_set_tlsext_ticket_key_cb ( ctx , ssl_tlsext_ticket_key_cb ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': unable to set callback for TLS ticket validation for bind '%s' at [%s:%d]. \n " ,
curproxy - > id , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2015-02-27 13:56:49 -05:00
cfgerr + + ;
}
}
# endif
MEDIUM: shctx: separate ssl and shctx
This patch reorganize the shctx API in a generic storage API, separating
the shared SSL session handling from its core.
The shctx API only handles the generic data part, it does not know what
kind of data you use with it.
A shared_context is a storage structure allocated in a shared memory,
allowing its usage in a multithread or a multiprocess context.
The structure use 2 linked list, one containing the available blocks,
and another for the hot locked blocks. At initialization the available
list is filled with <maxblocks> blocks of size <blocksize>. An <extra>
space is initialized outside the list in case you need some specific
storage.
+-----------------------+--------+--------+--------+--------+----
| struct shared_context | extra | block1 | block2 | block3 | ...
+-----------------------+--------+--------+--------+--------+----
<-------- maxblocks --------->
* blocksize
The API allows to store content on several linked blocks. For example,
if you allocated blocks of 16 bytes, and you want to store an object of
60 bytes, the object will be allocated in a row of 4 blocks.
The API was made for LRU usage, each time you get an object, it pushes
the object at the end of the list. When it needs more space, it discards
The functions name have been renamed in a more logical way, the part
regarding shctx have been prefixed by shctx_ and the functions for the
shared ssl session cache have been prefixed by sh_ssl_sess_.
2017-10-30 15:08:51 -04:00
ssl_set_shctx ( ctx ) ;
2016-12-29 12:26:15 -05:00
conf_ciphers = ( ssl_conf & & ssl_conf - > ciphers ) ? ssl_conf - > ciphers : bind_conf - > ssl_conf . ciphers ;
if ( conf_ciphers & &
! SSL_CTX_set_cipher_list ( ctx , conf_ciphers ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': unable to set SSL cipher list to '%s' for bind '%s' at [%s:%d]. \n " ,
curproxy - > id , conf_ciphers , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2012-09-07 11:30:07 -04:00
cfgerr + + ;
}
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
conf_ciphersuites = ( ssl_conf & & ssl_conf - > ciphersuites ) ? ssl_conf - > ciphersuites : bind_conf - > ssl_conf . ciphersuites ;
if ( conf_ciphersuites & &
! SSL_CTX_set_ciphersuites ( ctx , conf_ciphersuites ) ) {
ha_alert ( " Proxy '%s': unable to set TLS 1.3 cipher suites to '%s' for bind '%s' at [%s:%d]. \n " ,
curproxy - > id , conf_ciphersuites , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
cfgerr + + ;
}
# endif
2017-03-03 11:04:14 -05:00
# ifndef OPENSSL_NO_DH
2015-05-29 09:53:22 -04:00
/* If tune.ssl.default-dh-param has not been set,
neither has ssl - default - dh - file and no static DH
params were in the certificate file . */
2016-12-22 17:12:01 -05:00
if ( global_ssl . default_dh_param = = 0 & &
2015-05-29 09:53:22 -04:00
global_dh = = NULL & &
2015-05-28 10:23:00 -04:00
( ssl_dh_ptr_index = = - 1 | |
SSL_CTX_get_ex_data ( ctx , ssl_dh_ptr_index ) = = NULL ) ) {
2017-03-03 11:04:14 -05:00
STACK_OF ( SSL_CIPHER ) * ciphers = NULL ;
const SSL_CIPHER * cipher = NULL ;
char cipher_description [ 128 ] ;
/* The description of ciphers using an Ephemeral Diffie Hellman key exchange
contains " Kx=DH " or " Kx=DH( " . Beware of " Kx=DH/ " ,
which is not ephemeral DH . */
const char dhe_description [ ] = " Kx=DH " ;
const char dhe_export_description [ ] = " Kx=DH( " ;
int idx = 0 ;
int dhe_found = 0 ;
SSL * ssl = NULL ;
2014-08-17 18:56:33 -04:00
2014-10-10 11:04:26 -04:00
ssl = SSL_new ( ctx ) ;
if ( ssl ) {
ciphers = SSL_get_ciphers ( ssl ) ;
if ( ciphers ) {
for ( idx = 0 ; idx < sk_SSL_CIPHER_num ( ciphers ) ; idx + + ) {
cipher = sk_SSL_CIPHER_value ( ciphers , idx ) ;
if ( SSL_CIPHER_description ( cipher , cipher_description , sizeof ( cipher_description ) ) = = cipher_description ) {
if ( strstr ( cipher_description , dhe_description ) ! = NULL | |
strstr ( cipher_description , dhe_export_description ) ! = NULL ) {
dhe_found = 1 ;
break ;
}
2014-06-12 12:20:11 -04:00
}
2014-06-12 08:58:40 -04:00
}
}
2014-10-10 11:04:26 -04:00
SSL_free ( ssl ) ;
ssl = NULL ;
2014-08-17 18:56:33 -04:00
}
2014-06-12 08:58:40 -04:00
2014-08-17 18:56:33 -04:00
if ( dhe_found ) {
2017-11-24 10:50:31 -05:00
ha_warning ( " Setting tune.ssl.default-dh-param to 1024 by default, if your workload permits it you should set it to at least 2048. Please set a value >= 1024 to make this warning disappear. \n " ) ;
2014-06-12 08:58:40 -04:00
}
2016-12-22 17:12:01 -05:00
global_ssl . default_dh_param = 1024 ;
2014-06-12 08:58:40 -04:00
}
2016-12-22 17:12:01 -05:00
if ( global_ssl . default_dh_param > = 1024 ) {
2014-07-15 05:36:40 -04:00
if ( local_dh_1024 = = NULL ) {
local_dh_1024 = ssl_get_dh_1024 ( ) ;
}
2016-12-22 17:12:01 -05:00
if ( global_ssl . default_dh_param > = 2048 ) {
2014-07-15 05:36:40 -04:00
if ( local_dh_2048 = = NULL ) {
local_dh_2048 = ssl_get_dh_2048 ( ) ;
}
2016-12-22 17:12:01 -05:00
if ( global_ssl . default_dh_param > = 4096 ) {
2014-07-15 05:36:40 -04:00
if ( local_dh_4096 = = NULL ) {
local_dh_4096 = ssl_get_dh_4096 ( ) ;
}
}
}
}
# endif /* OPENSSL_NO_DH */
2012-09-07 11:30:07 -04:00
SSL_CTX_set_info_callback ( ctx , ssl_sock_infocbk ) ;
2014-05-08 16:45:11 -04:00
# if OPENSSL_VERSION_NUMBER >= 0x00907000L
2014-04-25 13:05:36 -04:00
SSL_CTX_set_msg_callback ( ctx , ssl_sock_msgcbk ) ;
2014-05-08 16:45:11 -04:00
# endif
2014-04-25 13:05:36 -04:00
2018-02-15 07:34:58 -05:00
# if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2016-12-29 12:26:15 -05:00
ssl_conf_cur = NULL ;
if ( ssl_conf & & ssl_conf - > npn_str )
ssl_conf_cur = ssl_conf ;
else if ( bind_conf - > ssl_conf . npn_str )
ssl_conf_cur = & bind_conf - > ssl_conf ;
if ( ssl_conf_cur )
SSL_CTX_set_next_protos_advertised_cb ( ctx , ssl_sock_advertise_npn_protos , ssl_conf_cur ) ;
2012-10-18 12:57:14 -04:00
# endif
2014-02-13 06:29:42 -05:00
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2016-12-29 12:26:15 -05:00
ssl_conf_cur = NULL ;
if ( ssl_conf & & ssl_conf - > alpn_str )
ssl_conf_cur = ssl_conf ;
else if ( bind_conf - > ssl_conf . alpn_str )
ssl_conf_cur = & bind_conf - > ssl_conf ;
if ( ssl_conf_cur )
SSL_CTX_set_alpn_select_cb ( ctx , ssl_sock_advertise_alpn_protos , ssl_conf_cur ) ;
2013-04-01 20:30:41 -04:00
# endif
2017-01-09 10:15:54 -05:00
# if OPENSSL_VERSION_NUMBER >= 0x1000200fL
conf_curves = ( ssl_conf & & ssl_conf - > curves ) ? ssl_conf - > curves : bind_conf - > ssl_conf . curves ;
if ( conf_curves ) {
if ( ! SSL_CTX_set1_curves_list ( ctx , conf_curves ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': unable to set SSL curves list to '%s' for bind '%s' at [%s:%d]. \n " ,
curproxy - > id , conf_curves , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2017-01-09 10:15:54 -05:00
cfgerr + + ;
}
2017-03-20 06:11:49 -04:00
# if defined(SSL_CTX_set_ecdh_auto)
( void ) SSL_CTX_set_ecdh_auto ( ctx , 1 ) ;
# endif
2017-01-09 10:15:54 -05:00
}
# endif
2012-09-20 11:10:03 -04:00
# if defined(SSL_CTX_set_tmp_ecdh) && !defined(OPENSSL_NO_ECDH)
2017-01-09 10:15:54 -05:00
if ( ! conf_curves ) {
2012-09-20 11:10:03 -04:00
int i ;
EC_KEY * ecdh ;
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L)
2016-12-29 12:26:15 -05:00
const char * ecdhe = ( ssl_conf & & ssl_conf - > ecdhe ) ? ssl_conf - > ecdhe :
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
( bind_conf - > ssl_conf . ecdhe ? bind_conf - > ssl_conf . ecdhe :
NULL ) ;
if ( ecdhe = = NULL ) {
SSL_CTX_set_dh_auto ( ctx , 1 ) ;
return cfgerr ;
}
# else
const char * ecdhe = ( ssl_conf & & ssl_conf - > ecdhe ) ? ssl_conf - > ecdhe :
( bind_conf - > ssl_conf . ecdhe ? bind_conf - > ssl_conf . ecdhe :
ECDHE_DEFAULT_CURVE ) ;
# endif
2012-09-20 11:10:03 -04:00
2016-12-29 12:26:15 -05:00
i = OBJ_sn2nid ( ecdhe ) ;
2012-09-20 11:10:03 -04:00
if ( ! i | | ( ( ecdh = EC_KEY_new_by_curve_name ( i ) ) = = NULL ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': unable to set elliptic named curve to '%s' for bind '%s' at [%s:%d]. \n " ,
curproxy - > id , ecdhe , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2012-09-20 11:10:03 -04:00
cfgerr + + ;
}
else {
SSL_CTX_set_tmp_ecdh ( ctx , ecdh ) ;
EC_KEY_free ( ecdh ) ;
}
}
# endif
2012-09-07 11:30:07 -04:00
return cfgerr ;
}
2013-06-27 03:05:25 -04:00
static int ssl_sock_srv_hostcheck ( const char * pattern , const char * hostname )
{
const char * pattern_wildcard , * pattern_left_label_end , * hostname_left_label_end ;
size_t prefixlen , suffixlen ;
/* Trivial case */
if ( strcmp ( pattern , hostname ) = = 0 )
return 1 ;
/* The rest of this logic is based on RFC 6125, section 6.4.3
* ( http : //tools.ietf.org/html/rfc6125#section-6.4.3) */
2013-10-08 05:27:28 -04:00
pattern_wildcard = NULL ;
pattern_left_label_end = pattern ;
while ( * pattern_left_label_end ! = ' . ' ) {
switch ( * pattern_left_label_end ) {
case 0 :
/* End of label not found */
return 0 ;
case ' * ' :
/* If there is more than one wildcards */
if ( pattern_wildcard )
return 0 ;
pattern_wildcard = pattern_left_label_end ;
break ;
}
pattern_left_label_end + + ;
}
/* If it's not trivial and there is no wildcard, it can't
* match */
if ( ! pattern_wildcard )
2013-06-27 03:05:25 -04:00
return 0 ;
/* Make sure all labels match except the leftmost */
hostname_left_label_end = strchr ( hostname , ' . ' ) ;
if ( ! hostname_left_label_end
| | strcmp ( pattern_left_label_end , hostname_left_label_end ) ! = 0 )
return 0 ;
/* Make sure the leftmost label of the hostname is long enough
* that the wildcard can match */
2013-10-08 05:39:35 -04:00
if ( hostname_left_label_end - hostname < ( pattern_left_label_end - pattern ) - 1 )
2013-06-27 03:05:25 -04:00
return 0 ;
/* Finally compare the string on either side of the
* wildcard */
prefixlen = pattern_wildcard - pattern ;
suffixlen = pattern_left_label_end - ( pattern_wildcard + 1 ) ;
2013-10-08 05:27:28 -04:00
if ( ( prefixlen & & ( memcmp ( pattern , hostname , prefixlen ) ! = 0 ) )
| | ( suffixlen & & ( memcmp ( pattern_wildcard + 1 , hostname_left_label_end - suffixlen , suffixlen ) ! = 0 ) ) )
2013-06-27 03:05:25 -04:00
return 0 ;
return 1 ;
}
static int ssl_sock_srv_verifycbk ( int ok , X509_STORE_CTX * ctx )
{
SSL * ssl ;
struct connection * conn ;
2017-07-05 12:23:03 -04:00
const char * servername ;
2017-07-26 14:09:56 -04:00
const char * sni ;
2013-06-27 03:05:25 -04:00
int depth ;
X509 * cert ;
STACK_OF ( GENERAL_NAME ) * alt_names ;
int i ;
X509_NAME * cert_subject ;
char * str ;
if ( ok = = 0 )
return ok ;
ssl = X509_STORE_CTX_get_ex_data ( ctx , SSL_get_ex_data_X509_STORE_CTX_idx ( ) ) ;
BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
We never saw unexplicated crash with SSL, so I suppose that we are
luck, or the slot 0 is always reserved. Anyway the usage of the macro
SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
the deprecated functions SSL_get_app_data() and SSL_set_app_data()
by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
it reserves the slot in the SSL memory space.
For information, this is the two declaration which seems wrong or
incomplete in the OpenSSL ssl.h file. We can see the usage of the
slot 0 whoch is hardcoded, but never reserved.
#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
This patch must be backported at least in 1.8, maybe in other versions.
2018-06-17 15:37:05 -04:00
conn = SSL_get_ex_data ( ssl , ssl_app_data_index ) ;
2013-06-27 03:05:25 -04:00
2017-07-28 05:38:41 -04:00
/* We're checking if the provided hostnames match the desired one. The
* desired hostname comes from the SNI we presented if any , or if not
* provided then it may have been explicitly stated using a " verifyhost "
* directive . If neither is set , we don ' t care about the name so the
* verification is OK .
2017-07-05 12:23:03 -04:00
*/
2017-07-28 05:38:41 -04:00
servername = SSL_get_servername ( conn - > xprt_ctx , TLSEXT_NAMETYPE_host_name ) ;
2017-07-26 14:09:56 -04:00
sni = servername ;
2017-07-05 12:23:03 -04:00
if ( ! servername ) {
2018-09-20 04:57:52 -04:00
servername = __objt_server ( conn - > target ) - > ssl_ctx . verify_host ;
2017-07-05 12:23:03 -04:00
if ( ! servername )
return ok ;
}
2013-06-27 03:05:25 -04:00
/* We only need to verify the CN on the actual server cert,
* not the indirect CAs */
depth = X509_STORE_CTX_get_error_depth ( ctx ) ;
if ( depth ! = 0 )
return ok ;
/* At this point, the cert is *not* OK unless we can find a
* hostname match */
ok = 0 ;
cert = X509_STORE_CTX_get_current_cert ( ctx ) ;
/* It seems like this might happen if verify peer isn't set */
if ( ! cert )
return ok ;
alt_names = X509_get_ext_d2i ( cert , NID_subject_alt_name , NULL , NULL ) ;
if ( alt_names ) {
for ( i = 0 ; ! ok & & i < sk_GENERAL_NAME_num ( alt_names ) ; i + + ) {
GENERAL_NAME * name = sk_GENERAL_NAME_value ( alt_names , i ) ;
if ( name - > type = = GEN_DNS ) {
2013-09-17 09:47:48 -04:00
# if OPENSSL_VERSION_NUMBER < 0x00907000L
if ( ASN1_STRING_to_UTF8 ( ( unsigned char * * ) & str , name - > d . ia5 ) > = 0 ) {
# else
2013-06-27 03:05:25 -04:00
if ( ASN1_STRING_to_UTF8 ( ( unsigned char * * ) & str , name - > d . dNSName ) > = 0 ) {
2013-09-17 09:47:48 -04:00
# endif
2013-06-27 03:05:25 -04:00
ok = ssl_sock_srv_hostcheck ( str , servername ) ;
OPENSSL_free ( str ) ;
}
}
}
2013-09-17 09:19:54 -04:00
sk_GENERAL_NAME_pop_free ( alt_names , GENERAL_NAME_free ) ;
2013-06-27 03:05:25 -04:00
}
cert_subject = X509_get_subject_name ( cert ) ;
i = - 1 ;
while ( ! ok & & ( i = X509_NAME_get_index_by_NID ( cert_subject , NID_commonName , i ) ) ! = - 1 ) {
X509_NAME_ENTRY * entry = X509_NAME_get_entry ( cert_subject , i ) ;
2016-08-29 07:26:37 -04:00
ASN1_STRING * value ;
value = X509_NAME_ENTRY_get_data ( entry ) ;
if ( ASN1_STRING_to_UTF8 ( ( unsigned char * * ) & str , value ) > = 0 ) {
2013-06-27 03:05:25 -04:00
ok = ssl_sock_srv_hostcheck ( str , servername ) ;
OPENSSL_free ( str ) ;
}
}
2017-07-26 14:09:56 -04:00
/* report the mismatch and indicate if SNI was used or not */
if ( ! ok & & ! conn - > err_code )
conn - > err_code = sni ? CO_ER_SSL_MISMATCH_SNI : CO_ER_SSL_MISMATCH ;
2013-06-27 03:05:25 -04:00
return ok ;
}
2012-10-11 08:00:19 -04:00
/* prepare ssl context from servers options. Returns an error count */
2016-12-22 11:08:28 -05:00
int ssl_sock_prepare_srv_ctx ( struct server * srv )
2012-10-11 08:00:19 -04:00
{
2016-12-22 11:08:28 -05:00
struct proxy * curproxy = srv - > proxy ;
2012-10-11 08:00:19 -04:00
int cfgerr = 0 ;
2014-05-19 04:29:58 -04:00
long options =
2012-10-11 08:00:19 -04:00
SSL_OP_ALL | /* all known workarounds for bugs */
SSL_OP_NO_SSLv2 |
SSL_OP_NO_COMPRESSION ;
2014-05-19 04:29:58 -04:00
long mode =
2012-10-11 08:00:19 -04:00
SSL_MODE_ENABLE_PARTIAL_WRITE |
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
2014-11-13 08:06:52 -05:00
SSL_MODE_RELEASE_BUFFERS |
SSL_MODE_SMALL_BUFFERS ;
2014-01-29 06:24:34 -05:00
int verify = SSL_VERIFY_NONE ;
2017-03-03 06:21:32 -05:00
SSL_CTX * ctx = NULL ;
2017-03-30 13:19:37 -04:00
struct tls_version_filter * conf_ssl_methods = & srv - > ssl_ctx . methods ;
2017-03-30 13:25:07 -04:00
int i , min , max , hole ;
2017-05-05 12:06:12 -04:00
int flags = MC_SSL_O_ALL ;
2012-10-11 08:00:19 -04:00
2013-01-24 08:15:43 -05:00
/* Make sure openssl opens /dev/urandom before the chroot */
if ( ! ssl_initialize_random ( ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " OpenSSL random data generator initialization failed. \n " ) ;
2013-01-24 08:15:43 -05:00
cfgerr + + ;
}
2015-01-15 15:32:40 -05:00
/* Automatic memory computations need to know we use SSL there */
global . ssl_used_backend = 1 ;
/* Initiate SSL context for current server */
2017-06-15 10:37:39 -04:00
if ( ! srv - > ssl_ctx . reused_sess ) {
2017-11-16 11:42:52 -05:00
if ( ( srv - > ssl_ctx . reused_sess = calloc ( 1 , global . nbthread * sizeof ( * srv - > ssl_ctx . reused_sess ) ) ) = = NULL ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s', server '%s' [%s:%d] out of memory. \n " ,
curproxy - > id , srv - > id ,
srv - > conf . file , srv - > conf . line ) ;
2017-06-15 10:37:39 -04:00
cfgerr + + ;
return cfgerr ;
}
}
2012-10-11 08:00:19 -04:00
if ( srv - > use_ssl )
srv - > xprt = & ssl_sock ;
if ( srv - > check . use_ssl )
2014-11-15 16:41:27 -05:00
srv - > check . xprt = & ssl_sock ;
2012-10-11 08:00:19 -04:00
2017-03-30 13:19:37 -04:00
ctx = SSL_CTX_new ( SSLv23_client_method ( ) ) ;
2017-03-03 06:21:32 -05:00
if ( ! ctx ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " config : %s '%s', server '%s': unable to allocate ssl context. \n " ,
proxy_type_str ( curproxy ) , curproxy - > id ,
srv - > id ) ;
2012-10-11 08:00:19 -04:00
cfgerr + + ;
return cfgerr ;
}
2017-03-30 13:19:37 -04:00
2017-05-05 12:06:12 -04:00
if ( conf_ssl_methods - > flags & & ( conf_ssl_methods - > min | | conf_ssl_methods - > max ) )
2017-11-24 10:50:31 -05:00
ha_warning ( " config : %s '%s': no-sslv3/no-tlsv1x are ignored for server '%s'. "
" Use only 'ssl-min-ver' and 'ssl-max-ver' to fix. \n " ,
proxy_type_str ( curproxy ) , curproxy - > id , srv - > id ) ;
2017-05-05 12:06:12 -04:00
else
flags = conf_ssl_methods - > flags ;
2017-03-30 13:25:07 -04:00
/* Real min and max should be determinate with configuration and openssl's capabilities */
if ( conf_ssl_methods - > min )
2017-05-05 12:06:12 -04:00
flags | = ( methodVersions [ conf_ssl_methods - > min ] . flag - 1 ) ;
2017-03-30 13:25:07 -04:00
if ( conf_ssl_methods - > max )
2017-05-05 12:06:12 -04:00
flags | = ~ ( ( methodVersions [ conf_ssl_methods - > max ] . flag < < 1 ) - 1 ) ;
2017-03-30 13:25:07 -04:00
2017-05-18 06:33:19 -04:00
/* find min, max and holes */
2017-03-30 13:25:07 -04:00
min = max = CONF_TLSV_NONE ;
hole = 0 ;
2017-03-30 13:19:37 -04:00
for ( i = CONF_TLSV_MIN ; i < = CONF_TLSV_MAX ; i + + )
2017-03-30 13:25:07 -04:00
/* version is in openssl && version not disable in configuration */
2017-05-05 12:06:12 -04:00
if ( methodVersions [ i ] . option & & ! ( flags & methodVersions [ i ] . flag ) ) {
2017-03-30 13:25:07 -04:00
if ( min ) {
if ( hole ) {
2017-11-24 10:50:31 -05:00
ha_warning ( " config : %s '%s': SSL/TLS versions range not contiguous for server '%s'. "
" Hole find for %s. Use only 'ssl-min-ver' and 'ssl-max-ver' to fix. \n " ,
proxy_type_str ( curproxy ) , curproxy - > id , srv - > id ,
methodVersions [ hole ] . name ) ;
2017-03-30 13:25:07 -04:00
hole = 0 ;
}
max = i ;
}
else {
min = max = i ;
}
}
else {
if ( min )
hole = i ;
}
2017-05-05 12:06:12 -04:00
if ( ! min ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " config : %s '%s': all SSL/TLS versions are disabled for server '%s'. \n " ,
proxy_type_str ( curproxy ) , curproxy - > id , srv - > id ) ;
2017-05-05 12:06:12 -04:00
cfgerr + = 1 ;
}
2017-03-30 13:19:37 -04:00
2017-10-02 11:12:06 -04:00
# if (OPENSSL_VERSION_NUMBER < 0x1010000fL)
2017-03-30 13:19:37 -04:00
/* Keep force-xxx implementation as it is in older haproxy. It's a
2018-11-15 12:07:59 -05:00
precautionary measure to avoid any surprise with older openssl version . */
2017-03-30 13:19:37 -04:00
if ( min = = max )
2017-05-18 06:33:19 -04:00
methodVersions [ min ] . ctx_set_version ( ctx , SET_CLIENT ) ;
2017-05-05 12:06:12 -04:00
else
for ( i = CONF_TLSV_MIN ; i < = CONF_TLSV_MAX ; i + + )
if ( flags & methodVersions [ i ] . flag )
options | = methodVersions [ i ] . option ;
2017-03-30 13:19:37 -04:00
# else /* openssl >= 1.1.0 */
2017-03-30 13:25:07 -04:00
/* set the max_version is required to cap TLS version or activate new TLS (v1.3) */
2017-05-18 06:33:19 -04:00
methodVersions [ min ] . ctx_set_version ( ctx , SET_MIN ) ;
methodVersions [ max ] . ctx_set_version ( ctx , SET_MAX ) ;
2017-03-30 13:19:37 -04:00
# endif
if ( srv - > ssl_ctx . options & SRV_SSL_O_NO_TLS_TICKETS )
options | = SSL_OP_NO_TICKET ;
2017-03-03 06:21:32 -05:00
SSL_CTX_set_options ( ctx , options ) ;
2017-01-13 20:42:15 -05:00
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-01-13 20:42:15 -05:00
if ( global_ssl . async )
mode | = SSL_MODE_ASYNC ;
# endif
2017-03-03 06:21:32 -05:00
SSL_CTX_set_mode ( ctx , mode ) ;
srv - > ssl_ctx . ctx = ctx ;
2012-10-26 06:58:00 -04:00
if ( srv - > ssl_ctx . client_crt ) {
if ( SSL_CTX_use_PrivateKey_file ( srv - > ssl_ctx . ctx , srv - > ssl_ctx . client_crt , SSL_FILETYPE_PEM ) < = 0 ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " config : %s '%s', server '%s': unable to load SSL private key from PEM file '%s'. \n " ,
proxy_type_str ( curproxy ) , curproxy - > id ,
srv - > id , srv - > ssl_ctx . client_crt ) ;
2012-10-26 06:58:00 -04:00
cfgerr + + ;
}
else if ( SSL_CTX_use_certificate_chain_file ( srv - > ssl_ctx . ctx , srv - > ssl_ctx . client_crt ) < = 0 ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " config : %s '%s', server '%s': unable to load ssl certificate from PEM file '%s'. \n " ,
proxy_type_str ( curproxy ) , curproxy - > id ,
srv - > id , srv - > ssl_ctx . client_crt ) ;
2012-10-26 06:58:00 -04:00
cfgerr + + ;
}
else if ( SSL_CTX_check_private_key ( srv - > ssl_ctx . ctx ) < = 0 ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " config : %s '%s', server '%s': inconsistencies between private key and certificate loaded from PEM file '%s'. \n " ,
proxy_type_str ( curproxy ) , curproxy - > id ,
srv - > id , srv - > ssl_ctx . client_crt ) ;
2012-10-26 06:58:00 -04:00
cfgerr + + ;
}
}
2012-10-11 08:00:19 -04:00
2014-01-29 06:24:34 -05:00
if ( global . ssl_server_verify = = SSL_SERVER_VERIFY_REQUIRED )
verify = SSL_VERIFY_PEER ;
switch ( srv - > ssl_ctx . verify ) {
case SSL_SOCK_VERIFY_NONE :
verify = SSL_VERIFY_NONE ;
break ;
case SSL_SOCK_VERIFY_REQUIRED :
verify = SSL_VERIFY_PEER ;
break ;
}
2013-06-27 03:05:25 -04:00
SSL_CTX_set_verify ( srv - > ssl_ctx . ctx ,
2014-01-29 06:24:34 -05:00
verify ,
2017-07-05 12:23:03 -04:00
( srv - > ssl_ctx . verify_host | | ( verify & SSL_VERIFY_PEER ) ) ? ssl_sock_srv_verifycbk : NULL ) ;
2014-01-29 06:24:34 -05:00
if ( verify & SSL_VERIFY_PEER ) {
2012-10-11 10:11:36 -04:00
if ( srv - > ssl_ctx . ca_file ) {
/* load CAfile to verify */
if ( ! SSL_CTX_load_verify_locations ( srv - > ssl_ctx . ctx , srv - > ssl_ctx . ca_file , NULL ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s', server '%s' [%s:%d] unable to load CA file '%s'. \n " ,
curproxy - > id , srv - > id ,
srv - > conf . file , srv - > conf . line , srv - > ssl_ctx . ca_file ) ;
2012-10-11 10:11:36 -04:00
cfgerr + + ;
}
}
2014-01-29 06:24:34 -05:00
else {
if ( global . ssl_server_verify = = SSL_SERVER_VERIFY_REQUIRED )
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s', server '%s' [%s:%d] verify is enabled by default but no CA file specified. If you're running on a LAN where you're certain to trust the server's certificate, please set an explicit 'verify none' statement on the 'server' line, or use 'ssl-server-verify none' in the global section to disable server-side verifications by default. \n " ,
curproxy - > id , srv - > id ,
srv - > conf . file , srv - > conf . line ) ;
2014-01-29 06:24:34 -05:00
else
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s', server '%s' [%s:%d] verify is enabled but no CA file specified. \n " ,
curproxy - > id , srv - > id ,
srv - > conf . file , srv - > conf . line ) ;
2014-01-29 06:24:34 -05:00
cfgerr + + ;
}
2012-10-11 10:11:36 -04:00
# ifdef X509_V_FLAG_CRL_CHECK
if ( srv - > ssl_ctx . crl_file ) {
X509_STORE * store = SSL_CTX_get_cert_store ( srv - > ssl_ctx . ctx ) ;
if ( ! store | | ! X509_STORE_load_locations ( store , srv - > ssl_ctx . crl_file , NULL ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s', server '%s' [%s:%d] unable to configure CRL file '%s'. \n " ,
curproxy - > id , srv - > id ,
srv - > conf . file , srv - > conf . line , srv - > ssl_ctx . crl_file ) ;
2012-10-11 10:11:36 -04:00
cfgerr + + ;
}
else {
X509_STORE_set_flags ( store , X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ) ;
}
}
# endif
}
2017-11-03 08:43:35 -04:00
SSL_CTX_set_session_cache_mode ( srv - > ssl_ctx . ctx , SSL_SESS_CACHE_CLIENT |
SSL_SESS_CACHE_NO_INTERNAL_STORE ) ;
SSL_CTX_sess_set_new_cb ( srv - > ssl_ctx . ctx , ssl_sess_new_srv_cb ) ;
2012-10-11 08:00:19 -04:00
if ( srv - > ssl_ctx . ciphers & &
! SSL_CTX_set_cipher_list ( srv - > ssl_ctx . ctx , srv - > ssl_ctx . ciphers ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s', server '%s' [%s:%d] : unable to set SSL cipher list to '%s'. \n " ,
curproxy - > id , srv - > id ,
srv - > conf . file , srv - > conf . line , srv - > ssl_ctx . ciphers ) ;
2012-10-11 08:00:19 -04:00
cfgerr + + ;
}
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
if ( srv - > ssl_ctx . ciphersuites & &
! SSL_CTX_set_cipher_list ( srv - > ssl_ctx . ctx , srv - > ssl_ctx . ciphersuites ) ) {
ha_alert ( " Proxy '%s', server '%s' [%s:%d] : unable to set TLS 1.3 cipher suites to '%s'. \n " ,
curproxy - > id , srv - > id ,
srv - > conf . file , srv - > conf . line , srv - > ssl_ctx . ciphersuites ) ;
cfgerr + + ;
}
# endif
2018-11-20 17:33:50 -05:00
# if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
if ( srv - > ssl_ctx . npn_str )
SSL_CTX_set_next_proto_select_cb ( ctx , ssl_sock_srv_select_protos , srv ) ;
# endif
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
if ( srv - > ssl_ctx . alpn_str )
SSL_CTX_set_alpn_protos ( ctx , ( unsigned char * ) srv - > ssl_ctx . alpn_str , srv - > ssl_ctx . alpn_len ) ;
# endif
2018-09-14 05:14:21 -04:00
2012-10-11 08:00:19 -04:00
return cfgerr ;
}
2012-09-13 11:54:29 -04:00
/* Walks down the two trees in bind_conf and prepares all certs. The pointer may
2012-09-07 11:30:07 -04:00
* be NULL , in which case nothing is done . Returns the number of errors
* encountered .
*/
2016-12-22 11:08:28 -05:00
int ssl_sock_prepare_all_ctx ( struct bind_conf * bind_conf )
2012-09-07 11:30:07 -04:00
{
struct ebmb_node * node ;
struct sni_ctx * sni ;
int err = 0 ;
2015-01-15 15:32:40 -05:00
/* Automatic memory computations need to know we use SSL there */
global . ssl_used_frontend = 1 ;
2017-03-06 09:34:44 -05:00
/* Make sure openssl opens /dev/urandom before the chroot */
if ( ! ssl_initialize_random ( ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " OpenSSL random data generator initialization failed. \n " ) ;
2017-03-06 09:34:44 -05:00
err + + ;
}
/* Create initial_ctx used to start the ssl connection before do switchctx */
if ( ! bind_conf - > initial_ctx ) {
2017-05-05 12:06:12 -04:00
err + = ssl_sock_initial_ctx ( bind_conf ) ;
2017-03-06 09:34:44 -05:00
/* It should not be necessary to call this function, but it's
necessary first to check and move all initialisation related
to initial_ctx in ssl_sock_initial_ctx . */
err + = ssl_sock_prepare_ctx ( bind_conf , NULL , bind_conf - > initial_ctx ) ;
}
2014-10-30 14:25:24 -04:00
if ( bind_conf - > default_ctx )
2016-12-29 12:26:15 -05:00
err + = ssl_sock_prepare_ctx ( bind_conf , bind_conf - > default_ssl_conf , bind_conf - > default_ctx ) ;
2014-10-30 14:25:24 -04:00
2012-09-13 11:54:29 -04:00
node = ebmb_first ( & bind_conf - > sni_ctx ) ;
2012-09-07 11:30:07 -04:00
while ( node ) {
sni = ebmb_entry ( node , struct sni_ctx , name ) ;
2014-10-30 14:25:24 -04:00
if ( ! sni - > order & & sni - > ctx ! = bind_conf - > default_ctx )
/* only initialize the CTX on its first occurrence and
if it is not the default_ctx */
2016-12-29 12:26:15 -05:00
err + = ssl_sock_prepare_ctx ( bind_conf , sni - > conf , sni - > ctx ) ;
2012-09-07 11:30:07 -04:00
node = ebmb_next ( node ) ;
}
2012-09-13 11:54:29 -04:00
node = ebmb_first ( & bind_conf - > sni_w_ctx ) ;
2012-09-07 11:30:07 -04:00
while ( node ) {
sni = ebmb_entry ( node , struct sni_ctx , name ) ;
2014-10-30 14:25:24 -04:00
if ( ! sni - > order & & sni - > ctx ! = bind_conf - > default_ctx )
/* only initialize the CTX on its first occurrence and
if it is not the default_ctx */
2016-12-29 12:26:15 -05:00
err + = ssl_sock_prepare_ctx ( bind_conf , sni - > conf , sni - > ctx ) ;
2012-09-07 11:30:07 -04:00
node = ebmb_next ( node ) ;
}
return err ;
}
2016-12-21 17:38:39 -05:00
/* Prepares all the contexts for a bind_conf and allocates the shared SSL
* context if needed . Returns < 0 on error , 0 on success . The warnings and
* alerts are directly emitted since the rest of the stack does it below .
*/
int ssl_sock_prepare_bind_conf ( struct bind_conf * bind_conf )
{
struct proxy * px = bind_conf - > frontend ;
int alloc_ctx ;
int err ;
if ( ! bind_conf - > is_ssl ) {
if ( bind_conf - > default_ctx ) {
2017-11-24 10:50:31 -05:00
ha_warning ( " Proxy '%s': A certificate was specified but SSL was not enabled on bind '%s' at [%s:%d] (use 'ssl'). \n " ,
px - > id , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2016-12-21 17:38:39 -05:00
}
return 0 ;
}
if ( ! bind_conf - > default_ctx ) {
2017-08-09 05:24:25 -04:00
if ( bind_conf - > strict_sni & & ! bind_conf - > generate_certs ) {
2017-11-24 10:50:31 -05:00
ha_warning ( " Proxy '%s': no SSL certificate specified for bind '%s' at [%s:%d], ssl connections will fail (use 'crt'). \n " ,
px - > id , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2017-08-09 05:24:25 -04:00
}
else {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': no SSL certificate specified for bind '%s' at [%s:%d] (use 'crt'). \n " ,
px - > id , bind_conf - > arg , bind_conf - > file , bind_conf - > line ) ;
2017-08-09 05:24:25 -04:00
return - 1 ;
}
2016-12-21 17:38:39 -05:00
}
2017-12-04 12:46:39 -05:00
if ( ! ssl_shctx & & global . tune . sslcachesize ) {
2017-11-28 05:04:43 -05:00
alloc_ctx = shctx_init ( & ssl_shctx , global . tune . sslcachesize ,
2018-10-22 10:21:39 -04:00
sizeof ( struct sh_ssl_sess_hdr ) + SHSESS_BLOCK_MIN_SIZE , - 1 ,
2017-11-28 05:04:43 -05:00
sizeof ( * sh_ssl_sess_tree ) ,
( ( global . nbthread > 1 ) | | ( ! global_ssl . private_cache & & ( global . nbproc > 1 ) ) ) ? 1 : 0 ) ;
2018-10-25 14:22:46 -04:00
if ( alloc_ctx < = 0 ) {
2017-11-28 05:04:43 -05:00
if ( alloc_ctx = = SHCTX_E_INIT_LOCK )
ha_alert ( " Unable to initialize the lock for the shared SSL session cache. You can retry using the global statement 'tune.ssl.force-private-cache' but it could increase CPU usage due to renegotiations if nbproc > 1. \n " ) ;
else
ha_alert ( " Unable to allocate SSL session cache. \n " ) ;
return - 1 ;
}
/* free block callback */
ssl_shctx - > free_block = sh_ssl_sess_free_blocks ;
/* init the root tree within the extra space */
sh_ssl_sess_tree = ( void * ) ssl_shctx + sizeof ( struct shared_context ) ;
* sh_ssl_sess_tree = EB_ROOT_UNIQUE ;
2016-12-21 17:38:39 -05:00
}
err = 0 ;
/* initialize all certificate contexts */
err + = ssl_sock_prepare_all_ctx ( bind_conf ) ;
/* initialize CA variables if the certificates generation is enabled */
err + = ssl_sock_load_ca ( bind_conf ) ;
return - err ;
}
2015-07-29 07:02:40 -04:00
/* release ssl context allocated for servers. */
void ssl_sock_free_srv_ctx ( struct server * srv )
{
2018-11-20 17:33:50 -05:00
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
if ( srv - > ssl_ctx . alpn_str )
free ( srv - > ssl_ctx . alpn_str ) ;
# endif
2018-11-25 07:21:27 -05:00
# ifdef OPENSSL_NPN_NEGOTIATED
2018-11-20 17:33:50 -05:00
if ( srv - > ssl_ctx . npn_str )
free ( srv - > ssl_ctx . npn_str ) ;
2018-11-26 16:57:17 -05:00
# endif
2015-07-29 07:02:40 -04:00
if ( srv - > ssl_ctx . ctx )
SSL_CTX_free ( srv - > ssl_ctx . ctx ) ;
}
2012-09-13 11:54:29 -04:00
/* Walks down the two trees in bind_conf and frees all the certs. The pointer may
2012-09-07 11:30:07 -04:00
* be NULL , in which case nothing is done . The default_ctx is nullified too .
*/
2012-09-13 11:54:29 -04:00
void ssl_sock_free_all_ctx ( struct bind_conf * bind_conf )
2012-09-07 11:30:07 -04:00
{
struct ebmb_node * node , * back ;
struct sni_ctx * sni ;
2012-09-13 11:54:29 -04:00
node = ebmb_first ( & bind_conf - > sni_ctx ) ;
2012-09-07 11:30:07 -04:00
while ( node ) {
sni = ebmb_entry ( node , struct sni_ctx , name ) ;
back = ebmb_next ( node ) ;
ebmb_delete ( node ) ;
2016-12-29 12:26:15 -05:00
if ( ! sni - > order ) { /* only free the CTX on its first occurrence */
2012-09-07 11:30:07 -04:00
SSL_CTX_free ( sni - > ctx ) ;
2016-12-29 12:26:15 -05:00
ssl_sock_free_ssl_conf ( sni - > conf ) ;
free ( sni - > conf ) ;
sni - > conf = NULL ;
}
2012-09-07 11:30:07 -04:00
free ( sni ) ;
node = back ;
}
2012-09-13 11:54:29 -04:00
node = ebmb_first ( & bind_conf - > sni_w_ctx ) ;
2012-09-07 11:30:07 -04:00
while ( node ) {
sni = ebmb_entry ( node , struct sni_ctx , name ) ;
back = ebmb_next ( node ) ;
ebmb_delete ( node ) ;
2016-12-29 12:26:15 -05:00
if ( ! sni - > order ) { /* only free the CTX on its first occurrence */
2012-09-07 11:30:07 -04:00
SSL_CTX_free ( sni - > ctx ) ;
2016-12-29 12:26:15 -05:00
ssl_sock_free_ssl_conf ( sni - > conf ) ;
free ( sni - > conf ) ;
sni - > conf = NULL ;
}
2012-09-07 11:30:07 -04:00
free ( sni ) ;
node = back ;
}
2017-03-06 09:34:44 -05:00
SSL_CTX_free ( bind_conf - > initial_ctx ) ;
bind_conf - > initial_ctx = NULL ;
2012-09-13 11:54:29 -04:00
bind_conf - > default_ctx = NULL ;
2016-12-29 12:26:15 -05:00
bind_conf - > default_ssl_conf = NULL ;
2012-09-07 11:30:07 -04:00
}
2016-12-22 11:30:54 -05:00
/* Destroys all the contexts for a bind_conf. This is used during deinit(). */
void ssl_sock_destroy_bind_conf ( struct bind_conf * bind_conf )
{
ssl_sock_free_ca ( bind_conf ) ;
ssl_sock_free_all_ctx ( bind_conf ) ;
2016-12-29 12:26:15 -05:00
ssl_sock_free_ssl_conf ( & bind_conf - > ssl_conf ) ;
2016-12-22 11:30:54 -05:00
free ( bind_conf - > ca_sign_file ) ;
free ( bind_conf - > ca_sign_pass ) ;
2018-07-17 04:05:32 -04:00
if ( bind_conf - > keys_ref & & ! - - bind_conf - > keys_ref - > refcount ) {
2016-12-22 11:30:54 -05:00
free ( bind_conf - > keys_ref - > filename ) ;
free ( bind_conf - > keys_ref - > tlskeys ) ;
LIST_DEL ( & bind_conf - > keys_ref - > list ) ;
free ( bind_conf - > keys_ref ) ;
}
bind_conf - > keys_ref = NULL ;
bind_conf - > ca_sign_pass = NULL ;
bind_conf - > ca_sign_file = NULL ;
}
2015-06-09 11:29:50 -04:00
/* Load CA cert file and private key used to generate certificates */
int
2016-12-22 11:08:28 -05:00
ssl_sock_load_ca ( struct bind_conf * bind_conf )
2015-06-09 11:29:50 -04:00
{
2016-12-22 11:08:28 -05:00
struct proxy * px = bind_conf - > frontend ;
2015-06-09 11:29:50 -04:00
FILE * fp ;
X509 * cacert = NULL ;
EVP_PKEY * capkey = NULL ;
int err = 0 ;
2017-09-15 03:52:49 -04:00
if ( ! bind_conf - > generate_certs )
2015-06-09 11:29:50 -04:00
return err ;
2017-01-13 11:48:18 -05:00
# if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
2017-06-15 10:37:39 -04:00
if ( global_ssl . ctx_cache ) {
2016-12-22 17:12:01 -05:00
ssl_ctx_lru_tree = lru64_new ( global_ssl . ctx_cache ) ;
2017-06-15 10:37:39 -04:00
}
2015-07-28 10:03:47 -04:00
ssl_ctx_lru_seed = ( unsigned int ) time ( NULL ) ;
2017-06-15 10:37:39 -04:00
ssl_ctx_serial = now_ms ;
2015-10-09 06:10:13 -04:00
# endif
2015-07-28 10:03:47 -04:00
2015-06-09 11:29:50 -04:00
if ( ! bind_conf - > ca_sign_file ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': cannot enable certificate generation, "
" no CA certificate File configured at [%s:%d]. \n " ,
px - > id , bind_conf - > file , bind_conf - > line ) ;
2015-06-09 11:29:50 -04:00
goto load_error ;
2015-10-09 04:53:31 -04:00
}
2015-06-09 11:29:50 -04:00
/* read in the CA certificate */
if ( ! ( fp = fopen ( bind_conf - > ca_sign_file , " r " ) ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': Failed to read CA certificate file '%s' at [%s:%d]. \n " ,
px - > id , bind_conf - > ca_sign_file , bind_conf - > file , bind_conf - > line ) ;
2015-06-09 11:29:50 -04:00
goto load_error ;
}
if ( ! ( cacert = PEM_read_X509 ( fp , NULL , NULL , NULL ) ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': Failed to read CA certificate file '%s' at [%s:%d]. \n " ,
px - > id , bind_conf - > ca_sign_file , bind_conf - > file , bind_conf - > line ) ;
2015-10-09 04:53:31 -04:00
goto read_error ;
2015-06-09 11:29:50 -04:00
}
2015-10-09 04:53:31 -04:00
rewind ( fp ) ;
2015-06-09 11:29:50 -04:00
if ( ! ( capkey = PEM_read_PrivateKey ( fp , NULL , NULL , bind_conf - > ca_sign_pass ) ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " Proxy '%s': Failed to read CA private key file '%s' at [%s:%d]. \n " ,
px - > id , bind_conf - > ca_sign_file , bind_conf - > file , bind_conf - > line ) ;
2015-10-09 04:53:31 -04:00
goto read_error ;
2015-06-09 11:29:50 -04:00
}
2015-10-09 04:53:31 -04:00
fclose ( fp ) ;
2015-06-09 11:29:50 -04:00
bind_conf - > ca_sign_cert = cacert ;
bind_conf - > ca_sign_pkey = capkey ;
return err ;
2015-10-09 04:53:31 -04:00
read_error :
fclose ( fp ) ;
2015-06-09 11:29:50 -04:00
if ( capkey ) EVP_PKEY_free ( capkey ) ;
if ( cacert ) X509_free ( cacert ) ;
2015-10-09 04:53:31 -04:00
load_error :
bind_conf - > generate_certs = 0 ;
err + + ;
2015-06-09 11:29:50 -04:00
return err ;
}
/* Release CA cert and private key used to generate certificated */
void
ssl_sock_free_ca ( struct bind_conf * bind_conf )
{
if ( bind_conf - > ca_sign_pkey )
EVP_PKEY_free ( bind_conf - > ca_sign_pkey ) ;
if ( bind_conf - > ca_sign_cert )
X509_free ( bind_conf - > ca_sign_cert ) ;
2016-12-22 11:57:46 -05:00
bind_conf - > ca_sign_pkey = NULL ;
bind_conf - > ca_sign_cert = NULL ;
2015-06-09 11:29:50 -04:00
}
2012-05-18 09:47:34 -04:00
/*
* This function is called if SSL * context is not yet allocated . The function
* is designed to be called before any other data - layer operation and sets the
* handshake flag on the connection . It is safe to call it multiple times .
* It returns 0 on success and - 1 in error case .
*/
static int ssl_sock_init ( struct connection * conn )
{
/* already initialized */
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
if ( conn - > xprt_ctx )
2012-05-18 09:47:34 -04:00
return 0 ;
2014-01-23 07:50:42 -05:00
if ( ! conn_ctrl_ready ( conn ) )
MAJOR: connection: add two new flags to indicate readiness of control/transport
Currently the control and transport layers of a connection are supposed
to be initialized when their respective pointers are not NULL. This will
not work anymore when we plan to reuse connections, because there is an
asymmetry between the accept() side and the connect() side :
- on accept() side, the fd is set first, then the ctrl layer then the
transport layer ; upon error, they must be undone in the reverse order,
then the FD must be closed. The FD must not be deleted if the control
layer was not yet initialized ;
- on the connect() side, the fd is set last and there is no reliable way
to know if it has been initialized or not. In practice it's initialized
to -1 first but this is hackish and supposes that local FDs only will
be used forever. Also, there are even less solutions for keeping trace
of the transport layer's state.
Also it is possible to support delayed close() when something (eg: logs)
tracks some information requiring the transport and/or control layers,
making it even more difficult to clean them.
So the proposed solution is to add two flags to the connection :
- CO_FL_CTRL_READY is set when the control layer is initialized (fd_insert)
and cleared after it's released (fd_delete).
- CO_FL_XPRT_READY is set when the control layer is initialized (xprt->init)
and cleared after it's released (xprt->close).
The functions have been adapted to rely on this and not on the pointers
anymore. conn_xprt_close() was unused and dangerous : it did not close
the control layer (eg: the socket itself) but still marks the transport
layer as closed, preventing any future call to conn_full_close() from
finishing the job.
The problem comes from conn_full_close() in fact. It needs to close the
xprt and ctrl layers independantly. After that we're still having an issue :
we don't know based on ->ctrl alone whether the fd was registered or not.
For this we use the two new flags CO_FL_XPRT_READY and CO_FL_CTRL_READY. We
now rely on this and not on conn->xprt nor conn->ctrl anymore to decide what
remains to be done on the connection.
In order not to miss some flag assignments, we introduce conn_ctrl_init()
to initialize the control layer, register the fd using fd_insert() and set
the flag, and conn_ctrl_close() which unregisters the fd and removes the
flag, but only if the transport layer was closed.
Similarly, at the transport layer, conn_xprt_init() calls ->init and sets
the flag, while conn_xprt_close() checks the flag, calls ->close and clears
the flag, regardless xprt_ctx or xprt_st. This also ensures that the ->init
and the ->close functions are called only once each and in the correct order.
Note that conn_xprt_close() does nothing if the transport layer is still
tracked.
conn_full_close() now simply calls conn_xprt_close() then conn_full_close()
in turn, which do nothing if CO_FL_XPRT_TRACKED is set.
In order to handle the error path, we also provide conn_force_close() which
ignores CO_FL_XPRT_TRACKED and closes the transport and the control layers
in turns. All relevant instances of fd_delete() have been replaced with
conn_force_close(). Now we always know what state the connection is in and
we can expect to split its initialization.
2013-10-21 10:30:56 -04:00
return 0 ;
2012-12-03 10:32:10 -05:00
if ( global . maxsslconn & & sslconns > = global . maxsslconn ) {
conn - > err_code = CO_ER_SSL_TOO_MANY ;
2012-09-06 05:58:37 -04:00
return - 1 ;
2012-12-03 10:32:10 -05:00
}
2012-09-06 05:58:37 -04:00
2012-05-18 09:47:34 -04:00
/* If it is in client mode initiate SSL session
in connect state otherwise accept state */
2012-11-11 18:42:33 -05:00
if ( objt_server ( conn - > target ) ) {
2014-11-13 07:48:58 -05:00
int may_retry = 1 ;
retry_connect :
2012-05-18 09:47:34 -04:00
/* Alloc a new SSL session ctx */
2018-09-20 04:57:52 -04:00
conn - > xprt_ctx = SSL_new ( __objt_server ( conn - > target ) - > ssl_ctx . ctx ) ;
2012-12-03 10:32:10 -05:00
if ( ! conn - > xprt_ctx ) {
2014-11-13 07:48:58 -05:00
if ( may_retry - - ) {
2017-11-24 11:34:44 -05:00
pool_gc ( NULL ) ;
2014-11-13 07:48:58 -05:00
goto retry_connect ;
}
2012-12-03 10:32:10 -05:00
conn - > err_code = CO_ER_SSL_NO_MEM ;
2012-05-18 09:47:34 -04:00
return - 1 ;
2012-12-03 10:32:10 -05:00
}
2012-05-18 09:47:34 -04:00
/* set fd on SSL session context */
2017-08-24 08:31:19 -04:00
if ( ! SSL_set_fd ( conn - > xprt_ctx , conn - > handle . fd ) ) {
2014-11-12 11:35:37 -05:00
SSL_free ( conn - > xprt_ctx ) ;
conn - > xprt_ctx = NULL ;
2014-11-13 07:48:58 -05:00
if ( may_retry - - ) {
2017-11-24 11:34:44 -05:00
pool_gc ( NULL ) ;
2014-11-13 07:48:58 -05:00
goto retry_connect ;
}
2014-11-12 11:35:37 -05:00
conn - > err_code = CO_ER_SSL_NO_MEM ;
return - 1 ;
}
2012-05-18 09:47:34 -04:00
2013-06-27 03:05:25 -04:00
/* set connection pointer */
BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
We never saw unexplicated crash with SSL, so I suppose that we are
luck, or the slot 0 is always reserved. Anyway the usage of the macro
SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
the deprecated functions SSL_get_app_data() and SSL_set_app_data()
by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
it reserves the slot in the SSL memory space.
For information, this is the two declaration which seems wrong or
incomplete in the OpenSSL ssl.h file. We can see the usage of the
slot 0 whoch is hardcoded, but never reserved.
#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
This patch must be backported at least in 1.8, maybe in other versions.
2018-06-17 15:37:05 -04:00
if ( ! SSL_set_ex_data ( conn - > xprt_ctx , ssl_app_data_index , conn ) ) {
2014-11-12 11:35:37 -05:00
SSL_free ( conn - > xprt_ctx ) ;
conn - > xprt_ctx = NULL ;
2014-11-13 07:48:58 -05:00
if ( may_retry - - ) {
2017-11-24 11:34:44 -05:00
pool_gc ( NULL ) ;
2014-11-13 07:48:58 -05:00
goto retry_connect ;
}
2014-11-12 11:35:37 -05:00
conn - > err_code = CO_ER_SSL_NO_MEM ;
return - 1 ;
}
SSL_set_connect_state ( conn - > xprt_ctx ) ;
2018-09-20 04:57:52 -04:00
if ( __objt_server ( conn - > target ) - > ssl_ctx . reused_sess [ tid ] . ptr ) {
const unsigned char * ptr = __objt_server ( conn - > target ) - > ssl_ctx . reused_sess [ tid ] . ptr ;
SSL_SESSION * sess = d2i_SSL_SESSION ( NULL , & ptr , __objt_server ( conn - > target ) - > ssl_ctx . reused_sess [ tid ] . size ) ;
if ( sess & & ! SSL_set_session ( conn - > xprt_ctx , sess ) ) {
2017-11-16 11:42:52 -05:00
SSL_SESSION_free ( sess ) ;
2018-09-20 04:57:52 -04:00
free ( __objt_server ( conn - > target ) - > ssl_ctx . reused_sess [ tid ] . ptr ) ;
__objt_server ( conn - > target ) - > ssl_ctx . reused_sess [ tid ] . ptr = NULL ;
2017-11-16 11:42:52 -05:00
} else if ( sess ) {
SSL_SESSION_free ( sess ) ;
2014-11-12 11:35:37 -05:00
}
}
2013-06-27 03:05:25 -04:00
2012-05-18 09:47:34 -04:00
/* leave init state and start handshake */
2012-09-04 02:03:39 -04:00
conn - > flags | = CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN ;
2012-09-06 05:58:37 -04:00
2019-03-08 12:54:43 -05:00
_HA_ATOMIC_ADD ( & sslconns , 1 ) ;
_HA_ATOMIC_ADD ( & totalsslconns , 1 ) ;
2012-05-18 09:47:34 -04:00
return 0 ;
}
2012-11-11 18:42:33 -05:00
else if ( objt_listener ( conn - > target ) ) {
2014-11-13 07:48:58 -05:00
int may_retry = 1 ;
retry_accept :
2012-05-18 09:47:34 -04:00
/* Alloc a new SSL session ctx */
2018-09-20 04:57:52 -04:00
conn - > xprt_ctx = SSL_new ( __objt_listener ( conn - > target ) - > bind_conf - > initial_ctx ) ;
2012-12-03 10:32:10 -05:00
if ( ! conn - > xprt_ctx ) {
2014-11-13 07:48:58 -05:00
if ( may_retry - - ) {
2017-11-24 11:34:44 -05:00
pool_gc ( NULL ) ;
2014-11-13 07:48:58 -05:00
goto retry_accept ;
}
2012-12-03 10:32:10 -05:00
conn - > err_code = CO_ER_SSL_NO_MEM ;
2012-05-18 09:47:34 -04:00
return - 1 ;
2012-12-03 10:32:10 -05:00
}
2012-05-18 09:47:34 -04:00
/* set fd on SSL session context */
2017-08-24 08:31:19 -04:00
if ( ! SSL_set_fd ( conn - > xprt_ctx , conn - > handle . fd ) ) {
2014-11-12 11:35:37 -05:00
SSL_free ( conn - > xprt_ctx ) ;
conn - > xprt_ctx = NULL ;
2014-11-13 07:48:58 -05:00
if ( may_retry - - ) {
2017-11-24 11:34:44 -05:00
pool_gc ( NULL ) ;
2014-11-13 07:48:58 -05:00
goto retry_accept ;
}
2014-11-12 11:35:37 -05:00
conn - > err_code = CO_ER_SSL_NO_MEM ;
return - 1 ;
}
2012-05-18 09:47:34 -04:00
2012-09-03 14:36:47 -04:00
/* set connection pointer */
BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
We never saw unexplicated crash with SSL, so I suppose that we are
luck, or the slot 0 is always reserved. Anyway the usage of the macro
SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
the deprecated functions SSL_get_app_data() and SSL_set_app_data()
by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
it reserves the slot in the SSL memory space.
For information, this is the two declaration which seems wrong or
incomplete in the OpenSSL ssl.h file. We can see the usage of the
slot 0 whoch is hardcoded, but never reserved.
#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
This patch must be backported at least in 1.8, maybe in other versions.
2018-06-17 15:37:05 -04:00
if ( ! SSL_set_ex_data ( conn - > xprt_ctx , ssl_app_data_index , conn ) ) {
2014-11-12 11:35:37 -05:00
SSL_free ( conn - > xprt_ctx ) ;
conn - > xprt_ctx = NULL ;
2014-11-13 07:48:58 -05:00
if ( may_retry - - ) {
2017-11-24 11:34:44 -05:00
pool_gc ( NULL ) ;
2014-11-13 07:48:58 -05:00
goto retry_accept ;
}
2014-11-12 11:35:37 -05:00
conn - > err_code = CO_ER_SSL_NO_MEM ;
return - 1 ;
}
SSL_set_accept_state ( conn - > xprt_ctx ) ;
2012-09-03 14:36:47 -04:00
2012-05-18 09:47:34 -04:00
/* leave init state and start handshake */
2012-09-04 02:03:39 -04:00
conn - > flags | = CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN ;
2017-11-23 06:40:07 -05:00
# if OPENSSL_VERSION_NUMBER >= 0x10101000L || defined(OPENSSL_IS_BORINGSSL)
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
conn - > flags | = CO_FL_EARLY_SSL_HS ;
# endif
2012-09-06 05:58:37 -04:00
2019-03-08 12:54:43 -05:00
_HA_ATOMIC_ADD ( & sslconns , 1 ) ;
_HA_ATOMIC_ADD ( & totalsslconns , 1 ) ;
2012-05-18 09:47:34 -04:00
return 0 ;
}
/* don't know how to handle such a target */
2012-12-03 10:32:10 -05:00
conn - > err_code = CO_ER_SSL_NO_TARGET ;
2012-05-18 09:47:34 -04:00
return - 1 ;
}
/* This is the callback which is used when an SSL handshake is pending. It
* updates the FD status if it wants some polling before being called again .
* It returns 0 if it fails in a fatal way or needs to poll to go further ,
* otherwise it returns non - zero and removes itself from the connection ' s
* flags ( the bit is provided in < flag > by the caller ) .
*/
int ssl_sock_handshake ( struct connection * conn , unsigned int flag )
{
int ret ;
2014-01-23 07:50:42 -05:00
if ( ! conn_ctrl_ready ( conn ) )
MAJOR: connection: add two new flags to indicate readiness of control/transport
Currently the control and transport layers of a connection are supposed
to be initialized when their respective pointers are not NULL. This will
not work anymore when we plan to reuse connections, because there is an
asymmetry between the accept() side and the connect() side :
- on accept() side, the fd is set first, then the ctrl layer then the
transport layer ; upon error, they must be undone in the reverse order,
then the FD must be closed. The FD must not be deleted if the control
layer was not yet initialized ;
- on the connect() side, the fd is set last and there is no reliable way
to know if it has been initialized or not. In practice it's initialized
to -1 first but this is hackish and supposes that local FDs only will
be used forever. Also, there are even less solutions for keeping trace
of the transport layer's state.
Also it is possible to support delayed close() when something (eg: logs)
tracks some information requiring the transport and/or control layers,
making it even more difficult to clean them.
So the proposed solution is to add two flags to the connection :
- CO_FL_CTRL_READY is set when the control layer is initialized (fd_insert)
and cleared after it's released (fd_delete).
- CO_FL_XPRT_READY is set when the control layer is initialized (xprt->init)
and cleared after it's released (xprt->close).
The functions have been adapted to rely on this and not on the pointers
anymore. conn_xprt_close() was unused and dangerous : it did not close
the control layer (eg: the socket itself) but still marks the transport
layer as closed, preventing any future call to conn_full_close() from
finishing the job.
The problem comes from conn_full_close() in fact. It needs to close the
xprt and ctrl layers independantly. After that we're still having an issue :
we don't know based on ->ctrl alone whether the fd was registered or not.
For this we use the two new flags CO_FL_XPRT_READY and CO_FL_CTRL_READY. We
now rely on this and not on conn->xprt nor conn->ctrl anymore to decide what
remains to be done on the connection.
In order not to miss some flag assignments, we introduce conn_ctrl_init()
to initialize the control layer, register the fd using fd_insert() and set
the flag, and conn_ctrl_close() which unregisters the fd and removes the
flag, but only if the transport layer was closed.
Similarly, at the transport layer, conn_xprt_init() calls ->init and sets
the flag, while conn_xprt_close() checks the flag, calls ->close and clears
the flag, regardless xprt_ctx or xprt_st. This also ensures that the ->init
and the ->close functions are called only once each and in the correct order.
Note that conn_xprt_close() does nothing if the transport layer is still
tracked.
conn_full_close() now simply calls conn_xprt_close() then conn_full_close()
in turn, which do nothing if CO_FL_XPRT_TRACKED is set.
In order to handle the error path, we also provide conn_force_close() which
ignores CO_FL_XPRT_TRACKED and closes the transport and the control layers
in turns. All relevant instances of fd_delete() have been replaced with
conn_force_close(). Now we always know what state the connection is in and
we can expect to split its initialization.
2013-10-21 10:30:56 -04:00
return 0 ;
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
if ( ! conn - > xprt_ctx )
2012-05-18 09:47:34 -04:00
goto out_error ;
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
# if OPENSSL_VERSION_NUMBER >= 0x10101000L
/*
* Check if we have early data . If we do , we have to read them
* before SSL_do_handshake ( ) is called , And there ' s no way to
* detect early data , except to try to read them
*/
if ( conn - > flags & CO_FL_EARLY_SSL_HS ) {
size_t read_data ;
ret = SSL_read_early_data ( conn - > xprt_ctx , & conn - > tmp_early_data ,
1 , & read_data ) ;
if ( ret = = SSL_READ_EARLY_DATA_ERROR )
goto check_error ;
if ( ret = = SSL_READ_EARLY_DATA_SUCCESS ) {
conn - > flags & = ~ ( CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN ) ;
return 1 ;
} else
conn - > flags & = ~ CO_FL_EARLY_SSL_HS ;
}
# endif
2012-11-08 13:21:55 -05:00
/* If we use SSL_do_handshake to process a reneg initiated by
* the remote peer , it sometimes returns SSL_ERROR_SSL .
* Usually SSL_write and SSL_read are used and process implicitly
* the reneg handshake .
* Here we use SSL_peek as a workaround for reneg .
*/
if ( ( conn - > flags & CO_FL_CONNECTED ) & & SSL_renegotiate_pending ( conn - > xprt_ctx ) ) {
char c ;
ret = SSL_peek ( conn - > xprt_ctx , & c , 1 ) ;
if ( ret < = 0 ) {
/* handshake may have not been completed, let's find why */
ret = SSL_get_error ( conn - > xprt_ctx , ret ) ;
2017-01-13 20:42:15 -05:00
2012-11-08 13:21:55 -05:00
if ( ret = = SSL_ERROR_WANT_WRITE ) {
/* SSL handshake needs to write, L4 connection may not be ready */
__conn_sock_stop_recv ( conn ) ;
2014-01-22 14:02:06 -05:00
__conn_sock_want_send ( conn ) ;
2017-08-24 08:31:19 -04:00
fd_cant_send ( conn - > handle . fd ) ;
2012-11-08 13:21:55 -05:00
return 0 ;
}
else if ( ret = = SSL_ERROR_WANT_READ ) {
/* handshake may have been completed but we have
* no more data to read .
*/
if ( ! SSL_renegotiate_pending ( conn - > xprt_ctx ) ) {
ret = 1 ;
goto reneg_ok ;
}
/* SSL handshake needs to read, L4 connection is ready */
if ( conn - > flags & CO_FL_WAIT_L4_CONN )
conn - > flags & = ~ CO_FL_WAIT_L4_CONN ;
__conn_sock_stop_send ( conn ) ;
2014-01-22 14:02:06 -05:00
__conn_sock_want_recv ( conn ) ;
2017-08-24 08:31:19 -04:00
fd_cant_recv ( conn - > handle . fd ) ;
2012-11-08 13:21:55 -05:00
return 0 ;
}
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-01-13 20:42:15 -05:00
else if ( ret = = SSL_ERROR_WANT_ASYNC ) {
2017-05-17 14:42:48 -04:00
ssl_async_process_fds ( conn , conn - > xprt_ctx ) ;
2017-01-13 20:42:15 -05:00
return 0 ;
}
# endif
2012-11-08 13:21:55 -05:00
else if ( ret = = SSL_ERROR_SYSCALL ) {
/* if errno is null, then connection was successfully established */
if ( ! errno & & conn - > flags & CO_FL_WAIT_L4_CONN )
conn - > flags & = ~ CO_FL_WAIT_L4_CONN ;
2012-12-03 10:32:10 -05:00
if ( ! conn - > err_code ) {
2018-08-16 05:36:40 -04:00
# ifdef OPENSSL_IS_BORINGSSL /* BoringSSL */
2017-01-13 11:48:18 -05:00
conn - > err_code = CO_ER_SSL_HANDSHAKE ;
# else
2016-08-29 07:26:37 -04:00
int empty_handshake ;
2016-12-12 04:56:56 -05:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(LIBRESSL_VERSION_NUMBER)
2016-08-29 07:26:37 -04:00
OSSL_HANDSHAKE_STATE state = SSL_get_state ( ( SSL * ) conn - > xprt_ctx ) ;
empty_handshake = state = = TLS_ST_BEFORE ;
# else
empty_handshake = ! ( ( SSL * ) conn - > xprt_ctx ) - > packet_length ;
# endif
if ( empty_handshake ) {
2014-04-25 13:05:36 -04:00
if ( ! errno ) {
if ( conn - > xprt_st & SSL_SOCK_RECV_HEARTBEAT )
conn - > err_code = CO_ER_SSL_HANDSHAKE_HB ;
else
conn - > err_code = CO_ER_SSL_EMPTY ;
}
else {
if ( conn - > xprt_st & SSL_SOCK_RECV_HEARTBEAT )
conn - > err_code = CO_ER_SSL_HANDSHAKE_HB ;
else
conn - > err_code = CO_ER_SSL_ABORT ;
}
}
else {
if ( conn - > xprt_st & SSL_SOCK_RECV_HEARTBEAT )
conn - > err_code = CO_ER_SSL_HANDSHAKE_HB ;
2012-12-03 10:32:10 -05:00
else
2014-04-25 13:05:36 -04:00
conn - > err_code = CO_ER_SSL_HANDSHAKE ;
}
2017-01-13 11:48:18 -05:00
# endif
2012-12-03 10:32:10 -05:00
}
2012-11-08 13:21:55 -05:00
goto out_error ;
}
else {
/* Fail on all other handshake errors */
/* Note: OpenSSL may leave unread bytes in the socket's
* buffer , causing an RST to be emitted upon close ( ) on
* TCP sockets . We first try to drain possibly pending
* data to avoid this as much as possible .
*/
2015-03-12 19:40:28 -04:00
conn_sock_drain ( conn ) ;
2012-12-03 10:32:10 -05:00
if ( ! conn - > err_code )
2014-04-25 14:02:39 -04:00
conn - > err_code = ( conn - > xprt_st & SSL_SOCK_RECV_HEARTBEAT ) ?
CO_ER_SSL_KILLED_HB : CO_ER_SSL_HANDSHAKE ;
2012-11-08 13:21:55 -05:00
goto out_error ;
}
}
/* read some data: consider handshake completed */
goto reneg_ok ;
}
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
ret = SSL_do_handshake ( conn - > xprt_ctx ) ;
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
check_error :
2012-05-18 09:47:34 -04:00
if ( ret ! = 1 ) {
/* handshake did not complete, let's find why */
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
ret = SSL_get_error ( conn - > xprt_ctx , ret ) ;
2012-05-18 09:47:34 -04:00
if ( ret = = SSL_ERROR_WANT_WRITE ) {
/* SSL handshake needs to write, L4 connection may not be ready */
__conn_sock_stop_recv ( conn ) ;
2014-01-22 14:02:06 -05:00
__conn_sock_want_send ( conn ) ;
2017-08-24 08:31:19 -04:00
fd_cant_send ( conn - > handle . fd ) ;
2012-05-18 09:47:34 -04:00
return 0 ;
}
else if ( ret = = SSL_ERROR_WANT_READ ) {
/* SSL handshake needs to read, L4 connection is ready */
if ( conn - > flags & CO_FL_WAIT_L4_CONN )
conn - > flags & = ~ CO_FL_WAIT_L4_CONN ;
__conn_sock_stop_send ( conn ) ;
2014-01-22 14:02:06 -05:00
__conn_sock_want_recv ( conn ) ;
2017-08-24 08:31:19 -04:00
fd_cant_recv ( conn - > handle . fd ) ;
2012-05-18 09:47:34 -04:00
return 0 ;
}
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-01-13 20:42:15 -05:00
else if ( ret = = SSL_ERROR_WANT_ASYNC ) {
2017-05-17 14:42:48 -04:00
ssl_async_process_fds ( conn , conn - > xprt_ctx ) ;
2017-01-13 20:42:15 -05:00
return 0 ;
}
# endif
2012-09-28 14:22:13 -04:00
else if ( ret = = SSL_ERROR_SYSCALL ) {
/* if errno is null, then connection was successfully established */
if ( ! errno & & conn - > flags & CO_FL_WAIT_L4_CONN )
conn - > flags & = ~ CO_FL_WAIT_L4_CONN ;
2017-01-13 11:48:18 -05:00
if ( ! conn - > err_code ) {
2018-08-16 05:36:40 -04:00
# ifdef OPENSSL_IS_BORINGSSL /* BoringSSL */
2017-01-13 11:48:18 -05:00
conn - > err_code = CO_ER_SSL_HANDSHAKE ;
# else
int empty_handshake ;
2016-12-12 04:56:56 -05:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(LIBRESSL_VERSION_NUMBER)
2017-01-13 11:48:18 -05:00
OSSL_HANDSHAKE_STATE state = SSL_get_state ( ( SSL * ) conn - > xprt_ctx ) ;
empty_handshake = state = = TLS_ST_BEFORE ;
2016-08-29 07:26:37 -04:00
# else
2017-01-13 11:48:18 -05:00
empty_handshake = ! ( ( SSL * ) conn - > xprt_ctx ) - > packet_length ;
2016-08-29 07:26:37 -04:00
# endif
2017-01-13 11:48:18 -05:00
if ( empty_handshake ) {
if ( ! errno ) {
if ( conn - > xprt_st & SSL_SOCK_RECV_HEARTBEAT )
conn - > err_code = CO_ER_SSL_HANDSHAKE_HB ;
else
conn - > err_code = CO_ER_SSL_EMPTY ;
}
else {
if ( conn - > xprt_st & SSL_SOCK_RECV_HEARTBEAT )
conn - > err_code = CO_ER_SSL_HANDSHAKE_HB ;
else
conn - > err_code = CO_ER_SSL_ABORT ;
}
2014-04-25 13:05:36 -04:00
}
else {
if ( conn - > xprt_st & SSL_SOCK_RECV_HEARTBEAT )
conn - > err_code = CO_ER_SSL_HANDSHAKE_HB ;
else
2017-01-13 11:48:18 -05:00
conn - > err_code = CO_ER_SSL_HANDSHAKE ;
2014-04-25 13:05:36 -04:00
}
2017-01-13 11:48:18 -05:00
# endif
2014-04-25 13:05:36 -04:00
}
2012-09-28 14:22:13 -04:00
goto out_error ;
}
2012-05-18 09:47:34 -04:00
else {
/* Fail on all other handshake errors */
2012-10-19 14:52:18 -04:00
/* Note: OpenSSL may leave unread bytes in the socket's
* buffer , causing an RST to be emitted upon close ( ) on
* TCP sockets . We first try to drain possibly pending
* data to avoid this as much as possible .
*/
2015-03-12 19:40:28 -04:00
conn_sock_drain ( conn ) ;
2012-12-03 10:32:10 -05:00
if ( ! conn - > err_code )
2014-04-25 14:02:39 -04:00
conn - > err_code = ( conn - > xprt_st & SSL_SOCK_RECV_HEARTBEAT ) ?
CO_ER_SSL_KILLED_HB : CO_ER_SSL_HANDSHAKE ;
2012-05-18 09:47:34 -04:00
goto out_error ;
}
}
2017-11-03 11:27:47 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L)
else {
/*
* If the server refused the early data , we have to send a
* 425 to the client , as we no longer have the data to sent
* them again .
*/
if ( ( conn - > flags & CO_FL_EARLY_DATA ) & & ( objt_server ( conn - > target ) ) ) {
if ( SSL_get_early_data_status ( conn - > xprt_ctx ) = = SSL_EARLY_DATA_REJECTED ) {
conn - > err_code = CO_ER_SSL_EARLY_FAILED ;
goto out_error ;
}
}
}
# endif
2012-05-18 09:47:34 -04:00
2012-11-08 13:21:55 -05:00
reneg_ok :
2017-06-06 08:35:14 -04:00
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-06-06 08:35:14 -04:00
/* ASYNC engine API doesn't support moving read/write
* buffers . So we disable ASYNC mode right after
* the handshake to avoid buffer oveflows .
*/
if ( global_ssl . async )
SSL_clear_mode ( conn - > xprt_ctx , SSL_MODE_ASYNC ) ;
# endif
2012-05-18 09:47:34 -04:00
/* Handshake succeeded */
2014-05-28 06:28:58 -04:00
if ( ! SSL_session_reused ( conn - > xprt_ctx ) ) {
if ( objt_server ( conn - > target ) ) {
update_freq_ctr ( & global . ssl_be_keys_per_sec , 1 ) ;
if ( global . ssl_be_keys_per_sec . curr_ctr > global . ssl_be_keys_max )
global . ssl_be_keys_max = global . ssl_be_keys_per_sec . curr_ctr ;
2012-05-18 09:47:34 -04:00
}
2014-05-28 06:28:58 -04:00
else {
update_freq_ctr ( & global . ssl_fe_keys_per_sec , 1 ) ;
if ( global . ssl_fe_keys_per_sec . curr_ctr > global . ssl_fe_keys_max )
global . ssl_fe_keys_max = global . ssl_fe_keys_per_sec . curr_ctr ;
}
2012-05-18 09:47:34 -04:00
}
2017-11-23 06:40:07 -05:00
# ifdef OPENSSL_IS_BORINGSSL
if ( ( conn - > flags & CO_FL_EARLY_SSL_HS ) & & ! SSL_in_early_data ( conn - > xprt_ctx ) )
conn - > flags & = ~ CO_FL_EARLY_SSL_HS ;
# endif
2012-05-18 09:47:34 -04:00
/* The connection is now established at both layers, it's time to leave */
conn - > flags & = ~ ( flag | CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN ) ;
return 1 ;
out_error :
2012-12-14 05:21:13 -05:00
/* Clear openssl global errors stack */
2016-10-10 05:59:50 -04:00
ssl_sock_dump_errors ( conn ) ;
2012-12-14 05:21:13 -05:00
ERR_clear_error ( ) ;
2012-10-04 11:09:56 -04:00
/* free resumed session if exists */
2018-09-20 04:57:52 -04:00
if ( objt_server ( conn - > target ) & & __objt_server ( conn - > target ) - > ssl_ctx . reused_sess [ tid ] . ptr ) {
free ( __objt_server ( conn - > target ) - > ssl_ctx . reused_sess [ tid ] . ptr ) ;
__objt_server ( conn - > target ) - > ssl_ctx . reused_sess [ tid ] . ptr = NULL ;
2012-10-04 11:09:56 -04:00
}
2012-05-18 09:47:34 -04:00
/* Fail on all other handshake errors */
conn - > flags | = CO_FL_ERROR ;
2012-12-03 10:32:10 -05:00
if ( ! conn - > err_code )
conn - > err_code = CO_ER_SSL_HANDSHAKE ;
2012-05-18 09:47:34 -04:00
return 0 ;
}
/* Receive up to <count> bytes from connection <conn>'s socket and store them
2014-01-14 05:31:27 -05:00
* into buffer < buf > . Only one call to recv ( ) is performed , unless the
2012-05-18 09:47:34 -04:00
* buffer wraps , in which case a second call may be performed . The connection ' s
* flags are updated with whatever special event is detected ( error , read0 ,
* empty ) . The caller is responsible for taking care of those events and
* avoiding the call if inappropriate . The function does not call the
* connection ' s polling update function , so the caller is responsible for this .
*/
2018-06-19 00:15:17 -04:00
static size_t ssl_sock_to_buf ( struct connection * conn , struct buffer * buf , size_t count , int flags )
2012-05-18 09:47:34 -04:00
{
2018-07-18 05:22:03 -04:00
ssize_t ret ;
size_t try , done = 0 ;
2012-05-18 09:47:34 -04:00
2017-10-25 03:32:15 -04:00
conn_refresh_polling_flags ( conn ) ;
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
if ( ! conn - > xprt_ctx )
2012-05-18 09:47:34 -04:00
goto out_error ;
if ( conn - > flags & CO_FL_HANDSHAKE )
/* a handshake was requested */
return 0 ;
/* read the largest possible block. For this, we perform only one call
* to recv ( ) unless the buffer wraps and we exactly fill the first hunk ,
* in which case we accept to do it once again . A new attempt is made on
* EINTR too .
*/
2014-01-17 05:09:40 -05:00
while ( count > 0 ) {
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
int need_out = 0 ;
2018-06-15 11:21:00 -04:00
try = b_contig_space ( buf ) ;
if ( ! try )
break ;
2014-01-14 05:31:27 -05:00
if ( try > count )
try = count ;
2018-06-15 11:21:00 -04:00
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
if ( ( ( conn - > flags & ( CO_FL_EARLY_SSL_HS | CO_FL_EARLY_DATA ) ) = = CO_FL_EARLY_SSL_HS ) & &
conn - > tmp_early_data ! = - 1 ) {
2018-06-07 12:46:28 -04:00
* b_tail ( buf ) = conn - > tmp_early_data ;
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
done + + ;
try - - ;
count - - ;
2018-06-28 12:17:23 -04:00
b_add ( buf , 1 ) ;
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
conn - > tmp_early_data = - 1 ;
continue ;
}
2014-01-14 05:31:27 -05:00
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L)
if ( conn - > flags & CO_FL_EARLY_SSL_HS ) {
size_t read_length ;
ret = SSL_read_early_data ( conn - > xprt_ctx ,
2018-06-07 12:46:28 -04:00
b_tail ( buf ) , try , & read_length ) ;
2017-11-03 11:27:47 -04:00
if ( ret = = SSL_READ_EARLY_DATA_SUCCESS & &
read_length > 0 )
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
conn - > flags | = CO_FL_EARLY_DATA ;
if ( ret = = SSL_READ_EARLY_DATA_SUCCESS | |
ret = = SSL_READ_EARLY_DATA_FINISH ) {
if ( ret = = SSL_READ_EARLY_DATA_FINISH ) {
/*
* We ' re done reading the early data ,
* let ' s make the handshake
*/
conn - > flags & = ~ CO_FL_EARLY_SSL_HS ;
conn - > flags | = CO_FL_SSL_WAIT_HS ;
need_out = 1 ;
if ( read_length = = 0 )
break ;
}
ret = read_length ;
}
} else
# endif
2018-06-07 12:46:28 -04:00
ret = SSL_read ( conn - > xprt_ctx , b_tail ( buf ) , try ) ;
2017-11-23 06:40:07 -05:00
# ifdef OPENSSL_IS_BORINGSSL
if ( conn - > flags & CO_FL_EARLY_SSL_HS ) {
if ( SSL_in_early_data ( conn - > xprt_ctx ) ) {
if ( ret > 0 )
conn - > flags | = CO_FL_EARLY_DATA ;
} else {
2017-11-27 10:14:40 -05:00
conn - > flags & = ~ ( CO_FL_EARLY_SSL_HS ) ;
2017-11-23 06:40:07 -05:00
}
}
# endif
2012-09-03 14:36:47 -04:00
if ( conn - > flags & CO_FL_ERROR ) {
/* CO_FL_ERROR may be set by ssl_sock_infocbk */
2012-12-14 05:21:13 -05:00
goto out_error ;
2012-09-03 14:36:47 -04:00
}
2012-05-18 09:47:34 -04:00
if ( ret > 0 ) {
2018-06-28 12:17:23 -04:00
b_add ( buf , ret ) ;
2012-05-18 09:47:34 -04:00
done + = ret ;
count - = ret ;
}
else {
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
ret = SSL_get_error ( conn - > xprt_ctx , ret ) ;
2012-05-18 09:47:34 -04:00
if ( ret = = SSL_ERROR_WANT_WRITE ) {
2012-11-08 11:56:20 -05:00
/* handshake is running, and it needs to enable write */
2012-05-18 09:47:34 -04:00
conn - > flags | = CO_FL_SSL_WAIT_HS ;
2012-11-08 11:56:20 -05:00
__conn_sock_want_send ( conn ) ;
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-06-06 08:35:14 -04:00
/* Async mode can be re-enabled, because we're leaving data state.*/
if ( global_ssl . async )
SSL_set_mode ( conn - > xprt_ctx , SSL_MODE_ASYNC ) ;
# endif
2012-05-18 09:47:34 -04:00
break ;
}
else if ( ret = = SSL_ERROR_WANT_READ ) {
2012-11-08 12:02:56 -05:00
if ( SSL_renegotiate_pending ( conn - > xprt_ctx ) ) {
/* handshake is running, and it may need to re-enable read */
conn - > flags | = CO_FL_SSL_WAIT_HS ;
__conn_sock_want_recv ( conn ) ;
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-06-06 08:35:14 -04:00
/* Async mode can be re-enabled, because we're leaving data state.*/
if ( global_ssl . async )
SSL_set_mode ( conn - > xprt_ctx , SSL_MODE_ASYNC ) ;
# endif
2012-11-08 12:02:56 -05:00
break ;
}
2012-05-18 09:47:34 -04:00
/* we need to poll for retry a read later */
2017-08-24 08:31:19 -04:00
fd_cant_recv ( conn - > handle . fd ) ;
2012-05-18 09:47:34 -04:00
break ;
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
} else if ( ret = = SSL_ERROR_ZERO_RETURN )
goto read0 ;
2018-02-19 08:25:15 -05:00
/* For SSL_ERROR_SYSCALL, make sure to clear the error
* stack before shutting down the connection for
* reading . */
2018-02-13 09:17:23 -05:00
if ( ret = = SSL_ERROR_SYSCALL & & ( ! errno | | errno = = EAGAIN ) )
goto clear_ssl_error ;
2012-05-18 09:47:34 -04:00
/* otherwise it's a real error */
goto out_error ;
}
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
if ( need_out )
break ;
2012-05-18 09:47:34 -04:00
}
2017-10-25 03:32:15 -04:00
leave :
conn_cond_update_sock_polling ( conn ) ;
2012-05-18 09:47:34 -04:00
return done ;
2018-02-19 08:25:15 -05:00
clear_ssl_error :
/* Clear openssl global errors stack */
ssl_sock_dump_errors ( conn ) ;
ERR_clear_error ( ) ;
2012-05-18 09:47:34 -04:00
read0 :
conn_sock_read0 ( conn ) ;
2017-10-25 03:32:15 -04:00
goto leave ;
2018-02-19 08:25:15 -05:00
2012-05-18 09:47:34 -04:00
out_error :
2018-02-13 09:17:23 -05:00
conn - > flags | = CO_FL_ERROR ;
2012-12-14 05:21:13 -05:00
/* Clear openssl global errors stack */
2016-10-10 05:59:50 -04:00
ssl_sock_dump_errors ( conn ) ;
2012-12-14 05:21:13 -05:00
ERR_clear_error ( ) ;
2017-10-25 03:32:15 -04:00
goto leave ;
2012-05-18 09:47:34 -04:00
}
2018-06-14 12:31:46 -04:00
/* Send up to <count> pending bytes from buffer <buf> to connection <conn>'s
* socket . < flags > may contain some CO_SFL_ * flags to hint the system about
* other pending data for example , but this flag is ignored at the moment .
2012-05-18 09:47:34 -04:00
* Only one call to send ( ) is performed , unless the buffer wraps , in which case
* a second call may be performed . The connection ' s flags are updated with
* whatever special event is detected ( error , empty ) . The caller is responsible
* for taking care of those events and avoiding the call if inappropriate . The
* function does not call the connection ' s polling update function , so the caller
2018-06-14 12:31:46 -04:00
* is responsible for this . The buffer ' s output is not adjusted , it ' s up to the
* caller to take care of this . It ' s up to the caller to update the buffer ' s
* contents based on the return value .
2012-05-18 09:47:34 -04:00
*/
2018-06-14 12:31:46 -04:00
static size_t ssl_sock_from_buf ( struct connection * conn , const struct buffer * buf , size_t count , int flags )
2012-05-18 09:47:34 -04:00
{
2018-06-14 12:31:46 -04:00
ssize_t ret ;
size_t try , done ;
2012-05-18 09:47:34 -04:00
done = 0 ;
2017-10-25 03:32:15 -04:00
conn_refresh_polling_flags ( conn ) ;
2012-05-18 09:47:34 -04:00
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
if ( ! conn - > xprt_ctx )
2012-05-18 09:47:34 -04:00
goto out_error ;
if ( conn - > flags & CO_FL_HANDSHAKE )
/* a handshake was requested */
return 0 ;
/* send the largest possible block. For this we perform only one call
* to send ( ) unless the buffer wraps and we exactly fill the first hunk ,
* in which case we accept to do it once again .
*/
2018-06-14 12:31:46 -04:00
while ( count ) {
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L)
size_t written_data ;
# endif
2018-06-14 12:31:46 -04:00
try = b_contig_data ( buf , done ) ;
if ( try > count )
try = count ;
2013-02-21 01:46:09 -05:00
2014-02-01 20:00:24 -05:00
if ( ! ( flags & CO_SFL_STREAMER ) & &
2014-02-17 09:43:01 -05:00
! ( conn - > xprt_st & SSL_SOCK_SEND_UNLIMITED ) & &
2016-12-22 17:12:01 -05:00
global_ssl . max_record & & try > global_ssl . max_record ) {
try = global_ssl . max_record ;
2014-02-17 09:43:01 -05:00
}
else {
/* we need to keep the information about the fact that
* we ' re not limiting the upcoming send ( ) , because if it
* fails , we ' ll have to retry with at least as many data .
*/
conn - > xprt_st | = SSL_SOCK_SEND_UNLIMITED ;
}
2013-02-21 01:46:09 -05:00
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L)
if ( ! SSL_is_init_finished ( conn - > xprt_ctx ) ) {
unsigned int max_early ;
2017-11-03 11:27:47 -04:00
if ( objt_listener ( conn - > target ) )
max_early = SSL_get_max_early_data ( conn - > xprt_ctx ) ;
else {
if ( SSL_get0_session ( conn - > xprt_ctx ) )
max_early = SSL_SESSION_get_max_early_data ( SSL_get0_session ( conn - > xprt_ctx ) ) ;
else
max_early = 0 ;
}
2017-11-23 12:21:29 -05:00
if ( try + conn - > sent_early_data > max_early ) {
try - = ( try + conn - > sent_early_data ) - max_early ;
2017-11-03 11:27:47 -04:00
if ( try < = 0 ) {
2017-11-23 12:21:29 -05:00
if ( ! ( conn - > flags & CO_FL_EARLY_SSL_HS ) )
conn - > flags | = CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN ;
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
break ;
2017-11-03 11:27:47 -04:00
}
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
}
2018-06-14 12:31:46 -04:00
ret = SSL_write_early_data ( conn - > xprt_ctx , b_peek ( buf , done ) , try , & written_data ) ;
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
if ( ret = = 1 ) {
ret = written_data ;
2017-11-23 12:21:29 -05:00
conn - > sent_early_data + = ret ;
2017-11-03 11:27:47 -04:00
if ( objt_server ( conn - > target ) ) {
conn - > flags & = ~ CO_FL_EARLY_SSL_HS ;
conn - > flags | = CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN | CO_FL_EARLY_DATA ;
}
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
}
} else
# endif
2018-06-14 12:31:46 -04:00
ret = SSL_write ( conn - > xprt_ctx , b_peek ( buf , done ) , try ) ;
2014-02-17 09:43:01 -05:00
2012-09-03 14:36:47 -04:00
if ( conn - > flags & CO_FL_ERROR ) {
/* CO_FL_ERROR may be set by ssl_sock_infocbk */
2012-12-14 05:21:13 -05:00
goto out_error ;
2012-09-03 14:36:47 -04:00
}
2012-05-18 09:47:34 -04:00
if ( ret > 0 ) {
2019-01-17 13:09:11 -05:00
/* A send succeeded, so we can consier ourself connected */
conn - > flags | = CO_FL_CONNECTED ;
2014-02-17 09:43:01 -05:00
conn - > xprt_st & = ~ SSL_SOCK_SEND_UNLIMITED ;
2018-06-14 12:31:46 -04:00
count - = ret ;
2012-05-18 09:47:34 -04:00
done + = ret ;
}
else {
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
ret = SSL_get_error ( conn - > xprt_ctx , ret ) ;
2017-01-13 20:42:15 -05:00
2012-05-18 09:47:34 -04:00
if ( ret = = SSL_ERROR_WANT_WRITE ) {
2012-11-08 12:02:56 -05:00
if ( SSL_renegotiate_pending ( conn - > xprt_ctx ) ) {
/* handshake is running, and it may need to re-enable write */
conn - > flags | = CO_FL_SSL_WAIT_HS ;
__conn_sock_want_send ( conn ) ;
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-06-06 08:35:14 -04:00
/* Async mode can be re-enabled, because we're leaving data state.*/
if ( global_ssl . async )
SSL_set_mode ( conn - > xprt_ctx , SSL_MODE_ASYNC ) ;
# endif
2012-11-08 12:02:56 -05:00
break ;
}
2012-05-18 09:47:34 -04:00
/* we need to poll to retry a write later */
2017-08-24 08:31:19 -04:00
fd_cant_send ( conn - > handle . fd ) ;
2012-05-18 09:47:34 -04:00
break ;
}
else if ( ret = = SSL_ERROR_WANT_READ ) {
2012-11-08 11:56:20 -05:00
/* handshake is running, and it needs to enable read */
2012-05-18 09:47:34 -04:00
conn - > flags | = CO_FL_SSL_WAIT_HS ;
2012-11-08 11:56:20 -05:00
__conn_sock_want_recv ( conn ) ;
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-06-06 08:35:14 -04:00
/* Async mode can be re-enabled, because we're leaving data state.*/
if ( global_ssl . async )
SSL_set_mode ( conn - > xprt_ctx , SSL_MODE_ASYNC ) ;
# endif
2017-01-13 20:42:15 -05:00
break ;
}
2012-05-18 09:47:34 -04:00
goto out_error ;
}
}
2017-10-25 03:32:15 -04:00
leave :
conn_cond_update_sock_polling ( conn ) ;
2012-05-18 09:47:34 -04:00
return done ;
out_error :
2012-12-14 05:21:13 -05:00
/* Clear openssl global errors stack */
2016-10-10 05:59:50 -04:00
ssl_sock_dump_errors ( conn ) ;
2012-12-14 05:21:13 -05:00
ERR_clear_error ( ) ;
2012-05-18 09:47:34 -04:00
conn - > flags | = CO_FL_ERROR ;
2017-10-25 03:32:15 -04:00
goto leave ;
2012-05-18 09:47:34 -04:00
}
static void ssl_sock_close ( struct connection * conn ) {
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
if ( conn - > xprt_ctx ) {
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-05-17 14:42:48 -04:00
if ( global_ssl . async ) {
OSSL_ASYNC_FD all_fd [ 32 ] , afd ;
size_t num_all_fds = 0 ;
int i ;
SSL_get_all_async_fds ( conn - > xprt_ctx , NULL , & num_all_fds ) ;
if ( num_all_fds > 32 ) {
send_log ( NULL , LOG_EMERG , " haproxy: openssl returns too many async fds. It seems a bug. Process may crash \n " ) ;
return ;
}
SSL_get_all_async_fds ( conn - > xprt_ctx , all_fd , & num_all_fds ) ;
/* If an async job is pending, we must try to
to catch the end using polling before calling
SSL_free */
if ( num_all_fds & & SSL_waiting_for_async ( conn - > xprt_ctx ) ) {
for ( i = 0 ; i < num_all_fds ; i + + ) {
/* switch on an handler designed to
* handle the SSL_free
*/
afd = all_fd [ i ] ;
fdtab [ afd ] . iocb = ssl_async_fd_free ;
fdtab [ afd ] . owner = conn - > xprt_ctx ;
fd_want_recv ( afd ) ;
2017-05-31 06:02:53 -04:00
/* To ensure that the fd cache won't be used
* and we ' ll catch a real RD event .
*/
fd_cant_recv ( afd ) ;
2017-05-17 14:42:48 -04:00
}
2017-01-13 20:42:15 -05:00
conn - > xprt_ctx = NULL ;
2019-03-08 12:54:43 -05:00
_HA_ATOMIC_ADD ( & jobs , 1 ) ;
2017-01-13 20:42:15 -05:00
return ;
}
2017-05-17 14:42:48 -04:00
/* Else we can remove the fds from the fdtab
* and call SSL_free .
* note : we do a fd_remove and not a delete
* because the fd is owned by the engine .
* the engine is responsible to close
*/
for ( i = 0 ; i < num_all_fds ; i + + )
fd_remove ( all_fd [ i ] ) ;
2017-01-13 20:42:15 -05:00
}
# endif
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
SSL_free ( conn - > xprt_ctx ) ;
conn - > xprt_ctx = NULL ;
2019-03-08 12:54:43 -05:00
_HA_ATOMIC_SUB ( & sslconns , 1 ) ;
2012-05-18 09:47:34 -04:00
}
}
/* This function tries to perform a clean shutdown on an SSL connection, and in
* any case , flags the connection as reusable if no handshake was in progress .
*/
static void ssl_sock_shutw ( struct connection * conn , int clean )
{
if ( conn - > flags & CO_FL_HANDSHAKE )
return ;
2017-01-08 08:07:39 -05:00
if ( ! clean )
/* don't sent notify on SSL_shutdown */
2017-02-13 05:12:29 -05:00
SSL_set_quiet_shutdown ( conn - > xprt_ctx , 1 ) ;
2012-05-18 09:47:34 -04:00
/* no handshake was in progress, try a clean ssl shutdown */
2017-01-08 08:07:39 -05:00
if ( SSL_shutdown ( conn - > xprt_ctx ) < = 0 ) {
2012-12-14 05:21:13 -05:00
/* Clear openssl global errors stack */
2016-10-10 05:59:50 -04:00
ssl_sock_dump_errors ( conn ) ;
2012-12-14 05:21:13 -05:00
ERR_clear_error ( ) ;
}
2012-05-18 09:47:34 -04:00
}
2017-10-31 10:46:07 -04:00
/* used for ppv2 pkey alog (can be used for logging) */
2018-07-13 05:56:34 -04:00
int ssl_sock_get_pkey_algo ( struct connection * conn , struct buffer * out )
2017-10-31 10:46:07 -04:00
{
struct pkey_info * pkinfo ;
int bits = 0 ;
int sig = TLSEXT_signature_anonymous ;
int len = - 1 ;
if ( ! ssl_sock_is_ssl ( conn ) )
return 0 ;
2018-06-18 06:44:19 -04:00
pkinfo = SSL_CTX_get_ex_data ( SSL_get_SSL_CTX ( conn - > xprt_ctx ) , ssl_pkey_info_index ) ;
2017-10-31 10:46:07 -04:00
if ( pkinfo ) {
sig = pkinfo - > sig ;
bits = pkinfo - > bits ;
} else {
/* multicert and generated cert have no pkey info */
X509 * crt ;
EVP_PKEY * pkey ;
crt = SSL_get_certificate ( conn - > xprt_ctx ) ;
if ( ! crt )
return 0 ;
pkey = X509_get_pubkey ( crt ) ;
if ( pkey ) {
bits = EVP_PKEY_bits ( pkey ) ;
switch ( EVP_PKEY_base_id ( pkey ) ) {
case EVP_PKEY_RSA :
sig = TLSEXT_signature_rsa ;
break ;
case EVP_PKEY_EC :
sig = TLSEXT_signature_ecdsa ;
break ;
case EVP_PKEY_DSA :
sig = TLSEXT_signature_dsa ;
break ;
}
EVP_PKEY_free ( pkey ) ;
}
}
switch ( sig ) {
case TLSEXT_signature_rsa :
len = chunk_printf ( out , " RSA%d " , bits ) ;
break ;
case TLSEXT_signature_ecdsa :
len = chunk_printf ( out , " EC%d " , bits ) ;
break ;
case TLSEXT_signature_dsa :
len = chunk_printf ( out , " DSA%d " , bits ) ;
break ;
default :
return 0 ;
}
if ( len < 0 )
return 0 ;
return 1 ;
}
2017-11-02 09:05:23 -04:00
/* used for ppv2 cert signature (can be used for logging) */
const char * ssl_sock_get_cert_sig ( struct connection * conn )
{
__OPENSSL_110_CONST__ ASN1_OBJECT * algorithm ;
X509 * crt ;
if ( ! ssl_sock_is_ssl ( conn ) )
return NULL ;
crt = SSL_get_certificate ( conn - > xprt_ctx ) ;
if ( ! crt )
return NULL ;
X509_ALGOR_get0 ( & algorithm , NULL , NULL , X509_get0_tbs_sigalg ( crt ) ) ;
return OBJ_nid2sn ( OBJ_obj2nid ( algorithm ) ) ;
}
2018-02-01 12:29:59 -05:00
/* used for ppv2 authority */
const char * ssl_sock_get_sni ( struct connection * conn )
{
# ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
if ( ! ssl_sock_is_ssl ( conn ) )
return NULL ;
return SSL_get_servername ( conn - > xprt_ctx , TLSEXT_NAMETYPE_host_name ) ;
# else
return 0 ;
# endif
}
2017-10-13 10:59:49 -04:00
/* used for logging/ppv2, may be changed for a sample fetch later */
2012-10-12 14:17:54 -04:00
const char * ssl_sock_get_cipher_name ( struct connection * conn )
{
2017-10-13 10:59:49 -04:00
if ( ! ssl_sock_is_ssl ( conn ) )
2012-10-12 14:17:54 -04:00
return NULL ;
2017-10-13 10:59:49 -04:00
2012-10-12 14:17:54 -04:00
return SSL_get_cipher_name ( conn - > xprt_ctx ) ;
}
2017-10-13 10:59:49 -04:00
/* used for logging/ppv2, may be changed for a sample fetch later */
2012-10-12 14:17:54 -04:00
const char * ssl_sock_get_proto_version ( struct connection * conn )
{
2017-10-13 10:59:49 -04:00
if ( ! ssl_sock_is_ssl ( conn ) )
2012-10-12 14:17:54 -04:00
return NULL ;
2017-10-13 10:59:49 -04:00
2012-10-12 14:17:54 -04:00
return SSL_get_version ( conn - > xprt_ctx ) ;
}
2012-10-22 11:58:39 -04:00
/* Extract a serial from a cert, and copy it to a chunk.
* Returns 1 if serial is found and copied , 0 if no serial found and
* - 1 if output is not large enough .
*/
static int
2018-07-13 05:56:34 -04:00
ssl_sock_get_serial ( X509 * crt , struct buffer * out )
2012-10-22 11:58:39 -04:00
{
ASN1_INTEGER * serial ;
serial = X509_get_serialNumber ( crt ) ;
if ( ! serial )
return 0 ;
if ( out - > size < serial - > length )
return - 1 ;
2018-07-13 04:54:26 -04:00
memcpy ( out - > area , serial - > data , serial - > length ) ;
out - > data = serial - > length ;
2012-10-22 11:58:39 -04:00
return 1 ;
}
2014-10-29 14:03:26 -04:00
/* Extract a cert to der, and copy it to a chunk.
2018-11-15 12:07:59 -05:00
* Returns 1 if the cert is found and copied , 0 on der conversion failure
* and - 1 if the output is not large enough .
2014-10-29 14:03:26 -04:00
*/
static int
2018-07-13 05:56:34 -04:00
ssl_sock_crt2der ( X509 * crt , struct buffer * out )
2014-10-29 14:03:26 -04:00
{
int len ;
2018-07-13 04:54:26 -04:00
unsigned char * p = ( unsigned char * ) out - > area ; ;
2014-10-29 14:03:26 -04:00
len = i2d_X509 ( crt , NULL ) ;
if ( len < = 0 )
return 1 ;
if ( out - > size < len )
return - 1 ;
i2d_X509 ( crt , & p ) ;
2018-07-13 04:54:26 -04:00
out - > data = len ;
2014-10-29 14:03:26 -04:00
return 1 ;
}
2012-10-22 08:11:22 -04:00
2018-07-13 05:56:34 -04:00
/* Copy Date in ASN1_UTCTIME format in struct buffer out.
2012-10-22 08:11:22 -04:00
* Returns 1 if serial is found and copied , 0 if no valid time found
* and - 1 if output is not large enough .
*/
static int
2018-07-13 05:56:34 -04:00
ssl_sock_get_time ( ASN1_TIME * tm , struct buffer * out )
2012-10-22 08:11:22 -04:00
{
if ( tm - > type = = V_ASN1_GENERALIZEDTIME ) {
ASN1_GENERALIZEDTIME * gentm = ( ASN1_GENERALIZEDTIME * ) tm ;
if ( gentm - > length < 12 )
return 0 ;
if ( gentm - > data [ 0 ] ! = 0x32 | | gentm - > data [ 1 ] ! = 0x30 )
return 0 ;
if ( out - > size < gentm - > length - 2 )
return - 1 ;
2018-07-13 04:54:26 -04:00
memcpy ( out - > area , gentm - > data + 2 , gentm - > length - 2 ) ;
out - > data = gentm - > length - 2 ;
2012-10-22 08:11:22 -04:00
return 1 ;
}
else if ( tm - > type = = V_ASN1_UTCTIME ) {
ASN1_UTCTIME * utctm = ( ASN1_UTCTIME * ) tm ;
if ( utctm - > length < 10 )
return 0 ;
if ( utctm - > data [ 0 ] > = 0x35 )
return 0 ;
if ( out - > size < utctm - > length )
return - 1 ;
2018-07-13 04:54:26 -04:00
memcpy ( out - > area , utctm - > data , utctm - > length ) ;
out - > data = utctm - > length ;
2012-10-22 08:11:22 -04:00
return 1 ;
}
return 0 ;
}
2012-10-17 11:39:35 -04:00
/* Extract an entry from a X509_NAME and copy its value to an output chunk.
* Returns 1 if entry found , 0 if entry not found , or - 1 if output not large enough .
*/
static int
2018-07-13 05:56:34 -04:00
ssl_sock_get_dn_entry ( X509_NAME * a , const struct buffer * entry , int pos ,
struct buffer * out )
2012-10-17 11:39:35 -04:00
{
X509_NAME_ENTRY * ne ;
2016-08-29 07:26:37 -04:00
ASN1_OBJECT * obj ;
ASN1_STRING * data ;
const unsigned char * data_ptr ;
int data_len ;
2012-10-17 11:39:35 -04:00
int i , j , n ;
int cur = 0 ;
const char * s ;
char tmp [ 128 ] ;
2016-08-29 07:26:37 -04:00
int name_count ;
name_count = X509_NAME_entry_count ( a ) ;
2012-10-17 11:39:35 -04:00
2018-07-13 04:54:26 -04:00
out - > data = 0 ;
2016-08-29 07:26:37 -04:00
for ( i = 0 ; i < name_count ; i + + ) {
2012-10-17 11:39:35 -04:00
if ( pos < 0 )
2016-08-29 07:26:37 -04:00
j = ( name_count - 1 ) - i ;
2012-10-17 11:39:35 -04:00
else
j = i ;
2016-08-29 07:26:37 -04:00
ne = X509_NAME_get_entry ( a , j ) ;
obj = X509_NAME_ENTRY_get_object ( ne ) ;
data = X509_NAME_ENTRY_get_data ( ne ) ;
data_ptr = ASN1_STRING_get0_data ( data ) ;
data_len = ASN1_STRING_length ( data ) ;
n = OBJ_obj2nid ( obj ) ;
2012-10-17 11:39:35 -04:00
if ( ( n = = NID_undef ) | | ( ( s = OBJ_nid2sn ( n ) ) = = NULL ) ) {
2016-08-29 07:26:37 -04:00
i2t_ASN1_OBJECT ( tmp , sizeof ( tmp ) , obj ) ;
2012-10-17 11:39:35 -04:00
s = tmp ;
}
if ( chunk_strcasecmp ( entry , s ) ! = 0 )
continue ;
if ( pos < 0 )
cur - - ;
else
cur + + ;
if ( cur ! = pos )
continue ;
2016-08-29 07:26:37 -04:00
if ( data_len > out - > size )
2012-10-17 11:39:35 -04:00
return - 1 ;
2018-07-13 04:54:26 -04:00
memcpy ( out - > area , data_ptr , data_len ) ;
out - > data = data_len ;
2012-10-17 11:39:35 -04:00
return 1 ;
}
return 0 ;
}
/* Extract and format full DN from a X509_NAME and copy result into a chunk
* Returns 1 if dn entries exits , 0 if no dn entry found or - 1 if output is not large enough .
*/
static int
2018-07-13 05:56:34 -04:00
ssl_sock_get_dn_oneline ( X509_NAME * a , struct buffer * out )
2012-10-17 11:39:35 -04:00
{
X509_NAME_ENTRY * ne ;
2016-08-29 07:26:37 -04:00
ASN1_OBJECT * obj ;
ASN1_STRING * data ;
const unsigned char * data_ptr ;
int data_len ;
2012-10-17 11:39:35 -04:00
int i , n , ln ;
int l = 0 ;
const char * s ;
char * p ;
char tmp [ 128 ] ;
2016-08-29 07:26:37 -04:00
int name_count ;
name_count = X509_NAME_entry_count ( a ) ;
2012-10-17 11:39:35 -04:00
2018-07-13 04:54:26 -04:00
out - > data = 0 ;
p = out - > area ;
2016-08-29 07:26:37 -04:00
for ( i = 0 ; i < name_count ; i + + ) {
ne = X509_NAME_get_entry ( a , i ) ;
obj = X509_NAME_ENTRY_get_object ( ne ) ;
data = X509_NAME_ENTRY_get_data ( ne ) ;
data_ptr = ASN1_STRING_get0_data ( data ) ;
data_len = ASN1_STRING_length ( data ) ;
n = OBJ_obj2nid ( obj ) ;
2012-10-17 11:39:35 -04:00
if ( ( n = = NID_undef ) | | ( ( s = OBJ_nid2sn ( n ) ) = = NULL ) ) {
2016-08-29 07:26:37 -04:00
i2t_ASN1_OBJECT ( tmp , sizeof ( tmp ) , obj ) ;
2012-10-17 11:39:35 -04:00
s = tmp ;
}
ln = strlen ( s ) ;
2016-08-29 07:26:37 -04:00
l + = 1 + ln + 1 + data_len ;
2012-10-17 11:39:35 -04:00
if ( l > out - > size )
return - 1 ;
2018-07-13 04:54:26 -04:00
out - > data = l ;
2012-10-17 11:39:35 -04:00
* ( p + + ) = ' / ' ;
memcpy ( p , s , ln ) ;
p + = ln ;
* ( p + + ) = ' = ' ;
2016-08-29 07:26:37 -04:00
memcpy ( p , data_ptr , data_len ) ;
p + = data_len ;
2012-10-17 11:39:35 -04:00
}
2018-07-13 04:54:26 -04:00
if ( ! out - > data )
2012-10-17 11:39:35 -04:00
return 0 ;
return 1 ;
}
2018-12-21 13:45:40 -05:00
void ssl_sock_set_alpn ( struct connection * conn , const unsigned char * alpn , int len )
{
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
SSL_set_alpn_protos ( conn - > xprt_ctx , alpn , len ) ;
# endif
}
2016-12-22 15:58:38 -05:00
/* Sets advertised SNI for outgoing connections. Please set <hostname> to NULL
* to disable SNI .
*/
2015-07-10 05:33:32 -04:00
void ssl_sock_set_servername ( struct connection * conn , const char * hostname )
{
# ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
2016-12-22 15:58:38 -05:00
char * prev_name ;
2015-07-10 05:33:32 -04:00
if ( ! ssl_sock_is_ssl ( conn ) )
return ;
2016-12-22 15:58:38 -05:00
/* if the SNI changes, we must destroy the reusable context so that a
* new connection will present a new SNI . As an optimization we could
* later imagine having a small cache of ssl_ctx to hold a few SNI per
* server .
*/
prev_name = ( char * ) SSL_get_servername ( conn - > xprt_ctx , TLSEXT_NAMETYPE_host_name ) ;
if ( ( ! prev_name & & hostname ) | |
( prev_name & & ( ! hostname | | strcmp ( hostname , prev_name ) ! = 0 ) ) )
SSL_set_session ( conn - > xprt_ctx , NULL ) ;
2015-07-10 05:33:32 -04:00
SSL_set_tlsext_host_name ( conn - > xprt_ctx , hostname ) ;
# endif
}
2014-06-24 12:26:41 -04:00
/* Extract peer certificate's common name into the chunk dest
* Returns
* the len of the extracted common name
* or 0 if no CN found in DN
* or - 1 on error case ( i . e . no peer certificate )
*/
2018-07-13 05:56:34 -04:00
int ssl_sock_get_remote_common_name ( struct connection * conn ,
struct buffer * dest )
2014-05-08 23:42:08 -04:00
{
X509 * crt = NULL ;
X509_NAME * name ;
const char find_cn [ ] = " CN " ;
2018-07-13 05:56:34 -04:00
const struct buffer find_cn_chunk = {
2018-07-13 04:54:26 -04:00
. area = ( char * ) & find_cn ,
. data = sizeof ( find_cn ) - 1
2014-05-08 23:42:08 -04:00
} ;
2014-06-24 12:26:41 -04:00
int result = - 1 ;
2014-05-08 23:42:08 -04:00
if ( ! ssl_sock_is_ssl ( conn ) )
2014-06-24 12:26:41 -04:00
goto out ;
2014-05-08 23:42:08 -04:00
/* SSL_get_peer_certificate, it increase X509 * ref count */
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
if ( ! crt )
goto out ;
name = X509_get_subject_name ( crt ) ;
if ( ! name )
goto out ;
2014-06-24 12:26:41 -04:00
result = ssl_sock_get_dn_entry ( name , & find_cn_chunk , 1 , dest ) ;
out :
2014-05-08 23:42:08 -04:00
if ( crt )
X509_free ( crt ) ;
return result ;
}
2014-07-30 10:39:13 -04:00
/* returns 1 if client passed a certificate for this session, 0 if not */
int ssl_sock_get_cert_used_sess ( struct connection * conn )
{
X509 * crt = NULL ;
if ( ! ssl_sock_is_ssl ( conn ) )
return 0 ;
/* SSL_get_peer_certificate, it increase X509 * ref count */
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
if ( ! crt )
return 0 ;
X509_free ( crt ) ;
return 1 ;
}
/* returns 1 if client passed a certificate for this connection, 0 if not */
int ssl_sock_get_cert_used_conn ( struct connection * conn )
2014-05-08 23:42:08 -04:00
{
if ( ! ssl_sock_is_ssl ( conn ) )
return 0 ;
return SSL_SOCK_ST_FL_VERIFY_DONE & conn - > xprt_st ? 1 : 0 ;
}
/* returns result from SSL verify */
unsigned int ssl_sock_get_verify_result ( struct connection * conn )
{
if ( ! ssl_sock_is_ssl ( conn ) )
return ( unsigned int ) X509_V_ERR_APPLICATION_VERIFICATION ;
return ( unsigned int ) SSL_get_verify_result ( conn - > xprt_ctx ) ;
}
2016-12-04 12:44:29 -05:00
/* Returns the application layer protocol name in <str> and <len> when known.
* Zero is returned if the protocol name was not found , otherwise non - zero is
* returned . The string is allocated in the SSL context and doesn ' t have to be
* freed by the caller . NPN is also checked if available since older versions
* of openssl ( 1.0 .1 ) which are more common in field only support this one .
*/
static int ssl_sock_get_alpn ( const struct connection * conn , const char * * str , int * len )
{
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
return 0 ;
* str = NULL ;
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
SSL_get0_alpn_selected ( conn - > xprt_ctx , ( const unsigned char * * ) str , ( unsigned * ) len ) ;
if ( * str )
return 1 ;
# endif
2018-02-15 07:34:58 -05:00
# if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2016-12-04 12:44:29 -05:00
SSL_get0_next_proto_negotiated ( conn - > xprt_ctx , ( const unsigned char * * ) str , ( unsigned * ) len ) ;
if ( * str )
return 1 ;
# endif
return 0 ;
}
2012-09-10 02:20:03 -04:00
/***** Below are some sample fetching functions for ACL/patterns *****/
2017-10-02 05:51:03 -04:00
static int
smp_fetch_ssl_fc_has_early ( const struct arg * args , struct sample * smp , const char * kw , void * private )
{
struct connection * conn ;
conn = objt_conn ( smp - > sess - > origin ) ;
if ( ! conn | | conn - > xprt ! = & ssl_sock )
return 0 ;
smp - > flags = 0 ;
smp - > data . type = SMP_T_BOOL ;
2017-11-29 13:51:19 -05:00
smp - > data . u . sint = ( ( conn - > flags & CO_FL_EARLY_DATA ) & &
( conn - > flags & ( CO_FL_EARLY_SSL_HS | CO_FL_HANDSHAKE ) ) ) ? 1 : 0 ;
2017-10-02 05:51:03 -04:00
return 1 ;
}
2012-09-21 07:15:06 -04:00
/* boolean, returns true if client cert was present */
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_fc_has_crt ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-09-21 07:15:06 -04:00
{
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
2012-09-21 07:15:06 -04:00
return 0 ;
2013-10-01 04:45:07 -04:00
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-09-21 07:15:06 -04:00
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
smp - > flags = 0 ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_BOOL ;
2015-08-19 03:07:19 -04:00
smp - > data . u . sint = SSL_SOCK_ST_FL_VERIFY_DONE & conn - > xprt_st ? 1 : 0 ;
2012-09-21 07:15:06 -04:00
return 1 ;
}
2014-10-29 14:03:26 -04:00
/* binary, returns a certificate in a binary chunk (der/raw).
* The 5 th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
* should be use .
*/
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_x_der ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2014-10-29 14:03:26 -04:00
{
int cert_peer = ( kw [ 4 ] = = ' c ' ) ? 1 : 0 ;
X509 * crt = NULL ;
int ret = 0 ;
2018-07-13 05:56:34 -04:00
struct buffer * smp_trash ;
2014-10-29 14:03:26 -04:00
struct connection * conn ;
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2014-10-29 14:03:26 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
return 0 ;
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
if ( cert_peer )
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
else
crt = SSL_get_certificate ( conn - > xprt_ctx ) ;
if ( ! crt )
goto out ;
smp_trash = get_trash_chunk ( ) ;
if ( ssl_sock_crt2der ( crt , smp_trash ) < = 0 )
goto out ;
2015-08-19 03:07:19 -04:00
smp - > data . u . str = * smp_trash ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_BIN ;
2014-10-29 14:03:26 -04:00
ret = 1 ;
out :
/* SSL_get_peer_certificate, it increase X509 * ref count */
if ( cert_peer & & crt )
X509_free ( crt ) ;
return ret ;
}
2014-04-30 11:05:08 -04:00
/* binary, returns serial of certificate in a binary chunk.
* The 5 th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
* should be use .
*/
2012-10-22 11:58:39 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_x_serial ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-22 11:58:39 -04:00
{
2014-04-30 11:05:08 -04:00
int cert_peer = ( kw [ 4 ] = = ' c ' ) ? 1 : 0 ;
2012-10-22 11:58:39 -04:00
X509 * crt = NULL ;
int ret = 0 ;
2018-07-13 05:56:34 -04:00
struct buffer * smp_trash ;
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
2012-10-22 11:58:39 -04:00
return 0 ;
2013-10-01 04:45:07 -04:00
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-10-22 11:58:39 -04:00
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
2014-04-30 11:05:08 -04:00
if ( cert_peer )
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
else
crt = SSL_get_certificate ( conn - > xprt_ctx ) ;
2012-10-22 11:58:39 -04:00
if ( ! crt )
goto out ;
2012-12-23 14:22:19 -05:00
smp_trash = get_trash_chunk ( ) ;
2012-10-22 11:58:39 -04:00
if ( ssl_sock_get_serial ( crt , smp_trash ) < = 0 )
goto out ;
2015-08-19 03:07:19 -04:00
smp - > data . u . str = * smp_trash ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_BIN ;
2012-10-22 11:58:39 -04:00
ret = 1 ;
out :
2014-04-30 11:05:08 -04:00
/* SSL_get_peer_certificate, it increase X509 * ref count */
if ( cert_peer & & crt )
2012-10-22 11:58:39 -04:00
X509_free ( crt ) ;
return ret ;
}
2012-09-21 07:15:06 -04:00
2014-04-30 11:05:08 -04:00
/* binary, returns the client certificate's SHA-1 fingerprint (SHA-1 hash of DER-encoded certificate) in a binary chunk.
* The 5 th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
* should be use .
*/
2013-05-14 14:37:59 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_x_sha1 ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2013-05-14 14:37:59 -04:00
{
2014-04-30 11:05:08 -04:00
int cert_peer = ( kw [ 4 ] = = ' c ' ) ? 1 : 0 ;
2013-05-14 14:37:59 -04:00
X509 * crt = NULL ;
const EVP_MD * digest ;
int ret = 0 ;
2018-07-13 05:56:34 -04:00
struct buffer * smp_trash ;
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
2013-05-14 14:37:59 -04:00
return 0 ;
2013-10-01 04:45:07 -04:00
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2013-05-14 14:37:59 -04:00
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
2014-04-30 11:05:08 -04:00
if ( cert_peer )
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
else
crt = SSL_get_certificate ( conn - > xprt_ctx ) ;
2013-05-14 14:37:59 -04:00
if ( ! crt )
goto out ;
smp_trash = get_trash_chunk ( ) ;
digest = EVP_sha1 ( ) ;
2018-07-13 04:54:26 -04:00
X509_digest ( crt , digest , ( unsigned char * ) smp_trash - > area ,
( unsigned int * ) & smp_trash - > data ) ;
2013-05-14 14:37:59 -04:00
2015-08-19 03:07:19 -04:00
smp - > data . u . str = * smp_trash ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_BIN ;
2013-05-14 14:37:59 -04:00
ret = 1 ;
out :
2014-04-30 11:05:08 -04:00
/* SSL_get_peer_certificate, it increase X509 * ref count */
if ( cert_peer & & crt )
2013-05-14 14:37:59 -04:00
X509_free ( crt ) ;
return ret ;
}
2014-04-30 11:05:08 -04:00
/* string, returns certificate's notafter date in ASN1_UTCTIME format.
* The 5 th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
* should be use .
*/
2012-10-22 08:11:22 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_x_notafter ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-22 08:11:22 -04:00
{
2014-04-30 11:05:08 -04:00
int cert_peer = ( kw [ 4 ] = = ' c ' ) ? 1 : 0 ;
2012-10-22 08:11:22 -04:00
X509 * crt = NULL ;
int ret = 0 ;
2018-07-13 05:56:34 -04:00
struct buffer * smp_trash ;
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2012-10-22 08:11:22 -04:00
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
return 0 ;
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-10-22 08:11:22 -04:00
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
2014-04-30 11:05:08 -04:00
if ( cert_peer )
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
else
crt = SSL_get_certificate ( conn - > xprt_ctx ) ;
2012-10-22 08:11:22 -04:00
if ( ! crt )
goto out ;
2012-12-23 14:22:19 -05:00
smp_trash = get_trash_chunk ( ) ;
2018-12-14 11:47:02 -05:00
if ( ssl_sock_get_time ( X509_getm_notAfter ( crt ) , smp_trash ) < = 0 )
2012-10-22 08:11:22 -04:00
goto out ;
2015-08-19 03:07:19 -04:00
smp - > data . u . str = * smp_trash ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_STR ;
2012-10-22 08:11:22 -04:00
ret = 1 ;
out :
2014-04-30 11:05:08 -04:00
/* SSL_get_peer_certificate, it increase X509 * ref count */
if ( cert_peer & & crt )
2012-10-22 08:11:22 -04:00
X509_free ( crt ) ;
return ret ;
}
2014-04-30 11:05:08 -04:00
/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's issuer
* The 5 th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
* should be use .
*/
2012-10-17 11:39:35 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_x_i_dn ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-17 11:39:35 -04:00
{
2014-04-30 11:05:08 -04:00
int cert_peer = ( kw [ 4 ] = = ' c ' ) ? 1 : 0 ;
2012-10-17 11:39:35 -04:00
X509 * crt = NULL ;
X509_NAME * name ;
int ret = 0 ;
2018-07-13 05:56:34 -04:00
struct buffer * smp_trash ;
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2012-10-17 11:39:35 -04:00
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
return 0 ;
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-10-17 11:39:35 -04:00
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
2014-04-30 11:05:08 -04:00
if ( cert_peer )
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
else
crt = SSL_get_certificate ( conn - > xprt_ctx ) ;
2012-10-17 11:39:35 -04:00
if ( ! crt )
goto out ;
name = X509_get_issuer_name ( crt ) ;
if ( ! name )
goto out ;
2012-12-23 14:22:19 -05:00
smp_trash = get_trash_chunk ( ) ;
2012-10-17 11:39:35 -04:00
if ( args & & args [ 0 ] . type = = ARGT_STR ) {
int pos = 1 ;
if ( args [ 1 ] . type = = ARGT_SINT )
pos = args [ 1 ] . data . sint ;
if ( ssl_sock_get_dn_entry ( name , & args [ 0 ] . data . str , pos , smp_trash ) < = 0 )
goto out ;
}
else if ( ssl_sock_get_dn_oneline ( name , smp_trash ) < = 0 )
goto out ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_STR ;
2015-08-19 03:07:19 -04:00
smp - > data . u . str = * smp_trash ;
2012-10-17 11:39:35 -04:00
ret = 1 ;
out :
2014-04-30 11:05:08 -04:00
/* SSL_get_peer_certificate, it increase X509 * ref count */
if ( cert_peer & & crt )
2012-10-17 11:39:35 -04:00
X509_free ( crt ) ;
return ret ;
}
2014-04-30 11:05:08 -04:00
/* string, returns notbefore date in ASN1_UTCTIME format.
* The 5 th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
* should be use .
*/
2012-10-22 08:11:22 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_x_notbefore ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-22 08:11:22 -04:00
{
2014-04-30 11:05:08 -04:00
int cert_peer = ( kw [ 4 ] = = ' c ' ) ? 1 : 0 ;
2012-10-22 08:11:22 -04:00
X509 * crt = NULL ;
int ret = 0 ;
2018-07-13 05:56:34 -04:00
struct buffer * smp_trash ;
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2012-10-22 08:11:22 -04:00
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
return 0 ;
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-10-22 08:11:22 -04:00
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
2014-04-30 11:05:08 -04:00
if ( cert_peer )
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
else
crt = SSL_get_certificate ( conn - > xprt_ctx ) ;
2012-10-22 08:11:22 -04:00
if ( ! crt )
goto out ;
2012-12-23 14:22:19 -05:00
smp_trash = get_trash_chunk ( ) ;
2018-12-14 11:47:02 -05:00
if ( ssl_sock_get_time ( X509_getm_notBefore ( crt ) , smp_trash ) < = 0 )
2012-10-22 08:11:22 -04:00
goto out ;
2015-08-19 03:07:19 -04:00
smp - > data . u . str = * smp_trash ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_STR ;
2012-10-22 08:11:22 -04:00
ret = 1 ;
out :
2014-04-30 11:05:08 -04:00
/* SSL_get_peer_certificate, it increase X509 * ref count */
if ( cert_peer & & crt )
2012-10-22 08:11:22 -04:00
X509_free ( crt ) ;
return ret ;
}
2014-04-30 11:05:08 -04:00
/* string, returns a string of a formatted full dn \C=..\O=..\OU=.. \CN=.. of certificate's subject
* The 5 th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
* should be use .
*/
2012-10-17 11:39:35 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_x_s_dn ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-17 11:39:35 -04:00
{
2014-04-30 11:05:08 -04:00
int cert_peer = ( kw [ 4 ] = = ' c ' ) ? 1 : 0 ;
2012-10-17 11:39:35 -04:00
X509 * crt = NULL ;
X509_NAME * name ;
int ret = 0 ;
2018-07-13 05:56:34 -04:00
struct buffer * smp_trash ;
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2012-10-17 11:39:35 -04:00
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
return 0 ;
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-10-17 11:39:35 -04:00
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
2014-04-30 11:05:08 -04:00
if ( cert_peer )
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
else
crt = SSL_get_certificate ( conn - > xprt_ctx ) ;
2012-10-17 11:39:35 -04:00
if ( ! crt )
goto out ;
name = X509_get_subject_name ( crt ) ;
if ( ! name )
goto out ;
2012-12-23 14:22:19 -05:00
smp_trash = get_trash_chunk ( ) ;
2012-10-17 11:39:35 -04:00
if ( args & & args [ 0 ] . type = = ARGT_STR ) {
int pos = 1 ;
if ( args [ 1 ] . type = = ARGT_SINT )
pos = args [ 1 ] . data . sint ;
if ( ssl_sock_get_dn_entry ( name , & args [ 0 ] . data . str , pos , smp_trash ) < = 0 )
goto out ;
}
else if ( ssl_sock_get_dn_oneline ( name , smp_trash ) < = 0 )
goto out ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_STR ;
2015-08-19 03:07:19 -04:00
smp - > data . u . str = * smp_trash ;
2012-10-17 11:39:35 -04:00
ret = 1 ;
out :
2014-04-30 11:05:08 -04:00
/* SSL_get_peer_certificate, it increase X509 * ref count */
if ( cert_peer & & crt )
2012-10-17 11:39:35 -04:00
X509_free ( crt ) ;
return ret ;
}
2012-12-20 09:44:16 -05:00
/* integer, returns true if current session use a client certificate */
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_c_used ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-12-20 09:44:16 -05:00
{
X509 * crt ;
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
2012-12-20 09:44:16 -05:00
return 0 ;
2013-10-01 04:45:07 -04:00
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-12-20 09:44:16 -05:00
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
/* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
2013-10-01 04:45:07 -04:00
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
2012-12-20 09:44:16 -05:00
if ( crt ) {
X509_free ( crt ) ;
}
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_BOOL ;
2015-08-19 03:07:19 -04:00
smp - > data . u . sint = ( crt ! = NULL ) ;
2012-12-20 09:44:16 -05:00
return 1 ;
}
2014-04-30 11:05:08 -04:00
/* integer, returns the certificate version
* The 5 th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
* should be use .
*/
2012-10-17 09:03:11 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_x_version ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-17 09:03:11 -04:00
{
2014-04-30 11:05:08 -04:00
int cert_peer = ( kw [ 4 ] = = ' c ' ) ? 1 : 0 ;
2012-10-17 09:03:11 -04:00
X509 * crt ;
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
2012-10-17 09:03:11 -04:00
return 0 ;
2013-10-01 04:45:07 -04:00
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-10-17 09:03:11 -04:00
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
2014-04-30 11:05:08 -04:00
if ( cert_peer )
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
else
crt = SSL_get_certificate ( conn - > xprt_ctx ) ;
2012-10-17 09:03:11 -04:00
if ( ! crt )
return 0 ;
2015-08-19 03:07:19 -04:00
smp - > data . u . sint = ( unsigned int ) ( 1 + X509_get_version ( crt ) ) ;
2014-04-30 11:05:08 -04:00
/* SSL_get_peer_certificate increase X509 * ref count */
if ( cert_peer )
X509_free ( crt ) ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_SINT ;
2012-10-17 09:03:11 -04:00
return 1 ;
}
2014-04-30 11:05:08 -04:00
/* string, returns the certificate's signature algorithm.
* The 5 th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
* should be use .
*/
2012-10-19 12:15:40 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_x_sig_alg ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-19 12:15:40 -04:00
{
2014-04-30 11:05:08 -04:00
int cert_peer = ( kw [ 4 ] = = ' c ' ) ? 1 : 0 ;
2012-10-19 12:15:40 -04:00
X509 * crt ;
2016-08-29 07:26:37 -04:00
__OPENSSL_110_CONST__ ASN1_OBJECT * algorithm ;
2012-10-19 12:15:40 -04:00
int nid ;
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
2012-10-19 12:15:40 -04:00
return 0 ;
2013-10-01 04:45:07 -04:00
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-10-19 12:15:40 -04:00
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
2014-04-30 11:05:08 -04:00
if ( cert_peer )
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
else
crt = SSL_get_certificate ( conn - > xprt_ctx ) ;
2012-10-19 12:15:40 -04:00
if ( ! crt )
return 0 ;
2016-08-29 07:26:37 -04:00
X509_ALGOR_get0 ( & algorithm , NULL , NULL , X509_get0_tbs_sigalg ( crt ) ) ;
nid = OBJ_obj2nid ( algorithm ) ;
2012-10-19 12:15:40 -04:00
2018-07-13 04:54:26 -04:00
smp - > data . u . str . area = ( char * ) OBJ_nid2sn ( nid ) ;
if ( ! smp - > data . u . str . area ) {
2014-04-30 11:05:08 -04:00
/* SSL_get_peer_certificate increase X509 * ref count */
if ( cert_peer )
X509_free ( crt ) ;
2012-10-19 12:15:40 -04:00
return 0 ;
2013-10-07 08:31:44 -04:00
}
2012-10-19 12:15:40 -04:00
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_STR ;
2013-12-16 18:20:33 -05:00
smp - > flags | = SMP_F_CONST ;
2018-07-13 04:54:26 -04:00
smp - > data . u . str . data = strlen ( smp - > data . u . str . area ) ;
2014-04-30 11:05:08 -04:00
/* SSL_get_peer_certificate increase X509 * ref count */
if ( cert_peer )
X509_free ( crt ) ;
2012-10-19 12:15:40 -04:00
return 1 ;
}
2014-04-30 11:05:08 -04:00
/* string, returns the certificate's key algorithm.
* The 5 th keyword char is used to know if SSL_get_certificate or SSL_get_peer_certificate
* should be use .
*/
2012-10-22 06:22:55 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_x_key_alg ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-22 06:22:55 -04:00
{
2014-04-30 11:05:08 -04:00
int cert_peer = ( kw [ 4 ] = = ' c ' ) ? 1 : 0 ;
2012-10-22 06:22:55 -04:00
X509 * crt ;
2016-08-29 07:26:37 -04:00
ASN1_OBJECT * algorithm ;
2012-10-22 06:22:55 -04:00
int nid ;
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
2012-10-22 06:22:55 -04:00
return 0 ;
2013-10-01 04:45:07 -04:00
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-10-22 06:22:55 -04:00
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
2014-04-30 11:05:08 -04:00
if ( cert_peer )
crt = SSL_get_peer_certificate ( conn - > xprt_ctx ) ;
else
crt = SSL_get_certificate ( conn - > xprt_ctx ) ;
2012-10-22 06:22:55 -04:00
if ( ! crt )
return 0 ;
2016-08-29 07:26:37 -04:00
X509_PUBKEY_get0_param ( & algorithm , NULL , NULL , NULL , X509_get_X509_PUBKEY ( crt ) ) ;
nid = OBJ_obj2nid ( algorithm ) ;
2012-10-22 06:22:55 -04:00
2018-07-13 04:54:26 -04:00
smp - > data . u . str . area = ( char * ) OBJ_nid2sn ( nid ) ;
if ( ! smp - > data . u . str . area ) {
2014-04-30 11:05:08 -04:00
/* SSL_get_peer_certificate increase X509 * ref count */
if ( cert_peer )
X509_free ( crt ) ;
2012-10-22 06:22:55 -04:00
return 0 ;
2013-10-07 08:31:44 -04:00
}
2012-10-22 06:22:55 -04:00
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_STR ;
2013-12-16 18:20:33 -05:00
smp - > flags | = SMP_F_CONST ;
2018-07-13 04:54:26 -04:00
smp - > data . u . str . data = strlen ( smp - > data . u . str . area ) ;
2014-04-30 11:05:08 -04:00
if ( cert_peer )
X509_free ( crt ) ;
2012-10-22 06:22:55 -04:00
return 1 ;
}
2014-04-30 08:21:06 -04:00
/* boolean, returns true if front conn. transport layer is SSL.
* This function is also usable on backend conn if the fetch keyword 5 th
* char is ' b ' .
*/
2012-09-10 02:20:03 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_fc ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-09-10 02:20:03 -04:00
{
2018-02-19 09:59:48 -05:00
struct connection * conn = ( kw [ 4 ] ! = ' b ' ) ? objt_conn ( smp - > sess - > origin ) :
smp - > strm ? cs_conn ( objt_cs ( smp - > strm - > si [ 1 ] . end ) ) : NULL ;
2013-10-01 04:45:07 -04:00
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_BOOL ;
2015-08-19 03:07:19 -04:00
smp - > data . u . sint = ( conn & & conn - > xprt = = & ssl_sock ) ;
2012-09-10 02:20:03 -04:00
return 1 ;
}
2012-10-18 09:59:43 -04:00
/* boolean, returns true if client present a SNI */
2012-09-10 02:20:03 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_fc_has_sni ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-09-10 02:20:03 -04:00
{
# ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
2015-05-11 09:20:49 -04:00
struct connection * conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_BOOL ;
2015-08-19 03:07:19 -04:00
smp - > data . u . sint = ( conn & & conn - > xprt = = & ssl_sock ) & &
2013-10-01 04:45:07 -04:00
conn - > xprt_ctx & &
SSL_get_servername ( conn - > xprt_ctx , TLSEXT_NAMETYPE_host_name ) ! = NULL ;
2012-09-10 02:20:03 -04:00
return 1 ;
# else
return 0 ;
# endif
}
2018-02-19 10:14:12 -05:00
/* boolean, returns true if client session has been resumed.
* This function is also usable on backend conn if the fetch keyword 5 th
* char is ' b ' .
*/
2015-05-17 20:28:57 -04:00
static int
smp_fetch_ssl_fc_is_resumed ( const struct arg * args , struct sample * smp , const char * kw , void * private )
{
2018-02-19 10:14:12 -05:00
struct connection * conn = ( kw [ 4 ] ! = ' b ' ) ? objt_conn ( smp - > sess - > origin ) :
smp - > strm ? cs_conn ( objt_cs ( smp - > strm - > si [ 1 ] . end ) ) : NULL ;
2015-05-17 20:28:57 -04:00
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_BOOL ;
2015-08-19 03:07:19 -04:00
smp - > data . u . sint = ( conn & & conn - > xprt = = & ssl_sock ) & &
2015-05-17 20:28:57 -04:00
conn - > xprt_ctx & &
SSL_session_reused ( conn - > xprt_ctx ) ;
return 1 ;
}
2014-04-30 08:21:06 -04:00
/* string, returns the used cipher if front conn. transport layer is SSL.
* This function is also usable on backend conn if the fetch keyword 5 th
* char is ' b ' .
*/
2012-10-16 08:13:26 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_fc_cipher ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-16 08:13:26 -04:00
{
2018-02-19 09:59:48 -05:00
struct connection * conn = ( kw [ 4 ] ! = ' b ' ) ? objt_conn ( smp - > sess - > origin ) :
smp - > strm ? cs_conn ( objt_cs ( smp - > strm - > si [ 1 ] . end ) ) : NULL ;
2012-10-16 08:13:26 -04:00
2016-03-10 05:47:01 -05:00
smp - > flags = 0 ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
2012-10-16 08:13:26 -04:00
return 0 ;
2018-07-13 04:54:26 -04:00
smp - > data . u . str . area = ( char * ) SSL_get_cipher_name ( conn - > xprt_ctx ) ;
if ( ! smp - > data . u . str . area )
2012-10-16 08:13:26 -04:00
return 0 ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_STR ;
2013-12-16 18:20:33 -05:00
smp - > flags | = SMP_F_CONST ;
2018-07-13 04:54:26 -04:00
smp - > data . u . str . data = strlen ( smp - > data . u . str . area ) ;
2012-10-16 08:13:26 -04:00
return 1 ;
}
2014-04-30 08:21:06 -04:00
/* integer, returns the algoritm's keysize if front conn. transport layer
* is SSL .
* This function is also usable on backend conn if the fetch keyword 5 th
* char is ' b ' .
*/
2012-10-16 08:13:26 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_fc_alg_keysize ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-16 08:13:26 -04:00
{
2018-02-19 09:59:48 -05:00
struct connection * conn = ( kw [ 4 ] ! = ' b ' ) ? objt_conn ( smp - > sess - > origin ) :
smp - > strm ? cs_conn ( objt_cs ( smp - > strm - > si [ 1 ] . end ) ) : NULL ;
2016-03-10 11:05:28 -05:00
int sint ;
2016-03-10 05:47:01 -05:00
2012-10-16 08:13:26 -04:00
smp - > flags = 0 ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
2012-10-16 08:13:26 -04:00
return 0 ;
2015-07-06 17:43:03 -04:00
if ( ! SSL_get_cipher_bits ( conn - > xprt_ctx , & sint ) )
2012-10-16 08:13:26 -04:00
return 0 ;
2015-08-19 03:07:19 -04:00
smp - > data . u . sint = sint ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_SINT ;
2012-10-16 08:13:26 -04:00
return 1 ;
}
2014-04-30 08:21:06 -04:00
/* integer, returns the used keysize if front conn. transport layer is SSL.
* This function is also usable on backend conn if the fetch keyword 5 th
* char is ' b ' .
*/
2012-10-16 08:13:26 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_fc_use_keysize ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-16 08:13:26 -04:00
{
2018-02-19 09:59:48 -05:00
struct connection * conn = ( kw [ 4 ] ! = ' b ' ) ? objt_conn ( smp - > sess - > origin ) :
smp - > strm ? cs_conn ( objt_cs ( smp - > strm - > si [ 1 ] . end ) ) : NULL ;
2016-03-10 05:47:01 -05:00
2012-10-16 08:13:26 -04:00
smp - > flags = 0 ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
2012-10-16 08:13:26 -04:00
return 0 ;
2015-08-19 03:07:19 -04:00
smp - > data . u . sint = ( unsigned int ) SSL_get_cipher_bits ( conn - > xprt_ctx , NULL ) ;
if ( ! smp - > data . u . sint )
2012-10-16 08:13:26 -04:00
return 0 ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_SINT ;
2012-10-16 08:13:26 -04:00
return 1 ;
}
2018-02-15 07:34:58 -05:00
# if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2012-10-15 07:19:06 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_fc_npn ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-15 07:19:06 -04:00
{
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2013-12-16 18:20:33 -05:00
smp - > flags = SMP_F_CONST ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_STR ;
2012-10-15 07:19:06 -04:00
2018-11-22 12:18:29 -05:00
conn = ( kw [ 4 ] ! = ' b ' ) ? objt_conn ( smp - > sess - > origin ) :
smp - > strm ? cs_conn ( objt_cs ( smp - > strm - > si [ 1 ] . end ) ) : NULL ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
2012-10-15 07:19:06 -04:00
return 0 ;
2018-07-13 04:54:26 -04:00
smp - > data . u . str . area = NULL ;
2013-10-01 04:45:07 -04:00
SSL_get0_next_proto_negotiated ( conn - > xprt_ctx ,
2018-07-13 04:54:26 -04:00
( const unsigned char * * ) & smp - > data . u . str . area ,
( unsigned * ) & smp - > data . u . str . data ) ;
2012-10-15 07:19:06 -04:00
2018-07-13 04:54:26 -04:00
if ( ! smp - > data . u . str . area )
2012-10-15 07:19:06 -04:00
return 0 ;
return 1 ;
}
2012-10-18 12:57:14 -04:00
# endif
2012-10-15 07:19:06 -04:00
2014-02-13 06:29:42 -05:00
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2013-04-01 20:30:41 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_fc_alpn ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2013-04-01 20:30:41 -04:00
{
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2013-12-16 18:20:33 -05:00
smp - > flags = SMP_F_CONST ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_STR ;
2013-04-01 20:30:41 -04:00
2018-11-22 12:18:29 -05:00
conn = ( kw [ 4 ] ! = ' b ' ) ? objt_conn ( smp - > sess - > origin ) :
smp - > strm ? cs_conn ( objt_cs ( smp - > strm - > si [ 1 ] . end ) ) : NULL ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
2013-04-01 20:30:41 -04:00
return 0 ;
2018-07-13 04:54:26 -04:00
smp - > data . u . str . area = NULL ;
2014-02-13 06:29:42 -05:00
SSL_get0_alpn_selected ( conn - > xprt_ctx ,
2018-07-13 04:54:26 -04:00
( const unsigned char * * ) & smp - > data . u . str . area ,
( unsigned * ) & smp - > data . u . str . data ) ;
2013-04-01 20:30:41 -04:00
2018-07-13 04:54:26 -04:00
if ( ! smp - > data . u . str . area )
2013-04-01 20:30:41 -04:00
return 0 ;
return 1 ;
}
# endif
2014-04-30 08:21:06 -04:00
/* string, returns the used protocol if front conn. transport layer is SSL.
* This function is also usable on backend conn if the fetch keyword 5 th
* char is ' b ' .
*/
2012-10-16 08:13:26 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_fc_protocol ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-16 08:13:26 -04:00
{
2018-02-19 09:59:48 -05:00
struct connection * conn = ( kw [ 4 ] ! = ' b ' ) ? objt_conn ( smp - > sess - > origin ) :
smp - > strm ? cs_conn ( objt_cs ( smp - > strm - > si [ 1 ] . end ) ) : NULL ;
2016-03-10 05:47:01 -05:00
2012-10-16 08:13:26 -04:00
smp - > flags = 0 ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
2012-10-16 08:13:26 -04:00
return 0 ;
2018-07-13 04:54:26 -04:00
smp - > data . u . str . area = ( char * ) SSL_get_version ( conn - > xprt_ctx ) ;
if ( ! smp - > data . u . str . area )
2012-10-16 08:13:26 -04:00
return 0 ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_STR ;
2013-12-16 18:20:33 -05:00
smp - > flags = SMP_F_CONST ;
2018-07-13 04:54:26 -04:00
smp - > data . u . str . data = strlen ( smp - > data . u . str . area ) ;
2012-10-16 08:13:26 -04:00
return 1 ;
}
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
/* binary, returns the SSL stream id if front conn. transport layer is SSL.
2014-04-30 08:21:06 -04:00
* This function is also usable on backend conn if the fetch keyword 5 th
* char is ' b ' .
*/
2018-04-28 19:15:48 -04:00
# if OPENSSL_VERSION_NUMBER > 0x0090800fL
2012-10-16 08:59:28 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_fc_session_id ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-10-16 08:59:28 -04:00
{
2018-02-19 09:59:48 -05:00
struct connection * conn = ( kw [ 4 ] ! = ' b ' ) ? objt_conn ( smp - > sess - > origin ) :
smp - > strm ? cs_conn ( objt_cs ( smp - > strm - > si [ 1 ] . end ) ) : NULL ;
2016-03-10 11:05:28 -05:00
SSL_SESSION * ssl_sess ;
2016-03-10 05:47:01 -05:00
2013-12-16 18:20:33 -05:00
smp - > flags = SMP_F_CONST ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_BIN ;
2012-10-16 08:59:28 -04:00
2013-10-01 04:45:07 -04:00
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
return 0 ;
2015-04-03 19:47:55 -04:00
ssl_sess = SSL_get_session ( conn - > xprt_ctx ) ;
if ( ! ssl_sess )
2012-10-16 08:59:28 -04:00
return 0 ;
2018-07-13 04:54:26 -04:00
smp - > data . u . str . area = ( char * ) SSL_SESSION_get_id ( ssl_sess ,
( unsigned int * ) & smp - > data . u . str . data ) ;
if ( ! smp - > data . u . str . area | | ! smp - > data . u . str . data )
2012-10-16 08:59:28 -04:00
return 0 ;
return 1 ;
}
2018-04-28 19:15:48 -04:00
# endif
2012-10-16 08:59:28 -04:00
2018-04-28 19:15:51 -04:00
# if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
static int
smp_fetch_ssl_fc_session_key ( const struct arg * args , struct sample * smp , const char * kw , void * private )
{
struct connection * conn = ( kw [ 4 ] ! = ' b ' ) ? objt_conn ( smp - > sess - > origin ) :
smp - > strm ? cs_conn ( objt_cs ( smp - > strm - > si [ 1 ] . end ) ) : NULL ;
SSL_SESSION * ssl_sess ;
2018-07-13 05:56:34 -04:00
struct buffer * data ;
2018-04-28 19:15:51 -04:00
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
return 0 ;
ssl_sess = SSL_get_session ( conn - > xprt_ctx ) ;
if ( ! ssl_sess )
return 0 ;
data = get_trash_chunk ( ) ;
2018-07-13 04:54:26 -04:00
data - > data = SSL_SESSION_get_master_key ( ssl_sess ,
( unsigned char * ) data - > area ,
data - > size ) ;
if ( ! data - > data )
2018-04-28 19:15:51 -04:00
return 0 ;
smp - > flags = 0 ;
smp - > data . type = SMP_T_BIN ;
smp - > data . u . str = * data ;
return 1 ;
}
# endif
2018-04-28 19:15:48 -04:00
# ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
2012-09-10 02:20:03 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_fc_sni ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-09-10 02:20:03 -04:00
{
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2013-12-16 18:20:33 -05:00
smp - > flags = SMP_F_CONST ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_STR ;
2012-09-10 02:20:03 -04:00
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
2012-09-10 02:20:03 -04:00
return 0 ;
2018-07-13 04:54:26 -04:00
smp - > data . u . str . area = ( char * ) SSL_get_servername ( conn - > xprt_ctx , TLSEXT_NAMETYPE_host_name ) ;
if ( ! smp - > data . u . str . area )
2012-09-14 17:56:58 -04:00
return 0 ;
2018-07-13 04:54:26 -04:00
smp - > data . u . str . data = strlen ( smp - > data . u . str . area ) ;
2012-09-10 02:20:03 -04:00
return 1 ;
}
2018-04-28 19:15:48 -04:00
# endif
2012-09-10 02:20:03 -04:00
2017-02-25 06:45:22 -05:00
static int
smp_fetch_ssl_fc_cl_bin ( const struct arg * args , struct sample * smp , const char * kw , void * private )
{
struct connection * conn ;
struct ssl_capture * capture ;
conn = objt_conn ( smp - > sess - > origin ) ;
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
return 0 ;
2017-03-07 12:34:58 -05:00
capture = SSL_get_ex_data ( conn - > xprt_ctx , ssl_capture_ptr_index ) ;
2017-02-25 06:45:22 -05:00
if ( ! capture )
return 0 ;
smp - > flags = SMP_F_CONST ;
smp - > data . type = SMP_T_BIN ;
2018-07-13 04:54:26 -04:00
smp - > data . u . str . area = capture - > ciphersuite ;
smp - > data . u . str . data = capture - > ciphersuite_len ;
2017-02-25 06:45:22 -05:00
return 1 ;
}
static int
smp_fetch_ssl_fc_cl_hex ( const struct arg * args , struct sample * smp , const char * kw , void * private )
{
2018-07-13 05:56:34 -04:00
struct buffer * data ;
2017-02-25 06:45:22 -05:00
if ( ! smp_fetch_ssl_fc_cl_bin ( args , smp , kw , private ) )
return 0 ;
data = get_trash_chunk ( ) ;
2018-07-13 04:54:26 -04:00
dump_binary ( data , smp - > data . u . str . area , smp - > data . u . str . data ) ;
2017-02-25 06:45:22 -05:00
smp - > data . type = SMP_T_BIN ;
smp - > data . u . str = * data ;
return 1 ;
}
static int
smp_fetch_ssl_fc_cl_xxh64 ( const struct arg * args , struct sample * smp , const char * kw , void * private )
{
struct connection * conn ;
struct ssl_capture * capture ;
conn = objt_conn ( smp - > sess - > origin ) ;
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
return 0 ;
2017-03-07 12:34:58 -05:00
capture = SSL_get_ex_data ( conn - > xprt_ctx , ssl_capture_ptr_index ) ;
2017-02-25 06:45:22 -05:00
if ( ! capture )
return 0 ;
smp - > data . type = SMP_T_SINT ;
smp - > data . u . sint = capture - > xxh64 ;
return 1 ;
}
static int
smp_fetch_ssl_fc_cl_str ( const struct arg * args , struct sample * smp , const char * kw , void * private )
{
2017-09-01 11:32:08 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && !defined(LIBRESSL_VERSION_NUMBER)
2018-07-13 05:56:34 -04:00
struct buffer * data ;
2017-02-25 06:45:22 -05:00
int i ;
if ( ! smp_fetch_ssl_fc_cl_bin ( args , smp , kw , private ) )
return 0 ;
data = get_trash_chunk ( ) ;
2018-07-13 04:54:26 -04:00
for ( i = 0 ; i + 1 < smp - > data . u . str . data ; i + = 2 ) {
2017-09-01 11:32:08 -04:00
const char * str ;
const SSL_CIPHER * cipher ;
2018-07-13 04:54:26 -04:00
const unsigned char * bin = ( const unsigned char * ) smp - > data . u . str . area + i ;
2017-09-01 11:32:08 -04:00
uint16_t id = ( bin [ 0 ] < < 8 ) | bin [ 1 ] ;
# if defined(OPENSSL_IS_BORINGSSL)
cipher = SSL_get_cipher_by_value ( id ) ;
# else
2018-10-15 05:01:59 -04:00
struct connection * conn = __objt_conn ( smp - > sess - > origin ) ;
2017-09-01 11:32:08 -04:00
cipher = SSL_CIPHER_find ( conn - > xprt_ctx , bin ) ;
# endif
str = SSL_CIPHER_get_name ( cipher ) ;
if ( ! str | | strcmp ( str , " (NONE) " ) = = 0 )
chunk_appendf ( data , " %sUNKNOWN(%04x) " , i = = 0 ? " " : " , " , id ) ;
2017-02-25 06:45:22 -05:00
else
chunk_appendf ( data , " %s%s " , i = = 0 ? " " : " , " , str ) ;
}
smp - > data . type = SMP_T_STR ;
smp - > data . u . str = * data ;
return 1 ;
# else
return smp_fetch_ssl_fc_cl_xxh64 ( args , smp , kw , private ) ;
# endif
}
2018-04-28 19:15:48 -04:00
# if OPENSSL_VERSION_NUMBER > 0x0090800fL
2014-04-08 18:48:47 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_fc_unique_id ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2014-04-08 18:48:47 -04:00
{
2018-02-19 09:59:48 -05:00
struct connection * conn = ( kw [ 4 ] ! = ' b ' ) ? objt_conn ( smp - > sess - > origin ) :
smp - > strm ? cs_conn ( objt_cs ( smp - > strm - > si [ 1 ] . end ) ) : NULL ;
2014-04-08 18:48:47 -04:00
int finished_len ;
2018-07-13 05:56:34 -04:00
struct buffer * finished_trash ;
2014-04-08 18:48:47 -04:00
smp - > flags = 0 ;
if ( ! conn | | ! conn - > xprt_ctx | | conn - > xprt ! = & ssl_sock )
return 0 ;
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
smp - > flags | = SMP_F_MAY_CHANGE ;
return 0 ;
}
finished_trash = get_trash_chunk ( ) ;
if ( ! SSL_session_reused ( conn - > xprt_ctx ) )
2018-07-13 04:54:26 -04:00
finished_len = SSL_get_peer_finished ( conn - > xprt_ctx ,
finished_trash - > area ,
finished_trash - > size ) ;
2014-04-08 18:48:47 -04:00
else
2018-07-13 04:54:26 -04:00
finished_len = SSL_get_finished ( conn - > xprt_ctx ,
finished_trash - > area ,
finished_trash - > size ) ;
2014-04-08 18:48:47 -04:00
if ( ! finished_len )
return 0 ;
2018-07-13 04:54:26 -04:00
finished_trash - > data = finished_len ;
2015-08-19 03:07:19 -04:00
smp - > data . u . str = * finished_trash ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_BIN ;
2014-04-08 18:48:47 -04:00
return 1 ;
}
2018-04-28 19:15:48 -04:00
# endif
2014-04-08 18:48:47 -04:00
2012-10-18 09:59:43 -04:00
/* integer, returns the first verify error in CA chain of client certificate chain. */
2012-09-21 09:27:54 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_c_ca_err ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-09-21 09:27:54 -04:00
{
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
2012-09-21 09:27:54 -04:00
return 0 ;
2013-10-01 04:45:07 -04:00
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-09-21 09:27:54 -04:00
smp - > flags = SMP_F_MAY_CHANGE ;
return 0 ;
}
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_SINT ;
2015-08-19 03:07:19 -04:00
smp - > data . u . sint = ( unsigned long long int ) SSL_SOCK_ST_TO_CA_ERROR ( conn - > xprt_st ) ;
2012-09-21 09:27:54 -04:00
smp - > flags = 0 ;
return 1 ;
}
2012-10-18 09:59:43 -04:00
/* integer, returns the depth of the first verify error in CA chain of client certificate chain. */
2012-09-21 09:27:54 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_c_ca_err_depth ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-09-21 09:27:54 -04:00
{
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
2012-09-21 09:27:54 -04:00
return 0 ;
2013-10-01 04:45:07 -04:00
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-09-21 09:27:54 -04:00
smp - > flags = SMP_F_MAY_CHANGE ;
return 0 ;
}
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_SINT ;
2015-08-19 03:07:19 -04:00
smp - > data . u . sint = ( long long int ) SSL_SOCK_ST_TO_CAEDEPTH ( conn - > xprt_st ) ;
2012-09-21 09:27:54 -04:00
smp - > flags = 0 ;
return 1 ;
}
2012-10-18 09:59:43 -04:00
/* integer, returns the first verify error on client certificate */
2012-09-21 09:27:54 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_c_err ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-09-21 09:27:54 -04:00
{
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
return 0 ;
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-09-21 09:27:54 -04:00
smp - > flags = SMP_F_MAY_CHANGE ;
return 0 ;
}
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_SINT ;
2015-08-19 03:07:19 -04:00
smp - > data . u . sint = ( long long int ) SSL_SOCK_ST_TO_CRTERROR ( conn - > xprt_st ) ;
2012-09-21 09:27:54 -04:00
smp - > flags = 0 ;
return 1 ;
}
2012-10-18 09:59:43 -04:00
/* integer, returns the verify result on client cert */
2012-09-21 09:27:20 -04:00
static int
2015-05-11 09:42:45 -04:00
smp_fetch_ssl_c_verify ( const struct arg * args , struct sample * smp , const char * kw , void * private )
2012-09-21 09:27:20 -04:00
{
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2015-05-11 09:20:49 -04:00
conn = objt_conn ( smp - > sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( ! conn | | conn - > xprt ! = & ssl_sock )
return 0 ;
if ( ! ( conn - > flags & CO_FL_CONNECTED ) ) {
2012-09-21 09:27:20 -04:00
smp - > flags = SMP_F_MAY_CHANGE ;
return 0 ;
}
2013-10-01 04:45:07 -04:00
if ( ! conn - > xprt_ctx )
2012-09-21 09:27:20 -04:00
return 0 ;
2015-08-19 03:00:18 -04:00
smp - > data . type = SMP_T_SINT ;
2015-08-19 03:07:19 -04:00
smp - > data . u . sint = ( long long int ) SSL_get_verify_result ( conn - > xprt_ctx ) ;
2012-09-21 09:27:20 -04:00
smp - > flags = 0 ;
return 1 ;
}
2012-10-05 06:00:26 -04:00
/* parse the "ca-file" bind keyword */
2016-12-29 12:26:15 -05:00
static int ssl_bind_parse_ca_file ( char * * args , int cur_arg , struct proxy * px , struct ssl_bind_conf * conf , char * * err )
2012-09-20 12:23:56 -04:00
{
if ( ! * args [ cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing CAfile path " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2016-12-22 17:12:01 -05:00
if ( ( * args [ cur_arg + 1 ] ! = ' / ' ) & & global_ssl . ca_base )
memprintf ( & conf - > ca_file , " %s/%s " , global_ssl . ca_base , args [ cur_arg + 1 ] ) ;
2012-10-11 10:11:36 -04:00
else
memprintf ( & conf - > ca_file , " %s " , args [ cur_arg + 1 ] ) ;
2012-10-02 12:42:10 -04:00
2012-09-20 12:23:56 -04:00
return 0 ;
}
2016-12-29 12:26:15 -05:00
static int bind_parse_ca_file ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
return ssl_bind_parse_ca_file ( args , cur_arg , px , & conf - > ssl_conf , err ) ;
}
2012-09-20 12:23:56 -04:00
2015-06-09 11:29:50 -04:00
/* parse the "ca-sign-file" bind keyword */
static int bind_parse_ca_sign_file ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
if ( ! * args [ cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing CAfile path " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2016-12-22 17:12:01 -05:00
if ( ( * args [ cur_arg + 1 ] ! = ' / ' ) & & global_ssl . ca_base )
memprintf ( & conf - > ca_sign_file , " %s/%s " , global_ssl . ca_base , args [ cur_arg + 1 ] ) ;
2015-06-09 11:29:50 -04:00
else
memprintf ( & conf - > ca_sign_file , " %s " , args [ cur_arg + 1 ] ) ;
return 0 ;
}
2016-11-13 11:37:11 -05:00
/* parse the "ca-sign-pass" bind keyword */
2015-06-09 11:29:50 -04:00
static int bind_parse_ca_sign_pass ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
if ( ! * args [ cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing CAkey password " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
memprintf ( & conf - > ca_sign_pass , " %s " , args [ cur_arg + 1 ] ) ;
return 0 ;
}
2012-09-14 01:53:05 -04:00
/* parse the "ciphers" bind keyword */
2016-12-29 12:26:15 -05:00
static int ssl_bind_parse_ciphers ( char * * args , int cur_arg , struct proxy * px , struct ssl_bind_conf * conf , char * * err )
2012-09-14 01:53:05 -04:00
{
if ( ! * args [ cur_arg + 1 ] ) {
2012-09-20 13:43:14 -04:00
memprintf ( err , " '%s' : missing cipher suite " , args [ cur_arg ] ) ;
2012-09-14 01:53:05 -04:00
return ERR_ALERT | ERR_FATAL ;
}
2012-10-05 09:47:31 -04:00
free ( conf - > ciphers ) ;
2012-09-20 10:48:07 -04:00
conf - > ciphers = strdup ( args [ cur_arg + 1 ] ) ;
2012-09-14 01:53:05 -04:00
return 0 ;
}
2016-12-29 12:26:15 -05:00
static int bind_parse_ciphers ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
return ssl_bind_parse_ciphers ( args , cur_arg , px , & conf - > ssl_conf , err ) ;
}
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
/* parse the "ciphersuites" bind keyword */
static int ssl_bind_parse_ciphersuites ( char * * args , int cur_arg , struct proxy * px , struct ssl_bind_conf * conf , char * * err )
{
if ( ! * args [ cur_arg + 1 ] ) {
memprintf ( err , " '%s' : missing cipher suite " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
free ( conf - > ciphersuites ) ;
conf - > ciphersuites = strdup ( args [ cur_arg + 1 ] ) ;
return 0 ;
}
static int bind_parse_ciphersuites ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
return ssl_bind_parse_ciphersuites ( args , cur_arg , px , & conf - > ssl_conf , err ) ;
}
# endif
2012-09-14 01:53:05 -04:00
/* parse the "crt" bind keyword */
2012-09-20 10:48:07 -04:00
static int bind_parse_crt ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
2012-09-14 01:53:05 -04:00
{
2013-08-13 10:59:39 -04:00
char path [ MAXPATHLEN ] ;
2014-04-14 12:05:41 -04:00
2012-09-14 01:53:05 -04:00
if ( ! * args [ cur_arg + 1 ] ) {
2012-09-20 13:43:14 -04:00
memprintf ( err , " '%s' : missing certificate location " , args [ cur_arg ] ) ;
2012-09-14 01:53:05 -04:00
return ERR_ALERT | ERR_FATAL ;
}
2016-12-22 17:12:01 -05:00
if ( ( * args [ cur_arg + 1 ] ! = ' / ' ) & & global_ssl . crt_base ) {
if ( ( strlen ( global_ssl . crt_base ) + 1 + strlen ( args [ cur_arg + 1 ] ) + 1 ) > MAXPATHLEN ) {
2012-10-02 12:42:10 -04:00
memprintf ( err , " '%s' : path too long " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2016-12-22 17:12:01 -05:00
snprintf ( path , sizeof ( path ) , " %s/%s " , global_ssl . crt_base , args [ cur_arg + 1 ] ) ;
2016-12-22 11:08:28 -05:00
if ( ssl_sock_load_cert ( path , conf , err ) > 0 )
2012-10-02 12:42:10 -04:00
return ERR_ALERT | ERR_FATAL ;
return 0 ;
}
2016-12-22 11:08:28 -05:00
if ( ssl_sock_load_cert ( args [ cur_arg + 1 ] , conf , err ) > 0 )
2012-09-14 01:53:05 -04:00
return ERR_ALERT | ERR_FATAL ;
return 0 ;
}
2013-01-22 09:31:15 -05:00
/* parse the "crt-list" bind keyword */
static int bind_parse_crt_list ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
if ( ! * args [ cur_arg + 1 ] ) {
memprintf ( err , " '%s' : missing certificate location " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2016-12-29 12:26:15 -05:00
if ( ssl_sock_load_cert_list_file ( args [ cur_arg + 1 ] , conf , px , err ) > 0 ) {
2013-04-02 11:35:58 -04:00
memprintf ( err , " '%s' : %s " , args [ cur_arg ] , * err ) ;
2013-01-22 09:31:15 -05:00
return ERR_ALERT | ERR_FATAL ;
2013-04-02 11:35:58 -04:00
}
2013-01-22 09:31:15 -05:00
return 0 ;
}
2012-10-05 06:00:26 -04:00
/* parse the "crl-file" bind keyword */
2016-12-29 12:26:15 -05:00
static int ssl_bind_parse_crl_file ( char * * args , int cur_arg , struct proxy * px , struct ssl_bind_conf * conf , char * * err )
2012-09-20 12:23:56 -04:00
{
2012-10-02 13:25:50 -04:00
# ifndef X509_V_FLAG_CRL_CHECK
if ( err )
memprintf ( err , " '%s' : library does not support CRL verify " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
# else
2012-09-20 12:23:56 -04:00
if ( ! * args [ cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing CRLfile path " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2016-12-22 17:12:01 -05:00
if ( ( * args [ cur_arg + 1 ] ! = ' / ' ) & & global_ssl . ca_base )
memprintf ( & conf - > crl_file , " %s/%s " , global_ssl . ca_base , args [ cur_arg + 1 ] ) ;
2012-10-11 10:11:36 -04:00
else
memprintf ( & conf - > crl_file , " %s " , args [ cur_arg + 1 ] ) ;
2012-10-02 12:42:10 -04:00
2012-09-20 12:23:56 -04:00
return 0 ;
2012-10-02 13:25:50 -04:00
# endif
2012-09-20 12:23:56 -04:00
}
2016-12-29 12:26:15 -05:00
static int bind_parse_crl_file ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
return ssl_bind_parse_crl_file ( args , cur_arg , px , & conf - > ssl_conf , err ) ;
}
2012-09-20 12:23:56 -04:00
2017-01-09 10:15:54 -05:00
/* parse the "curves" bind keyword keyword */
static int ssl_bind_parse_curves ( char * * args , int cur_arg , struct proxy * px , struct ssl_bind_conf * conf , char * * err )
{
# if OPENSSL_VERSION_NUMBER >= 0x1000200fL
if ( ! * args [ cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing curve suite " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
conf - > curves = strdup ( args [ cur_arg + 1 ] ) ;
return 0 ;
# else
if ( err )
memprintf ( err , " '%s' : library does not support curve suite " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
# endif
}
static int bind_parse_curves ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
return ssl_bind_parse_curves ( args , cur_arg , px , & conf - > ssl_conf , err ) ;
}
2016-11-13 11:37:11 -05:00
/* parse the "ecdhe" bind keyword keyword */
2016-12-29 12:26:15 -05:00
static int ssl_bind_parse_ecdhe ( char * * args , int cur_arg , struct proxy * px , struct ssl_bind_conf * conf , char * * err )
2012-09-20 11:10:03 -04:00
{
# if OPENSSL_VERSION_NUMBER < 0x0090800fL
if ( err )
memprintf ( err , " '%s' : library does not support elliptic curve Diffie-Hellman (too old) " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
# elif defined(OPENSSL_NO_ECDH)
if ( err )
memprintf ( err , " '%s' : library does not support elliptic curve Diffie-Hellman (disabled via OPENSSL_NO_ECDH) " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
# else
if ( ! * args [ cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing named curve " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
conf - > ecdhe = strdup ( args [ cur_arg + 1 ] ) ;
return 0 ;
# endif
}
2016-12-29 12:26:15 -05:00
static int bind_parse_ecdhe ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
return ssl_bind_parse_ecdhe ( args , cur_arg , px , & conf - > ssl_conf , err ) ;
}
2012-09-20 11:10:03 -04:00
2016-11-13 11:37:11 -05:00
/* parse the "crt-ignore-err" and "ca-ignore-err" bind keywords */
2012-09-21 08:31:21 -04:00
static int bind_parse_ignore_err ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
int code ;
char * p = args [ cur_arg + 1 ] ;
unsigned long long * ignerr = & conf - > crt_ignerr ;
if ( ! * p ) {
if ( err )
memprintf ( err , " '%s' : missing error IDs list " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
if ( strcmp ( args [ cur_arg ] , " ca-ignore-err " ) = = 0 )
ignerr = & conf - > ca_ignerr ;
if ( strcmp ( p , " all " ) = = 0 ) {
* ignerr = ~ 0ULL ;
return 0 ;
}
while ( p ) {
code = atoi ( p ) ;
if ( ( code < = 0 ) | | ( code > 63 ) ) {
if ( err )
memprintf ( err , " '%s' : ID '%d' out of range (1..63) in error IDs list '%s' " ,
args [ cur_arg ] , code , args [ cur_arg + 1 ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
* ignerr | = 1ULL < < code ;
p = strchr ( p , ' , ' ) ;
if ( p )
p + + ;
}
return 0 ;
}
2017-03-31 09:02:54 -04:00
/* parse tls_method_options "no-xxx" and "force-xxx" */
static int parse_tls_method_options ( char * arg , struct tls_version_filter * methods , char * * err )
2012-10-05 08:14:21 -04:00
{
2017-03-31 09:02:54 -04:00
uint16_t v ;
2017-03-30 13:19:37 -04:00
char * p ;
p = strchr ( arg , ' - ' ) ;
if ( ! p )
2017-03-31 09:02:54 -04:00
goto fail ;
2017-03-30 13:19:37 -04:00
p + + ;
if ( ! strcmp ( p , " sslv3 " ) )
v = CONF_SSLV3 ;
else if ( ! strcmp ( p , " tlsv10 " ) )
v = CONF_TLSV10 ;
else if ( ! strcmp ( p , " tlsv11 " ) )
v = CONF_TLSV11 ;
else if ( ! strcmp ( p , " tlsv12 " ) )
v = CONF_TLSV12 ;
2017-03-30 13:29:39 -04:00
else if ( ! strcmp ( p , " tlsv13 " ) )
v = CONF_TLSV13 ;
2017-03-30 13:19:37 -04:00
else
2017-03-31 09:02:54 -04:00
goto fail ;
2017-03-30 13:19:37 -04:00
if ( ! strncmp ( arg , " no- " , 3 ) )
methods - > flags | = methodVersions [ v ] . flag ;
else if ( ! strncmp ( arg , " force- " , 6 ) )
methods - > min = methods - > max = v ;
else
2017-03-31 09:02:54 -04:00
goto fail ;
2012-10-05 08:14:21 -04:00
return 0 ;
2017-03-31 09:02:54 -04:00
fail :
if ( err )
memprintf ( err , " '%s' : option not implemented " , arg ) ;
return ERR_ALERT | ERR_FATAL ;
2012-10-05 08:14:21 -04:00
}
2017-03-30 13:19:37 -04:00
static int bind_parse_tls_method_options ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
2012-10-05 08:14:21 -04:00
{
2017-08-09 12:26:20 -04:00
return parse_tls_method_options ( args [ cur_arg ] , & conf - > ssl_conf . ssl_methods , err ) ;
2012-10-05 08:14:21 -04:00
}
2017-03-30 13:19:37 -04:00
static int srv_parse_tls_method_options ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
2012-10-05 08:14:21 -04:00
{
2017-03-31 09:02:54 -04:00
return parse_tls_method_options ( args [ * cur_arg ] , & newsrv - > ssl_ctx . methods , err ) ;
}
/* parse tls_method min/max: "ssl-min-ver" and "ssl-max-ver" */
static int parse_tls_method_minmax ( char * * args , int cur_arg , struct tls_version_filter * methods , char * * err )
{
uint16_t i , v = 0 ;
char * argv = args [ cur_arg + 1 ] ;
if ( ! * argv ) {
if ( err )
memprintf ( err , " '%s' : missing the ssl/tls version " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
for ( i = CONF_TLSV_MIN ; i < = CONF_TLSV_MAX ; i + + )
if ( ! strcmp ( argv , methodVersions [ i ] . name ) )
v = i ;
if ( ! v ) {
2017-03-30 13:19:37 -04:00
if ( err )
2017-03-31 09:02:54 -04:00
memprintf ( err , " '%s' : unknown ssl/tls version " , args [ cur_arg + 1 ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
if ( ! strcmp ( " ssl-min-ver " , args [ cur_arg ] ) )
methods - > min = v ;
else if ( ! strcmp ( " ssl-max-ver " , args [ cur_arg ] ) )
methods - > max = v ;
else {
if ( err )
memprintf ( err , " '%s' : option not implemented " , args [ cur_arg ] ) ;
2017-03-30 13:19:37 -04:00
return ERR_ALERT | ERR_FATAL ;
}
2012-10-05 08:14:21 -04:00
return 0 ;
}
2017-05-18 06:46:50 -04:00
static int ssl_bind_parse_tls_method_minmax ( char * * args , int cur_arg , struct proxy * px , struct ssl_bind_conf * conf , char * * err )
{
2019-03-05 17:14:32 -05:00
# if (OPENSSL_VERSION_NUMBER < 0x10101000L) && !defined(OPENSSL_IS_BORINGSSL)
2017-11-24 10:50:31 -05:00
ha_warning ( " crt-list: ssl-min-ver and ssl-max-ver are not supported with this Openssl version (skipped). \n " ) ;
2017-05-18 06:46:50 -04:00
# endif
return parse_tls_method_minmax ( args , cur_arg , & conf - > ssl_methods , err ) ;
}
2017-03-31 09:02:54 -04:00
static int bind_parse_tls_method_minmax ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
2017-08-09 12:26:20 -04:00
return parse_tls_method_minmax ( args , cur_arg , & conf - > ssl_conf . ssl_methods , err ) ;
2017-03-31 09:02:54 -04:00
}
static int srv_parse_tls_method_minmax ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
return parse_tls_method_minmax ( args , * cur_arg , & newsrv - > ssl_ctx . methods , err ) ;
}
2012-10-02 07:45:20 -04:00
/* parse the "no-tls-tickets" bind keyword */
2017-01-20 07:06:27 -05:00
static int bind_parse_no_tls_tickets ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
2012-10-02 07:45:20 -04:00
{
2012-10-05 07:48:26 -04:00
conf - > ssl_options | = BC_SSL_O_NO_TLS_TICKETS ;
2012-10-02 07:45:20 -04:00
return 0 ;
}
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
/* parse the "allow-0rtt" bind keyword */
static int ssl_bind_parse_allow_0rtt ( char * * args , int cur_arg , struct proxy * px , struct ssl_bind_conf * conf , char * * err )
{
conf - > early_data = 1 ;
return 0 ;
}
static int bind_parse_allow_0rtt ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
2017-10-27 08:58:08 -04:00
conf - > ssl_conf . early_data = 1 ;
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
return 0 ;
}
2012-10-18 12:57:14 -04:00
/* parse the "npn" bind keyword */
2016-12-29 12:26:15 -05:00
static int ssl_bind_parse_npn ( char * * args , int cur_arg , struct proxy * px , struct ssl_bind_conf * conf , char * * err )
2012-10-18 12:57:14 -04:00
{
2018-02-15 07:34:58 -05:00
# if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2012-10-18 12:57:14 -04:00
char * p1 , * p2 ;
if ( ! * args [ cur_arg + 1 ] ) {
memprintf ( err , " '%s' : missing the comma-delimited NPN protocol suite " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
free ( conf - > npn_str ) ;
2016-02-12 11:11:12 -05:00
/* the NPN string is built as a suite of (<len> <name>)*,
* so we reuse each comma to store the next < len > and need
* one more for the end of the string .
*/
2012-10-18 12:57:14 -04:00
conf - > npn_len = strlen ( args [ cur_arg + 1 ] ) + 1 ;
2016-02-12 11:11:12 -05:00
conf - > npn_str = calloc ( 1 , conf - > npn_len + 1 ) ;
2012-10-18 12:57:14 -04:00
memcpy ( conf - > npn_str + 1 , args [ cur_arg + 1 ] , conf - > npn_len ) ;
/* replace commas with the name length */
p1 = conf - > npn_str ;
p2 = p1 + 1 ;
while ( 1 ) {
p2 = memchr ( p1 + 1 , ' , ' , conf - > npn_str + conf - > npn_len - ( p1 + 1 ) ) ;
if ( ! p2 )
p2 = p1 + 1 + strlen ( p1 + 1 ) ;
if ( p2 - ( p1 + 1 ) > 255 ) {
* p2 = ' \0 ' ;
memprintf ( err , " '%s' : NPN protocol name too long : '%s' " , args [ cur_arg ] , p1 + 1 ) ;
return ERR_ALERT | ERR_FATAL ;
}
* p1 = p2 - ( p1 + 1 ) ;
p1 = p2 ;
if ( ! * p2 )
break ;
* ( p2 + + ) = ' \0 ' ;
}
return 0 ;
# else
if ( err )
memprintf ( err , " '%s' : library does not support TLS NPN extension " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
# endif
}
2016-12-29 12:26:15 -05:00
static int bind_parse_npn ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
return ssl_bind_parse_npn ( args , cur_arg , px , & conf - > ssl_conf , err ) ;
}
2013-04-01 20:30:41 -04:00
/* parse the "alpn" bind keyword */
2016-12-29 12:26:15 -05:00
static int ssl_bind_parse_alpn ( char * * args , int cur_arg , struct proxy * px , struct ssl_bind_conf * conf , char * * err )
2013-04-01 20:30:41 -04:00
{
2014-02-13 06:29:42 -05:00
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2013-04-01 20:30:41 -04:00
char * p1 , * p2 ;
if ( ! * args [ cur_arg + 1 ] ) {
memprintf ( err , " '%s' : missing the comma-delimited ALPN protocol suite " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
free ( conf - > alpn_str ) ;
2016-02-12 11:05:24 -05:00
/* the ALPN string is built as a suite of (<len> <name>)*,
* so we reuse each comma to store the next < len > and need
* one more for the end of the string .
*/
2013-04-01 20:30:41 -04:00
conf - > alpn_len = strlen ( args [ cur_arg + 1 ] ) + 1 ;
2016-02-12 11:05:24 -05:00
conf - > alpn_str = calloc ( 1 , conf - > alpn_len + 1 ) ;
2013-04-01 20:30:41 -04:00
memcpy ( conf - > alpn_str + 1 , args [ cur_arg + 1 ] , conf - > alpn_len ) ;
/* replace commas with the name length */
p1 = conf - > alpn_str ;
p2 = p1 + 1 ;
while ( 1 ) {
p2 = memchr ( p1 + 1 , ' , ' , conf - > alpn_str + conf - > alpn_len - ( p1 + 1 ) ) ;
if ( ! p2 )
p2 = p1 + 1 + strlen ( p1 + 1 ) ;
if ( p2 - ( p1 + 1 ) > 255 ) {
* p2 = ' \0 ' ;
memprintf ( err , " '%s' : ALPN protocol name too long : '%s' " , args [ cur_arg ] , p1 + 1 ) ;
return ERR_ALERT | ERR_FATAL ;
}
* p1 = p2 - ( p1 + 1 ) ;
p1 = p2 ;
if ( ! * p2 )
break ;
* ( p2 + + ) = ' \0 ' ;
}
return 0 ;
# else
if ( err )
memprintf ( err , " '%s' : library does not support TLS ALPN extension " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
# endif
}
2016-12-29 12:26:15 -05:00
static int bind_parse_alpn ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
return ssl_bind_parse_alpn ( args , cur_arg , px , & conf - > ssl_conf , err ) ;
}
2012-09-14 01:53:05 -04:00
/* parse the "ssl" bind keyword */
2012-09-20 10:48:07 -04:00
static int bind_parse_ssl ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
2012-09-14 01:53:05 -04:00
{
2016-12-21 16:04:54 -05:00
conf - > xprt = & ssl_sock ;
2012-09-20 10:48:07 -04:00
conf - > is_ssl = 1 ;
2012-10-05 09:47:31 -04:00
2016-12-29 12:26:15 -05:00
if ( global_ssl . listen_default_ciphers & & ! conf - > ssl_conf . ciphers )
conf - > ssl_conf . ciphers = strdup ( global_ssl . listen_default_ciphers ) ;
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
if ( global_ssl . listen_default_ciphersuites & & ! conf - > ssl_conf . ciphersuites )
conf - > ssl_conf . ciphersuites = strdup ( global_ssl . listen_default_ciphersuites ) ;
# endif
2017-01-20 07:06:27 -05:00
conf - > ssl_options | = global_ssl . listen_default_ssloptions ;
2017-08-09 12:26:20 -04:00
conf - > ssl_conf . ssl_methods . flags | = global_ssl . listen_default_sslmethods . flags ;
if ( ! conf - > ssl_conf . ssl_methods . min )
conf - > ssl_conf . ssl_methods . min = global_ssl . listen_default_sslmethods . min ;
if ( ! conf - > ssl_conf . ssl_methods . max )
conf - > ssl_conf . ssl_methods . max = global_ssl . listen_default_sslmethods . max ;
2012-10-05 09:47:31 -04:00
2012-09-14 01:53:05 -04:00
return 0 ;
}
2017-05-04 11:45:40 -04:00
/* parse the "prefer-client-ciphers" bind keyword */
static int bind_parse_pcc ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
conf - > ssl_options | = BC_SSL_O_PREF_CLIE_CIPH ;
return 0 ;
}
2015-06-09 11:29:50 -04:00
/* parse the "generate-certificates" bind keyword */
static int bind_parse_generate_certs ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
2017-01-13 11:48:18 -05:00
# if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
2015-06-09 11:29:50 -04:00
conf - > generate_certs = 1 ;
# else
memprintf ( err , " %sthis version of openssl cannot generate SSL certificates. \n " ,
err & & * err ? * err : " " ) ;
# endif
return 0 ;
}
2013-01-24 11:17:15 -05:00
/* parse the "strict-sni" bind keyword */
static int bind_parse_strict_sni ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
conf - > strict_sni = 1 ;
return 0 ;
}
2015-02-27 13:56:49 -05:00
/* parse the "tls-ticket-keys" bind keyword */
static int bind_parse_tls_ticket_keys ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
# if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
FILE * f ;
int i = 0 ;
char thisline [ LINESIZE ] ;
2015-05-09 02:46:00 -04:00
struct tls_keys_ref * keys_ref ;
2015-02-27 13:56:49 -05:00
if ( ! * args [ cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing TLS ticket keys file path " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2015-05-09 02:46:01 -04:00
keys_ref = tlskeys_ref_lookup ( args [ cur_arg + 1 ] ) ;
2018-07-17 04:05:32 -04:00
if ( keys_ref ) {
keys_ref - > refcount + + ;
2015-05-09 02:46:01 -04:00
conf - > keys_ref = keys_ref ;
return 0 ;
}
2016-04-03 07:48:43 -04:00
keys_ref = malloc ( sizeof ( * keys_ref ) ) ;
2019-01-10 04:51:13 -05:00
if ( ! keys_ref ) {
if ( err )
memprintf ( err , " '%s' : allocation error " , args [ cur_arg + 1 ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2019-01-10 11:51:55 -05:00
keys_ref - > tlskeys = malloc ( TLS_TICKETS_NO * sizeof ( union tls_sess_key ) ) ;
2019-01-10 04:51:13 -05:00
if ( ! keys_ref - > tlskeys ) {
free ( keys_ref ) ;
if ( err )
memprintf ( err , " '%s' : allocation error " , args [ cur_arg + 1 ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2015-02-27 13:56:49 -05:00
if ( ( f = fopen ( args [ cur_arg + 1 ] , " r " ) ) = = NULL ) {
2019-01-10 04:51:13 -05:00
free ( keys_ref - > tlskeys ) ;
free ( keys_ref ) ;
2015-02-27 13:56:49 -05:00
if ( err )
memprintf ( err , " '%s' : unable to load ssl tickets keys file " , args [ cur_arg + 1 ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2015-05-09 02:46:00 -04:00
keys_ref - > filename = strdup ( args [ cur_arg + 1 ] ) ;
2019-01-10 04:51:13 -05:00
if ( ! keys_ref - > filename ) {
free ( keys_ref - > tlskeys ) ;
free ( keys_ref ) ;
if ( err )
memprintf ( err , " '%s' : allocation error " , args [ cur_arg + 1 ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2015-05-09 02:46:00 -04:00
2019-01-10 11:51:55 -05:00
keys_ref - > key_size_bits = 0 ;
2015-02-27 13:56:49 -05:00
while ( fgets ( thisline , sizeof ( thisline ) , f ) ! = NULL ) {
int len = strlen ( thisline ) ;
2019-01-10 11:51:55 -05:00
int dec_size ;
2015-02-27 13:56:49 -05:00
/* Strip newline characters from the end */
if ( thisline [ len - 1 ] = = ' \n ' )
thisline [ - - len ] = 0 ;
if ( thisline [ len - 1 ] = = ' \r ' )
thisline [ - - len ] = 0 ;
2019-01-10 11:51:55 -05:00
dec_size = base64dec ( thisline , len , ( char * ) ( keys_ref - > tlskeys + i % TLS_TICKETS_NO ) , sizeof ( union tls_sess_key ) ) ;
if ( dec_size < 0 ) {
2019-01-10 04:51:13 -05:00
free ( keys_ref - > filename ) ;
free ( keys_ref - > tlskeys ) ;
free ( keys_ref ) ;
2015-02-27 13:56:49 -05:00
if ( err )
memprintf ( err , " '%s' : unable to decode base64 key on line %d " , args [ cur_arg + 1 ] , i + 1 ) ;
2016-06-22 11:46:29 -04:00
fclose ( f ) ;
2015-02-27 13:56:49 -05:00
return ERR_ALERT | ERR_FATAL ;
}
2019-01-10 11:51:55 -05:00
else if ( ! keys_ref - > key_size_bits & & ( dec_size = = sizeof ( struct tls_sess_key_128 ) ) ) {
keys_ref - > key_size_bits = 128 ;
}
else if ( ! keys_ref - > key_size_bits & & ( dec_size = = sizeof ( struct tls_sess_key_256 ) ) ) {
keys_ref - > key_size_bits = 256 ;
}
else if ( ( ( dec_size ! = sizeof ( struct tls_sess_key_128 ) ) & & ( dec_size ! = sizeof ( struct tls_sess_key_256 ) ) )
| | ( ( dec_size = = sizeof ( struct tls_sess_key_128 ) & & ( keys_ref - > key_size_bits ! = 128 ) ) )
| | ( ( dec_size = = sizeof ( struct tls_sess_key_256 ) & & ( keys_ref - > key_size_bits ! = 256 ) ) ) ) {
free ( keys_ref - > filename ) ;
free ( keys_ref - > tlskeys ) ;
free ( keys_ref ) ;
if ( err )
memprintf ( err , " '%s' : wrong sized key on line %d " , args [ cur_arg + 1 ] , i + 1 ) ;
fclose ( f ) ;
return ERR_ALERT | ERR_FATAL ;
}
2015-02-27 13:56:49 -05:00
i + + ;
}
if ( i < TLS_TICKETS_NO ) {
2019-01-10 04:51:13 -05:00
free ( keys_ref - > filename ) ;
free ( keys_ref - > tlskeys ) ;
free ( keys_ref ) ;
2015-02-27 13:56:49 -05:00
if ( err )
memprintf ( err , " '%s' : please supply at least %d keys in the tls-tickets-file " , args [ cur_arg + 1 ] , TLS_TICKETS_NO ) ;
2016-06-22 11:46:29 -04:00
fclose ( f ) ;
2015-02-27 13:56:49 -05:00
return ERR_ALERT | ERR_FATAL ;
}
fclose ( f ) ;
/* Use penultimate key for encryption, handle when TLS_TICKETS_NO = 1 */
2016-03-25 17:16:57 -04:00
i - = 2 ;
keys_ref - > tls_ticket_enc_index = i < 0 ? 0 : i % TLS_TICKETS_NO ;
2015-05-09 02:46:01 -04:00
keys_ref - > unique_id = - 1 ;
2018-07-17 04:05:32 -04:00
keys_ref - > refcount = 1 ;
2018-02-16 05:23:49 -05:00
HA_RWLOCK_INIT ( & keys_ref - > lock ) ;
2015-05-09 02:46:00 -04:00
conf - > keys_ref = keys_ref ;
2015-02-27 13:56:49 -05:00
2015-05-09 02:46:01 -04:00
LIST_ADD ( & tlskeys_reference , & keys_ref - > list ) ;
2015-02-27 13:56:49 -05:00
return 0 ;
# else
if ( err )
memprintf ( err , " '%s' : TLS ticket callback extension not supported " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
# endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */
}
2012-09-20 12:23:56 -04:00
/* parse the "verify" bind keyword */
2016-12-29 12:26:15 -05:00
static int ssl_bind_parse_verify ( char * * args , int cur_arg , struct proxy * px , struct ssl_bind_conf * conf , char * * err )
2012-09-20 12:23:56 -04:00
{
if ( ! * args [ cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing verify method " , args [ cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
if ( strcmp ( args [ cur_arg + 1 ] , " none " ) = = 0 )
2014-01-29 06:24:34 -05:00
conf - > verify = SSL_SOCK_VERIFY_NONE ;
2012-09-20 12:23:56 -04:00
else if ( strcmp ( args [ cur_arg + 1 ] , " optional " ) = = 0 )
2014-01-29 06:24:34 -05:00
conf - > verify = SSL_SOCK_VERIFY_OPTIONAL ;
2012-09-20 12:23:56 -04:00
else if ( strcmp ( args [ cur_arg + 1 ] , " required " ) = = 0 )
2014-01-29 06:24:34 -05:00
conf - > verify = SSL_SOCK_VERIFY_REQUIRED ;
2012-09-20 12:23:56 -04:00
else {
if ( err )
memprintf ( err , " '%s' : unknown verify method '%s', only 'none', 'optional', and 'required' are supported \n " ,
args [ cur_arg ] , args [ cur_arg + 1 ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
return 0 ;
}
2016-12-29 12:26:15 -05:00
static int bind_parse_verify ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
return ssl_bind_parse_verify ( args , cur_arg , px , & conf - > ssl_conf , err ) ;
}
2012-09-20 12:23:56 -04:00
2017-07-28 09:01:05 -04:00
/* parse the "no-ca-names" bind keyword */
static int ssl_bind_parse_no_ca_names ( char * * args , int cur_arg , struct proxy * px , struct ssl_bind_conf * conf , char * * err )
{
conf - > no_ca_names = 1 ;
return 0 ;
}
static int bind_parse_no_ca_names ( char * * args , int cur_arg , struct proxy * px , struct bind_conf * conf , char * * err )
{
return ssl_bind_parse_no_ca_names ( args , cur_arg , px , & conf - > ssl_conf , err ) ;
}
2012-10-10 17:04:25 -04:00
/************** "server" keywords ****************/
2018-11-20 17:33:50 -05:00
/* parse the "npn" bind keyword */
static int srv_parse_npn ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
# if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
char * p1 , * p2 ;
if ( ! * args [ * cur_arg + 1 ] ) {
memprintf ( err , " '%s' : missing the comma-delimited NPN protocol suite " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
free ( newsrv - > ssl_ctx . npn_str ) ;
/* the NPN string is built as a suite of (<len> <name>)*,
* so we reuse each comma to store the next < len > and need
* one more for the end of the string .
*/
newsrv - > ssl_ctx . npn_len = strlen ( args [ * cur_arg + 1 ] ) + 1 ;
newsrv - > ssl_ctx . npn_str = calloc ( 1 , newsrv - > ssl_ctx . npn_len + 1 ) ;
memcpy ( newsrv - > ssl_ctx . npn_str + 1 , args [ * cur_arg + 1 ] ,
newsrv - > ssl_ctx . npn_len ) ;
/* replace commas with the name length */
p1 = newsrv - > ssl_ctx . npn_str ;
p2 = p1 + 1 ;
while ( 1 ) {
p2 = memchr ( p1 + 1 , ' , ' , newsrv - > ssl_ctx . npn_str +
newsrv - > ssl_ctx . npn_len - ( p1 + 1 ) ) ;
if ( ! p2 )
p2 = p1 + 1 + strlen ( p1 + 1 ) ;
if ( p2 - ( p1 + 1 ) > 255 ) {
* p2 = ' \0 ' ;
memprintf ( err , " '%s' : NPN protocol name too long : '%s' " , args [ * cur_arg ] , p1 + 1 ) ;
return ERR_ALERT | ERR_FATAL ;
}
* p1 = p2 - ( p1 + 1 ) ;
p1 = p2 ;
if ( ! * p2 )
break ;
* ( p2 + + ) = ' \0 ' ;
}
return 0 ;
# else
if ( err )
memprintf ( err , " '%s' : library does not support TLS NPN extension " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
# endif
}
2018-12-21 13:47:01 -05:00
/* parse the "alpn" or the "check-alpn" server keyword */
2018-11-20 17:33:50 -05:00
static int srv_parse_alpn ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
char * p1 , * p2 ;
2018-12-21 13:47:01 -05:00
char * * alpn_str ;
int * alpn_len ;
if ( * args [ * cur_arg ] = = ' c ' ) {
alpn_str = & newsrv - > check . alpn_str ;
alpn_len = & newsrv - > check . alpn_len ;
} else {
alpn_str = & newsrv - > ssl_ctx . alpn_str ;
alpn_len = & newsrv - > ssl_ctx . alpn_len ;
2018-11-20 17:33:50 -05:00
2018-12-21 13:47:01 -05:00
}
2018-11-20 17:33:50 -05:00
if ( ! * args [ * cur_arg + 1 ] ) {
memprintf ( err , " '%s' : missing the comma-delimited ALPN protocol suite " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2018-12-21 13:47:01 -05:00
free ( * alpn_str ) ;
2018-11-20 17:33:50 -05:00
/* the ALPN string is built as a suite of (<len> <name>)*,
* so we reuse each comma to store the next < len > and need
* one more for the end of the string .
*/
2018-12-21 13:47:01 -05:00
* alpn_len = strlen ( args [ * cur_arg + 1 ] ) + 1 ;
* alpn_str = calloc ( 1 , * alpn_len + 1 ) ;
memcpy ( * alpn_str + 1 , args [ * cur_arg + 1 ] , * alpn_len ) ;
2018-11-20 17:33:50 -05:00
/* replace commas with the name length */
2018-12-21 13:47:01 -05:00
p1 = * alpn_str ;
2018-11-20 17:33:50 -05:00
p2 = p1 + 1 ;
while ( 1 ) {
2018-12-21 13:47:01 -05:00
p2 = memchr ( p1 + 1 , ' , ' , * alpn_str + * alpn_len - ( p1 + 1 ) ) ;
2018-11-20 17:33:50 -05:00
if ( ! p2 )
p2 = p1 + 1 + strlen ( p1 + 1 ) ;
if ( p2 - ( p1 + 1 ) > 255 ) {
* p2 = ' \0 ' ;
memprintf ( err , " '%s' : ALPN protocol name too long : '%s' " , args [ * cur_arg ] , p1 + 1 ) ;
return ERR_ALERT | ERR_FATAL ;
}
* p1 = p2 - ( p1 + 1 ) ;
p1 = p2 ;
if ( ! * p2 )
break ;
* ( p2 + + ) = ' \0 ' ;
}
return 0 ;
# else
if ( err )
memprintf ( err , " '%s' : library does not support TLS ALPN extension " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
# endif
}
2012-10-11 10:11:36 -04:00
/* parse the "ca-file" server keyword */
static int srv_parse_ca_file ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
if ( ! * args [ * cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing CAfile path " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2016-12-22 17:12:01 -05:00
if ( ( * args [ * cur_arg + 1 ] ! = ' / ' ) & & global_ssl . ca_base )
memprintf ( & newsrv - > ssl_ctx . ca_file , " %s/%s " , global_ssl . ca_base , args [ * cur_arg + 1 ] ) ;
2012-10-11 10:11:36 -04:00
else
memprintf ( & newsrv - > ssl_ctx . ca_file , " %s " , args [ * cur_arg + 1 ] ) ;
return 0 ;
}
2017-10-17 11:33:43 -04:00
/* parse the "check-sni" server keyword */
static int srv_parse_check_sni ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
if ( ! * args [ * cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing SNI " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
newsrv - > check . sni = strdup ( args [ * cur_arg + 1 ] ) ;
if ( ! newsrv - > check . sni ) {
memprintf ( err , " '%s' : failed to allocate memory " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
return 0 ;
}
2012-10-10 17:04:25 -04:00
/* parse the "check-ssl" server keyword */
static int srv_parse_check_ssl ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > check . use_ssl = 1 ;
2016-12-22 17:12:01 -05:00
if ( global_ssl . connect_default_ciphers & & ! newsrv - > ssl_ctx . ciphers )
newsrv - > ssl_ctx . ciphers = strdup ( global_ssl . connect_default_ciphers ) ;
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
if ( global_ssl . connect_default_ciphersuites & & ! newsrv - > ssl_ctx . ciphersuites )
newsrv - > ssl_ctx . ciphersuites = strdup ( global_ssl . connect_default_ciphersuites ) ;
# endif
2016-12-22 17:12:01 -05:00
newsrv - > ssl_ctx . options | = global_ssl . connect_default_ssloptions ;
2017-03-30 13:19:37 -04:00
newsrv - > ssl_ctx . methods . flags | = global_ssl . connect_default_sslmethods . flags ;
if ( ! newsrv - > ssl_ctx . methods . min )
newsrv - > ssl_ctx . methods . min = global_ssl . connect_default_sslmethods . min ;
if ( ! newsrv - > ssl_ctx . methods . max )
newsrv - > ssl_ctx . methods . max = global_ssl . connect_default_sslmethods . max ;
2012-10-10 17:04:25 -04:00
return 0 ;
}
/* parse the "ciphers" server keyword */
static int srv_parse_ciphers ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
if ( ! * args [ * cur_arg + 1 ] ) {
memprintf ( err , " '%s' : missing cipher suite " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
free ( newsrv - > ssl_ctx . ciphers ) ;
newsrv - > ssl_ctx . ciphers = strdup ( args [ * cur_arg + 1 ] ) ;
return 0 ;
}
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
/* parse the "ciphersuites" server keyword */
static int srv_parse_ciphersuites ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
if ( ! * args [ * cur_arg + 1 ] ) {
memprintf ( err , " '%s' : missing cipher suite " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
free ( newsrv - > ssl_ctx . ciphersuites ) ;
newsrv - > ssl_ctx . ciphersuites = strdup ( args [ * cur_arg + 1 ] ) ;
return 0 ;
}
# endif
2012-10-11 10:11:36 -04:00
/* parse the "crl-file" server keyword */
static int srv_parse_crl_file ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
# ifndef X509_V_FLAG_CRL_CHECK
if ( err )
memprintf ( err , " '%s' : library does not support CRL verify " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
# else
if ( ! * args [ * cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing CRLfile path " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2016-12-22 17:12:01 -05:00
if ( ( * args [ * cur_arg + 1 ] ! = ' / ' ) & & global_ssl . ca_base )
memprintf ( & newsrv - > ssl_ctx . crl_file , " %s/%s " , global_ssl . ca_base , args [ * cur_arg + 1 ] ) ;
2012-10-11 10:11:36 -04:00
else
memprintf ( & newsrv - > ssl_ctx . crl_file , " %s " , args [ * cur_arg + 1 ] ) ;
return 0 ;
# endif
}
2012-10-26 06:58:00 -04:00
/* parse the "crt" server keyword */
static int srv_parse_crt ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
if ( ! * args [ * cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing certificate file path " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2016-12-22 17:12:01 -05:00
if ( ( * args [ * cur_arg + 1 ] ! = ' / ' ) & & global_ssl . crt_base )
2017-11-23 03:13:32 -05:00
memprintf ( & newsrv - > ssl_ctx . client_crt , " %s/%s " , global_ssl . crt_base , args [ * cur_arg + 1 ] ) ;
2012-10-26 06:58:00 -04:00
else
memprintf ( & newsrv - > ssl_ctx . client_crt , " %s " , args [ * cur_arg + 1 ] ) ;
return 0 ;
}
2012-10-11 10:11:36 -04:00
2017-03-13 05:38:04 -04:00
/* parse the "no-check-ssl" server keyword */
static int srv_parse_no_check_ssl ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > check . use_ssl = 0 ;
free ( newsrv - > ssl_ctx . ciphers ) ;
newsrv - > ssl_ctx . ciphers = NULL ;
newsrv - > ssl_ctx . options & = ~ global_ssl . connect_default_ssloptions ;
return 0 ;
}
2017-03-13 07:08:01 -04:00
/* parse the "no-send-proxy-v2-ssl" server keyword */
static int srv_parse_no_send_proxy_ssl ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > pp_opts & = ~ SRV_PP_V2 ;
newsrv - > pp_opts & = ~ SRV_PP_V2_SSL ;
return 0 ;
}
/* parse the "no-send-proxy-v2-ssl-cn" server keyword */
static int srv_parse_no_send_proxy_cn ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > pp_opts & = ~ SRV_PP_V2 ;
newsrv - > pp_opts & = ~ SRV_PP_V2_SSL ;
newsrv - > pp_opts & = ~ SRV_PP_V2_SSL_CN ;
return 0 ;
}
2017-03-13 06:54:17 -04:00
/* parse the "no-ssl" server keyword */
static int srv_parse_no_ssl ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > use_ssl = 0 ;
free ( newsrv - > ssl_ctx . ciphers ) ;
newsrv - > ssl_ctx . ciphers = NULL ;
return 0 ;
}
2017-11-03 11:27:47 -04:00
/* parse the "allow-0rtt" server keyword */
static int srv_parse_allow_0rtt ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > ssl_ctx . options | = SRV_SSL_O_EARLY_DATA ;
return 0 ;
}
2015-02-05 10:47:07 -05:00
/* parse the "no-ssl-reuse" server keyword */
static int srv_parse_no_ssl_reuse ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > ssl_ctx . options | = SRV_SSL_O_NO_REUSE ;
return 0 ;
}
2012-10-11 09:28:34 -04:00
/* parse the "no-tls-tickets" server keyword */
static int srv_parse_no_tls_tickets ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > ssl_ctx . options | = SRV_SSL_O_NO_TLS_TICKETS ;
return 0 ;
}
2014-05-08 23:42:08 -04:00
/* parse the "send-proxy-v2-ssl" server keyword */
static int srv_parse_send_proxy_ssl ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > pp_opts | = SRV_PP_V2 ;
newsrv - > pp_opts | = SRV_PP_V2_SSL ;
return 0 ;
}
/* parse the "send-proxy-v2-ssl-cn" server keyword */
static int srv_parse_send_proxy_cn ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > pp_opts | = SRV_PP_V2 ;
newsrv - > pp_opts | = SRV_PP_V2_SSL ;
newsrv - > pp_opts | = SRV_PP_V2_SSL_CN ;
return 0 ;
}
2012-10-11 09:28:34 -04:00
2015-07-09 05:40:25 -04:00
/* parse the "sni" server keyword */
static int srv_parse_sni ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
# ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
memprintf ( err , " '%s' : the current SSL library doesn't support the SNI TLS extension " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
# else
2017-03-20 09:54:41 -04:00
char * arg ;
2015-07-09 05:40:25 -04:00
2017-03-20 09:54:41 -04:00
arg = args [ * cur_arg + 1 ] ;
if ( ! * arg ) {
2015-07-09 05:40:25 -04:00
memprintf ( err , " '%s' : missing sni expression " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2017-03-20 09:54:41 -04:00
free ( newsrv - > sni_expr ) ;
newsrv - > sni_expr = strdup ( arg ) ;
2015-07-09 05:40:25 -04:00
return 0 ;
# endif
}
2012-10-10 17:04:25 -04:00
/* parse the "ssl" server keyword */
static int srv_parse_ssl ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > use_ssl = 1 ;
2016-12-22 17:12:01 -05:00
if ( global_ssl . connect_default_ciphers & & ! newsrv - > ssl_ctx . ciphers )
newsrv - > ssl_ctx . ciphers = strdup ( global_ssl . connect_default_ciphers ) ;
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
if ( global_ssl . connect_default_ciphersuites & & ! newsrv - > ssl_ctx . ciphersuites )
newsrv - > ssl_ctx . ciphersuites = strdup ( global_ssl . connect_default_ciphersuites ) ;
# endif
2012-10-10 17:04:25 -04:00
return 0 ;
}
2017-03-13 06:32:20 -04:00
/* parse the "ssl-reuse" server keyword */
static int srv_parse_ssl_reuse ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > ssl_ctx . options & = ~ SRV_SSL_O_NO_REUSE ;
return 0 ;
}
/* parse the "tls-tickets" server keyword */
static int srv_parse_tls_tickets ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
newsrv - > ssl_ctx . options & = ~ SRV_SSL_O_NO_TLS_TICKETS ;
return 0 ;
}
2012-10-11 10:11:36 -04:00
/* parse the "verify" server keyword */
static int srv_parse_verify ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
if ( ! * args [ * cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing verify method " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
if ( strcmp ( args [ * cur_arg + 1 ] , " none " ) = = 0 )
2014-01-29 06:24:34 -05:00
newsrv - > ssl_ctx . verify = SSL_SOCK_VERIFY_NONE ;
2012-10-11 10:11:36 -04:00
else if ( strcmp ( args [ * cur_arg + 1 ] , " required " ) = = 0 )
2014-01-29 06:24:34 -05:00
newsrv - > ssl_ctx . verify = SSL_SOCK_VERIFY_REQUIRED ;
2012-10-11 10:11:36 -04:00
else {
if ( err )
memprintf ( err , " '%s' : unknown verify method '%s', only 'none' and 'required' are supported \n " ,
args [ * cur_arg ] , args [ * cur_arg + 1 ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
return 0 ;
}
2013-06-27 03:05:25 -04:00
/* parse the "verifyhost" server keyword */
static int srv_parse_verifyhost ( char * * args , int * cur_arg , struct proxy * px , struct server * newsrv , char * * err )
{
if ( ! * args [ * cur_arg + 1 ] ) {
if ( err )
memprintf ( err , " '%s' : missing hostname to verify against " , args [ * cur_arg ] ) ;
return ERR_ALERT | ERR_FATAL ;
}
2017-03-13 10:52:01 -04:00
free ( newsrv - > ssl_ctx . verify_host ) ;
2013-06-27 03:05:25 -04:00
newsrv - > ssl_ctx . verify_host = strdup ( args [ * cur_arg + 1 ] ) ;
return 0 ;
}
2014-10-30 10:56:50 -04:00
/* parse the "ssl-default-bind-options" keyword in global section */
static int ssl_parse_default_bind_options ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err ) {
int i = 1 ;
if ( * ( args [ i ] ) = = 0 ) {
memprintf ( err , " global statement '%s' expects an option as an argument. " , args [ 0 ] ) ;
return - 1 ;
}
while ( * ( args [ i ] ) ) {
2017-03-30 13:19:37 -04:00
if ( ! strcmp ( args [ i ] , " no-tls-tickets " ) )
2016-12-22 17:12:01 -05:00
global_ssl . listen_default_ssloptions | = BC_SSL_O_NO_TLS_TICKETS ;
2017-05-04 11:45:40 -04:00
else if ( ! strcmp ( args [ i ] , " prefer-client-ciphers " ) )
global_ssl . listen_default_ssloptions | = BC_SSL_O_PREF_CLIE_CIPH ;
2017-03-31 09:02:54 -04:00
else if ( ! strcmp ( args [ i ] , " ssl-min-ver " ) | | ! strcmp ( args [ i ] , " ssl-max-ver " ) ) {
if ( ! parse_tls_method_minmax ( args , i , & global_ssl . listen_default_sslmethods , err ) )
i + + ;
else {
memprintf ( err , " %s on global statement '%s'. " , * err , args [ 0 ] ) ;
return - 1 ;
}
}
else if ( parse_tls_method_options ( args [ i ] , & global_ssl . listen_default_sslmethods , err ) ) {
2014-10-30 10:56:50 -04:00
memprintf ( err , " unknown option '%s' on global statement '%s'. " , args [ i ] , args [ 0 ] ) ;
return - 1 ;
}
i + + ;
}
return 0 ;
}
/* parse the "ssl-default-server-options" keyword in global section */
static int ssl_parse_default_server_options ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err ) {
int i = 1 ;
if ( * ( args [ i ] ) = = 0 ) {
memprintf ( err , " global statement '%s' expects an option as an argument. " , args [ 0 ] ) ;
return - 1 ;
}
while ( * ( args [ i ] ) ) {
2017-03-30 13:19:37 -04:00
if ( ! strcmp ( args [ i ] , " no-tls-tickets " ) )
2016-12-22 17:12:01 -05:00
global_ssl . connect_default_ssloptions | = SRV_SSL_O_NO_TLS_TICKETS ;
2017-03-31 09:02:54 -04:00
else if ( ! strcmp ( args [ i ] , " ssl-min-ver " ) | | ! strcmp ( args [ i ] , " ssl-max-ver " ) ) {
if ( ! parse_tls_method_minmax ( args , i , & global_ssl . connect_default_sslmethods , err ) )
i + + ;
else {
memprintf ( err , " %s on global statement '%s'. " , * err , args [ 0 ] ) ;
return - 1 ;
}
}
else if ( parse_tls_method_options ( args [ i ] , & global_ssl . connect_default_sslmethods , err ) ) {
2014-10-30 10:56:50 -04:00
memprintf ( err , " unknown option '%s' on global statement '%s'. " , args [ i ] , args [ 0 ] ) ;
return - 1 ;
}
i + + ;
}
return 0 ;
}
2016-12-21 16:44:46 -05:00
/* parse the "ca-base" / "crt-base" keywords in global section.
* Returns < 0 on alert , > 0 on warning , 0 on success .
*/
static int ssl_parse_global_ca_crt_base ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err )
{
char * * target ;
2016-12-22 17:12:01 -05:00
target = ( args [ 0 ] [ 1 ] = = ' a ' ) ? & global_ssl . ca_base : & global_ssl . crt_base ;
2016-12-21 16:44:46 -05:00
if ( too_many_args ( 1 , args , err , NULL ) )
return - 1 ;
if ( * target ) {
memprintf ( err , " '%s' already specified. " , args [ 0 ] ) ;
return - 1 ;
}
if ( * ( args [ 1 ] ) = = 0 ) {
memprintf ( err , " global statement '%s' expects a directory path as an argument. " , args [ 0 ] ) ;
return - 1 ;
}
* target = strdup ( args [ 1 ] ) ;
return 0 ;
}
2017-01-13 20:42:15 -05:00
/* parse the "ssl-mode-async" keyword in global section.
* Returns < 0 on alert , > 0 on warning , 0 on success .
*/
static int ssl_parse_global_ssl_async ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err )
{
2017-10-24 12:11:48 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(OPENSSL_NO_ASYNC)
2017-01-13 20:42:15 -05:00
global_ssl . async = 1 ;
2017-12-06 07:51:49 -05:00
global . ssl_used_async_engines = nb_engines ;
2017-01-13 20:42:15 -05:00
return 0 ;
# else
memprintf ( err , " '%s': openssl library does not support async mode " , args [ 0 ] ) ;
return - 1 ;
# endif
}
2017-05-29 08:36:20 -04:00
# ifndef OPENSSL_NO_ENGINE
2017-01-13 20:42:15 -05:00
static int ssl_check_async_engine_count ( void ) {
int err_code = 0 ;
2017-05-17 14:42:48 -04:00
if ( global_ssl . async & & ( openssl_engines_initialized > 32 ) ) {
2017-11-24 10:50:31 -05:00
ha_alert ( " ssl-mode-async only supports a maximum of 32 engines. \n " ) ;
2017-01-13 20:42:15 -05:00
err_code = ERR_ABORT ;
}
return err_code ;
}
2017-01-20 20:10:18 -05:00
/* parse the "ssl-engine" keyword in global section.
* Returns < 0 on alert , > 0 on warning , 0 on success .
*/
static int ssl_parse_global_ssl_engine ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err )
{
char * algo ;
int ret = - 1 ;
if ( * ( args [ 1 ] ) = = 0 ) {
memprintf ( err , " global statement '%s' expects a valid engine name as an argument. " , args [ 0 ] ) ;
return ret ;
}
if ( * ( args [ 2 ] ) = = 0 ) {
/* if no list of algorithms is given, it defaults to ALL */
algo = strdup ( " ALL " ) ;
goto add_engine ;
}
/* otherwise the expected format is ssl-engine <engine_name> algo <list of algo> */
if ( strcmp ( args [ 2 ] , " algo " ) ! = 0 ) {
memprintf ( err , " global statement '%s' expects to have algo keyword. " , args [ 0 ] ) ;
return ret ;
}
if ( * ( args [ 3 ] ) = = 0 ) {
memprintf ( err , " global statement '%s' expects algorithm names as an argument. " , args [ 0 ] ) ;
return ret ;
}
algo = strdup ( args [ 3 ] ) ;
add_engine :
if ( ssl_init_single_engine ( args [ 1 ] , algo ) = = 0 ) {
openssl_engines_initialized + + ;
ret = 0 ;
}
free ( algo ) ;
return ret ;
}
2017-05-29 08:36:20 -04:00
# endif
2017-01-20 20:10:18 -05:00
2016-12-21 17:23:19 -05:00
/* parse the "ssl-default-bind-ciphers" / "ssl-default-server-ciphers" keywords
* in global section . Returns < 0 on alert , > 0 on warning , 0 on success .
*/
static int ssl_parse_global_ciphers ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err )
{
char * * target ;
2016-12-22 17:12:01 -05:00
target = ( args [ 0 ] [ 12 ] = = ' b ' ) ? & global_ssl . listen_default_ciphers : & global_ssl . connect_default_ciphers ;
2016-12-21 17:23:19 -05:00
if ( too_many_args ( 1 , args , err , NULL ) )
return - 1 ;
if ( * ( args [ 1 ] ) = = 0 ) {
memprintf ( err , " global statement '%s' expects a cipher suite as an argument. " , args [ 0 ] ) ;
return - 1 ;
}
free ( * target ) ;
* target = strdup ( args [ 1 ] ) ;
return 0 ;
}
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
/* parse the "ssl-default-bind-ciphersuites" / "ssl-default-server-ciphersuites" keywords
* in global section . Returns < 0 on alert , > 0 on warning , 0 on success .
*/
static int ssl_parse_global_ciphersuites ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err )
{
char * * target ;
target = ( args [ 0 ] [ 12 ] = = ' b ' ) ? & global_ssl . listen_default_ciphersuites : & global_ssl . connect_default_ciphersuites ;
if ( too_many_args ( 1 , args , err , NULL ) )
return - 1 ;
if ( * ( args [ 1 ] ) = = 0 ) {
memprintf ( err , " global statement '%s' expects a cipher suite as an argument. " , args [ 0 ] ) ;
return - 1 ;
}
free ( * target ) ;
* target = strdup ( args [ 1 ] ) ;
return 0 ;
}
# endif
2016-12-21 17:13:03 -05:00
/* parse various global tune.ssl settings consisting in positive integers.
* Returns < 0 on alert , > 0 on warning , 0 on success .
*/
static int ssl_parse_global_int ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err )
{
int * target ;
if ( strcmp ( args [ 0 ] , " tune.ssl.cachesize " ) = = 0 )
target = & global . tune . sslcachesize ;
else if ( strcmp ( args [ 0 ] , " tune.ssl.maxrecord " ) = = 0 )
2016-12-22 17:12:01 -05:00
target = ( int * ) & global_ssl . max_record ;
2016-12-21 17:13:03 -05:00
else if ( strcmp ( args [ 0 ] , " tune.ssl.ssl-ctx-cache-size " ) = = 0 )
2016-12-22 17:12:01 -05:00
target = & global_ssl . ctx_cache ;
2016-12-21 17:17:25 -05:00
else if ( strcmp ( args [ 0 ] , " maxsslconn " ) = = 0 )
target = & global . maxsslconn ;
2017-02-25 06:45:22 -05:00
else if ( strcmp ( args [ 0 ] , " tune.ssl.capture-cipherlist-size " ) = = 0 )
target = & global_ssl . capture_cipherlist ;
2016-12-21 17:13:03 -05:00
else {
memprintf ( err , " '%s' keyword not unhandled (please report this bug). " , args [ 0 ] ) ;
return - 1 ;
}
if ( too_many_args ( 1 , args , err , NULL ) )
return - 1 ;
if ( * ( args [ 1 ] ) = = 0 ) {
memprintf ( err , " '%s' expects an integer argument. " , args [ 0 ] ) ;
return - 1 ;
}
* target = atoi ( args [ 1 ] ) ;
if ( * target < 0 ) {
memprintf ( err , " '%s' expects a positive numeric value. " , args [ 0 ] ) ;
return - 1 ;
}
return 0 ;
}
2017-02-25 06:45:22 -05:00
static int ssl_parse_global_capture_cipherlist ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err )
{
int ret ;
ret = ssl_parse_global_int ( args , section_type , curpx , defpx , file , line , err ) ;
if ( ret ! = 0 )
return ret ;
2017-11-24 11:34:44 -05:00
if ( pool_head_ssl_capture ) {
2017-02-25 06:45:22 -05:00
memprintf ( err , " '%s' is already configured. " , args [ 0 ] ) ;
return - 1 ;
}
2017-11-24 11:34:44 -05:00
pool_head_ssl_capture = create_pool ( " ssl-capture " , sizeof ( struct ssl_capture ) + global_ssl . capture_cipherlist , MEM_F_SHARED ) ;
if ( ! pool_head_ssl_capture ) {
2017-02-25 06:45:22 -05:00
memprintf ( err , " Out of memory error. " ) ;
return - 1 ;
}
return 0 ;
}
2016-12-21 17:13:03 -05:00
/* parse "ssl.force-private-cache".
* Returns < 0 on alert , > 0 on warning , 0 on success .
*/
static int ssl_parse_global_private_cache ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err )
{
if ( too_many_args ( 0 , args , err , NULL ) )
return - 1 ;
2016-12-22 17:12:01 -05:00
global_ssl . private_cache = 1 ;
2016-12-21 17:13:03 -05:00
return 0 ;
}
/* parse "ssl.lifetime".
* Returns < 0 on alert , > 0 on warning , 0 on success .
*/
static int ssl_parse_global_lifetime ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err )
{
const char * res ;
if ( too_many_args ( 1 , args , err , NULL ) )
return - 1 ;
if ( * ( args [ 1 ] ) = = 0 ) {
memprintf ( err , " '%s' expects ssl sessions <lifetime> in seconds as argument. " , args [ 0 ] ) ;
return - 1 ;
}
2016-12-22 17:12:01 -05:00
res = parse_time_err ( args [ 1 ] , & global_ssl . life_time , TIME_UNIT_S ) ;
2016-12-21 17:13:03 -05:00
if ( res ) {
memprintf ( err , " unexpected character '%c' in argument to <%s>. " , * res , args [ 0 ] ) ;
return - 1 ;
}
return 0 ;
}
# ifndef OPENSSL_NO_DH
2016-12-21 17:28:13 -05:00
/* parse "ssl-dh-param-file".
* Returns < 0 on alert , > 0 on warning , 0 on success .
*/
static int ssl_parse_global_dh_param_file ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err )
{
if ( too_many_args ( 1 , args , err , NULL ) )
return - 1 ;
if ( * ( args [ 1 ] ) = = 0 ) {
memprintf ( err , " '%s' expects a file path as an argument. " , args [ 0 ] ) ;
return - 1 ;
}
if ( ssl_sock_load_global_dh_param_from_file ( args [ 1 ] ) ) {
memprintf ( err , " '%s': unable to load DH parameters from file <%s>. " , args [ 0 ] , args [ 1 ] ) ;
return - 1 ;
}
return 0 ;
}
2016-12-21 17:13:03 -05:00
/* parse "ssl.default-dh-param".
* Returns < 0 on alert , > 0 on warning , 0 on success .
*/
static int ssl_parse_global_default_dh ( char * * args , int section_type , struct proxy * curpx ,
struct proxy * defpx , const char * file , int line ,
char * * err )
{
if ( too_many_args ( 1 , args , err , NULL ) )
return - 1 ;
if ( * ( args [ 1 ] ) = = 0 ) {
memprintf ( err , " '%s' expects an integer argument. " , args [ 0 ] ) ;
return - 1 ;
}
2016-12-22 17:12:01 -05:00
global_ssl . default_dh_param = atoi ( args [ 1 ] ) ;
if ( global_ssl . default_dh_param < 1024 ) {
2016-12-21 17:13:03 -05:00
memprintf ( err , " '%s' expects a value >= 1024. " , args [ 0 ] ) ;
return - 1 ;
}
return 0 ;
}
# endif
2016-10-29 12:09:35 -04:00
/* This function is used with TLS ticket keys management. It permits to browse
* each reference . The variable < getnext > must contain the current node ,
* < end > point to the root node .
*/
# if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
static inline
struct tls_keys_ref * tlskeys_list_get_next ( struct tls_keys_ref * getnext , struct list * end )
{
struct tls_keys_ref * ref = getnext ;
while ( 1 ) {
/* Get next list entry. */
ref = LIST_NEXT ( & ref - > list , struct tls_keys_ref * , list ) ;
/* If the entry is the last of the list, return NULL. */
if ( & ref - > list = = end )
return NULL ;
return ref ;
}
}
static inline
struct tls_keys_ref * tlskeys_ref_lookup_ref ( const char * reference )
{
int id ;
char * error ;
/* If the reference starts by a '#', this is numeric id. */
if ( reference [ 0 ] = = ' # ' ) {
/* Try to convert the numeric id. If the conversion fails, the lookup fails. */
id = strtol ( reference + 1 , & error , 10 ) ;
if ( * error ! = ' \0 ' )
return NULL ;
/* Perform the unique id lookup. */
return tlskeys_ref_lookupid ( id ) ;
}
/* Perform the string lookup. */
return tlskeys_ref_lookup ( reference ) ;
}
# endif
# if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
static int cli_io_handler_tlskeys_files ( struct appctx * appctx ) ;
static inline int cli_io_handler_tlskeys_entries ( struct appctx * appctx ) {
return cli_io_handler_tlskeys_files ( appctx ) ;
}
2016-12-16 12:47:27 -05:00
/* dumps all tls keys. Relies on cli.i0 (non-null = only list file names), cli.i1
* ( next index to be dumped ) , and cli . p0 ( next key reference ) .
*/
2016-10-29 12:09:35 -04:00
static int cli_io_handler_tlskeys_files ( struct appctx * appctx ) {
struct stream_interface * si = appctx - > owner ;
switch ( appctx - > st2 ) {
case STAT_ST_INIT :
/* Display the column headers. If the message cannot be sent,
2018-11-15 12:07:59 -05:00
* quit the function with returning 0. The function is called
2016-10-29 12:09:35 -04:00
* later and restart at the state " STAT_ST_INIT " .
*/
chunk_reset ( & trash ) ;
if ( appctx - > io_handler = = cli_io_handler_tlskeys_entries )
chunk_appendf ( & trash , " # id secret \n " ) ;
else
chunk_appendf ( & trash , " # id (file) \n " ) ;
REORG: channel: finally rename the last bi_* / bo_* functions
For HTTP/2 we'll need some buffer-only equivalent functions to some of
the ones applying to channels and still squatting the bi_* / bo_*
namespace. Since these names have kept being misleading for quite some
time now and are really getting annoying, it's time to rename them. This
commit will use "ci/co" as the prefix (for "channel in", "channel out")
instead of "bi/bo". The following ones were renamed :
bi_getblk_nc, bi_getline_nc, bi_putblk, bi_putchr,
bo_getblk, bo_getblk_nc, bo_getline, bo_getline_nc, bo_inject,
bi_putchk, bi_putstr, bo_getchr, bo_skip, bi_swpbuf
2017-10-19 08:32:15 -04:00
if ( ci_putchk ( si_ic ( si ) , & trash ) = = - 1 ) {
2018-11-15 05:08:52 -05:00
si_rx_room_blk ( si ) ;
2016-10-29 12:09:35 -04:00
return 0 ;
}
/* Now, we start the browsing of the references lists.
* Note that the following call to LIST_ELEM return bad pointer . The only
* available field of this pointer is < list > . It is used with the function
* tlskeys_list_get_next ( ) for retruning the first available entry
*/
2016-12-16 12:47:27 -05:00
if ( appctx - > ctx . cli . p0 = = NULL ) {
appctx - > ctx . cli . p0 = LIST_ELEM ( & tlskeys_reference , struct tls_keys_ref * , list ) ;
appctx - > ctx . cli . p0 = tlskeys_list_get_next ( appctx - > ctx . cli . p0 , & tlskeys_reference ) ;
2016-10-29 12:09:35 -04:00
}
appctx - > st2 = STAT_ST_LIST ;
/* fall through */
case STAT_ST_LIST :
2016-12-16 12:47:27 -05:00
while ( appctx - > ctx . cli . p0 ) {
struct tls_keys_ref * ref = appctx - > ctx . cli . p0 ;
2016-10-29 12:09:35 -04:00
chunk_reset ( & trash ) ;
2016-12-16 12:47:27 -05:00
if ( appctx - > io_handler = = cli_io_handler_tlskeys_entries & & appctx - > ctx . cli . i1 = = 0 )
2016-10-29 12:09:35 -04:00
chunk_appendf ( & trash , " # " ) ;
2016-12-16 12:47:27 -05:00
if ( appctx - > ctx . cli . i1 = = 0 )
chunk_appendf ( & trash , " %d (%s) \n " , ref - > unique_id , ref - > filename ) ;
2016-10-29 12:09:35 -04:00
if ( appctx - > io_handler = = cli_io_handler_tlskeys_entries ) {
2018-02-16 05:23:49 -05:00
int head ;
HA_RWLOCK_RDLOCK ( TLSKEYS_REF_LOCK , & ref - > lock ) ;
head = ref - > tls_ticket_enc_index ;
2016-12-16 12:47:27 -05:00
while ( appctx - > ctx . cli . i1 < TLS_TICKETS_NO ) {
2018-07-13 05:56:34 -04:00
struct buffer * t2 = get_trash_chunk ( ) ;
2016-10-29 12:09:35 -04:00
chunk_reset ( t2 ) ;
/* should never fail here because we dump only a key in the t2 buffer */
2019-01-10 11:51:55 -05:00
if ( ref - > key_size_bits = = 128 ) {
t2 - > data = a2base64 ( ( char * ) ( ref - > tlskeys + ( head + 2 + appctx - > ctx . cli . i1 ) % TLS_TICKETS_NO ) ,
sizeof ( struct tls_sess_key_128 ) ,
t2 - > area , t2 - > size ) ;
chunk_appendf ( & trash , " %d.%d %s \n " , ref - > unique_id , appctx - > ctx . cli . i1 ,
t2 - > area ) ;
}
else if ( ref - > key_size_bits = = 256 ) {
t2 - > data = a2base64 ( ( char * ) ( ref - > tlskeys + ( head + 2 + appctx - > ctx . cli . i1 ) % TLS_TICKETS_NO ) ,
sizeof ( struct tls_sess_key_256 ) ,
t2 - > area , t2 - > size ) ;
chunk_appendf ( & trash , " %d.%d %s \n " , ref - > unique_id , appctx - > ctx . cli . i1 ,
t2 - > area ) ;
}
else {
/* This case should never happen */
chunk_appendf ( & trash , " %d.%d <unknown> \n " , ref - > unique_id , appctx - > ctx . cli . i1 ) ;
}
2016-10-29 12:09:35 -04:00
REORG: channel: finally rename the last bi_* / bo_* functions
For HTTP/2 we'll need some buffer-only equivalent functions to some of
the ones applying to channels and still squatting the bi_* / bo_*
namespace. Since these names have kept being misleading for quite some
time now and are really getting annoying, it's time to rename them. This
commit will use "ci/co" as the prefix (for "channel in", "channel out")
instead of "bi/bo". The following ones were renamed :
bi_getblk_nc, bi_getline_nc, bi_putblk, bi_putchr,
bo_getblk, bo_getblk_nc, bo_getline, bo_getline_nc, bo_inject,
bi_putchk, bi_putstr, bo_getchr, bo_skip, bi_swpbuf
2017-10-19 08:32:15 -04:00
if ( ci_putchk ( si_ic ( si ) , & trash ) = = - 1 ) {
2016-10-29 12:09:35 -04:00
/* let's try again later from this stream. We add ourselves into
* this stream ' s users so that it can remove us upon termination .
*/
2018-02-16 05:23:49 -05:00
HA_RWLOCK_RDUNLOCK ( TLSKEYS_REF_LOCK , & ref - > lock ) ;
2018-11-15 05:08:52 -05:00
si_rx_room_blk ( si ) ;
2016-10-29 12:09:35 -04:00
return 0 ;
}
2016-12-16 12:47:27 -05:00
appctx - > ctx . cli . i1 + + ;
2016-10-29 12:09:35 -04:00
}
2018-02-16 05:23:49 -05:00
HA_RWLOCK_RDUNLOCK ( TLSKEYS_REF_LOCK , & ref - > lock ) ;
2016-12-16 12:47:27 -05:00
appctx - > ctx . cli . i1 = 0 ;
2016-10-29 12:09:35 -04:00
}
REORG: channel: finally rename the last bi_* / bo_* functions
For HTTP/2 we'll need some buffer-only equivalent functions to some of
the ones applying to channels and still squatting the bi_* / bo_*
namespace. Since these names have kept being misleading for quite some
time now and are really getting annoying, it's time to rename them. This
commit will use "ci/co" as the prefix (for "channel in", "channel out")
instead of "bi/bo". The following ones were renamed :
bi_getblk_nc, bi_getline_nc, bi_putblk, bi_putchr,
bo_getblk, bo_getblk_nc, bo_getline, bo_getline_nc, bo_inject,
bi_putchk, bi_putstr, bo_getchr, bo_skip, bi_swpbuf
2017-10-19 08:32:15 -04:00
if ( ci_putchk ( si_ic ( si ) , & trash ) = = - 1 ) {
2016-10-29 12:09:35 -04:00
/* let's try again later from this stream. We add ourselves into
* this stream ' s users so that it can remove us upon termination .
*/
2018-11-15 05:08:52 -05:00
si_rx_room_blk ( si ) ;
2016-10-29 12:09:35 -04:00
return 0 ;
}
2016-12-16 12:47:27 -05:00
if ( appctx - > ctx . cli . i0 = = 0 ) /* don't display everything if not necessary */
2016-10-29 12:09:35 -04:00
break ;
/* get next list entry and check the end of the list */
2016-12-16 12:47:27 -05:00
appctx - > ctx . cli . p0 = tlskeys_list_get_next ( appctx - > ctx . cli . p0 , & tlskeys_reference ) ;
2016-10-29 12:09:35 -04:00
}
appctx - > st2 = STAT_ST_FIN ;
/* fall through */
default :
appctx - > st2 = STAT_ST_FIN ;
return 1 ;
}
return 0 ;
}
2016-12-16 12:47:27 -05:00
/* sets cli.i0 to non-zero if only file lists should be dumped */
2018-04-18 07:26:46 -04:00
static int cli_parse_show_tlskeys ( char * * args , char * payload , struct appctx * appctx , void * private )
2016-10-29 12:09:35 -04:00
{
/* no parameter, shows only file list */
if ( ! * args [ 2 ] ) {
2016-12-16 12:47:27 -05:00
appctx - > ctx . cli . i0 = 1 ;
2016-10-29 12:09:35 -04:00
appctx - > io_handler = cli_io_handler_tlskeys_files ;
2016-12-05 08:50:15 -05:00
return 0 ;
2016-10-29 12:09:35 -04:00
}
if ( args [ 2 ] [ 0 ] = = ' * ' ) {
/* list every TLS ticket keys */
2016-12-16 12:47:27 -05:00
appctx - > ctx . cli . i0 = 1 ;
2016-10-29 12:09:35 -04:00
} else {
2016-12-16 12:47:27 -05:00
appctx - > ctx . cli . p0 = tlskeys_ref_lookup_ref ( args [ 2 ] ) ;
if ( ! appctx - > ctx . cli . p0 ) {
2017-07-20 10:49:14 -04:00
appctx - > ctx . cli . severity = LOG_ERR ;
2016-10-29 12:09:35 -04:00
appctx - > ctx . cli . msg = " 'show tls-keys' unable to locate referenced filename \n " ;
2016-11-24 09:53:53 -05:00
appctx - > st0 = CLI_ST_PRINT ;
2016-10-29 12:09:35 -04:00
return 1 ;
}
}
appctx - > io_handler = cli_io_handler_tlskeys_entries ;
2016-12-05 08:50:15 -05:00
return 0 ;
2016-10-29 12:09:35 -04:00
}
2018-04-18 07:26:46 -04:00
static int cli_parse_set_tlskeys ( char * * args , char * payload , struct appctx * appctx , void * private )
2016-10-29 12:09:35 -04:00
{
2016-12-16 12:47:27 -05:00
struct tls_keys_ref * ref ;
2018-08-21 23:26:57 -04:00
int ret ;
2016-12-16 12:47:27 -05:00
2016-10-29 12:09:35 -04:00
/* Expect two parameters: the filename and the new new TLS key in encoding */
if ( ! * args [ 3 ] | | ! * args [ 4 ] ) {
2017-07-20 10:49:14 -04:00
appctx - > ctx . cli . severity = LOG_ERR ;
2016-10-29 12:09:35 -04:00
appctx - > ctx . cli . msg = " 'set ssl tls-key' expects a filename and the new TLS key in base64 encoding. \n " ;
2016-11-24 09:53:53 -05:00
appctx - > st0 = CLI_ST_PRINT ;
2016-10-29 12:09:35 -04:00
return 1 ;
}
2016-12-16 12:47:27 -05:00
ref = tlskeys_ref_lookup_ref ( args [ 3 ] ) ;
if ( ! ref ) {
2017-07-20 10:49:14 -04:00
appctx - > ctx . cli . severity = LOG_ERR ;
2016-10-29 12:09:35 -04:00
appctx - > ctx . cli . msg = " 'set ssl tls-key' unable to locate referenced filename \n " ;
2016-11-24 09:53:53 -05:00
appctx - > st0 = CLI_ST_PRINT ;
2016-10-29 12:09:35 -04:00
return 1 ;
}
2018-08-21 23:26:57 -04:00
ret = base64dec ( args [ 4 ] , strlen ( args [ 4 ] ) , trash . area , trash . size ) ;
2019-01-10 11:51:55 -05:00
if ( ret < 0 ) {
2017-07-20 10:49:14 -04:00
appctx - > ctx . cli . severity = LOG_ERR ;
2016-10-29 12:09:35 -04:00
appctx - > ctx . cli . msg = " 'set ssl tls-key' received invalid base64 encoded TLS key. \n " ;
2016-11-24 09:53:53 -05:00
appctx - > st0 = CLI_ST_PRINT ;
2016-10-29 12:09:35 -04:00
return 1 ;
}
2019-01-10 11:51:55 -05:00
2018-08-21 23:26:57 -04:00
trash . data = ret ;
2019-01-10 11:51:55 -05:00
if ( ssl_sock_update_tlskey_ref ( ref , & trash ) < 0 ) {
appctx - > ctx . cli . severity = LOG_ERR ;
appctx - > ctx . cli . msg = " 'set ssl tls-key' received a key of wrong size. \n " ;
appctx - > st0 = CLI_ST_PRINT ;
return 1 ;
}
2017-07-20 10:49:14 -04:00
appctx - > ctx . cli . severity = LOG_INFO ;
2018-03-15 16:48:50 -04:00
appctx - > ctx . cli . msg = " TLS ticket key updated! \n " ;
2016-11-24 09:53:53 -05:00
appctx - > st0 = CLI_ST_PRINT ;
2016-10-29 12:09:35 -04:00
return 1 ;
}
2017-01-13 11:48:18 -05:00
# endif
2016-10-29 12:09:35 -04:00
2018-04-18 07:26:46 -04:00
static int cli_parse_set_ocspresponse ( char * * args , char * payload , struct appctx * appctx , void * private )
2016-10-29 12:09:35 -04:00
{
# if (defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP)
char * err = NULL ;
2018-08-21 23:26:57 -04:00
int i , j , ret ;
2018-04-18 08:04:58 -04:00
if ( ! payload )
payload = args [ 3 ] ;
2016-10-29 12:09:35 -04:00
/* Expect one parameter: the new response in base64 encoding */
2018-04-18 08:04:58 -04:00
if ( ! * payload ) {
2017-07-20 10:49:14 -04:00
appctx - > ctx . cli . severity = LOG_ERR ;
2016-10-29 12:09:35 -04:00
appctx - > ctx . cli . msg = " 'set ssl ocsp-response' expects response in base64 encoding. \n " ;
2016-11-24 09:53:53 -05:00
appctx - > st0 = CLI_ST_PRINT ;
2016-10-29 12:09:35 -04:00
return 1 ;
}
2018-04-18 08:04:58 -04:00
/* remove \r and \n from the payload */
for ( i = 0 , j = 0 ; payload [ i ] ; i + + ) {
if ( payload [ i ] = = ' \r ' | | payload [ i ] = = ' \n ' )
continue ;
payload [ j + + ] = payload [ i ] ;
}
payload [ j ] = 0 ;
2018-08-21 23:26:57 -04:00
ret = base64dec ( payload , j , trash . area , trash . size ) ;
if ( ret < 0 ) {
2017-07-20 10:49:14 -04:00
appctx - > ctx . cli . severity = LOG_ERR ;
2016-10-29 12:09:35 -04:00
appctx - > ctx . cli . msg = " 'set ssl ocsp-response' received invalid base64 encoded response. \n " ;
2016-11-24 09:53:53 -05:00
appctx - > st0 = CLI_ST_PRINT ;
2016-10-29 12:09:35 -04:00
return 1 ;
}
2018-08-21 23:26:57 -04:00
trash . data = ret ;
2016-10-29 12:09:35 -04:00
if ( ssl_sock_update_ocsp_response ( & trash , & err ) ) {
if ( err ) {
memprintf ( & err , " %s. \n " , err ) ;
appctx - > ctx . cli . err = err ;
2016-11-24 09:53:53 -05:00
appctx - > st0 = CLI_ST_PRINT_FREE ;
2016-10-29 12:09:35 -04:00
}
2018-04-16 13:02:42 -04:00
else {
appctx - > ctx . cli . severity = LOG_ERR ;
appctx - > ctx . cli . msg = " Failed to update OCSP response. \n " ;
appctx - > st0 = CLI_ST_PRINT ;
}
2016-10-29 12:09:35 -04:00
return 1 ;
}
2017-07-20 10:49:14 -04:00
appctx - > ctx . cli . severity = LOG_INFO ;
2018-03-15 16:48:50 -04:00
appctx - > ctx . cli . msg = " OCSP Response updated! \n " ;
2016-11-24 09:53:53 -05:00
appctx - > st0 = CLI_ST_PRINT ;
2016-10-29 12:09:35 -04:00
return 1 ;
# else
2017-07-20 10:49:14 -04:00
appctx - > ctx . cli . severity = LOG_ERR ;
2016-10-29 12:09:35 -04:00
appctx - > ctx . cli . msg = " HAProxy was compiled against a version of OpenSSL that doesn't support OCSP stapling. \n " ;
2016-11-24 09:53:53 -05:00
appctx - > st0 = CLI_ST_PRINT ;
2016-10-29 12:09:35 -04:00
return 1 ;
# endif
}
/* register cli keywords */
static struct cli_kw_list cli_kws = { { } , {
# if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
{ { " show " , " tls-keys " , NULL } , " show tls-keys [id|*]: show tls keys references or dump tls ticket keys when id specified " , cli_parse_show_tlskeys , NULL } ,
2017-10-24 06:26:31 -04:00
{ { " set " , " ssl " , " tls-key " , NULL } , " set ssl tls-key [id|keyfile] <tlskey>: set the next TLS key for the <id> or <keyfile> listener to <tlskey> " , cli_parse_set_tlskeys , NULL } ,
2016-10-29 12:09:35 -04:00
# endif
2017-01-13 11:48:18 -05:00
{ { " set " , " ssl " , " ocsp-response " , NULL } , NULL , cli_parse_set_ocspresponse , NULL } ,
2016-10-29 12:09:35 -04:00
{ { NULL } , NULL , NULL , NULL }
} } ;
2018-11-25 13:14:37 -05:00
INITCALL1 ( STG_REGISTER , cli_register_kw , & cli_kws ) ;
2016-10-29 12:09:35 -04:00
2012-09-10 02:20:03 -04:00
/* Note: must not be declared <const> as its list will be overwritten.
* Please take care of keeping this list alphabetically sorted .
*/
2013-06-21 17:16:39 -04:00
static struct sample_fetch_kw_list sample_fetch_keywords = { ILH , {
2014-04-30 08:21:06 -04:00
{ " ssl_bc " , smp_fetch_ssl_fc , 0 , NULL , SMP_T_BOOL , SMP_USE_L5SRV } ,
2015-07-06 17:43:03 -04:00
{ " ssl_bc_alg_keysize " , smp_fetch_ssl_fc_alg_keysize , 0 , NULL , SMP_T_SINT , SMP_USE_L5SRV } ,
2018-11-22 12:18:29 -05:00
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2018-12-03 16:21:04 -05:00
{ " ssl_bc_alpn " , smp_fetch_ssl_fc_alpn , 0 , NULL , SMP_T_STR , SMP_USE_L5SRV } ,
2018-11-22 12:18:29 -05:00
# endif
2014-04-30 08:21:06 -04:00
{ " ssl_bc_cipher " , smp_fetch_ssl_fc_cipher , 0 , NULL , SMP_T_STR , SMP_USE_L5SRV } ,
2018-11-22 12:18:29 -05:00
# if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
{ " ssl_bc_npn " , smp_fetch_ssl_fc_npn , 0 , NULL , SMP_T_STR , SMP_USE_L5SRV } ,
# endif
2018-02-19 10:14:12 -05:00
{ " ssl_bc_is_resumed " , smp_fetch_ssl_fc_is_resumed , 0 , NULL , SMP_T_BOOL , SMP_USE_L5SRV } ,
2014-04-30 08:21:06 -04:00
{ " ssl_bc_protocol " , smp_fetch_ssl_fc_protocol , 0 , NULL , SMP_T_STR , SMP_USE_L5SRV } ,
2014-04-30 12:49:19 -04:00
{ " ssl_bc_unique_id " , smp_fetch_ssl_fc_unique_id , 0 , NULL , SMP_T_BIN , SMP_USE_L5SRV } ,
2015-07-06 17:43:03 -04:00
{ " ssl_bc_use_keysize " , smp_fetch_ssl_fc_use_keysize , 0 , NULL , SMP_T_SINT , SMP_USE_L5SRV } ,
2018-04-28 19:15:48 -04:00
# if OPENSSL_VERSION_NUMBER > 0x0090800fL
2014-04-30 08:21:06 -04:00
{ " ssl_bc_session_id " , smp_fetch_ssl_fc_session_id , 0 , NULL , SMP_T_BIN , SMP_USE_L5SRV } ,
2018-04-28 19:15:51 -04:00
# endif
# if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
{ " ssl_bc_session_key " , smp_fetch_ssl_fc_session_key , 0 , NULL , SMP_T_BIN , SMP_USE_L5SRV } ,
2018-04-28 19:15:48 -04:00
# endif
2015-07-06 17:43:03 -04:00
{ " ssl_c_ca_err " , smp_fetch_ssl_c_ca_err , 0 , NULL , SMP_T_SINT , SMP_USE_L5CLI } ,
{ " ssl_c_ca_err_depth " , smp_fetch_ssl_c_ca_err_depth , 0 , NULL , SMP_T_SINT , SMP_USE_L5CLI } ,
2014-10-29 14:03:26 -04:00
{ " ssl_c_der " , smp_fetch_ssl_x_der , 0 , NULL , SMP_T_BIN , SMP_USE_L5CLI } ,
2015-07-06 17:43:03 -04:00
{ " ssl_c_err " , smp_fetch_ssl_c_err , 0 , NULL , SMP_T_SINT , SMP_USE_L5CLI } ,
2014-04-30 11:05:08 -04:00
{ " ssl_c_i_dn " , smp_fetch_ssl_x_i_dn , ARG2 ( 0 , STR , SINT ) , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_c_key_alg " , smp_fetch_ssl_x_key_alg , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_c_notafter " , smp_fetch_ssl_x_notafter , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_c_notbefore " , smp_fetch_ssl_x_notbefore , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_c_sig_alg " , smp_fetch_ssl_x_sig_alg , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_c_s_dn " , smp_fetch_ssl_x_s_dn , ARG2 ( 0 , STR , SINT ) , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_c_serial " , smp_fetch_ssl_x_serial , 0 , NULL , SMP_T_BIN , SMP_USE_L5CLI } ,
{ " ssl_c_sha1 " , smp_fetch_ssl_x_sha1 , 0 , NULL , SMP_T_BIN , SMP_USE_L5CLI } ,
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
{ " ssl_c_used " , smp_fetch_ssl_c_used , 0 , NULL , SMP_T_BOOL , SMP_USE_L5CLI } ,
2015-07-06 17:43:03 -04:00
{ " ssl_c_verify " , smp_fetch_ssl_c_verify , 0 , NULL , SMP_T_SINT , SMP_USE_L5CLI } ,
{ " ssl_c_version " , smp_fetch_ssl_x_version , 0 , NULL , SMP_T_SINT , SMP_USE_L5CLI } ,
2014-10-29 14:03:26 -04:00
{ " ssl_f_der " , smp_fetch_ssl_x_der , 0 , NULL , SMP_T_BIN , SMP_USE_L5CLI } ,
2014-04-30 11:05:08 -04:00
{ " ssl_f_i_dn " , smp_fetch_ssl_x_i_dn , ARG2 ( 0 , STR , SINT ) , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_f_key_alg " , smp_fetch_ssl_x_key_alg , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_f_notafter " , smp_fetch_ssl_x_notafter , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_f_notbefore " , smp_fetch_ssl_x_notbefore , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_f_sig_alg " , smp_fetch_ssl_x_sig_alg , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_f_s_dn " , smp_fetch_ssl_x_s_dn , ARG2 ( 0 , STR , SINT ) , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_f_serial " , smp_fetch_ssl_x_serial , 0 , NULL , SMP_T_BIN , SMP_USE_L5CLI } ,
2014-04-30 11:11:25 -04:00
{ " ssl_f_sha1 " , smp_fetch_ssl_x_sha1 , 0 , NULL , SMP_T_BIN , SMP_USE_L5CLI } ,
2015-07-06 17:43:03 -04:00
{ " ssl_f_version " , smp_fetch_ssl_x_version , 0 , NULL , SMP_T_SINT , SMP_USE_L5CLI } ,
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
{ " ssl_fc " , smp_fetch_ssl_fc , 0 , NULL , SMP_T_BOOL , SMP_USE_L5CLI } ,
2015-07-06 17:43:03 -04:00
{ " ssl_fc_alg_keysize " , smp_fetch_ssl_fc_alg_keysize , 0 , NULL , SMP_T_SINT , SMP_USE_L5CLI } ,
2013-12-16 18:20:33 -05:00
{ " ssl_fc_cipher " , smp_fetch_ssl_fc_cipher , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
{ " ssl_fc_has_crt " , smp_fetch_ssl_fc_has_crt , 0 , NULL , SMP_T_BOOL , SMP_USE_L5CLI } ,
2017-10-02 05:51:03 -04:00
{ " ssl_fc_has_early " , smp_fetch_ssl_fc_has_early , 0 , NULL , SMP_T_BOOL , SMP_USE_L5CLI } ,
MEDIUM: samples: use new flags to describe compatibility between fetches and their usages
Samples fetches were relying on two flags SMP_CAP_REQ/SMP_CAP_RES to describe
whether they were compatible with requests rules or with response rules. This
was never reliable because we need a finer granularity (eg: an HTTP request
method needs to parse an HTTP request, and is available past this point).
Some fetches are also dependant on the context (eg: "hdr" uses request or
response depending where it's involved, causing some abiguity).
In order to solve this, we need to precisely indicate in fetches what they
use, and their users will have to compare with what they have.
So now we have a bunch of bits indicating where the sample is fetched in the
processing chain, with a few variants indicating for some of them if it is
permanent or volatile (eg: an HTTP status is stored into the transaction so
it is permanent, despite being caught in the response contents).
The fetches also have a second mask indicating their validity domain. This one
is computed from a conversion table at registration time, so there is no need
for doing it by hand. This validity domain consists in a bitmask with one bit
set for each usage point in the processing chain. Some provisions were made
for upcoming controls such as connection-based TCP rules which apply on top of
the connection layer but before instantiating the session.
Then everywhere a fetch is used, the bit for the control point is checked in
the fetch's validity domain, and it becomes possible to finely ensure that a
fetch will work or not.
Note that we need these two separate bitfields because some fetches are usable
both in request and response (eg: "hdr", "payload"). So the keyword will have
a "use" field made of a combination of several SMP_USE_* values, which will be
converted into a wider list of SMP_VAL_* flags.
The knowledge of permanent vs dynamic information has disappeared for now, as
it was never used. Later we'll probably reintroduce it differently when
dealing with variables. Its only use at the moment could have been to avoid
caching a dynamic rate measurement, but nothing is cached as of now.
2013-01-07 09:42:20 -05:00
{ " ssl_fc_has_sni " , smp_fetch_ssl_fc_has_sni , 0 , NULL , SMP_T_BOOL , SMP_USE_L5CLI } ,
2015-05-17 20:28:57 -04:00
{ " ssl_fc_is_resumed " , smp_fetch_ssl_fc_is_resumed , 0 , NULL , SMP_T_BOOL , SMP_USE_L5CLI } ,
2018-02-15 07:34:58 -05:00
# if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
2013-12-16 18:20:33 -05:00
{ " ssl_fc_npn " , smp_fetch_ssl_fc_npn , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
2013-04-01 20:30:41 -04:00
# endif
2014-02-13 06:29:42 -05:00
# ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
2013-12-16 18:20:33 -05:00
{ " ssl_fc_alpn " , smp_fetch_ssl_fc_alpn , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
2012-10-15 07:19:06 -04:00
# endif
2013-12-16 18:20:33 -05:00
{ " ssl_fc_protocol " , smp_fetch_ssl_fc_protocol , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
2018-04-28 19:15:48 -04:00
# if OPENSSL_VERSION_NUMBER > 0x0090800fL
2014-04-30 12:49:19 -04:00
{ " ssl_fc_unique_id " , smp_fetch_ssl_fc_unique_id , 0 , NULL , SMP_T_BIN , SMP_USE_L5CLI } ,
2018-04-28 19:15:48 -04:00
# endif
2015-07-06 17:43:03 -04:00
{ " ssl_fc_use_keysize " , smp_fetch_ssl_fc_use_keysize , 0 , NULL , SMP_T_SINT , SMP_USE_L5CLI } ,
2018-04-28 19:15:48 -04:00
# if OPENSSL_VERSION_NUMBER > 0x0090800fL
2013-12-16 18:20:33 -05:00
{ " ssl_fc_session_id " , smp_fetch_ssl_fc_session_id , 0 , NULL , SMP_T_BIN , SMP_USE_L5CLI } ,
2018-04-28 19:15:48 -04:00
# endif
2018-04-28 19:15:51 -04:00
# if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
{ " ssl_fc_session_key " , smp_fetch_ssl_fc_session_key , 0 , NULL , SMP_T_BIN , SMP_USE_L5CLI } ,
# endif
2018-04-28 19:15:48 -04:00
# ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
2013-12-16 18:20:33 -05:00
{ " ssl_fc_sni " , smp_fetch_ssl_fc_sni , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
2018-04-28 19:15:48 -04:00
# endif
2017-02-25 06:45:22 -05:00
{ " ssl_fc_cipherlist_bin " , smp_fetch_ssl_fc_cl_bin , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_fc_cipherlist_hex " , smp_fetch_ssl_fc_cl_hex , 0 , NULL , SMP_T_BIN , SMP_USE_L5CLI } ,
{ " ssl_fc_cipherlist_str " , smp_fetch_ssl_fc_cl_str , 0 , NULL , SMP_T_STR , SMP_USE_L5CLI } ,
{ " ssl_fc_cipherlist_xxh " , smp_fetch_ssl_fc_cl_xxh64 , 0 , NULL , SMP_T_SINT , SMP_USE_L5CLI } ,
2012-09-10 02:20:03 -04:00
{ NULL , NULL , 0 , 0 , 0 } ,
} } ;
2018-11-25 13:14:37 -05:00
INITCALL1 ( STG_REGISTER , sample_register_fetches , & sample_fetch_keywords ) ;
2012-09-10 02:20:03 -04:00
/* Note: must not be declared <const> as its list will be overwritten.
* Please take care of keeping this list alphabetically sorted .
*/
2013-06-21 17:16:39 -04:00
static struct acl_kw_list acl_kws = { ILH , {
2014-03-05 10:07:08 -05:00
{ " ssl_fc_sni_end " , " ssl_fc_sni " , PAT_MATCH_END } ,
{ " ssl_fc_sni_reg " , " ssl_fc_sni " , PAT_MATCH_REG } ,
2013-01-11 09:49:37 -05:00
{ /* END */ } ,
2012-09-10 02:20:03 -04:00
} } ;
2018-11-25 13:14:37 -05:00
INITCALL1 ( STG_REGISTER , acl_register_keywords , & acl_kws ) ;
2012-09-14 01:53:05 -04:00
/* Note: must not be declared <const> as its list will be overwritten.
* Please take care of keeping this list alphabetically sorted , doing so helps
* all code contributors .
* Optional keywords are also declared with a NULL - > parse ( ) function so that
* the config parser can report an appropriate error when a known keyword was
* not enabled .
*/
2016-12-29 12:26:15 -05:00
static struct ssl_bind_kw ssl_bind_kws [ ] = {
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
{ " allow-0rtt " , ssl_bind_parse_allow_0rtt , 0 } , /* allow 0-RTT */
2016-12-29 12:26:15 -05:00
{ " alpn " , ssl_bind_parse_alpn , 1 } , /* set ALPN supported protocols */
{ " ca-file " , ssl_bind_parse_ca_file , 1 } , /* set CAfile to process verify on client cert */
{ " ciphers " , ssl_bind_parse_ciphers , 1 } , /* set SSL cipher suite */
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
{ " ciphersuites " , ssl_bind_parse_ciphersuites , 1 } , /* set TLS 1.3 cipher suite */
# endif
2016-12-29 12:26:15 -05:00
{ " crl-file " , ssl_bind_parse_crl_file , 1 } , /* set certificat revocation list file use on client cert verify */
2017-01-09 10:15:54 -05:00
{ " curves " , ssl_bind_parse_curves , 1 } , /* set SSL curve suite */
2016-12-29 12:26:15 -05:00
{ " ecdhe " , ssl_bind_parse_ecdhe , 1 } , /* defines named curve for elliptic curve Diffie-Hellman */
2017-07-28 09:01:05 -04:00
{ " no-ca-names " , ssl_bind_parse_no_ca_names , 0 } , /* do not send ca names to clients (ca_file related) */
2016-12-29 12:26:15 -05:00
{ " npn " , ssl_bind_parse_npn , 1 } , /* set NPN supported protocols */
2017-05-18 06:46:50 -04:00
{ " ssl-min-ver " , ssl_bind_parse_tls_method_minmax , 1 } , /* minimum version */
{ " ssl-max-ver " , ssl_bind_parse_tls_method_minmax , 1 } , /* maximum version */
2016-12-29 12:26:15 -05:00
{ " verify " , ssl_bind_parse_verify , 1 } , /* set SSL verify method */
{ NULL , NULL , 0 } ,
} ;
2018-11-25 13:14:37 -05:00
/* no initcall for ssl_bind_kws, these ones are parsed in the parser loop */
2012-09-18 12:24:39 -04:00
static struct bind_kw_list bind_kws = { " SSL " , { } , {
MEDIUM: ssl: Handle early data with OpenSSL 1.1.1
When compiled with Openssl >= 1.1.1, before attempting to do the handshake,
try to read any early data. If any early data is present, then we'll create
the session, read the data, and handle the request before we're doing the
handshake.
For this, we add a new connection flag, CO_FL_EARLY_SSL_HS, which is not
part of the CO_FL_HANDSHAKE set, allowing to proceed with a session even
before an SSL handshake is completed.
As early data do have security implication, we let the origin server know
the request comes from early data by adding the "Early-Data" header, as
specified in this draft from the HTTP working group :
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-replay
2017-09-22 12:26:28 -04:00
{ " allow-0rtt " , bind_parse_allow_0rtt , 0 } , /* Allow 0RTT */
2017-03-30 13:19:37 -04:00
{ " alpn " , bind_parse_alpn , 1 } , /* set ALPN supported protocols */
{ " ca-file " , bind_parse_ca_file , 1 } , /* set CAfile to process verify on client cert */
{ " ca-ignore-err " , bind_parse_ignore_err , 1 } , /* set error IDs to ignore on verify depth > 0 */
{ " ca-sign-file " , bind_parse_ca_sign_file , 1 } , /* set CAFile used to generate and sign server certs */
{ " ca-sign-pass " , bind_parse_ca_sign_pass , 1 } , /* set CAKey passphrase */
{ " ciphers " , bind_parse_ciphers , 1 } , /* set SSL cipher suite */
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
{ " ciphersuites " , bind_parse_ciphersuites , 1 } , /* set TLS 1.3 cipher suite */
# endif
2017-03-30 13:19:37 -04:00
{ " crl-file " , bind_parse_crl_file , 1 } , /* set certificat revocation list file use on client cert verify */
{ " crt " , bind_parse_crt , 1 } , /* load SSL certificates from this location */
{ " crt-ignore-err " , bind_parse_ignore_err , 1 } , /* set error IDs to ingore on verify depth == 0 */
{ " crt-list " , bind_parse_crt_list , 1 } , /* load a list of crt from this location */
{ " curves " , bind_parse_curves , 1 } , /* set SSL curve suite */
{ " ecdhe " , bind_parse_ecdhe , 1 } , /* defines named curve for elliptic curve Diffie-Hellman */
{ " force-sslv3 " , bind_parse_tls_method_options , 0 } , /* force SSLv3 */
{ " force-tlsv10 " , bind_parse_tls_method_options , 0 } , /* force TLSv10 */
{ " force-tlsv11 " , bind_parse_tls_method_options , 0 } , /* force TLSv11 */
{ " force-tlsv12 " , bind_parse_tls_method_options , 0 } , /* force TLSv12 */
2017-03-30 13:29:39 -04:00
{ " force-tlsv13 " , bind_parse_tls_method_options , 0 } , /* force TLSv13 */
2017-03-30 13:19:37 -04:00
{ " generate-certificates " , bind_parse_generate_certs , 0 } , /* enable the server certificates generation */
2017-07-28 09:01:05 -04:00
{ " no-ca-names " , bind_parse_no_ca_names , 0 } , /* do not send ca names to clients (ca_file related) */
2017-03-30 13:19:37 -04:00
{ " no-sslv3 " , bind_parse_tls_method_options , 0 } , /* disable SSLv3 */
{ " no-tlsv10 " , bind_parse_tls_method_options , 0 } , /* disable TLSv10 */
{ " no-tlsv11 " , bind_parse_tls_method_options , 0 } , /* disable TLSv11 */
{ " no-tlsv12 " , bind_parse_tls_method_options , 0 } , /* disable TLSv12 */
2017-03-30 13:29:39 -04:00
{ " no-tlsv13 " , bind_parse_tls_method_options , 0 } , /* disable TLSv13 */
2017-03-30 13:19:37 -04:00
{ " no-tls-tickets " , bind_parse_no_tls_tickets , 0 } , /* disable session resumption tickets */
{ " ssl " , bind_parse_ssl , 0 } , /* enable SSL processing */
2017-03-31 09:02:54 -04:00
{ " ssl-min-ver " , bind_parse_tls_method_minmax , 1 } , /* minimum version */
{ " ssl-max-ver " , bind_parse_tls_method_minmax , 1 } , /* maximum version */
2017-03-30 13:19:37 -04:00
{ " strict-sni " , bind_parse_strict_sni , 0 } , /* refuse negotiation if sni doesn't match a certificate */
{ " tls-ticket-keys " , bind_parse_tls_ticket_keys , 1 } , /* set file to load TLS ticket keys from */
{ " verify " , bind_parse_verify , 1 } , /* set SSL verify method */
{ " npn " , bind_parse_npn , 1 } , /* set NPN supported protocols */
{ " prefer-client-ciphers " , bind_parse_pcc , 0 } , /* prefer client ciphers */
2012-09-14 01:53:05 -04:00
{ NULL , NULL , 0 } ,
} } ;
2012-05-18 09:47:34 -04:00
2018-11-25 13:14:37 -05:00
INITCALL1 ( STG_REGISTER , bind_register_keywords , & bind_kws ) ;
2012-10-10 17:04:25 -04:00
/* Note: must not be declared <const> as its list will be overwritten.
* Please take care of keeping this list alphabetically sorted , doing so helps
* all code contributors .
* Optional keywords are also declared with a NULL - > parse ( ) function so that
* the config parser can report an appropriate error when a known keyword was
* not enabled .
*/
static struct srv_kw_list srv_kws = { " SSL " , { } , {
2017-11-03 11:27:47 -04:00
{ " allow-0rtt " , srv_parse_allow_0rtt , 0 , 1 } , /* Allow using early data on this server */
2018-11-20 17:33:50 -05:00
{ " alpn " , srv_parse_alpn , 1 , 1 } , /* Set ALPN supported protocols */
2017-03-31 09:02:54 -04:00
{ " ca-file " , srv_parse_ca_file , 1 , 1 } , /* set CAfile to process verify server cert */
2018-12-21 13:47:01 -05:00
{ " check-alpn " , srv_parse_alpn , 1 , 1 } , /* Set ALPN used for checks */
2017-10-17 11:33:43 -04:00
{ " check-sni " , srv_parse_check_sni , 1 , 1 } , /* set SNI */
2017-03-31 09:02:54 -04:00
{ " check-ssl " , srv_parse_check_ssl , 0 , 1 } , /* enable SSL for health checks */
{ " ciphers " , srv_parse_ciphers , 1 , 1 } , /* select the cipher suite */
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
{ " ciphersuites " , srv_parse_ciphersuites , 1 , 1 } , /* select the cipher suite */
# endif
2017-03-31 09:02:54 -04:00
{ " crl-file " , srv_parse_crl_file , 1 , 1 } , /* set certificate revocation list file use on server cert verify */
{ " crt " , srv_parse_crt , 1 , 1 } , /* set client certificate */
{ " force-sslv3 " , srv_parse_tls_method_options , 0 , 1 } , /* force SSLv3 */
{ " force-tlsv10 " , srv_parse_tls_method_options , 0 , 1 } , /* force TLSv10 */
{ " force-tlsv11 " , srv_parse_tls_method_options , 0 , 1 } , /* force TLSv11 */
{ " force-tlsv12 " , srv_parse_tls_method_options , 0 , 1 } , /* force TLSv12 */
{ " force-tlsv13 " , srv_parse_tls_method_options , 0 , 1 } , /* force TLSv13 */
{ " no-check-ssl " , srv_parse_no_check_ssl , 0 , 1 } , /* disable SSL for health checks */
{ " no-send-proxy-v2-ssl " , srv_parse_no_send_proxy_ssl , 0 , 1 } , /* do not send PROXY protocol header v2 with SSL info */
{ " no-send-proxy-v2-ssl-cn " , srv_parse_no_send_proxy_cn , 0 , 1 } , /* do not send PROXY protocol header v2 with CN */
{ " no-ssl " , srv_parse_no_ssl , 0 , 1 } , /* disable SSL processing */
{ " no-ssl-reuse " , srv_parse_no_ssl_reuse , 0 , 1 } , /* disable session reuse */
{ " no-sslv3 " , srv_parse_tls_method_options , 0 , 0 } , /* disable SSLv3 */
{ " no-tlsv10 " , srv_parse_tls_method_options , 0 , 0 } , /* disable TLSv10 */
{ " no-tlsv11 " , srv_parse_tls_method_options , 0 , 0 } , /* disable TLSv11 */
{ " no-tlsv12 " , srv_parse_tls_method_options , 0 , 0 } , /* disable TLSv12 */
{ " no-tlsv13 " , srv_parse_tls_method_options , 0 , 0 } , /* disable TLSv13 */
{ " no-tls-tickets " , srv_parse_no_tls_tickets , 0 , 1 } , /* disable session resumption tickets */
2018-11-20 17:33:50 -05:00
{ " npn " , srv_parse_npn , 1 , 1 } , /* Set NPN supported protocols */
2017-03-31 09:02:54 -04:00
{ " send-proxy-v2-ssl " , srv_parse_send_proxy_ssl , 0 , 1 } , /* send PROXY protocol header v2 with SSL info */
{ " send-proxy-v2-ssl-cn " , srv_parse_send_proxy_cn , 0 , 1 } , /* send PROXY protocol header v2 with CN */
{ " sni " , srv_parse_sni , 1 , 1 } , /* send SNI extension */
{ " ssl " , srv_parse_ssl , 0 , 1 } , /* enable SSL processing */
{ " ssl-min-ver " , srv_parse_tls_method_minmax , 1 , 1 } , /* minimum version */
{ " ssl-max-ver " , srv_parse_tls_method_minmax , 1 , 1 } , /* maximum version */
{ " ssl-reuse " , srv_parse_ssl_reuse , 0 , 1 } , /* enable session reuse */
{ " tls-tickets " , srv_parse_tls_tickets , 0 , 1 } , /* enable session resumption tickets */
{ " verify " , srv_parse_verify , 1 , 1 } , /* set SSL verify method */
{ " verifyhost " , srv_parse_verifyhost , 1 , 1 } , /* require that SSL cert verifies for hostname */
2012-10-10 17:04:25 -04:00
{ NULL , NULL , 0 , 0 } ,
} } ;
2018-11-25 13:14:37 -05:00
INITCALL1 ( STG_REGISTER , srv_register_keywords , & srv_kws ) ;
2014-10-30 10:56:50 -04:00
static struct cfg_kw_list cfg_kws = { ILH , {
2016-12-21 16:44:46 -05:00
{ CFG_GLOBAL , " ca-base " , ssl_parse_global_ca_crt_base } ,
{ CFG_GLOBAL , " crt-base " , ssl_parse_global_ca_crt_base } ,
2016-12-21 17:17:25 -05:00
{ CFG_GLOBAL , " maxsslconn " , ssl_parse_global_int } ,
2014-10-30 10:56:50 -04:00
{ CFG_GLOBAL , " ssl-default-bind-options " , ssl_parse_default_bind_options } ,
{ CFG_GLOBAL , " ssl-default-server-options " , ssl_parse_default_server_options } ,
2016-12-21 17:28:13 -05:00
# ifndef OPENSSL_NO_DH
{ CFG_GLOBAL , " ssl-dh-param-file " , ssl_parse_global_dh_param_file } ,
# endif
2017-01-13 20:42:15 -05:00
{ CFG_GLOBAL , " ssl-mode-async " , ssl_parse_global_ssl_async } ,
2017-05-29 08:36:20 -04:00
# ifndef OPENSSL_NO_ENGINE
2017-01-20 20:10:18 -05:00
{ CFG_GLOBAL , " ssl-engine " , ssl_parse_global_ssl_engine } ,
2017-05-29 08:36:20 -04:00
# endif
2016-12-21 17:13:03 -05:00
{ CFG_GLOBAL , " tune.ssl.cachesize " , ssl_parse_global_int } ,
# ifndef OPENSSL_NO_DH
{ CFG_GLOBAL , " tune.ssl.default-dh-param " , ssl_parse_global_default_dh } ,
# endif
{ CFG_GLOBAL , " tune.ssl.force-private-cache " , ssl_parse_global_private_cache } ,
{ CFG_GLOBAL , " tune.ssl.lifetime " , ssl_parse_global_lifetime } ,
{ CFG_GLOBAL , " tune.ssl.maxrecord " , ssl_parse_global_int } ,
{ CFG_GLOBAL , " tune.ssl.ssl-ctx-cache-size " , ssl_parse_global_int } ,
2017-02-25 06:45:22 -05:00
{ CFG_GLOBAL , " tune.ssl.capture-cipherlist-size " , ssl_parse_global_capture_cipherlist } ,
2016-12-21 17:23:19 -05:00
{ CFG_GLOBAL , " ssl-default-bind-ciphers " , ssl_parse_global_ciphers } ,
{ CFG_GLOBAL , " ssl-default-server-ciphers " , ssl_parse_global_ciphers } ,
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
{ CFG_GLOBAL , " ssl-default-bind-ciphersuites " , ssl_parse_global_ciphersuites } ,
{ CFG_GLOBAL , " ssl-default-server-ciphersuites " , ssl_parse_global_ciphersuites } ,
# endif
2014-10-30 10:56:50 -04:00
{ 0 , NULL , NULL } ,
} } ;
2018-11-25 13:14:37 -05:00
INITCALL1 ( STG_REGISTER , cfg_register_keywords , & cfg_kws ) ;
REORG: connection: rename the data layer the "transport layer"
While working on the changes required to make the health checks use the
new connections, it started to become obvious that some naming was not
logical at all in the connections. Specifically, it is not logical to
call the "data layer" the layer which is in charge for all the handshake
and which does not yet provide a data layer once established until a
session has allocated all the required buffers.
In fact, it's more a transport layer, which makes much more sense. The
transport layer offers a medium on which data can transit, and it offers
the functions to move these data when the upper layer requests this. And
it is the upper layer which iterates over the transport layer's functions
to move data which should be called the data layer.
The use case where it's obvious is with embryonic sessions : an incoming
SSL connection is accepted. Only the connection is allocated, not the
buffers nor stream interface, etc... The connection handles the SSL
handshake by itself. Once this handshake is complete, we can't use the
data functions because the buffers and stream interface are not there
yet. Hence we have to first call a specific function to complete the
session initialization, after which we'll be able to use the data
functions. This clearly proves that SSL here is only a transport layer
and that the stream interface constitutes the data layer.
A similar change will be performed to rename app_cb => data, but the
two could not be in the same commit for obvious reasons.
2012-10-02 18:19:48 -04:00
/* transport-layer operations for SSL sockets */
2016-12-22 15:08:52 -05:00
static struct xprt_ops ssl_sock = {
2012-05-18 09:47:34 -04:00
. snd_buf = ssl_sock_from_buf ,
. rcv_buf = ssl_sock_to_buf ,
2018-07-17 12:46:31 -04:00
. subscribe = conn_subscribe ,
2018-09-28 11:57:58 -04:00
. unsubscribe = conn_unsubscribe ,
2012-05-18 09:47:34 -04:00
. rcv_pipe = NULL ,
. snd_pipe = NULL ,
. shutr = NULL ,
. shutw = ssl_sock_shutw ,
. close = ssl_sock_close ,
. init = ssl_sock_init ,
2016-12-21 17:38:39 -05:00
. prepare_bind_conf = ssl_sock_prepare_bind_conf ,
2016-12-22 11:30:54 -05:00
. destroy_bind_conf = ssl_sock_destroy_bind_conf ,
2016-12-22 15:16:08 -05:00
. prepare_srv = ssl_sock_prepare_srv_ctx ,
. destroy_srv = ssl_sock_free_srv_ctx ,
2016-12-04 12:44:29 -05:00
. get_alpn = ssl_sock_get_alpn ,
2016-11-24 10:58:12 -05:00
. name = " SSL " ,
2012-05-18 09:47:34 -04:00
} ;
2017-10-02 05:51:03 -04:00
enum act_return ssl_action_wait_for_hs ( struct act_rule * rule , struct proxy * px ,
struct session * sess , struct stream * s , int flags )
{
struct connection * conn ;
2017-11-27 12:41:32 -05:00
struct conn_stream * cs ;
2017-10-02 05:51:03 -04:00
conn = objt_conn ( sess - > origin ) ;
2017-11-27 12:41:32 -05:00
cs = objt_cs ( s - > si [ 0 ] . end ) ;
2017-10-02 05:51:03 -04:00
2017-11-27 12:41:32 -05:00
if ( conn & & cs ) {
2017-10-02 05:51:03 -04:00
if ( conn - > flags & ( CO_FL_EARLY_SSL_HS | CO_FL_SSL_WAIT_HS ) ) {
2017-11-27 12:41:32 -05:00
cs - > flags | = CS_FL_WAIT_FOR_HS ;
2017-10-02 05:51:03 -04:00
s - > req . flags | = CF_READ_NULL ;
return ACT_RET_YIELD ;
}
}
return ( ACT_RET_CONT ) ;
}
static enum act_parse_ret ssl_parse_wait_for_hs ( const char * * args , int * orig_arg , struct proxy * px , struct act_rule * rule , char * * err )
{
rule - > action_ptr = ssl_action_wait_for_hs ;
return ACT_RET_PRS_OK ;
}
static struct action_kw_list http_req_actions = { ILH , {
{ " wait-for-handshake " , ssl_parse_wait_for_hs } ,
{ /* END */ }
} } ;
2018-11-25 13:14:37 -05:00
INITCALL1 ( STG_REGISTER , http_req_keywords_register , & http_req_actions ) ;
2015-11-06 14:02:41 -05:00
# if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
2015-03-07 17:03:59 -05:00
static void ssl_sock_sctl_free_func ( void * parent , void * ptr , CRYPTO_EX_DATA * ad , int idx , long argl , void * argp )
{
if ( ptr ) {
chunk_destroy ( ptr ) ;
free ( ptr ) ;
}
}
# endif
2017-03-07 12:34:58 -05:00
static void ssl_sock_capture_free_func ( void * parent , void * ptr , CRYPTO_EX_DATA * ad , int idx , long argl , void * argp )
{
2017-11-24 11:34:44 -05:00
pool_free ( pool_head_ssl_capture , ptr ) ;
2017-03-07 12:34:58 -05:00
}
2015-03-07 17:03:59 -05:00
2012-05-18 09:47:34 -04:00
__attribute__ ( ( constructor ) )
2012-10-10 17:04:25 -04:00
static void __ssl_sock_init ( void )
{
2012-05-18 09:47:34 -04:00
STACK_OF ( SSL_COMP ) * cm ;
2016-12-22 17:12:01 -05:00
if ( global_ssl . listen_default_ciphers )
global_ssl . listen_default_ciphers = strdup ( global_ssl . listen_default_ciphers ) ;
if ( global_ssl . connect_default_ciphers )
global_ssl . connect_default_ciphers = strdup ( global_ssl . connect_default_ciphers ) ;
2018-09-14 05:14:21 -04:00
# if (OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
if ( global_ssl . listen_default_ciphersuites )
global_ssl . listen_default_ciphersuites = strdup ( global_ssl . listen_default_ciphersuites ) ;
if ( global_ssl . connect_default_ciphersuites )
global_ssl . connect_default_ciphersuites = strdup ( global_ssl . connect_default_ciphersuites ) ;
# endif
2014-02-13 05:36:41 -05:00
2016-12-22 14:25:26 -05:00
xprt_register ( XPRT_SSL , & ssl_sock ) ;
2018-12-14 11:47:02 -05:00
# if OPENSSL_VERSION_NUMBER < 0x10100000L
2012-05-18 09:47:34 -04:00
SSL_library_init ( ) ;
2018-12-14 11:47:02 -05:00
# endif
2012-05-18 09:47:34 -04:00
cm = SSL_COMP_get_compression_methods ( ) ;
sk_SSL_COMP_zero ( cm ) ;
2018-12-14 11:47:02 -05:00
# if defined(USE_THREAD) && ((OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER))
2017-06-15 10:37:39 -04:00
ssl_locking_init ( ) ;
# endif
2015-11-06 14:02:41 -05:00
# if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER)
2015-03-07 17:03:59 -05:00
sctl_ex_index = SSL_CTX_get_ex_new_index ( 0 , NULL , NULL , NULL , ssl_sock_sctl_free_func ) ;
# endif
BUG/MAJOR: ssl: OpenSSL context is stored in non-reserved memory slot
We never saw unexplicated crash with SSL, so I suppose that we are
luck, or the slot 0 is always reserved. Anyway the usage of the macro
SSL_get_app_data() and SSL_set_app_data() seem wrong. This patch change
the deprecated functions SSL_get_app_data() and SSL_set_app_data()
by the new functions SSL_get_ex_data() and SSL_set_ex_data(), and
it reserves the slot in the SSL memory space.
For information, this is the two declaration which seems wrong or
incomplete in the OpenSSL ssl.h file. We can see the usage of the
slot 0 whoch is hardcoded, but never reserved.
#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg))
#define SSL_get_app_data(s) (SSL_get_ex_data(s,0))
This patch must be backported at least in 1.8, maybe in other versions.
2018-06-17 15:37:05 -04:00
ssl_app_data_index = SSL_get_ex_new_index ( 0 , NULL , NULL , NULL , NULL ) ;
2018-06-17 15:33:01 -04:00
ssl_capture_ptr_index = SSL_get_ex_new_index ( 0 , NULL , NULL , NULL , ssl_sock_capture_free_func ) ;
2017-10-31 10:46:07 -04:00
ssl_pkey_info_index = SSL_CTX_get_ex_new_index ( 0 , NULL , NULL , NULL , NULL ) ;
2017-05-29 08:36:20 -04:00
# ifndef OPENSSL_NO_ENGINE
2017-01-20 20:10:18 -05:00
ENGINE_load_builtin_engines ( ) ;
2017-01-13 20:42:15 -05:00
hap_register_post_check ( ssl_check_async_engine_count ) ;
2017-05-29 08:36:20 -04:00
# endif
2016-12-22 16:46:15 -05:00
# if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
hap_register_post_check ( tlskeys_finalize_config ) ;
# endif
2015-01-15 15:34:39 -05:00
2018-11-26 04:19:54 -05:00
global . ssl_session_max_cost = SSL_SESSION_MAX_COST ;
global . ssl_handshake_max_cost = SSL_HANDSHAKE_MAX_COST ;
# ifndef OPENSSL_NO_DH
ssl_dh_ptr_index = SSL_CTX_get_ex_new_index ( 0 , NULL , NULL , NULL , NULL ) ;
hap_register_post_deinit ( ssl_free_dh ) ;
# endif
# ifndef OPENSSL_NO_ENGINE
hap_register_post_deinit ( ssl_free_engines ) ;
# endif
/* Load SSL string for the verbose & debug mode. */
ERR_load_SSL_strings ( ) ;
}
/* Compute and register the version string */
static void ssl_register_build_options ( )
{
char * ptr = NULL ;
int i ;
2016-12-21 13:23:20 -05:00
memprintf ( & ptr , " Built with OpenSSL version : "
# ifdef OPENSSL_IS_BORINGSSL
2017-03-24 10:20:03 -04:00
" BoringSSL " ) ;
2016-12-21 13:23:20 -05:00
# else /* OPENSSL_IS_BORINGSSL */
OPENSSL_VERSION_TEXT
" \n Running on OpenSSL version : %s%s " ,
2018-12-14 11:47:02 -05:00
OpenSSL_version ( OPENSSL_VERSION ) ,
( ( OPENSSL_VERSION_NUMBER ^ OpenSSL_version_num ( ) ) > > 8 ) ? " (VERSIONS DIFFER!) " : " " ) ;
2016-12-21 13:23:20 -05:00
# endif
memprintf ( & ptr , " %s \n OpenSSL library supports TLS extensions : "
# if OPENSSL_VERSION_NUMBER < 0x00907000L
" no (library version too old) "
# elif defined(OPENSSL_NO_TLSEXT)
" no (disabled via OPENSSL_NO_TLSEXT) "
# else
" yes "
# endif
" " , ptr ) ;
memprintf ( & ptr , " %s \n OpenSSL library supports SNI : "
# ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
" yes "
# else
# ifdef OPENSSL_NO_TLSEXT
" no (because of OPENSSL_NO_TLSEXT) "
# else
" no (version might be too old, 0.9.8f min needed) "
# endif
2017-03-24 10:20:03 -04:00
# endif
" " , ptr ) ;
2017-07-12 08:25:38 -04:00
memprintf ( & ptr , " %s \n OpenSSL library supports : " , ptr ) ;
for ( i = CONF_TLSV_MIN ; i < = CONF_TLSV_MAX ; i + + )
if ( methodVersions [ i ] . option )
memprintf ( & ptr , " %s %s " , ptr , methodVersions [ i ] . name ) ;
2016-12-21 13:23:20 -05:00
hap_register_build_opts ( ptr , 1 ) ;
2018-11-26 04:19:54 -05:00
}
2016-12-21 13:23:20 -05:00
2018-11-26 04:19:54 -05:00
INITCALL0 ( STG_REGISTER , ssl_register_build_options ) ;
2015-05-28 10:23:00 -04:00
2012-05-18 09:47:34 -04:00
2017-05-29 08:36:20 -04:00
# ifndef OPENSSL_NO_ENGINE
2017-01-20 20:10:18 -05:00
void ssl_free_engines ( void ) {
struct ssl_engine_list * wl , * wlb ;
/* free up engine list */
list_for_each_entry_safe ( wl , wlb , & openssl_engines , list ) {
ENGINE_finish ( wl - > e ) ;
ENGINE_free ( wl - > e ) ;
LIST_DEL ( & wl - > list ) ;
free ( wl ) ;
}
}
2017-05-29 08:36:20 -04:00
# endif
2015-06-09 11:29:50 -04:00
2015-05-28 10:39:47 -04:00
# ifndef OPENSSL_NO_DH
2017-01-20 20:10:18 -05:00
void ssl_free_dh ( void ) {
if ( local_dh_1024 ) {
DH_free ( local_dh_1024 ) ;
local_dh_1024 = NULL ;
}
if ( local_dh_2048 ) {
DH_free ( local_dh_2048 ) ;
local_dh_2048 = NULL ;
}
if ( local_dh_4096 ) {
DH_free ( local_dh_4096 ) ;
local_dh_4096 = NULL ;
}
2015-05-29 09:53:22 -04:00
if ( global_dh ) {
DH_free ( global_dh ) ;
global_dh = NULL ;
}
2017-01-20 20:10:18 -05:00
}
# endif
__attribute__ ( ( destructor ) )
static void __ssl_sock_deinit ( void )
{
# if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME && !defined SSL_NO_GENERATE_CERTIFICATES)
2017-06-15 10:37:39 -04:00
if ( ssl_ctx_lru_tree ) {
lru64_destroy ( ssl_ctx_lru_tree ) ;
2017-11-07 04:42:54 -05:00
HA_RWLOCK_DESTROY ( & ssl_ctx_lru_rwlock ) ;
2017-06-15 10:37:39 -04:00
}
2015-05-28 10:39:47 -04:00
# endif
2018-12-14 11:47:02 -05:00
# if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
2015-05-28 10:39:47 -04:00
ERR_remove_state ( 0 ) ;
ERR_free_strings ( ) ;
EVP_cleanup ( ) ;
2018-12-14 11:47:02 -05:00
# endif
2015-05-28 10:39:47 -04:00
2018-12-14 11:47:02 -05:00
# if ((OPENSSL_VERSION_NUMBER >= 0x00907000L) && (OPENSSL_VERSION_NUMBER < 0x10100000L)) || defined(LIBRESSL_VERSION_NUMBER)
2015-05-28 10:39:47 -04:00
CRYPTO_cleanup_all_ex_data ( ) ;
# endif
}
2012-05-18 09:47:34 -04:00
/*
* Local variables :
* c - indent - level : 8
* c - basic - offset : 8
* End :
*/