mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 23:42:34 +00:00
Check OpenSSL peers commonName+subjectAltName; new option openssl-commonname
This commit is contained in:
parent
241e5256ec
commit
cd164e7b58
13 changed files with 514 additions and 170 deletions
11
CHANGES
11
CHANGES
|
@ -18,6 +18,17 @@ security:
|
||||||
Turn off nested signal handler invocations
|
Turn off nested signal handler invocations
|
||||||
Thanks to Peter Lobsinger for reporting and explaining this issue.
|
Thanks to Peter Lobsinger for reporting and explaining this issue.
|
||||||
|
|
||||||
|
Red Hat issue 1019975: add TLS host name checks
|
||||||
|
OpenSSL client checks if the server certificates names in
|
||||||
|
extensions/subjectAltName/DNS or in subject/commonName match the name
|
||||||
|
used to connect or the value of the openssl-commonname option.
|
||||||
|
Test: OPENSSL_CN_CLIENT_SECURITY
|
||||||
|
|
||||||
|
OpenSSL server checks if the client certificates names in
|
||||||
|
extensions/subjectAltNames/DNS or subject/commonName match the value of
|
||||||
|
the openssl-commonname option when it is used.
|
||||||
|
Test: OPENSSL_CN_SERVER_SECURITY
|
||||||
|
|
||||||
corrections:
|
corrections:
|
||||||
LISTEN based addresses applied some address options, e.g. so-keepalive,
|
LISTEN based addresses applied some address options, e.g. so-keepalive,
|
||||||
to the listening file descriptor instead of the connected file
|
to the listening file descriptor instead of the connected file
|
||||||
|
|
34
doc/socat.yo
34
doc/socat.yo
|
@ -542,14 +542,23 @@ label(ADDRESS_OPENSSL_CONNECT)dit(bf(tt(OPENSSL:<host>:<port>)))
|
||||||
<host> [link(IP address)(TYPE_IP_ADDRESS)] using TCP/IP version 4 or 6
|
<host> [link(IP address)(TYPE_IP_ADDRESS)] using TCP/IP version 4 or 6
|
||||||
depending on address specification, name resolution, or option
|
depending on address specification, name resolution, or option
|
||||||
link(pf)(OPTION_PROTOCOL_FAMILY).nl()
|
link(pf)(OPTION_PROTOCOL_FAMILY).nl()
|
||||||
NOTE: The server certificate is only checked for validity against
|
NOTE: Up to version 1.7.2.4 and 2.0.0-b7
|
||||||
link(cafile)(OPTION_OPENSSL_CAFILE) or link(capath)(OPTION_OPENSSL_CAPATH),
|
the server certificate was only checked for validity against the system
|
||||||
but not for match with the server's name or its IP address!nl()
|
certificate store or link(cafile)(OPTION_OPENSSL_CAFILE) or
|
||||||
|
link(capath)(OPTION_OPENSSL_CAPATH),
|
||||||
|
but not for match with the server's name or its IP address.
|
||||||
|
Since version 1.7.3.0 and 2.0.0-b8 socat checks the peer certificate for match with the
|
||||||
|
<host> parameter or the value of the
|
||||||
|
link(openssl-commonname)(OPTION_OPENSSL_COMMONNAME) option.
|
||||||
|
Socat tries to match it against the certificates subject commonName,
|
||||||
|
and the certifications extension subjectAltName DNS names. Wildcards in the
|
||||||
|
certificate are supported.nl()
|
||||||
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(OPENSSL)(GROUP_OPENSSL),link(RETRY)(GROUP_RETRY) nl()
|
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(OPENSSL)(GROUP_OPENSSL),link(RETRY)(GROUP_RETRY) nl()
|
||||||
Useful options:
|
Useful options:
|
||||||
link(cipher)(OPTION_OPENSSL_CIPHERLIST),
|
link(cipher)(OPTION_OPENSSL_CIPHERLIST),
|
||||||
link(method)(OPTION_OPENSSL_METHOD),
|
link(method)(OPTION_OPENSSL_METHOD),
|
||||||
link(verify)(OPTION_OPENSSL_VERIFY),
|
link(verify)(OPTION_OPENSSL_VERIFY),
|
||||||
|
link(commonname)(OPTION_OPENSSL_COMMONNAME)
|
||||||
link(cafile)(OPTION_OPENSSL_CAFILE),
|
link(cafile)(OPTION_OPENSSL_CAFILE),
|
||||||
link(capath)(OPTION_OPENSSL_CAPATH),
|
link(capath)(OPTION_OPENSSL_CAPATH),
|
||||||
link(certificate)(OPTION_OPENSSL_CERTIFICATE),
|
link(certificate)(OPTION_OPENSSL_CERTIFICATE),
|
||||||
|
@ -577,6 +586,7 @@ label(ADDRESS_OPENSSL_LISTEN)dit(bf(tt(OPENSSL-LISTEN:<port>)))
|
||||||
link(cipher)(OPTION_OPENSSL_CIPHERLIST),
|
link(cipher)(OPTION_OPENSSL_CIPHERLIST),
|
||||||
link(method)(OPTION_OPENSSL_METHOD),
|
link(method)(OPTION_OPENSSL_METHOD),
|
||||||
link(verify)(OPTION_OPENSSL_VERIFY),
|
link(verify)(OPTION_OPENSSL_VERIFY),
|
||||||
|
link(commonname)(OPTION_OPENSSL_COMMONNAME)
|
||||||
link(cafile)(OPTION_OPENSSL_CAFILE),
|
link(cafile)(OPTION_OPENSSL_CAFILE),
|
||||||
link(capath)(OPTION_OPENSSL_CAPATH),
|
link(capath)(OPTION_OPENSSL_CAPATH),
|
||||||
link(certificate)(OPTION_OPENSSL_CERTIFICATE),
|
link(certificate)(OPTION_OPENSSL_CERTIFICATE),
|
||||||
|
@ -2750,6 +2760,14 @@ label(OPTION_OPENSSL_COMPRESS)dit(bf(tt(compress)))
|
||||||
compression-related settings.
|
compression-related settings.
|
||||||
NOTE: Requires OpenSSL 0.9.8 or higher and disabling compression with
|
NOTE: Requires OpenSSL 0.9.8 or higher and disabling compression with
|
||||||
OpenSSL 0.9.8 affects all new connections in the process.
|
OpenSSL 0.9.8 affects all new connections in the process.
|
||||||
|
label(OPTION_OPENSSL_COMMONNAME)dit(bf(tt(commonname=<string>)))
|
||||||
|
Specify the commonname that the peer certificate must match. With
|
||||||
|
link(OPENSSL-CONNECT)(ADDRESS_OPENSSL_CONNECT) address this overrides the
|
||||||
|
given hostname or IP target address; with
|
||||||
|
link(OPENSSL-LISTEN)(ADDRESS_OPENSSL_LISTEN) this turns on check of peer
|
||||||
|
certificates commonname. This option has only meaning when option
|
||||||
|
link(verify)(OPTION_OPENSSL_VERIFY) is not disabled and the choosen cipher
|
||||||
|
provides a peer certificate.
|
||||||
enddit()
|
enddit()
|
||||||
|
|
||||||
startdit()enddit()nl()
|
startdit()enddit()nl()
|
||||||
|
@ -3534,6 +3552,16 @@ dit(bf(SOCAT_IPV6_TCLASS) (output)) With all IPv6 based RECVFROM addresses
|
||||||
where address option link(ipv6-recvtclass)(OPTION_IPV6_RECVTCLASS) is applied,
|
where address option link(ipv6-recvtclass)(OPTION_IPV6_RECVTCLASS) is applied,
|
||||||
socat() sets this variable to the transfer class of the received packet.
|
socat() sets this variable to the transfer class of the received packet.
|
||||||
|
|
||||||
|
dit(bf(SOCAT_OPENSSL_X509_ISSUER) (output)) Issuer field from peer certificate
|
||||||
|
|
||||||
|
dit(bf(SOCAT_OPENSSL_X509_SUBJECT (output))) Subject field from peer certificate
|
||||||
|
|
||||||
|
dit(bf(SOCAT_OPENSSL_X509_COMMONNAME) (output)) commonName entries from peer certificates subject. Multiple values are separated by " // ".
|
||||||
|
|
||||||
|
dit(bf(SOCAT_OPENSSL_X509_*) (output)) all other entries from peer certificates subject
|
||||||
|
|
||||||
|
dit(bf(SOCAT_OPENSSL_X509V3_DNS) (output)) DNS entries from peer certificates extensions - subjectAltName field. Multiple values are separated by " // ".
|
||||||
|
|
||||||
dit(bf(HOSTNAME) (input)) Is used to determine the hostname for logging (see
|
dit(bf(HOSTNAME) (input)) Is used to determine the hostname for logging (see
|
||||||
link(-lh)(option_lh)).
|
link(-lh)(option_lh)).
|
||||||
|
|
||||||
|
|
2
socat.c
2
socat.c
|
@ -275,7 +275,7 @@ int main(int argc, const char *argv[]) {
|
||||||
Info(copyright_ssleay);
|
Info(copyright_ssleay);
|
||||||
#endif
|
#endif
|
||||||
Debug2("socat version %s on %s", socatversion, timestamp);
|
Debug2("socat version %s on %s", socatversion, timestamp);
|
||||||
xiosetenv("VERSION", socatversion, 1); /* SOCAT_VERSION */
|
xiosetenv("VERSION", socatversion, 1, NULL); /* SOCAT_VERSION */
|
||||||
uname(&ubuf); /* ! here we circumvent internal tracing (Uname) */
|
uname(&ubuf); /* ! here we circumvent internal tracing (Uname) */
|
||||||
Debug4("running on %s version %s, release %s, machine %s\n",
|
Debug4("running on %s version %s, release %s, machine %s\n",
|
||||||
ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);
|
ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);
|
||||||
|
|
86
sysutils.c
86
sysutils.c
|
@ -666,24 +666,19 @@ int ifindex(const char *ifname, unsigned int *ifindex, int anysock) {
|
||||||
#endif /* WITH_IP4 || WITH_IP6 || WITH_INTERFACE */
|
#endif /* WITH_IP4 || WITH_IP6 || WITH_INTERFACE */
|
||||||
|
|
||||||
|
|
||||||
/* constructs an environment variable whose name is built from socats uppercase
|
int _xiosetenv(const char *envname, const char *value, int overwrite, const char *sep) {
|
||||||
program name, and underscore and varname; if a variable of this name already
|
char *oldval;
|
||||||
exists a non zero value of overwrite lets the old value be overwritten.
|
char *newval;
|
||||||
returns 0 on success or <0 if an error occurred. */
|
if (overwrite >= 2 && (oldval = getenv(envname)) != NULL) {
|
||||||
int xiosetenv(const char *varname, const char *value, int overwrite) {
|
size_t newlen = strlen(oldval)+strlen(sep)+strlen(value)+1;
|
||||||
# define XIO_ENVNAMELEN 256
|
if ((newval = Malloc(newlen+1)) == NULL) {
|
||||||
const char *progname;
|
return -1;
|
||||||
char envname[XIO_ENVNAMELEN];
|
}
|
||||||
size_t i, l;
|
snprintf(newval, newlen+1, "%s%s%s", oldval, sep, value);
|
||||||
|
} else {
|
||||||
progname = diag_get_string('p');
|
newval = (char *)value;
|
||||||
envname[0] = '\0'; strncat(envname, progname, XIO_ENVNAMELEN-1);
|
}
|
||||||
l = strlen(progname);
|
if (Setenv(envname, newval, overwrite) < 0) {
|
||||||
for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
|
|
||||||
strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
|
|
||||||
l += 1;
|
|
||||||
strncat(envname+l, varname, XIO_ENVNAMELEN-l-1);
|
|
||||||
if (Setenv(envname, value, overwrite) < 0) {
|
|
||||||
Warn3("setenv(\"%s\", \"%s\", 1): %s",
|
Warn3("setenv(\"%s\", \"%s\", 1): %s",
|
||||||
envname, value, strerror(errno));
|
envname, value, strerror(errno));
|
||||||
#if HAVE_UNSETENV
|
#if HAVE_UNSETENV
|
||||||
|
@ -692,11 +687,34 @@ int xiosetenv(const char *varname, const char *value, int overwrite) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* constructs an environment variable whose name is built from socats uppercase
|
||||||
|
program name, and underscore and varname;
|
||||||
|
if the variable of this name already exists arg overwrite determines:
|
||||||
|
0: keep old value
|
||||||
|
1: overwrite with new value
|
||||||
|
2: append to old value, separated by *sep
|
||||||
|
returns 0 on success or <0 if an error occurred. */
|
||||||
|
int xiosetenv(const char *varname, const char *value, int overwrite, const char *sep) {
|
||||||
|
# define XIO_ENVNAMELEN 256
|
||||||
|
const char *progname;
|
||||||
|
char envname[XIO_ENVNAMELEN];
|
||||||
|
size_t i, l;
|
||||||
|
|
||||||
|
progname = diag_get_string('p');
|
||||||
|
envname[0] = '\0'; strncat(envname, progname, XIO_ENVNAMELEN-1);
|
||||||
|
l = strlen(envname);
|
||||||
|
for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
|
||||||
|
strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
|
||||||
|
l += 1;
|
||||||
|
strncat(envname+l, varname, XIO_ENVNAMELEN-l-1);
|
||||||
|
return _xiosetenv(envname, value, overwrite, sep);
|
||||||
# undef XIO_ENVNAMELEN
|
# undef XIO_ENVNAMELEN
|
||||||
}
|
}
|
||||||
|
|
||||||
int xiosetenv2(const char *varname, const char *varname2, const char *value,
|
int xiosetenv2(const char *varname, const char *varname2, const char *value,
|
||||||
int overwrite) {
|
int overwrite, const char *sep) {
|
||||||
# define XIO_ENVNAMELEN 256
|
# define XIO_ENVNAMELEN 256
|
||||||
const char *progname;
|
const char *progname;
|
||||||
char envname[XIO_ENVNAMELEN];
|
char envname[XIO_ENVNAMELEN];
|
||||||
|
@ -708,27 +726,19 @@ int xiosetenv2(const char *varname, const char *varname2, const char *value,
|
||||||
strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
|
strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
|
||||||
l += 1;
|
l += 1;
|
||||||
strncat(envname+l, varname, XIO_ENVNAMELEN-l-1);
|
strncat(envname+l, varname, XIO_ENVNAMELEN-l-1);
|
||||||
l += strlen(varname+l);
|
l += strlen(envname+l);
|
||||||
strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
|
strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
|
||||||
l += 1;
|
l += 1;
|
||||||
strncat(envname+l, varname2, XIO_ENVNAMELEN-l-1);
|
strncat(envname+l, varname2, XIO_ENVNAMELEN-l-1);
|
||||||
l += strlen(varname+l);
|
l += strlen(envname+l);
|
||||||
for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
|
for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
|
||||||
if (Setenv(envname, value, overwrite) < 0) {
|
return _xiosetenv(envname, value, overwrite, sep);
|
||||||
Warn3("setenv(\"%s\", \"%s\", 1): %s",
|
|
||||||
envname, value, strerror(errno));
|
|
||||||
#if HAVE_UNSETENV
|
|
||||||
Unsetenv(envname); /* dont want to have a wrong value */
|
|
||||||
#endif
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
# undef XIO_ENVNAMELEN
|
# undef XIO_ENVNAMELEN
|
||||||
}
|
}
|
||||||
|
|
||||||
int xiosetenv3(const char *varname, const char *varname2, const char *varname3,
|
int xiosetenv3(const char *varname, const char *varname2, const char *varname3,
|
||||||
const char *value,
|
const char *value,
|
||||||
int overwrite) {
|
int overwrite, const char *sep) {
|
||||||
# define XIO_ENVNAMELEN 256
|
# define XIO_ENVNAMELEN 256
|
||||||
const char *progname;
|
const char *progname;
|
||||||
char envname[XIO_ENVNAMELEN];
|
char envname[XIO_ENVNAMELEN];
|
||||||
|
@ -750,15 +760,7 @@ int xiosetenv3(const char *varname, const char *varname2, const char *varname3,
|
||||||
strncat(envname+l, varname3, XIO_ENVNAMELEN-l-1);
|
strncat(envname+l, varname3, XIO_ENVNAMELEN-l-1);
|
||||||
l += strlen(envname+l);
|
l += strlen(envname+l);
|
||||||
for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
|
for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
|
||||||
if (Setenv(envname, value, overwrite) < 0) {
|
return _xiosetenv(envname, value, overwrite, sep);
|
||||||
Warn3("setenv(\"%s\", \"%s\", 1): %s",
|
|
||||||
envname, value, strerror(errno));
|
|
||||||
#if HAVE_UNSETENV
|
|
||||||
Unsetenv(envname); /* dont want to have a wrong value */
|
|
||||||
#endif
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
# undef XIO_ENVNAMELEN
|
# undef XIO_ENVNAMELEN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,7 +771,7 @@ int xiosetenvulong(const char *varname, unsigned long value, int overwrite) {
|
||||||
char envbuff[XIO_LONGLEN];
|
char envbuff[XIO_LONGLEN];
|
||||||
|
|
||||||
snprintf(envbuff, XIO_LONGLEN, "%lu", value);
|
snprintf(envbuff, XIO_LONGLEN, "%lu", value);
|
||||||
return xiosetenv(varname, envbuff, overwrite);
|
return xiosetenv(varname, envbuff, overwrite, NULL);
|
||||||
# undef XIO_LONGLEN
|
# undef XIO_LONGLEN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -779,6 +781,6 @@ int xiosetenvushort(const char *varname, unsigned short value, int overwrite) {
|
||||||
char envbuff[XIO_SHORTLEN];
|
char envbuff[XIO_SHORTLEN];
|
||||||
|
|
||||||
snprintf(envbuff, XIO_SHORTLEN, "%hu", value);
|
snprintf(envbuff, XIO_SHORTLEN, "%hu", value);
|
||||||
return xiosetenv(varname, envbuff, overwrite);
|
return xiosetenv(varname, envbuff, overwrite, NULL);
|
||||||
# undef XIO_SHORTLEN
|
# undef XIO_SHORTLEN
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,13 +89,13 @@ extern int parseport(const char *portname, int proto);
|
||||||
extern int ifindexbyname(const char *ifname, int anysock);
|
extern int ifindexbyname(const char *ifname, int anysock);
|
||||||
extern int ifindex(const char *ifname, unsigned int *ifindex, int anysock);
|
extern int ifindex(const char *ifname, unsigned int *ifindex, int anysock);
|
||||||
|
|
||||||
extern int xiosetenv(const char *varname, const char *value, int overwrite);
|
extern int xiosetenv(const char *varname, const char *value, int overwrite, const char *sep);
|
||||||
extern int
|
extern int
|
||||||
xiosetenv2(const char *varname, const char *varname2, const char *value,
|
xiosetenv2(const char *varname, const char *varname2, const char *value,
|
||||||
int overwrite);
|
int overwrite, const char *sep);
|
||||||
extern int
|
extern int
|
||||||
xiosetenv3(const char *varname, const char *varname2, const char *varname3,
|
xiosetenv3(const char *varname, const char *varname2, const char *varname3,
|
||||||
const char *value, int overwrite);
|
const char *value, int overwrite, const char *sep);
|
||||||
extern int xiosetenvulong(const char *varname, unsigned long value,
|
extern int xiosetenvulong(const char *varname, unsigned long value,
|
||||||
int overwrite);
|
int overwrite);
|
||||||
extern int xiosetenvushort(const char *varname, unsigned short value,
|
extern int xiosetenvushort(const char *varname, unsigned short value,
|
||||||
|
|
124
test.sh
124
test.sh
|
@ -70,8 +70,8 @@ else
|
||||||
fi
|
fi
|
||||||
MCINTERFACE=lo # !!! Linux only
|
MCINTERFACE=lo # !!! Linux only
|
||||||
#LOCALHOST=192.168.58.1
|
#LOCALHOST=192.168.58.1
|
||||||
#LOCALHOST=localhost
|
LOCALHOST=localhost
|
||||||
LOCALHOST=127.0.0.1
|
#LOCALHOST=127.0.0.1
|
||||||
LOCALHOST6=[::1]
|
LOCALHOST6=[::1]
|
||||||
#PROTO=$(awk '{print($2);}' /etc/protocols |sort -n |tail -n 1)
|
#PROTO=$(awk '{print($2);}' /etc/protocols |sort -n |tail -n 1)
|
||||||
#PROTO=$(($PROTO+1))
|
#PROTO=$(($PROTO+1))
|
||||||
|
@ -79,10 +79,24 @@ PROTO=$((144+RANDOM/2048))
|
||||||
PORT=12002
|
PORT=12002
|
||||||
SOURCEPORT=2002
|
SOURCEPORT=2002
|
||||||
TESTCERT_CONF=testcert.conf
|
TESTCERT_CONF=testcert.conf
|
||||||
TESTCERT_SUBJECT="/C=XY"
|
TESTCERT6_CONF=testcert6.conf
|
||||||
TESTCERT_ISSUER="/C=XY"
|
# keep these values consistent with testcert.conf
|
||||||
|
TESTCERT_COMMONNAME="$LOCALHOST"
|
||||||
|
TESTCERT_COUNTRYNAME="$(grep ^countryName= testcert.conf)"; TESTCERT_COUNTRYNAME="${TESTCERT_COUNTRYNAME##*=}"
|
||||||
|
TESTCERT_LOCALITYNAME="$(grep ^L= testcert.conf)"; TESTCERT_LOCALITYNAME="${TESTCERT_LOCALITYNAME##*=}"
|
||||||
|
TESTCERT_ORGANIZATIONALUNITNAME="$(grep ^OU= testcert.conf)"; TESTCERT_ORGANIZATIONALUNITNAME="${TESTCERT_ORGANIZATIONALUNITNAME##*=}"
|
||||||
|
TESTCERT_ORGANIZATIONNAME="$(grep ^O= testcert.conf)"; TESTCERT_ORGANIZATIONNAME="${TESTCERT_ORGANIZATIONNAME##*=}"
|
||||||
|
TESTCERT_SUBJECT="C = XY, CN = localhost, O = dest-unreach, OU = socat, L = Lunar Base"
|
||||||
|
TESTCERT_ISSUER="C = XY, CN = localhost, O = dest-unreach, OU = socat, L = Lunar Base"
|
||||||
CAT=cat
|
CAT=cat
|
||||||
OD_C="od -c"
|
OD_C="od -c"
|
||||||
|
|
||||||
|
# clean up from previous runs
|
||||||
|
rm -f testcli.{crt,key,pem}
|
||||||
|
rm -f testsrv.{crt,key,pem}
|
||||||
|
rm -f testcli6.{crt,key,pem}
|
||||||
|
rm -f testsrv6.{crt,key,pem}
|
||||||
|
|
||||||
# precision sleep; takes seconds with fractional part
|
# precision sleep; takes seconds with fractional part
|
||||||
psleep () {
|
psleep () {
|
||||||
local T="$1"
|
local T="$1"
|
||||||
|
@ -2244,6 +2258,17 @@ gentestdsacert () {
|
||||||
cat $name-dsa.pem $name-dh.pem $name.key $name.crt >$name.pem
|
cat $name-dsa.pem $name-dh.pem $name.key $name.crt >$name.pem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gentestcert6 () {
|
||||||
|
local name="$1"
|
||||||
|
if [ -s $name.key -a -s $name.crt -a -s $name.pem ]; then return; fi
|
||||||
|
cat $TESTCERT_CONF |
|
||||||
|
{ echo "# automatically generated by $0"; cat; } |
|
||||||
|
sed 's/\(commonName\s*=\s*\).*/\1[::1]/' >$TESTCERT6_CONF
|
||||||
|
openssl genrsa $OPENSSL_RAND -out $name.key 768 >/dev/null 2>&1
|
||||||
|
openssl req -new -config $TESTCERT6_CONF -key $name.key -x509 -out $name.crt -days 3653 >/dev/null 2>&1
|
||||||
|
cat $name.key $name.crt >$name.pem
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
NAME=UNISTDIO
|
NAME=UNISTDIO
|
||||||
case "$TESTS " in
|
case "$TESTS " in
|
||||||
|
@ -4137,7 +4162,7 @@ TESTKEYW=${TESTADDR%%:*}
|
||||||
# does our address implementation support halfclose?
|
# does our address implementation support halfclose?
|
||||||
NAME=${NAMEKEYW}_HALFCLOSE
|
NAME=${NAMEKEYW}_HALFCLOSE
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%functions%*|*%socket%*|*%halfclose%*|*%$NAME%*)
|
*%$N%*|*%functions%*|*%$FEAT%*|*%socket%*|*%halfclose%*|*%$NAME%*)
|
||||||
TEST="$NAME: $TESTKEYW half close"
|
TEST="$NAME: $TESTKEYW half close"
|
||||||
# have a "peer" socat "peer" that executes "$OD_C" and see if EOF on the
|
# have a "peer" socat "peer" that executes "$OD_C" and see if EOF on the
|
||||||
# connecting socat brings the result of od
|
# connecting socat brings the result of od
|
||||||
|
@ -5166,7 +5191,7 @@ N=$((N+1))
|
||||||
#!
|
#!
|
||||||
NAME=OUTBOUNDIN
|
NAME=OUTBOUNDIN
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%functions%*|*%chain%*|*%proxy%*|*%$NAME%*)
|
*%$N%*|*%functions%|*%chain%**|*%openssl%*|*%proxy%*|*%$NAME%*)
|
||||||
TEST="$NAME: gender changer via SSL through HTTP proxy, oneshot"
|
TEST="$NAME: gender changer via SSL through HTTP proxy, oneshot"
|
||||||
if ! eval $NUMCOND; then :;
|
if ! eval $NUMCOND; then :;
|
||||||
elif ! feat=$(testaddrs openssl proxy); then
|
elif ! feat=$(testaddrs openssl proxy); then
|
||||||
|
@ -5254,7 +5279,7 @@ PORT=$((RANDOM+16184))
|
||||||
#!
|
#!
|
||||||
NAME=INTRANETRIPPER
|
NAME=INTRANETRIPPER
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%functions%*|*%chain%*|*%proxy%*|*%$NAME%*)
|
*%$N%*|*%functions%*|*%chain%*|*%openssl%*|*%proxy%*|*%$NAME%*)
|
||||||
TEST="$NAME: gender changer via SSL through HTTP proxy, daemons"
|
TEST="$NAME: gender changer via SSL through HTTP proxy, daemons"
|
||||||
if ! eval $NUMCOND; then :;
|
if ! eval $NUMCOND; then :;
|
||||||
elif ! feat=$(testaddrs openssl proxy); then
|
elif ! feat=$(testaddrs openssl proxy); then
|
||||||
|
@ -5387,7 +5412,6 @@ testserversec () {
|
||||||
local stat result
|
local stat result
|
||||||
|
|
||||||
$PRINTF "test $F_n %s... " $N "$title"
|
$PRINTF "test $F_n %s... " $N "$title"
|
||||||
#set -vx
|
|
||||||
# first: without security
|
# first: without security
|
||||||
# start server
|
# start server
|
||||||
$TRACE $SOCAT $opts "$arg1,$secopt0" echo 2>"${te}1" &
|
$TRACE $SOCAT $opts "$arg1,$secopt0" echo 2>"${te}1" &
|
||||||
|
@ -5404,7 +5428,7 @@ testserversec () {
|
||||||
(echo "$da"; sleep $T) |$TRACE $SOCAT $opts - "$arg2" >"$tf" 2>"${te}2"
|
(echo "$da"; sleep $T) |$TRACE $SOCAT $opts - "$arg2" >"$tf" 2>"${te}2"
|
||||||
stat="$?"
|
stat="$?"
|
||||||
kill $spid 2>/dev/null
|
kill $spid 2>/dev/null
|
||||||
#killall $TRACE $SOCAT 2>/dev/null
|
#killall $SOCAT 2>/dev/null
|
||||||
if [ "$stat" != 0 ]; then
|
if [ "$stat" != 0 ]; then
|
||||||
$PRINTF "$NO_RESULT (ph.1 function fails): $TRACE $SOCAT:\n"
|
$PRINTF "$NO_RESULT (ph.1 function fails): $TRACE $SOCAT:\n"
|
||||||
echo "$TRACE $SOCAT $opts \"$arg1,$secopt0\" echo &"
|
echo "$TRACE $SOCAT $opts \"$arg1,$secopt0\" echo &"
|
||||||
|
@ -5814,7 +5838,7 @@ elif ! testaddrs openssl >/dev/null; then
|
||||||
numCANT=$((numCANT+1))
|
numCANT=$((numCANT+1))
|
||||||
else
|
else
|
||||||
gentestcert testsrv
|
gentestcert testsrv
|
||||||
testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "range=$SECONDADDR/32" "ssl:127.0.0.1:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1
|
testserversec "$N" "$TEST" "$opts -s" "SSL-L:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "range=$SECONDADDR/32" "SSL:$LOCALHOST:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1
|
||||||
fi ;; # NUMCOND, feats
|
fi ;; # NUMCOND, feats
|
||||||
esac
|
esac
|
||||||
PORT=$((PORT+1))
|
PORT=$((PORT+1))
|
||||||
|
@ -5830,7 +5854,7 @@ elif ! testaddrs openssl >/dev/null; then
|
||||||
numCANT=$((numCANT+1))
|
numCANT=$((numCANT+1))
|
||||||
else
|
else
|
||||||
gentestcert testsrv
|
gentestcert testsrv
|
||||||
testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "sp=$PORT" "ssl:127.0.0.1:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1
|
testserversec "$N" "$TEST" "$opts -s" "SSL-L:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "sp=$PORT" "SSL:$LOCALHOST:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1
|
||||||
fi ;; # NUMCOND, feats
|
fi ;; # NUMCOND, feats
|
||||||
esac
|
esac
|
||||||
PORT=$((PORT+1))
|
PORT=$((PORT+1))
|
||||||
|
@ -5846,7 +5870,7 @@ elif ! testaddrs openssl >/dev/null; then
|
||||||
numCANT=$((numCANT+1))
|
numCANT=$((numCANT+1))
|
||||||
else
|
else
|
||||||
gentestcert testsrv
|
gentestcert testsrv
|
||||||
testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "lowport" "ssl:127.0.0.1:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1
|
testserversec "$N" "$TEST" "$opts -s" "SSL-L:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "lowport" "SSL:$LOCALHOST:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1
|
||||||
fi ;; # NUMCOND, feats
|
fi ;; # NUMCOND, feats
|
||||||
esac
|
esac
|
||||||
PORT=$((PORT+1))
|
PORT=$((PORT+1))
|
||||||
|
@ -5866,7 +5890,7 @@ ha="$td/hosts.allow"
|
||||||
hd="$td/hosts.deny"
|
hd="$td/hosts.deny"
|
||||||
$ECHO "socat: $SECONDADDR" >"$ha"
|
$ECHO "socat: $SECONDADDR" >"$ha"
|
||||||
$ECHO "ALL: ALL" >"$hd"
|
$ECHO "ALL: ALL" >"$hd"
|
||||||
testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "tcpwrap-etc=$td" "ssl:127.0.0.1:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1
|
testserversec "$N" "$TEST" "$opts -s" "SSL-L:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "tcpwrap-etc=$td" "SSL:$LOCALHOST:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 4 tcp $PORT -1
|
||||||
fi ;; # NUMCOND, feats
|
fi ;; # NUMCOND, feats
|
||||||
esac
|
esac
|
||||||
PORT=$((PORT+1))
|
PORT=$((PORT+1))
|
||||||
|
@ -5883,7 +5907,7 @@ elif ! testaddrs openssl >/dev/null; then
|
||||||
else
|
else
|
||||||
gentestcert testsrv
|
gentestcert testsrv
|
||||||
gentestcert testcli
|
gentestcert testcli
|
||||||
testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify,cert=testsrv.crt,key=testsrv.key" "cafile=testcli.crt" "cafile=testsrv.crt" "ssl:127.0.0.1:$PORT,cafile=testsrv.crt,cert=testcli.pem,$SOCAT_EGD" 4 tcp $PORT -1
|
testserversec "$N" "$TEST" "$opts -s" "SSL-L:$PORT,pf=ip4,reuseaddr,fork,retry=1,$SOCAT_EGD,verify,cert=testsrv.crt,key=testsrv.key" "cafile=testcli.crt" "cafile=testsrv.crt" "SSL:$LOCALHOST:$PORT,cafile=testsrv.crt,cert=testcli.pem,$SOCAT_EGD" 4 tcp $PORT -1
|
||||||
fi ;; # NUMCOND, feats
|
fi ;; # NUMCOND, feats
|
||||||
esac
|
esac
|
||||||
PORT=$((PORT+1))
|
PORT=$((PORT+1))
|
||||||
|
@ -5919,8 +5943,8 @@ elif ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then
|
||||||
$PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N
|
$PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N
|
||||||
numCANT=$((numCANT+1))
|
numCANT=$((numCANT+1))
|
||||||
else
|
else
|
||||||
gentestcert testsrv
|
gentestcert6 testsrv6
|
||||||
testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "range=[::2/128]" "ssl:[::1]:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 6 tcp $PORT -1
|
testserversec "$N" "$TEST" "$opts -s" "SSL-L:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv6.crt,key=testsrv6.key" "" "range=[::2/128]" "SSL:[::1]:$PORT,cafile=testsrv6.crt,$SOCAT_EGD" 6 tcp $PORT -1
|
||||||
fi ;; # NUMCOND, feats
|
fi ;; # NUMCOND, feats
|
||||||
esac
|
esac
|
||||||
PORT=$((PORT+1))
|
PORT=$((PORT+1))
|
||||||
|
@ -5938,8 +5962,8 @@ elif ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then
|
||||||
$PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N
|
$PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N
|
||||||
numCANT=$((numCANT+1))
|
numCANT=$((numCANT+1))
|
||||||
else
|
else
|
||||||
gentestcert testsrv
|
gentestcert6 testsrv6
|
||||||
testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "sp=$PORT" "ssl:[::1]:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 6 tcp $PORT -1
|
testserversec "$N" "$TEST" "$opts -s" "SSL-L:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv6.crt,key=testsrv6.key" "" "sp=$PORT" "SSL:[::1]:$PORT,cafile=testsrv6.crt,$SOCAT_EGD" 6 tcp $PORT -1
|
||||||
fi ;; # NUMCOND, feats
|
fi ;; # NUMCOND, feats
|
||||||
esac
|
esac
|
||||||
PORT=$((PORT+1))
|
PORT=$((PORT+1))
|
||||||
|
@ -5957,8 +5981,8 @@ elif ! feat=$(testaddrs tcp ip6) || ! runsip6 >/dev/null; then
|
||||||
$PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N
|
$PRINTF "test $F_n $TEST... ${YELLOW}TCP6 not available${NORMAL}\n" $N
|
||||||
numCANT=$((numCANT+1))
|
numCANT=$((numCANT+1))
|
||||||
else
|
else
|
||||||
gentestcert testsrv
|
gentestcert6 testsrv6
|
||||||
testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "lowport" "ssl:[::1]:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 6 tcp $PORT -1
|
testserversec "$N" "$TEST" "$opts -s" "SSL-L:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv6.crt,key=testsrv6.key" "" "lowport" "SSL:[::1]:$PORT,cafile=testsrv6.crt,$SOCAT_EGD" 6 tcp $PORT -1
|
||||||
fi ;; # NUMCOND, feats
|
fi ;; # NUMCOND, feats
|
||||||
esac
|
esac
|
||||||
PORT=$((PORT+1))
|
PORT=$((PORT+1))
|
||||||
|
@ -5973,18 +5997,66 @@ elif ! feat=$(testaddrs ip6 tcp libwrap openssl) || ! runsip6 >/dev/null; then
|
||||||
$PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N
|
$PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N
|
||||||
numCANT=$((numCANT+1))
|
numCANT=$((numCANT+1))
|
||||||
else
|
else
|
||||||
gentestcert testsrv
|
gentestcert6 testsrv6
|
||||||
ha="$td/hosts.allow"
|
ha="$td/hosts.allow"
|
||||||
hd="$td/hosts.deny"
|
hd="$td/hosts.deny"
|
||||||
$ECHO "socat: [::2]" >"$ha"
|
$ECHO "socat: [::2]" >"$ha"
|
||||||
$ECHO "ALL: ALL" >"$hd"
|
$ECHO "ALL: ALL" >"$hd"
|
||||||
testserversec "$N" "$TEST" "$opts -s" "ssl-l:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv.crt,key=testsrv.key" "" "tcpwrap-etc=$td" "ssl:[::1]:$PORT,cafile=testsrv.crt,$SOCAT_EGD" 6 tcp $PORT -1
|
testserversec "$N" "$TEST" "$opts -s" "SSL-L:$PORT,pf=ip6,reuseaddr,fork,retry=1,$SOCAT_EGD,verify=0,cert=testsrv6.crt,key=testsrv6.key" "" "tcpwrap-etc=$td" "SSL:[::1]:$PORT,cafile=testsrv6.crt,$SOCAT_EGD" 6 tcp $PORT -1
|
||||||
fi ;; # NUMCOND, feats
|
fi ;; # NUMCOND, feats
|
||||||
esac
|
esac
|
||||||
PORT=$((PORT+1))
|
PORT=$((PORT+1))
|
||||||
N=$((N+1))
|
N=$((N+1))
|
||||||
|
|
||||||
|
|
||||||
|
# test security with the openssl-commonname option on client side
|
||||||
|
NAME=OPENSSL_CN_CLIENT_SECURITY
|
||||||
|
case "$TESTS" in
|
||||||
|
*%$N%*|*%functions%*|*%security%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
|
||||||
|
TEST="$NAME: security of client openssl-commonname option"
|
||||||
|
# connect using non matching server name/address with commonname
|
||||||
|
# options, this should succeed. Then without this option, should fail
|
||||||
|
if ! eval $NUMCOND; then :;
|
||||||
|
elif ! testaddrs openssl >/dev/null; then
|
||||||
|
$PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N
|
||||||
|
numCANT=$((numCANT+1))
|
||||||
|
elif ! testaddrs listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then
|
||||||
|
$PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N
|
||||||
|
numCANT=$((numCANT+1))
|
||||||
|
else
|
||||||
|
gentestcert testsrv
|
||||||
|
gentestcert testcli
|
||||||
|
testserversec "$N" "$TEST" "$opts" "SSL:127.0.0.1:$PORT,fork,retry=2,verify,cafile=testsrv.crt" "commonname=$LOCALHOST" "" "SSL-L:$PORT,pf=ip4,reuseaddr,cert=testsrv.crt,key=testsrv.key,verify=0" 4 tcp "" 0
|
||||||
|
fi ;; # testaddrs, NUMCOND
|
||||||
|
esac
|
||||||
|
PORT=$((PORT+1))
|
||||||
|
N=$((N+1))
|
||||||
|
|
||||||
|
# test security with the openssl-commonname option on server side
|
||||||
|
NAME=OPENSSL_CN_SERVER_SECURITY
|
||||||
|
case "$TESTS" in
|
||||||
|
*%$N%*|*%functions%*|*%security%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
|
||||||
|
TEST="$NAME: security of server openssl-commonname option"
|
||||||
|
# connect using with client certificate to server, this should succeed.
|
||||||
|
# Then use the server with a non matching openssl-commonname option,
|
||||||
|
# this must fail
|
||||||
|
if ! eval $NUMCOND; then :;
|
||||||
|
elif ! testaddrs openssl >/dev/null; then
|
||||||
|
$PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N
|
||||||
|
numCANT=$((numCANT+1))
|
||||||
|
elif ! testaddrs listen tcp ip4 >/dev/null || ! runsip4 >/dev/null; then
|
||||||
|
$PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N
|
||||||
|
numCANT=$((numCANT+1))
|
||||||
|
else
|
||||||
|
gentestcert testsrv
|
||||||
|
gentestcert testcli
|
||||||
|
testserversec "$N" "$TEST" "$opts" "SSL-L:$PORT,pf=ip4,reuseaddr,cert=testsrv.crt,key=testsrv.key,cafile=testcli.crt" "" "commonname=onlyyou" "SSL:$LOCALHOST:$PORT,verify=0,cafile=testsrv.crt,cert=testcli.crt,key=testcli.key" 4 tcp "" 0
|
||||||
|
fi ;; # testaddrs, NUMCOND
|
||||||
|
esac
|
||||||
|
PORT=$((PORT+1))
|
||||||
|
N=$((N+1))
|
||||||
|
|
||||||
|
|
||||||
NAME=OPENSSL_FIPS_SECURITY
|
NAME=OPENSSL_FIPS_SECURITY
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%functions%*|*%security%*|*%openssl%*|*%fips%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
|
*%$N%*|*%functions%*|*%security%*|*%openssl%*|*%fips%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
|
||||||
|
@ -9123,7 +9195,7 @@ NAME=OPENSSLREAD
|
||||||
# keeps there and is not transferred by socat until the socket indicates more
|
# keeps there and is not transferred by socat until the socket indicates more
|
||||||
# data or EOF.
|
# data or EOF.
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%functions%*|*%$NAME%*)
|
*%$N%*|*%functions%*|*%openssl%*|*%$NAME%*)
|
||||||
TEST="$NAME: socat handles data buffered by openssl"
|
TEST="$NAME: socat handles data buffered by openssl"
|
||||||
#idea: have a socat process (server) that gets an SSL block that is larger than
|
#idea: have a socat process (server) that gets an SSL block that is larger than
|
||||||
# socat transfer block size; keep the socket connection open and kill the
|
# socat transfer block size; keep the socket connection open and kill the
|
||||||
|
@ -10015,10 +10087,10 @@ N=$((N+1))
|
||||||
set +xv
|
set +xv
|
||||||
#
|
#
|
||||||
done <<<"
|
done <<<"
|
||||||
TCP4 TCP $LOCALHOST $SECONDADDR $PORT $((PORT+1))
|
TCP4 TCP 127.0.0.1 $SECONDADDR $PORT $((PORT+1))
|
||||||
TCP6 IP6 [0000:0000:0000:0000:0000:0000:0000:0001] [0000:0000:0000:0000:0000:0000:0000:0001] $((PORT+2)) $((PORT+3))
|
TCP6 IP6 [0000:0000:0000:0000:0000:0000:0000:0001] [0000:0000:0000:0000:0000:0000:0000:0001] $((PORT+2)) $((PORT+3))
|
||||||
UDP6 IP6 [0000:0000:0000:0000:0000:0000:0000:0001] [0000:0000:0000:0000:0000:0000:0000:0001] $((PORT+6)) $((PORT+7))
|
UDP6 IP6 [0000:0000:0000:0000:0000:0000:0000:0001] [0000:0000:0000:0000:0000:0000:0000:0001] $((PORT+6)) $((PORT+7))
|
||||||
SCTP4 SCTP $LOCALHOST $SECONDADDR $((PORT+8)) $((PORT+9))
|
SCTP4 SCTP 127.0.0.1 $SECONDADDR $((PORT+8)) $((PORT+9))
|
||||||
SCTP6 SCTP [0000:0000:0000:0000:0000:0000:0000:0001] [0000:0000:0000:0000:0000:0000:0000:0001] $((PORT+10)) $((PORT+11))
|
SCTP6 SCTP [0000:0000:0000:0000:0000:0000:0000:0001] [0000:0000:0000:0000:0000:0000:0000:0001] $((PORT+10)) $((PORT+11))
|
||||||
UNIX UNIX $td/test\$N.server $td/test\$N.client , ,
|
UNIX UNIX $td/test\$N.server $td/test\$N.client , ,
|
||||||
"
|
"
|
||||||
|
@ -11737,7 +11809,7 @@ N=$((N+1))
|
||||||
# Linux) with "Invalid argument".
|
# Linux) with "Invalid argument".
|
||||||
NAME=OPENSSL_CONNECT_BIND
|
NAME=OPENSSL_CONNECT_BIND
|
||||||
case "$TESTS" in
|
case "$TESTS" in
|
||||||
*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%ssl%*|*%$NAME%*)
|
*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%ssl%*|*%openssl%*|*%$NAME%*)
|
||||||
TEST="$NAME: test OPENSSL-CONNECT with bind option"
|
TEST="$NAME: test OPENSSL-CONNECT with bind option"
|
||||||
# have a simple SSL server that just echoes data.
|
# have a simple SSL server that just echoes data.
|
||||||
# connect with socat using OPENSSL-CONNECT with bind, send data and check if the
|
# connect with socat using OPENSSL-CONNECT with bind, send data and check if the
|
||||||
|
|
|
@ -6,4 +6,8 @@ distinguished_name=Test
|
||||||
|
|
||||||
[ Test ]
|
[ Test ]
|
||||||
countryName=XY
|
countryName=XY
|
||||||
|
commonName=localhost
|
||||||
|
O=dest-unreach
|
||||||
|
OU=socat
|
||||||
|
L=Lunar Base
|
||||||
|
|
||||||
|
|
2
utils.c
2
utils.c
|
@ -67,7 +67,7 @@ const struct wordent *keyw(const struct wordent *keywds, const char *name, unsig
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Linux: setenv(), AIX: putenv() */
|
/* Linux: setenv(), AIX (4.3?): putenv() */
|
||||||
#if !HAVE_SETENV
|
#if !HAVE_SETENV
|
||||||
int setenv(const char *name, const char *value, int overwrite) {
|
int setenv(const char *name, const char *value, int overwrite) {
|
||||||
int result;
|
int result;
|
||||||
|
|
324
xio-openssl.c
324
xio-openssl.c
|
@ -6,6 +6,9 @@
|
||||||
|
|
||||||
#include "xiosysincludes.h"
|
#include "xiosysincludes.h"
|
||||||
#if WITH_OPENSSL /* make this address configure dependend */
|
#if WITH_OPENSSL /* make this address configure dependend */
|
||||||
|
#include <openssl/conf.h>
|
||||||
|
#include <openssl/x509v3.h>
|
||||||
|
|
||||||
#include "xioopen.h"
|
#include "xioopen.h"
|
||||||
|
|
||||||
#include "xio-fd.h"
|
#include "xio-fd.h"
|
||||||
|
@ -45,10 +48,13 @@ static int xioopen_openssl_listen(int argc, const char *argv[], struct opt *opts
|
||||||
int xioflags, xiofile_t *fd, unsigned groups,
|
int xioflags, xiofile_t *fd, unsigned groups,
|
||||||
int dummy1, int dummy2, int dummy3);
|
int dummy1, int dummy2, int dummy3);
|
||||||
static int openssl_SSL_ERROR_SSL(int level, const char *funcname);
|
static int openssl_SSL_ERROR_SSL(int level, const char *funcname);
|
||||||
static int openssl_handle_peer_certificate(struct single *xfd, bool opt_ver,
|
static int openssl_handle_peer_certificate(struct single *xfd,
|
||||||
|
const char *peername,
|
||||||
|
bool opt_ver,
|
||||||
int level);
|
int level);
|
||||||
static int xioSSL_set_fd(struct single *xfd, int level);
|
static int xioSSL_set_fd(struct single *xfd, int level);
|
||||||
static int xioSSL_connect(struct single *xfd, bool opt_ver, int level);
|
static int xioSSL_connect(struct single *xfd, const char *opt_commonname, bool opt_ver, int level);
|
||||||
|
static int openssl_delete_cert_info(void);
|
||||||
|
|
||||||
|
|
||||||
/* description record for inter-address ssl connect with 0 parameters */
|
/* description record for inter-address ssl connect with 0 parameters */
|
||||||
|
@ -183,6 +189,7 @@ const struct optdesc opt_openssl_compress = { "openssl-compress", "compress
|
||||||
#if WITH_FIPS
|
#if WITH_FIPS
|
||||||
const struct optdesc opt_openssl_fips = { "openssl-fips", "fips", OPT_OPENSSL_FIPS, GROUP_OPENSSL, PH_SPEC, TYPE_BOOL, OFUNC_SPEC };
|
const struct optdesc opt_openssl_fips = { "openssl-fips", "fips", OPT_OPENSSL_FIPS, GROUP_OPENSSL, PH_SPEC, TYPE_BOOL, OFUNC_SPEC };
|
||||||
#endif
|
#endif
|
||||||
|
const struct optdesc opt_openssl_commonname = { "openssl-commonname", "cn", OPT_OPENSSL_COMMONNAME, GROUP_OPENSSL, PH_SPEC, TYPE_STRING, OFUNC_SPEC };
|
||||||
|
|
||||||
|
|
||||||
/* If FIPS is compiled in, we need to track if the user asked for FIPS mode.
|
/* If FIPS is compiled in, we need to track if the user asked for FIPS mode.
|
||||||
|
@ -263,6 +270,7 @@ static int
|
||||||
/*0 SSL_CTX* ctx;*/
|
/*0 SSL_CTX* ctx;*/
|
||||||
bool opt_ver = true; /* verify peer certificate */
|
bool opt_ver = true; /* verify peer certificate */
|
||||||
char *opt_cert = NULL; /* file name of client certificate */
|
char *opt_cert = NULL; /* file name of client certificate */
|
||||||
|
const char *opt_commonname = NULL; /* for checking peer certificate */
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (!(xioflags & XIO_MAYCONVERT)) {
|
if (!(xioflags & XIO_MAYCONVERT)) {
|
||||||
|
@ -278,6 +286,12 @@ static int
|
||||||
if (argc == 3) {
|
if (argc == 3) {
|
||||||
hostname = argv[1];
|
hostname = argv[1];
|
||||||
portname = argv[2];
|
portname = argv[2];
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/* a "terminal" form where we build a tcp connection to given host and
|
/* a "terminal" form where we build a tcp connection to given host and
|
||||||
port */
|
port */
|
||||||
|
@ -288,6 +302,11 @@ static int
|
||||||
retropt_bool(opts, OPT_FORK, &dofork);
|
retropt_bool(opts, OPT_FORK, &dofork);
|
||||||
|
|
||||||
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
|
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
|
||||||
|
retropt_string(opts, OPT_OPENSSL_COMMONNAME, (char **)&opt_commonname);
|
||||||
|
|
||||||
|
if (opt_commonname == NULL) {
|
||||||
|
opt_commonname = hostname;
|
||||||
|
}
|
||||||
|
|
||||||
result =
|
result =
|
||||||
_xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert,
|
_xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert,
|
||||||
|
@ -314,6 +333,7 @@ static int
|
||||||
|
|
||||||
retropt_bool(opts, OPT_FORK, &dofork);
|
retropt_bool(opts, OPT_FORK, &dofork);
|
||||||
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
|
retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert);
|
||||||
|
retropt_string(opts, OPT_OPENSSL_COMMONNAME, (char **)&opt_commonname);
|
||||||
|
|
||||||
result =
|
result =
|
||||||
_xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert,
|
_xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert,
|
||||||
|
@ -378,7 +398,7 @@ static int
|
||||||
}
|
}
|
||||||
|
|
||||||
result =
|
result =
|
||||||
_xioopen_openssl_connect(xfd, opt_ver, xfd->para.openssl.ctx, level);
|
_xioopen_openssl_connect(xfd, opt_ver, opt_commonname, xfd->para.openssl.ctx, level);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case STAT_OK: break;
|
case STAT_OK: break;
|
||||||
#if WITH_RETRY
|
#if WITH_RETRY
|
||||||
|
@ -449,6 +469,7 @@ static int
|
||||||
SSL connection from an FD and a CTX. */
|
SSL connection from an FD and a CTX. */
|
||||||
int _xioopen_openssl_connect(struct single *xfd,
|
int _xioopen_openssl_connect(struct single *xfd,
|
||||||
bool opt_ver,
|
bool opt_ver,
|
||||||
|
const char *opt_commonname,
|
||||||
SSL_CTX *ctx,
|
SSL_CTX *ctx,
|
||||||
int level) {
|
int level) {
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
|
@ -473,14 +494,15 @@ static int
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = xioSSL_connect(xfd, opt_ver, level);
|
result = xioSSL_connect(xfd, opt_commonname, opt_ver, level);
|
||||||
if (result != STAT_OK) {
|
if (result != STAT_OK) {
|
||||||
sycSSL_free(xfd->para.openssl.ssl);
|
sycSSL_free(xfd->para.openssl.ssl);
|
||||||
xfd->para.openssl.ssl = NULL;
|
xfd->para.openssl.ssl = NULL;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = openssl_handle_peer_certificate(xfd, opt_ver, level);
|
result = openssl_handle_peer_certificate(xfd, opt_commonname,
|
||||||
|
opt_ver, level);
|
||||||
if (result != STAT_OK) {
|
if (result != STAT_OK) {
|
||||||
sycSSL_free(xfd->para.openssl.ssl);
|
sycSSL_free(xfd->para.openssl.ssl);
|
||||||
xfd->para.openssl.ssl = NULL;
|
xfd->para.openssl.ssl = NULL;
|
||||||
|
@ -522,6 +544,7 @@ static int
|
||||||
/*0 SSL_CTX* ctx;*/
|
/*0 SSL_CTX* ctx;*/
|
||||||
bool opt_ver = true; /* verify peer certificate - changed with 1.6.0 */
|
bool opt_ver = true; /* verify peer certificate - changed with 1.6.0 */
|
||||||
char *opt_cert = NULL; /* file name of server certificate */
|
char *opt_cert = NULL; /* file name of server certificate */
|
||||||
|
const char *opt_commonname = NULL; /* for checking peer certificate */
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (!(xioflags & XIO_MAYCONVERT)) {
|
if (!(xioflags & XIO_MAYCONVERT)) {
|
||||||
|
@ -549,6 +572,8 @@ static int
|
||||||
Warn("no certificate given; consider option \"cert\"");
|
Warn("no certificate given; consider option \"cert\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retropt_string(opts, OPT_OPENSSL_COMMONNAME, (char **)&opt_commonname);
|
||||||
|
|
||||||
result =
|
result =
|
||||||
_xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert,
|
_xioopen_openssl_prepare(opts, xfd, true, &opt_ver, opt_cert,
|
||||||
&xfd->para.openssl.ctx);
|
&xfd->para.openssl.ctx);
|
||||||
|
@ -576,6 +601,8 @@ static int
|
||||||
Warn("no certificate given; consider option \"cert\"");
|
Warn("no certificate given; consider option \"cert\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retropt_string(opts, OPT_OPENSSL_COMMONNAME, (char **)&opt_commonname);
|
||||||
|
|
||||||
applyopts(-1, opts, PH_EARLY);
|
applyopts(-1, opts, PH_EARLY);
|
||||||
|
|
||||||
result =
|
result =
|
||||||
|
@ -634,7 +661,7 @@ static int
|
||||||
xfd->wfd = xfd->rfd;
|
xfd->wfd = xfd->rfd;
|
||||||
}
|
}
|
||||||
result =
|
result =
|
||||||
_xioopen_openssl_listen(xfd, opt_ver, xfd->para.openssl.ctx, level);
|
_xioopen_openssl_listen(xfd, opt_ver, opt_commonname, xfd->para.openssl.ctx, level);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case STAT_OK: break;
|
case STAT_OK: break;
|
||||||
#if WITH_RETRY
|
#if WITH_RETRY
|
||||||
|
@ -668,6 +695,7 @@ static int
|
||||||
|
|
||||||
int _xioopen_openssl_listen(struct single *xfd,
|
int _xioopen_openssl_listen(struct single *xfd,
|
||||||
bool opt_ver,
|
bool opt_ver,
|
||||||
|
const char *opt_commonname,
|
||||||
SSL_CTX *ctx,
|
SSL_CTX *ctx,
|
||||||
int level) {
|
int level) {
|
||||||
char error_string[120];
|
char error_string[120];
|
||||||
|
@ -748,7 +776,7 @@ int _xioopen_openssl_listen(struct single *xfd,
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openssl_handle_peer_certificate(xfd, opt_ver, E_ERROR/*!*/) < 0) {
|
if (openssl_handle_peer_certificate(xfd, opt_commonname, opt_ver, E_ERROR/*!*/) < 0) {
|
||||||
return STAT_NORETRY;
|
return STAT_NORETRY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -852,7 +880,6 @@ int
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
|
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
|
||||||
retropt_string(opts, OPT_OPENSSL_COMPRESS, &opt_compress);
|
retropt_string(opts, OPT_OPENSSL_COMPRESS, &opt_compress);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if WITH_FIPS
|
#if WITH_FIPS
|
||||||
if (opt_fips) {
|
if (opt_fips) {
|
||||||
if (!sycFIPS_mode_set(1)) {
|
if (!sycFIPS_mode_set(1)) {
|
||||||
|
@ -865,6 +892,8 @@ int
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
openssl_delete_cert_info();
|
||||||
|
|
||||||
OpenSSL_add_all_algorithms();
|
OpenSSL_add_all_algorithms();
|
||||||
OpenSSL_add_all_ciphers();
|
OpenSSL_add_all_ciphers();
|
||||||
OpenSSL_add_all_digests();
|
OpenSSL_add_all_digests();
|
||||||
|
@ -1104,19 +1133,21 @@ int
|
||||||
static int openssl_SSL_ERROR_SSL(int level, const char *funcname) {
|
static int openssl_SSL_ERROR_SSL(int level, const char *funcname) {
|
||||||
unsigned long e;
|
unsigned long e;
|
||||||
char buf[120]; /* this value demanded by "man ERR_error_string" */
|
char buf[120]; /* this value demanded by "man ERR_error_string" */
|
||||||
|
int stat = STAT_OK;
|
||||||
|
|
||||||
e = ERR_get_error();
|
while (e = ERR_get_error()) {
|
||||||
Debug1("ERR_get_error(): %lx", e);
|
Debug1("ERR_get_error(): %lx", e);
|
||||||
if (e == ((ERR_LIB_RAND<<24)|
|
if (e == ((ERR_LIB_RAND<<24)|
|
||||||
(RAND_F_SSLEAY_RAND_BYTES<<12)|
|
(RAND_F_SSLEAY_RAND_BYTES<<12)|
|
||||||
(RAND_R_PRNG_NOT_SEEDED)) /*0x24064064*/) {
|
(RAND_R_PRNG_NOT_SEEDED)) /*0x24064064*/) {
|
||||||
Error("too few entropy; use options \"egd\" or \"pseudo\"");
|
Error("too few entropy; use options \"egd\" or \"pseudo\"");
|
||||||
return STAT_NORETRY;
|
stat = STAT_NORETRY;
|
||||||
} else {
|
} else {
|
||||||
Msg2(level, "%s(): %s", funcname, ERR_error_string(e, buf));
|
Msg2(level, "%s(): %s", funcname, ERR_error_string(e, buf));
|
||||||
return level==E_ERROR ? STAT_NORETRY : STAT_RETRYLATER;
|
stat = level==E_ERROR ? STAT_NORETRY : STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
return STAT_OK;
|
}
|
||||||
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *openssl_verify_messages[] = {
|
static const char *openssl_verify_messages[] = {
|
||||||
|
@ -1173,9 +1204,115 @@ static const char *openssl_verify_messages[] = {
|
||||||
/* 50 */ "application verification failure",
|
/* 50 */ "application verification failure",
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
static int openssl_extract_cert_info(const char *field, X509_NAME *name) {
|
|
||||||
int n, i;
|
/* 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);
|
||||||
|
for (i = 0; i < l; ++i) envprefix[i] = toupper(envprefix[i]);
|
||||||
|
strncat(envprefix+l, "_OPENSSL_", XIO_ENVNAMELEN-l-1);
|
||||||
|
|
||||||
|
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);
|
||||||
|
Unsetenv(envname);
|
||||||
|
} else {
|
||||||
|
++entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
static bool openssl_check_name(const char *cn, const char *peername) {
|
||||||
|
const char *dotp;
|
||||||
|
if (peername == NULL) {
|
||||||
|
Info1("commonName \"%s\": no peername", cn);
|
||||||
|
return false;
|
||||||
|
} else if (peername[0] == '\0') {
|
||||||
|
Info1("commonName \"%s\": matched by empty peername", cn);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (! (cn[0] == '*' && cn[1] == '.')) {
|
||||||
|
/* normal server name - this is simple */
|
||||||
|
Debug1("commonName \"%s\" has no wildcard", cn);
|
||||||
|
if (strcmp(cn, peername) == 0) {
|
||||||
|
Debug2("commonName \"%s\" matches peername \"%s\"", cn, peername);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Info2("commonName \"%s\" does not match peername \"%s\"", cn, peername);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* wildcard cert */
|
||||||
|
Debug1("commonName \"%s\" is a wildcard name", cn);
|
||||||
|
/* case: just the base domain */
|
||||||
|
if (strcmp(cn+2, peername) == 0) {
|
||||||
|
Debug2("wildcard commonName \"%s\" matches base domain \"%s\"", cn, peername);
|
||||||
|
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) {
|
||||||
|
Info2("commonName \"%s\" does not match subdomain peername \"%s\"", cn, peername);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Debug2("commonName \"%s\" matches subdomain peername \"%s\"", cn, peername);
|
||||||
|
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;
|
||||||
|
unsigned char *text;
|
||||||
|
ind = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
|
||||||
|
if (ind < 0) {
|
||||||
|
Info("no COMMONNAME field in peer certificate");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
entry = X509_NAME_get_entry(name, ind);
|
||||||
|
data = X509_NAME_ENTRY_get_data(entry);
|
||||||
|
text = ASN1_STRING_data(data);
|
||||||
|
return openssl_check_name((const char *)text, peername);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* retrieves certificate provided by peer, sets env vars containing
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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());
|
BIO *bio = BIO_new(BIO_s_mem());
|
||||||
char *buf = NULL, *str;
|
char *buf = NULL, *str;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
@ -1187,59 +1324,69 @@ static int openssl_extract_cert_info(const char *field, X509_NAME *name) {
|
||||||
}
|
}
|
||||||
str[len] = '\0';
|
str[len] = '\0';
|
||||||
Info2("SSL peer cert %s: \"%s\"", field, buf);
|
Info2("SSL peer cert %s: \"%s\"", field, buf);
|
||||||
xiosetenv2("OPENSSL_X509", field, buf, 1);
|
xiosetenv2("OPENSSL_X509", field, buf, 1, NULL);
|
||||||
free(str);
|
free(str);
|
||||||
BIO_free(bio);
|
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;
|
||||||
n = X509_NAME_entry_count(name);
|
n = X509_NAME_entry_count(name);
|
||||||
|
/* extract fields of cert name */
|
||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
X509_NAME_ENTRY *entry;
|
X509_NAME_ENTRY *entry;
|
||||||
char *text;
|
|
||||||
ASN1_STRING *data;
|
|
||||||
ASN1_OBJECT *obj;
|
ASN1_OBJECT *obj;
|
||||||
|
ASN1_STRING *data;
|
||||||
|
unsigned char *text;
|
||||||
int nid;
|
int nid;
|
||||||
entry = X509_NAME_get_entry(name, i);
|
entry = X509_NAME_get_entry(name, i);
|
||||||
data = X509_NAME_ENTRY_get_data(entry);
|
|
||||||
obj = X509_NAME_ENTRY_get_object(entry);
|
obj = X509_NAME_ENTRY_get_object(entry);
|
||||||
|
data = X509_NAME_ENTRY_get_data(entry);
|
||||||
nid = OBJ_obj2nid(obj);
|
nid = OBJ_obj2nid(obj);
|
||||||
text = (char *)ASN1_STRING_data(data);
|
text = ASN1_STRING_data(data);
|
||||||
Debug3("SSL peer cert %s entry: %s=\"%s\"", field, OBJ_nid2ln(nid), text);
|
Debug3("SSL peer cert %s entry: %s=\"%s\"", (field[0]?field:"subject"), OBJ_nid2ln(nid), text);
|
||||||
xiosetenv3("OPENSSL_X509", field, OBJ_nid2ln(nid), text, 0);
|
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, " // ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openssl_handle_peer_certificate(struct single *xfd,
|
static int openssl_handle_peer_certificate(struct single *xfd,
|
||||||
|
const char *peername,
|
||||||
bool opt_ver, int level) {
|
bool opt_ver, int level) {
|
||||||
X509 *peer_cert;
|
X509 *peer_cert;
|
||||||
|
X509_NAME *subjectname, *issuername;
|
||||||
/*ASN1_TIME not_before, not_after;*/
|
/*ASN1_TIME not_before, not_after;*/
|
||||||
|
int extcount, i, ok = 0;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
/* SSL_CTX_add_extra_chain_cert
|
if ((peer_cert = SSL_get_peer_certificate(xfd->para.openssl.ssl)) == NULL) {
|
||||||
SSL_get_verify_result
|
if (opt_ver) {
|
||||||
*/
|
Msg(level, "no peer certificate");
|
||||||
if ((peer_cert = SSL_get_peer_certificate(xfd->para.openssl.ssl)) != NULL) {
|
status = STAT_RETRYLATER;
|
||||||
X509_NAME *name;
|
} else {
|
||||||
if ((name = X509_get_subject_name(peer_cert)) != NULL)
|
Notice("no peer certificate and no check");
|
||||||
openssl_extract_cert_info("subject", name);
|
status = STAT_OK;
|
||||||
if ((name = X509_get_issuer_name(peer_cert)) != NULL)
|
}
|
||||||
openssl_extract_cert_info("issuer", name);
|
return status;
|
||||||
/* I'd like to provide dates too; see
|
|
||||||
http://markmail.org/message/yi4vspp7aeu3xwtu#query:+page:1+mid:jhnl4wklif3pgzqf+state:results */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peer_cert) {
|
/* verify peer certificate (trust, signature, validity dates) */
|
||||||
if (opt_ver) {
|
if (opt_ver) {
|
||||||
long verify_result;
|
long verify_result;
|
||||||
if ((verify_result = sycSSL_get_verify_result(xfd->para.openssl.ssl)) == X509_V_OK) {
|
if ((verify_result = sycSSL_get_verify_result(xfd->para.openssl.ssl)) != X509_V_OK) {
|
||||||
Info("accepted peer certificate");
|
|
||||||
status = STAT_OK;
|
|
||||||
} else {
|
|
||||||
const char *message = NULL;
|
const char *message = NULL;
|
||||||
if (verify_result >= 0 &&
|
if (verify_result >= 0 &&
|
||||||
(size_t)verify_result <
|
(size_t)verify_result <
|
||||||
sizeof(openssl_verify_messages)/sizeof(char*))
|
sizeof(openssl_verify_messages)/sizeof(char*)) {
|
||||||
{
|
|
||||||
message = openssl_verify_messages[verify_result];
|
message = openssl_verify_messages[verify_result];
|
||||||
}
|
}
|
||||||
if (message) {
|
if (message) {
|
||||||
|
@ -1248,21 +1395,93 @@ static int openssl_handle_peer_certificate(struct single *xfd,
|
||||||
Msg1(level, "rejected peer certificate with error %ld", verify_result);
|
Msg1(level, "rejected peer certificate with error %ld", verify_result);
|
||||||
}
|
}
|
||||||
status = STAT_RETRYLATER;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
if (!(meth = X509V3_EXT_get(ext))) break;
|
||||||
|
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 */
|
||||||
|
for ( i=0; ( i<numalts ); i++ ) {
|
||||||
|
/* get a handle to alternative name number i */
|
||||||
|
const GENERAL_NAME *pName = sk_GENERAL_NAME_value (names, i );
|
||||||
|
unsigned char *pBuffer;
|
||||||
|
switch ( pName->type ) {
|
||||||
|
|
||||||
|
case GEN_DNS:
|
||||||
|
ASN1_STRING_to_UTF8(&pBuffer, pName->d.ia5);
|
||||||
|
xiosetenv("OPENSSL_X509V3_SUBJECTALTNAME_DNS", (char *)pBuffer, 2, " // ");
|
||||||
|
if (peername != NULL &&
|
||||||
|
openssl_check_name((char *)pBuffer, /*const char*/peername)) {
|
||||||
|
ok = 1;
|
||||||
|
}
|
||||||
|
OPENSSL_free(pBuffer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Notice("no check of certificate");
|
|
||||||
status = STAT_OK;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (opt_ver) {
|
|
||||||
Msg(level, "no peer certificate");
|
|
||||||
status = STAT_RETRYLATER;
|
|
||||||
} else {
|
|
||||||
Notice("no peer certificate and no check");
|
|
||||||
status = STAT_OK;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!opt_ver) {
|
||||||
|
Notice("option openssl-verify disabled, no check of certificate");
|
||||||
|
X509_free(peer_cert);
|
||||||
|
return STAT_OK;
|
||||||
|
}
|
||||||
|
if (peername == NULL || peername[0] == '\0') {
|
||||||
|
Notice("trusting certificate, no check of commonName");
|
||||||
|
X509_free(peer_cert);
|
||||||
|
return STAT_OK;
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
Notice("trusting certificate, commonName matches");
|
||||||
|
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)) {
|
||||||
|
Error("certificate is valid but its commonName does not match hostname");
|
||||||
|
status = STAT_NORETRY;
|
||||||
|
} else {
|
||||||
|
Notice("trusting certificate, commonName matches");
|
||||||
|
status = STAT_OK;
|
||||||
|
}
|
||||||
X509_free(peer_cert);
|
X509_free(peer_cert);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -1310,7 +1529,8 @@ static int xioSSL_set_fd(struct single *xfd, int level) {
|
||||||
in case of an error condition, this function check forever and retry
|
in case of an error condition, this function check forever and retry
|
||||||
options and ev. sleeps an interval. It returns NORETRY when the caller
|
options and ev. sleeps an interval. It returns NORETRY when the caller
|
||||||
should not retry for any reason. */
|
should not retry for any reason. */
|
||||||
static int xioSSL_connect(struct single *xfd, bool opt_ver, int level) {
|
static int xioSSL_connect(struct single *xfd, const char *opt_commonname,
|
||||||
|
bool opt_ver, int level) {
|
||||||
char error_string[120];
|
char error_string[120];
|
||||||
int errint, status, ret;
|
int errint, status, ret;
|
||||||
unsigned long err;
|
unsigned long err;
|
||||||
|
@ -1355,7 +1575,7 @@ static int xioSSL_connect(struct single *xfd, bool opt_ver, int level) {
|
||||||
break;
|
break;
|
||||||
case SSL_ERROR_SSL:
|
case SSL_ERROR_SSL:
|
||||||
status = openssl_SSL_ERROR_SSL(level, "SSL_connect");
|
status = openssl_SSL_ERROR_SSL(level, "SSL_connect");
|
||||||
if (openssl_handle_peer_certificate(xfd, opt_ver, level/*!*/) < 0) {
|
if (openssl_handle_peer_certificate(xfd, opt_commonname, opt_ver, level/*!*/) < 0) {
|
||||||
return STAT_RETRYLATER;
|
return STAT_RETRYLATER;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* source: xio-openssl.h */
|
/* source: xio-openssl.h */
|
||||||
/* Copyright Gerhard Rieger 2002-2012 */
|
/* Copyright Gerhard Rieger */
|
||||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||||
|
|
||||||
#ifndef __xio_openssl_included
|
#ifndef __xio_openssl_included
|
||||||
|
@ -29,6 +29,7 @@ extern const struct optdesc opt_openssl_compress;
|
||||||
#if WITH_FIPS
|
#if WITH_FIPS
|
||||||
extern const struct optdesc opt_openssl_fips;
|
extern const struct optdesc opt_openssl_fips;
|
||||||
#endif
|
#endif
|
||||||
|
extern const struct optdesc opt_openssl_commonname;
|
||||||
|
|
||||||
extern int
|
extern int
|
||||||
_xioopen_openssl_prepare(struct opt *opts, struct single *xfd,
|
_xioopen_openssl_prepare(struct opt *opts, struct single *xfd,
|
||||||
|
@ -36,9 +37,11 @@ extern int
|
||||||
SSL_CTX **ctx);
|
SSL_CTX **ctx);
|
||||||
extern int
|
extern int
|
||||||
_xioopen_openssl_connect(struct single *xfd, bool opt_ver,
|
_xioopen_openssl_connect(struct single *xfd, bool opt_ver,
|
||||||
|
const char *opt_commonname,
|
||||||
SSL_CTX *ctx, int level);
|
SSL_CTX *ctx, int level);
|
||||||
extern int
|
extern int
|
||||||
_xioopen_openssl_listen(struct single *xfd, bool opt_ver,
|
_xioopen_openssl_listen(struct single *xfd, bool opt_ver,
|
||||||
|
const char *opt_commonname,
|
||||||
SSL_CTX *ctx, int level);
|
SSL_CTX *ctx, int level);
|
||||||
extern int xioclose_openssl(xiofile_t *xfd);
|
extern int xioclose_openssl(xiofile_t *xfd);
|
||||||
extern int xioshutdown_openssl(xiofile_t *xfd, int how);
|
extern int xioshutdown_openssl(xiofile_t *xfd, int how);
|
||||||
|
|
12
xio-socket.c
12
xio-socket.c
|
@ -1741,11 +1741,11 @@ int xiodopacketinfo(struct msghdr *msgh, bool withlog, bool withenv) {
|
||||||
}
|
}
|
||||||
if (withenv) {
|
if (withenv) {
|
||||||
if (*envp) {
|
if (*envp) {
|
||||||
xiosetenv(envp, valp, 1);
|
xiosetenv(envp, valp, 1, NULL);
|
||||||
} else if (!strcasecmp(typp+strlen(typp)-strlen(namp), namp)) {
|
} else if (!strcasecmp(typp+strlen(typp)-strlen(namp), namp)) {
|
||||||
xiosetenv(typp, valp, 1);
|
xiosetenv(typp, valp, 1, NULL);
|
||||||
} else {
|
} else {
|
||||||
xiosetenv2(typp, namp, valp, 1);
|
xiosetenv2(typp, namp, valp, 1, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (++i == num) break;
|
if (++i == num) break;
|
||||||
|
@ -2132,7 +2132,7 @@ int xiosetsockaddrenv(const char *lr,
|
||||||
xiosetsockaddrenv_unix(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
|
xiosetsockaddrenv_unix(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
|
||||||
valuebuff, XIOSOCKADDRENVLEN,
|
valuebuff, XIOSOCKADDRENVLEN,
|
||||||
&sau->un, salen, proto);
|
&sau->un, salen, proto);
|
||||||
xiosetenv(namebuff, valuebuff, 1);
|
xiosetenv(namebuff, valuebuff, 1, NULL);
|
||||||
break;
|
break;
|
||||||
#endif /* WITH_UNIX */
|
#endif /* WITH_UNIX */
|
||||||
#if WITH_IP4
|
#if WITH_IP4
|
||||||
|
@ -2142,7 +2142,7 @@ int xiosetsockaddrenv(const char *lr,
|
||||||
xiosetsockaddrenv_ip4(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
|
xiosetsockaddrenv_ip4(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
|
||||||
valuebuff, XIOSOCKADDRENVLEN,
|
valuebuff, XIOSOCKADDRENVLEN,
|
||||||
&sau->ip4, proto);
|
&sau->ip4, proto);
|
||||||
xiosetenv(namebuff, valuebuff, 1);
|
xiosetenv(namebuff, valuebuff, 1, NULL);
|
||||||
namebuff[strlen(lr)] = '\0'; ++idx;
|
namebuff[strlen(lr)] = '\0'; ++idx;
|
||||||
} while (result > 0);
|
} while (result > 0);
|
||||||
break;
|
break;
|
||||||
|
@ -2155,7 +2155,7 @@ int xiosetsockaddrenv(const char *lr,
|
||||||
xiosetsockaddrenv_ip6(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
|
xiosetsockaddrenv_ip6(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
|
||||||
valuebuff, XIOSOCKADDRENVLEN,
|
valuebuff, XIOSOCKADDRENVLEN,
|
||||||
&sau->ip6, proto);
|
&sau->ip6, proto);
|
||||||
xiosetenv(namebuff, valuebuff, 1);
|
xiosetenv(namebuff, valuebuff, 1, NULL);
|
||||||
namebuff[strlen(lr)] = '\0'; ++idx;
|
namebuff[strlen(lr)] = '\0'; ++idx;
|
||||||
} while (result > 0);
|
} while (result > 0);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -296,6 +296,8 @@ const struct optname optionnames[] = {
|
||||||
IF_TERMIOS("clocal", &opt_clocal)
|
IF_TERMIOS("clocal", &opt_clocal)
|
||||||
IF_ANY ("cloexec", &opt_cloexec)
|
IF_ANY ("cloexec", &opt_cloexec)
|
||||||
IF_ANY ("close", &opt_end_close)
|
IF_ANY ("close", &opt_end_close)
|
||||||
|
IF_OPENSSL("cn", &opt_openssl_commonname)
|
||||||
|
IF_OPENSSL("commonname", &opt_openssl_commonname)
|
||||||
IF_EXEC ("commtype", &opt_commtype)
|
IF_EXEC ("commtype", &opt_commtype)
|
||||||
#if WITH_EXT2 && defined(EXT2_COMPR_FL)
|
#if WITH_EXT2 && defined(EXT2_COMPR_FL)
|
||||||
IF_ANY ("compr", &opt_ext2_compr)
|
IF_ANY ("compr", &opt_ext2_compr)
|
||||||
|
@ -1058,6 +1060,7 @@ const struct optname optionnames[] = {
|
||||||
IF_OPENSSL("openssl-capath", &opt_openssl_capath)
|
IF_OPENSSL("openssl-capath", &opt_openssl_capath)
|
||||||
IF_OPENSSL("openssl-certificate", &opt_openssl_certificate)
|
IF_OPENSSL("openssl-certificate", &opt_openssl_certificate)
|
||||||
IF_OPENSSL("openssl-cipherlist", &opt_openssl_cipherlist)
|
IF_OPENSSL("openssl-cipherlist", &opt_openssl_cipherlist)
|
||||||
|
IF_OPENSSL("openssl-commonname", &opt_openssl_commonname)
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
|
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
|
||||||
IF_OPENSSL("openssl-compress", &opt_openssl_compress)
|
IF_OPENSSL("openssl-compress", &opt_openssl_compress)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* source: xioopts.h */
|
/* source: xioopts.h */
|
||||||
/* Copyright Gerhard Rieger 2001-2012 */
|
/* Copyright Gerhard Rieger */
|
||||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||||
|
|
||||||
#ifndef __xioopts_h_included
|
#ifndef __xioopts_h_included
|
||||||
|
@ -477,6 +477,7 @@ enum e_optcode {
|
||||||
OPT_OPENSSL_CAPATH,
|
OPT_OPENSSL_CAPATH,
|
||||||
OPT_OPENSSL_CERTIFICATE,
|
OPT_OPENSSL_CERTIFICATE,
|
||||||
OPT_OPENSSL_CIPHERLIST,
|
OPT_OPENSSL_CIPHERLIST,
|
||||||
|
OPT_OPENSSL_COMMONNAME,
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
|
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
|
||||||
OPT_OPENSSL_COMPRESS,
|
OPT_OPENSSL_COMPRESS,
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue