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:
parent
cf3f6403bc
commit
05afec429d
8
CHANGES
8
CHANGES
@ -18,6 +18,14 @@ security:
|
||||
Turn off nested signal handler invocations
|
||||
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:
|
||||
Bind with ABSTRACT commands used non-abstract namespace (Linux).
|
||||
Test: ABSTRACT_BIND
|
||||
|
36
sysutils.c
36
sysutils.c
@ -726,6 +726,42 @@ int xiosetenv2(const char *varname, const char *varname2, const char *value,
|
||||
# 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 */
|
||||
int xiosetenvulong(const char *varname, unsigned long value, int overwrite) {
|
||||
|
@ -92,6 +92,9 @@ extern int xiosetenv(const char *varname, const char *value, int overwrite);
|
||||
extern int
|
||||
xiosetenv2(const char *varname, const char *varname2, const char *value,
|
||||
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,
|
||||
int overwrite);
|
||||
extern int xiosetenvushort(const char *varname, unsigned short value,
|
||||
|
99
test.sh
99
test.sh
@ -78,6 +78,9 @@ LOCALHOST6=[::1]
|
||||
PROTO=$((144+RANDOM/2048))
|
||||
PORT=12002
|
||||
SOURCEPORT=2002
|
||||
TESTCERT_CONF=testcert.conf
|
||||
TESTCERT_SUBJECT="/C=XY"
|
||||
TESTCERT_ISSUER="/C=XY"
|
||||
CAT=cat
|
||||
OD_C="od -c"
|
||||
# precision sleep; takes seconds with fractional part
|
||||
@ -2204,7 +2207,7 @@ gentestcert () {
|
||||
local name="$1"
|
||||
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 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
|
||||
}
|
||||
|
||||
@ -2214,7 +2217,7 @@ gentestdsacert () {
|
||||
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 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
|
||||
}
|
||||
|
||||
@ -11448,6 +11451,98 @@ PORT=$((PORT+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
|
||||
while read addr fileopt addropts proto diropt ADDR2; do
|
||||
|
@ -602,7 +602,7 @@ int _xioopen_openssl_listen(struct single *xfd,
|
||||
ERR_lib_error_string(err), ERR_func_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;
|
||||
case SSL_ERROR_SSL:
|
||||
@ -1042,22 +1042,59 @@ static const char *openssl_verify_messages[] = {
|
||||
/* 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,
|
||||
bool opt_ver, int level) {
|
||||
X509 *peer_cert;
|
||||
char *str;
|
||||
char buff[2048]; /* hold peer certificate */
|
||||
/*ASN1_TIME not_before, not_after;*/
|
||||
int status;
|
||||
|
||||
/* SSL_CTX_add_extra_chain_cert
|
||||
SSL_get_verify_result
|
||||
*/
|
||||
if ((peer_cert = SSL_get_peer_certificate(xfd->para.openssl.ssl)) != NULL) {
|
||||
Debug("peer certificate:");
|
||||
if ((str = X509_NAME_oneline(X509_get_subject_name(peer_cert), buff, sizeof(buff))) != NULL)
|
||||
Debug1("\tsubject: %s", str); /*free (str); SIGSEGV*/
|
||||
if ((str = X509_NAME_oneline(X509_get_issuer_name(peer_cert), buff, sizeof(buff))) != NULL)
|
||||
Debug1("\tissuer: %s", str); /*free (str); SIGSEGV*/
|
||||
X509_NAME *name;
|
||||
if ((name = X509_get_subject_name(peer_cert)) != NULL)
|
||||
openssl_extract_cert_info("subject", name);
|
||||
if ((name = X509_get_issuer_name(peer_cert)) != NULL)
|
||||
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) {
|
||||
@ -1192,6 +1229,7 @@ ssize_t xioread_openssl(struct single *pipe, void *buff, size_t bufsiz) {
|
||||
case SSL_ERROR_NONE:
|
||||
/* this is not an error, but I dare not continue for security reasons*/
|
||||
Error("ok");
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
Error("connection closed by peer");
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user