2008-01-28 21:37:16 +00:00
/* source: xio-openssl.c */
2016-07-22 06:54:31 +00:00
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
2008-01-27 12:00:08 +00:00
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file contains the implementation of the openssl addresses */
# include "xiosysincludes.h"
# if WITH_OPENSSL /* make this address configure dependend */
2015-01-12 22:34:47 +00:00
# include <openssl/conf.h>
# include <openssl/x509v3.h>
2008-01-27 12:00:08 +00:00
# include "xioopen.h"
# include "xio-fd.h"
2023-10-22 21:15:49 +00:00
# include "xio-ip.h"
2008-01-27 12:00:08 +00:00
# include "xio-socket.h" /* _xioopen_connect() */
# include "xio-listen.h"
2020-12-30 18:46:42 +00:00
# include "xio-udp.h"
2008-01-27 12:00:08 +00:00
# include "xio-ipapp.h"
2020-12-31 11:06:32 +00:00
# include "xio-ip6.h"
2008-01-27 12:00:08 +00:00
# include "xio-openssl.h"
/* the openssl library requires a file descriptor for external communications.
2023-06-12 21:01:54 +00:00
so our best effort is to provide any possible kind of un * x file descriptor
2008-01-27 12:00:08 +00:00
( not only tcp , but also pipes , stdin , files . . . )
for tcp we want to provide support for socks and proxy .
read and write functions must use the openssl crypt versions .
but currently only plain tcp4 is implemented .
*/
/* Linux: "man 3 ssl" */
/* generate a simple openssl server for testing:
1 ) generate a private key
openssl genrsa - out server . key 1024
2 ) generate a self signed cert
openssl req - new - key server . key - x509 - days 3653 - out server . crt
enter fields . . .
3 ) generate the pem file
cat server . key server . crt > server . pem
openssl s_server ( listens on 4433 / tcp )
*/
/* static declaration of ssl's open function */
2023-07-13 07:06:35 +00:00
static int xioopen_openssl_connect ( int argc , const char * argv [ ] , struct opt * opts , int xioflags , xiofile_t * fd , const struct addrdesc * addrdesc ) ;
2008-01-27 12:00:08 +00:00
/* static declaration of ssl's open function */
2023-07-13 07:06:35 +00:00
static int xioopen_openssl_listen ( int argc , const char * argv [ ] , struct opt * opts , int xioflags , xiofile_t * fd , const struct addrdesc * addrdesc ) ;
2008-01-27 12:00:08 +00:00
static int openssl_SSL_ERROR_SSL ( int level , const char * funcname ) ;
2023-07-13 07:06:35 +00:00
static int openssl_handle_peer_certificate ( struct single * sfd ,
2015-01-12 22:34:47 +00:00
const char * peername ,
bool opt_ver ,
2008-01-27 12:00:08 +00:00
int level ) ;
2023-07-13 07:06:35 +00:00
static int xioSSL_set_fd ( struct single * sfd , int level ) ;
static int xioSSL_connect ( struct single * sfd , const char * opt_commonname , bool opt_ver , int level ) ;
2015-01-12 22:34:47 +00:00
static int openssl_delete_cert_info ( void ) ;
2008-01-27 12:00:08 +00:00
/* description record for ssl connect */
2020-12-30 18:46:42 +00:00
const struct addrdesc xioaddr_openssl = {
2023-10-26 12:56:50 +00:00
" OPENSSL " , /* keyword for selecting this address type in xioopen calls
2008-01-27 12:00:08 +00:00
( canonical or main name ) */
3 , /* data flow directions this address supports on API layer:
1. . read , 2. . write , 3. . both */
xioopen_openssl_connect , /* a function pointer used to "open" these addresses.*/
GROUP_FD | GROUP_SOCKET | GROUP_SOCK_IP4 | GROUP_SOCK_IP6 | GROUP_IP_TCP | GROUP_CHILD | GROUP_OPENSSL | GROUP_RETRY , /* bitwise OR of address groups this address belongs to.
You might have to specify a new group in xioopts . h */
0 , /* an integer passed to xioopen_openssl; makes it possible to
2020-12-30 18:46:42 +00:00
use the xioopen_openssl_connect function for slightly different
2008-01-27 12:00:08 +00:00
address types . */
0 , /* like previous argument */
0 /* like previous arguments, but pointer type.
No trailing comma or semicolon ! */
HELP ( " :<host>:<port> " ) /* a text displayed from xio help function.
No trailing comma or semicolon !
only generates this text if WITH_HELP is ! = 0 */
} ;
# if WITH_LISTEN
/* description record for ssl listen */
2020-12-30 18:46:42 +00:00
const struct addrdesc xioaddr_openssl_listen = {
2023-10-26 12:56:50 +00:00
" OPENSSL-LISTEN " , /* keyword for selecting this address type in xioopen calls
2008-01-27 12:00:08 +00:00
( canonical or main name ) */
3 , /* data flow directions this address supports on API layer:
1. . read , 2. . write , 3. . both */
xioopen_openssl_listen , /* a function pointer used to "open" these addresses.*/
GROUP_FD | GROUP_SOCKET | GROUP_SOCK_IP4 | GROUP_SOCK_IP6 | GROUP_IP_TCP | GROUP_LISTEN | GROUP_CHILD | GROUP_RANGE | GROUP_OPENSSL | GROUP_RETRY , /* bitwise OR of address groups this address belongs to.
You might have to specify a new group in xioopts . h */
0 , /* an integer passed to xioopen_openssl_listen; makes it possible to
2020-12-30 18:46:42 +00:00
use the xioopen_openssl_listen function for slightly different
2008-01-27 12:00:08 +00:00
address types . */
0 , /* like previous argument */
0 /* like previous arguments, but pointer type.
No trailing comma or semicolon ! */
HELP ( " :<port> " ) /* a text displayed from xio help function.
No trailing comma or semicolon !
only generates this text if WITH_HELP is ! = 0 */
} ;
# endif /* WITH_LISTEN */
2023-10-26 12:56:50 +00:00
const struct addrdesc xioaddr_openssl_dtls_client = { " OPENSSL-DTLS-CLIENT " , 3 , xioopen_openssl_connect , GROUP_FD | GROUP_SOCKET | GROUP_SOCK_IP4 | GROUP_SOCK_IP6 | GROUP_IP_UDP | GROUP_CHILD | GROUP_OPENSSL | GROUP_RETRY , 1 , 0 , 0 HELP ( " :<host>:<port> " ) } ;
2021-01-03 15:56:50 +00:00
# if WITH_LISTEN
2023-10-26 12:56:50 +00:00
const struct addrdesc xioaddr_openssl_dtls_server = { " OPENSSL-DTLS-SERVER " , 3 , xioopen_openssl_listen , GROUP_FD | GROUP_SOCKET | GROUP_SOCK_IP4 | GROUP_SOCK_IP6 | GROUP_IP_UDP | GROUP_LISTEN | GROUP_CHILD | GROUP_RANGE | GROUP_OPENSSL | GROUP_RETRY , 1 , 0 , 0 HELP ( " :<port> " ) } ;
2021-01-03 15:56:50 +00:00
# endif
2020-12-30 18:46:42 +00:00
2008-01-27 12:00:08 +00:00
/* both client and server */
const struct optdesc opt_openssl_cipherlist = { " openssl-cipherlist " , " ciphers " , OPT_OPENSSL_CIPHERLIST , GROUP_OPENSSL , PH_SPEC , TYPE_STRING , OFUNC_SPEC } ;
2019-02-10 12:16:42 +00:00
# if WITH_OPENSSL_METHOD
2008-01-27 12:00:08 +00:00
const struct optdesc opt_openssl_method = { " openssl-method " , " method " , OPT_OPENSSL_METHOD , GROUP_OPENSSL , PH_SPEC , TYPE_STRING , OFUNC_SPEC } ;
2019-02-10 12:16:42 +00:00
# endif
2020-12-27 19:25:10 +00:00
# if HAVE_SSL_CTX_set_min_proto_version || defined(SSL_CTX_set_min_proto_version)
2023-11-05 18:39:01 +00:00
const struct optdesc opt_openssl_min_proto_version = { " openssl-min-proto-version " , " min-version " , OPT_OPENSSL_MIN_PROTO_VERSION , GROUP_OPENSSL , PH_OFFSET , TYPE_STRING , OFUNC_OFFSET , XIO_OFFSETOF ( para . openssl . min_proto_version ) } ;
2020-12-27 19:25:10 +00:00
# endif
# if HAVE_SSL_CTX_set_max_proto_version || defined(SSL_CTX_set_max_proto_version)
2023-11-05 18:39:01 +00:00
const struct optdesc opt_openssl_max_proto_version = { " openssl-max-proto-version " , " max-version " , OPT_OPENSSL_MAX_PROTO_VERSION , GROUP_OPENSSL , PH_OFFSET , TYPE_STRING , OFUNC_OFFSET , XIO_OFFSETOF ( para . openssl . max_proto_version ) } ;
2020-12-27 19:25:10 +00:00
# endif
2008-01-27 12:00:08 +00:00
const struct optdesc opt_openssl_verify = { " openssl-verify " , " verify " , OPT_OPENSSL_VERIFY , GROUP_OPENSSL , PH_SPEC , TYPE_BOOL , OFUNC_SPEC } ;
const struct optdesc opt_openssl_certificate = { " openssl-certificate " , " cert " , OPT_OPENSSL_CERTIFICATE , GROUP_OPENSSL , PH_SPEC , TYPE_FILENAME , OFUNC_SPEC } ;
const struct optdesc opt_openssl_key = { " openssl-key " , " key " , OPT_OPENSSL_KEY , GROUP_OPENSSL , PH_SPEC , TYPE_FILENAME , OFUNC_SPEC } ;
const struct optdesc opt_openssl_dhparam = { " openssl-dhparam " , " dh " , OPT_OPENSSL_DHPARAM , GROUP_OPENSSL , PH_SPEC , TYPE_FILENAME , OFUNC_SPEC } ;
const struct optdesc opt_openssl_cafile = { " openssl-cafile " , " cafile " , OPT_OPENSSL_CAFILE , GROUP_OPENSSL , PH_SPEC , TYPE_FILENAME , OFUNC_SPEC } ;
const struct optdesc opt_openssl_capath = { " openssl-capath " , " capath " , OPT_OPENSSL_CAPATH , GROUP_OPENSSL , PH_SPEC , TYPE_FILENAME , OFUNC_SPEC } ;
const struct optdesc opt_openssl_egd = { " openssl-egd " , " egd " , OPT_OPENSSL_EGD , GROUP_OPENSSL , PH_SPEC , TYPE_FILENAME , OFUNC_SPEC } ;
2023-10-26 14:43:20 +00:00
# if HAVE_SSL_CTX_set_tlsext_max_fragment_length || defined(SSL_CTX_set_tlsext_max_fragment_length)
const struct optdesc opt_openssl_maxfraglen = { " openssl-maxfraglen " , " maxfraglen " , OPT_OPENSSL_MAXFRAGLEN , GROUP_OPENSSL , PH_SPEC , TYPE_INT , OFUNC_SPEC } ;
# endif
# if HAVE_SSL_CTX_set_max_send_fragment || defined(SSL_CTX_set_max_send_fragment)
const struct optdesc opt_openssl_maxsendfrag = { " openssl-maxsendfrag " , " maxsendfrag " , OPT_OPENSSL_MAXSENDFRAG , GROUP_OPENSSL , PH_SPEC , TYPE_INT , OFUNC_SPEC } ;
# endif
2008-01-27 12:00:08 +00:00
const struct optdesc opt_openssl_pseudo = { " openssl-pseudo " , " pseudo " , OPT_OPENSSL_PSEUDO , GROUP_OPENSSL , PH_SPEC , TYPE_BOOL , OFUNC_SPEC } ;
2015-07-20 10:57:30 +00:00
# if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_COMP)
2011-11-26 13:27:02 +00:00
const struct optdesc opt_openssl_compress = { " openssl-compress " , " compress " , OPT_OPENSSL_COMPRESS , GROUP_OPENSSL , PH_SPEC , TYPE_STRING , OFUNC_SPEC } ;
# endif
2008-01-27 12:00:08 +00:00
# if WITH_FIPS
const struct optdesc opt_openssl_fips = { " openssl-fips " , " fips " , OPT_OPENSSL_FIPS , GROUP_OPENSSL , PH_SPEC , TYPE_BOOL , OFUNC_SPEC } ;
# endif
2015-01-12 22:34:47 +00:00
const struct optdesc opt_openssl_commonname = { " openssl-commonname " , " cn " , OPT_OPENSSL_COMMONNAME , GROUP_OPENSSL , PH_SPEC , TYPE_STRING , OFUNC_SPEC } ;
2020-12-31 13:30:04 +00:00
# if defined(HAVE_SSL_set_tlsext_host_name) || defined(SSL_set_tlsext_host_name)
const struct optdesc opt_openssl_no_sni = { " openssl-no-sni " , " nosni " , OPT_OPENSSL_NO_SNI , GROUP_OPENSSL , PH_SPEC , TYPE_BOOL , OFUNC_SPEC } ;
const struct optdesc opt_openssl_snihost = { " openssl-snihost " , " snihost " , OPT_OPENSSL_SNIHOST , GROUP_OPENSSL , PH_SPEC , TYPE_STRING , OFUNC_SPEC } ;
# endif
2008-01-27 12:00:08 +00:00
/* If FIPS is compiled in, we need to track if the user asked for FIPS mode.
* On forks , the FIPS mode must be reset by a disable , then enable since
* FIPS tracks the process ID that initializes things .
* If FIPS is not compiled in , no tracking variable is needed
* and we make the reset code compile out . This keeps the
* rest of the code below free of FIPS related # ifs
*/
# if WITH_FIPS
static bool xio_openssl_fips = false ;
int xio_reset_fips_mode ( void ) {
if ( xio_openssl_fips ) {
if ( ! sycFIPS_mode_set ( 0 ) | | ! sycFIPS_mode_set ( 1 ) ) {
ERR_load_crypto_strings ( ) ;
ERR_print_errors ( BIO_new_fp ( stderr , BIO_NOCLOSE ) ) ;
Error ( " Failed to reset OpenSSL FIPS mode " ) ;
xio_openssl_fips = false ;
return - 1 ;
}
}
return 0 ;
}
# else
# define xio_reset_fips_mode() 0
# endif
2011-11-26 13:27:02 +00:00
static void openssl_conn_loginfo ( SSL * ssl ) {
2020-12-27 19:25:10 +00:00
const char * string ;
2023-10-26 14:43:20 +00:00
SSL_SESSION * session ;
2020-12-27 19:25:10 +00:00
string = SSL_get_cipher_version ( ssl ) ;
Notice1 ( " SSL proto version used: %s " , string ) ;
xiosetenv ( " OPENSSL_PROTO_VERSION " , string , 1 , NULL ) ;
string = SSL_get_cipher ( ssl ) ;
Notice1 ( " SSL connection using %s " , string ) ;
xiosetenv ( " OPENSSL_CIPHER " , string , 1 , NULL ) ;
2011-11-26 13:27:02 +00:00
2015-07-20 10:57:30 +00:00
# if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_COMP)
2011-11-26 13:27:02 +00:00
{
const COMP_METHOD * comp , * expansion ;
comp = sycSSL_get_current_compression ( ssl ) ;
expansion = sycSSL_get_current_expansion ( ssl ) ;
Notice1 ( " SSL connection compression \" %s \" " ,
comp ? sycSSL_COMP_get_name ( comp ) : " none " ) ;
Notice1 ( " SSL connection expansion \" %s \" " ,
expansion ? sycSSL_COMP_get_name ( expansion ) : " none " ) ;
}
2023-10-26 14:43:20 +00:00
# endif
session = SSL_get_session ( ssl ) ;
if ( session = = NULL ) {
Warn1 ( " SSL_get_session(%p) failed " , ssl ) ;
return ;
}
# if HAVE_SSL_CTX_set_tlsext_max_fragment_length || defined(SSL_CTX_set_tlsext_max_fragment_length)
{
uint8_t fragcod ;
int fraglen = - 1 ;
fragcod = SSL_SESSION_get_max_fragment_length ( session ) ;
switch ( fragcod ) {
case TLSEXT_max_fragment_length_DISABLED : fraglen = 0 ; break ;
case TLSEXT_max_fragment_length_512 : fraglen = 512 ; break ;
case TLSEXT_max_fragment_length_1024 : fraglen = 1024 ; break ;
case TLSEXT_max_fragment_length_2048 : fraglen = 2048 ; break ;
case TLSEXT_max_fragment_length_4096 : fraglen = 4096 ; break ;
default : Warn1 ( " SSL_SESSION_get_max_fragment_length(): unknown code %u " ,
fragcod ) ;
break ;
}
if ( fraglen > 0 ) {
Info1 ( " OpenSSL: max fragment length is %d " , fraglen ) ;
}
}
2011-11-26 13:27:02 +00:00
# endif
}
2008-01-27 12:00:08 +00:00
/* the open function for OpenSSL client */
2023-07-13 07:06:35 +00:00
static int xioopen_openssl_connect (
int argc ,
const char * argv [ ] , /* the arguments in the address string */
struct opt * opts ,
int xioflags , /* is the open meant for reading (0),
2008-01-27 12:00:08 +00:00
writing ( 1 ) , or both ( 2 ) ? */
2023-07-13 07:06:35 +00:00
xiofile_t * xxfd , /* a xio file descriptor structure,
2008-01-27 12:00:08 +00:00
already allocated */
2023-07-13 07:06:35 +00:00
const struct addrdesc * addrdesc ) /* the above descriptor */
2008-01-27 12:00:08 +00:00
{
2023-07-13 07:06:35 +00:00
struct single * sfd = & xxfd - > stream ;
2008-01-27 12:00:08 +00:00
struct opt * opts0 = NULL ;
const char * hostname , * portname ;
2023-07-13 07:06:35 +00:00
int protogrp = addrdesc - > arg1 ;
2008-01-27 12:00:08 +00:00
int pf = PF_UNSPEC ;
2020-12-30 18:46:42 +00:00
bool use_dtls = ( protogrp ! = 0 ) ;
2008-01-27 12:00:08 +00:00
int socktype = SOCK_STREAM ;
2020-12-30 18:46:42 +00:00
int ipproto = IPPROTO_TCP ;
2008-01-27 12:00:08 +00:00
bool dofork = false ;
union sockaddr_union us_sa , * us = & us_sa ;
socklen_t uslen = sizeof ( us_sa ) ;
2024-08-21 18:53:15 +00:00
struct addrinfo * * themarr , * themp ;
2008-01-27 12:00:08 +00:00
bool needbind = false ;
bool lowport = false ;
2023-11-05 12:59:14 +00:00
int level = E_ERROR ;
int i ;
2008-01-27 12:00:08 +00:00
SSL_CTX * ctx ;
bool opt_ver = true ; /* verify peer certificate */
char * opt_cert = NULL ; /* file name of client certificate */
2015-01-12 22:34:47 +00:00
const char * opt_commonname = NULL ; /* for checking peer certificate */
2021-11-15 07:45:59 +00:00
bool opt_no_sni = false ;
2020-12-31 13:30:04 +00:00
const char * opt_snihost = NULL ; /* for SNI host */
2008-01-27 12:00:08 +00:00
int result ;
if ( ! ( xioflags & XIO_MAYCONVERT ) ) {
Error ( " address with data processing not allowed here " ) ;
return STAT_NORETRY ;
}
2023-07-13 07:06:35 +00:00
sfd - > flags | = XIO_DOESCONVERT ;
2008-01-27 12:00:08 +00:00
if ( argc ! = 3 ) {
2023-07-13 07:06:35 +00:00
xio_syntax ( argv [ 0 ] , 2 , argc - 1 , addrdesc - > syntax ) ;
2008-01-27 12:00:08 +00:00
return STAT_NORETRY ;
}
hostname = argv [ 1 ] ;
portname = argv [ 2 ] ;
2015-01-12 22:34:47 +00:00
if ( hostname [ 0 ] = = ' \0 ' ) {
/* we catch this explicitely because empty commonname (peername) disables
commonName check of peer certificate */
Error1 ( " %s: empty host name " , argv [ 0 ] ) ;
return STAT_NORETRY ;
}
2008-01-27 12:00:08 +00:00
2023-11-06 20:23:27 +00:00
if ( sfd - > howtoend = = END_UNSPEC )
sfd - > howtoend = END_SHUTDOWN ;
2023-07-13 07:06:35 +00:00
if ( applyopts_single ( sfd , opts , PH_INIT ) < 0 )
return - 1 ;
2023-07-13 07:06:08 +00:00
applyopts ( sfd , - 1 , opts , PH_INIT ) ;
2008-01-27 12:00:08 +00:00
retropt_bool ( opts , OPT_FORK , & dofork ) ;
retropt_string ( opts , OPT_OPENSSL_CERTIFICATE , & opt_cert ) ;
2015-01-12 22:34:47 +00:00
retropt_string ( opts , OPT_OPENSSL_COMMONNAME , ( char * * ) & opt_commonname ) ;
2020-12-31 13:30:04 +00:00
# if defined(HAVE_SSL_set_tlsext_host_name) || defined(SSL_set_tlsext_host_name)
retropt_bool ( opts , OPT_OPENSSL_NO_SNI , & opt_no_sni ) ;
retropt_string ( opts , OPT_OPENSSL_SNIHOST , ( char * * ) & opt_snihost ) ;
# endif
2023-06-12 21:01:54 +00:00
2015-01-12 22:34:47 +00:00
if ( opt_commonname = = NULL ) {
2020-12-31 13:30:04 +00:00
opt_commonname = strdup ( hostname ) ;
if ( opt_commonname = = NULL ) {
Error1 ( " strdup( " F_Zu " ): out of memory " , strlen ( hostname ) + 1 ) ;
}
}
# if defined(HAVE_SSL_set_tlsext_host_name) || defined(SSL_set_tlsext_host_name)
2023-06-12 17:23:09 +00:00
if ( opt_snihost ! = NULL ) {
if ( check_ipaddr ( opt_snihost ) = = 0 ) {
Warn1 ( " specified SNI host \" %s \" is an IP address " , opt_snihost ) ;
}
} else if ( check_ipaddr ( opt_commonname ) ! = 0 ) {
2020-12-31 13:30:04 +00:00
opt_snihost = strdup ( opt_commonname ) ;
if ( opt_snihost = = NULL ) {
Error1 ( " strdup( " F_Zu " ): out of memory " , strlen ( opt_commonname ) + 1 ) ;
}
2015-01-12 22:34:47 +00:00
}
2020-12-31 13:30:04 +00:00
# endif
2008-01-27 12:00:08 +00:00
result =
2023-07-13 07:06:35 +00:00
_xioopen_openssl_prepare ( opts , sfd , false , & opt_ver , opt_cert , & ctx , ( bool * ) & use_dtls ) ;
2008-01-27 12:00:08 +00:00
if ( result ! = STAT_OK ) return STAT_NORETRY ;
2020-12-30 18:46:42 +00:00
if ( use_dtls ) {
socktype = SOCK_DGRAM ;
ipproto = IPPROTO_UDP ;
}
retropt_int ( opts , OPT_SO_TYPE , & socktype ) ;
retropt_int ( opts , OPT_SO_PROTOTYPE , & ipproto ) ;
2008-01-27 12:00:08 +00:00
result =
_xioopen_ipapp_prepare ( opts , & opts0 , hostname , portname , & pf , ipproto ,
2023-07-13 07:06:35 +00:00
sfd - > para . socket . ip . ai_flags ,
2024-08-21 18:53:15 +00:00
& themarr , us , & uslen ,
2008-09-20 21:47:06 +00:00
& needbind , & lowport , socktype ) ;
2008-01-27 12:00:08 +00:00
if ( result ! = STAT_OK ) return STAT_NORETRY ;
2023-06-23 14:21:05 +00:00
if ( xioparms . logopt = = ' m ' ) {
2008-01-27 12:00:08 +00:00
Info ( " starting connect loop, switching to syslog " ) ;
2023-06-23 14:21:05 +00:00
diag_set ( ' y ' , xioparms . syslogfac ) ; xioparms . logopt = ' y ' ;
2008-01-27 12:00:08 +00:00
} else {
Info ( " starting connect loop " ) ;
}
do { /* loop over failed connect and SSL handshake attempts */
2024-08-21 18:53:15 +00:00
/* Loop over themarr (which had been "ai_sorted") */
2023-11-05 12:59:14 +00:00
i = 0 ;
2024-08-21 18:53:15 +00:00
themp = themarr [ i + + ] ;
2023-11-05 12:59:14 +00:00
while ( themp ! = NULL ) {
2008-01-27 12:00:08 +00:00
# if WITH_RETRY
2024-08-21 18:53:15 +00:00
if ( sfd - > forever | | sfd - > retry | | themarr [ i ] ! = NULL ) {
2023-11-05 12:59:14 +00:00
level = E_INFO ;
} else
2008-01-27 12:00:08 +00:00
# endif /* WITH_RETRY */
2023-11-05 12:59:14 +00:00
level = E_ERROR ;
2008-01-27 12:00:08 +00:00
2023-11-05 12:59:14 +00:00
/* This cannot fork because we retrieved fork option above */
2023-10-22 21:15:49 +00:00
result =
2023-07-13 07:06:35 +00:00
_xioopen_connect ( sfd ,
2020-12-27 11:39:48 +00:00
needbind ? us : NULL , uslen ,
2023-10-22 21:15:49 +00:00
themp - > ai_addr , themp - > ai_addrlen ,
opts , pf ? pf : themp - > ai_addr - > sa_family , socktype , ipproto , lowport , level ) ;
if ( result = = STAT_OK )
break ;
2024-08-21 18:53:15 +00:00
themp = themarr [ i + + ] ;
2023-10-22 21:15:49 +00:00
if ( themp = = NULL ) {
result = STAT_RETRYLATER ;
}
}
2008-01-27 12:00:08 +00:00
switch ( result ) {
case STAT_OK : break ;
# if WITH_RETRY
case STAT_RETRYLATER :
case STAT_RETRYNOW :
2023-07-13 07:06:35 +00:00
if ( sfd - > forever | | sfd - > retry ) {
2008-01-27 12:00:08 +00:00
dropopts ( opts , PH_ALL ) ; opts = copyopts ( opts0 , GROUP_ALL ) ;
if ( result = = STAT_RETRYLATER ) {
2023-07-13 07:06:35 +00:00
Nanosleep ( & sfd - > intervall , NULL ) ;
2008-01-27 12:00:08 +00:00
}
2023-07-13 07:06:35 +00:00
- - sfd - > retry ;
2008-01-27 12:00:08 +00:00
continue ;
}
2024-08-21 18:53:15 +00:00
xiofreeaddrinfo ( themarr ) ;
2008-01-27 12:00:08 +00:00
return STAT_NORETRY ;
# endif /* WITH_RETRY */
default :
2024-08-21 18:53:15 +00:00
xiofreeaddrinfo ( themarr ) ;
2008-01-27 12:00:08 +00:00
return result ;
}
/*! isn't this too early? */
2023-07-13 07:06:35 +00:00
if ( ( result = _xio_openlate ( sfd , opts ) ) < 0 ) {
2024-08-21 18:53:15 +00:00
xiofreeaddrinfo ( themarr ) ;
2008-01-27 12:00:08 +00:00
return result ;
}
2023-07-13 07:06:35 +00:00
result = _xioopen_openssl_connect ( sfd , opt_ver , opt_commonname ,
2020-12-31 13:30:04 +00:00
opt_no_sni , opt_snihost , ctx , level ) ;
2008-01-27 12:00:08 +00:00
switch ( result ) {
case STAT_OK : break ;
# if WITH_RETRY
case STAT_RETRYLATER :
case STAT_RETRYNOW :
2023-07-13 07:06:35 +00:00
if ( sfd - > forever | | sfd - > retry ) {
Close ( sfd - > fd ) ;
2008-01-27 12:00:08 +00:00
dropopts ( opts , PH_ALL ) ; opts = copyopts ( opts0 , GROUP_ALL ) ;
if ( result = = STAT_RETRYLATER ) {
2023-07-13 07:06:35 +00:00
Nanosleep ( & sfd - > intervall , NULL ) ;
2008-01-27 12:00:08 +00:00
}
2023-07-13 07:06:35 +00:00
- - sfd - > retry ;
2008-01-27 12:00:08 +00:00
continue ;
}
# endif /* WITH_RETRY */
2023-10-22 21:15:49 +00:00
default :
2024-08-21 18:53:15 +00:00
xiofreeaddrinfo ( themarr ) ;
2023-10-22 21:15:49 +00:00
return STAT_NORETRY ;
2008-01-27 12:00:08 +00:00
}
2008-02-01 22:15:14 +00:00
if ( dofork ) {
xiosetchilddied ( ) ; /* set SIGCHLD handler */
}
2008-01-27 12:00:08 +00:00
# if WITH_RETRY
if ( dofork ) {
pid_t pid ;
2008-09-22 20:17:55 +00:00
int level = E_ERROR ;
2023-07-13 07:06:35 +00:00
if ( sfd - > forever | | sfd - > retry ) {
2008-09-22 20:17:55 +00:00
level = E_WARN ;
}
2023-07-13 07:06:35 +00:00
while ( ( pid = xio_fork ( false , level , sfd - > shutup ) ) < 0 ) {
if ( sfd - > forever | | - - sfd - > retry ) {
Nanosleep ( & sfd - > intervall , NULL ) ; continue ;
2008-01-27 12:00:08 +00:00
}
2024-08-21 18:53:15 +00:00
xiofreeaddrinfo ( themarr ) ;
2008-01-27 12:00:08 +00:00
return STAT_RETRYLATER ;
}
2008-09-22 20:17:55 +00:00
if ( pid = = 0 ) { /* child process */
2023-07-13 07:06:35 +00:00
sfd - > forever = false ; sfd - > retry = 0 ;
2008-01-27 12:00:08 +00:00
break ;
}
2008-09-22 20:17:55 +00:00
2008-01-27 12:00:08 +00:00
/* parent process */
2023-07-13 07:06:35 +00:00
Close ( sfd - > fd ) ;
sycSSL_free ( sfd - > para . openssl . ssl ) ;
sfd - > para . openssl . ssl = NULL ;
2008-01-27 12:00:08 +00:00
/* with and without retry */
2023-07-13 07:06:35 +00:00
Nanosleep ( & sfd - > intervall , NULL ) ;
2008-01-27 12:00:08 +00:00
dropopts ( opts , PH_ALL ) ; opts = copyopts ( opts0 , GROUP_ALL ) ;
continue ; /* with next socket() bind() connect() */
}
# endif /* WITH_RETRY */
break ;
} while ( true ) ; /* drop out on success */
2024-08-21 18:53:15 +00:00
xiofreeaddrinfo ( themarr ) ;
2008-01-27 12:00:08 +00:00
2023-07-13 07:06:35 +00:00
openssl_conn_loginfo ( sfd - > para . openssl . ssl ) ;
2008-01-27 12:00:08 +00:00
2020-12-31 13:30:04 +00:00
free ( ( void * ) opt_commonname ) ;
free ( ( void * ) opt_snihost ) ;
2008-01-27 12:00:08 +00:00
/* fill in the fd structure */
return STAT_OK ;
}
/* this function is typically called within the OpenSSL client fork/retry loop.
2023-07-13 07:06:35 +00:00
sfd must be of type DATA_OPENSSL , and its fd must be set with a valid file
2008-01-27 12:00:08 +00:00
descriptor . this function then performs all SSL related step to make a valid
SSL connection from an FD and a CTX . */
2023-07-13 07:06:35 +00:00
int _xioopen_openssl_connect ( struct single * sfd ,
2008-01-27 12:00:08 +00:00
bool opt_ver ,
2015-01-12 22:34:47 +00:00
const char * opt_commonname ,
2020-12-31 13:30:04 +00:00
bool no_sni ,
const char * snihost ,
2008-01-27 12:00:08 +00:00
SSL_CTX * ctx ,
int level ) {
SSL * ssl ;
unsigned long err ;
int result ;
/* create a SSL object */
if ( ( ssl = sycSSL_new ( ctx ) ) = = NULL ) {
if ( ERR_peek_error ( ) = = 0 ) Msg ( level , " SSL_new() failed " ) ;
while ( err = ERR_get_error ( ) ) {
Msg1 ( level , " SSL_new(): %s " , ERR_error_string ( err , NULL ) ) ;
}
/*Error("SSL_new()");*/
return STAT_RETRYLATER ;
}
2023-07-13 07:06:35 +00:00
sfd - > para . openssl . ssl = ssl ;
2008-01-27 12:00:08 +00:00
2023-07-13 07:06:35 +00:00
result = xioSSL_set_fd ( sfd , level ) ;
2008-01-27 12:00:08 +00:00
if ( result ! = STAT_OK ) {
2023-07-13 07:06:35 +00:00
sycSSL_free ( sfd - > para . openssl . ssl ) ;
sfd - > para . openssl . ssl = NULL ;
2008-01-27 12:00:08 +00:00
return result ;
}
2020-12-31 13:30:04 +00:00
# if defined(HAVE_SSL_set_tlsext_host_name) || defined(SSL_set_tlsext_host_name)
if ( ! no_sni ) {
2023-10-26 12:52:53 +00:00
if ( snihost = = NULL | | strlen ( snihost ) = = 0 ) {
Warn ( " refusing to set empty SNI host name " ) ;
} else if ( ! SSL_set_tlsext_host_name ( ssl , snihost ) ) {
2020-12-31 13:30:04 +00:00
Error1 ( " Failed to set SNI host \" %s \" " , snihost ) ;
2023-07-13 07:06:35 +00:00
sycSSL_free ( sfd - > para . openssl . ssl ) ;
sfd - > para . openssl . ssl = NULL ;
2020-12-31 13:30:04 +00:00
return STAT_NORETRY ;
}
}
# endif
2023-07-13 07:06:35 +00:00
result = xioSSL_connect ( sfd , opt_commonname , opt_ver , level ) ;
2008-01-27 12:00:08 +00:00
if ( result ! = STAT_OK ) {
2023-07-13 07:06:35 +00:00
sycSSL_free ( sfd - > para . openssl . ssl ) ;
sfd - > para . openssl . ssl = NULL ;
2008-01-27 12:00:08 +00:00
return result ;
}
2023-07-13 07:06:35 +00:00
result = openssl_handle_peer_certificate ( sfd , opt_commonname ,
2015-01-12 22:34:47 +00:00
opt_ver , level ) ;
2008-01-27 12:00:08 +00:00
if ( result ! = STAT_OK ) {
2023-07-13 07:06:35 +00:00
sycSSL_free ( sfd - > para . openssl . ssl ) ;
sfd - > para . openssl . ssl = NULL ;
2008-01-27 12:00:08 +00:00
return result ;
}
return STAT_OK ;
}
# if WITH_LISTEN
2023-07-13 07:06:35 +00:00
static int xioopen_openssl_listen (
int argc ,
const char * argv [ ] , /* the arguments in the address string */
struct opt * opts ,
int xioflags , /* is the open meant for reading (0),
2008-01-27 12:00:08 +00:00
writing ( 1 ) , or both ( 2 ) ? */
2023-07-13 07:06:35 +00:00
xiofile_t * xxfd , /* a xio file descriptor structure,
2008-01-27 12:00:08 +00:00
already allocated */
2023-07-13 07:06:35 +00:00
const struct addrdesc * addrdesc ) /* the above descriptor */
2008-01-27 12:00:08 +00:00
{
2023-07-13 07:06:35 +00:00
struct single * sfd = & xxfd - > stream ;
2008-01-27 12:00:08 +00:00
const char * portname ;
2023-07-13 07:06:35 +00:00
int protogrp = addrdesc - > arg1 ;
2008-01-27 12:00:08 +00:00
struct opt * opts0 = NULL ;
union sockaddr_union us_sa , * us = & us_sa ;
socklen_t uslen = sizeof ( us_sa ) ;
2023-10-26 20:16:21 +00:00
int pf = PF_UNSPEC ;
2020-12-30 18:46:42 +00:00
bool use_dtls = ( protogrp ! = 0 ) ;
2008-01-27 12:00:08 +00:00
int socktype = SOCK_STREAM ;
int ipproto = IPPROTO_TCP ;
/*! lowport? */
int level ;
SSL_CTX * ctx ;
bool opt_ver = true ; /* verify peer certificate - changed with 1.6.0 */
char * opt_cert = NULL ; /* file name of server certificate */
2015-01-12 22:34:47 +00:00
const char * opt_commonname = NULL ; /* for checking peer certificate */
2008-01-27 12:00:08 +00:00
int result ;
if ( ! ( xioflags & XIO_MAYCONVERT ) ) {
Error ( " address with data processing not allowed here " ) ;
return STAT_NORETRY ;
}
2023-07-13 07:06:35 +00:00
sfd - > flags | = XIO_DOESCONVERT ;
2008-01-27 12:00:08 +00:00
if ( argc ! = 2 ) {
2023-07-13 07:06:35 +00:00
xio_syntax ( argv [ 0 ] , 1 , argc - 1 , addrdesc - > syntax ) ;
2008-01-27 12:00:08 +00:00
return STAT_NORETRY ;
}
2023-07-13 07:06:35 +00:00
xioinit_ip ( & pf , xioparms . default_ip ) ;
2008-01-27 12:00:08 +00:00
# if WITH_IP4 && WITH_IP6
2023-10-26 20:16:21 +00:00
switch ( xioparms . default_ip ) {
case ' 4 ' : pf = PF_INET ; break ;
case ' 6 ' : pf = PF_INET6 ; break ;
default : break ; /* includes \0 */
}
2008-01-27 12:00:08 +00:00
# elif WITH_IP6
pf = PF_INET6 ;
# else
pf = PF_INET ;
# endif
2023-06-12 21:01:54 +00:00
2008-01-27 12:00:08 +00:00
portname = argv [ 1 ] ;
2023-11-06 20:23:27 +00:00
if ( sfd - > howtoend = = END_UNSPEC )
sfd - > howtoend = END_SHUTDOWN ;
2023-07-13 07:06:35 +00:00
if ( applyopts_single ( sfd , opts , PH_INIT ) < 0 ) return - 1 ;
2023-07-13 07:06:08 +00:00
applyopts ( sfd , - 1 , opts , PH_INIT ) ;
2008-01-27 12:00:08 +00:00
retropt_string ( opts , OPT_OPENSSL_CERTIFICATE , & opt_cert ) ;
if ( opt_cert = = NULL ) {
Warn ( " no certificate given; consider option \" cert \" " ) ;
}
2015-01-12 22:34:47 +00:00
retropt_string ( opts , OPT_OPENSSL_COMMONNAME , ( char * * ) & opt_commonname ) ;
2023-07-13 07:06:08 +00:00
applyopts ( sfd , - 1 , opts , PH_EARLY ) ;
2008-01-27 12:00:08 +00:00
result =
2023-07-13 07:06:35 +00:00
_xioopen_openssl_prepare ( opts , sfd , true , & opt_ver , opt_cert , & ctx , & use_dtls ) ;
2008-01-27 12:00:08 +00:00
if ( result ! = STAT_OK ) return STAT_NORETRY ;
2020-12-30 18:46:42 +00:00
if ( use_dtls ) {
socktype = SOCK_DGRAM ;
ipproto = IPPROTO_UDP ;
}
retropt_int ( opts , OPT_SO_TYPE , & socktype ) ;
retropt_int ( opts , OPT_SO_PROTOTYPE , & ipproto ) ;
2008-01-27 12:00:08 +00:00
if ( _xioopen_ipapp_listen_prepare ( opts , & opts0 , portname , & pf , ipproto ,
2023-07-13 07:06:35 +00:00
sfd - > para . socket . ip . ai_flags ,
2008-09-20 21:47:06 +00:00
us , & uslen , socktype )
2008-01-27 12:00:08 +00:00
! = STAT_OK ) {
return STAT_NORETRY ;
}
2023-10-26 20:16:21 +00:00
if ( pf = = 0 )
pf = us - > soa . sa_family ;
2008-01-27 12:00:08 +00:00
2023-07-13 07:06:35 +00:00
sfd - > dtype = XIODATA_OPENSSL ;
2008-01-27 12:00:08 +00:00
while ( true ) { /* loop over failed attempts */
# if WITH_RETRY
2023-07-13 07:06:35 +00:00
if ( sfd - > forever | | sfd - > retry ) {
2008-01-27 12:00:08 +00:00
level = E_INFO ;
} else
# endif /* WITH_RETRY */
level = E_ERROR ;
2020-12-30 18:46:42 +00:00
/* this can fork() for us; it only returns on error or on
successful establishment of connection */
2023-11-13 19:08:23 +00:00
if ( ipproto = = IPPROTO_TCP
# ifdef IPPROTO_DCCP
| | ipproto = = IPPROTO_DCCP
# endif
) {
2023-07-13 07:06:35 +00:00
result = _xioopen_listen ( sfd , xioflags ,
2008-01-27 12:00:08 +00:00
( struct sockaddr * ) us , uslen ,
2020-12-30 18:46:42 +00:00
opts , pf , socktype , ipproto ,
2008-01-27 12:00:08 +00:00
# if WITH_RETRY
2023-07-13 07:06:35 +00:00
( sfd - > retry | | sfd - > forever ) ? E_INFO : E_ERROR
2008-01-27 12:00:08 +00:00
# else
E_ERROR
# endif /* WITH_RETRY */
) ;
2021-01-03 15:56:50 +00:00
# if WITH_UDP
2020-12-30 18:46:42 +00:00
} else {
2023-07-13 07:06:35 +00:00
result = _xioopen_ipdgram_listen ( sfd , xioflags ,
2020-12-30 18:46:42 +00:00
us , uslen , opts , pf , socktype , ipproto ) ;
2021-01-03 15:56:50 +00:00
# endif /* WITH_UDP */
2020-12-30 18:46:42 +00:00
}
2008-01-27 12:00:08 +00:00
/*! not sure if we should try again on retry/forever */
switch ( result ) {
case STAT_OK : break ;
# if WITH_RETRY
case STAT_RETRYLATER :
case STAT_RETRYNOW :
2023-07-13 07:06:35 +00:00
if ( sfd - > forever | | sfd - > retry ) {
2008-01-27 12:00:08 +00:00
dropopts ( opts , PH_ALL ) ; opts = copyopts ( opts0 , GROUP_ALL ) ;
if ( result = = STAT_RETRYLATER ) {
2023-07-13 07:06:35 +00:00
Nanosleep ( & sfd - > intervall , NULL ) ;
2008-01-27 12:00:08 +00:00
}
dropopts ( opts , PH_ALL ) ; opts = copyopts ( opts0 , GROUP_ALL ) ;
2023-07-13 07:06:35 +00:00
- - sfd - > retry ;
2008-01-27 12:00:08 +00:00
continue ;
}
return STAT_NORETRY ;
# endif /* WITH_RETRY */
default :
return result ;
}
2023-07-13 07:06:35 +00:00
result = _xioopen_openssl_listen ( sfd , opt_ver , opt_commonname , ctx , level ) ;
2008-01-27 12:00:08 +00:00
switch ( result ) {
case STAT_OK : break ;
# if WITH_RETRY
case STAT_RETRYLATER :
case STAT_RETRYNOW :
2023-07-13 07:06:35 +00:00
if ( sfd - > forever | | sfd - > retry ) {
2008-01-27 12:00:08 +00:00
dropopts ( opts , PH_ALL ) ; opts = copyopts ( opts0 , GROUP_ALL ) ;
if ( result = = STAT_RETRYLATER ) {
2023-07-13 07:06:35 +00:00
Nanosleep ( & sfd - > intervall , NULL ) ;
2008-01-27 12:00:08 +00:00
}
dropopts ( opts , PH_ALL ) ; opts = copyopts ( opts0 , GROUP_ALL ) ;
2023-07-13 07:06:35 +00:00
- - sfd - > retry ;
2008-01-27 12:00:08 +00:00
continue ;
}
return STAT_NORETRY ;
# endif /* WITH_RETRY */
default :
return result ;
}
2023-07-13 07:06:35 +00:00
openssl_conn_loginfo ( sfd - > para . openssl . ssl ) ;
2008-01-27 12:00:08 +00:00
break ;
} /* drop out on success */
/* fill in the fd structure */
return STAT_OK ;
}
2023-07-13 07:06:35 +00:00
int _xioopen_openssl_listen ( struct single * sfd ,
2008-01-27 12:00:08 +00:00
bool opt_ver ,
2015-01-12 22:34:47 +00:00
const char * opt_commonname ,
2008-01-27 12:00:08 +00:00
SSL_CTX * ctx ,
int level ) {
char error_string [ 120 ] ;
unsigned long err ;
int errint , ret ;
/* create an SSL object */
2023-07-13 07:06:35 +00:00
if ( ( sfd - > para . openssl . ssl = sycSSL_new ( ctx ) ) = = NULL ) {
2008-01-27 12:00:08 +00:00
if ( ERR_peek_error ( ) = = 0 ) Msg ( level , " SSL_new() failed " ) ;
while ( err = ERR_get_error ( ) ) {
Msg1 ( level , " SSL_new(): %s " , ERR_error_string ( err , NULL ) ) ;
}
/*Error("SSL_new()");*/
return STAT_NORETRY ;
}
/* assign the network connection to the SSL object */
2023-07-13 07:06:35 +00:00
if ( sycSSL_set_fd ( sfd - > para . openssl . ssl , sfd - > fd ) < = 0 ) {
2008-01-27 12:00:08 +00:00
if ( ERR_peek_error ( ) = = 0 ) Msg ( level , " SSL_set_fd() failed " ) ;
while ( err = ERR_get_error ( ) ) {
Msg2 ( level , " SSL_set_fd(, %d): %s " ,
2023-07-13 07:06:35 +00:00
sfd - > fd , ERR_error_string ( err , NULL ) ) ;
2008-01-27 12:00:08 +00:00
}
}
# if WITH_DEBUG
{
int i = 0 ;
const char * ciphers = NULL ;
Debug ( " available ciphers: " ) ;
do {
2023-07-13 07:06:35 +00:00
ciphers = SSL_get_cipher_list ( sfd - > para . openssl . ssl , i ) ;
2008-01-27 12:00:08 +00:00
if ( ciphers = = NULL ) break ;
Debug2 ( " CIPHERS pri=%d: %s " , i , ciphers ) ;
+ + i ;
} while ( 1 ) ;
}
# endif /* WITH_DEBUG */
/* connect via SSL by performing handshake */
2023-07-13 07:06:35 +00:00
if ( ( ret = sycSSL_accept ( sfd - > para . openssl . ssl ) ) < = 0 ) {
2008-01-27 12:00:08 +00:00
/*if (ERR_peek_error() == 0) Msg(level, "SSL_accept() failed");*/
2023-07-13 07:06:35 +00:00
errint = SSL_get_error ( sfd - > para . openssl . ssl , ret ) ;
2008-01-27 12:00:08 +00:00
switch ( errint ) {
case SSL_ERROR_NONE :
Msg ( level , " ok " ) ; break ;
case SSL_ERROR_ZERO_RETURN :
Msg ( level , " connection closed (wrong version number?) " ) ; break ;
case SSL_ERROR_WANT_READ : case SSL_ERROR_WANT_WRITE :
case SSL_ERROR_WANT_CONNECT :
case SSL_ERROR_WANT_X509_LOOKUP :
Msg ( level , " nonblocking operation did not complete " ) ; break ; /*!*/
case SSL_ERROR_SYSCALL :
if ( ERR_peek_error ( ) = = 0 ) {
if ( ret = = 0 ) {
Msg ( level , " SSL_accept(): socket closed by peer " ) ;
} else if ( ret = = - 1 ) {
Msg1 ( level , " SSL_accept(): %s " , strerror ( errno ) ) ;
}
} else {
Msg ( level , " I/O error " ) ; /*!*/
while ( err = ERR_get_error ( ) ) {
ERR_error_string_n ( err , error_string , sizeof ( error_string ) ) ;
Msg4 ( level , " SSL_accept(): %s / %s / %s / %s " , error_string ,
ERR_lib_error_string ( err ) , ERR_func_error_string ( err ) ,
ERR_reason_error_string ( err ) ) ;
}
2015-01-12 22:11:26 +00:00
/* Msg1(level, "SSL_accept(): %s", ERR_error_string(e, buf));*/
2008-01-27 12:00:08 +00:00
}
break ;
case SSL_ERROR_SSL :
/*ERR_print_errors_fp(stderr);*/
openssl_SSL_ERROR_SSL ( level , " SSL_accept " ) ;
break ;
default :
Msg ( level , " unknown error " ) ;
}
return STAT_RETRYLATER ;
}
2023-07-13 07:06:35 +00:00
if ( openssl_handle_peer_certificate ( sfd , opt_commonname , opt_ver , E_ERROR /*!*/ ) < 0 ) {
2008-01-27 12:00:08 +00:00
return STAT_NORETRY ;
}
return STAT_OK ;
}
# endif /* WITH_LISTEN */
2011-11-26 13:27:02 +00:00
# if OPENSSL_VERSION_NUMBER >= 0x00908000L
/* In OpenSSL 0.9.7 compression methods could be added using
* SSL_COMP_add_compression_method ( 3 ) , but the implemntation is not compatible
* with the standard ( RFC3749 ) .
*/
static int openssl_setup_compression ( SSL_CTX * ctx , char * method )
{
STACK_OF ( SSL_COMP ) * comp_methods ;
assert ( method ) ;
/* Getting the stack of compression methods has the intended side-effect of
* initializing the SSL library ' s compression part .
*/
comp_methods = SSL_COMP_get_compression_methods ( ) ;
if ( ! comp_methods ) {
Info ( " OpenSSL built without compression support " ) ;
return STAT_OK ;
}
if ( strcasecmp ( method , " auto " ) = = 0 ) {
Info ( " Using default OpenSSL compression " ) ;
return STAT_OK ;
}
if ( strcasecmp ( method , " none " ) = = 0 ) {
/* Disable compression */
# ifdef SSL_OP_NO_COMPRESSION
Info ( " Disabling OpenSSL compression " ) ;
SSL_CTX_set_options ( ctx , SSL_OP_NO_COMPRESSION ) ;
# else
/* SSL_OP_NO_COMPRESSION was only introduced in OpenSSL 0.9.9 (released
* as 1.0 .0 ) . Removing all compression methods is a work - around for
* earlier versions of OpenSSL , but it affects all SSL connections .
*/
Info ( " Disabling OpenSSL compression globally " ) ;
sk_SSL_COMP_zero ( comp_methods ) ;
# endif
return STAT_OK ;
}
/* zlib compression in OpenSSL before version 0.9.8e-beta1 uses the libc's
* default malloc / free instead of the ones passed to OpenSSL . Should socat
* ever use custom malloc / free functions for OpenSSL , this must be taken
* into consideration . See OpenSSL bug # 1468.
*/
Error1 ( " openssl-compress= \" %s \" : unknown compression method " , method ) ;
return STAT_NORETRY ;
}
# endif
2020-12-27 19:25:10 +00:00
# if HAVE_CTX_SSL_set_min_proto_version || defined(SSL_CTX_set_min_proto_version) || \
HAVE_SSL_CTX_set_max_proto_version | | defined ( SSL_CTX_set_max_proto_version )
# define XIO_OPENSSL_VERSIONGROUP_TLS 1
# define XIO_OPENSSL_VERSIONGROUP_DTLS 2
static struct wordent _xio_openssl_versions [ ] = {
# ifdef DTLS1_VERSION
{ " DTLS1 " , ( void * ) DTLS1_VERSION } ,
{ " DTLS1.0 " , ( void * ) DTLS1_VERSION } ,
# endif
# ifdef DTLS1_2_VERSION
{ " DTLS1.2 " , ( void * ) DTLS1_2_VERSION } ,
# endif
# ifdef DTLS1_VERSION
{ " DTLSv1 " , ( void * ) DTLS1_VERSION } ,
{ " DTLSv1.0 " , ( void * ) DTLS1_VERSION } ,
# endif
# ifdef DTLS1_2_VERSION
{ " DTLSv1.2 " , ( void * ) DTLS1_2_VERSION } ,
# endif
# ifdef SSL2_VERSION
{ " SSL2 " , ( void * ) SSL2_VERSION } ,
# endif
# ifdef SSL3_VERSION
{ " SSL3 " , ( void * ) SSL3_VERSION } ,
# endif
# ifdef SSL2_VERSION
{ " SSLv2 " , ( void * ) SSL2_VERSION } ,
# endif
# ifdef SSL3_VERSION
{ " SSLv3 " , ( void * ) SSL3_VERSION } ,
# endif
# ifdef TLS1_VERSION
{ " TLS1 " , ( void * ) TLS1_VERSION } ,
{ " TLS1.0 " , ( void * ) TLS1_VERSION } ,
# endif
# ifdef TLS1_1_VERSION
{ " TLS1.1 " , ( void * ) TLS1_1_VERSION } ,
# endif
# ifdef TLS1_2_VERSION
{ " TLS1.2 " , ( void * ) TLS1_2_VERSION } ,
# endif
# ifdef TLS1_3_VERSION
{ " TLS1.3 " , ( void * ) TLS1_3_VERSION } ,
# endif
# ifdef TLS1_VERSION
{ " TLSv1 " , ( void * ) TLS1_VERSION } ,
{ " TLSv1.0 " , ( void * ) TLS1_VERSION } ,
# endif
# ifdef TLS1_1_VERSION
{ " TLSv1.1 " , ( void * ) TLS1_1_VERSION } ,
# endif
# ifdef TLS1_2_VERSION
{ " TLSv1.2 " , ( void * ) TLS1_2_VERSION } ,
# endif
# ifdef TLS1_3_VERSION
{ " TLSv1.3 " , ( void * ) TLS1_3_VERSION } ,
# endif
} ;
static int _xio_openssl_parse_version ( const char * verstring , int vergroups ) {
int sslver ;
const struct wordent * we ;
we = keyw ( _xio_openssl_versions , verstring ,
sizeof ( _xio_openssl_versions ) / sizeof ( struct wordent ) ) ;
if ( we = = 0 ) {
Error1 ( " Unknown SSL/TLS version \" %s \" " , verstring ) ;
return - 1 ;
}
sslver = ( size_t ) we - > desc ;
switch ( sslver ) {
# ifdef SSL2_VERSION
case SSL2_VERSION :
# endif
# ifdef SSL3_VERSION
case SSL3_VERSION :
# endif
# ifdef TLS1_VERSION
case TLS1_VERSION :
# endif
# ifdef TLS1_1_VERSION
case TLS1_1_VERSION :
# endif
# ifdef TLS1_2_VERSION
case TLS1_2_VERSION :
# endif
# ifdef TLS1_3_VERSION
case TLS1_3_VERSION :
# endif
if ( ! ( vergroups & XIO_OPENSSL_VERSIONGROUP_TLS ) ) {
Error1 ( " Wrong type of TLS/DTLS version \" %s \" " , verstring ) ;
return - 1 ;
}
# ifdef DTLS1_VERSION
case DTLS1_VERSION :
# endif
# ifdef DTLS1_2_VERSION
case DTLS1_2_VERSION :
# endif
if ( ! ( vergroups & XIO_OPENSSL_VERSIONGROUP_DTLS ) ) {
Error1 ( " Wrong type of TLS/DTLS version \" %s \" " , verstring ) ;
return - 1 ;
}
break ;
}
return sslver ;
}
# endif /* defined(SSL_CTX_set_min_proto_version) || defined(SSL_CTX_set_max_proto_version) */
2008-01-27 12:00:08 +00:00
int
_xioopen_openssl_prepare ( struct opt * opts ,
2023-07-13 07:06:35 +00:00
struct single * sfd , /* a xio file descriptor
2008-01-27 12:00:08 +00:00
structure , already allocated
*/
bool server , /* SSL client: false */
bool * opt_ver ,
const char * opt_cert ,
2020-12-30 18:46:42 +00:00
SSL_CTX * * ctxp ,
bool * use_dtls ) /* checked,overwritten with true if DTLS-method */
2008-01-27 12:00:08 +00:00
{
2020-12-27 19:25:10 +00:00
SSL_CTX * ctx ;
2008-01-27 12:00:08 +00:00
bool opt_fips = false ;
2015-01-23 17:38:06 +00:00
const SSL_METHOD * method = NULL ;
2008-01-27 12:00:08 +00:00
char * me_str = NULL ; /* method string */
2014-11-23 12:48:05 +00:00
char * ci_str = " HIGH:-NULL:-PSK:-aNULL " ; /* cipher string */
2008-01-27 12:00:08 +00:00
char * opt_key = NULL ; /* file name of client private key */
char * opt_dhparam = NULL ; /* file name of DH params */
char * opt_cafile = NULL ; /* certificate authority file */
char * opt_capath = NULL ; /* certificate authority directory */
char * opt_egd = NULL ; /* entropy gathering daemon socket path */
2011-11-26 13:27:02 +00:00
# if OPENSSL_VERSION_NUMBER >= 0x00908000L
char * opt_compress = NULL ; /* compression method */
# endif
2008-01-27 12:00:08 +00:00
bool opt_pseudo = false ; /* use pseudo entropy if nothing else */
unsigned long err ;
int result ;
2023-07-13 07:06:35 +00:00
sfd - > dtype = XIODATA_OPENSSL ;
2008-01-27 12:00:08 +00:00
retropt_bool ( opts , OPT_OPENSSL_FIPS , & opt_fips ) ;
retropt_string ( opts , OPT_OPENSSL_METHOD , & me_str ) ;
retropt_string ( opts , OPT_OPENSSL_CIPHERLIST , & ci_str ) ;
retropt_bool ( opts , OPT_OPENSSL_VERIFY , opt_ver ) ;
retropt_string ( opts , OPT_OPENSSL_CAFILE , & opt_cafile ) ;
retropt_string ( opts , OPT_OPENSSL_CAPATH , & opt_capath ) ;
retropt_string ( opts , OPT_OPENSSL_KEY , & opt_key ) ;
retropt_string ( opts , OPT_OPENSSL_DHPARAM , & opt_dhparam ) ;
retropt_string ( opts , OPT_OPENSSL_EGD , & opt_egd ) ;
retropt_bool ( opts , OPT_OPENSSL_PSEUDO , & opt_pseudo ) ;
2011-11-26 13:27:02 +00:00
# if OPENSSL_VERSION_NUMBER >= 0x00908000L
retropt_string ( opts , OPT_OPENSSL_COMPRESS , & opt_compress ) ;
# endif
2008-01-27 12:00:08 +00:00
# if WITH_FIPS
if ( opt_fips ) {
if ( ! sycFIPS_mode_set ( 1 ) ) {
ERR_load_crypto_strings ( ) ;
ERR_print_errors ( BIO_new_fp ( stderr , BIO_NOCLOSE ) ) ;
Error ( " Failed to set FIPS mode " ) ;
} else {
xio_openssl_fips = true ;
}
}
# endif
2015-01-12 22:34:47 +00:00
openssl_delete_cert_info ( ) ;
2021-01-03 06:43:00 +00:00
/* OpenSSL preparation */
2023-04-02 14:40:32 +00:00
# if defined(HAVE_OPENSSL_INIT_SSL) && defined(HAVE_OPENSSL_INIT_new)
2021-01-03 06:43:00 +00:00
{
2022-07-09 13:29:26 +00:00
uint64_t opts = 0 ;
2023-10-02 17:43:13 +00:00
# if defined(OPENSSL_INIT_SETTINGS)
2021-01-03 06:43:00 +00:00
OPENSSL_INIT_SETTINGS * settings ;
2023-10-02 17:43:13 +00:00
# else
void * settings ;
# endif
2021-01-03 06:43:00 +00:00
settings = OPENSSL_INIT_new ( ) ;
2022-07-09 13:29:26 +00:00
# ifdef OPENSSL_INIT_NO_ATEXIT
opts | = OPENSSL_INIT_NO_ATEXIT ;
# endif
sycOPENSSL_init_ssl ( opts , settings ) ;
2021-01-03 06:43:00 +00:00
}
# else
2023-04-02 14:40:32 +00:00
# if defined(HAVE_SSL_library_init)
2021-01-03 06:43:00 +00:00
sycSSL_library_init ( ) ;
2023-04-02 14:40:32 +00:00
# endif
2008-01-27 12:00:08 +00:00
OpenSSL_add_all_algorithms ( ) ;
OpenSSL_add_all_ciphers ( ) ;
OpenSSL_add_all_digests ( ) ;
sycSSL_load_error_strings ( ) ;
2023-04-02 14:40:32 +00:00
# endif /* defined(HAVE_OPENSSL_INIT_SSL) && defined(HAVE OPENSSL_INIT_new) */
2008-01-27 12:00:08 +00:00
/*! actions_to_seed_PRNG();*/
if ( ! server ) {
2015-01-23 17:38:06 +00:00
if ( me_str ! = NULL ) {
if ( false ) {
; /* for canonical reasons */
2011-12-04 14:14:34 +00:00
# if HAVE_SSLv2_client_method
2015-01-23 17:38:06 +00:00
} else if ( ! strcasecmp ( me_str , " SSL2 " ) ) {
2008-01-27 12:00:08 +00:00
method = sycSSLv2_client_method ( ) ;
2011-12-04 14:14:34 +00:00
# endif
2015-01-23 17:38:06 +00:00
# if HAVE_SSLv3_client_method
} else if ( ! strcasecmp ( me_str , " SSL3 " ) ) {
2008-01-27 12:00:08 +00:00
method = sycSSLv3_client_method ( ) ;
2015-01-23 17:38:06 +00:00
# endif
# if HAVE_SSLv23_client_method
} else if ( ! strcasecmp ( me_str , " SSL23 " ) ) {
2008-01-27 12:00:08 +00:00
method = sycSSLv23_client_method ( ) ;
2015-01-23 17:38:06 +00:00
# endif
# if HAVE_TLSv1_client_method
} else if ( ! strcasecmp ( me_str , " TLS1 " ) | | ! strcasecmp ( me_str , " TLS1.0 " ) ) {
2008-01-27 12:00:08 +00:00
method = sycTLSv1_client_method ( ) ;
2015-01-23 17:38:06 +00:00
# endif
# if HAVE_TLSv1_1_client_method
} else if ( ! strcasecmp ( me_str , " TLS1.1 " ) ) {
method = sycTLSv1_1_client_method ( ) ;
# endif
# if HAVE_TLSv1_2_client_method
} else if ( ! strcasecmp ( me_str , " TLS1.2 " ) ) {
method = sycTLSv1_2_client_method ( ) ;
# endif
# if HAVE_DTLSv1_client_method
2020-12-30 18:46:42 +00:00
} else if ( ! strcasecmp ( me_str , " DTLS1 " ) | | ! strcasecmp ( me_str , " DTLS1.0 " ) ) {
2015-01-23 17:38:06 +00:00
method = sycDTLSv1_client_method ( ) ;
2020-12-30 18:46:42 +00:00
* use_dtls = true ;
# endif
# if HAVE_DTLSv1_2_client_method
} else if ( ! strcasecmp ( me_str , " DTLS1.2 " ) ) {
method = sycDTLSv1_2_client_method ( ) ;
* use_dtls = true ;
2015-01-23 17:38:06 +00:00
# endif
2008-01-27 12:00:08 +00:00
} else {
2015-01-23 17:38:06 +00:00
Error1 ( " openssl-method= \" %s \" : method unknown or not provided by library " , me_str ) ;
2008-01-27 12:00:08 +00:00
}
2020-12-30 18:46:42 +00:00
} else if ( ! * use_dtls ) {
2019-02-10 12:16:42 +00:00
# if HAVE_TLS_client_method
2020-12-30 18:46:42 +00:00
method = sycTLS_client_method ( ) ;
2019-02-10 12:16:42 +00:00
# elif HAVE_SSLv23_client_method
2015-01-24 17:40:03 +00:00
method = sycSSLv23_client_method ( ) ;
# elif HAVE_TLSv1_2_client_method
2015-01-23 17:38:06 +00:00
method = sycTLSv1_2_client_method ( ) ;
# elif HAVE_TLSv1_1_client_method
method = sycTLSv1_1_client_method ( ) ;
# elif HAVE_TLSv1_client_method
method = sycTLSv1_client_method ( ) ;
# elif HAVE_SSLv3_client_method
method = sycSSLv3_client_method ( ) ;
# elif HAVE_SSLv2_client_method
method = sycSSLv2_client_method ( ) ;
# else
2020-12-30 18:46:42 +00:00
# error "OpenSSL does not seem to provide SSL / TLS client methods"
# endif
} else {
# if HAVE_DTLS_client_method
method = sycDTLS_client_method ( ) ;
# elif HAVE_DTLSv1_2_client_method
method = sycDTLSv1_2_client_method ( ) ;
# elif HAVE_DTLSv1_client_method
method = sycDTLSv1_client_method ( ) ;
# else
2024-06-21 11:59:45 +00:00
# warning "OpenSSL does not seem to provide DTLS client methods"
2015-01-23 17:38:06 +00:00
# endif
2020-12-30 18:46:42 +00:00
* use_dtls = true ;
2008-01-27 12:00:08 +00:00
}
} else /* server */ {
if ( me_str ! = 0 ) {
2015-01-23 17:38:06 +00:00
if ( false ) {
; /* for canonical reasons */
2011-12-04 14:14:34 +00:00
# if HAVE_SSLv2_server_method
2015-01-23 17:38:06 +00:00
} else if ( ! strcasecmp ( me_str , " SSL2 " ) ) {
2008-01-27 12:00:08 +00:00
method = sycSSLv2_server_method ( ) ;
2011-12-04 14:14:34 +00:00
# endif
2015-01-23 17:38:06 +00:00
# if HAVE_SSLv3_server_method
} else if ( ! strcasecmp ( me_str , " SSL3 " ) ) {
2008-01-27 12:00:08 +00:00
method = sycSSLv3_server_method ( ) ;
2015-01-23 17:38:06 +00:00
# endif
# if HAVE_SSLv23_server_method
} else if ( ! strcasecmp ( me_str , " SSL23 " ) ) {
2008-01-27 12:00:08 +00:00
method = sycSSLv23_server_method ( ) ;
2015-01-23 17:38:06 +00:00
# endif
# if HAVE_TLSv1_server_method
} else if ( ! strcasecmp ( me_str , " TLS1 " ) | | ! strcasecmp ( me_str , " TLS1.0 " ) ) {
2008-01-27 12:00:08 +00:00
method = sycTLSv1_server_method ( ) ;
2015-01-23 17:38:06 +00:00
# endif
# if HAVE_TLSv1_1_server_method
} else if ( ! strcasecmp ( me_str , " TLS1.1 " ) ) {
method = sycTLSv1_1_server_method ( ) ;
# endif
# if HAVE_TLSv1_2_server_method
} else if ( ! strcasecmp ( me_str , " TLS1.2 " ) ) {
method = sycTLSv1_2_server_method ( ) ;
# endif
# if HAVE_DTLSv1_server_method
2020-12-30 18:46:42 +00:00
} else if ( ! strcasecmp ( me_str , " DTLS1 " ) | | ! strcasecmp ( me_str , " DTLS1.0 " ) ) {
2015-01-23 17:38:06 +00:00
method = sycDTLSv1_server_method ( ) ;
2020-12-30 18:46:42 +00:00
* use_dtls = true ;
# endif
# if HAVE_DTLSv1_2_server_method
} else if ( ! strcasecmp ( me_str , " DTLS1.2 " ) ) {
method = sycDTLSv1_2_server_method ( ) ;
* use_dtls = true ;
2015-01-23 17:38:06 +00:00
# endif
2008-01-27 12:00:08 +00:00
} else {
2015-01-23 17:38:06 +00:00
Error1 ( " openssl-method= \" %s \" : method unknown or not provided by library " , me_str ) ;
2008-01-27 12:00:08 +00:00
}
2020-12-30 18:46:42 +00:00
} else if ( ! * use_dtls ) {
2019-02-10 12:16:42 +00:00
# if HAVE_TLS_server_method
2020-12-30 18:46:42 +00:00
method = sycTLS_server_method ( ) ;
2019-02-10 12:16:42 +00:00
# elif HAVE_SSLv23_server_method
2015-01-24 17:40:03 +00:00
method = sycSSLv23_server_method ( ) ;
# elif HAVE_TLSv1_2_server_method
2015-01-23 17:38:06 +00:00
method = sycTLSv1_2_server_method ( ) ;
# elif HAVE_TLSv1_1_server_method
method = sycTLSv1_1_server_method ( ) ;
# elif HAVE_TLSv1_server_method
2015-01-24 17:40:03 +00:00
method = sycTLSv1_server_method ( ) ;
2015-01-23 17:38:06 +00:00
# elif HAVE_SSLv3_server_method
method = sycSSLv3_server_method ( ) ;
# elif HAVE_SSLv2_server_method
method = sycSSLv2_server_method ( ) ;
# else
2020-12-30 18:46:42 +00:00
# error "OpenSSL does not seem to provide SSL / TLS server methods"
# endif
} else {
# if HAVE_DTLS_server_method
method = sycDTLS_server_method ( ) ;
# elif HAVE_DTLSv1_2_server_method
method = sycDTLSv1_2_server_method ( ) ;
# elif HAVE_DTLSv1_server_method
method = sycDTLSv1_server_method ( ) ;
# else
2024-06-21 11:59:45 +00:00
# warning "OpenSSL does not seem to provide DTLS server methods"
2015-01-23 17:38:06 +00:00
# endif
2020-12-30 18:46:42 +00:00
* use_dtls = true ;
2008-01-27 12:00:08 +00:00
}
}
2024-06-21 11:59:45 +00:00
if ( method = = NULL ) {
Error ( " no OpenSSL method available " ) ;
return STAT_NORETRY ;
}
2008-01-27 12:00:08 +00:00
if ( opt_egd ) {
2016-12-05 11:05:02 +00:00
# if !defined(OPENSSL_NO_EGD) && HAVE_RAND_egd
2008-01-27 12:00:08 +00:00
sycRAND_egd ( opt_egd ) ;
2016-12-05 11:05:02 +00:00
# else
Debug ( " RAND_egd() is not available by OpenSSL " ) ;
# endif
2008-01-27 12:00:08 +00:00
}
if ( opt_pseudo ) {
long int randdata ;
/* initialize libc random from actual microseconds */
struct timeval tv ;
struct timezone tz ;
tz . tz_minuteswest = 0 ;
tz . tz_dsttime = 0 ;
if ( ( result = Gettimeofday ( & tv , & tz ) ) < 0 ) {
Warn2 ( " gettimeofday(%p, {0,0}): %s " , & tv , strerror ( errno ) ) ;
}
srandom ( tv . tv_sec * 1000000 + tv . tv_usec ) ;
while ( ! RAND_status ( ) ) {
randdata = random ( ) ;
Debug2 ( " RAND_seed(0x{%lx}, " F_Zu " ) " ,
randdata , sizeof ( randdata ) ) ;
RAND_seed ( & randdata , sizeof ( randdata ) ) ;
}
}
2020-12-27 19:25:10 +00:00
if ( ( ctx = sycSSL_CTX_new ( method ) ) = = NULL ) {
2008-01-27 12:00:08 +00:00
if ( ERR_peek_error ( ) = = 0 ) Error ( " SSL_CTX_new() " ) ;
while ( err = ERR_get_error ( ) ) {
Error1 ( " SSL_CTX_new(): %s " , ERR_error_string ( err , NULL ) ) ;
}
/*ERR_clear_error;*/
return STAT_RETRYLATER ;
}
2023-07-13 07:06:35 +00:00
sfd - > para . openssl . ctx = ctx ;
2020-12-27 19:25:10 +00:00
* ctxp = ctx ;
# if HAVE_SSL_CTX_set_min_proto_version || defined(SSL_CTX_set_min_proto_version)
2023-07-13 07:06:35 +00:00
if ( sfd - > para . openssl . min_proto_version ! = NULL ) {
2020-12-27 19:25:10 +00:00
int sslver , rc ;
2023-07-13 07:06:35 +00:00
sslver = _xio_openssl_parse_version ( sfd - > para . openssl . min_proto_version ,
2020-12-27 19:25:10 +00:00
XIO_OPENSSL_VERSIONGROUP_TLS | XIO_OPENSSL_VERSIONGROUP_DTLS ) ;
if ( sslver < 0 )
return STAT_NORETRY ;
if ( ( rc = SSL_CTX_set_min_proto_version ( ctx , sslver ) ) < = 0 ) {
2021-01-03 15:56:50 +00:00
Debug1 ( " version: %ld " , SSL_CTX_get_min_proto_version ( ctx ) ) ;
2020-12-27 19:25:10 +00:00
Error3 ( " _xioopen_openssl_prepare(): SSL_CTX_set_min_proto_version( \" %s \" ->%d): failed (%d) " ,
2023-07-13 07:06:35 +00:00
sfd - > para . openssl . min_proto_version , sslver , rc ) ;
2020-12-27 19:25:10 +00:00
return STAT_NORETRY ;
}
2021-01-03 15:56:50 +00:00
Debug1 ( " version: %ld " , SSL_CTX_get_min_proto_version ( ctx ) ) ;
2020-12-27 19:25:10 +00:00
}
# endif /* HAVE_SSL_set_min_proto_version || defined(SSL_set_min_proto_version) */
# if HAVE_SSL_CTX_set_max_proto_version || defined(SSL_CTX_set_max_proto_version)
2023-07-13 07:06:35 +00:00
if ( sfd - > para . openssl . max_proto_version ! = NULL ) {
2020-12-27 19:25:10 +00:00
int sslver ;
2023-07-13 07:06:35 +00:00
sslver = _xio_openssl_parse_version ( sfd - > para . openssl . max_proto_version ,
2020-12-27 19:25:10 +00:00
XIO_OPENSSL_VERSIONGROUP_TLS | XIO_OPENSSL_VERSIONGROUP_DTLS ) ;
if ( sslver < 0 )
return STAT_NORETRY ;
if ( SSL_CTX_set_max_proto_version ( ctx , sslver ) < = 0 ) {
Error2 ( " _xioopen_openssl_prepare(): SSL_CTX_set_max_proto_version( \" %s \" ->%d): failed " ,
2023-07-13 07:06:35 +00:00
sfd - > para . openssl . max_proto_version , sslver ) ;
2020-12-27 19:25:10 +00:00
return STAT_NORETRY ;
}
}
# endif /* HAVE_SSL_set_max_proto_version || defined(SSL_set_max_proto_version) */
2008-01-27 12:00:08 +00:00
2011-11-22 09:42:38 +00:00
{
2016-01-29 10:29:11 +00:00
static unsigned char dh2048_p [ ] = {
0x00 , 0xdc , 0x21 , 0x64 , 0x56 , 0xbd , 0x9c , 0xb2 , 0xac , 0xbe , 0xc9 , 0x98 , 0xef , 0x95 , 0x3e ,
0x26 , 0xfa , 0xb5 , 0x57 , 0xbc , 0xd9 , 0xe6 , 0x75 , 0xc0 , 0x43 , 0xa2 , 0x1c , 0x7a , 0x85 , 0xdf ,
0x34 , 0xab , 0x57 , 0xa8 , 0xf6 , 0xbc , 0xf6 , 0x84 , 0x7d , 0x05 , 0x69 , 0x04 , 0x83 , 0x4c , 0xd5 ,
0x56 , 0xd3 , 0x85 , 0x09 , 0x0a , 0x08 , 0xff , 0xb5 , 0x37 , 0xa1 , 0xa3 , 0x8a , 0x37 , 0x04 , 0x46 ,
0xd2 , 0x93 , 0x31 , 0x96 , 0xf4 , 0xe4 , 0x0d , 0x9f , 0xbd , 0x3e , 0x7f , 0x9e , 0x4d , 0xaf , 0x08 ,
0xe2 , 0xe8 , 0x03 , 0x94 , 0x73 , 0xc4 , 0xdc , 0x06 , 0x87 , 0xbb , 0x6d , 0xae , 0x66 , 0x2d , 0x18 ,
0x1f , 0xd8 , 0x47 , 0x06 , 0x5c , 0xcf , 0x8a , 0xb5 , 0x00 , 0x51 , 0x57 , 0x9b , 0xea , 0x1e , 0xd8 ,
0xdb , 0x8e , 0x3c , 0x1f , 0xd3 , 0x2f , 0xba , 0x1f , 0x5f , 0x3d , 0x15 , 0xc1 , 0x3b , 0x2c , 0x82 ,
0x42 , 0xc8 , 0x8c , 0x87 , 0x79 , 0x5b , 0x38 , 0x86 , 0x3a , 0xeb , 0xfd , 0x81 , 0xa9 , 0xba , 0xf7 ,
0x26 , 0x5b , 0x93 , 0xc5 , 0x3e , 0x03 , 0x30 , 0x4b , 0x00 , 0x5c , 0xb6 , 0x23 , 0x3e , 0xea , 0x94 ,
0xc3 , 0xb4 , 0x71 , 0xc7 , 0x6e , 0x64 , 0x3b , 0xf8 , 0x92 , 0x65 , 0xad , 0x60 , 0x6c , 0xd4 , 0x7b ,
0xa9 , 0x67 , 0x26 , 0x04 , 0xa8 , 0x0a , 0xb2 , 0x06 , 0xeb , 0xe0 , 0x7d , 0x90 , 0xdd , 0xdd , 0xf5 ,
0xcf , 0xb4 , 0x11 , 0x7c , 0xab , 0xc1 , 0xa3 , 0x84 , 0xbe , 0x27 , 0x77 , 0xc7 , 0xde , 0x20 , 0x57 ,
0x66 , 0x47 , 0xa7 , 0x35 , 0xfe , 0x0d , 0x6a , 0x1c , 0x52 , 0xb8 , 0x58 , 0xbf , 0x26 , 0x33 , 0x81 ,
0x5e , 0xb7 , 0xa9 , 0xc0 , 0xee , 0x58 , 0x11 , 0x74 , 0x86 , 0x19 , 0x08 , 0x89 , 0x1c , 0x37 , 0x0d ,
0x52 , 0x47 , 0x70 , 0x75 , 0x8b , 0xa8 , 0x8b , 0x30 , 0x11 , 0x71 , 0x36 , 0x62 , 0xf0 , 0x73 , 0x41 ,
0xee , 0x34 , 0x9d , 0x0a , 0x2b , 0x67 , 0x4e , 0x6a , 0xa3 , 0xe2 , 0x99 , 0x92 , 0x1b , 0xf5 , 0x32 ,
0x73 , 0x63
2011-11-22 09:42:38 +00:00
} ;
2016-01-29 10:29:11 +00:00
static unsigned char dh2048_g [ ] = {
2011-11-22 09:42:38 +00:00
0x02 ,
} ;
DH * dh ;
2016-12-05 11:05:02 +00:00
BIGNUM * p = NULL , * g = NULL ;
2011-11-22 09:42:38 +00:00
unsigned long err ;
2016-12-05 11:05:02 +00:00
dh = DH_new ( ) ;
p = BN_bin2bn ( dh2048_p , sizeof ( dh2048_p ) , NULL ) ;
g = BN_bin2bn ( dh2048_g , sizeof ( dh2048_g ) , NULL ) ;
if ( ! dh | | ! p | | ! g ) {
if ( dh )
DH_free ( dh ) ;
if ( p )
BN_free ( p ) ;
if ( g )
BN_free ( g ) ;
while ( err = ERR_get_error ( ) ) {
Warn1 ( " dh2048 setup(): %s " ,
ERR_error_string ( err , NULL ) ) ;
}
Error ( " dh2048 setup failed " ) ;
goto cont_out ;
}
# if HAVE_DH_set0_pqg
if ( ! DH_set0_pqg ( dh , p , NULL , g ) ) {
DH_free ( dh ) ;
BN_free ( p ) ;
BN_free ( g ) ;
goto cont_out ;
}
# else
dh - > p = p ;
dh - > g = g ;
# endif /* HAVE_DH_set0_pqg */
2020-12-27 19:25:10 +00:00
if ( sycSSL_CTX_set_tmp_dh ( ctx , dh ) < = 0 ) {
2016-12-05 11:05:02 +00:00
while ( err = ERR_get_error ( ) ) {
2020-12-27 19:25:10 +00:00
Warn3 ( " SSL_CTX_set_tmp_dh(%p, %p): %s " , ctx , dh ,
2016-12-05 11:05:02 +00:00
ERR_error_string ( err , NULL ) ) ;
}
2020-12-27 19:25:10 +00:00
Error2 ( " SSL_CTX_set_tmp_dh(%p, %p) failed " , ctx , dh ) ;
2011-11-22 09:42:38 +00:00
}
2016-12-05 11:05:02 +00:00
/* p & g are freed by DH_free() once attached */
DH_free ( dh ) ;
cont_out :
;
2011-11-22 09:42:38 +00:00
}
2016-12-10 20:51:27 +00:00
# if HAVE_TYPE_EC_KEY /* not on Openindiana 5.11 */
2015-01-23 16:31:14 +00:00
{
/* see http://openssl.6102.n7.nabble.com/Problem-with-cipher-suite-ECDHE-ECDSA-AES256-SHA384-td42229.html */
int nid ;
EC_KEY * ecdh ;
#if 0
nid = OBJ_sn2nid ( ECDHE_CURVE ) ;
if ( nid = = NID_undef ) {
Error ( " openssl: failed to set ECDHE parameters " ) ;
return - 1 ;
}
# endif
nid = NID_X9_62_prime256v1 ;
ecdh = EC_KEY_new_by_curve_name ( nid ) ;
if ( NULL = = ecdh ) {
Error ( " openssl: failed to set ECDHE parameters " ) ;
return - 1 ;
}
2020-12-27 19:25:10 +00:00
SSL_CTX_set_tmp_ecdh ( ctx , ecdh ) ;
2015-01-23 16:31:14 +00:00
}
2016-12-10 20:51:27 +00:00
# endif /* HAVE_TYPE_EC_KEY */
2015-01-23 16:31:14 +00:00
2011-11-26 13:27:02 +00:00
# if OPENSSL_VERSION_NUMBER >= 0x00908000L
if ( opt_compress ) {
int result ;
2020-12-27 19:25:10 +00:00
result = openssl_setup_compression ( ctx , opt_compress ) ;
2011-11-26 13:27:02 +00:00
if ( result ! = STAT_OK ) {
return result ;
}
}
# endif
2019-08-31 16:26:41 +00:00
# if defined(HAVE_SSL_CTX_clear_mode) || defined(SSL_CTX_clear_mode)
2019-03-12 20:09:18 +00:00
/* It seems that OpenSSL-1.1.1 presets the mode differently.
Without correction socat might hang in SSL_read ( ) */
{
long mode = 0 ;
2020-12-27 19:25:10 +00:00
mode = SSL_CTX_get_mode ( ctx ) ;
2019-03-12 20:09:18 +00:00
if ( mode & SSL_MODE_AUTO_RETRY ) {
Info ( " SSL_CTX mode has SSL_MODE_AUTO_RETRY set. Correcting.. " ) ;
2021-01-10 12:32:27 +00:00
Debug1 ( " SSL_CTX_clear_mode(%p, SSL_MODE_AUTO_RETRY) " , ctx ) ;
2020-12-27 19:25:10 +00:00
SSL_CTX_clear_mode ( ctx , SSL_MODE_AUTO_RETRY ) ;
2019-03-12 20:09:18 +00:00
}
}
2019-08-31 16:26:41 +00:00
# endif /* defined(HAVE_SSL_CTX_clear_mode) || defined(SSL_CTX_clear_mode) */
2019-03-12 20:09:18 +00:00
2008-01-27 12:00:08 +00:00
if ( opt_cafile ! = NULL | | opt_capath ! = NULL ) {
2020-12-27 19:25:10 +00:00
if ( sycSSL_CTX_load_verify_locations ( ctx , opt_cafile , opt_capath ) ! = 1 ) {
2008-01-27 12:00:08 +00:00
int result ;
if ( ( result =
openssl_SSL_ERROR_SSL ( E_ERROR , " SSL_CTX_load_verify_locations " ) )
! = STAT_OK ) {
/*! free ctx */
return STAT_RETRYLATER ;
}
}
2014-04-03 10:57:43 +00:00
# ifdef HAVE_SSL_CTX_set_default_verify_paths
} else {
2020-12-27 19:25:10 +00:00
SSL_CTX_set_default_verify_paths ( ctx ) ;
2014-04-03 10:57:43 +00:00
# endif
2008-01-27 12:00:08 +00:00
}
2023-08-05 17:05:14 +00:00
/* set pre openssl-connect options */
/* SSL_CIPHERS */
if ( ci_str ! = NULL ) {
if ( sycSSL_CTX_set_cipher_list ( ctx , ci_str ) < = 0 ) {
if ( ERR_peek_error ( ) = = 0 )
Error1 ( " SSL_set_cipher_list(, \" %s \" ) failed " , ci_str ) ;
while ( err = ERR_get_error ( ) ) {
Error2 ( " SSL_set_cipher_list(, \" %s \" ): %s " ,
ci_str , ERR_error_string ( err , NULL ) ) ;
}
/*Error("SSL_new()");*/
return STAT_RETRYLATER ;
}
}
2008-01-27 12:00:08 +00:00
if ( opt_cert ) {
BIO * bio ;
DH * dh ;
2020-12-27 19:25:10 +00:00
if ( sycSSL_CTX_use_certificate_chain_file ( ctx , opt_cert ) < = 0 ) {
2008-01-27 12:00:08 +00:00
/*! trace functions */
/*0 ERR_print_errors_fp(stderr);*/
if ( ERR_peek_error ( ) = = 0 )
Error2 ( " SSL_CTX_use_certificate_file(%p, \" %s \" , SSL_FILETYPE_PEM) failed " ,
2020-12-27 19:25:10 +00:00
ctx , opt_cert ) ;
2008-01-27 12:00:08 +00:00
while ( err = ERR_get_error ( ) ) {
Error1 ( " SSL_CTX_use_certificate_file(): %s " ,
ERR_error_string ( err , NULL ) ) ;
}
return STAT_RETRYLATER ;
}
2020-12-27 19:25:10 +00:00
if ( sycSSL_CTX_use_PrivateKey_file ( ctx , opt_key ? opt_key : opt_cert , SSL_FILETYPE_PEM ) < = 0 ) {
2008-01-27 12:00:08 +00:00
/*ERR_print_errors_fp(stderr);*/
openssl_SSL_ERROR_SSL ( E_ERROR /*!*/ , " SSL_CTX_use_PrivateKey_file " ) ;
return STAT_RETRYLATER ;
}
if ( opt_dhparam = = NULL ) {
opt_dhparam = ( char * ) opt_cert ;
}
if ( ( bio = sycBIO_new_file ( opt_dhparam , " r " ) ) = = NULL ) {
Warn2 ( " BIO_new_file( \" %s \" , \" r \" ): %s " ,
opt_dhparam , strerror ( errno ) ) ;
} else {
if ( ( dh = sycPEM_read_bio_DHparams ( bio , NULL , NULL , NULL ) ) = = NULL ) {
Info1 ( " PEM_read_bio_DHparams(%p, NULL, NULL, NULL): error " , bio ) ;
} else {
BIO_free ( bio ) ;
2020-12-27 19:25:10 +00:00
if ( sycSSL_CTX_set_tmp_dh ( ctx , dh ) < = 0 ) {
2015-01-23 17:38:06 +00:00
while ( err = ERR_get_error ( ) ) {
2020-12-27 19:25:10 +00:00
Warn3 ( " SSL_CTX_set_tmp_dh(%p, %p): %s " , ctx , dh ,
2015-01-23 17:38:06 +00:00
ERR_error_string ( err , NULL ) ) ;
}
2020-12-27 19:25:10 +00:00
Error2 ( " SSL_CTX_set_tmp_dh(%p, %p): error " , ctx , dh ) ;
2008-01-27 12:00:08 +00:00
}
}
}
}
if ( * opt_ver ) {
2020-12-27 19:25:10 +00:00
sycSSL_CTX_set_verify ( ctx ,
2008-01-27 12:00:08 +00:00
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT ,
NULL ) ;
2024-08-22 16:18:52 +00:00
if ( first_child ) {
/* The first forked off process, print the warning only once */
Warn ( " OpenSSL: Warning: this implementation does not check CRLs " ) ;
}
2008-01-27 12:00:08 +00:00
} else {
2020-12-27 19:25:10 +00:00
sycSSL_CTX_set_verify ( ctx ,
2008-01-27 12:00:08 +00:00
SSL_VERIFY_NONE ,
NULL ) ;
}
2023-10-26 14:43:20 +00:00
# if HAVE_SSL_CTX_set_tlsext_max_fragment_length || defined(SSL_CTX_set_tlsext_max_fragment_length)
{
/* set client max fragment length negotiation (512, 1024, 2048, or 4096) */
int opt_maxfraglen = - 1 ;
retropt_int ( opts , OPT_OPENSSL_MAXFRAGLEN , & opt_maxfraglen ) ;
if ( ! server ) {
/* on client connection, ask the server not to send us packets bigger than our inbound buffer */
uint8_t mfl_code = TLSEXT_max_fragment_length_DISABLED ;
if ( opt_maxfraglen = = - 1 ) {
/* max frag length is not specified, leave DISABLED */
} else if ( opt_maxfraglen = = 512 ) {
mfl_code = TLSEXT_max_fragment_length_512 ;
} else if ( opt_maxfraglen = = 1024 ) {
mfl_code = TLSEXT_max_fragment_length_1024 ;
} else if ( opt_maxfraglen = = 2048 ) {
mfl_code = TLSEXT_max_fragment_length_2048 ;
} else if ( opt_maxfraglen = = 4096 ) {
mfl_code = TLSEXT_max_fragment_length_4096 ;
} else {
Error1 ( " openssl: maxfraglen %d is not one of 512, 1024, 2048, or 4096 " , opt_maxfraglen ) ;
return STAT_NORETRY ;
}
sycSSL_CTX_set_tlsext_max_fragment_length ( ctx , mfl_code ) ;
} else {
if ( opt_maxfraglen ! = - 1 ) {
Error ( " openssl: maxfraglen option not applicable to a server " ) ;
return STAT_NORETRY ;
}
}
}
# endif
# if HAVE_SSL_CTX_set_max_send_fragment || defined(SSL_CTX_set_max_send_fragment)
{
/* limit the maximum size of sent packets */
const int maxsendfrag_min = 512 ; /* per OpenSSL documentation */
int opt_maxsendfrag = SSL3_RT_MAX_PLAIN_LENGTH ;
retropt_int ( opts , OPT_OPENSSL_MAXSENDFRAG , & opt_maxsendfrag ) ;
if ( opt_maxsendfrag < maxsendfrag_min | | opt_maxsendfrag > SSL3_RT_MAX_PLAIN_LENGTH ) {
Error2 ( " openssl: maxsendfrag %d out of range 512 - %d " , maxsendfrag_min ,
SSL3_RT_MAX_PLAIN_LENGTH ) ;
return STAT_NORETRY ;
}
sycSSL_CTX_set_max_send_fragment ( ctx , opt_maxsendfrag ) ;
}
# endif
2008-01-27 12:00:08 +00:00
return STAT_OK ;
}
/* analyses an OpenSSL error condition, prints the appropriate messages with
severity ' level ' and returns one of STAT_OK , STAT_RETRYLATER , or
STAT_NORETRY */
static int openssl_SSL_ERROR_SSL ( int level , const char * funcname ) {
unsigned long e ;
char buf [ 120 ] ; /* this value demanded by "man ERR_error_string" */
2015-01-12 22:34:47 +00:00
int stat = STAT_OK ;
while ( e = ERR_get_error ( ) ) {
Debug1 ( " ERR_get_error(): %lx " , e ) ;
2016-12-12 19:53:08 +00:00
if
(
# if defined(OPENSSL_IS_BORINGSSL)
0 /* BoringSSL's RNG always succeeds. */
2016-07-24 19:51:33 +00:00
# elif defined(HAVE_RAND_status)
ERR_GET_LIB ( e ) = = ERR_LIB_RAND & & RAND_status ( ) ! = 1
2016-12-12 19:53:08 +00:00
# else
e = = ( ( ERR_LIB_RAND < < 24 ) |
2016-12-05 11:05:02 +00:00
# if defined(RAND_F_RAND_BYTES)
( RAND_F_RAND_BYTES < < 12 ) |
# else
2015-01-12 22:34:47 +00:00
( RAND_F_SSLEAY_RAND_BYTES < < 12 ) |
2016-12-05 11:05:02 +00:00
# endif
2016-12-12 19:53:08 +00:00
( RAND_R_PRNG_NOT_SEEDED ) ) /*0x24064064*/
# endif
)
{
2015-01-12 22:34:47 +00:00
Error ( " too few entropy; use options \" egd \" or \" pseudo \" " ) ;
stat = STAT_NORETRY ;
} else {
Msg2 ( level , " %s(): %s " , funcname , ERR_error_string ( e , buf ) ) ;
stat = level = = E_ERROR ? STAT_NORETRY : STAT_RETRYLATER ;
}
2008-01-27 12:00:08 +00:00
}
2015-01-12 22:34:47 +00:00
return stat ;
2008-01-27 12:00:08 +00:00
}
static const char * openssl_verify_messages [ ] = {
/* 0 */ " ok " ,
/* 1 */ NULL ,
/* 2 */ " unable to get issuer certificate " ,
/* 3 */ " unable to get certificate CRL " ,
/* 4 */ " unable to decrypt certificate's signature " ,
/* 5 */ " unable to decrypt CRL's signature " ,
/* 6 */ " unable to decode issuer public key " ,
/* 7 */ " certificate signature failure " ,
/* 8 */ " CRL signature failure " ,
/* 9 */ " certificate is not yet valid " ,
/* 10 */ " certificate has expired " ,
/* 11 */ " CRL is not yet valid " ,
/* 12 */ " CRL has expired " ,
/* 13 */ " format error in certificate's notBefore field " ,
/* 14 */ " format error in certificate's notAfter field " ,
/* 15 */ " format error in CRL's lastUpdate field " ,
/* 16 */ " format error in CRL's nextUpdate field " ,
/* 17 */ " out of memory " ,
/* 18 */ " self signed certificate " ,
/* 19 */ " self signed certificate in certificate chain " ,
/* 20 */ " unable to get local issuer certificate " ,
/* 21 */ " unable to verify the first certificate " ,
/* 22 */ " certificate chain too long " ,
/* 23 */ " certificate revoked " ,
/* 24 */ " invalid CA certificate " ,
/* 25 */ " path length constraint exceeded " ,
/* 26 */ " unsupported certificate purpose " ,
/* 27 */ " certificate not trusted " ,
/* 28 */ " certificate rejected " ,
/* 29 */ " subject issuer mismatch " ,
/* 30 */ " authority and subject key identifier mismatch " ,
/* 31 */ " authority and issuer serial number mismatch " ,
/* 32 */ " key usage does not include certificate signing " ,
/* 33 */ NULL ,
/* 34 */ NULL ,
/* 35 */ NULL ,
/* 36 */ NULL ,
/* 37 */ NULL ,
/* 38 */ NULL ,
/* 39 */ NULL ,
/* 40 */ NULL ,
/* 41 */ NULL ,
/* 42 */ NULL ,
/* 43 */ NULL ,
/* 44 */ NULL ,
/* 45 */ NULL ,
/* 46 */ NULL ,
/* 47 */ NULL ,
/* 48 */ NULL ,
/* 49 */ NULL ,
/* 50 */ " application verification failure " ,
} ;
2015-01-12 22:34:47 +00:00
/* delete all environment variables whose name begins with SOCAT_OPENSSL_
resp . < progname > _OPENSSL_ */
static int openssl_delete_cert_info ( void ) {
# define XIO_ENVNAMELEN 256
const char * progname ;
char envprefix [ XIO_ENVNAMELEN ] ;
char envname [ XIO_ENVNAMELEN ] ;
size_t i , l ;
const char * * entry ;
progname = diag_get_string ( ' p ' ) ;
envprefix [ 0 ] = ' \0 ' ; strncat ( envprefix , progname , XIO_ENVNAMELEN - 1 ) ;
l = strlen ( envprefix ) ;
2022-04-08 08:54:00 +00:00
for ( i = 0 ; i < l ; + + i ) envprefix [ i ] = toupper ( ( unsigned char ) envprefix [ i ] ) ;
2015-01-12 22:34:47 +00:00
strncat ( envprefix + l , " _OPENSSL_ " , XIO_ENVNAMELEN - l - 1 ) ;
2015-01-18 16:43:13 +00:00
# if HAVE_VAR_ENVIRON
2015-01-12 22:34:47 +00:00
entry = ( const char * * ) environ ;
while ( * entry ! = NULL ) {
if ( ! strncmp ( * entry , envprefix , strlen ( envprefix ) ) ) {
const char * eq = strchr ( * entry , ' = ' ) ;
if ( eq = = NULL ) eq = * entry + strlen ( * entry ) ;
envname [ 0 ] = ' \0 ' ; strncat ( envname , * entry , eq - * entry ) ;
2020-11-24 19:22:45 +00:00
# if HAVE_UNSETENV
2015-01-12 22:34:47 +00:00
Unsetenv ( envname ) ;
2020-11-24 19:22:45 +00:00
# endif
2015-01-12 22:34:47 +00:00
} else {
+ + entry ;
2015-01-12 22:11:26 +00:00
}
2015-01-12 22:34:47 +00:00
}
2015-01-18 16:43:13 +00:00
# endif /* HAVE_VAR_ENVIRON */
2015-01-12 22:34:47 +00:00
return 0 ;
}
/* read in the "name" information (from field "issuer" or "subject") and
create environment variable with complete info , eg :
SOCAT_OPENSSL_X509_SUBJECT */
static int openssl_setenv_cert_name ( const char * field , X509_NAME * name ) {
BIO * bio = BIO_new ( BIO_s_mem ( ) ) ;
char * buf = NULL , * str ;
size_t len ;
X509_NAME_print_ex ( bio , name , 0 , XN_FLAG_ONELINE & ~ ASN1_STRFLGS_ESC_MSB ) ; /* rc not documented */
len = BIO_get_mem_data ( bio , & buf ) ;
if ( ( str = Malloc ( len + 1 ) ) = = NULL ) {
2015-01-12 22:11:26 +00:00
BIO_free ( bio ) ;
2015-01-12 22:34:47 +00:00
return - 1 ;
2015-01-12 22:11:26 +00:00
}
2015-01-24 17:40:03 +00:00
memcpy ( str , buf , len ) ;
2015-01-12 22:34:47 +00:00
str [ len ] = ' \0 ' ;
2021-11-27 14:04:08 +00:00
Info2 ( " SSL peer cert %s: \" %s \" " , field , str ) ;
2015-01-24 17:40:03 +00:00
xiosetenv2 ( " OPENSSL_X509 " , field , str , 1 , NULL ) ;
2015-01-12 22:34:47 +00:00
free ( str ) ;
BIO_free ( bio ) ;
return 0 ;
}
/* read in the "name" information (from field "issuer" or "subject") and
create environment variables with the fields , eg :
SOCAT_OPENSSL_X509_COMMONNAME
*/
static int openssl_setenv_cert_fields ( const char * field , X509_NAME * name ) {
int n , i ;
2015-01-12 22:11:26 +00:00
n = X509_NAME_entry_count ( name ) ;
2015-01-12 22:34:47 +00:00
/* extract fields of cert name */
2015-01-12 22:11:26 +00:00
for ( i = 0 ; i < n ; + + i ) {
X509_NAME_ENTRY * entry ;
ASN1_OBJECT * obj ;
2015-01-12 22:34:47 +00:00
ASN1_STRING * data ;
2016-12-05 11:05:02 +00:00
const unsigned char * text ;
2015-01-12 22:11:26 +00:00
int nid ;
entry = X509_NAME_get_entry ( name , i ) ;
obj = X509_NAME_ENTRY_get_object ( entry ) ;
2015-01-12 22:34:47 +00:00
data = X509_NAME_ENTRY_get_data ( entry ) ;
2015-01-12 22:11:26 +00:00
nid = OBJ_obj2nid ( obj ) ;
2016-12-05 11:05:02 +00:00
# if HAVE_ASN1_STRING_get0_data
text = ASN1_STRING_get0_data ( data ) ;
# else
2015-01-12 22:34:47 +00:00
text = ASN1_STRING_data ( data ) ;
2016-12-05 11:05:02 +00:00
# endif
2015-01-12 22:34:47 +00:00
Debug3 ( " SSL peer cert %s entry: %s= \" %s \" " , ( field [ 0 ] ? field : " subject " ) , OBJ_nid2ln ( nid ) , text ) ;
if ( field ! = NULL & & field [ 0 ] ! = ' \0 ' ) {
xiosetenv3 ( " OPENSSL_X509 " , field , OBJ_nid2ln ( nid ) , ( const char * ) text , 2 , " // " ) ;
} else {
xiosetenv2 ( " OPENSSL_X509 " , OBJ_nid2ln ( nid ) , ( const char * ) text , 2 , " // " ) ;
}
2015-01-12 22:11:26 +00:00
}
return 0 ;
}
2015-01-12 22:34:47 +00:00
/* compares the peername used/provided by the client to cn as extracted from
the peer certificate .
supports wildcard cn like * . domain which matches domain and
host . domain
returns true on match */
2020-12-31 11:06:32 +00:00
static bool openssl_check_name ( const char * nametype , const char * cn , const char * peername ) {
2015-01-12 22:34:47 +00:00
const char * dotp ;
if ( peername = = NULL ) {
2020-12-31 11:06:32 +00:00
Info2 ( " %s \" %s \" : no peername " , nametype , cn ) ;
2015-01-12 22:34:47 +00:00
return false ;
} else if ( peername [ 0 ] = = ' \0 ' ) {
2020-12-31 11:06:32 +00:00
Info2 ( " %s \" %s \" : matched by empty peername " , nametype , cn ) ;
2015-01-12 22:34:47 +00:00
return true ;
}
if ( ! ( cn [ 0 ] = = ' * ' & & cn [ 1 ] = = ' . ' ) ) {
/* normal server name - this is simple */
if ( strcmp ( cn , peername ) = = 0 ) {
2020-12-31 11:06:32 +00:00
Debug3 ( " %s \" %s \" matches peername \" %s \" " , nametype , cn , peername ) ;
2015-01-12 22:34:47 +00:00
return true ;
} else {
2020-12-31 11:06:32 +00:00
Info3 ( " %s \" %s \" does not match peername \" %s \" " , nametype , cn , peername ) ;
2015-01-12 22:34:47 +00:00
return false ;
}
}
/* wildcard cert */
2020-12-31 11:06:32 +00:00
Debug2 ( " %s \" %s \" is a wildcard name " , nametype , cn ) ;
2015-01-12 22:34:47 +00:00
/* case: just the base domain */
if ( strcmp ( cn + 2 , peername ) = = 0 ) {
2020-12-31 11:06:32 +00:00
Debug3 ( " wildcard %s \" %s \" matches base domain \" %s \" " , nametype , cn , peername ) ;
2015-01-12 22:34:47 +00:00
return true ;
}
/* case: subdomain; only one level! */
dotp = strchr ( peername , ' . ' ) ;
if ( dotp = = NULL ) {
Info2 ( " peername \" %s \" is not a subdomain, thus is not matched by wildcard commonName \" %s \" " ,
peername , cn ) ;
return false ;
}
if ( strcmp ( cn + 1 , dotp ) ! = 0 ) {
2020-12-31 11:06:32 +00:00
Info3 ( " %s \" %s \" does not match subdomain peername \" %s \" " , nametype , cn , peername ) ;
2015-01-12 22:34:47 +00:00
return false ;
}
2020-12-31 11:06:32 +00:00
Debug3 ( " %s \" %s \" matches subdomain peername \" %s \" " , nametype , cn , peername ) ;
2015-01-12 22:34:47 +00:00
return true ;
}
/* retrieves the commonName field and compares it to the peername
returns true on match , false otherwise */
static bool openssl_check_peername ( X509_NAME * name , const char * peername ) {
int ind = - 1 ;
X509_NAME_ENTRY * entry ;
ASN1_STRING * data ;
2016-12-05 11:05:02 +00:00
const unsigned char * text ;
2015-01-12 22:34:47 +00:00
ind = X509_NAME_get_index_by_NID ( name , NID_commonName , - 1 ) ;
if ( ind < 0 ) {
2023-06-12 21:01:54 +00:00
Info ( " no COMMONNAME field in peer certificate " ) ;
2015-01-12 22:34:47 +00:00
return false ;
}
entry = X509_NAME_get_entry ( name , ind ) ;
data = X509_NAME_ENTRY_get_data ( entry ) ;
2016-12-05 11:05:02 +00:00
# if HAVE_ASN1_STRING_get0_data
text = ASN1_STRING_get0_data ( data ) ;
# else
2015-01-12 22:34:47 +00:00
text = ASN1_STRING_data ( data ) ;
2016-12-05 11:05:02 +00:00
# endif
2020-12-31 11:06:32 +00:00
return openssl_check_name ( " commonName " , ( const char * ) text , peername ) ;
2015-01-12 22:34:47 +00:00
}
/* retrieves certificate provided by peer, sets env vars containing
certificates field values , and checks peername if provided by
calling function */
/* parts of this code were copied from Gene Spaffords C/C++ Secure Programming at Etutorials.org:
http : //etutorials.org/Programming/secure+programming/Chapter+10.+Public+Key+Infrastructure/10.8+Adding+Hostname+Checking+to+Certificate+Verification/
The code examples in this tutorial do not seem to have explicit license restrictions .
*/
2020-12-31 11:06:32 +00:00
/* peername is, with OpenSSL client, the server name, or the value of option
commonname if provided ;
With OpenSSL server , it is the value of option commonname */
2023-07-13 07:06:35 +00:00
static int openssl_handle_peer_certificate ( struct single * sfd ,
2015-01-12 22:34:47 +00:00
const char * peername ,
2008-01-27 12:00:08 +00:00
bool opt_ver , int level ) {
X509 * peer_cert ;
2015-01-12 22:34:47 +00:00
X509_NAME * subjectname , * issuername ;
2015-01-12 22:11:26 +00:00
/*ASN1_TIME not_before, not_after;*/
2015-01-12 22:34:47 +00:00
int extcount , i , ok = 0 ;
2008-01-27 12:00:08 +00:00
int status ;
2023-07-13 07:06:35 +00:00
if ( ( peer_cert = SSL_get_peer_certificate ( sfd - > para . openssl . ssl ) ) = = NULL ) {
2008-01-27 12:00:08 +00:00
if ( opt_ver ) {
Msg ( level , " no peer certificate " ) ;
status = STAT_RETRYLATER ;
} else {
Notice ( " no peer certificate and no check " ) ;
status = STAT_OK ;
}
2015-01-12 22:34:47 +00:00
return status ;
}
/* verify peer certificate (trust, signature, validity dates) */
if ( opt_ver ) {
long verify_result ;
2023-07-13 07:06:35 +00:00
if ( ( verify_result = sycSSL_get_verify_result ( sfd - > para . openssl . ssl ) ) ! = X509_V_OK ) {
2015-01-12 22:34:47 +00:00
const char * message = NULL ;
if ( verify_result > = 0 & &
( size_t ) verify_result <
sizeof ( openssl_verify_messages ) / sizeof ( char * ) ) {
message = openssl_verify_messages [ verify_result ] ;
}
if ( message ) {
Msg1 ( level , " %s " , message ) ;
} else {
Msg1 ( level , " rejected peer certificate with error %ld " , verify_result ) ;
}
status = STAT_RETRYLATER ;
X509_free ( peer_cert ) ;
return STAT_RETRYLATER ;
}
Info ( " peer certificate is trusted " ) ;
}
/* set env vars from cert's subject and issuer values */
if ( ( subjectname = X509_get_subject_name ( peer_cert ) ) ! = NULL ) {
openssl_setenv_cert_name ( " subject " , subjectname ) ;
openssl_setenv_cert_fields ( " " , subjectname ) ;
/*! I'd like to provide dates too; see
http : //markmail.org/message/yi4vspp7aeu3xwtu#query:+page:1+mid:jhnl4wklif3pgzqf+state:results */
}
if ( ( issuername = X509_get_issuer_name ( peer_cert ) ) ! = NULL ) {
openssl_setenv_cert_name ( " issuer " , issuername ) ;
}
2020-12-31 11:06:32 +00:00
if ( ! opt_ver ) {
Notice ( " option openssl-verify disabled, no check of certificate " ) ;
X509_free ( peer_cert ) ;
return STAT_OK ;
}
2015-01-12 22:34:47 +00:00
/* check peername against cert's subjectAltName DNS entries */
/* this code is based on example from Gerhard Gappmeier in
http : //openssl.6102.n7.nabble.com/How-to-extract-subjectAltName-td17236.html
2020-12-31 11:06:32 +00:00
and the GEN_IPADD from
http : //openssl.6102.n7.nabble.com/reading-IP-addresses-from-Subject-Alternate-Name-extension-td29245.html
2015-01-12 22:34:47 +00:00
*/
if ( ( extcount = X509_get_ext_count ( peer_cert ) ) > 0 ) {
for ( i = 0 ; ! ok & & i < extcount ; + + i ) {
const char * extstr ;
X509_EXTENSION * ext ;
const X509V3_EXT_METHOD * meth ;
ext = X509_get_ext ( peer_cert , i ) ;
extstr = OBJ_nid2sn ( OBJ_obj2nid ( X509_EXTENSION_get_object ( ext ) ) ) ;
if ( ! strcasecmp ( extstr , " subjectAltName " ) ) {
void * names ;
2023-06-12 21:01:54 +00:00
if ( ! ( meth = X509V3_EXT_get ( ext ) ) ) break ;
2015-01-12 22:34:47 +00:00
names = X509_get_ext_d2i ( peer_cert , NID_subject_alt_name , NULL , NULL ) ;
if ( names ) {
int numalts ;
int i ;
/* get amount of alternatives, RFC2459 claims there MUST be at least one, but we don't depend on it... */
numalts = sk_GENERAL_NAME_num ( names ) ;
/* loop through all alternatives */
2020-12-31 11:06:32 +00:00
for ( i = 0 ; i < numalts ; + + i ) {
2015-01-12 22:34:47 +00:00
/* get a handle to alternative name number i */
2020-12-31 11:06:32 +00:00
const GENERAL_NAME * pName = sk_GENERAL_NAME_value ( names , i ) ;
2015-01-12 22:34:47 +00:00
unsigned char * pBuffer ;
2020-12-31 11:06:32 +00:00
switch ( pName - > type ) {
2015-01-12 22:34:47 +00:00
case GEN_DNS :
2020-12-31 11:06:32 +00:00
ASN1_STRING_to_UTF8 ( & pBuffer , pName - > d . ia5 ) ;
2015-01-12 22:34:47 +00:00
xiosetenv ( " OPENSSL_X509V3_SUBJECTALTNAME_DNS " , ( char * ) pBuffer , 2 , " // " ) ;
if ( peername ! = NULL & &
2020-12-31 11:06:32 +00:00
openssl_check_name ( " subjectAltName " , ( char * ) pBuffer , /*const char*/ peername ) ) {
2015-01-12 22:34:47 +00:00
ok = 1 ;
}
OPENSSL_free ( pBuffer ) ;
break ;
2020-12-31 11:06:32 +00:00
case GEN_IPADD :
{
/* binary address format */
const unsigned char * data = pName - > d . iPAddress - > data ;
size_t len = pName - > d . iPAddress - > length ;
char aBuffer [ INET6_ADDRSTRLEN ] ; /* canonical peername */
struct in6_addr ip6bin ;
switch ( len ) {
case 4 : /* IPv4 */
snprintf ( aBuffer , sizeof ( aBuffer ) , " %u.%u.%u.%u " , data [ 0 ] , data [ 1 ] , data [ 2 ] , data [ 3 ] ) ;
if ( peername ! = NULL & &
openssl_check_name ( " subjectAltName " , aBuffer , /*const char*/ peername ) ) {
ok = 1 ;
}
break ;
2021-01-03 15:56:50 +00:00
# if WITH_IP6
2020-12-31 11:06:32 +00:00
case 16 : /* IPv6 */
inet_ntop ( AF_INET6 , data , aBuffer , sizeof ( aBuffer ) ) ;
2021-10-26 17:26:18 +00:00
if ( peername ! = NULL ) {
2023-07-13 07:06:35 +00:00
xioip6_pton ( peername , & ip6bin , sfd - > para . socket . ip . ai_flags ) ;
2021-10-26 17:26:18 +00:00
if ( memcmp ( data , & ip6bin , sizeof ( ip6bin ) ) = = 0 ) {
Debug2 ( " subjectAltName \" %s \" matches peername \" %s \" " ,
aBuffer , peername ) ;
ok = 1 ;
} else {
Info2 ( " subjectAltName \" %s \" does not match peername \" %s \" " ,
aBuffer , peername ) ;
}
}
2020-12-31 11:06:32 +00:00
break ;
2021-01-03 15:56:50 +00:00
# endif
2020-12-31 11:06:32 +00:00
}
xiosetenv ( " OPENSSL_X509V3_SUBJECTALTNAME_IPADD " , ( char * ) aBuffer , 2 , " // " ) ;
}
break ;
default : Warn3 ( " Unknown subject type %d (GEN_DNS=%d, GEN_IPADD=%d " ,
pName - > type , GEN_DNS , GEN_IPADD ) ;
continue ;
2015-01-12 22:34:47 +00:00
}
2020-12-31 11:06:32 +00:00
if ( ok ) { break ; }
2015-01-12 22:34:47 +00:00
}
}
}
}
2008-01-27 12:00:08 +00:00
}
2020-12-31 11:06:32 +00:00
if ( ok ) {
Notice ( " trusting certificate, commonName matches " ) ;
2015-01-12 22:34:47 +00:00
X509_free ( peer_cert ) ;
return STAT_OK ;
}
2020-12-31 11:06:32 +00:00
2015-01-12 22:34:47 +00:00
if ( peername = = NULL | | peername [ 0 ] = = ' \0 ' ) {
Notice ( " trusting certificate, no check of commonName " ) ;
X509_free ( peer_cert ) ;
return STAT_OK ;
}
/* here: all envs set; opt_ver, cert verified, no subjAltName match -> check subject CN */
if ( ! openssl_check_peername ( /*X509_NAME*/ subjectname , /*const char*/ peername ) ) {
2020-12-31 11:06:32 +00:00
Error1 ( " certificate is valid but its commonName does not match hostname \" %s \" " ,
peername ) ;
2015-01-12 22:34:47 +00:00
status = STAT_NORETRY ;
} else {
Notice ( " trusting certificate, commonName matches " ) ;
status = STAT_OK ;
}
2008-01-27 12:00:08 +00:00
X509_free ( peer_cert ) ;
return status ;
}
2023-07-13 07:06:35 +00:00
static int xioSSL_set_fd ( struct single * sfd , int level ) {
2008-01-27 12:00:08 +00:00
unsigned long err ;
/* assign a network connection to the SSL object */
2023-07-13 07:06:35 +00:00
if ( sycSSL_set_fd ( sfd - > para . openssl . ssl , sfd - > fd ) < = 0 ) {
2008-01-27 12:00:08 +00:00
Msg ( level , " SSL_set_fd() failed " ) ;
while ( err = ERR_get_error ( ) ) {
Msg2 ( level , " SSL_set_fd(, %d): %s " ,
2023-07-13 07:06:35 +00:00
sfd - > fd , ERR_error_string ( err , NULL ) ) ;
2008-01-27 12:00:08 +00:00
}
return STAT_RETRYLATER ;
}
return STAT_OK ;
}
/* ...
in case of an error condition , this function check forever and retry
options and ev . sleeps an interval . It returns NORETRY when the caller
should not retry for any reason . */
2023-07-13 07:06:35 +00:00
static int xioSSL_connect ( struct single * sfd , const char * opt_commonname ,
2015-01-12 22:34:47 +00:00
bool opt_ver , int level ) {
2008-01-27 12:00:08 +00:00
char error_string [ 120 ] ;
int errint , status , ret ;
unsigned long err ;
/* connect via SSL by performing handshake */
2023-07-13 07:06:35 +00:00
if ( ( ret = sycSSL_connect ( sfd - > para . openssl . ssl ) ) < = 0 ) {
2008-01-27 12:00:08 +00:00
/*if (ERR_peek_error() == 0) Msg(level, "SSL_connect() failed");*/
2023-07-13 07:06:35 +00:00
errint = SSL_get_error ( sfd - > para . openssl . ssl , ret ) ;
2008-01-27 12:00:08 +00:00
switch ( errint ) {
case SSL_ERROR_NONE :
/* this is not an error, but I dare not continue for security reasons*/
Msg ( level , " ok " ) ;
status = STAT_RETRYLATER ;
case SSL_ERROR_ZERO_RETURN :
Msg ( level , " connection closed (wrong version number?) " ) ;
status = STAT_RETRYLATER ;
break ;
case SSL_ERROR_WANT_READ :
case SSL_ERROR_WANT_WRITE :
case SSL_ERROR_WANT_CONNECT :
case SSL_ERROR_WANT_X509_LOOKUP :
Msg ( level , " nonblocking operation did not complete " ) ;
status = STAT_RETRYLATER ;
break ; /*!*/
case SSL_ERROR_SYSCALL :
if ( ERR_peek_error ( ) = = 0 ) {
if ( ret = = 0 ) {
Msg ( level , " SSL_connect(): socket closed by peer " ) ;
} else if ( ret = = - 1 ) {
Msg1 ( level , " SSL_connect(): %s " , strerror ( errno ) ) ;
}
} else {
Msg ( level , " I/O error " ) ; /*!*/
while ( err = ERR_get_error ( ) ) {
ERR_error_string_n ( err , error_string , sizeof ( error_string ) ) ;
Msg4 ( level , " SSL_connect(): %s / %s / %s / %s " , error_string ,
ERR_lib_error_string ( err ) , ERR_func_error_string ( err ) ,
ERR_reason_error_string ( err ) ) ;
}
}
status = STAT_RETRYLATER ;
break ;
case SSL_ERROR_SSL :
status = openssl_SSL_ERROR_SSL ( level , " SSL_connect " ) ;
2023-07-13 07:06:35 +00:00
if ( openssl_handle_peer_certificate ( sfd , opt_commonname , opt_ver , level /*!*/ ) < 0 ) {
2008-01-27 12:00:08 +00:00
return STAT_RETRYLATER ;
}
break ;
default :
Msg ( level , " unknown error " ) ;
status = STAT_RETRYLATER ;
break ;
}
return status ;
}
return STAT_OK ;
}
/* on result < 0: errno is set (at least to EIO) */
ssize_t xioread_openssl ( struct single * pipe , void * buff , size_t bufsiz ) {
unsigned long err ;
char error_string [ 120 ] ;
int _errno = EIO ; /* if we have no better idea about nature of error */
int errint , ret ;
ret = sycSSL_read ( pipe - > para . openssl . ssl , buff , bufsiz ) ;
if ( ret < 0 ) {
errint = SSL_get_error ( pipe - > para . openssl . ssl , ret ) ;
switch ( errint ) {
case SSL_ERROR_NONE :
/* this is not an error, but I dare not continue for security reasons*/
Error ( " ok " ) ;
2015-01-12 22:11:26 +00:00
break ;
2008-01-27 12:00:08 +00:00
case SSL_ERROR_ZERO_RETURN :
Error ( " connection closed by peer " ) ;
break ;
case SSL_ERROR_WANT_READ :
case SSL_ERROR_WANT_WRITE :
case SSL_ERROR_WANT_CONNECT :
case SSL_ERROR_WANT_X509_LOOKUP :
2010-01-09 12:35:24 +00:00
Info ( " nonblocking operation did not complete " ) ;
errno = EAGAIN ;
return - 1 ;
2008-01-27 12:00:08 +00:00
case SSL_ERROR_SYSCALL :
if ( ERR_peek_error ( ) = = 0 ) {
if ( ret = = 0 ) {
Error ( " SSL_read(): socket closed by peer " ) ;
} else if ( ret = = - 1 ) {
_errno = errno ;
Error1 ( " SSL_read(): %s " , strerror ( errno ) ) ;
}
} else {
Error ( " I/O error " ) ; /*!*/
while ( err = ERR_get_error ( ) ) {
ERR_error_string_n ( err , error_string , sizeof ( error_string ) ) ;
Error4 ( " SSL_read(): %s / %s / %s / %s " , error_string ,
ERR_lib_error_string ( err ) , ERR_func_error_string ( err ) ,
ERR_reason_error_string ( err ) ) ;
}
}
break ;
case SSL_ERROR_SSL :
2020-10-13 20:11:05 +00:00
openssl_SSL_ERROR_SSL ( E_ERROR , " SSL_read " ) ;
2008-01-27 12:00:08 +00:00
break ;
default :
Error ( " unknown error " ) ;
break ;
}
errno = _errno ;
return - 1 ;
}
return ret ;
}
ssize_t xiopending_openssl ( struct single * pipe ) {
int bytes = sycSSL_pending ( pipe - > para . openssl . ssl ) ;
return bytes ;
}
/* on result < 0: errno is set (at least to EIO) */
ssize_t xiowrite_openssl ( struct single * pipe , const void * buff , size_t bufsiz ) {
unsigned long err ;
char error_string [ 120 ] ;
int _errno = EIO ; /* if we have no better idea about nature of error */
int errint , ret ;
ret = sycSSL_write ( pipe - > para . openssl . ssl , buff , bufsiz ) ;
if ( ret < 0 ) {
errint = SSL_get_error ( pipe - > para . openssl . ssl , ret ) ;
switch ( errint ) {
case SSL_ERROR_NONE :
/* this is not an error, but I dare not continue for security reasons*/
Error ( " ok " ) ;
case SSL_ERROR_ZERO_RETURN :
Error ( " connection closed by peer " ) ;
break ;
case SSL_ERROR_WANT_READ :
case SSL_ERROR_WANT_WRITE :
case SSL_ERROR_WANT_CONNECT :
case SSL_ERROR_WANT_X509_LOOKUP :
Error ( " nonblocking operation did not complete " ) ;
break ; /*!*/
case SSL_ERROR_SYSCALL :
if ( ERR_peek_error ( ) = = 0 ) {
if ( ret = = 0 ) {
Error ( " SSL_write(): socket closed by peer " ) ;
} else if ( ret = = - 1 ) {
_errno = errno ;
Error1 ( " SSL_write(): %s " , strerror ( errno ) ) ;
}
} else {
Error ( " I/O error " ) ; /*!*/
while ( err = ERR_get_error ( ) ) {
ERR_error_string_n ( err , error_string , sizeof ( error_string ) ) ;
Error4 ( " SSL_write(): %s / %s / %s / %s " , error_string ,
ERR_lib_error_string ( err ) , ERR_func_error_string ( err ) ,
ERR_reason_error_string ( err ) ) ;
}
}
break ;
case SSL_ERROR_SSL :
2020-10-13 20:11:05 +00:00
openssl_SSL_ERROR_SSL ( E_ERROR , " SSL_write " ) ;
2008-01-27 12:00:08 +00:00
break ;
default :
Error ( " unknown error " ) ;
break ;
}
errno = _errno ;
return - 1 ;
}
return ret ;
}
2021-01-10 12:32:27 +00:00
int xioshutdown_openssl ( struct single * sfd , int how )
{
int rc ;
if ( ( rc = sycSSL_shutdown ( sfd - > para . openssl . ssl ) ) < 0 ) {
Warn1 ( " xioshutdown_openssl(): SSL_shutdown() -> %d " , rc ) ;
}
if ( sfd - > tag = = XIO_TAG_WRONLY ) {
char buff [ 1 ] ;
/* give peer time to read all data before closing socket */
xioread_openssl ( sfd , buff , 1 ) ;
}
return 0 ;
}
2008-01-27 12:00:08 +00:00
# endif /* WITH_OPENSSL */