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
|
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
|
||||||
|
36
sysutils.c
36
sysutils.c
@ -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) {
|
||||||
|
@ -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
99
test.sh
@ -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
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user