mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
OpenSSL client checks SubjectAltName IP addresses
This commit is contained in:
parent
6635e159c4
commit
6128ea36ac
5 changed files with 305 additions and 43 deletions
10
CHANGES
10
CHANGES
|
@ -120,22 +120,24 @@ Testing:
|
|||
* renamed testaddrs() to testfeats(), and introduced new testaddrs()
|
||||
|
||||
New features:
|
||||
<<<<<<< HEAD
|
||||
GOPEN and UNIX-CLIENT addresses now support sockets of type SEQPACKET.
|
||||
Test: GOPENUNIXSEQPACKET
|
||||
Feature suggested by vi0oss.
|
||||
|
||||
Features:
|
||||
The generic setsockopt-int and related options are, in case of
|
||||
listening/accepting addresses, applied to the connected socket(s). To enable
|
||||
setting options on the listening socket, a new option setsockopt-listen
|
||||
has been implemented. See the documentation for info on data types.
|
||||
Tests: SETSOCKOPT SETSOCKOPT_LISTEN
|
||||
Thanks to Steven Danna and Korian Edeline for reporting this issue.
|
||||
=======
|
||||
|
||||
Filan option -S gives short description like -s but with improved
|
||||
format
|
||||
>>>>>>> 7cd82d9... Fixed filan -s, added -S
|
||||
|
||||
Socat OpenSSL client, when server was specified using IP address, did
|
||||
not verify connection on certificates SubjectAltName IP entries.
|
||||
Tests: OPENSSL_SERVERALTAUTH OPENSSL_SERVERALTIP4AUTH OPENSSL_SERVERALTIP6AUTH
|
||||
Fixes Red Hat bug 1805132
|
||||
|
||||
####################### V 1.7.3.4:
|
||||
|
||||
|
|
206
test.sh
206
test.sh
|
@ -99,6 +99,7 @@ REUSEADDR=reuseaddr # use this with LISTEN addresses and bind options
|
|||
# SSL certificate contents
|
||||
TESTCERT_CONF=testcert.conf
|
||||
TESTCERT6_CONF=testcert6.conf
|
||||
TESTALT_CONF=testalt.conf
|
||||
#
|
||||
TESTCERT_COMMONNAME="$LOCALHOST"
|
||||
TESTCERT_COMMONNAME6="$LOCALHOST6"
|
||||
|
@ -123,6 +124,7 @@ commonName=$TESTCERT_COMMONNAME
|
|||
O=$TESTCERT_ORGANIZATIONNAME
|
||||
OU=$TESTCERT_ORGANIZATIONALUNITNAME
|
||||
L=$TESTCERT_LOCALITYNAME
|
||||
|
||||
EOF
|
||||
|
||||
cat >$TESTCERT6_CONF <<EOF
|
||||
|
@ -138,6 +140,36 @@ commonName=$TESTCERT_COMMONNAME6
|
|||
O=$TESTCERT_ORGANIZATIONNAME
|
||||
OU=$TESTCERT_ORGANIZATIONALUNITNAME
|
||||
L=$TESTCERT_LOCALITYNAME
|
||||
|
||||
EOF
|
||||
|
||||
cat >$TESTALT_CONF <<EOF
|
||||
# config for generation of self signed certificate with IP addresses in
|
||||
# SubjectAltNames
|
||||
prompt=no
|
||||
|
||||
[ req ]
|
||||
default_bits = $RSABITS
|
||||
distinguished_name = subject
|
||||
x509_extensions = x509_ext
|
||||
|
||||
[ subject ]
|
||||
countryName=$TESTCERT_COUNTRYNAME
|
||||
commonName=servername
|
||||
O=$TESTCERT_ORGANIZATIONNAME
|
||||
OU=$TESTCERT_ORGANIZATIONALUNITNAME
|
||||
L=$TESTCERT_LOCALITYNAME
|
||||
|
||||
[ x509_ext ]
|
||||
subjectAltName = @alternate_names
|
||||
|
||||
[ alternate_names ]
|
||||
DNS.1 = localhost
|
||||
DNS.2 = localhost4
|
||||
DNS.3 = localhost6
|
||||
IP.1 = 127.0.0.1
|
||||
IP.2 = ::1
|
||||
|
||||
EOF
|
||||
|
||||
# clean up from previous runs
|
||||
|
@ -145,7 +177,7 @@ rm -f testcli.{crt,key,pem}
|
|||
rm -f testsrv.{crt,key,pem}
|
||||
rm -f testcli6.{crt,key,pem}
|
||||
rm -f testsrv6.{crt,key,pem}
|
||||
|
||||
rm -f testalt.{crt,key,pem}
|
||||
|
||||
CAT=cat
|
||||
OD_C="od -c"
|
||||
|
@ -2402,6 +2434,7 @@ gentestcert () {
|
|||
fi
|
||||
if [ -s $name.key -a -s $name.crt -a -s $name.pem ]; then return; fi
|
||||
openssl genrsa $OPENSSL_RAND -out $name.key $RSABITS >/dev/null 2>&1
|
||||
#openssl req -new -config $TESTCERT_CONF -key $name.key -x509 -out $name.crt -days 3653 -extensions v3_ca >/dev/null 2>&1
|
||||
openssl req -new -config $TESTCERT_CONF -key $name.key -x509 -out $name.crt -days 3653 >/dev/null 2>&1
|
||||
cat $name.key $name.crt testcert.dh >$name.pem
|
||||
}
|
||||
|
@ -2437,6 +2470,18 @@ gentestcert6 () {
|
|||
cat $name.key $name.crt >$name.pem
|
||||
}
|
||||
|
||||
# generate a server certificate and key with SubjectAltName
|
||||
gentestaltcert () {
|
||||
local name="$1"
|
||||
if ! [ -f testcert.dh ]; then
|
||||
openssl dhparam -out testcert.dh $RSABITS
|
||||
fi
|
||||
if [ -s $name.key -a -s $name.crt -a -s $name.pem ]; then return; fi
|
||||
openssl genrsa $OPENSSL_RAND -out $name.key $RSABITS >/dev/null 2>&1
|
||||
openssl req -new -config $TESTALT_CONF -key $name.key -x509 -out $name.crt -days 3653 >/dev/null 2>&1
|
||||
cat $name.key $name.crt testcert.dh >$name.pem
|
||||
}
|
||||
|
||||
|
||||
NAME=UNISTDIO
|
||||
case "$TESTS " in
|
||||
|
@ -4209,7 +4254,6 @@ te="$td/test$N.stderr"
|
|||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD2="$TRACE $SOCAT $opts exec:'openssl s_server -accept "$PORT" -quiet -cert testsrv.pem' pipe"
|
||||
#! CMD="$TRACE $SOCAT $opts - openssl:$LOCALHOST:$PORT"
|
||||
CMD="$TRACE $SOCAT $opts - openssl:$LOCALHOST:$PORT,pf=ip4,verify=0,$SOCAT_EGD"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD2 2>\"${te}1\" &"
|
||||
|
@ -4413,7 +4457,7 @@ OPENSSL6SERVER OPENSSL tcp6 OPENSSL-LISTEN:\$PORT,pf=ip6,$SOCAT_EGD,cert=tests
|
|||
NAME=OPENSSL_SERVERAUTH
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
|
||||
TEST="$NAME: openssl server authentication"
|
||||
TEST="$NAME: OpenSSL server authentication (hostname)"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! testfeats openssl >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N
|
||||
|
@ -4430,19 +4474,19 @@ tf="$td/test$N.stdout"
|
|||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD2="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe"
|
||||
CMD="$TRACE $SOCAT $opts - openssl:$LOCALHOST:$PORT,verify=1,cafile=testsrv.crt,$SOCAT_EGD"
|
||||
CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,$SOCAT_EGD,cert=testsrv.crt,key=testsrv.key,verify=0 pipe"
|
||||
CMD1="$TRACE $SOCAT $opts - OPENSSL:$LOCALHOST:$PORT,verify=1,cafile=testsrv.crt,$SOCAT_EGD"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD2 2>\"${te}1\" &"
|
||||
eval "$CMD0 2>\"${te}0\" &"
|
||||
pid=$! # background process id
|
||||
waittcp4port $PORT
|
||||
echo "$da" |$CMD >$tf 2>"${te}2"
|
||||
echo "$da" |$CMD1 >$tf 2>"${te}1"
|
||||
if ! echo "$da" |diff - "$tf" >"$tdiff"; then
|
||||
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
|
||||
echo "$CMD2 &"
|
||||
echo "$CMD"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0"
|
||||
echo "$CMD1"
|
||||
cat "${te}1"
|
||||
cat "${te}2"
|
||||
cat "$tdiff"
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
|
@ -14069,6 +14113,148 @@ PORT=$((PORT+1))
|
|||
N=$((N+1))
|
||||
|
||||
|
||||
NAME=OPENSSL_SERVERALTAUTH
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
|
||||
TEST="$NAME: OpenSSL server authentication with SubjectAltName (hostname)"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! testfeats openssl >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! testfeats 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))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
gentestaltcert testalt
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,$SOCAT_EGD,cert=testalt.crt,key=testalt.key,verify=0 pipe"
|
||||
CMD1="$TRACE $SOCAT $opts - OPENSSL:$LOCALHOST:$PORT,verify=1,cafile=testalt.crt,$SOCAT_EGD"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD0 2>\"${te}0\" &"
|
||||
pid=$! # background process id
|
||||
waittcp4port $PORT
|
||||
echo "$da" |$CMD1 >$tf 2>"${te}1"
|
||||
if ! echo "$da" |diff - "$tf" >"$tdiff"; then
|
||||
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
|
||||
echo "$CMD0 &" >&2
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1" >&2
|
||||
cat "${te}1" >&2
|
||||
cat "$tdiff" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi
|
||||
numOK=$((numOK+1))
|
||||
fi
|
||||
kill $pid 2>/dev/null
|
||||
wait
|
||||
fi ;; # NUMCOND, feats
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
N=$((N+1))
|
||||
|
||||
NAME=OPENSSL_SERVERALTIP4AUTH
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp4%*|*%ip4%*|*%$NAME%*)
|
||||
TEST="$NAME: OpenSSL server authentication with SubjectAltName (IPv4 address)"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! testfeats openssl >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! testfeats listen tcp ip4 openssl >/dev/null || ! runsip4 >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv4 not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
gentestaltcert testalt
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,$REUSEADDR,$SOCAT_EGD,cert=testalt.crt,key=testalt.key,verify=0 pipe"
|
||||
CMD1="$TRACE $SOCAT $opts - OPENSSL:127.0.0.1:$PORT,verify=1,cafile=testalt.crt,$SOCAT_EGD"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD0 2>\"${te}0\" &"
|
||||
pid=$! # background process id
|
||||
waittcp4port $PORT
|
||||
echo "$da" |$CMD1 >$tf 2>"${te}1"
|
||||
if ! echo "$da" |diff - "$tf" >"$tdiff"; then
|
||||
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
|
||||
echo "$CMD0 &" >&2
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1" >&2
|
||||
cat "${te}1" >&2
|
||||
cat "$tdiff" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi
|
||||
numOK=$((numOK+1))
|
||||
fi
|
||||
kill $pid 2>/dev/null
|
||||
wait
|
||||
fi ;; # NUMCOND, feats
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
N=$((N+1))
|
||||
|
||||
NAME=OPENSSL_SERVERALTIP6AUTH
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%openssl%*|*%tcp%*|*%tcp6%*|*%ip6%*|*%$NAME%*)
|
||||
TEST="$NAME: OpenSSL server authentication with SubjectAltName (IPv6 address)"
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! testfeats openssl >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}OPENSSL not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! testfeats listen tcp ip6 openssl >/dev/null || ! runsip6 >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}TCP/IPv6 not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
gentestaltcert testalt
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD0="$TRACE $SOCAT $opts OPENSSL-LISTEN:$PORT,pf=ip6,$REUSEADDR,$SOCAT_EGD,cert=testalt.crt,key=testalt.key,verify=0 pipe"
|
||||
CMD1="$TRACE $SOCAT $opts - OPENSSL:[::1]:$PORT,verify=1,cafile=testalt.crt,$SOCAT_EGD"
|
||||
printf "test $F_n $TEST... " $N
|
||||
eval "$CMD0 2>\"${te}0\" &"
|
||||
pid=$! # background process id
|
||||
waittcp6port $PORT
|
||||
echo "$da" |$CMD1 >$tf 2>"${te}1"
|
||||
if ! echo "$da" |diff - "$tf" >"$tdiff"; then
|
||||
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
|
||||
echo "$CMD0 &" >&2
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1" >&2
|
||||
cat "${te}1" >&2
|
||||
cat "$tdiff" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi
|
||||
numOK=$((numOK+1))
|
||||
fi
|
||||
kill $pid 2>/dev/null
|
||||
wait
|
||||
fi ;; # NUMCOND, feats
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
N=$((N+1))
|
||||
|
||||
|
||||
##################################################################################
|
||||
#=================================================================================
|
||||
# here come tests that might affect your systems integrity. Put normal tests
|
||||
|
|
26
xio-ip6.c
26
xio-ip6.c
|
@ -75,6 +75,32 @@ const struct optdesc opt_ipv6_recvtclass = { "ipv6-recvtclass", "recvtclass", OP
|
|||
const struct optdesc opt_ipv6_recvpathmtu = { "ipv6-recvpathmtu", "recvpathmtu", OPT_IPV6_RECVPATHMTU, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVPATHMTU };
|
||||
#endif
|
||||
|
||||
/* Returns canonical form of IPv6 address.
|
||||
IPv6 address may bei enclose in brackets.
|
||||
Returns STAT_OK on success, STAT_NORETRY on failure. */
|
||||
int xioip6_pton(const char *src, struct in6_addr *dst) {
|
||||
union sockaddr_union sockaddr;
|
||||
socklen_t sockaddrlen = sizeof(sockaddr);
|
||||
|
||||
if (src[0] == '[') {
|
||||
char plainaddr[INET6_ADDRSTRLEN];
|
||||
char *clos;
|
||||
|
||||
strncpy(plainaddr, src+1, INET6_ADDRSTRLEN);
|
||||
plainaddr[INET6_ADDRSTRLEN-1] = '\0';
|
||||
if ((clos = strchr(plainaddr, ']')) != NULL)
|
||||
*clos = '\0';
|
||||
return xioip6_pton(plainaddr, dst);
|
||||
}
|
||||
if (xiogetaddrinfo(src, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen,
|
||||
0, 0)
|
||||
!= STAT_OK) {
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
*dst = sockaddr.ip6.sin6_addr;
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
int xioparsenetwork_ip6(const char *rangename, struct xiorange *range) {
|
||||
char *delimpos; /* absolute address of delimiter */
|
||||
size_t delimind; /* index of delimiter in string */
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
|
||||
#if WITH_IP6
|
||||
|
||||
#ifndef INET6_ADDRSTRLEN
|
||||
# define INET6_ADDRSTRLEN 46
|
||||
#endif
|
||||
|
||||
extern const struct optdesc opt_ipv6_v6only;
|
||||
extern const struct optdesc opt_ipv6_join_group;
|
||||
extern const struct optdesc opt_ipv6_pktinfo;
|
||||
|
@ -27,6 +31,7 @@ extern const struct optdesc opt_ipv6_tclass;
|
|||
extern const struct optdesc opt_ipv6_recvtclass;
|
||||
extern const struct optdesc opt_ipv6_recvpathmtu;
|
||||
|
||||
extern int xioip6_pton(const char *src, struct in6_addr *dst);
|
||||
extern
|
||||
int xioparsenetwork_ip6(const char *rangename, struct xiorange *range);
|
||||
extern int xiorange_ip6andmask(struct xiorange *range);
|
||||
|
|
101
xio-openssl.c
101
xio-openssl.c
|
@ -16,6 +16,8 @@
|
|||
#include "xio-listen.h"
|
||||
#include "xio-udp.h"
|
||||
#include "xio-ipapp.h"
|
||||
#include "xio-ip6.h"
|
||||
|
||||
#include "xio-openssl.h"
|
||||
|
||||
/* the openssl library requires a file descriptor for external communications.
|
||||
|
@ -1534,31 +1536,30 @@ static int openssl_setenv_cert_fields(const char *field, X509_NAME *name) {
|
|||
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) {
|
||||
static bool openssl_check_name(const char *nametype, const char *cn, const char *peername) {
|
||||
const char *dotp;
|
||||
if (peername == NULL) {
|
||||
Info1("commonName \"%s\": no peername", cn);
|
||||
Info2("%s \"%s\": no peername", nametype, cn);
|
||||
return false;
|
||||
} else if (peername[0] == '\0') {
|
||||
Info1("commonName \"%s\": matched by empty peername", cn);
|
||||
Info2("%s \"%s\": matched by empty peername", nametype, 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);
|
||||
Debug3("%s \"%s\" matches peername \"%s\"", nametype, cn, peername);
|
||||
return true;
|
||||
} else {
|
||||
Info2("commonName \"%s\" does not match peername \"%s\"", cn, peername);
|
||||
Info3("%s \"%s\" does not match peername \"%s\"", nametype, cn, peername);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* wildcard cert */
|
||||
Debug1("commonName \"%s\" is a wildcard name", cn);
|
||||
Debug2("%s \"%s\" is a wildcard name", nametype, cn);
|
||||
/* case: just the base domain */
|
||||
if (strcmp(cn+2, peername) == 0) {
|
||||
Debug2("wildcard commonName \"%s\" matches base domain \"%s\"", cn, peername);
|
||||
Debug3("wildcard %s \"%s\" matches base domain \"%s\"", nametype, cn, peername);
|
||||
return true;
|
||||
}
|
||||
/* case: subdomain; only one level! */
|
||||
|
@ -1569,10 +1570,10 @@ static bool openssl_check_name(const char *cn, const char *peername) {
|
|||
return false;
|
||||
}
|
||||
if (strcmp(cn+1, dotp) != 0) {
|
||||
Info2("commonName \"%s\" does not match subdomain peername \"%s\"", cn, peername);
|
||||
Info3("%s \"%s\" does not match subdomain peername \"%s\"", nametype, cn, peername);
|
||||
return false;
|
||||
}
|
||||
Debug2("commonName \"%s\" matches subdomain peername \"%s\"", cn, peername);
|
||||
Debug3("%s \"%s\" matches subdomain peername \"%s\"", nametype, cn, peername);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1595,7 +1596,7 @@ static bool openssl_check_peername(X509_NAME *name, const char *peername) {
|
|||
#else
|
||||
text = ASN1_STRING_data(data);
|
||||
#endif
|
||||
return openssl_check_name((const char *)text, peername);
|
||||
return openssl_check_name("commonName", (const char *)text, peername);
|
||||
}
|
||||
|
||||
/* retrieves certificate provided by peer, sets env vars containing
|
||||
|
@ -1605,6 +1606,9 @@ static bool openssl_check_peername(X509_NAME *name, const char *peername) {
|
|||
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.
|
||||
*/
|
||||
/* 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 */
|
||||
static int openssl_handle_peer_certificate(struct single *xfd,
|
||||
const char *peername,
|
||||
bool opt_ver, int level) {
|
||||
|
@ -1658,9 +1662,17 @@ static int openssl_handle_peer_certificate(struct single *xfd,
|
|||
openssl_setenv_cert_name("issuer", issuername);
|
||||
}
|
||||
|
||||
if (!opt_ver) {
|
||||
Notice("option openssl-verify disabled, no check of certificate");
|
||||
X509_free(peer_cert);
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
/* 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
|
||||
and the GEN_IPADD from
|
||||
http://openssl.6102.n7.nabble.com/reading-IP-addresses-from-Subject-Alternate-Name-extension-td29245.html
|
||||
*/
|
||||
if ((extcount = X509_get_ext_count(peer_cert)) > 0) {
|
||||
for (i = 0; !ok && i < extcount; ++i) {
|
||||
|
@ -1680,50 +1692,81 @@ static int openssl_handle_peer_certificate(struct single *xfd,
|
|||
/* 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++ ) {
|
||||
for (i = 0; i < numalts; ++i) {
|
||||
/* get a handle to alternative name number i */
|
||||
const GENERAL_NAME *pName = sk_GENERAL_NAME_value (names, i );
|
||||
const GENERAL_NAME *pName = sk_GENERAL_NAME_value (names, i);
|
||||
unsigned char *pBuffer;
|
||||
switch ( pName->type ) {
|
||||
switch (pName->type) {
|
||||
|
||||
case GEN_DNS:
|
||||
ASN1_STRING_to_UTF8(&pBuffer,
|
||||
pName->d.ia5);
|
||||
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)) {
|
||||
openssl_check_name("subjectAltName", (char *)pBuffer, /*const char*/peername)) {
|
||||
ok = 1;
|
||||
}
|
||||
OPENSSL_free(pBuffer);
|
||||
break;
|
||||
|
||||
default: continue;
|
||||
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;
|
||||
case 16: /* IPv6 */
|
||||
inet_ntop(AF_INET6, data, aBuffer, sizeof(aBuffer));
|
||||
xioip6_pton(peername, &ip6bin);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (ok) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
Error("certificate is valid but its commonName does not match hostname");
|
||||
Error1("certificate is valid but its commonName does not match hostname \"%s\"",
|
||||
peername);
|
||||
status = STAT_NORETRY;
|
||||
} else {
|
||||
Notice("trusting certificate, commonName matches");
|
||||
|
|
Loading…
Reference in a new issue