1
0
mirror of https://github.com/moparisthebest/socat synced 2024-12-21 22:48:48 -05:00

OpenSSL peer certificate subject,issuer details are passed to env

This commit is contained in:
Gerhard Rieger 2015-01-12 23:11:26 +01:00
parent cf3f6403bc
commit 05afec429d
5 changed files with 190 additions and 10 deletions

View File

@ -18,6 +18,14 @@ 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.
new features:
OpenSSL addresses set couple of environment variables from values in
peer certificate, e.g.:
SOCAT_OPENSSL_X509_SUBJECT, SOCAT_OPENSSL_X509_ISSUER,
SOCAT_OPENSSL_X509_COMMONNAME,
SOCAT_OPENSSL_X509V3_SUBJECTALTNAME_DNS
Tests: ENV_OPENSSL_{CLIENT,SERVER}_X509_*
corrections: corrections:
Bind with ABSTRACT commands used non-abstract namespace (Linux). Bind with ABSTRACT commands used non-abstract namespace (Linux).
Test: ABSTRACT_BIND Test: ABSTRACT_BIND

View File

@ -726,6 +726,42 @@ int xiosetenv2(const char *varname, const char *varname2, const char *value,
# undef XIO_ENVNAMELEN # undef XIO_ENVNAMELEN
} }
int xiosetenv3(const char *varname, const char *varname2, const char *varname3,
const char *value,
int overwrite) {
# 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(progname);
strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
l += 1;
strncat(envname+l, varname, XIO_ENVNAMELEN-l-1);
l += strlen(envname+l);
strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
l += 1;
strncat(envname+l, varname2, XIO_ENVNAMELEN-l-1);
l += strlen(envname+l);
strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
l += 1;
strncat(envname+l, varname3, XIO_ENVNAMELEN-l-1);
l += strlen(envname+l);
for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
if (Setenv(envname, value, overwrite) < 0) {
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
}
/* like xiosetenv(), but uses an unsigned long value */ /* like xiosetenv(), but uses an unsigned long value */
int xiosetenvulong(const char *varname, unsigned long value, int overwrite) { int xiosetenvulong(const char *varname, unsigned long value, int overwrite) {

View File

@ -92,6 +92,9 @@ extern int xiosetenv(const char *varname, const char *value, int overwrite);
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);
extern int
xiosetenv3(const char *varname, const char *varname2, const char *varname3,
const char *value, int overwrite);
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,

99
test.sh
View File

@ -78,6 +78,9 @@ LOCALHOST6=[::1]
PROTO=$((144+RANDOM/2048)) PROTO=$((144+RANDOM/2048))
PORT=12002 PORT=12002
SOURCEPORT=2002 SOURCEPORT=2002
TESTCERT_CONF=testcert.conf
TESTCERT_SUBJECT="/C=XY"
TESTCERT_ISSUER="/C=XY"
CAT=cat CAT=cat
OD_C="od -c" OD_C="od -c"
# precision sleep; takes seconds with fractional part # precision sleep; takes seconds with fractional part
@ -2204,7 +2207,7 @@ gentestcert () {
local name="$1" local name="$1"
if [ -s $name.key -a -s $name.crt -a -s $name.pem ]; then return; fi if [ -s $name.key -a -s $name.crt -a -s $name.pem ]; then return; fi
openssl genrsa $OPENSSL_RAND -out $name.key 768 >/dev/null 2>&1 openssl genrsa $OPENSSL_RAND -out $name.key 768 >/dev/null 2>&1
openssl req -new -config testcert.conf -key $name.key -x509 -out $name.crt -days 3653 >/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 >$name.pem cat $name.key $name.crt >$name.pem
} }
@ -2214,7 +2217,7 @@ gentestdsacert () {
if [ -s $name.key -a -s $name.crt -a -s $name.pem ]; then return; fi if [ -s $name.key -a -s $name.crt -a -s $name.pem ]; then return; fi
openssl dsaparam -out $name-dsa.pem 512 >/dev/null 2>&1 openssl dsaparam -out $name-dsa.pem 512 >/dev/null 2>&1
openssl dhparam -dsaparam -out $name-dh.pem 512 >/dev/null 2>&1 openssl dhparam -dsaparam -out $name-dh.pem 512 >/dev/null 2>&1
openssl req -newkey dsa:$name-dsa.pem -keyout $name.key -nodes -x509 -config testcert.conf -out $name.crt -days 3653 >/dev/null 2>&1 openssl req -newkey dsa:$name-dsa.pem -keyout $name.key -nodes -x509 -config $TESTCERT_CONF -out $name.crt -days 3653 >/dev/null 2>&1
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
} }
@ -11448,6 +11451,98 @@ PORT=$((PORT+1))
N=$((N+1)) N=$((N+1))
#set -xv
# test: OPENSSL sets of environment variables with important values of peer certificate
unset SOCAT_OPENSSL_X509_SUBJECT SOCAT_OPENSSL_X509_ISSUER
while read SSLDIST MODE MODULE FIELD VALUE TESTADDRESS PEERADDRESS; do
if [ -z "$SSLDIST" ] || [[ "$SSLDIST" == \#* ]]; then continue; fi
#
test_proto="$(echo "$KEYW" |tr A-Z a-z)"
NAME="ENV_${SSLDIST}_${MODE}_${MODULE}_${FIELD}"
case "$TESTS" in
*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%$SSLDIST%*|*%envvar%*|*%$NAME%*)
TEST="$NAME: $SSLDIST generates environment variable SOCAT_${SSLDIST}_${MODULE}_${FIELD} with correct value"
# have a server accepting a connection and invoking some shell code. The shell
# code extracts and prints the SOCAT related environment vars.
# outside code then checks if the environment contains the variables correctly
# describing the desired field.
if ! eval $NUMCOND; then :;
elif ! feat=$(testaddrs $FEAT); then
$PRINTF "test $F_n $TEST... ${YELLOW}$(echo "$feat" |tr a-z A-Z) not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
gentestcert testsrv
gentestcert testcli
#CMD0="$SOCAT $opts -u ${SSLDIST}-LISTEN:$PORT,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 system:\"echo SOCAT_${SSLDIST}_${MODULE}_${FIELD}=\\\$SOCAT_${SSLDIST}_${MODULE}_${FIELD}; sleep 1\""
test_proto=tcp4
case "$MODE" in
SERVER)
CMD0="$SOCAT $opts -u $TESTADDRESS system:\"echo SOCAT_${SSLDIST}_${MODULE}_${FIELD}=\\\$SOCAT_${SSLDIST}_${MODULE}_${FIELD}; sleep 1\""
CMD1="$SOCAT $opts -u /dev/null $PEERADDRESS"
printf "test $F_n $TEST... " $N
eval "$CMD0 2>\"${te}0\" >\"$tf\" &"
pid0=$!
wait${test_proto}port $PORT 1
$CMD1 2>"${te}1"
rc1=$?
waitfile "$tf" 2
kill $pid0 2>/dev/null; wait
;;
CLIENT)
CMD0="$SOCAT $opts -u /dev/null $PEERADDRESS"
CMD1="$SOCAT $opts -u $TESTADDRESS system:\"echo SOCAT_${SSLDIST}_${MODULE}_${FIELD}=\\\$SOCAT_${SSLDIST}_${MODULE}_${FIELD}; sleep 1\""
printf "test $F_n $TEST... " $N
$CMD0 2>"${te}0" &
pid0=$!
wait${test_proto}port $PORT 1
eval "$CMD1 2>\"${te}1\" >\"$tf\""
rc1=$?
waitfile "$tf" 2
kill $pid0 2>/dev/null; wait
;;
esac
if [ $rc1 != 0 ]; then
$PRINTF "$NO_RESULT (client failed):\n"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numCANT=$((numCANT+1))
elif [ "$(grep SOCAT_${SSLDIST}_${MODULE}_${FIELD} "${tf}" |sed -e 's/^[^=]*=//' |sed -e "s/[\"']//g")" = "$VALUE" ]; then
$PRINTF "$OK\n"
if [ "$debug" ]; then
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
fi
numOK=$((numOK+1))
else
$PRINTF "$FAILED\n"
echo "$CMD0 &"
cat "${te}0"
echo "$CMD1"
cat "${te}1"
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
fi
fi # NUMCOND, feats
;;
esac
N=$((N+1))
#set +xv
#
done <<<"
OPENSSL SERVER X509 SUBJECT $TESTCERT_SUBJECT OPENSSL-LISTEN:$PORT,so-reuseaddr,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1
OPENSSL SERVER X509 ISSUER $TESTCERT_ISSUER OPENSSL-LISTEN:$PORT,so-reuseaddr,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1 OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1
OPENSSL CLIENT X509 SUBJECT $TESTCERT_SUBJECT OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1 OPENSSL-LISTEN:$PORT,so-reuseaddr,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1
OPENSSL CLIENT X509 ISSUER $TESTCERT_ISSUER OPENSSL-CONNECT:$LOCALHOST:$PORT,cert=testcli.pem,cafile=testsrv.crt,verify=1 OPENSSL-LISTEN:$PORT,so-reuseaddr,bind=$LOCALHOST,cert=testsrv.pem,cafile=testcli.crt,verify=1
"
set +xv
############################################################################### ###############################################################################
# tests: option umask with "passive" NAMED group addresses # tests: option umask with "passive" NAMED group addresses
while read addr fileopt addropts proto diropt ADDR2; do while read addr fileopt addropts proto diropt ADDR2; do

View File

@ -602,7 +602,7 @@ int _xioopen_openssl_listen(struct single *xfd,
ERR_lib_error_string(err), ERR_func_error_string(err), ERR_lib_error_string(err), ERR_func_error_string(err),
ERR_reason_error_string(err)); ERR_reason_error_string(err));
} }
/* Msg1(level, "SSL_connect(): %s", ERR_error_string(e, buf));*/ /* Msg1(level, "SSL_accept(): %s", ERR_error_string(e, buf));*/
} }
break; break;
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
@ -1042,22 +1042,59 @@ 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;
{
BIO *bio = BIO_new(BIO_s_mem());
char *buf = NULL, *str;
size_t len;
X509_NAME_print_ex(bio, name, 0, XN_FLAG_ONELINE&~ASN1_STRFLGS_ESC_MSB); /* rc not documented */
len = BIO_get_mem_data (bio, &buf);
if ((str = Malloc(len+1)) == NULL) {
BIO_free(bio);
return -1;
}
str[len] = '\0';
Info2("SSL peer cert %s: \"%s\"", field, buf);
xiosetenv2("OPENSSL_X509", field, buf, 1);
free(str);
BIO_free(bio);
}
n = X509_NAME_entry_count(name);
for (i = 0; i < n; ++i) {
X509_NAME_ENTRY *entry;
char *text;
ASN1_STRING *data;
ASN1_OBJECT *obj;
int nid;
entry = X509_NAME_get_entry(name, i);
data = X509_NAME_ENTRY_get_data(entry);
obj = X509_NAME_ENTRY_get_object(entry);
nid = OBJ_obj2nid(obj);
text = (char *)ASN1_STRING_data(data);
Debug3("SSL peer cert %s entry: %s=\"%s\"", field, OBJ_nid2ln(nid), text);
xiosetenv3("OPENSSL_X509", field, OBJ_nid2ln(nid), text, 0);
}
return 0;
}
static int openssl_handle_peer_certificate(struct single *xfd, static int openssl_handle_peer_certificate(struct single *xfd,
bool opt_ver, int level) { bool opt_ver, int level) {
X509 *peer_cert; X509 *peer_cert;
char *str; /*ASN1_TIME not_before, not_after;*/
char buff[2048]; /* hold peer certificate */
int status; int status;
/* SSL_CTX_add_extra_chain_cert /* SSL_CTX_add_extra_chain_cert
SSL_get_verify_result SSL_get_verify_result
*/ */
if ((peer_cert = SSL_get_peer_certificate(xfd->para.openssl.ssl)) != NULL) { if ((peer_cert = SSL_get_peer_certificate(xfd->para.openssl.ssl)) != NULL) {
Debug("peer certificate:"); X509_NAME *name;
if ((str = X509_NAME_oneline(X509_get_subject_name(peer_cert), buff, sizeof(buff))) != NULL) if ((name = X509_get_subject_name(peer_cert)) != NULL)
Debug1("\tsubject: %s", str); /*free (str); SIGSEGV*/ openssl_extract_cert_info("subject", name);
if ((str = X509_NAME_oneline(X509_get_issuer_name(peer_cert), buff, sizeof(buff))) != NULL) if ((name = X509_get_issuer_name(peer_cert)) != NULL)
Debug1("\tissuer: %s", str); /*free (str); SIGSEGV*/ openssl_extract_cert_info("issuer", name);
/* I'd like to provide dates too; see
http://markmail.org/message/yi4vspp7aeu3xwtu#query:+page:1+mid:jhnl4wklif3pgzqf+state:results */
} }
if (peer_cert) { if (peer_cert) {
@ -1192,6 +1229,7 @@ ssize_t xioread_openssl(struct single *pipe, void *buff, size_t bufsiz) {
case SSL_ERROR_NONE: case SSL_ERROR_NONE:
/* this is not an error, but I dare not continue for security reasons*/ /* this is not an error, but I dare not continue for security reasons*/
Error("ok"); Error("ok");
break;
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
Error("connection closed by peer"); Error("connection closed by peer");
break; break;