diff options
Diffstat (limited to 'src')
87 files changed, 6794 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..f1f124b --- /dev/null +++ b/src/Makefile @@ -0,0 +1,351 @@ +# Don't edit Makefile! Use conf-* for configuration. + +SHELL=/bin/sh + +default: it + +auto-str: \ +load auto-str.o + ./load auto-str + +auto-str.o: \ +compile auto-str.c + ./compile auto-str.c + +auto_cadir.c: \ +auto-str ../conf-cadir + ./auto-str auto_cadir "`head -1 ../conf-cadir`" > auto_cadir.c + +auto_cadir.o: \ +compile auto_cadir.c + ./compile auto_cadir.c + +auto_cafile.c: \ +auto-str ../conf-cafile + ./auto-str auto_cafile "`head -1 ../conf-cafile`" > auto_cafile.c + +auto_cafile.o: \ +compile auto_cafile.c + ./compile auto_cafile.c + +auto_ccafile.c: \ +auto-str ../conf-ccafile + ./auto-str auto_ccafile "`head -1 ../conf-ccafile`" > auto_ccafile.c + +auto_ccafile.o: \ +compile auto_ccafile.c + ./compile auto_ccafile.c + +auto_certchainfile.c: \ +auto-str ../conf-certchainfile + ./auto-str auto_certchainfile "`head -1 ../conf-certchainfile`" > auto_certchainfile.c + +auto_certchainfile.o: \ +compile auto_certchainfile.c + ./compile auto_certchainfile.c + +auto_certfile.c: \ +auto-str ../conf-certfile + ./auto-str auto_certfile "`head -1 ../conf-certfile`" > auto_certfile.c + +auto_certfile.o: \ +compile auto_certfile.c + ./compile auto_certfile.c + +auto_ciphers.c: \ +auto-str ../conf-ciphers + ./auto-str auto_ciphers "`head -1 ../conf-ciphers`" > auto_ciphers.c + +auto_ciphers.o: \ +compile auto_ciphers.c + ./compile auto_ciphers.c + +auto_dhfile.c: \ +auto-str ../conf-dhfile + ./auto-str auto_dhfile "`head -1 ../conf-dhfile`" > auto_dhfile.c + +auto_dhfile.o: \ +compile auto_dhfile.c + ./compile auto_dhfile.c + +auto_keyfile.c: \ +auto-str ../conf-keyfile + ./auto-str auto_keyfile "`head -1 ../conf-keyfile`" > auto_keyfile.c + +auto_keyfile.o: \ +compile auto_keyfile.c + ./compile auto_keyfile.c + +ccperl: \ +../conf-ccperl ../conf-perl print-ccperl.sh + rm -f ccperl + sh print-ccperl.sh > ccperl + +chkshsgr: \ +load chkshsgr.o + ./load chkshsgr + +chkshsgr.o: \ +compile chkshsgr.c + ./compile chkshsgr.c + +choose: \ +warn-auto.sh choose.sh + rm -f choose + cat warn-auto.sh choose.sh \ + | sed s}HOME}"`head -1 ../conf-home`"}g \ + > choose + chmod 755 choose + +coe.o: \ +compile coe.c coe.h + ./compile coe.c + +compile: \ +../conf-cc ../conf-ssl print-cc.sh systype warn-auto.sh + rm -f compile + sh print-cc.sh > compile + chmod 755 compile + +hassgact.h: \ +choose compile trysgact.c hassgact.h1 hassgact.h2 + ./choose cl trysgact hassgact.h1 hassgact.h2 > hassgact.h + +hassgprm.h: \ +choose compile trysgprm.c hassgprm.h1 hassgprm.h2 + ./choose cl trysgprm hassgprm.h1 hassgprm.h2 > hassgprm.h + +hasshsgr.h: \ +choose compile tryshsgr.c hasshsgr.h1 hasshsgr.h2 chkshsgr warn-shsgr + ./chkshsgr || ( cat warn-shsgr; exit 1 ) + ./choose clr tryshsgr hasshsgr.h1 hasshsgr.h2 > hasshsgr.h + +https@: warn-auto.sh https@.sh + rm -f https@ + cat warn-auto.sh https@.sh \ + | sed s}HOME}"`head -1 ../conf-home`"}g \ + > https@ + chmod 755 https@ + +it: it-sys it-base it-sslperl + +it-base: sslclient sslserver https@ sslcat sslconnect sslprint sslhandle + +it-sslperl: sslperl + +it-sys: sysdeps auto-str + +load: \ +../conf-ld print-ld.sh systype warn-auto.sh + rm -f load + sh print-ld.sh > load + chmod 755 load + +makelib: \ +print-ar.sh systype warn-auto.sh + rm -f makelib + sh print-ar.sh > makelib + chmod 755 makelib + +perlembed.lib: \ +../conf-perl ../conf-ldperl print-perlembed.sh + rm -f perlembed.lib + sh print-ldperl.sh > perlembed.lib + +remoteinfo.o: \ +compile remoteinfo.c remoteinfo.h + ./compile remoteinfo.c + +rules.o: \ +compile rules.c rules.h ip4_bit.c ip6_bit.c ip_bit.h + ./compile rules.c ip4_bit.c ip6_bit.c ip_bit.h + +socket.lib: \ +trylsock.c compile load + ( ( ./compile trylsock.c && \ + ./load trylsock -lsocket -lnsl ) >/dev/null 2>&1 \ + && echo -lsocket -lnsl || exit 0 ) > socket.lib + rm -f trylsock.o trylsock + +ssl.lib: \ +../conf-ssllib print-dl.sh + rm -f ssl.lib + sh print-dl.sh > ssl.lib + chmod 755 ssl.lib + +ssl_ca.o: \ +compile ssl_ca.c ucspissl.h + ./compile ssl_ca.c + +ssl_cca.o: \ +compile ssl_cca.c ucspissl.h + ./compile ssl_cca.c + +ssl_chainfile.o: \ +compile ssl_chainfile.c ucspissl.h + ./compile ssl_chainfile.c + +ssl_certkey.o: \ +compile ssl_certkey.c ucspissl.h + ./compile ssl_certkey.c + +ssl_ciphers.o: \ +compile ssl_ciphers.c ucspissl.h + ./compile ssl_ciphers.c + +ssl_context.o: \ +compile ssl_context.c ucspissl.h + ./compile ssl_context.c + +ssl_env.o: \ +compile ssl_env.c ucspissl.h + ./compile ssl_env.c + +ssl_error.o: \ +compile ssl_error.c ucspissl.h + ./compile ssl_error.c + +ssl_io.o: \ +compile ssl_io.c ucspissl.h + ./compile ssl_io.c + +ssl_new.o: \ +compile ssl_new.c ucspissl.h + ./compile ssl_new.c + +ssl_params.o: \ +compile ssl_params.c ucspissl.h + ./compile ssl_params.c + +ssl_timeout.o: \ +compile ssl_timeout.c ucspissl.h + ./compile ssl_timeout.c + +ssl_verify.o: \ +compile ssl_verify.c ucspissl.h + ./compile ssl_verify.c + +sslcat: \ +warn-auto.sh sslcat.sh + rm -f sslcat + cat warn-auto.sh sslcat.sh \ + | sed s}HOME}"`head -1 ../conf-home`"}g \ + > sslcat + chmod 755 sslcat + +sslclient: \ +load sslclient.o auto_cafile.o auto_cadir.o auto_ciphers.o \ +remoteinfo.o ucspissl.a socket.lib ssl.lib + ./load sslclient auto_cafile.o auto_cadir.o auto_ciphers.o \ + remoteinfo.o ucspissl.a \ + `cat socket.lib` `cat ssl.lib` + +sslclient.o: \ +compile sslclient.c auto_cadir.h auto_cafile.h auto_ciphers.h \ +remoteinfo.h ucspissl.h + ./compile sslclient.c + +sslconnect: \ +warn-auto.sh sslconnect.sh + rm -f sslconnect + cat warn-auto.sh sslconnect.sh \ + | sed s}HOME}"`head -1 ../conf-home`"}g \ + > sslconnect + chmod 755 sslconnect + +sslhandle: \ +load sslhandle.o auto_cafile.o auto_ccafile.o auto_cadir.o \ +auto_certchainfile.o auto_dhfile.o \ +auto_certfile.o auto_keyfile.o auto_ciphers.o \ +coe.o rules.o ip4_bit.o ip6_bit.o remoteinfo.o sslprint.o \ +ucspissl.a socket.lib ssl.lib + ./load sslhandle auto_cafile.o auto_ccafile.o auto_cadir.o \ + auto_dhfile.o auto_ciphers.o \ + auto_certchainfile.o auto_certfile.o auto_keyfile.o \ + coe.o rules.o ip4_bit.o ip6_bit.o remoteinfo.o sslprint.o \ + ucspissl.a `cat socket.lib` `cat ssl.lib` + +sslhandle.o: \ +compile sslhandle.c auto_cadir.h auto_cafile.h auto_ccafile.h \ +auto_certchainfile.h auto_certfile.h auto_ciphers.h \ +auto_dhfile.h auto_keyfile.h rules.h ip_bit.h ucspissl.h coe.h \ +remoteinfo.o rules.o ip4_bit.o ip6_bit.o ucspissl.a + ./compile sslhandle.c + +sslperl: \ +load sslperl.o ucspissl.a sslhandle.o \ +auto_cafile.o auto_ccafile.o auto_cadir.o \ +auto_dhfile.o auto_certfile.o auto_keyfile.o \ +auto_ciphers.o auto_certchainfile.o \ +coe.o rules.o remoteinfo.o ip4_bit.o ip6_bit.o \ +socket.lib ssl.lib perlembed.lib + ./load sslperl auto_cafile.o auto_ccafile.o auto_cadir.o \ + auto_dhfile.o auto_certfile.o auto_keyfile.o \ + auto_ciphers.o auto_certchainfile.o ucspissl.a sslhandle.o \ + rules.o ip4_bit.o ip6_bit.o remoteinfo.o coe.o \ + ucspissl.a `cat socket.lib` `cat ssl.lib` `cat perlembed.lib` + +sslperl.o: \ +compile ccperl sslperl.c sslperl.c ucspissl.h + ./compile `cat ccperl` sslperl.c + +sslprint: \ +load sslprint.o auto_cafile.o auto_ccafile.o auto_cadir.o \ +auto_dhfile.o auto_certfile.o auto_keyfile.o \ +auto_ciphers.o auto_certchainfile.o coe.o sslhandle.o \ +rules.o ip4_bit.o ip6_bit.o remoteinfo.o \ +ucspissl.a socket.lib ssl.lib + ./load sslprint auto_cafile.o auto_ccafile.o auto_cadir.o \ + auto_dhfile.o auto_certfile.o auto_keyfile.o \ + auto_ciphers.o auto_certchainfile.o \ + rules.o ip4_bit.o ip6_bit.o remoteinfo.o coe.o sslhandle.o \ + ucspissl.a `cat socket.lib` `cat ssl.lib` + +sslprint.o: \ +compile sslprint.c + ./compile sslprint.c + +sslserver: \ +load sslserver.o auto_cafile.o auto_ccafile.o auto_cadir.o \ +auto_certchainfile.o auto_dhfile.o \ +auto_certfile.o auto_keyfile.o auto_ciphers.o \ +rules.o ip4_bit.o ip6_bit.o remoteinfo.o \ +ucspissl.a socket.lib ssl.lib + ./load sslserver auto_cafile.o auto_ccafile.o auto_cadir.o \ + auto_dhfile.o auto_ciphers.o \ + auto_certchainfile.o auto_certfile.o auto_keyfile.o \ + rules.o ip4_bit.o ip6_bit.o remoteinfo.o ucspissl.a \ + `cat socket.lib` `cat ssl.lib` + +sslserver.o: \ +compile sslserver.c auto_cadir.h auto_cafile.h auto_ccafile.h \ +auto_certchainfile.h auto_certfile.h auto_ciphers.h \ +auto_dhfile.h auto_keyfile.h \ +remoteinfo.h rules.h ip_bit.h ucspissl.h + ./compile sslserver.c + +sysdeps: \ +systype compile load hassgact.h hassgprm.h + rm -f sysdeps + cat systype compile load >> sysdeps + grep sysdep hassgact.h >> sysdeps + grep sysdep hassgprm.h >> sysdeps + +systype: \ +find-systype.sh trycpp.c x86cpuid.c + sh find-systype.sh > systype + +ucspissl.a: \ +makelib ssl_ca.o ssl_cca.o ssl_certkey.o ssl_chainfile.o ssl_ciphers.o \ +ssl_context.o ssl_env.o ssl_error.o ssl_io.o ssl_new.o ssl_params.o \ +ssl_timeout.o ssl_verify.o ucspissl.o + ./makelib ucspissl.a ssl_ca.o ssl_cca.o ssl_certkey.o ssl_chainfile.o \ + ssl_ciphers.o ssl_context.o ssl_env.o ssl_error.o ssl_io.o ssl_new.o \ + ssl_params.o ssl_timeout.o ssl_verify.o ucspissl.o + +ucspissl.o: \ +compile ucspissl.c ucspissl.h + ./compile ucspissl.c + +clean: + rm -f `cat TARGETS` diff --git a/src/TARGETS b/src/TARGETS new file mode 100644 index 0000000..0c8ccf5 --- /dev/null +++ b/src/TARGETS @@ -0,0 +1,62 @@ +auto-str +auto-str.o +auto_cadir.c +auto_cadir.o +auto_cafile.c +auto_cafile.o +auto_ccafile.c +auto_ccafile.o +auto_certchainfile.c +auto_certchainfile.o +auto_certfile.c +auto_certfile.o +auto_ciphers.c +auto_ciphers.o +auto_dhfile.c +auto_dhfile.o +auto_keyfile.c +auto_keyfile.o +ccperl +choose +coe.o +compile +hasgact.h +hasgprm.h +https@ +load +makelib +perlembed.lib +remoteinfo.o +rules.o +socket.lib +ssl.lib +ssl_ca.o +ssl_cca.o +ssl_certkey.o +ssl_chainfile.o +ssl_ciphers.o +ssl_context.o +ssl_env.o +ssl_error.o +ssl_io.o +ssl_new.o +ssl_params.o +ssl_timeout.o +ssl_verify.o +sslcat +sslclient +sslclient.o +sslconnect +sslhandle.o +sslperl +sslperl.o +sslprint +sslprint.o +sslserver +sslserver.o +sysdeps +systype +tryssl.o +ucspissl.a +ucspissl.o +*.gch diff --git a/src/auto-str.c b/src/auto-str.c new file mode 100644 index 0000000..4086921 --- /dev/null +++ b/src/auto-str.c @@ -0,0 +1,42 @@ +/* what to do */ +#include "readwrite.h" +#include "exit.h" +#include "buffer.h" + +char bspace[BUFFER_SMALL]; +buffer b = BUFFER_INIT(buffer_unixwrite,1,bspace,sizeof(bspace)); + +static void outs(const char *s) +{ + if (buffer_puts(&b,s) == -1) _exit(111); +} + +int main(int argc,char **argv) +{ + char *name; + char *value; + unsigned char ch; + char octal[4]; + + name = argv[1]; + if (!name) _exit(100); + value = argv[2]; + if (!value) _exit(100); + + outs("const char "); + outs(name); + outs("[] = \"\\\n"); + + while ((ch = *value++)) { + outs("\\"); + octal[3] = 0; + octal[2] = '0' + (ch & 7); ch >>= 3; + octal[1] = '0' + (ch & 7); ch >>= 3; + octal[0] = '0' + (ch & 7); + outs(octal); + } + + outs("\\\n\";\n"); + if (buffer_flush(&b) == -1) _exit(111); + _exit(0); +} diff --git a/src/auto_cadir.h b/src/auto_cadir.h new file mode 100644 index 0000000..9d9dfe2 --- /dev/null +++ b/src/auto_cadir.h @@ -0,0 +1,6 @@ +#ifndef AUTO_CADIR_H +#define AUTO_CADIR_H + +extern const char auto_cadir[]; + +#endif diff --git a/src/auto_cafile.h b/src/auto_cafile.h new file mode 100644 index 0000000..102ca55 --- /dev/null +++ b/src/auto_cafile.h @@ -0,0 +1,6 @@ +#ifndef AUTO_CAFILE_H +#define AUTO_CAFILE_H + +extern const char auto_cafile[]; + +#endif diff --git a/src/auto_ccafile.h b/src/auto_ccafile.h new file mode 100644 index 0000000..9d39c72 --- /dev/null +++ b/src/auto_ccafile.h @@ -0,0 +1,6 @@ +#ifndef AUTO_CCAFILE_H +#define AUTO_CCAFILE_H + +extern const char auto_ccafile[]; + +#endif diff --git a/src/auto_certchainfile.h b/src/auto_certchainfile.h new file mode 100644 index 0000000..31d4df8 --- /dev/null +++ b/src/auto_certchainfile.h @@ -0,0 +1,6 @@ +#ifndef AUTO_CERTCHAINFILE_H +#define AUTO_CERTCHAINFILE_H + +extern const char auto_certchainfile[]; + +#endif diff --git a/src/auto_certfile.h b/src/auto_certfile.h new file mode 100644 index 0000000..add5826 --- /dev/null +++ b/src/auto_certfile.h @@ -0,0 +1,6 @@ +#ifndef AUTO_CERTFILE_H +#define AUTO_CERTFILE_H + +extern const char auto_certfile[]; + +#endif diff --git a/src/auto_ciphers.h b/src/auto_ciphers.h new file mode 100644 index 0000000..2842fbd --- /dev/null +++ b/src/auto_ciphers.h @@ -0,0 +1,6 @@ +#ifndef AUTO_CIPHERS_H +#define AUTO_CIPHERS_H + +extern const char auto_ciphers[]; + +#endif diff --git a/src/auto_dhfile.h b/src/auto_dhfile.h new file mode 100644 index 0000000..83afa2a --- /dev/null +++ b/src/auto_dhfile.h @@ -0,0 +1,6 @@ +#ifndef AUTO_DHFILE_H +#define AUTO_DHFILE_H + +extern const char auto_dhfile[]; + +#endif diff --git a/src/auto_keyfile.h b/src/auto_keyfile.h new file mode 100644 index 0000000..feac74f --- /dev/null +++ b/src/auto_keyfile.h @@ -0,0 +1,6 @@ +#ifndef AUTO_KEYFILE_H +#define AUTO_KEYFILE_H + +extern const char auto_keyfile[]; + +#endif diff --git a/src/chkshsgr.c b/src/chkshsgr.c new file mode 100644 index 0000000..12442ea --- /dev/null +++ b/src/chkshsgr.c @@ -0,0 +1,14 @@ +/* Public domain. */ + +#include <sys/types.h> +#include <unistd.h> +#include "exit.h" + +int main() +{ + short x[4]; + + x[0] = x[1] = 0; + if (getgroups(1,x) == 0) if (setgroups(1,x) == -1) _exit(1); + _exit(0); +} diff --git a/src/choose.sh b/src/choose.sh new file mode 100644 index 0000000..feff2da --- /dev/null +++ b/src/choose.sh @@ -0,0 +1,18 @@ + +result="$4" + +case "$1" in + *c*) ./compile $2.c >/dev/null 2>&1 || result="$3" ;; +esac + +case "$1" in + *l*) ./load $2 >/dev/null 2>&1 || result="$3" ;; +esac + +case "$1" in + *r*) ./$2 >/dev/null 2>&1 || result="$3" ;; +esac + +rm -f $2.o $2 + +exec cat "$result" diff --git a/src/coe.c b/src/coe.c new file mode 100644 index 0000000..50b2397 --- /dev/null +++ b/src/coe.c @@ -0,0 +1,9 @@ +/* Public domain. */ + +#include <fcntl.h> +#include "coe.h" + +int coe(int fd) +{ + return fcntl(fd,F_SETFD,1); +} diff --git a/src/coe.h b/src/coe.h new file mode 100644 index 0000000..b17db54 --- /dev/null +++ b/src/coe.h @@ -0,0 +1,8 @@ +/* Public domain. */ + +#ifndef COE_H +#define COE_H + +extern int coe(int); + +#endif diff --git a/src/exit.h b/src/exit.h new file mode 100644 index 0000000..39011c8 --- /dev/null +++ b/src/exit.h @@ -0,0 +1,6 @@ +#ifndef EXIT_H +#define EXIT_H + +extern void _exit(); + +#endif diff --git a/src/exp.base b/src/exp.base new file mode 100644 index 0000000..c182da0 --- /dev/null +++ b/src/exp.base @@ -0,0 +1,325 @@ +---> test sslserver + sslclient: four instances of sslserver (ports 50013, 50014, 50015, 50016) are used +---> sslserver @port 50015 requires client certs +++++ +---> test sslclient/sslserver behavior with wrong parm (timeout 2 secs) +++++ +--- sslclient prints usage message without enough arguments +sslclient: usage: sslclient [ -463hHrRdDiqQveEsSnNxX ] [ -i localip ] [ -p localport ] [ -T timeoutconn ] [ -l localname ] [ -t timeoutinfo ] [ -I interface ] [ -a cafile ] [ -A cadir ] [ -c certfile ] [ -z ciphers ] [ -k keyfile ] [ -V verifydepth ] [ -w progtimeout ] host port program +100 +--- sslclient prints error message with unknown port name +sslclient: fatal: (111) unable to figure out port number for nonexistentport +111 +--- sslclient prints error message when connection fails +sslclient: drop: (110) unable to connect to: 127.0.0.1 port: 16 +110 +--- sslclient -q does not print error message when connection fails +110 +--- sslclient prints error message with unknown host name +sslclient: error: (111) No IP address for: nonexistent.local. +111 +--- sslclient prints error message with unresolvable host name +sslclient: error: (111) No IP address for: thislabelistoolongbecausednshasalimitof63charactersinasinglelabel. +111 +--- sslserver prints usage message without enough arguments +sslserver: usage: sslserver [ -1346UXpPhHrRoOdDqQvVIeEsSnNmzZ ] [ -c limit ] [ -x rules.cdb ] [ -B banner ] [ -g gid ] [ -u uid ] [ -b backlog ] [ -l localname ] [ -t timeout ] [ -I interface ] [ -T ssltimeout ] [ -w progtimeout ] host port program +100 +--- sslserver prints error message with unknown port name +sslserver: fatal: (111) unable to figure out port number for: nonexistentport +111 +--- sslserver prints error message with unknown host name +sslserver: fatal: (111) no IP address for: nonexistent.local. +111 +--- sslserver prints error message with unresolvable host name +sslserver: fatal: (111) temporarily unable to figure out IP address for: thislabelistoolongbecausednshasalimitof63charactersinasinglelabel. +111 +--- sslserver prints error message with non-local host name +sslserver: fatal: (111) unable to bind to: ... +111 +---> test sslclient to connect to sslserver (on different port; note: cert verify will fail on localhost) +++++ +--- sslclient sets basic environment variables +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslserver -e also sets TCP environment variables +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslclient recognizes -D, -z, -r, -h, -t (with elective cipher) +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslclient sets basic environment variables +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslclient -e sets TCP environment variables +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslclient -s sets TLS environment variables +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslclient looks up host names properly (localhost. -> ip6-loopback) +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslclient -v works +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslserver -N does not check certificates CN +sslclient: tls connected to: ::1 port: 50014 +ok +0 +--- sslserver and sslclient print errors for incompatible cipher lists for TLS < 1.3 +sslclient: error: (111) unable to set cipher list +111 +--- sslclient -X ignores any server certificate +sslclient: tls connected to: ::1 port: 50014 +ok +0 +--- sslclient -n checks hostname with certificates SAN/CN +sslclient: fatal: (111) unable to bind to: ::1 port: 50027 +111 +---> test sslclient to connect to sslserver requiring client cert +++++ +--- sslserver prints error for no client certificate +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslserver prints error for bad client certificate +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslclient uses certificates +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +---> test sslcat to connect to sslserver@5016 +++++ +--- sslcat works +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslconnect works +banner0 +--- https@ works +0 +---> test sslconnect to connect to sslserver@5013 +++++ +--- sslclient and sslserver handle larger data +sslclient: tls connected to: ::1 port: 50013 +0 +--- sslserver times out +sslclient: tls connected to: ::1 port: 50013 +bannerhereur^M +0 +sslclient: tls connected to: ::1 port: 50013 +banner0 +---> test sslprint@50021 +++++ +--- sslprint prints usage message without enough arguments +sslprint: usage: sslprint[ -1346UXpPhHrRoOdDqQviIeEsS ] [ -c limit ] [ -x rules.cdb ] [ -B banner ] [ -g gid ] [ -u uid ] [ -b backlog ] [ -l localname ] [ -t timeout ] [ -T ssltimeout ] [ -w progtimeout ] [ -f lockfile ] [ -I interface ] host port program +100 +--- sslprint prints error message with unknown port name +sslprint: fatal: (111) unable to figure out port number for: nonexistentport +111 +--- sslprint prints error message with unknown host name +sslprint: fatal: (111) no IP address for: nonexistent.local. +111 +--- sslprint prints error message with unresolvable host name +sslprint: fatal: (111) temporarily unable to figure out IP address for: thislabelistoolongbecausednshasalimitof63charactersinasinglelabel. +111 +--- sslprint prints error message with non-local host name +sslprint: fatal: (111) unable to bind +111 +--- sslprint prints error message with used port +sslprint: fatal: (111) unable to bind +111 +--- sslprint sets basic environment variables +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslprint exits when environment changes +sslclient: error: (110) missing credentials (CA) or unable to validate server certificate +110 +--- sslprint does not lose descriptors +110 +--- sslserver -1v prints proper messages +::x1 : 50016 +sslserver::x ciphers x +sslserver::x cafile x xxx/rootCA_cert.pem +sslserver::x ccafile x +sslserver::x cadir x xxx/etc +sslserver::x certchainfile x +sslserver::x cert x xxx/::1_cert.pem +sslserver::x key x xxx/::1_key.pem +sslserver::x dhparam x xxx +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_CHACHA20_POLY1305_SHA256 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +::x1 : 50015 +sslserver::x ciphers x +sslserver::x cafile x xxx/rootCA_cert.pem +sslserver::x ccafile x xxx/rootCA_cert.pem +sslserver::x cadir x xxx/etc +sslserver::x certchainfile x +sslserver::x cert x xxx/::1_cert.pem +sslserver::x key x xxx/::1_key.pem +sslserver::x dhparam x xxx +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x error: (111) unable to accept TLS for pid: x +sslserver::x ended by x status 28416 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x error: (111) unable to accept TLS for pid: x +sslserver::x ended by x status 28416 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x error: (111) unable to accept TLS for pid: x +sslserver::x ended by x status 28416 +sslserver::x status: 0/1/0 +::x1 : 50014 +sslserver::x ciphers x +sslserver::x cafile x xxx/rootCA_cert.pem +sslserver::x ccafile x +sslserver::x cadir x xxx/etc +sslserver::x certchainfile x +sslserver::x cert x xxx/::1_cert.pem +sslserver::x key x xxx/::1_key.pem +sslserver::x dhparam x xxx +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x error: (111) unable to accept TLS for pid: x +sslserver::x ended by x status 28416 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +::x1 : 50013 +sslserver::x ciphers x +sslserver::x cafile x xxx/rootCA_cert.pem +sslserver::x ccafile x +sslserver::x cadir x xxx/etc +sslserver::x certchainfile x +sslserver::x cert x xxx/::1_cert.pem +sslserver::x key x xxx/::1_key.pem +sslserver::x dhparam x xxx +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +sslserver::x status: 1/1/0 +sslserver::x pid x from ::1 +sslserver::x ok x Localserver:::1:x ip6-loopback:::1::x +sslserver::x tls x accept TLSv1.3:TLS_AES_256_GCM_SHA384 +sslserver::x ended by x status 0 +sslserver::x status: 0/1/0 +::x1 : 50021 +sslprint::x ciphers x +sslprint::x cafile x xxx/rootCA_cert.pem +sslprint::x ccafile x +sslprint::x cadir x xxx/etc +sslprint::x certchainfile x +sslprint::x cert x xxx/::1_cert.pem +sslprint::x key x xxx/::1_key.pem +sslprint::x dhparam x xxx +sslprint::x status: 0/1 +sslprint::x status: 1/1 +sslprint::x pid x from :: +sslprint::x ok x Localserver:::1:x ip6-localnet:::::x +sslprint::x end x status 13 +sslprint::x status: 0/1 +sslprint::x status: 1/1 +sslprint::x pid x from :: +sslprint::x ok x Localserver:::1:x ip6-localnet:::::x +sslprint::x end x status 13 +sslprint::x status: 0/1 +sslprint::x status: 1/1 +sslprint::x pid x from :: +sslprint::x ok x Localserver:::1:x ip6-localnet:::::x +sslprint::x end x status 13 +sslprint::x status: 0/1 +sslprint::x status: 1/1 +sslprint::x end x status 15 +sslprint::x status: 0/1 diff --git a/src/exp.it b/src/exp.it new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/exp.it diff --git a/src/exp.sslperl b/src/exp.sslperl new file mode 100644 index 0000000..0a783dc --- /dev/null +++ b/src/exp.sslperl @@ -0,0 +1,105 @@ +--- sslperl works +sslperlHello, World! (1): here you are +0 +sslperlHello, World! (2): here you are +0 +sslperlHello, World! (1): here you are +0 +sslperlHello, World! (2): here you are +0 +--- sslperl prints usage message without enough arguments +sslperl: usage: sslperl[ -1346UXpPhHrRoOdDqQviIeEsS ] [ -c limit ] [ -x rules.cdb ] [ -B banner ] [ -g gid ] [ -u uid ] [ -b backlog ] [ -l localname ] [ -t timeout ] [ -T ssltimeout ] [ -w progtimeout ] [ -f lockfile ] [ -I interface ] host port program +100 +--- sslperl prints error message with unknown port name +sslperl: fatal: (111) unable to figure out port number for: nonexistentport +111 +--- sslperl prints error message with unknown host name +sslperl: fatal: (111) temporarily unable to figure out IP address for: nonexistent.local. +111 +--- sslperl prints error message with unresolvable host name +sslperl: fatal: (111) no IP address for: thislabelistoolongbecausednshasalimitof63charactersinasinglelabel. +111 +--- sslperl prints error message with non-local host name +sslperl: fatal: (111) unable to bind +111 +--- sslperl preserves environment +sslperl changed environment +0 +--- sslperl handles larger requests +sslclient: tls connected to: 127.0.0.1 port: 50022 +0 +--- sslserver -1v prints proper messages +127.0.0.1 : 50022 +sslperl: cafile x xxx/rootCA.pem +sslperl: ccafile x +sslperl: cadir x xxx/etc +sslperl: certchainfile x +sslperl: cert x xxx/::x +sslperl: key x xxx/::x +sslperl: dhparam x xxx +sslperl: status: 0/1/0 +sslperl: status: 1/1/0 +sslperl: pid x from 127.0.0.1 +sslperl: ok x Localserver:127.0.0.1:50022 ip4-loopback:127.0.0.1::x +sslperl: tls x accept +log: Hello, World! (1): here you are +sslperl: drop: (110) environ changed +sslperl: done ... +sslperl: pid x from 127.0.0.1 +sslperl: ok x Localserver:127.0.0.1:50022 ip4-loopback:127.0.0.1::x +sslperl: tls x accept +log: Hello, World! (2): here you are +sslperl: end x status 0 +sslperl: status: 0/1/0 +sslperl: status: 1/1/0 +sslperl: pid x from 127.0.0.1 +sslperl: ok x Localserver:127.0.0.1:50022 ip4-loopback:127.0.0.1::x +sslperl: tls x accept +log: Hello, World! (1): here you are +sslperl: drop: (110) environ changed +sslperl: done ... +sslperl: pid x from 127.0.0.1 +sslperl: ok x Localserver:127.0.0.1:50022 ip4-loopback:127.0.0.1::x +sslperl: tls x accept +log: Hello, World! (2): here you are +sslperl: end x status 0 +sslperl: status: 0/1/0 +sslperl: status: 1/1/0 +sslperl: end x status 15 +sslperl: status: 0/1/0 +127.0.0.1 : 50022 +sslperl: cafile x xxx/rootCA.pem +sslperl: ccafile x +sslperl: cadir x xxx/etc +sslperl: certchainfile x +sslperl: cert x xxx/::x +sslperl: key x xxx/::x +sslperl: dhparam x xxx +sslperl: status: 0/1/0 +sslperl: status: 1/1/0 +sslperl: pid x from 127.0.0.1 +sslperl: ok x Localserver:127.0.0.1:50022 ip4-loopback:127.0.0.1::x +sslperl: tls x accept +log: NOW= +log: changed environment +sslperl: drop: (110) environ changed +sslperl: done ... +sslperl: end x status 15 +sslperl: status: 0/1/0 +127.0.0.1 : 50022 +sslperl: cafile x xxx/rootCA.pem +sslperl: ccafile x +sslperl: cadir x xxx/etc +sslperl: certchainfile x +sslperl: cert x xxx/::x +sslperl: key x xxx/::x +sslperl: dhparam x xxx +sslperl: status: 0/1/0 +sslperl: status: 1/1/0 +sslperl: pid x from 127.0.0.1 +sslperl: ok x Localserver:127.0.0.1:50022 ip4-loopback:127.0.0.1::x +sslperl: tls x accept +sslperl: drop: (110) environ changed +sslperl: done ... +sslperl: end x status 15 +sslperl: status: 0/1/0 diff --git a/src/find-systype.sh b/src/find-systype.sh new file mode 100644 index 0000000..15322b4 --- /dev/null +++ b/src/find-systype.sh @@ -0,0 +1,151 @@ +# oper-:arch-:syst-:chip-:kern- +# oper = operating system type; e.g., sunos-4.1.4 +# arch = machine language; e.g., sparc +# syst = which binaries can run; e.g., sun4 +# chip = chip model; e.g., micro-2-80 +# kern = kernel version; e.g., sun4m +# dependence: arch --- chip +# \ \ +# oper --- syst --- kern +# so, for example, syst is interpreted in light of oper, but chip is not. +# anyway, no slashes, no extra colons, no uppercase letters. +# the point of the extra -'s is to ease parsing: can add hierarchies later. +# e.g., *:i386-*:*:pentium-*:* would handle pentium-100 as well as pentium, +# and i386-486 (486s do have more instructions, you know) as well as i386. +# the idea here is to include ALL useful available information. + +exec 2>/dev/null + +sys="`uname -s | tr '/:[:upper:]' '..[:lower:]'`" +if [ x"$sys" != x ] +then + unamer="`uname -r | tr /: ..`" + unamem="`uname -m | tr /: ..`" + unamev="`uname -v | tr /: ..`" + + case "$sys" in + bsd.os|freebsd|netbsd|openbsd) + # in bsd 4.4, uname -v does not have useful info. + # in bsd 4.4, uname -m is arch, not chip. + oper="$sys-$unamer" + arch="$unamem" + syst="" + chip="`sysctl -n hw.model`" # hopefully + kern="" + ;; + linux) + # as in bsd 4.4, uname -v does not have useful info. + oper="$sys-$unamer" + syst="" + chip="$unamem" + kern="" + case "$chip" in + i386|i486|i586|i686) + arch="i386" + ;; + alpha) + arch="alpha" + ;; + esac + ;; + aix) + # naturally IBM has to get uname -r and uname -v backwards. dorks. + oper="$sys-$unamev-$unamer" + arch="`arch | tr /: ..`" + syst="" + chip="$unamem" + kern="" + ;; + sunos) + oper="$sys-$unamer-$unamev" + arch="`(uname -p || mach) | tr /: ..`" + syst="`arch | tr /: ..`" + chip="$unamem" # this is wrong; is there any way to get the real info? + kern="`arch -k | tr /: ..`" + ;; + unix_sv) + oper="$sys-$unamer-$unamev" + arch="`uname -m`" + syst="" + chip="$unamem" + kern="" + ;; + *) + oper="$sys-$unamer-$unamev" + arch="`arch | tr /: ..`" + syst="" + chip="$unamem" + kern="" + ;; + esac +else + cc -c trycpp.c + cc -o trycpp trycpp.o + case `./trycpp` in + nextstep) + oper="nextstep-`hostinfo | sed -n 's/^[ ]*NeXT Mach \([^:]*\):.*$/\1/p'`" + arch="`hostinfo | sed -n 's/^Processor type: \(.*\) (.*)$/\1/p' | tr /: ..`" + syst="" + chip="`hostinfo | sed -n 's/^Processor type: .* (\(.*\))$/\1/p' | tr ' /:' '...'`" + kern="" + ;; + *) + oper="unknown" + arch="" + syst="" + chip="" + kern="" + ;; + esac + rm -f trycpp.o trycpp +fi + +case "$chip" in +80486) + # let's try to be consistent here. (BSD/OS) + chip=i486 + ;; +i486DX) + # respect the hyphen hierarchy. (FreeBSD) + chip=i486-dx + ;; +i486.DX2) + # respect the hyphen hierarchy. (FreeBSD) + chip=i486-dx2 + ;; +Intel.586) + # no, you nitwits, there is no such chip. (NeXTStep) + chip=pentium + ;; +i586) + # no, you nitwits, there is no such chip. (Linux) + chip=pentium + ;; +i686) + # STOP SAYING THAT! (Linux) + chip=ppro + ;; +arm) + # too many on the rood + chip=arm + ;; +arm64) + # pi 3+ + chip=arm64 +esac + +if cc -c x86cpuid.c +then + if cc -o x86cpuid x86cpuid.o + then + x86cpuid="`./x86cpuid | tr /: ..`" + case "$x86cpuid" in + ?*) + chip="$x86cpuid" + ;; + esac + fi +fi +rm -f x86cpuid x86cpuid.o + +echo "$oper-:$arch-:$syst-:$chip-:$kern-" | tr ' [A-Z]' '.[a-z]' diff --git a/src/fork.h1 b/src/fork.h1 new file mode 100644 index 0000000..ddd589d --- /dev/null +++ b/src/fork.h1 @@ -0,0 +1,9 @@ +#ifndef FORK_H +#define FORK_H + +/* sysdep: -vfork */ + +extern int fork(); +#define vfork fork + +#endif diff --git a/src/fork.h2 b/src/fork.h2 new file mode 100644 index 0000000..7c1b0b9 --- /dev/null +++ b/src/fork.h2 @@ -0,0 +1,9 @@ +#ifndef FORK_H +#define FORK_H + +/* sysdep: +vfork */ + +extern int fork(); +extern int vfork(); + +#endif diff --git a/src/hassgact.h1 b/src/hassgact.h1 new file mode 100644 index 0000000..7639d24 --- /dev/null +++ b/src/hassgact.h1 @@ -0,0 +1,3 @@ +/* Public domain. */ + +/* sysdep: -sigaction */ diff --git a/src/hassgact.h2 b/src/hassgact.h2 new file mode 100644 index 0000000..60ff776 --- /dev/null +++ b/src/hassgact.h2 @@ -0,0 +1,4 @@ +/* Public domain. */ + +/* sysdep: +sigaction */ +#define HASSIGACTION 1 diff --git a/src/hassgprm.h1 b/src/hassgprm.h1 new file mode 100644 index 0000000..ef3eee9 --- /dev/null +++ b/src/hassgprm.h1 @@ -0,0 +1,3 @@ +/* Public domain. */ + +/* sysdep: -sigprocmask */ diff --git a/src/hassgprm.h2 b/src/hassgprm.h2 new file mode 100644 index 0000000..be9d0d7 --- /dev/null +++ b/src/hassgprm.h2 @@ -0,0 +1,4 @@ +/* Public domain. */ + +/* sysdep: +sigprocmask */ +#define HASSIGPROCMASK 1 diff --git a/src/hasshsgr.h1 b/src/hasshsgr.h1 new file mode 100644 index 0000000..3806277 --- /dev/null +++ b/src/hasshsgr.h1 @@ -0,0 +1,3 @@ +/* Public domain. */ + +/* sysdep: -shortsetgroups */ diff --git a/src/hasshsgr.h2 b/src/hasshsgr.h2 new file mode 100644 index 0000000..5624ed0 --- /dev/null +++ b/src/hasshsgr.h2 @@ -0,0 +1,4 @@ +/* Public domain. */ + +/* sysdep: +shortsetgroups */ +#define HASSHORTSETGROUPS 1 diff --git a/src/haswaitp.h1 b/src/haswaitp.h1 new file mode 100644 index 0000000..0d6f82c --- /dev/null +++ b/src/haswaitp.h1 @@ -0,0 +1,3 @@ +/* Public domain. */ + +/* sysdep: -waitpid */ diff --git a/src/haswaitp.h2 b/src/haswaitp.h2 new file mode 100644 index 0000000..015413f --- /dev/null +++ b/src/haswaitp.h2 @@ -0,0 +1,4 @@ +/* Public domain. */ + +/* sysdep: +waitpid */ +#define HASWAITPID 1 diff --git a/src/https@.sh b/src/https@.sh new file mode 100644 index 0000000..6a902b7 --- /dev/null +++ b/src/https@.sh @@ -0,0 +1,15 @@ +host=${1-0} +path=${2-} +port=${3-443} +args="" +if [ $# -gt 3 ] +then + shift; shift; shift + args="$@" +fi +echo "GET /${path} HTTP/1.1 +Host: $host:$port +" | HOME/bin/sslclient -XRHl0 $args -- "$host" "$port" sh -c ' + addcr >&7 + exec HOME/bin/delcr <&6 +' | awk '/^$/ { body=1; next } { if (body) print }' diff --git a/src/ip4_bit.c b/src/ip4_bit.c new file mode 100644 index 0000000..02dbf7a --- /dev/null +++ b/src/ip4_bit.c @@ -0,0 +1,101 @@ +/*** + @file ip4_bit.c + @author Jens Wehrenbrecht, feh + @funcs ip4_bitstring, bitstring_ip4 +*/ +#include "ip.h" +#include "byte.h" +#include "scan.h" +#include "str.h" +#include "fmt.h" +#include "ip_bit.h" + +#define BITSUBSTITUTION + +static char strnum[FMT_ULONG]; + +/*** + /fn ip4_bitstring + /brief This function converts a IPv4 address into its binary representation with given prefix len + /param out: ip4string 0-terminated destination address. + /param in: ip4address The source address. + /param in: prefix The net prefix bits (maximum 32 bits for IPv4). + /return -1: lack of memory; 1: non valid IP address; 0: successful converted. +*/ + +int ip4_bitstring(stralloc *ip4string, char *ip, unsigned int prefix) +{ + int i, j; + char ip4[4]; + int count = 0; + unsigned char number; +#ifdef BITSUBSTITUTION + const char *letterarray = "abcdefghijklmnopqrstuvwxyz123456"; +#endif + + if (!stralloc_copys(ip4string,"")) return -1; + if (!stralloc_readyplus(ip4string,32)) return -1; + ip4_scan(ip,ip4); + + for (i = 0; i < 4; i++) { + number = (unsigned char) ip4[i]; + for (j = 7; j >= 0; j--) { + if (number & (1<<j)) { +#ifdef BITSUBSTITUTION + if (!stralloc_catb(ip4string,letterarray + count,1)) return -1; +#else + if (!stralloc_cats(ip4string,"1")) return -1; +#endif + } else { + if (!stralloc_cats(ip4string,"0")) return -1; + } + count++; + prefix--; + if (prefix == 0) return 0; + } + } + + return 1; +} + +/*** + /fn bitstring_ip4 + /brief This function takes an IPv4 bitstring and translates it to an IPv4 address + prefix + /param in: ip4string The source address (with '_' start token). + /param out: ip4addr 0-terminated estination IPv4 address + net prefix (eg. 127.0.0.0/16). + /return -1: lack of memory; 1: non valid IPv4 address; 0: successful converted. +*/ + +int bitstring_ip4(stralloc *ip4addr, stralloc *ip4string) +{ + int j; + int num = 0; + int value = 256; + int prefix; + + if (!stralloc_copys(ip4addr,"")) return -1; + prefix = ip4string->len - 1; + + if (prefix <= 0) return 1; + if (prefix <= 1 || prefix > 32) return 1; + + for (j = 1; j <= prefix; j++) { + if (ip4string->s[j] != '0') { + num += (value/2); + value /= 2; + } else + value /= 2; + if (j % 8 == 0 || j == prefix) { + if (!stralloc_catb(ip4addr,strnum,fmt_ulong(strnum,num))) return -1; + if (j < 32) if (!stralloc_cats(ip4addr,".")) return -1; + num = 0; + value = 256; + } + } + + if (!stralloc_cats(ip4addr,"/")) return -1; + if (!stralloc_catb(ip4addr,strnum,fmt_ulong(strnum,prefix))) return -1; + if (!stralloc_0(ip4addr)) return -1; + + return 0; +} diff --git a/src/ip6_bit.c b/src/ip6_bit.c new file mode 100644 index 0000000..528f0b0 --- /dev/null +++ b/src/ip6_bit.c @@ -0,0 +1,180 @@ +/** + @file ip6_bit.c + @author Li Minh Bui, feh + @funcs bytetohex, ip6_bitstring, bitstring_ip6, ip6_fmt_str +*/ +#include "ip.h" +#include "byte.h" +#include "str.h" +#include "fmt.h" +#include "stralloc.h" +#include "ip_bit.h" + +#define BITSUBSTITUTION + +/*** + /fn bytetohex + /brief Convert a number of max 255 to hex. + /param decimal The decimal number. + /param hex The converted hex value. +*/ + +void bytetohex(unsigned char decimal, char hex[3]) +{ + char* hexdigits = "0123456789ABCDEF"; + int rest, number; + hex[0] = '0'; + hex[1] = '0'; + hex[2] = '\0'; + + number = decimal / 16; + rest = decimal % 16; + + hex[0] = hexdigits[number]; + hex[1] = hexdigits[rest]; +} + +static char strnum[FMT_ULONG]; + +/*** + /fn ip6_bitstring + /brief This function converts a IPv6 address into its binary representation. + /param out: ip6string The destination address. + /param in: ip6addr The source address. + /param in: prefix The net prefix bits (maximum 128 bits for IPv6). + /return -1: lack of memory; 1: non valid IPv6 address; 0: successful converted. +*/ + +int ip6_bitstring(stralloc *ip6string, char *ip6addr, unsigned int prefix) +{ + char ip6[16]; + int bit, octettbitpos, number, shiftedvalue; + int i, slashpos, ip6len; + +#ifdef BITSUBSTITUTION + char subvalueforbitone[1]; + subvalueforbitone[0] = 96; /* substitution starts from token '_' = 96 */ +#endif + + ip6len = str_len(ip6addr); + slashpos = byte_chr(ip6addr,ip6len,'/'); + if (!stralloc_copyb(ip6string,ip6addr,slashpos)) return -1; + ip6addr[slashpos] = '\0'; + + if (!ip6_scan(ip6addr,ip6)) return 1; + if (!stralloc_copys(ip6string,"")) return -1; + + for (i = 0; i < 16; i++) { + number = (unsigned char) ip6[i]; + + for (octettbitpos = 7; octettbitpos >= 0; octettbitpos--) { + shiftedvalue = 1 << octettbitpos; + bit = number / shiftedvalue; + number = number - bit * (shiftedvalue); + + if (bit) { +#ifdef BITSUBSTITUTION + if (!stralloc_catb(ip6string,subvalueforbitone,1)) return -1; + subvalueforbitone[0]++; +#else + if (!stralloc_cats(ip6string,"1")) return -1; +#endif + } else + if (!stralloc_cats(ip6string,"0")) return -1; + + prefix--; + if (prefix == 0) return 0; + } + } + + return 1; +} + +/*** + /fn bitstring_ip6 + /brief This function converts a bit string which is produced by ip6_bitstring() + into an IPv6 address. The string may start with a '^'. + /param in: ip6string Source string which need to be converted. + /param out ip6addr 0-terminated IPv6 destination address with net prefix. + /return -1: No memory could allocated,0: Failure,1: Success. +*/ + +int bitstring_ip6(stralloc *ip6addr ,stralloc *ip6string) +{ + int j = 0; + int i = 0; + int len, prefix, shiftedvalue; + int bitpos = 7; + int decimalnumber = 0; + char ip6[16] = {0}; + char ip6compact[40] = {0}; + + if (!stralloc_copys(ip6addr,"")) return -1; + prefix = ip6string->len - 1; + + if (prefix <= 0) return 1; + if (prefix <= 1 || prefix > 128) return 1; + + if (ip6string->s[0] == '^') j = 1; + + for (i = j, j = 0; i <= prefix; i++) { + if (ip6string->s[i] != '0') { + shiftedvalue = 1 << bitpos; + decimalnumber += shiftedvalue; + } + bitpos--; + if (bitpos == -1) { /* Put each converted byte into the array. */ + if (j < 16) { + ip6[j] = (unsigned char) decimalnumber; + j++; + bitpos = 7; + decimalnumber = 0; + } + } + } + + if (bitpos < 7) { /* Last bit was read,but the number was not converted. */ + ip6[j] = (unsigned char) decimalnumber; + j++; + } + + len = ip6_fmt(ip6compact,ip6); + if (!len) return 1; + + if (!stralloc_copyb(ip6addr,ip6compact,len)) return -1; + if (!stralloc_cats(ip6addr,"/")) return -1; + if (!stralloc_catb(ip6addr,strnum,fmt_ulong(strnum,prefix))) return -1; + if (!stralloc_0(ip6addr)) return -1; + + return 0; +} +/*** + /fn ip6_fmt_str + /brief This function expands any valid IPv6 address into its full format of 16 bytes. + It returns the number of processed tokens on success. + /param src Source IPv6 address. + /param destination Expanded IPv6 address. + /return -1: No memory could allocated; 1: failure, 0: success +*/ + +unsigned int ip6_fmt_str(stralloc *dest, char *src) +{ + stralloc addr = {0}; + char ip6[16]; + char hexvalue[3] = {0, 0, 0}; + int i; + + if (!stralloc_copys(&addr,src)) return -1; + if (!stralloc_0(&addr)) return -1; + + if (ip6_scan(addr.s,ip6) == 0) return 1; + if (!stralloc_copys(dest,"")) return -1; + + for (i = 0; i < 16; i++) { + bytetohex((unsigned char)ip6[i],hexvalue); + stralloc_catb(dest,hexvalue,2); + if (!((i+1) % 2) && (i+1) < 16) + if (!stralloc_cats(dest,":")) return -1; /*Append ':' after every two bytes.*/ + } + return 0; +} diff --git a/src/ip_bit.h b/src/ip_bit.h new file mode 100644 index 0000000..49df160 --- /dev/null +++ b/src/ip_bit.h @@ -0,0 +1,15 @@ +#ifndef IP_BIT_H +#define IP_BIT_H + +#include "stralloc.h" + +extern int bitstring_ip4(stralloc *,stralloc *); +extern int ip4_bitstring(stralloc *,char *,unsigned int); +extern unsigned int ip4_cscan(const char *,char [4]); +extern void getnum(char *,int,unsigned long *); + +extern int bitstring_ip6(stralloc *,stralloc *); +extern int ip6_bitstring(stralloc *,char *,unsigned int); +extern unsigned int ip6_fmt_str(stralloc *,char *); + +#endif diff --git a/src/it-base=d b/src/it-base=d new file mode 100644 index 0000000..a1d0820 --- /dev/null +++ b/src/it-base=d @@ -0,0 +1,7 @@ +sslclient +sslserver +https@ +sslcat +sslconnect +sslprint +sslhandle diff --git a/src/it-sslperl=d b/src/it-sslperl=d new file mode 100644 index 0000000..68065ca --- /dev/null +++ b/src/it-sslperl=d @@ -0,0 +1 @@ +sslperl diff --git a/src/it-sys=d b/src/it-sys=d new file mode 100644 index 0000000..fa5d3e9 --- /dev/null +++ b/src/it-sys=d @@ -0,0 +1 @@ +sysdeps diff --git a/src/it=d b/src/it=d new file mode 100644 index 0000000..304fcac --- /dev/null +++ b/src/it=d @@ -0,0 +1 @@ +it-base diff --git a/src/print-ar.sh b/src/print-ar.sh new file mode 100644 index 0000000..99bc116 --- /dev/null +++ b/src/print-ar.sh @@ -0,0 +1,14 @@ +cat warn-auto.sh +echo 'main="$1"; shift' +echo 'rm -f "$main"' +echo 'ar cr "$main" ${1+"$@"}' +case "`cat systype`" in + sunos-5.*) ;; + unix_sv*) ;; + irix64-*) ;; + irix-*) ;; + dgux-*) ;; + hp-ux-*) ;; + sco*) ;; + *) echo 'ranlib "$main"' ;; +esac diff --git a/src/print-cc.sh b/src/print-cc.sh new file mode 100644 index 0000000..2a46533 --- /dev/null +++ b/src/print-cc.sh @@ -0,0 +1,62 @@ +cc="`head -1 ../conf-cc`" +systype="`cat systype`" + +ccqlibs="`head -1 ../conf-qlibs`" +[ -d "$ccqlibs"/include ] && ccqlibs="-I${ccqlibs}/include" \ +|| ccqlibs="" + +cc -c trycpp.c -malign-double >/dev/null 2>&1 \ +&& ccad="-malign-double" + +cc -c trycpp.c -march=ultrasparc >/dev/null 2>&1 \ +&& ccus="-march=ultrasparc" + +cc -c trycpp.c -march=powerpc >/dev/null 2>&1 \ +&& ccpp="-march=powerpc" + +cc -c trycpp.c -march=21164 >/dev/null 2>&1 \ +&& cc21="-march=21164" + +cc -c trycpp.c -march=native >/dev/null 2>&1 \ +&& ccarm="-march=native" + +rm -f trycpp.o + +ccssl="`head -1 ../conf-ssl`" +eval cc -c tryssl.c ${ccssl} >/dev/null 2>&1 \ +|| ccssl="" + +ccbase="cc -fomit-frame-pointer -Wall" + +case "$cc:$systype" in + auto:*:i386-*:*) + cc="$ccbase -O1 $ccad" + ;; + auto:*:amd64-*:*) + cc="$ccbase -O2 $ccad" + ;; + auto:*:x86_64-*:*) + cc="$ccbase -O2 $ccad" + ;; + auto:*:sparc-*:*:*:*) + cc="$ccbase -O1 $ccus" + ;; + auto:*:ppc-*:*:*:*) + cc="$ccbase -O2 $ccpp" + ;; + auto:*:alpha-*:*:*:*) + cc="$ccbase -O2 $cc21" + ;; + auto:aix-*:-:-:*:-) + cc="$ccbase -O2 $ccpp" + ;; + auto:*:armv7l-:*) + cc="$ccbase -O2 $ccarm" + ;; + auto:*) + cc="$ccbase -O2" + ;; +esac + +cat warn-auto.sh +echo exec "$cc" ${ccqlibs} ${ccssl} '-c ${1+"$@"}' diff --git a/src/print-ccperl.sh b/src/print-ccperl.sh new file mode 100644 index 0000000..9cda68d --- /dev/null +++ b/src/print-ccperl.sh @@ -0,0 +1,10 @@ +ccopts="`head -1 ../conf-ccperl`" +runperl="`head -1 ../conf-perl`" + +case "$ccopts" in + auto) + ccopts="`$runperl -MExtUtils::Embed -e ccopts`" + ;; +esac + +echo "$ccopts" diff --git a/src/print-dl.sh b/src/print-dl.sh new file mode 100644 index 0000000..faa491c --- /dev/null +++ b/src/print-dl.sh @@ -0,0 +1,14 @@ +ssllib="`head -1 ../conf-ssllib`" + +dlflag=0 + +rm -f trycpp.o + +dlflag=`cc -c tryssl.c -ldl 2>&1 | wc -l` +if [ $dlflag -eq 0 ]; then + ssllib="$ssllib -ldl" +fi + +rm -f trycpp.o + +echo $ssllib diff --git a/src/print-ld.sh b/src/print-ld.sh new file mode 100644 index 0000000..c13472c --- /dev/null +++ b/src/print-ld.sh @@ -0,0 +1,18 @@ +ld="`head -1 ../conf-ld`" +qlibs="`head -1 ../conf-qlibs`" +systype="`cat systype`" + +flag=0 + +rm -f trycpp.o + +flag=`cc -c tryssl.c -m64 2>&1 | wc -l` +if [ $flag -eq 0 ]; then + ld="$ld -m64" +fi + +rm -f trycpp.o + +cat warn-auto.sh +echo 'main="$1"; shift' +echo exec "$ld" -L"${qlibs}" '-o "$main" "$main".o ${1+"$@"} -ldnsresolv -lqlibs' diff --git a/src/print-ldperl.sh b/src/print-ldperl.sh new file mode 100644 index 0000000..02331f0 --- /dev/null +++ b/src/print-ldperl.sh @@ -0,0 +1,10 @@ +ldopts="`head -1 ../conf-ldperl`" +runperl="`head -1 ../conf-perl`" + +case "$ldopts" in + auto) + ldopts="`$runperl -MExtUtils::Embed -e ldopts`" + ;; +esac + +echo "$ldopts" diff --git a/src/print-perlembed.sh b/src/print-perlembed.sh new file mode 100644 index 0000000..337da8e --- /dev/null +++ b/src/print-perlembed.sh @@ -0,0 +1,10 @@ +ldopts="`head -1 ../conf-ldperl`" +runperl="`head -1 ../conf-perl`" + +case "$ldopts" in + auto) + ldopts="$runperl -MExtUtils::Embed -e ldopts" + ;; +esac + +echo "$ldopts" diff --git a/src/remoteinfo.c b/src/remoteinfo.c new file mode 100644 index 0000000..665d2e5 --- /dev/null +++ b/src/remoteinfo.c @@ -0,0 +1,102 @@ +#include <unistd.h> +#include "fmt.h" +#include "buffer.h" +#include "socket_if.h" +#include "error.h" +#include "iopause.h" +#include "timeoutconn.h" +#include "dnsresolv.h" +#include "remoteinfo.h" + +static struct taia now; +static struct taia deadline; + +static int mywrite(int fd,char *buf,int len) +{ + iopause_fd x; + int r; + + x.fd = fd; + x.events = IOPAUSE_WRITE; + for (;;) { + taia_now(&now); + r = iopause(&x,1,&deadline,&now); + if (r > 0 && x.revents) break; + if (taia_less(&deadline,&now)) { + errno = ETIMEDOUT; + return -1; + } + } + return write(fd,buf,len); +} + +static int myread(int fd,char *buf,int len) +{ + iopause_fd x; + int r; + + x.fd = fd; + x.events = IOPAUSE_READ; + for (;;) { + taia_now(&now); + r = iopause(&x,1,&deadline,&now); + if (r > 0 && x.revents) break; + if (taia_less(&deadline,&now)) { + errno = ETIMEDOUT; + return -1; + } + } + return read(fd,buf,len); +} + +static int doit(stralloc *out,int s,char ipremote[16],uint16 portremote,char iplocal[16],uint16 portlocal,unsigned int timeout,uint32 netif) +{ + buffer b; + char bspace[128]; + char strnum[FMT_ULONG]; + int numcolons; + char ch; + + if (socket_bind(s,iplocal,0,netif) == -1) return -1; + if (timeoutconn(s,ipremote,113,timeout,netif) == -1) return -1; + + buffer_init(&b,(ssize_t (*)())mywrite,s,bspace,sizeof(bspace)); + buffer_put(&b,strnum,fmt_ulong(strnum,portremote)); + buffer_put(&b," , ",3); + buffer_put(&b,strnum,fmt_ulong(strnum,portlocal)); + buffer_put(&b,"\r\n",2); + if (buffer_flush(&b) == -1) return -1; + + buffer_init(&b,(ssize_t (*)())myread,s,bspace,sizeof(bspace)); + numcolons = 0; + for (;;) { + if (buffer_get(&b,&ch,1) != 1) return -1; + if ((ch == ' ') || (ch == '\t') || (ch == '\r')) continue; + if (ch == '\n') return 0; + if (numcolons < 3) { + if (ch == ':') ++numcolons; + } + else { + if (!stralloc_append(out,&ch)) return -1; + if (out->len > 256) return 0; + } + } +} + +int remoteinfo(stralloc *out,char ipremote[16],uint16 portremote,char iplocal[16],uint16 portlocal,unsigned int timeout,uint32 netif) +{ + int s; + int r; + + if (!stralloc_copys(out,"")) return -1; + + taia_now(&now); + taia_uint(&deadline,timeout); + taia_add(&deadline,&now,&deadline); + + s = socket_tcp(); + if (s == -1) return -1; + r = doit(out,s,ipremote,portremote,iplocal,portlocal,timeout,netif); + close(s); + return r; +} diff --git a/src/remoteinfo.h b/src/remoteinfo.h new file mode 100644 index 0000000..37092d0 --- /dev/null +++ b/src/remoteinfo.h @@ -0,0 +1,9 @@ +#ifndef REMOTEINFO_H +#define REMOTEINFO_H + +#include "stralloc.h" +#include "uint_t.h" + +extern int remoteinfo(stralloc *,char *,uint16,char *,uint16,unsigned int,uint32); + +#endif diff --git a/src/rts.base b/src/rts.base new file mode 100644 index 0000000..0096007 --- /dev/null +++ b/src/rts.base @@ -0,0 +1,329 @@ +#!/bin/sh +# Assumptions: +# ucspi-tcp +# available TCP ports on ::1: 50013--50021 +# 127.0.0.1 is resolved as 'localhost' +# ::1/128 is resolved as 'ip6-loopback' +# 0.0.0.0 and ::/128 is resolved as 'localnet' +# +# $here is ucspi-ssl current directory +# +# Not tested: +# setting UID or GID +# rules +# write timeout + +echo '---> test sslserver + sslclient: four instances of sslserver (ports 50013, 50014, 50015, 50016) are used' +echo '---> sslserver @port 50015 requires client certs' +echo '++++' + +sslserver -w 2 \ +-s -E -c 1 -Bbanner -Vo -D -1 -3 -Xx rules.cdb -Rt5 -h -l Localserver -b 2 \ +::1 50016 ./print 3< $CADIR/::1.pw > log.50016 2>&1 & +pid_50016=$! + +sslserver -w 2 \ +-s -e -c 1 -Bbanner -Vo -D -1 -3 -Xx rules.cdb -Rt5 -h -l Localserver -b 2 -m \ +::1 50015 ./print 3< $CADIR/::1.pw > log.50015 2>&1 & +pid_50015=$! + +CIPHERS='' sslserver -w 2 \ +-s -e -c 1 -Bbanner -Vo -D -1 -3 -Xx rules.cdb -Rt5 -h -l Localserver -b 2 \ +::1 50014 ./print >log.50014 3< $CADIR/::1.pw 2>&1 & +pid_50014=$! +sleep 1 + +sslserver -w 2 \ +-s -e -c 1 -Bbanner -Vo -D -1 -3 -Xx rules.cdb -Rt5 -h -l Localserver -b 2 \ +::1 50013 cat - >log.50013 3< $CADIR/::1.pw 2>&1 & +pid_50013=$! +sleep 1 + +echo '---> test sslclient/sslserver behavior with wrong parm (timeout 2 secs)' +echo '++++' + +echo '--- sslclient prints usage message without enough arguments' +sslclient -T2 0 0; echo $? + +echo '--- sslclient prints error message with unknown port name' +sslclient -T2 0 nonexistentport echo wrong; echo $? + +echo '--- sslclient prints error message when connection fails' +sslclient -T2 0 016 echo wrong; echo $? + +echo '--- sslclient -q does not print error message when connection fails' +sslclient -T2 -q 0 016 echo wrong; echo $? + +echo '--- sslclient prints error message with unknown host name' +sslclient nonexistent.local. 016 echo wrong; echo $? + +echo '--- sslclient prints error message with unresolvable host name' +sslclient thislabelistoolongbecausednshasalimitof63charactersinasinglelabel. 50016 echo wrong; echo $? + +echo '--- sslserver prints usage message without enough arguments' +sslserver 0 0; echo $? + +echo '--- sslserver prints error message with unknown port name' +sslserver 0 nonexistentport echo wrong; echo $? + +echo '--- sslserver prints error message with unknown host name' +sslserver nonexistent.local. 016 echo wrong; echo $? + +echo '--- sslserver prints error message with unresolvable host name' +sslserver thislabelistoolongbecausednshasalimitof63charactersinasinglelabel. 50016 echo wrong; echo $? + +echo '--- sslserver prints error message with non-local host name' +( sslserver 1.2.3.4 016 echo wrong 2>&1 + echo $? +) | sed -e 's/unable to bind to: .*/unable to bind to: .../' + + +echo '---> test sslclient to connect to sslserver (on different port; note: cert verify will fail on localhost)' +echo '++++' + +echo '--- sslclient sets basic environment variables' +{ + sslclient -p 50017 -R -N -H -T 10 -l Local -a "$CAFILE" ::1 50016 sh -c 'cat <&6' + echo $? +} | sed -e 's/unable to bind to: .*/unable to bind to: .../' + + +echo '--- sslserver -e also sets TCP environment variables' +{ + sslclient -p 50018 -e -S -R -N -H -T 10 -l Local -a "$CAFILE" ::1 50016 sh -c 'cat <&6' + echo $? +} | sanitize + +echo '--- sslclient recognizes -D, -z, -r, -h, -t (with elective cipher)' +{ + sslclient -p 50019 -N -D -r -t1 -l Local -a "$CAFILE" \ + -z 'TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256' \ + ::1 50016 sh -c 'cat <&6' + echo $? +} +#} | sanitize + +echo '--- sslclient sets basic environment variables' +{ + sslclient -p 50020 -R -N -H -l Local -a "$CAFILE" ::1 50016 ./print + echo $? +} | sanitize + +echo '--- sslclient -e sets TCP environment variables' +{ + sslclient -p 50021 -e -R -N -H -l Local -a "$CAFILE" ::1 50016 ./print + echo $? +} | sanitize + +echo '--- sslclient -s sets TLS environment variables' +{ + sslclient -p 50022 -s -R -N -H -l Local -a "$CAFILE" ::1 50016 ./print + echo $? +} | sanitize + +echo '--- sslclient looks up host names properly (localhost. -> ip6-loopback)' +{ + sslclient -p 50023 -R -N -a "$CAFILE" localhost. 50016 ./print + echo $? +} | sanitize + +echo '--- sslclient -v works' +sslclient -p 50024 -v -R -N -H -l Local -a "$CAFILE" ::1 50016 echo ok +echo $? + +echo '--- sslserver -N does not check certificates CN' +( exec 2>&1 + sslclient -p 50025 -v -R -H -N -l ip6-localhost -a "$CAFILE" -X ::1 50014 sh -c 'sleep 1; echo ok' + echo $? +) | sanitize + +echo '--- sslserver and sslclient print errors for incompatible cipher lists for TLS < 1.3' +( exec 2>&1 + sslclient -p 50026 -v -R -H -N -l ip6-localhost -z 'FOOBAR' -a "$CAFILE" ::1 50014 \ + sh -c 'sleep 1; echo ok' + echo $? +) | sanitize + +echo '--- sslclient -X ignores any server certificate' +( exec 2>&1 + sslclient -p 50027 -v -R -H -l ip6-localhost -X ::1 50014 \ + sh -c 'sleep 1; echo ok' + echo $? +) | sanitize + +echo '--- sslclient -n checks hostname with certificates SAN/CN' +( exec 2>&1 + sslclient -p 50027 -v -R -H -l ip6-localhost -a "$CAFILE" ::1 50014 \ + sh -c 'sleep 1; echo ok' + echo $? +) | sanitize + +echo '---> test sslclient to connect to sslserver requiring client cert' +echo '++++' + +echo '--- sslserver prints error for no client certificate' +( exec 2>&1 + sslclient -p 50028 -v -R -N -h -l ip6-localhost -a "$CAFILE" ::1 50015 \ + sh -c 'sleep 1; echo ok' + echo $? +) | sanitize + +echo '--- sslserver prints error for bad client certificate' +( exec 2>&1 + exec 3< $CADIR/::1.pw + sslclient -p 50029 -v -R -h -l ip6-localhost -a "$CAFILE" -c "$CERTFILE" -k "$KEYFILE" -3 \ + ::1 50015 sh -c 'sleep 1; echo ok' + echo $? +) | sanitize + +echo '--- sslclient uses certificates' +( exec 2>&1 + exec 3< $CADIR/localhost.pw + sslclient -p 50030 -v -s -R -N -h -l ip6-localhost -a "$CAFILE" -c "$CCERTFILE" -k "$CKEYFILE" -3 \ + ::1 50015 sh -c 'cat <&6; ./print' + echo $? +) | sanitize + +echo '---> test sslcat to connect to sslserver@5016' +echo '++++' + +echo '--- sslcat works' +{ + sslcat ::1 50013 -N -a "$CAFILE" -N + echo $? +} | sanitize + +echo '--- sslconnect works' +{ + sslconnect ::1 50013 -N -a "$CAFILE" </dev/null + echo $? +} | sanitize + +echo '--- https@ works' +https@ ::1 somefile 50013 -X -a "$CAFILE" +echo $? + + +echo '---> test sslconnect to connect to sslserver@5013' +echo '++++' + + +echo '--- sslclient and sslserver handle larger data' +( exec 2>&1 + exec 3< $CADIR/localhost.pw + { for i in 0 1 2 3 4 5 6 7 8 9 + do + for j in 0 1 2 3 4 5 6 7 8 9 + do + for k in 0 1 2 3 4 5 6 7 8 9 + do + echo "abcdefghijklmnopqrstuvwxyz" + echo "abcdefghijklmnopqrstuvwxyz" + echo "abcdefghijklmnopqrstuvwxyz" + echo "abcdefghijklmnopqrstuvwxyz" + done + done + done + } | sslconnect ::1 50013 -v -s -N \ + -a "$CAFILE" -c "$CCERTFILE" -k "$CKEYFILE" -3 > /dev/null + echo $? +) | sanitize + +echo '--- sslserver times out' +( exec 2>&1 + exec 3< $CADIR/localhost.pw + ( exec echo hereur ) | sslconnect ::1 50013 -v -s -N \ + -a "$CAFILE" -c "$CCERTFILE" -k "$CKEYFILE" -3 + echo $? +) | sanitize + +( exec 2>&1 + exec 3< $CADIR/localhost.pw + ( sleep 6; exec echo hereur; ) | sslconnect ::1 50013 -v -s -N \ + -a "$CAFILE" -c "$CCERTFILE" -k "$CKEYFILE" -3 + echo $? +) | sanitize + +## Kill all sslserver processes + +kill -TERM $pid_50013 +kill -TERM $pid_50014 +kill -TERM $pid_50015 +kill -TERM $pid_50016 +wait $pid_50013 +wait $pid_50014 +wait $pid_50015 +wait $pid_50016 + +echo '---> test sslprint@50021' +echo '++++' + + +sslprint \ +-s -c 1 -Bsslprint -vo -D -e -1 -3 -Xx rules.cdb -Rt5 -hp -l Localserver -b 2 \ +::1 50021 3< $CADIR/::1.pw > log.sslprint 2>&1 & +pid_50021=$! +sleep 2 + +echo '--- sslprint prints usage message without enough arguments' +sslprint 0; echo $? + +echo '--- sslprint prints error message with unknown port name' +sslprint 0 nonexistentport; echo $? + +echo '--- sslprint prints error message with unknown host name' +sslprint nonexistent.local. 016; echo $? + +echo '--- sslprint prints error message with unresolvable host name' +sslprint thislabelistoolongbecausednshasalimitof63charactersinasinglelabel. 016; echo $? + +echo '--- sslprint prints error message with non-local host name' +( sslprint 1.2.3.4 16 2>&1 + echo $? +) | sed -e 's/unable to bind to: .*/unable to bind to: .../' + + +echo '--- sslprint prints error message with used port' +sslprint -R -H -l Localserver ::1 50021 echo wrong +echo $? + +echo '--- sslprint sets basic environment variables' +{ sslclient -R -H -T 5 -l Local -a "$CAFILE" -N ::1 50021 sh -c 'cat <&6' + echo $? +} | sanitize + +echo '--- sslprint exits when environment changes' +{ sslclient -R -H -T 5 -l Local -a "$CAFILE" -N ::1 50021 sh -c 'cat <&6' + echo $? +} | sanitize + +echo '--- sslprint does not lose descriptors' +{ sslclient -R -H -T 5 -l Local -a "$CAFILE" -N ::1 50021 sh -c 'cat <&6' \ + 0<&- 2<&- + echo $? +} | sanitize + +sleep 1 +kill -TERM $pid_50021 +wait $pid_50021 + + +echo '--- sslserver -1v prints proper messages' +cat log.50016 log.50015 log.50014 log.50013 log.sslprint | \ +sed -e 's/::*/::x/' \ + -e 's} [0-9]* } x }g' \ + -e 's} ip6-loopback:::1::[0-9]*} ip6-loopback:::1::x}' \ + -e 's} :::1:[0-9]*} :::1:x}' \ + -e 's} cafile x .*/\([^/]*\)} cafile x xxx/\1}' \ + -e 's} ccafile x .*/\([^/]*\)} ccafile x xxx/\1}' \ + -e 's} cadir x .*/\([^/]*\)} cadir x xxx/\1}' \ + -e 's} cert x .*/\([^/]*\)} cert x xxx/\1}' \ + -e 's} key x .*/\([^/]*\)} key x xxx/\1}' \ + -e 's} dhparam x .*} dhparam x xxx}' \ + -e 's} speak TLS: .*} speak TLS: ...}' \ + -e 's} accept TLS: .*} accept TLS: ...}' \ + -e 's} done [0-9]*$} done ...}' \ + -e 's} Localserver:::1:[0-9]*} Localserver:::1:x}' \ + -e 's} ip6-localnet:::::[0-9]*} ip6-localnet:::::x}' \ + -e 's} valid client cert received for pid: .*} valid client cert received for pid: ...}' + diff --git a/src/rts.it b/src/rts.it new file mode 100644 index 0000000..7c0fa0e --- /dev/null +++ b/src/rts.it @@ -0,0 +1,197 @@ +# Umbrella script to provide *SSL environment +# and helper functions + +PATH="`pwd`:$PATH" +CADIR=`pwd | cut -d':' -f1 | sed s/compile/etc/` + +# include the ssl and crypto libs by means of LD_LIBRARY_PATH +#export LD_LIBRARY_PATH="/home/ucspi/_SSL/libressl-3.7.2/ssl/.libs:/home/ucspi/_SSL/libressl-3.7.2/crypto/.libs" +export LD_LIBRARY_PATH="/home/ucspi/_SSL/openssl-3.2.0-alpha2" + +rm -rf rts-tmp +mkdir rts-tmp +cd rts-tmp + +CAFILE="$CADIR/rootCA_cert.pem" +if [ ! -f $CAFILE ] +then + echo "$CAFILE does no exist!" + exit 1 +fi +CERTFILE="$CADIR/::1_cert.pem" +if [ ! -f $CERTFILE ] +then + echo "$CERTFILE does no exist!" + exit 1 +fi +CHAINFILE="$CADIR/chain6.pem" +if [ ! -f $CHAINFILE ] +then + echo "$CHAINFILE does no exist!" + exit 1 +fi +KEYFILE="$CADIR/::1_key.pem" +if [ ! -f $KEYFILE ] +then + echo "$KEYFILE does no exist!" + exit 1 +fi +CCAFILE="$CADIR/rootCA_cert.pem" +if [ ! -f $CCAFILE ] +then + echo "$CCAFILE does no exist!" + exit 1 +fi +CCERTFILE="$CADIR/localhost_cert.pem" +if [ ! -f $CCERTFILE ] +then + echo "$CCERTFILE does no exist!" + exit 1 +fi +CKEYFILE="$CADIR/localhost_key.pem" +if [ ! -f $CKEYFILE ] +then + echo "$CKEYFILE does no exist!" + exit 1 +fi +DHFILE="$CADIR/dh2048.pem" +if [ ! -f $DHFILE ] +then + echo "$DHFILE does no exist!" + exit 1 +fi + +export CADIR CAFILE CCAFILE CERTFILE CHAINFILE KEYFILE CCERTFILE CKEYFILE DHFILE + +# Create ./print file + +echo '#!/bin/sh +# trap "" 13 + echo "" + echo PROTO="$PROTO" + echo SSLLOCALHOST="${SSLLOCALHOST-unset}" + echo SSLLOCALIP="${SSLLOCALIP-unset}" + echo SSLLOCALPORT="${SSLLOCALPORT-unset}" + echo SSLREMOTEHOST="${SSLREMOTEHOST-unset}" + echo SSLREMOTEIP="${SSLREMOTEIP-unset}" + echo SSLREMOTEPORT="${SSLREMOTEPORT-unset}" + echo SSLREMOTEINFO="${SSLREMOTEINFO-unset}" + + echo TCPLOCALHOST="${TCPLOCALHOST-unset}" + echo TCPLOCALIP="${TCPLOCALIP-unset}" + echo TCPLOCALPORT="${TCPLOCALPORT-unset}" + + echo TCPREMOTEHOST="${TCPREMOTEHOST-unset}" + echo TCPREMOTEIP="${TCPREMOTEIP-unset}" + echo TCPREMOTEPORT="${TCPREMOTEPORT-unset}" + echo TCPREMOTEINFO="${TCPREMOTEINFO-unset}" + + echo TCP6REMOTEHOST="${TCP6REMOTEHOST-unset}" + echo TCP6REMOTEIP="${TCP6REMOTEIP-unset}" + echo TCP6REMOTEPORT="${TCP6REMOTEPORT-unset}" + + echo SSL_PROTOCOL="${SSL_PROTOCOL-unset}" + echo SSL_SESSION_ID="${SSL_SESSION_ID-unset}" + echo SSL_CIPHER="${SSL_CIPHER-unset}" + echo SSL_CIPHER_EXPORT="${SSL_CIPHER_EXPORT-unset}" + echo SSL_CIPHER_USEKEYSIZE="${SSL_CIPHER_USEKEYSIZE-unset}" + echo SSL_CIPHER_ALGKEYSIZE="${SSL_CIPHER_ALGKEYSIZE-unset}" + echo SSL_VERSION_INTERFACE="${SSL_VERSION_INTERFACE-unset}" + echo SSL_VERSION_LIBRARY="${SSL_VERSION_LIBRARY-unset}" + + echo SSL_SERVER_M_VERSION="${SSL_SERVER_M_VERSION-unset}" + echo SSL_SERVER_M_SERIAL="${SSL_SERVER_M_SERIAL-unset}" + echo SSL_SERVER_S_DN="${SSL_SERVER_S_DN-unset}" + echo SSL_SERVER_S_DN_C="${SSL_SERVER_S_DN_C-unset}" + echo SSL_SERVER_S_DN_ST="${SSL_SERVER_S_DN_ST-unset}" + echo SSL_SERVER_S_DN_L="${SSL_SERVER_S_DN_L-unset}" + echo SSL_SERVER_S_DN_O="${SSL_SERVER_S_DN_O-unset}" + echo SSL_SERVER_S_DN_OU="${SSL_SERVER_S_DN_OU-unset}" + echo SSL_SERVER_S_DN_CN="${SSL_SERVER_S_DN_CN-unset}" + echo SSL_SERVER_S_DN_T="${SSL_SERVER_S_DN_T-unset}" + echo SSL_SERVER_S_DN_I="${SSL_SERVER_S_DN_I-unset}" + echo SSL_SERVER_S_DN_G="${SSL_SERVER_S_DN_G-unset}" + echo SSL_SERVER_S_DN_S="${SSL_SERVER_S_DN_S-unset}" + echo SSL_SERVER_S_DN_D="${SSL_SERVER_S_DN_D-unset}" + echo SSL_SERVER_S_DN_UID="${SSL_SERVER_S_DN_UID-unset}" + echo SSL_SERVER_S_DN_Email="${SSL_SERVER_S_DN_Email-unset}" + echo SSL_SERVER_I_DN="${SSL_SERVER_I_DN-unset}" + echo SSL_SERVER_I_DN_C="${SSL_SERVER_I_DN_C-unset}" + echo SSL_SERVER_I_DN_ST="${SSL_SERVER_I_DN_ST-unset}" + echo SSL_SERVER_I_DN_L="${SSL_SERVER_I_DN_L-unset}" + echo SSL_SERVER_I_DN_O="${SSL_SERVER_I_DN_O-unset}" + echo SSL_SERVER_I_DN_OU="${SSL_SERVER_I_DN_OU-unset}" + echo SSL_SERVER_I_DN_CN="${SSL_SERVER_I_DN_CN-unset}" + echo SSL_SERVER_I_DN_T="${SSL_SERVER_I_DN_T-unset}" + echo SSL_SERVER_I_DN_I="${SSL_SERVER_I_DN_I-unset}" + echo SSL_SERVER_I_DN_G="${SSL_SERVER_I_DN_G-unset}" + echo SSL_SERVER_I_DN_S="${SSL_SERVER_I_DN_S-unset}" + echo SSL_SERVER_I_DN_D="${SSL_SERVER_I_DN_D-unset}" + echo SSL_SERVER_I_DN_UID="${SSL_SERVER_I_DN_UID-unset}" + echo SSL_SERVER_I_DN_Email="${SSL_SERVER_I_DN_Email-unset}" + echo SSL_SERVER_V_START="${SSL_SERVER_V_START-unset}" + echo SSL_SERVER_V_END="${SSL_SERVER_V_END-unset}" + echo SSL_SERVER_A_SIG="${SSL_SERVER_A_SIG-unset}" + echo SSL_SERVER_A_KEY="${SSL_SERVER_A_KEY-unset}" + echo SSL_SERVER_CERT="${SSL_SERVER_CERT-unset}" + + echo SSL_CLIENT_M_VERSION="${SSL_CLIENT_M_VERSION-unset}" + echo SSL_CLIENT_M_SERIAL="${SSL_CLIENT_M_SERIAL-unset}" + echo SSL_CLIENT_S_DN="${SSL_CLIENT_S_DN-unset}" + echo SSL_CLIENT_S_DN_C="${SSL_CLIENT_S_DN_C-unset}" + echo SSL_CLIENT_S_DN_ST="${SSL_CLIENT_S_DN_ST-unset}" + echo SSL_CLIENT_S_DN_L="${SSL_CLIENT_S_DN_L-unset}" + echo SSL_CLIENT_S_DN_O="${SSL_CLIENT_S_DN_O-unset}" + echo SSL_CLIENT_S_DN_OU="${SSL_CLIENT_S_DN_OU-unset}" + echo SSL_CLIENT_S_DN_CN="${SSL_CLIENT_S_DN_CN-unset}" + echo SSL_CLIENT_S_DN_T="${SSL_CLIENT_S_DN_T-unset}" + echo SSL_CLIENT_S_DN_I="${SSL_CLIENT_S_DN_I-unset}" + echo SSL_CLIENT_S_DN_G="${SSL_CLIENT_S_DN_G-unset}" + echo SSL_CLIENT_S_DN_S="${SSL_CLIENT_S_DN_S-unset}" + echo SSL_CLIENT_S_DN_D="${SSL_CLIENT_S_DN_D-unset}" + echo SSL_CLIENT_S_DN_UID="${SSL_CLIENT_S_DN_UID-unset}" + echo SSL_CLIENT_S_DN_Email="${SSL_CLIENT_S_DN_Email-unset}" + echo SSL_CLIENT_I_DN="${SSL_CLIENT_I_DN-unset}" + echo SSL_CLIENT_I_DN_C="${SSL_CLIENT_I_DN_C-unset}" + echo SSL_CLIENT_I_DN_ST="${SSL_CLIENT_I_DN_ST-unset}" + echo SSL_CLIENT_I_DN_L="${SSL_CLIENT_I_DN_L-unset}" + echo SSL_CLIENT_I_DN_O="${SSL_CLIENT_I_DN_O-unset}" + echo SSL_CLIENT_I_DN_OU="${SSL_CLIENT_I_DN_OU-unset}" + echo SSL_CLIENT_I_DN_CN="${SSL_CLIENT_I_DN_CN-unset}" + echo SSL_CLIENT_I_DN_T="${SSL_CLIENT_I_DN_T-unset}" + echo SSL_CLIENT_I_DN_I="${SSL_CLIENT_I_DN_I-unset}" + echo SSL_CLIENT_I_DN_G="${SSL_CLIENT_I_DN_G-unset}" + echo SSL_CLIENT_I_DN_S="${SSL_CLIENT_I_DN_S-unset}" + echo SSL_CLIENT_I_DN_D="${SSL_CLIENT_I_DN_D-unset}" + echo SSL_CLIENT_I_DN_UID="${SSL_CLIENT_I_DN_UID-unset}" + echo SSL_CLIENT_I_DN_Email="${SSL_CLIENT_I_DN_Email-unset}" + echo SSL_CLIENT_V_START="${SSL_CLIENT_V_START-unset}" + echo SSL_CLIENT_V_END="${SSL_CLIENT_V_END-unset}" + echo SSL_CLIENT_A_SIG="${SSL_CLIENT_A_SIG-unset}" + echo SSL_CLIENT_A_KEY="${SSL_CLIENT_A_KEY-unset}" + echo SSL_CLIENT_CERT="${SSL_CLIENT_CERT-unset}" + echo SSL_CLIENT_CERT_CHAIN_0="${SSL_CLIENT_CERT_CHAIN_0-unset}" + echo SSL_CLIENT_CERT_CHAIN_1="${SSL_CLIENT_CERT_CHAIN_1-unset}" +' > print +chmod 755 print + + +# Sanitze output + +sanitize() { + sed -e 's/^SSL_SESSION_ID=.*/SSL_SESSION_ID=.../' \ + -e 's/^SSLREMOTEPORT=.*/SSLREMOTEPORT=.../' \ + -e 's/^SSLLOCALPORT=.*/SSLLOCALPORT=.../' \ + -e 's/^TCPREMOTEPORT=.*/TCPREMOTEPORT=.../' \ + -e 's/^TCP6REMOTEPORT=.*/TCP6REMOTEPORT=.../' \ + -e 's/^TCPLOCALPORT=.*/TCPLOCALPORT=.../' \ + -e 's/^SSL_VERSION_LIBRARY=.*/SSL_VERSION_LIBRARY=.../' \ + -e 's/^SSL_CIPHER_USEKEYSIZE=.*/SSL_CIPHER_USEKEYSIZE=.../' \ + -e 's/^SSL_CIPHER_ALGKEYSIZE=.*/SSL_CIPHER_ALGKEYSIZE=.../' \ + -e 's/^SSL_CIPHER=.*/SSL_CIPHER=.../' \ + -e 's/^SSL_PROTOCOL=TLSv1.*/SSL_PROTOCOL=TLSv1.../' \ + -e 's/Localserver:::1:[0-9]*/Localserver:::1:... /' \ + -e 's/ip6-localnet:::::[0-9]*/ip6-localnet:::::.../' +} + +# done diff --git a/src/rts.sslperl b/src/rts.sslperl new file mode 100644 index 0000000..3d1e560 --- /dev/null +++ b/src/rts.sslperl @@ -0,0 +1,157 @@ +# Assumptions: +# available TCP ports on 127.0.0.1: 50022 + +echo 'package Embedded::test; +my $n = 0; +$| = 1; +sub server (@) { + ++$n; + print STDERR "log: Hello, World! ($n): @_\n"; + print "Hello, World! ($n): @_\n"; + + $n > 1 and exit(0); +} +1; +' > hello.pm + +sanitize() { + sed -e 's/^SSL_SESSION_ID=.*/SSL_SESSION_ID=.../' \ + -e 's/^SSLREMOTEPORT=.*/SSLREMOTEPORT=.../' \ + -e 's/^SSLLOCALPORT=.*/SSLLOCALPORT=.../' \ + -e 's/^TCPREMOTEPORT=.*/TCPREMOTEPORT=.../' \ + -e 's/^TCP6REMOTEPORT=.*/TCP6REMOTEPORT=.../' \ + -e 's/^TCPLOCALPORT=.*/TCPLOCALPORT=.../' \ + -e 's/^SSL_VERSION_LIBRARY=.*/SSL_VERSION_LIBRARY=.../' \ + -e 's/^SSL_CIPHER_USEKEYSIZE=.*/SSL_CIPHER_USEKEYSIZE=.../' \ + -e 's/^SSL_CIPHER_ALGKEYSIZE=.*/SSL_CIPHER_ALGKEYSIZE=.../' \ + -e 's/^SSL_CIPHER=.*/SSL_CIPHER=.../' \ + -e 's/^SSL_PROTOCOL=TLSv1.*/SSL_PROTOCOL=TLSv1.../' +} + +sslperl -w 2 \ +-s -c 1 -Bsslperl -vo -D -1 -3 -Xx rules.cdb -Rt5 -hp -l Localserver -b 2 \ +-a -A \ +127.0.0.1 50022 hello.pm 'Embedded::test::server' here you are \ +3< $CADIR/127.0.0.1.pw >log.50022 2>&1 & +pid_50022=$! +sleep 2 + +echo '--- sslperl works' +{ sslclient -R -N -H -T 10 -l Local -a "$CAFILE" -4 0 50022 sh -c 'cat <&6' + echo $? +} | sanitize +{ sslclient -R -N -H -T 10 -l Local -a "$CAFILE" -4 0 50022 sh -c 'cat <&6' + echo $? +} | sanitize +{ sslclient -R -N -H -T 10 -l Local -a "$CAFILE" -4 0 50022 sh -c 'cat <&6' + echo $? +} | sanitize +{ sslclient -R -N -H -T 10 -l Local -X -4 0 50022 sh -c 'cat <&6' + echo $? +} | sanitize + +echo '--- sslperl prints usage message without enough arguments' +sslperl 0; echo $? + +echo '--- sslperl prints error message with unknown port name' +sslperl 0 nonexistentport echo wrong; echo $? + +echo '--- sslperl prints error message with unknown host name' +sslperl nonexistent.local. 016 echo wrong; echo $? + +echo '--- sslperl prints error message with unresolvable host name' +sslperl thislabelistoolongbecausednshasalimitof63charactersinasinglelabel. 50022 echo wrong; echo $? + +echo '--- sslperl prints error message with non-local host name' +( sslperl 1.2.3.4 016 echo wrong 2>&1 + echo $? +) | sed -e 's/unable to bind: .*$/unable to bind: .../' + +kill -TERM $pid_50022 +wait $pid_50022 + +echo '--- sslperl preserves environment' +echo 'package Embedded::test; +my $n = 0; +$| = 1; +sub server () { + print STDERR "log: NOW=$ENV{NOW}\n"; + print STDERR "log: changed environment\n"; + print " changed environment\n"; + $ENV{'HERE'} = 'NOW'; +} +1; +' > hello.pm + +sslperl -w 2 \ +-s -c 1 -Bsslperl -vo -D -1 -3 -Xx rules.cdb -Rt5 -hp -l Localserver -b 2 \ +-a -A \ +127.0.0.1 50022 hello.pm 'Embedded::test::server' here you are \ +3< $CADIR/127.0.0.1.pw >>log.50022 2>&1 & +pid_50022=$! +sleep 2 + +{ sslclient -R -N -H -T 10 -l Local -a "$CAFILE" -4 0 50022 sh -c 'cat <&6' + echo $? +} | sanitize + +kill -TERM $pid_50022 +wait $pid_50022 + +echo '--- sslperl handles larger requests' +echo 'package Embedded::test; +my $n = 0; +$| = 1; +sub server (@) { + print @_; + while(<>) { + print $_; + } +} +1; +' > echo.pm + +sslperl -w 2 \ +-s -c 1 -Bsslperl -vo -D -1 -3 -Xx rules.cdb -Rt5 -hp -l Localserver -b 2 \ +-a -A \ +127.0.0.1 50022 echo.pm 'Embedded::test::server' here you are \ +3< $CADIR/127.0.0.1.pw >>log.50022 2>&1 & +pid_50022=$! +sleep 2 + +( exec 2>&1 + exec 3< $CADIR/localhost.pw + { for i in 0 1 2 3 4 5 6 7 8 9 + do + for j in 0 1 2 3 4 5 6 7 8 9 + do + for k in 0 1 2 3 4 5 6 7 8 9 + do + echo "abcdefghijklmnopqrstuvwxyz" + echo "abcdefghijklmnopqrstuvwxyz" + echo "abcdefghijklmnopqrstuvwxyz" + echo "abcdefghijklmnopqrstuvwxyz" + done + done + done + } | sslconnect 127.0.0.1 50022 -v -s \ + -a "$CAFILE" -c "$CCERTFILE" -k "$CKEYFILE" -3 >/dev/null + echo $? +) | sanitize + +kill -TERM $pid_50022 +wait $pid_50022 + +echo '--- sslserver -1v prints proper messages' +cat log.50022 | \ +sed -e 's/::.*/::x/' -e 's/ [0-9]* / x /' \ + -e 's} cafile x .*/\([^/]*\)} cafile x xxx/\1}' \ + -e 's} ccafile x .*/\([^/]*\)} ccafile x xxx/\1}' \ + -e 's} cadir x .*/\([^/]*\)} cadir x xxx/\1}' \ + -e 's} cert x .*/\([^/]*\)} cert x xxx/\1}' \ + -e 's} key x .*/\([^/]*\)} key x xxx/\1}' \ + -e 's/ dhparam x .*/ dhparam x xxx/' \ + -e 's/ ecdhparam x .*/ ecdhparam x xxx/' \ + -e 's/ speak TLS: .*/ speak TLS: .../' \ + -e 's/ accept TLS: .*/ accept TLS: .../' \ + -e 's/ done [0-9]*$/ done .../' diff --git a/src/rules.c b/src/rules.c new file mode 100644 index 0000000..279ffae --- /dev/null +++ b/src/rules.c @@ -0,0 +1,141 @@ +#include "alloc.h" +#include "stralloc.h" +#include "open.h" +#include "cdbread.h" +#include "byte.h" +#include "fmt.h" +#include "getln.h" +#include "ip.h" +#include "str.h" +#include "ip_bit.h" +#include "rules.h" + +stralloc rules_name = {0}; +stralloc ipstring = {0}; + +static struct cdb c; + +static int dorule(void (*callback)(char *,unsigned int)) { + char *data; + unsigned int datalen; + + switch (cdb_find(&c,rules_name.s,rules_name.len)) { + case -1: return -1; + case 0: return 0; + } + + datalen = cdb_datalen(&c); + data = alloc(datalen); + if (!data) return -1; + if (cdb_read(&c,data,datalen,cdb_datapos(&c)) == -1) { + alloc_free(data); + return -1; + } + + callback(data, datalen); + alloc_free(data); + return 1; +} + +static int doit(void (*callback)(char *,unsigned int),char *ip,char *host,char *info) { + int p; + int r; + int ipv6 = str_len(ip) - byte_chr(ip,str_len(ip),':'); + + if (info) { /* 1. info@ip */ + if (!stralloc_copys(&rules_name,info)) return -1; + if (!stralloc_cats(&rules_name,"@")) return -1; + if (ipv6) { + if (!ip6_fmt_str(&ipstring,ip)) + if (!stralloc_catb(&rules_name,ipstring.s,ipstring.len)) return -1; + } + else + if (!stralloc_cats(&rules_name,ip)) return -1; + r = dorule(callback); + if (r) return r; + + if (host) { /* 2. info@=host */ + if (!stralloc_copys(&rules_name,info)) return -1; + if (!stralloc_cats(&rules_name,"@=")) return -1; + if (!stralloc_cats(&rules_name,host)) return -1; + r = dorule(callback); + if (r) return r; + } + } + + if (ipv6) { /* 3. IPv6/IPv4 */ + if (!ip6_fmt_str(&ipstring,ip)) { + if (!stralloc_copyb(&rules_name,ipstring.s,ipstring.len)) return -1; + r = dorule(callback); + if (r) return r; + } + } else { + if (!stralloc_copys(&rules_name,ip)) return -1; + r = dorule(callback); + if (r) return r; + } + + if (host) { /* 4. =host */ + if (!stralloc_copys(&rules_name,"=")) return -1; + if (!stralloc_cats(&rules_name,host)) return -1; + r = dorule(callback); + if (r) return r; + } + + if (!ipv6) { /* 5. IPv4 class-based */ + if (!stralloc_copys(&rules_name,ip)) return -1; + while (rules_name.len > 0) { + if (ip[rules_name.len - 1] == '.') { + r = dorule(callback); + if (r) return r; + } + --rules_name.len; + } + } + + if (ipv6) { /* 6. IPv6/IPv4 CIDR */ + if (!ip6_bitstring(&ipstring,ip,128)) { + for (p = 129; p > 1; p--) { + if (!stralloc_copys(&rules_name,"^")) return -1; + if (!stralloc_catb(&rules_name,ipstring.s,p)) return -1; + r = dorule(callback); + if (r) return r; + } + } + } else { + if (!ip4_bitstring(&ipstring,ip,32)) { + for (p = 33; p > 1; p--) { + if (!stralloc_copys(&rules_name,"_")) return -1; + if (!stralloc_catb(&rules_name,ipstring.s,p)) return -1; + r = dorule(callback); + if (r) return r; + } + } + } + + if (host) { /* 7. =host. */ + while (*host) { + if (*host == '.') { + if (!stralloc_copys(&rules_name,"=")) return -1; + if (!stralloc_cats(&rules_name,host)) return -1; + r = dorule(callback); + if (r) return r; + } + ++host; + } + if (!stralloc_copys(&rules_name,"=")) return -1; /* 8. = rule */ + r = dorule(callback); + if (r) return r; + } + + rules_name.len = 0; + return dorule(callback); +} + +int rules(void (*callback)(char *,unsigned int),int fd,char *ip,char *host,char *info) { + int r; + cdb_init(&c,fd); + r = doit(callback,ip,host,info); + cdb_free(&c); + return r; +} diff --git a/src/rules.h b/src/rules.h new file mode 100644 index 0000000..15d9b90 --- /dev/null +++ b/src/rules.h @@ -0,0 +1,9 @@ +#ifndef RULES_H +#define RULES_H + +#include "stralloc.h" + +extern stralloc rules_name; +extern int rules(void (*)(char *,unsigned int),int,char *,char *,char *); + +#endif diff --git a/src/select.h1 b/src/select.h1 new file mode 100644 index 0000000..68e971f --- /dev/null +++ b/src/select.h1 @@ -0,0 +1,12 @@ +/* Public domain. */ + +#ifndef SELECT_H +#define SELECT_H + +/* sysdep: -sysselect */ + +#include <sys/types.h> +#include <sys/time.h> +extern int select(); + +#endif diff --git a/src/select.h2 b/src/select.h2 new file mode 100644 index 0000000..4bd4fcf --- /dev/null +++ b/src/select.h2 @@ -0,0 +1,13 @@ +/* Public domain. */ + +#ifndef SELECT_H +#define SELECT_H + +/* sysdep: +sysselect */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/select.h> +extern int select(); + +#endif diff --git a/src/ssl_ca.c b/src/ssl_ca.c new file mode 100644 index 0000000..a6ab523 --- /dev/null +++ b/src/ssl_ca.c @@ -0,0 +1,11 @@ +#include "ucspissl.h" + +int ssl_ca(SSL_CTX *ctx,const char *certfile,const char *certdir,int d) +{ + if (!SSL_CTX_load_verify_locations(ctx,certfile,certdir)) return 0; + + SSL_CTX_set_verify_depth(ctx,d); + + return 1; +} + diff --git a/src/ssl_cca.c b/src/ssl_cca.c new file mode 100644 index 0000000..112a9f1 --- /dev/null +++ b/src/ssl_cca.c @@ -0,0 +1,18 @@ +#include "ucspissl.h" + +int ssl_cca(SSL_CTX *ctx,const char *certfile) +{ + STACK_OF(X509_NAME) *x; + + if (!certfile) return 1; + + x = SSL_load_client_CA_file(certfile); + if (!x) return 0; + + SSL_CTX_set_client_CA_list(ctx,x); + + SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0); + + return 1; +} + diff --git a/src/ssl_certkey.c b/src/ssl_certkey.c new file mode 100644 index 0000000..8292cbe --- /dev/null +++ b/src/ssl_certkey.c @@ -0,0 +1,19 @@ +#include "ucspissl.h" + +int ssl_certkey(SSL_CTX *ctx,const char *certfile,const char *keyfile,pem_password_cb *passwd_cb) +{ + if (!certfile) return 0; + + if (SSL_CTX_use_certificate_chain_file(ctx,certfile) != 1) + return -1; + + if (!keyfile) keyfile = certfile; + SSL_CTX_set_default_passwd_cb(ctx,passwd_cb); + if (SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM) != 1) + return -2; + + if (SSL_CTX_check_private_key(ctx) != 1) + return -3; + + return 0; +} diff --git a/src/ssl_chainfile.c b/src/ssl_chainfile.c new file mode 100644 index 0000000..9e353c2 --- /dev/null +++ b/src/ssl_chainfile.c @@ -0,0 +1,24 @@ +/** + @file ssl_certchainfile.c + @author feh + @brief Enables Certificate chain file presentation for sslserver +*/ +#include "ucspissl.h" + +int ssl_chainfile(SSL_CTX *ctx,const char *certchainfile,const char *keyfile,pem_password_cb *passwd_cb) +{ + if (!certchainfile) return 0; + if (!keyfile) return 0; + + if (SSL_CTX_use_certificate_chain_file(ctx,certchainfile) <= 0) + return -1; + + SSL_CTX_set_default_passwd_cb(ctx,passwd_cb); + if (SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM) != 1) + return -2; + + if (SSL_CTX_check_private_key(ctx) != 1) + return -3; + + return 0; +} diff --git a/src/ssl_ciphers.c b/src/ssl_ciphers.c new file mode 100644 index 0000000..168c2bb --- /dev/null +++ b/src/ssl_ciphers.c @@ -0,0 +1,21 @@ +#include "ucspissl.h" + +int ssl_ciphers(SSL_CTX *ctx,const char *ciphers) { + int r = 0; // no cipher selected + + if (!ciphers) return -1; + +/* TLS <= 1.2 SSL_CTX_set_cipher_list() + TLS = 1.3 SSL_CTX_set_ciphersuites() [only OpenSSL here] + + see: https://community.openvpn.net/openvpn/ticket/1159 +*/ + +#if (OPENSSL_VERSION_NUMBER > 0x10101000L && !LIBRESSL_VERSION_NUMBER) // 0xmnnffppsL + if ((r = SSL_CTX_set_ciphersuites(ctx,ciphers)) == 0) +#endif + r = SSL_CTX_set_cipher_list(ctx,ciphers); // TLS < 1.3 and fallback + + return r; +} + diff --git a/src/ssl_context.c b/src/ssl_context.c new file mode 100644 index 0000000..03ce58a --- /dev/null +++ b/src/ssl_context.c @@ -0,0 +1,34 @@ +#include "ucspissl.h" + +SSL_CTX *ssl_context(const SSL_METHOD *m) +{ + SSL_CTX *ctx; + + SSL_library_init(); + ctx = SSL_CTX_new(m); +#ifdef SSL_TWEAKING + SSL_CTX_set_options(ctx,SSL_OP_SINGLE_DH_USE|SSL_OP_NO_COMPRESSION|SSL_OP_CIPHER_SERVER_PREFERENCE); +#else + SSL_CTX_set_options(ctx,SSL_OP_SINGLE_DH_USE); +#endif +#ifdef SSLv2_DISABLE + SSL_CTX_set_options(ctx,SSL_OP_NO_SSLv2); +#endif +#ifdef SSLv3_DISABLE + SSL_CTX_set_options(ctx,SSL_OP_NO_SSLv3); +#endif +#ifdef TLSv1_DISABLE + SSL_CTX_set_options(ctx,SSL_OP_NO_TLSv1); +#endif +#ifdef TLSv1_1_DISABLE + SSL_CTX_set_options(ctx,SSL_OP_NO_TLSv1_1); +#endif +#ifdef TLSv1_2_DISABLE + SSL_CTX_set_options(ctx,SSL_OP_NO_TLSv1_2); +#endif +#ifdef TLSv1_3_DISABLE + SSL_CTX_set_options(ctx,SSL_OP_NO_TLSv1_3); +#endif + return ctx; +} + diff --git a/src/ssl_env.c b/src/ssl_env.c new file mode 100644 index 0000000..4ddff35 --- /dev/null +++ b/src/ssl_env.c @@ -0,0 +1,435 @@ +#include <unistd.h> +#include <string.h> +#include "fmt.h" +#include "pathexec.h" +#include "ucspissl.h" +#include "stralloc.h" +#include "str.h" + +static char strnum[FMT_ULONG]; +static stralloc ctemp = {0}; +static stralloc *envsa = 0; +static stralloc btemp = {0}; +static stralloc etemp = {0}; + +#define set_env_id(n,e,v) \ +if (!set_env_name_entry((n),(e),(v))) return 0 + +static int env_val(const char *env,const void *val,int len) { + const char *v = val; + if (envsa) { + if (!stralloc_cats(envsa,env)) return 0; + if (!stralloc_catb(envsa,"=",1)) return 0; + if (!stralloc_catb(envsa,v,len)) return 0; + if (!stralloc_0(envsa)) return 0; + return 1; + } + if (!stralloc_copyb(&etemp,v,len)) return 0; + if (!stralloc_0(&etemp)) return 0; + return pathexec_env(env,etemp.s); +} + +static int env_str(const char *env,const char *val) { + if (envsa) { + return env_val(env,val,str_len(val)); + if (!stralloc_cats(envsa,env)) return 0; + if (!stralloc_catb(envsa,"=",1)) return 0; + if (!stralloc_catb(envsa,val,str_len(val) + 1)) return 0; + return 1; + } + return pathexec_env(env,val); +} + +static int set_env_name_entry(X509_NAME *xname,const char *env,int nid) { + X509_NAME_ENTRY *xne; + int m; + int n; + + if (!env) return 1; +#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L)) + for (m = 0; m < sk_X509_NAME_ENTRY_num(xname->entries); m++) { + xne = sk_X509_NAME_ENTRY_value(xname->entries,m); + n = OBJ_obj2nid(xne->object); + if (n == nid) + if (!env_val(env,xne->value->data,xne->value->length)) return 0; +#else + for (m = 0; m < X509_NAME_entry_count(xname); m++) { + xne = X509_NAME_get_entry(xname,m); + n = OBJ_obj2nid(X509_NAME_ENTRY_get_object(xne)); + if (n == nid) + if (!env_val(env,X509_NAME_ENTRY_get_data(xne)->data,X509_NAME_ENTRY_get_data(xne)->length)) return 0; +#endif + } + + return 1; +} + +int ssl_session_vars(SSL *ssl) { + unsigned const char *x; + SSL_SESSION *session; + unsigned int n = 0; + int m; + const SSL_CIPHER *cipher; + unsigned char u; + unsigned char c; + + if (!env_str("SSL_PROTOCOL",SSL_get_version(ssl))) + return 0; + +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) // 0xmnnffppsL + session = SSL_get_session(ssl); + x = session->session_id; + n = session->session_id_length; +#else + session = SSL_get1_session(ssl); + x = SSL_SESSION_get_id(session,&n); +#endif + + if (!stralloc_ready(&btemp,2 * n)) return 0; + btemp.len = 2 * n; + while (n--) { + u = x[n]; + c = '0' + (u & 15); + if (c > '0' + 9) c += 'a' - '0' - 10; + btemp.s[2 * n + 1] = c; + u >>= 4; + c = '0' + (u & 15); + if (c > '0' + 9) c += 'a' - '0' - 10; + btemp.s[2 * n] = c; + } + if (!env_val("SSL_SESSION_ID",btemp.s,btemp.len)) return 0; + + if (!env_str("SSL_CIPHER",SSL_get_cipher_name(ssl))) return 0; + + cipher = SSL_get_current_cipher(ssl); + if (!cipher) return 0; + n = SSL_CIPHER_get_bits(cipher,&m); + if (!env_str("SSL_CIPHER_EXPORT",n < 56 ? "true" : "false")) return 0; + if (!env_val("SSL_CIPHER_USEKEYSIZE",strnum,fmt_ulong(strnum,n))) return 0; + if (!env_val("SSL_CIPHER_ALGKEYSIZE",strnum,fmt_ulong(strnum,m))) return 0; + + if (!env_str("SSL_VERSION_INTERFACE","ucspi-ssl")) return 0; + if (!env_str("SSL_VERSION_LIBRARY",OPENSSL_VERSION_TEXT)) return 0; + + return 1; +} + +static int ssl_client_bio_vars(X509 *cert,STACK_OF(X509) *chain,BIO *bio) { + ASN1_STRING *astring; + int n; + int m; + + astring = X509_get_notBefore(cert); + if (!ASN1_UTCTIME_print(bio,astring)) return 0; + n = BIO_pending(bio); + if (!stralloc_ready(&btemp,n)) return 0; + btemp.len = n; + n = BIO_read(bio,btemp.s,n); + if (n != btemp.len) return 0; + if (!env_val("SSL_CLIENT_V_START",btemp.s,btemp.len)) return 0; + + astring = X509_get_notAfter(cert); + if (!ASN1_UTCTIME_print(bio,astring)) return 0; + n = BIO_pending(bio); + if (!stralloc_ready(&btemp,n)) return 0; + btemp.len = n; + n = BIO_read(bio,btemp.s,n); + if (n != btemp.len) return 0; + if (!env_val("SSL_CLIENT_V_END",btemp.s,btemp.len)) return 0; + + if (!PEM_write_bio_X509(bio,cert)) return 0; + n = BIO_pending(bio); + if (!stralloc_ready(&btemp,n)) return 0; + btemp.len = n; + n = BIO_read(bio,btemp.s,n); + if (n != btemp.len) return 0; + if (!env_val("SSL_CLIENT_CERT",btemp.s,btemp.len)) return 0; + + if (chain) { + for (m = 0; m < sk_X509_num(chain); m++) { + if (!stralloc_copys(&ctemp,"SSL_CLIENT_CERT_CHAIN_")) return 0; + if (!stralloc_catb(&ctemp,strnum,fmt_ulong(strnum,m))) return 0; + if (!stralloc_0(&ctemp)) return 0; + + if (m < sk_X509_num(chain)) { + if (!PEM_write_bio_X509(bio,sk_X509_value(chain,m))) return 0; + n = BIO_pending(bio); + if (!stralloc_ready(&btemp,n)) return 0; + btemp.len = n; + n = BIO_read(bio,btemp.s,n); + if (n != btemp.len) return 0; + if (!env_val(ctemp.s,btemp.s,btemp.len)) return 0; + } + } + } + + return 1; +} + +static int ssl_client_vars(X509 *cert,STACK_OF(X509) *chain) { + X509_NAME *xname; + X509_PUBKEY *pubkey; + const X509_ALGOR *sigalg; + const ASN1_OBJECT *calgoid; + ASN1_OBJECT *algoid; + BIGNUM *bn; + BIO *bio; + char *x = 0; + int n; + + if (!cert) return 1; + + if (!env_val("SSL_CLIENT_M_VERSION",strnum,fmt_ulong(strnum,X509_get_version(cert) + 1))) + return 0; + + bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), 0); + x = BN_bn2dec(bn); + BN_free(bn); + if (!env_val("SSL_CLIENT_M_SERIAL",x,strlen(x))) + return 0; + OPENSSL_free(x); + + xname = X509_get_subject_name(cert); + x = X509_NAME_oneline(xname,0,0); + n = env_str("SSL_CLIENT_S_DN",x); + free(x); + if (!n) return 0; + + set_env_id(xname,"SSL_CLIENT_S_DN_C",NID_countryName); + set_env_id(xname,"SSL_CLIENT_S_DN_ST",NID_stateOrProvinceName); + set_env_id(xname,"SSL_CLIENT_S_DN_L",NID_localityName); + set_env_id(xname,"SSL_CLIENT_S_DN_O",NID_organizationName); + set_env_id(xname,"SSL_CLIENT_S_DN_OU",NID_organizationalUnitName); + set_env_id(xname,"SSL_CLIENT_S_DN_CN",NID_commonName); + set_env_id(xname,"SSL_CLIENT_S_DN_T",NID_title); + set_env_id(xname,"SSL_CLIENT_S_DN_I",NID_initials); + set_env_id(xname,"SSL_CLIENT_S_DN_G",NID_givenName); + set_env_id(xname,"SSL_CLIENT_S_DN_S",NID_surname); + set_env_id(xname,"SSL_CLIENT_S_DN_D",NID_description); + set_env_id(xname,"SSL_CLIENT_S_DN_UID",NID_x500UniqueIdentifier); + set_env_id(xname,"SSL_CLIENT_S_DN_Email",NID_pkcs9_emailAddress); + + xname = X509_get_issuer_name(cert); + x = X509_NAME_oneline(xname,0,0); + n = env_str("SSL_CLIENT_I_DN",x); + free(x); + if (!n) return 0; + + set_env_id(xname,"SSL_CLIENT_I_DN_C",NID_countryName); + set_env_id(xname,"SSL_CLIENT_I_DN_ST",NID_stateOrProvinceName); + set_env_id(xname,"SSL_CLIENT_I_DN_L",NID_localityName); + set_env_id(xname,"SSL_CLIENT_I_DN_O",NID_organizationName); + set_env_id(xname,"SSL_CLIENT_I_DN_OU",NID_organizationalUnitName); + set_env_id(xname,"SSL_CLIENT_I_DN_CN",NID_commonName); + set_env_id(xname,"SSL_CLIENT_I_DN_T",NID_title); + set_env_id(xname,"SSL_CLIENT_I_DN_I",NID_initials); + set_env_id(xname,"SSL_CLIENT_I_DN_G",NID_givenName); + set_env_id(xname,"SSL_CLIENT_I_DN_S",NID_surname); + set_env_id(xname,"SSL_CLIENT_I_DN_D",NID_description); + set_env_id(xname,"SSL_CLIENT_I_DN_UID",NID_x500UniqueIdentifier); + set_env_id(xname,"SSL_CLIENT_I_DN_Email",NID_pkcs9_emailAddress); + +/* Signature Algorithm for PubKey */ +#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L)) + n = OBJ_obj2nid(cert->cert_info->signature->algorithm); +#else + sigalg = X509_get0_tbs_sigalg(cert); + X509_ALGOR_get0(&calgoid,0,0,sigalg); + n = OBJ_obj2nid(calgoid); +#endif + if (!env_str("SSL_CLIENT_A_SIG",(n == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(n))) + return 0; + +/* Algorithm for PubKey */ +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) // 0xmnnffppsL + n = OBJ_obj2nid(cert->cert_info->key->algor->algorithm); +#else + pubkey = X509_get_X509_PUBKEY(cert); + X509_PUBKEY_get0_param(&algoid,0,0,0,pubkey); + n = OBJ_obj2nid(algoid); +#endif + if (!env_str("SSL_CLIENT_A_KEY",(n == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(n))) + return 0; + + bio = BIO_new(BIO_s_mem()); + if (!bio) return 0; + n = ssl_client_bio_vars(cert,chain,bio); + BIO_free(bio); + if (!n) return 0; + + return 1; +} + +static int ssl_server_bio_vars(X509 *cert,STACK_OF(X509) *chain,BIO *bio) { + ASN1_STRING *astring; + int n; + int m; + + astring = X509_get_notBefore(cert); + if (!ASN1_UTCTIME_print(bio,astring)) return 0; + n = BIO_pending(bio); + if (!stralloc_ready(&btemp,n)) return 0; + btemp.len = n; + n = BIO_read(bio,btemp.s,n); + if (n != btemp.len) return 0; + if (!env_val("SSL_SERVER_V_START",btemp.s,btemp.len)) return 0; + + astring = X509_get_notAfter(cert); + if (!ASN1_UTCTIME_print(bio,astring)) return 0; + n = BIO_pending(bio); + if (!stralloc_ready(&btemp,n)) return 0; + btemp.len = n; + n = BIO_read(bio,btemp.s,n); + if (n != btemp.len) return 0; + if (!env_val("SSL_SERVER_V_END",btemp.s,btemp.len)) return 0; + + if (!PEM_write_bio_X509(bio,cert)) return 0; + n = BIO_pending(bio); + if (!stralloc_ready(&btemp,n)) return 0; + btemp.len = n; + n = BIO_read(bio,btemp.s,n); + if (n != btemp.len) return 0; + if (!env_val("SSL_SERVER_CERT",btemp.s,btemp.len)) return 0; + + if (chain) { + for (m = 0; m < sk_X509_num(chain); m++) { + if (!stralloc_copys(&ctemp,"SSL_SERVER_CERT_CHAIN_")) return 0; + if (!stralloc_catb(&ctemp,strnum,fmt_ulong(strnum,m))) return 0; + if (!stralloc_0(&ctemp)) return 0; + + if (m < sk_X509_num(chain)) { + if (!PEM_write_bio_X509(bio,sk_X509_value(chain,m))) return 0; + n = BIO_pending(bio); + if (!stralloc_ready(&btemp,n)) return 0; + btemp.len = n; + n = BIO_read(bio,btemp.s,n); + if (n != btemp.len) return 0; + if (!env_val(ctemp.s,btemp.s,btemp.len)) return 0; + } + } + } + + return 1; +} + +static int ssl_server_vars(X509 *cert,STACK_OF(X509) *chain) { + X509_NAME *xname; + X509_PUBKEY *pubkey; + const X509_ALGOR *sigalg; + const ASN1_OBJECT *calgoid; + ASN1_OBJECT *algoid; + BIGNUM *bn; + BIO *bio; + char *x = 0; + int n; + + if (!cert) return 1; + + if (!env_val("SSL_SERVER_M_VERSION",strnum,fmt_ulong(strnum,X509_get_version(cert) + 1))) + return 0; + + bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), 0); + x = BN_bn2dec(bn); + BN_free(bn); + if (!env_val("SSL_SERVER_M_SERIAL",x,strlen(x))) return 0; + OPENSSL_free(x); + + xname = X509_get_subject_name(cert); + x = X509_NAME_oneline(xname,0,0); + n = env_str("SSL_SERVER_S_DN",x); + free(x); + if (!n) return 0; + + set_env_id(xname,"SSL_SERVER_S_DN_C",NID_countryName); + set_env_id(xname,"SSL_SERVER_S_DN_ST",NID_stateOrProvinceName); + set_env_id(xname,"SSL_SERVER_S_DN_L",NID_localityName); + set_env_id(xname,"SSL_SERVER_S_DN_O",NID_organizationName); + set_env_id(xname,"SSL_SERVER_S_DN_OU",NID_organizationalUnitName); + set_env_id(xname,"SSL_SERVER_S_DN_CN",NID_commonName); + set_env_id(xname,"SSL_SERVER_S_DN_T",NID_title); + set_env_id(xname,"SSL_SERVER_S_DN_I",NID_initials); + set_env_id(xname,"SSL_SERVER_S_DN_G",NID_givenName); + set_env_id(xname,"SSL_SERVER_S_DN_S",NID_surname); + set_env_id(xname,"SSL_SERVER_S_DN_D",NID_description); + set_env_id(xname,"SSL_SERVER_S_DN_UID",NID_x500UniqueIdentifier); + set_env_id(xname,"SSL_SERVER_S_DN_Email",NID_pkcs9_emailAddress); + + xname = X509_get_issuer_name(cert); + x = X509_NAME_oneline(xname,0,0); + n = env_str("SSL_SERVER_I_DN",x); + free(x); + if (!n) return 0; + + set_env_id(xname,"SSL_SERVER_I_DN_C",NID_countryName); + set_env_id(xname,"SSL_SERVER_I_DN_ST",NID_stateOrProvinceName); + set_env_id(xname,"SSL_SERVER_I_DN_L",NID_localityName); + set_env_id(xname,"SSL_SERVER_I_DN_O",NID_organizationName); + set_env_id(xname,"SSL_SERVER_I_DN_OU",NID_organizationalUnitName); + set_env_id(xname,"SSL_SERVER_I_DN_CN",NID_commonName); + set_env_id(xname,"SSL_SERVER_I_DN_T",NID_title); + set_env_id(xname,"SSL_SERVER_I_DN_I",NID_initials); + set_env_id(xname,"SSL_SERVER_I_DN_G",NID_givenName); + set_env_id(xname,"SSL_SERVER_I_DN_S",NID_surname); + set_env_id(xname,"SSL_SERVER_I_DN_D",NID_description); + set_env_id(xname,"SSL_SERVER_I_DN_UID",NID_x500UniqueIdentifier); + set_env_id(xname,"SSL_SERVER_I_DN_Email",NID_pkcs9_emailAddress); + +/* Signature Algorithm of PubKey */ +#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L)) + n = OBJ_obj2nid(cert->cert_info->signature->algorithm); +#else + sigalg = X509_get0_tbs_sigalg(cert); + X509_ALGOR_get0(&calgoid,0,0,sigalg); + n = OBJ_obj2nid(calgoid); +#endif + if (!env_str("SSL_SERVER_A_SIG",(n == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(n))) + return 0; + +/* Algorithm of PubKey */ +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) // 0xmnnffppsL + n = OBJ_obj2nid(cert->cert_info->key->algor->algorithm); +#else + pubkey = X509_get_X509_PUBKEY(cert); + X509_PUBKEY_get0_param(&algoid,0,0,0,pubkey); + n = OBJ_obj2nid(algoid); +#endif + if (!env_str("SSL_SERVER_A_KEY",(n == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(n))) + return 0; + + bio = BIO_new(BIO_s_mem()); + if (!bio) return 0; + n = ssl_server_bio_vars(cert,chain,bio); + BIO_free(bio); + + if (!n) return 0; + + return 1; +} + +int ssl_client_env(SSL *ssl,stralloc *sa) { + envsa = sa; + if (!ssl_session_vars(ssl)) return 0; + if (!ssl_client_vars(SSL_get_certificate(ssl),0)) + return 0; +#if (OPENSSL_VERSION_NUMBER > 0x30000000L) // 0xmnnffppsL + if (!ssl_server_vars(0,SSL_get_peer_cert_chain(ssl))) +#else + if (!ssl_server_vars(SSL_get_peer_certificate(ssl),SSL_get_peer_cert_chain(ssl))) +#endif + return 0; + return 1; +} + +int ssl_server_env(SSL *ssl,stralloc *sa) { + envsa = sa; + if (!ssl_session_vars(ssl)) return 0; + if (!ssl_server_vars(SSL_get_certificate(ssl),0)) + return 0; +#if (OPENSSL_VERSION_NUMBER > 0x30000000L) // 0xmnnffppsL + if (!ssl_server_vars(0,SSL_get_peer_cert_chain(ssl))) +#else + if (!ssl_client_vars(SSL_get_peer_certificate(ssl),SSL_get_peer_cert_chain(ssl))) +#endif + return 0; + return 1; +} diff --git a/src/ssl_error.c b/src/ssl_error.c new file mode 100644 index 0000000..88a01a1 --- /dev/null +++ b/src/ssl_error.c @@ -0,0 +1,12 @@ +#include "ucspissl.h" + +int ssl_error(int (*op)(const char *)) { + unsigned long e; + int r; + + e = ERR_get_error(); + if (!e) return 0; + r = op(ERR_error_string(e,0)); + if (r) return r; + return ssl_error(op); +} diff --git a/src/ssl_io.c b/src/ssl_io.c new file mode 100644 index 0000000..883380f --- /dev/null +++ b/src/ssl_io.c @@ -0,0 +1,269 @@ +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include "iopause.h" +#include "buffer.h" +#include "taia.h" +#include "ucspissl.h" +#include "error.h" + +static int leftstatus = 0; +static char leftbuf[16 * 1024]; +static int leftlen; +static int leftpos; + +static int rightstatus = 0; +static char rightbuf[16 * 1024]; +static int rightlen; +static int rightpos; + +int ssl_io(SSL *ssl,int fdleft,int fdright,unsigned int timeout) { + struct taia now; + struct taia deadline; + iopause_fd x[4]; + int xlen; + iopause_fd *io0; + iopause_fd *ioleft; + iopause_fd *io1; + iopause_fd *ioright; + int r; + int rc = 0; + int rfd; + int wfd; + + rfd = SSL_get_fd(ssl); /* XXX */ + if (rfd == -1) { + close(fdleft); close(fdright); + return -1; + } + wfd = SSL_get_fd(ssl); /* XXX */ + if (wfd == -1) { + close(fdleft); close(fdright); + return -1; + } + + for (;;) { + xlen = 0; + + if (leftstatus == -1 && rightstatus == -1) + goto DONE; + + io0 = 0; + if (leftstatus == 0 && rightstatus != 1) { + io0 = &x[xlen++]; + io0->fd = rfd; + io0->events = IOPAUSE_READ; + } + + ioleft = 0; + if (leftstatus == 1) { + ioleft = &x[xlen++]; + ioleft->fd = fdleft; + ioleft->events = IOPAUSE_WRITE; + } + + ioright = 0; + if (rightstatus == 0) { + ioright = &x[xlen++]; + ioright->fd = fdright; + ioright->events = IOPAUSE_READ; + } + + io1 = 0; + if (rightstatus == 1) { + io1 = &x[xlen++]; + io1->fd = wfd; + io1->events = IOPAUSE_WRITE; + } + + if (taia_now(&now) == -1) { + errno = ETIMEDOUT; + rc = -1; + goto BOMB; + } + taia_uint(&deadline,timeout); + taia_add(&deadline,&now,&deadline); + iopause(x,xlen,&deadline,&now); + + for (r = 0; r < xlen; ++r) + if (x[r].revents) goto EVENTS; + + if (io0 && !ssl_pending(ssl)) { + close(fdleft); + leftstatus = -1; + continue; + } + errno = ETIMEDOUT; + rc = -1; + goto BOMB; + + +EVENTS: + if (io0 && io0->revents) { + r = SSL_read(ssl,leftbuf,sizeof(leftbuf)); + ssl_errno = SSL_get_error(ssl,r); + switch (ssl_errno) { + case SSL_ERROR_NONE: + leftstatus = 1; + leftpos = 0; + leftlen = r; + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_X509_LOOKUP: + break; + case SSL_ERROR_ZERO_RETURN: + if (rightstatus == -1) goto DONE; + close(fdleft); + leftstatus = -1; + break; + case SSL_ERROR_SYSCALL: + if (errno == EAGAIN || errno == EINTR) break; + close(fdleft); + leftstatus = -1; + if (!errno) break; + /* premature close */ + if (errno == ECONNRESET && rightstatus == -1) goto DONE; + goto BOMB; + case SSL_ERROR_SSL: +/* Continuing after a received SSL error given the socket is still + * potentially active might be a noble cause, but is impracticle. + * We consider an SSL_ERROR_SSL as application failure; not TLS + * and close the connection gracefully. + * if (errno == EAGAIN || errno == EINTR) break; + * if (!errno) break; + */ + goto DONE; + default: + close(fdleft); + leftstatus = -1; + if (rightstatus == 1) break; + if (ssl_shutdown_pending(ssl)) goto DONE; + goto BOMB; + } + } + + if (ioleft && ioleft->revents) { + r = buffer_unixwrite(fdleft,leftbuf + leftpos,leftlen - leftpos); + if (r == -1) { + if (errno == EINTR || errno == EWOULDBLOCK) { + /* retry */ + } + else if (errno == EPIPE || errno == EAGAIN) { + if (rightstatus == -1) goto DONE; + close(fdleft); + leftstatus = -1; + } else { + rc = -1; + goto BOMB; + } + } + else { + leftpos += r; + if (leftpos == leftlen) { + leftstatus = 0; + if ((r = ssl_pending(ssl))) { + if (r > sizeof(leftbuf)) r = sizeof(leftbuf); + r = SSL_read(ssl,leftbuf,r); + ssl_errno = SSL_get_error(ssl,r); + switch (ssl_errno) { + case SSL_ERROR_NONE: + leftstatus = 1; + leftpos = 0; + leftlen = r; + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_X509_LOOKUP: + break; + case SSL_ERROR_ZERO_RETURN: + if (rightstatus == -1) goto DONE; + close(fdleft); + leftstatus = -1; + break; + default: + rc = -1; + goto BOMB; + } + } + } + } + } + + if (ioright && ioright->revents) { + r = buffer_unixread(fdright,rightbuf,sizeof(rightbuf)); + if (r == -1) { + if (errno == EINTR || errno == EWOULDBLOCK) { + /* retry */ + } else { + rc = -1; + goto BOMB; /* errno == EAGAIN => unrecoverable */ + } + } + else if (r == 0) { + close(fdright); + rightstatus = -1; + if (ssl_shutdown(ssl)) goto DONE; + if (leftstatus == -1) goto DONE; + } + else { + rightstatus = 1; + rightpos = 0; + rightlen = r; + } + } + + if (io1 && io1->revents) { + r = SSL_write(ssl,rightbuf + rightpos,rightlen - rightpos); + ssl_errno = SSL_get_error(ssl,r); + switch (ssl_errno) { + case SSL_ERROR_NONE: + rightpos += r; + if (rightpos == rightlen) rightstatus = 0; + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_X509_LOOKUP: + break; + case SSL_ERROR_ZERO_RETURN: + close(fdright); + rightstatus = -1; + if (leftstatus == -1) goto DONE; + if (ssl_shutdown(ssl)) goto DONE; + break; + case SSL_ERROR_SYSCALL: + if (errno == EAGAIN || errno == EINTR) break; + if (errno == EPIPE) { + close(fdright); + rightstatus = -1; + if (leftstatus == -1) goto DONE; + if (ssl_shutdown(ssl)) goto DONE; + break; + } + default: + rc = -1; + goto BOMB; + } + } + } + + +BOMB: + r = errno; + if (leftstatus != -1) close(fdleft); + if (rightstatus != -1) close(fdright); + if (!ssl_shutdown_sent(ssl)) ssl_shutdown(ssl); + if (!ssl_shutdown_pending(ssl)) ssl_shutdown(ssl); + shutdown(wfd,2); + errno = r; + return rc; + + +DONE: + if (!ssl_shutdown_sent(ssl)) ssl_shutdown(ssl); + if (!ssl_shutdown_pending(ssl)) ssl_shutdown(ssl); + shutdown(wfd,2); + if (leftstatus != -1) close(fdleft); + if (rightstatus != -1) close(fdright); + return 0; +} diff --git a/src/ssl_new.c b/src/ssl_new.c new file mode 100644 index 0000000..4833778 --- /dev/null +++ b/src/ssl_new.c @@ -0,0 +1,16 @@ +#include "ucspissl.h" +#include "ndelay.h" + +SSL *ssl_new(SSL_CTX *ctx,int s) +{ + BIO *sbio; + SSL *ssl; + + ssl = SSL_new(ctx); + if (!ssl) return 0; + sbio = BIO_new_socket(s,BIO_NOCLOSE); + if (!sbio) return 0; + SSL_set_bio(ssl,sbio,sbio); + return ssl; +} + diff --git a/src/ssl_params.c b/src/ssl_params.c new file mode 100644 index 0000000..d3a49d0 --- /dev/null +++ b/src/ssl_params.c @@ -0,0 +1,80 @@ +/** + @file ssl_params.c + @author web, bergmann + @brief setup RSA, DH, ECDH +*/ +#include "ucspissl.h" + +int ssl_params_rsa(SSL_CTX *ctx,int len) +{ + RSA *rsa; + long res; + BIGNUM *e; + + /* check if ephemeral RSA key is actually needed */ + if (!SSL_CTX_need_tmp_RSA(ctx)) return 1; + + if (len) { + e = BN_new(); + rsa = RSA_new(); + BN_set_word(e,RSA_F4); + + res = (long) RSA_generate_key_ex(rsa,len,e,NULL); + BN_free(e); + + if (res == -1) return 0; + if (!rsa) return 0; + + /* seldom "needed": maybe deal with an export cipher */ + res = SSL_CTX_set_tmp_rsa(ctx,rsa); + RSA_free(rsa); + if (!res) return 0; + } + + return 1; +} + +int ssl_params_dh(SSL_CTX *ctx,const char *dhfile) +{ + DH *dh; + BIO *bio; + + if (dhfile) { + dh = 0; + bio = BIO_new_file(dhfile,"r"); + if (!bio) return 0; + dh = PEM_read_bio_DHparams(bio,0,0,0); + BIO_free(bio); + if (!dh) return 0; + if (!SSL_CTX_set_tmp_dh(ctx,dh)) return 0; + } + + return 1; +} + +int ssl_params_ecdh(SSL_CTX *ctx,const char *ecdhfile) +{ + EC_KEY *ecdh; + + SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE); +#ifdef SSL_CTRL_SET_ECDH_AUTO + SSL_CTX_set_ecdh_auto(ctx,1); +#else + /* insecure and compatible curves, see http://safecurves.cr.yp.to/ */ + ecdh = EC_KEY_new_by_curve_name(NID_secp521r1); + if (ecdh == NULL) { + /* NIST P-384 / AES-256 */ + ecdh = EC_KEY_new_by_curve_name(NID_secp384r1); + } + if (ecdh == NULL) { + /* NIST P-256 / AES-128 */ + ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + } + if (ecdh != NULL) { + SSL_CTX_set_tmp_ecdh(ctx,ecdh); + EC_KEY_free(ecdh); + return 1; + } +#endif + return 0; +} diff --git a/src/ssl_timeout.c b/src/ssl_timeout.c new file mode 100644 index 0000000..737f72f --- /dev/null +++ b/src/ssl_timeout.c @@ -0,0 +1,125 @@ +#include "ucspissl.h" +#include "iopause.h" +#include "logmsg.h" + +#define WHO "ssl_timeout" + +int ssl_timeoutaccept(SSL *ssl,unsigned int timeout) +{ + struct taia now; + struct taia deadline; + iopause_fd x; + int r; + int rfd; + int wfd; + + if (taia_now(&now) == -1) { + errno = ETIMEDOUT; + return -1; + } + taia_uint(&deadline,timeout); + taia_add(&deadline,&now,&deadline); + + rfd = SSL_get_fd(ssl); /* XXX */ + wfd = SSL_get_fd(ssl); /* XXX */ + + SSL_set_accept_state(ssl); + + for (;;) { + r = SSL_accept(ssl); + if (r == 1) return 0; + ssl_errno = SSL_get_error(ssl,r); + errno = EPROTO; + if ((ssl_errno != SSL_ERROR_WANT_READ) && (ssl_errno != SSL_ERROR_WANT_WRITE)) + return -1; + if (ssl_errno == SSL_ERROR_WANT_READ) { + x.events = IOPAUSE_READ; + x.fd = rfd; + if (x.fd == -1) return -1; + } + else { + x.events = IOPAUSE_WRITE; + x.fd = wfd; + if (x.fd == -1) return -1; + } + for (;;) { + if (taia_now(&now) == -1) { + errno = ETIMEDOUT; + return -1; + } + iopause(&x,1,&deadline,&now); + if (x.revents) break; + if (taia_less(&deadline,&now)) { + errno = ETIMEDOUT; + return -1; + } + } + } +} + +int ssl_timeoutconn(SSL *ssl,unsigned int timeout) +{ + struct taia now; + struct taia deadline; + iopause_fd x; + int r; + int rfd; + int wfd; + + taia_now(&now); + taia_uint(&deadline,timeout); + taia_add(&deadline,&now,&deadline); + + rfd = SSL_get_fd(ssl); /* XXX */ + wfd = SSL_get_fd(ssl); /* XXX */ + + SSL_set_connect_state(ssl); + + for (;;) { + r = SSL_connect(ssl); + errno = EPROTO; + if (r == 1) return 0; + ssl_errno = SSL_get_error(ssl,r); + if ((ssl_errno != SSL_ERROR_WANT_READ) && (ssl_errno != SSL_ERROR_WANT_WRITE)) + return -1; + if (ssl_errno == SSL_ERROR_WANT_READ) { + x.events = IOPAUSE_READ; + x.fd = rfd; + if (x.fd == -1) return -1; + } + else { + x.events = IOPAUSE_WRITE; + x.fd = wfd; + if (x.fd == -1) return -1; + } + for (;;) { + if (taia_now(&now) == -1) { + errno = ETIMEDOUT; + return -1; + } + iopause(&x,1,&deadline,&now); + if (x.revents) break; + if (taia_less(&deadline,&now)) { + errno = ETIMEDOUT; + return -1; + } + } + } +} + +stralloc sslerror = {0}; + +int ssl_verberror(void) +{ + char buf[256]; + unsigned long err; + + if (!stralloc_copys(&sslerror,"")) return -1; + + while ((err = ERR_get_error()) != 0) { + ERR_error_string_n(err,buf,sizeof(buf)); + if (!stralloc_cats(&sslerror,buf)) return -1; + if (!stralloc_cats(&sslerror," ")) return -1; + } + return err; +} diff --git a/src/ssl_verify.c b/src/ssl_verify.c new file mode 100644 index 0000000..474c45b --- /dev/null +++ b/src/ssl_verify.c @@ -0,0 +1,63 @@ +/** + @file ssl_verify.c + @author web, feh -- parts of code borrowed from Pavel Shramov; tx Peter Conrad + @brief Compares 'hostname' against SubAltName DNS:hostname + DN: /CN=hostname +*/ +#include "ucspissl.h" +#include "case.h" +#include "str.h" + +int ssl_verify(SSL *ssl,const char *hostname,stralloc *dnsout) +{ + X509 *cert; + STACK_OF(GENERAL_NAME) *extensions; + const GENERAL_NAME *ext; + char buf[SSL_NAME_LEN]; + char *dnsname = 0; + int i; + int num; + int len; + int dname = 0; + +#if (OPENSSL_VERSION_NUMBER > 0x30100000L) + cert = SSL_get1_peer_certificate(ssl); +#else + cert = SSL_get_peer_certificate(ssl); +#endif + if (!cert) return -1; + + if (SSL_get_verify_result(ssl) != X509_V_OK) return -2; + + if (hostname) { + if (!stralloc_copys(dnsout,"")) return 1; + extensions = X509_get_ext_d2i(cert,NID_subject_alt_name,0,0); + num = sk_GENERAL_NAME_num(extensions); /* num = 0, if no SAN extensions */ + + for (i = 0; i < num; ++i) { + ext = sk_GENERAL_NAME_value(extensions,i); + if (ext->type == GEN_DNS) { + if (ASN1_STRING_type(ext->d.dNSName) != V_ASN1_IA5STRING) continue; +#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L)) + dnsname = (char *)ASN1_STRING_data(ext->d.dNSName); +#else + dnsname = (char *)ASN1_STRING_get0_data(ext->d.dNSName); +#endif + len = ASN1_STRING_length(ext->d.dNSName); + if (len != str_len(dnsname)) continue; + if (!stralloc_copyb(dnsout,dnsname,len)) return 1; + if (case_diffs((char *)hostname,dnsname) == 0) return 0; + dname = 1; + } + } + + if (!dname) { + X509_NAME_get_text_by_NID(X509_get_subject_name(cert),NID_commonName,buf,sizeof(buf)); + buf[SSL_NAME_LEN - 1] = 0; + if (!stralloc_copyb(dnsout,buf,str_len(buf))) return 1; + if (case_diffs((char *)hostname,buf) == 0) return 0; + } + + return -3; + } + return 0; +} diff --git a/src/sslcat.sh b/src/sslcat.sh new file mode 100644 index 0000000..f923935 --- /dev/null +++ b/src/sslcat.sh @@ -0,0 +1,9 @@ +host=${1-0} +port=${2-443} +args="" +if [ $# -gt 2 ] +then + shift; shift + args="$@" +fi +exec sslclient -RHl0 $args -- "$host" "$port" sh -c 'exec cat <&6' diff --git a/src/sslclient.c b/src/sslclient.c new file mode 100644 index 0000000..1d4ce57 --- /dev/null +++ b/src/sslclient.c @@ -0,0 +1,449 @@ +/** + @file sslclient.c + @author web, fefe, feh + @brief IPv6 enabled sslclient +*/ +#include <unistd.h> +#include <sys/types.h> +#include <sys/param.h> +#include <netdb.h> +#include <arpa/inet.h> +#include "ucspissl.h" +#include "sig.h" +#include "exit.h" +#include "getoptb.h" +#include "uint_t.h" +#include "fmt.h" +#include "scan.h" +#include "str.h" +#include "ip.h" +#include "socket_if.h" +#include "fd.h" +#include "stralloc.h" +#include "buffer.h" +#include "getln.h" +#include "logmsg.h" +#include "pathexec.h" +#include "timeoutconn.h" +#include "remoteinfo.h" +#include "dnsresolv.h" +#include "byte.h" +#include "ndelay.h" +#include "wait.h" +#include "auto_cafile.h" +#include "auto_cadir.h" +#include "auto_ciphers.h" + +#define WHO "sslclient" + +void nomem(void) { + logmsg(WHO,111,FATAL,"out of memory"); +} +void env(const char *s,const char *t) { + if (!pathexec_env(s,t)) nomem(); +} + +void usage(void) { + logmsg(WHO,100,USAGE,"sslclient \ +[ -463hHrRdDiqQveEsSnNxX ] \ +[ -i localip ] \ +[ -p localport ] \ +[ -T timeoutconn ] \ +[ -l localname ] \ +[ -t timeoutinfo ] \ +[ -I interface ] \ +[ -a cafile ] \ +[ -A cadir ] \ +[ -c certfile ] \ +[ -z ciphers ] \ +[ -k keyfile ] \ +[ -V verifydepth ] \ +[ -w progtimeout ] \ +host port program"); +} + +int verbosity = 1; +int flagdelay = 0; +int flagremoteinfo = 0; +int flagremotehost = 1; +int flag3 = 0; +int flagsslenv = 0; +int flagtcpenv = 0; +int flagsni = 0; +unsigned long itimeout = 26; +unsigned long ctimeout[2] = { 2, 58 }; +unsigned int progtimeout = 3600; +uint32 netif = 0; + +const char *loopback = "127.0.0.1"; +char iplocal[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; +uint16 portlocal = 0; +const char *forcelocal = 0; + +char ipremote[16]; +uint16 portremote; + +const char *hostname; +int flagname = 1; +int flagservercert = 1; +static stralloc addresses; +static stralloc certname; +static stralloc moreaddresses; + +static stralloc tmp; +static stralloc fqdn; +static char strnum[FMT_ULONG]; +static char ipstr[IP6_FMT]; + +char seed[128]; + +char bspace[16]; +buffer b; + +SSL_CTX *ctx; +const char *certfile = 0; +const char *keyfile = 0; +const char *cafile = auto_cafile; +const char *cadir = auto_cadir; +const char *ciphers = auto_ciphers; +stralloc password = {0}; +int match = 0; +int verifydepth = 1; + +int pi[2]; +int po[2]; +int pt[2]; + +void read_passwd() { + if (!password.len) { + buffer_init(&b,buffer_unixread,3,bspace,sizeof(bspace)); + if (getln(&b,&password,&match,'\0') == -1) + logmsg(WHO,111,ERROR,"unable to read password"); + close(3); + if (match) --password.len; + } +} + +int passwd_cb(char *buf,int size,int rwflag,void *userdata) { + if (size < password.len) + logmsg(WHO,111,ERROR,"password too long"); + + byte_copy(buf,password.len,password.s); + return password.len; +} + +int main(int argc,char * const *argv) { + unsigned long u; + int opt; + const char *x; + int j; + int s; + int r; + int cloop; + SSL *ssl; + int wstat; + int ipflag = 0; + + dns_random_init(seed); + + close(6); + close(7); + sig_ignore(sig_pipe); + + while ((opt = getopt(argc,argv,"dDvqQhHrRimM:p:t:T:l:a:A:c:z:k:V:346eEsSnN0xXw:")) != opteof) + switch(opt) { + case '4': ipflag = 1; break; + case '6': ipflag = 0; break; + case 'd': flagdelay = 1; break; + case 'D': flagdelay = 0; break; + case 'm': flagsni = 1; break; + case 'M': flagsni = 0; break; + case 'v': verbosity = 2; break; + case 'q': verbosity = 0; break; + case 'Q': verbosity = 1; break; + case 'l': forcelocal = optarg; break; + case 'H': flagremotehost = 0; break; + case 'h': flagremotehost = 1; break; + case 'R': flagremoteinfo = 0; break; + case 'r': flagremoteinfo = 1; break; + case 't': scan_ulong(optarg,&itimeout); break; + case 'T': j = scan_ulong(optarg,&ctimeout[0]); + if (optarg[j] == '+') ++j; + scan_ulong(optarg + j,&ctimeout[1]); + break; + case 'w': scan_uint(optarg,&progtimeout); break; + case 'i': if (!ip6_scan(optarg,iplocal)) usage(); break; + case 'I': netif = socket_getifidx(optarg); break; + case 'p': scan_ulong(optarg,&u); portlocal = u; break; + case 'a': cafile = optarg; break; + case 'A': cadir = optarg; break; + case 'c': certfile = optarg; break; + case 'z': ciphers = optarg; break; + case 'k': keyfile = optarg; break; + case 'V': scan_ulong(optarg,&u); verifydepth = u; break; + case '3': flag3 = 1; break; + case 'S': flagsslenv = 0; break; + case 's': flagsslenv = 1; break; + case 'E': flagtcpenv = 0; break; + case 'e': flagtcpenv = 1; break; + case 'N': flagname = 0; break; + case 'n': flagname = 1; break; + case 'x': flagservercert = 1; break; + case 'X': flagservercert = 0; break; + default: usage(); + } + argv += optind; + + if (!verbosity) + buffer_2->fd = -1; + + hostname = *argv; + if (!hostname || str_equal((char *)hostname,"")) usage(); + if (str_equal((char *)hostname,"0")) hostname = loopback; + + x = *++argv; + if (!x) usage(); + if (!x[scan_ulong(x,&u)]) + portremote = u; + else { + struct servent *se; + se = getservbyname(x,"tcp"); + if (!se) + logmsg(WHO,111,FATAL,B("unable to figure out port number for ",x)); + uint16_unpack_big((char*)&se->s_port,&portremote); + } + + if (flag3) read_passwd(); + + if (cafile && str_equal(cafile,"")) cafile = 0; + if (cadir && str_equal(cadir,"")) cadir= 0; + if (ciphers && str_equal(ciphers,"")) ciphers= 0; + + if (certfile && str_equal(certfile,"")) certfile = 0; + if (keyfile && str_equal(keyfile,"")) keyfile = 0; + + if (!*++argv) usage(); + + if (!stralloc_copys(&tmp,hostname)) nomem(); + dns_ip_qualify(&addresses,&fqdn,&tmp); + if (addresses.len < 16) + logmsg(WHO,111,ERROR,B("No IP address for: ",hostname)); + + if (addresses.len == 16) { + ctimeout[0] += ctimeout[1]; + ctimeout[1] = 0; + } + + for (cloop = 0; cloop < 2; ++cloop) { + if (!stralloc_copys(&moreaddresses,"")) nomem(); + for (j = 0; j + 16 <= addresses.len; j += 16) { + if (ipflag == 1 || ip6_isv4mapped(addresses.s + j)) { + s = socket_tcp4(); + if (s == -1) logmsg(WHO,111,FATAL,"unable to create socket"); + r = socket_bind4(s,iplocal,portlocal); + } else { + s = socket_tcp6(); + if (s == -1) logmsg(WHO,111,FATAL,"unable to create socket"); + r = socket_bind6(s,iplocal,portlocal,netif); + } + if (r == -1) { + strnum[fmt_ulong(strnum,portlocal)] = 0; + if (ip6_isv4mapped(addresses.s + j)) + ipstr[ip4_fmt(ipstr,addresses.s + j + 12)] = 0; + else + ipstr[ip6_fmt(ipstr,addresses.s + j)] = 0; + + logmsg(WHO,111,FATAL,B("unable to bind to: ",ipstr," port: ",strnum)); + } + if (timeoutconn(s,addresses.s + j,portremote,ctimeout[cloop],netif) == 0) + goto CONNECTED; + close(s); + if (!cloop && ctimeout[1] && (errno == ETIMEDOUT)) { + if (!stralloc_catb(&moreaddresses,addresses.s + j,16)) nomem(); + } + else { + strnum[fmt_ulong(strnum,portremote)] = 0; + if (ip6_isv4mapped(addresses.s + j)) + ipstr[ip4_fmt(ipstr,addresses.s + j + 12)] = 0; + else + ipstr[ip6_fmt(ipstr,addresses.s + j)] = 0; + } + } + if (!stralloc_copy(&addresses,&moreaddresses)) nomem(); + } + logmsg(WHO,110,DROP,B("unable to connect to: ",ipstr," port: ",strnum)); + + _exit(111); + + + CONNECTED: + + /* Local */ + + if (socket_local(s,iplocal,&portlocal,&netif) == -1) + logmsg(WHO,111,FATAL,"unable to get local address"); + + if (ip6_isv4mapped(iplocal)) { + env("PROTO","TCP6"); + ipstr[ip4_fmt(ipstr,iplocal + 12)] = 0; + } else { + env("PROTO","TCP6"); + if (flagtcpenv && netif) env("TCP6INTERFACE",socket_getifname(netif)); + ipstr[ip6_fmt(ipstr,iplocal)] = 0; + } + + env("SSLLOCALIP",ipstr); + if (flagtcpenv) env("TCPLOCALIP",ipstr); + + strnum[fmt_ulong(strnum,portlocal)] = 0; + env("SSLLOCALPORT",strnum); + if (flagtcpenv) env("TCPLOCALPORT",strnum); + + x = forcelocal; + if (!x) + if (dns_name(&tmp,iplocal) >= 0) { + if (!stralloc_0(&tmp)) nomem(); + x = tmp.s; + } + env("SSLLOCALHOST",x); + if (flagtcpenv) env("TCPLOCALHOST",x); + + /* Remote */ + + if (socket_remote(s,ipremote,&portremote,&netif) == -1) + logmsg(WHO,111,FATAL,"unable to get remote address"); + + if (ip6_isv4mapped(ipremote)) + ipstr[ip4_fmt(ipstr,ipremote + 12)] = 0; + else + ipstr[ip6_fmt(ipstr,ipremote)] = 0; + + env("SSLREMOTEIP",ipstr); + if (flagtcpenv) env("TCPREMOTEIP",ipstr); + + strnum[fmt_ulong(strnum,portremote)] = 0; + env("SSLREMOTEPORT",strnum); + if (flagtcpenv) env("TCPREMOTEPORT",strnum); + + x = 0; + if (flagremotehost) + if (dns_name(&tmp,ipremote) >= 0) { + if (!stralloc_0(&tmp)) nomem(); + x = tmp.s; + } + + env("SSLREMOTEHOST",x); + if (flagtcpenv) env("TCPREMOTEHOST",x); + + x = 0; + if (flagremoteinfo) + if (remoteinfo(&tmp,ipremote,portremote,iplocal,portlocal,itimeout,netif) == 0) { + if (!stralloc_0(&tmp)) nomem(); + x = tmp.s; + } + env("SSLREMOTEINFO",x); + if (flagtcpenv) env("TCPREMOTEINFO",x); + + /* Context */ + + ctx = ssl_client(); + ssl_errstr(); + if (!ctx) + logmsg(WHO,111,FATAL,"unable to create TLS context"); + + switch (ssl_certkey(ctx,certfile,keyfile,passwd_cb)) { + case -1: logmsg(WHO,111,ERROR,"unable to load certificate"); + case -2: logmsg(WHO,111,ERROR,"unable to load key pair"); + case -3: logmsg(WHO,111,ERROR,"key does not match certificate"); + default: break; + } + + if (flagservercert && !ssl_ca(ctx,cafile,cadir,verifydepth)) + logmsg(WHO,111,ERROR,"unable to load CA list"); + + if (!ssl_ciphers(ctx,ciphers)) + logmsg(WHO,111,ERROR,"unable to set cipher list"); + + ssl = ssl_new(ctx,s); + if (!ssl) logmsg(WHO,111,FATAL,"unable to create TLS instance"); + + if (flagsni) + if (!SSL_set_tlsext_host_name(ssl,hostname)) + logmsg(WHO,111,FATAL,B("unable to set TLS SNI extensions for hostname: ",(char *)hostname)); + + for (cloop = 0; cloop < 2; ++cloop) { + if (!ssl_timeoutconn(ssl,ctimeout[cloop])) goto SSLCONNECTED; + if (!cloop && ctimeout[1]) continue; + logmsg(WHO,111,FATAL,"unable to TLS connect"); + } + + _exit(111); + + SSLCONNECTED: + + ndelay_off(s); + + if (flagservercert) + switch(ssl_verify(ssl,hostname,&certname)) { + case -1: + logmsg(WHO,110,ERROR,"no server certificate"); + case -2: + logmsg(WHO,110,ERROR,"missing credentials (CA) or unable to validate server certificate"); + case -3: + if (!stralloc_0(&certname)) nomem(); + if (flagname) + logmsg(WHO,110,ERROR,B("server hostname does not match certificate: ",(char *)hostname," <=> ",certname.s)); + default: break; + } + + if (verbosity >= 2) + log_who(WHO,B("tls connected to: ",ipstr," port: ",strnum)); + + if (!flagdelay) + socket_tcpnodelay(s); /* if it fails, bummer */ + + if (pipe(pi) == -1) logmsg(WHO,111,FATAL,"unable to create pipe"); + if (pipe(po) == -1) logmsg(WHO,111,FATAL,"unable to create pipe"); + if (pi[0] == 7) { + if (pipe(pt) == -1) logmsg(WHO,111,FATAL,"unable to create pipe"); + close(pi[0]); close(pi[1]); + pi[0] = pt[0]; pi[1] = pt[1]; + } + if (po[1] == 6) { + if (pipe(pt) == -1) logmsg(WHO,111,FATAL,"unable to create pipe"); + close(po[0]); close(po[1]); + po[0] = pt[0]; po[1] = pt[1]; + } + + switch (opt = fork()) { + case -1: + logmsg(WHO,111,FATAL,"unable to fork"); + case 0: + break; + default: + close(pi[0]); close(po[1]); + if (ssl_io(ssl,pi[1],po[0],progtimeout)) { + logmsg(WHO,110,DROP,"unable to speak TLS"); + ssl_close(ssl); + wait_pid(&wstat,opt); + _exit(111); + } + ssl_close(ssl); + if (wait_pid(&wstat,opt) > 0) + _exit(wait_exitcode(wstat)); + _exit(0); + } + ssl_close(ssl); close(pi[1]); close(po[0]); + + if (flagsslenv && !ssl_client_env(ssl,0)) nomem(); + + if (fd_move(6,pi[0]) == -1) + logmsg(WHO,111,FATAL,"unable to set up descriptor 6"); + if (fd_move(7,po[1]) == -1) + logmsg(WHO,111,FATAL,"unable to set up descriptor 7"); + sig_uncatch(sig_pipe); + + pathexec(argv); + logmsg(WHO,111,FATAL,B("unable to run: ",*argv)); + return 0; /* never happens, but avoids compile warning */ +} diff --git a/src/sslconnect.sh b/src/sslconnect.sh new file mode 100644 index 0000000..3462540 --- /dev/null +++ b/src/sslconnect.sh @@ -0,0 +1,9 @@ +host=${1-0} +port=${2-465} +args="" +if [ $# -gt 2 ] +then + shift; shift + args="$@" +fi +exec sslclient -XRHl0 $args -- "$host" "$port" mconnect-io diff --git a/src/sslhandle.c b/src/sslhandle.c new file mode 100644 index 0000000..f31cee9 --- /dev/null +++ b/src/sslhandle.c @@ -0,0 +1,887 @@ +/** + @file sslhandle.c + @author web, feh + @brief IPv6 enabled TLS framework for a preforking server +*/ +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <netdb.h> +#include <signal.h> +#include <arpa/inet.h> +#include "ucspissl.h" +#include "uint_t.h" +#include "str.h" +#include "byte.h" +#include "fmt.h" +#include "scan.h" +#include "ip.h" +#include "fd.h" +#include "exit.h" +#include "env.h" +#include "prot.h" +#include "open.h" +#include "wait.h" +#include "stralloc.h" +#include "alloc.h" +#include "buffer.h" +#include "getln.h" +#include "logmsg.h" +#include "getoptb.h" +#include "socket_if.h" +#include "ndelay.h" +#include "remoteinfo.h" +#include "rules.h" +#include "sig.h" +#include "iopause.h" +#include "dnsresolv.h" +#include "auto_cafile.h" +#include "auto_cadir.h" +#include "auto_ccafile.h" +#include "auto_dhfile.h" +#include "auto_certchainfile.h" +#include "auto_certfile.h" +#include "auto_keyfile.h" +#include "auto_ciphers.h" +#include "iopause.h" +#include "coe.h" +#include "lock.h" + + +extern void server(int argcs,char * const *argvs); +char *who; + +int verbosity = 1; +int flagkillopts = 1; +int flagafter = 0; +int flagdelay = 0; +const char *banner = ""; +int flagremoteinfo = 1; +int flagremotehost = 1; +int flagparanoid = 0; +int flagclientcert = 0; +int flagsslenv = 0; +int flagtcpenv = 0; +unsigned long timeout = 26; +unsigned long ssltimeout = 26; +unsigned int progtimeout = 3600; +uint32 netif = 0; +int selfpipe[2]; +int flagexit = 0; +int flagdualstack = 0; + +static stralloc tcpremoteinfo = {0}; + +uint16 localport; +char localportstr[FMT_ULONG]; +char localip[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; +char localipstr[IP6_FMT]; +static stralloc localhostsa; +const char *localhost = 0; +const char *lockfile = 0; +int fdlock; + +uint16 remoteport; +char remoteportstr[FMT_ULONG]; +char remoteip[16]; +char remoteipstr[IP6_FMT]; +static stralloc remotehostsa; +char *remotehost = 0; + +const char *hostname; +const char *loopback = "127.0.0.1"; + +static char strnum[FMT_ULONG]; +static char strnum2[FMT_ULONG]; + +static stralloc tmp; +static stralloc fqdn; +static stralloc addresses; +static stralloc certname; +stralloc envplus = {0}; +stralloc envtmp = {0}; + +char bspace[16]; +buffer b; + +SSL_CTX *ctx; +const char *certchainfile = auto_certchainfile; +const char *certfile = auto_certfile; +const char *keyfile = auto_keyfile; +stralloc password = {0}; +int match = 0; +const char *cafile = auto_cafile; +const char *ccafile = auto_ccafile; +const char *cadir = auto_cadir; +const char *ciphers = auto_ciphers; +int verifydepth = 1; +const char *dhfile = auto_dhfile; +int rsalen = SSL_RSA_LEN; + +int pi[2]; +int po[2]; + +X509 *cert; +char buf[SSL_NAME_LEN]; + +char **e; +char **e1; + +/* ---------------------------- child */ + + +int flagdeny = 0; +int flagallownorules = 0; +const char *fnrules = 0; + +void drop_nomem(void) { + logmsg(who,111,FATAL,"out of memory"); +} +void drop_notemp(void) { + logmsg(who,111,FATAL,"out of timestamps"); +} +void cats(const char *s) { + if (!stralloc_cats(&tmp,s)) drop_nomem(); +} +void append(const char *ch) { + if (!stralloc_append(&tmp,ch)) drop_nomem(); +} +void safecats(const char *s) { + char ch; + int i; + + for (i = 0;i < 100;++i) { + ch = s[i]; + if (!ch) return; + if (ch < 33) ch = '?'; + if (ch > 126) ch = '?'; + if (ch == '%') ch = '?'; /* logger stupidity */ + append(&ch); + } + cats("..."); +} +void env(const char *s,const char *t) { + if (!s) return; + if (!stralloc_copys(&envtmp,s)) drop_nomem(); + if (t) { + if (!stralloc_cats(&envtmp,"=")) drop_nomem(); + if (!stralloc_cats(&envtmp,t)) drop_nomem(); + } + if (!stralloc_0(&envtmp)) drop_nomem(); + if (!stralloc_cat(&envplus,&envtmp)) drop_nomem(); +} +static void env_def() { + unsigned int elen; + unsigned int i; + unsigned int j; + unsigned int split; + unsigned int t; + + if (!stralloc_cats(&envplus,"")) return; + + elen = 0; + for (i = 0; environ[i]; ++i) + ++elen; + for (i = 0; i < envplus.len; ++i) + if (!envplus.s[i]) + ++elen; + + e = (char **) alloc((elen + 1) * sizeof(char *)); + if (!e) return; + + elen = 0; + for (i = 0; environ[i]; ++i) + e[elen++] = environ[i]; + + j = 0; + for (i = 0; i < envplus.len; ++i) + if (!envplus.s[i]) { + split = str_chr(envplus.s + j,'='); + for (t = 0;t < elen;++t) + if (byte_equal(envplus.s + j,split,e[t])) + if (e[t][split] == '=') { + --elen; + e[t] = e[elen]; + break; + } + if (envplus.s[j + split]) + e[elen++] = envplus.s + j; + j = i + 1; + } + e[elen] = 0; + + e1 = environ; + environ = e; +} +void env_reset(void) { + if (e) { + if (e != environ) { + alloc_free((char *)e); + logmsg(who,111,FATAL,"environ changed"); + } + } + + environ = e1; + envplus.len = 0; +} +int error_warn(const char *x) { + if (!x) return 0; + log_who(who,"x"); + return 0; +} +void drop_rules(void) { + logmsg(who,111,FATAL,B("unable to read: ",(char *)fnrules)); +} + +void found(char *data,unsigned int datalen) { + unsigned int next0; + unsigned int split; + + while ((next0 = byte_chr(data,datalen,0)) < datalen) { + switch(data[0]) { + case 'D': + flagdeny = 1; + break; + case '+': + split = str_chr(data + 1,'='); + if (data[1 + split] == '=') { + data[1 + split] = 0; + env(data + 1,data + 1 + split + 1); + } + break; + } + ++next0; + data += next0; datalen -= next0; + } +} + +int doit(int t) { + int j; + SSL *ssl; + uint32 netif; + + if (ip6_isv4mapped(remoteip)) { + remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0; + localipstr[ip4_fmt(localipstr,localip + 12)] = 0; + } else { + remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0; + localipstr[ip6_fmt(localipstr,localip)] = 0; + } + + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + log_who(who,B("pid ",strnum," from ",remoteipstr)); + } + + if (socket_local(t,localip,&localport,&netif) == -1) + logmsg(who,111,FATAL,"unable to get local address"); + + remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0; + + if (!localhost) + if (dns_name(&localhostsa,localip) >= 0) + if (localhostsa.len) { + if (!stralloc_0(&localhostsa)) drop_nomem(); + localhost = localhostsa.s; + } + + env("PROTO","TLS"); + env("SSLLOCALIP",localipstr); + env("SSLLOCALPORT",localportstr); + env("SSLLOCALHOST",localhost); + env("SSLREMOTEIP",remoteipstr); + env("SSLREMOTEPORT",remoteportstr); + env("SSLREMOTEHOST",remotehost); + + if (flagtcpenv) { + env("TCPLOCALIP",localipstr); + env("TCPLOCALPORT",localportstr); + env("TCPLOCALHOST",localhost); + env("TCPREMOTEIP",remoteipstr); + env("TCPREMOTEPORT",remoteportstr); + env("TCPREMOTEHOST",remotehost); + if (!ip6_isv4mapped(localip)) { + env("PROTO","TCP6"); + env("TCP6LOCALIP",localipstr); + env("TCP6LOCALHOST",localhost); + env("TCP6LOCALPORT",localportstr); + env("TCP6REMOTEIP",remoteipstr); + env("TCP6REMOTEPORT",remoteportstr); + env("TCP6REMOTEHOST",remotehost); + if (netif) + env("TCP6INTERFACE",socket_getifname(netif)); + } else + env("PROTO","TCP"); + } + + if (flagremotehost) + if (dns_name(&remotehostsa,remoteip) >= 0) + if (remotehostsa.len) { + if (flagparanoid) { + if (dns_ip6(&tmp,&remotehostsa) >= 0) + for (j = 0; j + 16 <= tmp.len; j += 16) + if (byte_equal(remoteip,16,tmp.s + j)) { + flagparanoid = 0; + break; + } + if (dns_ip4(&tmp,&remotehostsa) >= 0) + for (j = 0; j + 4 <= tmp.len; j += 4) + if (byte_equal(remoteip,4,tmp.s + j)) { + flagparanoid = 0; + break; + } + } + if (!flagparanoid) { + if (!stralloc_0(&remotehostsa)) drop_nomem(); + remotehost = remotehostsa.s; + } + } + + if (flagremoteinfo) { + if (remoteinfo(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1) + flagremoteinfo = 0; + if (!stralloc_0(&tcpremoteinfo)) drop_nomem(); + } + env("SSLREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); + if (flagtcpenv) + env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); + + if (fnrules) { + int fdrules; + flagdeny = 0; + fdrules = open_read(fnrules); + if (fdrules == -1) { + if (errno != ENOENT) drop_rules(); + if (!flagallownorules) drop_rules(); + } else { + if (rules(found,fdrules,remoteipstr,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) + drop_rules(); + close(fdrules); + } + } + + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + if (!stralloc_copys(&tmp,who)) drop_nomem(); + if (!stralloc_cats(&tmp,": ")) drop_nomem(); + safecats(flagdeny ? "deny" : "ok"); + cats(" "); safecats(strnum); + cats(" "); if (localhost) safecats(localhost); + cats(":"); safecats(localipstr); + cats(":"); safecats(localportstr); + cats(" "); if (remotehost) safecats(remotehost); + cats(":"); safecats(remoteipstr); + cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s); + cats(":"); safecats(remoteportstr); + cats("\n"); + buffer_putflush(buffer_2,tmp.s,tmp.len); + } + + if (flagdeny) { + close(t); + return(0); + } + + if (pipe(pi) == -1) logmsg(who,111,FATAL,"unable to create pipe"); + if (pipe(po) == -1) logmsg(who,111,FATAL,"unable to create pipe"); + + ssl = ssl_new(ctx,t); + if (!ssl) logmsg(who,111,FATAL,"unable to create SSL instance"); + if (ndelay_on(t) == -1) + logmsg(who,111,FATAL,"unable to set socket options"); + if (ssl_timeoutaccept(ssl,ssltimeout) == -1) { + strnum[fmt_ulong(strnum,getpid())] = 0; + logmsg(who,110,DROP,B("unable to TLS accept for pid:",strnum)); + ssl_error(error_warn); + } + + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + log_who(who,B("tls ",strnum," accept ")); + } + + if (flagclientcert) { + switch(ssl_verify(ssl,remotehost,&certname)) { + case -1: + logmsg(who,110,ERROR,"no client certificate"); + case -2: + logmsg(who,110,ERROR,"missing credentials (CA) or unable to validate client certificate"); + case -3: + if (!stralloc_0(&certname)) drop_nomem(); + logmsg(who,110,ERROR,B("client hostname name does not match certificate: ",remotehost," <=> ",certname.s)); + default: + break; + } + } + + switch(fork()) { + case -1: + logmsg(who,111,FATAL,"unable to fork "); + case 0: + close(pi[0]); close(po[1]); + sig_uncatch(sig_child); + sig_unblock(sig_child); + if (ssl_io(ssl,pi[1],po[0],progtimeout) == -1) { + strnum[fmt_ulong(strnum,getpid())] = 0; + logmsg(who,-99,WARN,B("unable to speak TLS for pid: ",strnum)); + ssl_error(error_warn); + _exit(111); + } + _exit(0); + } + close(pi[1]); close(po[0]); + + if (flagsslenv && !ssl_server_env(ssl,&envplus)) drop_nomem(); + env_def(); + + if (fd_move(0,pi[0]) == -1) + logmsg(who,111,FATAL,"unable to set up descriptor 0"); + if (fd_move(1,po[1]) == -1) + logmsg(who,111,FATAL,"unable to set up descriptor 1"); + + if (flagkillopts) { + socket_ipoptionskill(t); + } + if (!flagdelay) + socket_tcpnodelay(t); + + if (*banner) { + buffer_init(&b,buffer_unixwrite,1,bspace,sizeof(bspace)); + if (buffer_putsflush(&b,banner) == -1) + logmsg(who,111,FATAL,"unable to print banner"); + } + + ssl_free(ssl); + return 1; +} + +void done(void) { + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + if (!stralloc_copys(&tmp,who)) drop_nomem(); + if (!stralloc_cats(&tmp,": ")) drop_nomem(); + cats("done "); safecats(strnum); cats("\n"); + buffer_putflush(buffer_2,tmp.s,tmp.len); + } +} + + +/* ---------------------------- parent */ + +void usage(void) +{ + logmsg(who,100,USAGE,B(who,"\ +[ -1346UXpPhHrRoOdDqQviIeEsS ] \ +[ -c limit ] \ +[ -x rules.cdb ] \ +[ -B banner ] \ +[ -g gid ] \ +[ -u uid ] \ +[ -b backlog ] \ +[ -l localname ] \ +[ -t timeout ] \ +[ -T ssltimeout ] \ +[ -w progtimeout ] \ +[ -f lockfile ] \ +[ -I interface ] \ +host port program")); +} + +unsigned long limit = 40; +unsigned long numchildren = 0; + +int flag1 = 0; +int flag3 = 0; +unsigned long backlog = 20; +unsigned long uid = 0; +unsigned long gid = 0; + +void printstatus(void) { + if (verbosity < 2) return; + strnum[fmt_ulong(strnum,numchildren)] = 0; + strnum2[fmt_ulong(strnum2,limit)] = 0; + log_who(who,B("status: ",strnum,"/",strnum2)); +} + +void trigger(void) { + buffer_unixwrite(selfpipe[1],"",1); +} + +void sigterm(void) { + int pid; + + flagexit = 1; + pid = getpid(); + if (pid < 0) logmsg(who,111,FATAL,"cannot get pid"); + kill(-pid,SIGTERM); + trigger(); +} + +void sigchld(void) { + int wstat; + int pid; + + while ((pid = wait_nohang(&wstat)) > 0) { + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,pid)] = 0; + strnum2[fmt_ulong(strnum2,wstat)] = 0; + log_who(who,B("end ",strnum," status ",strnum2)); + } + if (numchildren) --numchildren; printstatus(); + if (flagexit && !numchildren) _exit(0); + } + trigger(); +} + +void read_passwd(void) { + if (!password.len) { + buffer_init(&b,buffer_unixread,3,bspace,sizeof(bspace)); + if (getln(&b,&password,&match,'\0') == -1) + logmsg(who,111,ERROR,"unable to read password"); + close(3); + if (match) --password.len; + } +} + +int passwd_cb(char *buff,int size,int rwflag,void *userdata) { + if (size < password.len) + logmsg(who,111,ERROR,"password too long"); + + byte_copy(buff,password.len,password.s); + return password.len; +} + +void spawn(int s,int argc,char * const *argv) { + int t; + + while (numchildren >= limit) sig_pause(); + while (numchildren < limit) { + ++numchildren; printstatus(); + + switch(fork()) { + case 0: + sig_uncatch(sig_child); + sig_unblock(sig_child); + sig_uncatch(sig_term); + sig_uncatch(sig_pipe); + for (;;) { + if (lockfile) { + if (lock_ex(fdlock) == -1) + logmsg(who,111,FATAL,B("unable to lock: ",(char *)lockfile)); + if (flagdualstack) + t = socket_accept6(s,remoteip,&remoteport,&netif); + else + t = socket_accept4(s,remoteip,&remoteport); + lock_un(fdlock); + } else { + if (flagdualstack) + t = socket_accept6(s,remoteip,&remoteport,&netif); + else + t = socket_accept4(s,remoteip,&remoteport); + } + + if (t == -1) continue; + if (!doit(t)) continue; + server(argc,argv); + close(0); close(1); + env_reset(); + done(); + } + break; + case -1: + logmsg(who,111,FATAL,"unable to fork"); + --numchildren; printstatus(); + } + } +} + +int main(int argc,char * const *argv) { + int opt; + struct servent *se; + char *x; + int j; + int s; + int ipflag = 0; + iopause_fd io[2]; + char ch; + struct taia deadline; + struct taia stamp; + unsigned long u; + + who = argv[0]; + while ((opt = getopt(argc,argv,"dDvqQhHrRUXx:t:T:u:g:l:b:B:c:pPoO1346I:EeSsaAf:w:zZ")) != opteof) + switch(opt) { + case 'b': scan_ulong(optarg,&backlog); break; + case 'c': scan_ulong(optarg,&limit); break; + case 'X': flagallownorules = 1; break; + case 'x': fnrules = optarg; break; + case 'B': banner = optarg; break; + case 'd': flagdelay = 1; break; + case 'D': flagdelay = 0; break; + case 'v': verbosity = 2; break; + case 'q': verbosity = 0; break; + case 'Q': verbosity = 1; break; + case 'P': flagparanoid = 0; break; + case 'p': flagparanoid = 1; break; + case 'O': flagkillopts = 1; break; + case 'o': flagkillopts = 0; break; + case 'H': flagremotehost = 0; break; + case 'h': flagremotehost = 1; break; + case 'R': flagremoteinfo = 0; break; + case 'r': flagremoteinfo = 1; break; + case 't': scan_ulong(optarg,&timeout); break; + case 'T': scan_ulong(optarg,&ssltimeout); break; + case 'U': x = env_get("UID"); if (x) scan_ulong(x,&uid); + x = env_get("GID"); if (x) scan_ulong(x,&gid); break; + case 'u': scan_ulong(optarg,&uid); break; + case 'g': scan_ulong(optarg,&gid); break; + case 'l': localhost = optarg; break; + case 'I': netif = socket_getifidx(optarg); break; + case '1': flag1 = 1; break; + case '3': flag3 = 1; break; + case '4': ipflag = 1; break; + case '6': ipflag = 2; break; + case 'Z': flagclientcert = 0; break; + case 'z': flagclientcert = 1; break; + case 'S': flagsslenv = 0; break; + case 's': flagsslenv = 1; break; + case 'E': flagtcpenv = 0; break; + case 'e': flagtcpenv = 1; break; + case 'A': flagafter = 0; break; + case 'a': flagafter = 1; break; + case 'f': lockfile = optarg; break; + case 'w': scan_uint(optarg,&progtimeout); break; + default: usage(); + } + argc -= optind; + argv += optind; + + if (!verbosity) buffer_2->fd = -1; + + hostname = *argv++; + if (!hostname || str_equal((char *)hostname,"")) usage(); + if (str_equal((char *)hostname,"0")) hostname = loopback; + else if (str_equal((char *)hostname,":0")) { + flagdualstack = 1; + hostname = "::"; + } + + x = *argv++; --argc; + if (!x) usage(); + if (!x[scan_ulong(x,&u)]) + localport = u; + else { + se = getservbyname(x,"tcp"); + if (!se) + logmsg(who,111,FATAL,B("unable to figure out port number for: ",x)); + uint16_unpack_big((char*)&se->s_port,&localport); + } + + if ((x = env_get("VERIFYDEPTH"))) { + scan_ulong(x,&u); + verifydepth = u; + } + + if ((x = env_get("CAFILE"))) cafile = x; + if (cafile && str_equal((char *)cafile,"")) cafile = 0; + + if ((x = env_get("CCAFILE"))) ccafile = x; + if (ccafile && str_equal((char *)ccafile,"")) ccafile = 0; + if (!flagclientcert) ccafile = 0; + + if ((x = env_get("CADIR"))) cadir = x; + if (cadir && str_equal((char *)cadir,"")) cadir= 0; + + if ((x = env_get("CERTCHAINFILE"))) certchainfile = x; + if (certchainfile && str_equal((char *)certchainfile,"")) certchainfile = 0; + + if ((x = env_get("CERTFILE"))) certfile = x; + if (certfile && str_equal((char *)certfile,"")) certfile = 0; + + if ((x = env_get("KEYFILE"))) keyfile = x; + if (keyfile && str_equal((char *)keyfile,"")) keyfile = 0; + + if ((x = env_get("DHFILE"))) dhfile = x; + if (dhfile && str_equal((char *)dhfile,"")) dhfile = 0; + + if ((x = env_get("CIPHERS"))) ciphers = x; + if (ciphers && str_equal((char *)ciphers,"")) ciphers = 0; + + if (setsid() == -1) + if (getpgrp() != getpid()) + logmsg(who,111,FATAL,"unable to create process group"); + + if (lockfile) { + fdlock = open_append(lockfile); + if (fdlock == -1) + logmsg(who,111,FATAL,B("unable to open: ",(char *)lockfile)); + } + + if (pipe(selfpipe) == -1) + logmsg(who,111,FATAL,"unable to create pipe"); + + coe(selfpipe[0]); + coe(selfpipe[1]); + ndelay_on(selfpipe[0]); + ndelay_on(selfpipe[1]); + + sig_block(sig_child); + sig_catch(sig_child,sigchld); + sig_catch(sig_term,sigterm); + sig_ignore(sig_pipe); + + /* IP address only */ + + if (ip4_scan(hostname,localip)) { + if (!stralloc_copyb(&addresses,(char *)V4mappedprefix,12)) drop_nomem(); + if (!stralloc_catb(&addresses,localip,4)) drop_nomem(); + byte_copy(localip,16,addresses.s); + } else if (ip6_scan(hostname,localip)) { + if (!stralloc_copyb(&addresses,localip,16)) drop_nomem(); + byte_copy(localip,16,addresses.s); + } + + /* Asynchronous DNS IPv4/IPv6 Name qualification */ + + if (!addresses.len) { + if (!stralloc_copys(&tmp,hostname)) drop_nomem(); + if (dns_ip_qualify(&addresses,&fqdn,&tmp) < 0) + logmsg(who,111,FATAL,B("temporarily unable to figure out IP address for: ",(char *)hostname)); + + byte_copy(localip,16,addresses.s); + + for (j = 0; j < addresses.len; j += 16) { // Select best matching IP address + if (ipflag == 1 && !ip6_isv4mapped(addresses.s + j)) continue; + if (ipflag == 2 && !ip6_isv4mapped(addresses.s + j)) continue; + byte_copy(localip,16,addresses.s + j); + } + + } + if (addresses.len < 16) + logmsg(who,111,FATAL,B("no IP address for: ",(char *)hostname)); + + if (ip6_isv4mapped(localip)) + s = socket_tcp4(); + else + s = socket_tcp6(); + if (s == -1) + logmsg(who,111,FATAL,"unable to create socket"); + + if (flagdualstack) + socket_dualstack(s); + if (socket_bind_reuse(s,localip,localport,netif) == -1) + logmsg(who,111,FATAL,"unable to bind"); + if (socket_local(s,localip,&localport,&netif) == -1) + logmsg(who,111,FATAL,"unable to get local address"); + if (socket_listen(s,backlog) == -1) + logmsg(who,111,FATAL,"unable to listen"); + ndelay_off(s); + + if (!flagafter) { + if (gid) if (prot_gid(gid) == -1) + logmsg(who,111,FATAL,"unable to set gid"); + if (uid) if (prot_uid(uid) == -1) + logmsg(who,111,FATAL,"unable to set uid"); + } + + if (ip6_isv4mapped(localip)) + localipstr[ip4_fmt(localipstr,localip + 12)] = 0; + else + localipstr[ip6_fmt(localipstr,localip)] = 0; + + localportstr[fmt_ulong(localportstr,localport)] = 0; + + if (flag1) { + buffer_init(&b,buffer_unixwrite,1,bspace,sizeof(bspace)); + buffer_puts(&b,localipstr); + buffer_puts(&b," : "); + buffer_puts(&b,localportstr); + buffer_puts(&b,"\n"); + buffer_flush(&b); + } + + if (flag3) read_passwd(); + + ctx = ssl_server(); + ssl_errstr(); + if (!ctx) logmsg(who,111,FATAL,"unable to create TLS context"); + + if (certchainfile) { + switch (ssl_chainfile(ctx,certchainfile,keyfile,passwd_cb)) { + case -1: logmsg(who,111,ERROR,"unable to load certificate chain file"); + case -2: logmsg(who,111,ERROR,"unable to load key"); + case -3: logmsg(who,111,ERROR,"key does not match certificate"); + default: break; + } + } else { + switch (ssl_certkey(ctx,certfile,keyfile,passwd_cb)) { + case -1: logmsg(who,111,ERROR,"unable to load certificate"); + case -2: logmsg(who,111,ERROR,"unable to load key"); + case -3: logmsg(who,111,ERROR,"key does not match certificate"); + default: break; + } + } + + if (flagclientcert && !ssl_ca(ctx,cafile,cadir,verifydepth)) + logmsg(who,111,ERROR,"unable to load CA list"); + + if (!ssl_cca(ctx,ccafile)) + logmsg(who,111,ERROR,"unable to load client CA list"); + + if (!ssl_params_rsa(ctx,rsalen)) + logmsg(who,111,ERROR,"unable to set RSA parameters"); + if (!ssl_params_dh(ctx,dhfile)) + logmsg(who,111,ERROR,"unable to set DH parameters"); + + if (flagafter) { + if (gid) if (prot_gid(gid) == -1) + logmsg(who,111,FATAL,"unable to set gid"); + if (uid) if (prot_uid(uid) == -1) + logmsg(who,111,FATAL,"unable to set uid"); + } + + if (!ssl_ciphers(ctx,ciphers)) + logmsg(who,111,ERROR,"unable to set cipher list"); + + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + strnum2[fmt_ulong(strnum2,rsalen)] = 0; + log_who(who,B("ciphers ",strnum," ",(char *)ciphers)); + log_who(who,B("cafile ",strnum," ",(char *)cafile)); + log_who(who,B("ccafile ",strnum," ",(char *)ccafile)); + log_who(who,B("cadir ",strnum," ",(char *)cadir)); + log_who(who,B("certchainfile ",strnum," ",(char *)certchainfile)); + log_who(who,B("cert ",strnum," ",(char *)certfile)); + log_who(who,B("key ",strnum," ",(char *)keyfile)); + /* XXX */ + log_who(who,B("dhparam ",strnum," ",(char *)dhfile," ",strnum2)); + } + + close(0); + close(1); + printstatus(); + + for (;;) { + int pause_ret, read_ret; + if (!flagexit) spawn(s,argc,argv); + + sig_unblock(sig_child); + io[0].fd = selfpipe[0]; + io[0].events = IOPAUSE_READ; + taia_now(&stamp); + taia_uint(&deadline,3600); + taia_add(&deadline,&stamp,&deadline); + pause_ret = iopause(io,1,&deadline,&stamp); + sig_block(sig_child); + + if (flagexit && !numchildren) _exit(0); + while ((read_ret = buffer_unixread(selfpipe[0],&ch,1)) == 1) + ; + if ((pause_ret > 0) && (read_ret == 0)) { + flagexit = 1; + --numchildren; + } + if (flagexit && !numchildren) _exit(0); + } +} diff --git a/src/sslperl.c b/src/sslperl.c new file mode 100644 index 0000000..1d01da1 --- /dev/null +++ b/src/sslperl.c @@ -0,0 +1,105 @@ +#include <EXTERN.h> +#include <perl.h> +#include "exit.h" +#include "logmsg.h" +#include "stralloc.h" +#include "str.h" +#include "ucspissl.h" + +#ifndef eval_pv +#define eval_pv perl_eval_pv +#endif + +#ifndef call_argv +#define call_argv perl_call_argv +#endif + +extern char *Who = "PERL!"; + +//extern const char *Who; + +/* ActiveState Perl requires this be called my_perl */ +static PerlInterpreter *my_perl = 0; + +static void usage(void) { + logmsg(Who,100,USAGE,"sslargs file sub args"); +} + +static stralloc newenv = {0}; +static char *trivenv[] = { 0 }; +static char **perlenv = trivenv; +static char **origenv = 0; + +void env_append(const char *c) { + if (!stralloc_append(&newenv,c)) + logmsg(Who,111,FATAL,"out of memory"); +} + +#define EXTERN_C extern + +EXTERN_C void xs_init() { +} + +void server(int argc,char **argv) { + char *prog[] = { "", *argv }; + int i; + int j; + int split; + const char *x; + + ++argv; --argc; + if (!argv) usage(); + if (!*argv) usage(); + + origenv = environ; + environ = perlenv; + + if (!my_perl) { + my_perl = perl_alloc(); + if (!my_perl) logmsg(Who,111,FATAL,"out of memory"); + perl_construct(my_perl); + if (perl_parse(my_perl,xs_init,2,prog,trivenv)) + logmsg(Who,111,FATAL,"perl_parse failed"); + + if (perl_run(my_perl)) + logmsg(Who,111,FATAL,"perl_run failed"); + } + + if (!stralloc_copys(&newenv,"%ENV=(")) + logmsg(Who,111,FATAL,"out of memory"); + + for (i = 0; origenv[i]; ++i) { + x = origenv[i]; + if (!x) continue; + split = str_chr(x,'='); + env_append("'"); + for (j = 0; j < split; ++j) { + if (*x == '\'' || *x == '\\') env_append("\\"); + env_append(x++); + } + env_append("'"); + env_append(","); + env_append("'"); + if (*x == '=') ++x; + while (*x) { + if (*x == '\'' || *x == '\\') env_append("\\"); + env_append(x++); + } + env_append("'"); + env_append(","); + } + env_append(")"); + env_append("\0"); + + ENTER; + SAVETMPS; + eval_pv(newenv.s,TRUE); + FREETMPS; + LEAVE; + + if (call_argv(*argv,G_VOID|G_DISCARD,argv + 1)) + logmsg(Who,111,FATAL,"interpreter failed"); + + perlenv = environ; + environ = origenv; +} diff --git a/src/sslprint.c b/src/sslprint.c new file mode 100644 index 0000000..0033107 --- /dev/null +++ b/src/sslprint.c @@ -0,0 +1,411 @@ +#include "buffer.h" +#include "env.h" + +static char *e[] = {0}; +static int n = 0; + +void server(int argc,const char * const *argv) { + char *x; + + buffer_puts(buffer_1,"\nPROTO="); + x = env_get("PROTO"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSLLOCALHOST="); + x = env_get("SSLLOCALHOST"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSLLOCALIP="); + x = env_get("SSLLOCALIP"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSLLOCALPORT="); + x = env_get("SSLLOCALPORT"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSLREMOTEHOST="); + x = env_get("SSLREMOTEHOST"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSLREMOTEIP="); + x = env_get("SSLREMOTEIP"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSLREMOTEPORT="); + x = env_get("SSLREMOTEPORT"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSLREMOTEINFO="); + x = env_get("SSLREMOTEINFO"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nTCPLOCALHOST="); + x = env_get("TCPLOCALHOST"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nTCPLOCALIP="); + x = env_get("TCPLOCALIP"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nTCPLOCALPORT="); + x = env_get("TCPLOCALPORT"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nTCPREMOTEHOST="); + x = env_get("TCPREMOTEHOST"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nTCPREMOTEIP="); + x = env_get("TCPREMOTEIP"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nTCPREMOTEPORT="); + x = env_get("TCPREMOTEPORT"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nTCPREMOTEINFO="); + x = env_get("TCPREMOTEINFO"); + buffer_puts(buffer_1,x ? x : "unset"); + + + buffer_puts(buffer_1,"\nTCP6REMOTEHOST="); + x = env_get("TCP6REMOTEHOST"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nTCP6REMOTEIP="); + x = env_get("TCP6REMOTEIP"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nTCP6REMOTEPORT="); + x = env_get("TCP6REMOTEPORT"); + buffer_puts(buffer_1,x ? x : "unset"); + + + buffer_puts(buffer_1,"\nSSL_PROTOCOL="); + x = env_get("SSL_PROTOCOL"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SESSION_ID="); + x = env_get("SSL_SESSION_ID"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CIPHER="); + x = env_get("SSL_CIPHER"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CIPHER_EXPORT="); + x = env_get("SSL_CIPHER_EXPORT"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CIPHER_USEKEYSIZE="); + x = env_get("SSL_CIPHER_USEKEYSIZE"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CIPHER_ALGKEYSIZE="); + x = env_get("SSL_CIPHER_ALGKEYSIZE"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_VERSION_INTERFACE="); + x = env_get("SSL_VERSION_INTERFACE"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_VERSION_LIBRARY="); + x = env_get("SSL_VERSION_LIBRARY"); + buffer_puts(buffer_1,x ? x : "unset"); + + + buffer_puts(buffer_1,"\nSSL_SERVER_M_VERSION="); + x = env_get("SSL_SERVER_M_VERSION"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_M_SERIAL="); + x = env_get("SSL_SERVER_M_SERIAL"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN="); + x = env_get("SSL_SERVER_S_DN"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_C="); + x = env_get("SSL_SERVER_S_DN_C"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_ST="); + x = env_get("SSL_SERVER_S_DN_ST"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_L="); + x = env_get("SSL_SERVER_S_DN_L"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_O="); + x = env_get("SSL_SERVER_S_DN_O"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_OU="); + x = env_get("SSL_SERVER_S_DN_OU"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_CN="); + x = env_get("SSL_SERVER_S_DN_CN"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_T="); + x = env_get("SSL_SERVER_S_DN_T"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_I="); + x = env_get("SSL_SERVER_S_DN_I"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_G="); + x = env_get("SSL_SERVER_S_DN_G"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_S="); + x = env_get("SSL_SERVER_S_DN_S"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_D="); + x = env_get("SSL_SERVER_S_DN_D"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_UID="); + x = env_get("SSL_SERVER_S_DN_UID"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_S_DN_Email="); + x = env_get("SSL_SERVER_S_DN_Email"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN="); + x = env_get("SSL_SERVER_I_DN"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_C="); + x = env_get("SSL_SERVER_I_DN_C"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_ST="); + x = env_get("SSL_SERVER_I_DN_ST"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_L="); + x = env_get("SSL_SERVER_I_DN_L"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_O="); + x = env_get("SSL_SERVER_I_DN_O"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_OU="); + x = env_get("SSL_SERVER_I_DN_OU"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_CN="); + x = env_get("SSL_SERVER_I_DN_CN"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_T="); + x = env_get("SSL_SERVER_I_DN_T"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_I="); + x = env_get("SSL_SERVER_I_DN_I"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_G="); + x = env_get("SSL_SERVER_I_DN_G"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_S="); + x = env_get("SSL_SERVER_I_DN_S"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_D="); + x = env_get("SSL_SERVER_I_DN_D"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_UID="); + x = env_get("SSL_SERVER_I_DN_UID"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_I_DN_Email="); + x = env_get("SSL_SERVER_I_DN_Email"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_V_START="); + x = env_get("SSL_SERVER_V_START"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_V_END="); + x = env_get("SSL_SERVER_V_END"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_A_SIG="); + x = env_get("SSL_SERVER_A_SIG"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_A_KEY="); + x = env_get("SSL_SERVER_A_KEY"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_SERVER_CERT="); + x = env_get("SSL_SERVER_CERT"); + buffer_puts(buffer_1,x ? x : "unset"); + + + buffer_puts(buffer_1,"\nSSL_CLIENT_M_VERSION="); + x = env_get("SSL_CLIENT_M_VERSION"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_M_SERIAL="); + x = env_get("SSL_CLIENT_M_SERIAL"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN="); + x = env_get("SSL_CLIENT_S_DN"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_C="); + x = env_get("SSL_CLIENT_S_DN_C"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_ST="); + x = env_get("SSL_CLIENT_S_DN_ST"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_L="); + x = env_get("SSL_CLIENT_S_DN_L"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_O="); + x = env_get("SSL_CLIENT_S_DN_O"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_OU="); + x = env_get("SSL_CLIENT_S_DN_OU"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_CN="); + x = env_get("SSL_CLIENT_S_DN_CN"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_T="); + x = env_get("SSL_CLIENT_S_DN_T"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_I="); + x = env_get("SSL_CLIENT_S_DN_I"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_G="); + x = env_get("SSL_CLIENT_S_DN_G"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_S="); + x = env_get("SSL_CLIENT_S_DN_S"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_D="); + x = env_get("SSL_CLIENT_S_DN_D"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_UID="); + x = env_get("SSL_CLIENT_S_DN_UID"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_S_DN_Email="); + x = env_get("SSL_CLIENT_S_DN_Email"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN="); + x = env_get("SSL_CLIENT_I_DN"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_C="); + x = env_get("SSL_CLIENT_I_DN_C"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_ST="); + x = env_get("SSL_CLIENT_I_DN_ST"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_L="); + x = env_get("SSL_CLIENT_I_DN_L"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_O="); + x = env_get("SSL_CLIENT_I_DN_O"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_OU="); + x = env_get("SSL_CLIENT_I_DN_OU"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_CN="); + x = env_get("SSL_CLIENT_I_DN_CN"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_T="); + x = env_get("SSL_CLIENT_I_DN_T"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_I="); + x = env_get("SSL_CLIENT_I_DN_I"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_G="); + x = env_get("SSL_CLIENT_I_DN_G"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_S="); + x = env_get("SSL_CLIENT_I_DN_S"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_D="); + x = env_get("SSL_CLIENT_I_DN_D"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_UID="); + x = env_get("SSL_CLIENT_I_DN_UID"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_I_DN_Email="); + x = env_get("SSL_CLIENT_I_DN_Email"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_V_START="); + x = env_get("SSL_CLIENT_V_START"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_V_END="); + x = env_get("SSL_CLIENT_V_END"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_A_SIG="); + x = env_get("SSL_CLIENT_A_SIG"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_A_KEY="); + x = env_get("SSL_CLIENT_A_KEY"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_CERT="); + x = env_get("SSL_CLIENT_CERT"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_CERT_CHAIN_0="); + x = env_get("SSL_CLIENT_CERT_CHAIN_0"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_puts(buffer_1,"\nSSL_CLIENT_CERT_CHAIN_1="); + x = env_get("SSL_CLIENT_CERT_CHAIN_1"); + buffer_puts(buffer_1,x ? x : "unset"); + + buffer_putsflush(buffer_1,"\n"); + + if (++n > 1) { + environ = e; + } +} diff --git a/src/sslserver.c b/src/sslserver.c new file mode 100644 index 0000000..b342430 --- /dev/null +++ b/src/sslserver.c @@ -0,0 +1,991 @@ +/** + @file sslserver.c + @author web, fefe, feh + @brief IPv6 enabled dualstack sslserver +*/ +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <netdb.h> +#include <fcntl.h> +#include <arpa/inet.h> +#include <signal.h> +#include "ucspissl.h" +#include "uint_t.h" +#include "str.h" +#include "byte.h" +#include "fmt.h" +#include "scan.h" +#include "ip.h" +#include "fd.h" +#include "exit.h" +#include "env.h" +#include "prot.h" +#include "open.h" +#include "wait.h" +#include "stralloc.h" +#include "genalloc.h" +#include "alloc.h" +#include "buffer.h" +#include "getln.h" +#include "error.h" +#include "logmsg.h" +#include "getoptb.h" +#include "pathexec.h" +#include "socket_if.h" +#include "ndelay.h" +#include "remoteinfo.h" +#include "rules.h" +#include "sig.h" +#include "iopause.h" +#include "dnsresolv.h" +#include "auto_cafile.h" +#include "auto_cadir.h" +#include "auto_ccafile.h" +#include "auto_dhfile.h" +#include "auto_certfile.h" +#include "auto_certchainfile.h" +#include "auto_keyfile.h" +#include "auto_ciphers.h" + +#define WHO "sslserver" + +int verbosity = 1; +int flagkillopts = 1; +int flagdelay = 0; +const char *banner = ""; +int flagremoteinfo = 0; +int flagremotehost = 1; +int flagparanoid = 0; +int flagclientcert = 0; +int flagsslenv = 0; +int flagtcpenv = 1; +int flagsslwait = 0; +unsigned long timeout = 26; +unsigned long ssltimeout = 26; +unsigned int progtimeout = 3600; +uint32 netif = 0; + +static stralloc tcpremoteinfo; + +uint16 localport; +char iplocal[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; +char localportstr[FMT_ULONG]; +char localip[16]; +char localipstr[IP6_FMT]; +static stralloc localhostsa; +const char *localhost = 0; + +uint16 remoteport; +char remoteportstr[FMT_ULONG]; +char remoteip[16]; +char remoteipstr[IP6_FMT]; +static stralloc remotehostsa; +char *remotehost = 0; +char *verifyhost = 0; + +const char *hostname; +const char *thishost = "0.0.0.0"; + +unsigned long uid = 0; +unsigned long gid = 0; + +static char strnum[FMT_ULONG]; +static char strnum2[FMT_ULONG]; +static char strnum3[FMT_ULONG]; + +static stralloc tmp; +static stralloc fqdn; +static stralloc addresses; + +unsigned long limit = 40; +unsigned long numchildren = 0; +unsigned long ipchildren = 0; +unsigned long maxconip = 0; + +char bspace[16]; +buffer bo; + +void drop_nomem(void) +{ + logmsg(WHO,111,FATAL,"out of memory"); +} + +/* ---------------------------- per ip limit */ + +struct child { + char ipaddr[16]; + uint32 num; +}; + +GEN_ALLOC_typedef(child_alloc,struct child,c,len,a) +GEN_ALLOC_readyplus(child_alloc,struct child,c,len,a,i,n,x,24,child_readyplus) +GEN_ALLOC_append(child_alloc,struct child,c,len,a,i,n,x,24,child_readyplus,child_append) + +child_alloc children = {0}; + +void ipchild_append(char ip[16],unsigned long n) +{ + struct child *ipchild = 0; + int i; + + for (i = 0; i <= n; ++i) { + ipchild = &children.c[i]; + if (byte_equal(ipchild->ipaddr,16,ip)) { + ++ipchild->num; + break; + } else { + byte_copy(ipchild->ipaddr,16,ip); + ++ipchild->num; + break; + } + } +} + +void ipchild_clear(char ip[16]) +{ + struct child *ipchild = 0; + int i; + + for (i = 0; i <= children.len; ++i) { + ipchild = &children.c[i]; + if (byte_equal(ipchild->ipaddr,16,ip)) { + if (ipchild->num) --ipchild->num; + break; + } + } +} + +int ipchild_limit(char ip[16],unsigned long n) +{ + int i; + + for (i = 0; i <= n; ++i) + if (byte_equal(children.c[i].ipaddr,16,ip)) + return children.c[i].num; + + return 0; +} + +SSL_CTX *ctx; +const char *certchainfile = auto_certchainfile; +const char *certfile = auto_certfile; +const char *keyfile = auto_keyfile; +stralloc password = {0}; +stralloc certname = {0}; +int match = 0; +const char *cafile = auto_cafile; +const char *ccafile = auto_ccafile; +const char *cadir = auto_cadir; +const char *ciphers = auto_ciphers; +int verifydepth = 1; +const char *dhfile = auto_dhfile; +int rsalen = SSL_RSA_LEN; + +char * const *prog; + +int pi[2]; +int po[2]; +int pt[2]; + +stralloc envsa = {0}; + +X509 *cert; +char buf[SSL_NAME_LEN]; + +/* ---------------------------- child */ + +int flagdualstack = 0; +int flagdeny = 0; +int flagallownorules = 0; +const char *fnrules = 0; +const char *fniprules = 0; + +void cats(const char *s) +{ + if (!stralloc_cats(&tmp,s)) drop_nomem(); +} +void append(const char *ch) +{ + if (!stralloc_append(&tmp,ch)) drop_nomem(); +} +void safecats(const char *s) { + char ch; + int i; + + for (i = 0;i < 100;++i) { + ch = s[i]; + if (!ch) return; + if (ch < 33) ch = '?'; + if (ch > 126) ch = '?'; + if (ch == '%') ch = '?'; /* logger stupidity */ + append(&ch); + } + cats("..."); +} + +void env(const char *s,const char *t) { + if (!pathexec_env(s,t)) drop_nomem(); +} + +void drop_rules(const char *fnbase) { + logmsg(WHO,110,FATAL,B("unable to read: ",fnbase)); +} + +void found(char *data,unsigned int datalen) { + unsigned int next0; + unsigned int split; + + while ((next0 = byte_chr(data,datalen,0)) < datalen) { + switch(data[0]) { + case 'D': + flagdeny = 1; + break; + case '+': + split = str_chr(data + 1,'='); + if (data[1 + split] == '=') { + data[1 + split] = 0; + env(data + 1,data + 1 + split + 1); + if (!str_diff(data + 1,"MAXCONIP")) { + scan_ulong(data + 1 + split + 1,&maxconip); + if (limit && maxconip > limit) maxconip = limit; + if (ipchildren >= maxconip) flagdeny = 2; + } + } + break; + } + ++next0; + data += next0; datalen -= next0; + } +} + +void doit(int t) { + int j; + SSL *ssl = 0; + int wstat; + int sslctl[2]; + char *s; + unsigned long tmp_long; + char ssl_cmd; + stralloc ssl_env = {0}; + int bytesleft; + char envbuf[8192]; + int childpid; + uint32 netif = 0; + stralloc tlsinfo = {0}; + + if (pipe(pi) == -1) logmsg(WHO,111,FATAL,"unable to create pipe"); + if (pipe(po) == -1) logmsg(WHO,111,FATAL,"unable to create pipe"); + if (socketpair(AF_UNIX,SOCK_STREAM,0,sslctl) == -1) + logmsg(WHO,111,FATAL,"unable to create socketpair"); + +/* Get remote IP and FQDN to validate X.509 cert */ + + if (ip6_isv4mapped(remoteip)) { + localipstr[ip4_fmt(localipstr,localip + 12)] = 0; + remoteipstr[ip4_fmt(remoteipstr,remoteip + 12)] = 0; + } else { + remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0; + localipstr[ip6_fmt(localipstr,localip)] = 0; + } + +/* Early evaluation of IP rules (only) */ + + if (fniprules) { + int fdrules; + fdrules = open_read(fniprules); + if (fdrules == -1) { + if (errno != ENOENT) drop_rules(fniprules); + if (!flagallownorules) drop_rules(fniprules); + } else { + if (rules(found,fdrules,remoteipstr,0,0) == -1) + drop_rules(fniprules); + close(fdrules); + } + } + + if (flagdeny) goto FINISH; + +/* Early lookup of remote information (before child invoked) */ + + if (flagremotehost) + if (dns_name(&remotehostsa,remoteip) >= 0) + if (remotehostsa.len) { + if (flagparanoid) { + verifyhost = remoteipstr; + if (dns_ip6(&tmp,&remotehostsa) >= 0) + for (j = 0; j + 16 <= tmp.len; j += 16) + if (byte_equal(remoteip,16,tmp.s + j)) { + flagparanoid = 0; + break; + } + if (dns_ip4(&tmp,&remotehostsa) >= 0) + for (j = 0; j + 4 <= tmp.len; j += 4) + if (byte_equal(remoteip + 12,4,tmp.s + j)) { + flagparanoid = 0; + break; + } + } + if (!flagparanoid) { + if (!stralloc_0(&remotehostsa)) drop_nomem(); + remotehost = remotehostsa.s; + verifyhost = remotehostsa.s; + } + } + + if (flagremoteinfo) { + if (remoteinfo(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1) + flagremoteinfo = 0; + if (!stralloc_0(&tcpremoteinfo)) drop_nomem(); + } + + if (fnrules) { + int fdrules; + fdrules = open_read(fnrules); + if (fdrules == -1) { + if (errno != ENOENT) drop_rules(fnrules); + if (!flagallownorules) drop_rules(fnrules); + } else { + if (rules(found,fdrules,remoteipstr,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) + drop_rules(fnrules); + close(fdrules); + } + } + + if (flagdeny) goto FINISH; + +/* Prepare the child process */ + + switch (childpid = fork()) { + case -1: + logmsg(WHO,111,FATAL,"unable to fork"); + case 0: + /* Child */ + close(sslctl[0]); + break; + default: + /* Parent */ + + close(pi[0]); close(po[1]); close(sslctl[1]); + + if ((s = env_get("SSL_CHROOT"))) + if (chroot(s) == -1) { + kill(childpid,SIGTERM); + logmsg(WHO,111,FATAL,"unable to chroot"); + } + + if ((s = env_get("SSL_GID"))) { + scan_ulong(s,&tmp_long); + gid = tmp_long; + } + if (gid) if (prot_gid(gid) == -1) { + kill(childpid,SIGTERM); + logmsg(WHO,111,FATAL,"unable to set gid"); + } + + if ((s = env_get("SSL_UID"))) { + scan_ulong(s,&tmp_long); + uid = tmp_long; + } + if (uid) + if (prot_uid(uid) == -1) { + kill(childpid,SIGTERM); + logmsg(WHO,111,FATAL,"unable to set uid"); + } + +/* Get remote IP info to report in logmsg */ + + if (ip6_isv4mapped(remoteip)) + remoteipstr[ip4_fmt(remoteipstr,remoteip + 12)] = 0; + else + remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0; + +/* Read the TLS command socket. This will block until/unless TLS is requested. */ + + if (read(sslctl[0],&ssl_cmd,1) == 1) { + ssl = ssl_new(ctx,t); + if (!ssl) { + kill(childpid,SIGTERM); + logmsg(WHO,111,FATAL,"unable to create TLS instance"); + } + if (ndelay_on(t) == -1) { + kill(childpid,SIGTERM); + logmsg(WHO,111,FATAL,"unable to set socket options"); + } + if (ssl_timeoutaccept(ssl,ssltimeout) == -1) { + strnum[fmt_ulong(strnum,childpid)] = 0; + kill(childpid,SIGTERM); + logmsg(WHO,111,FATAL,B("unable to accept TLS from: ",remoteipstr," for pid: ",strnum," ",ERR_reason_error_string(ssl_errno))); + } + } else if (errno == EAGAIN) { + strnum[fmt_ulong(strnum,childpid)] = 0; + kill(childpid,SIGTERM); + _exit(100); + } + +/* Check the remote client cert during TLS handshake; if requested */ + + if (flagclientcert) { + if (flagclientcert == 2) verifyhost = 0; + switch (ssl_verify(ssl,verifyhost,&certname)) { + case -1: + kill(childpid,SIGTERM); + logmsg(WHO,110,ERROR,B("no client certificate from: ",remoteipstr," for pid: ",strnum)); + case -2: + kill(childpid,SIGTERM); + logmsg(WHO,110,ERROR,B("missing credentials (CA) or unable to validate client certificate from: ",remoteipstr," for pid: ",strnum)); + case -3: + kill(childpid,SIGTERM); + if (!stralloc_0(&certname)) drop_nomem(); + logmsg(WHO,110,ERROR,B("client hostname does not match certificate for pid: ",strnum," ",verifyhost," <=> ",certname.s)); + default: + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,childpid)] = 0; + logmsg(WHO,0,INFO,B("valid client cert received from: ",remoteipstr," for pid: ",strnum)); + } + break; + } + } + +/* Request TLS communication pipe from/to the child process (the application called) */ + + if (ssl_cmd == 'Y') { + ssl_server_env(ssl,&ssl_env); + if (!stralloc_0(&ssl_env)) drop_nomem(); /* Add another NUL */ + env("SSLCTL",ssl_env.s); + + for (bytesleft = ssl_env.len; bytesleft > 0; bytesleft -= j) + if ((j = write(sslctl[0],ssl_env.s,bytesleft)) < 0) { + kill(childpid,SIGTERM); + logmsg(WHO,111,FATAL,"unable to write TLS environment"); + } + } + + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,childpid)] = 0; + if (verbosity >= 3 && ssl_env.len > 1) { + s = ssl_env.s; + if ((j = str_chr(s,'='))) + if (!stralloc_copys(&tlsinfo,s + j + 1)) drop_nomem(); + if (!stralloc_cats(&tlsinfo,":")) drop_nomem(); + s = s + str_len(s) + 1; + s = s + str_len(s) + 1; + if ((j = str_chr(s,'='))) + if (!stralloc_cats(&tlsinfo,s + j + 1)) drop_nomem(); + if (!stralloc_0(&tlsinfo)) drop_nomem(); + log_who(WHO,B("tls ",strnum," accept ",tlsinfo.s)); + } else + log_who(WHO,B("tls ",strnum," accept")); + } + + if (ssl_cmd == 'Y' || ssl_cmd == 'y') { + if (ssl_io(ssl,pi[1],po[0],progtimeout) != 0) { + strnum[fmt_ulong(strnum,childpid)] = 0; + kill(childpid,SIGTERM); + logmsg(WHO,111,ERROR,B("unable to speak TLS with: ",remoteipstr," for pid: ",strnum," ",ERR_reason_error_string(ssl_errno))); + } + if (wait_nohang(&wstat) > 0) + _exit(wait_exitcode(wstat)); + ssl_close(ssl); + } + kill(childpid,SIGTERM); + _exit(0); + } + +/* Child-only below this point */ + + if (ip6_isv4mapped(remoteip)) + localipstr[ip4_fmt(localipstr,localip + 12)] = 0; + else + localipstr[ip6_fmt(localipstr,localip)] = 0; + localportstr[fmt_ulong(localportstr,localport)] = 0; + + if (socket_local(t,localip,&localport,&netif) == -1) + logmsg(WHO,111,FATAL,B("unable to set local address/port: ",localipstr,"/",localportstr)); + + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + log_who(WHO,B("pid ",strnum," from ",remoteipstr)); + } + + if (!localhost) + if (dns_name(&localhostsa,localip) >= 0) + if (localhostsa.len) { + if (!stralloc_0(&localhostsa)) drop_nomem(); + localhost = localhostsa.s; + } + + remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0; + +/* Setup environment variables */ + + env("PROTO","TLS"); + env("SSLLOCALIP",localipstr); + env("SSLLOCALPORT",localportstr); + env("SSLLOCALHOST",localhost); + env("SSLREMOTEIP",remoteipstr); + env("SSLREMOTEPORT",remoteportstr); + env("SSLREMOTEHOST",remotehost); + env("SSLREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); + + if (flagtcpenv) { + env("TCPLOCALIP",localipstr); + env("TCPLOCALPORT",localportstr); + env("TCPLOCALHOST",localhost); + env("TCPREMOTEIP",remoteipstr); + env("TCPREMOTEPORT",remoteportstr); + env("TCPREMOTEHOST",remotehost); + if (!ip6_isv4mapped(remoteip)) { + env("PROTO","TCP6"); + env("TCP6LOCALIP",localipstr); + env("TCP6LOCALHOST",localhost); + env("TCP6LOCALPORT",localportstr); + env("TCP6REMOTEIP",remoteipstr); + env("TCP6REMOTEPORT",remoteportstr); + env("TCP6REMOTEHOST",remotehost); + if (netif) + env("TCP6INTERFACE",socket_getifname(netif)); + } else + env("PROTO","TCP"); + env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); + } + + FINISH: + + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + strnum2[fmt_ulong(strnum2,maxconip)] = 0; + if (!stralloc_copys(&tmp,"sslserver: ")) drop_nomem(); + safecats(flagdeny ? "deny" : "ok"); + cats(" "); safecats(strnum); + cats(" "); if (localhost) safecats(localhost); + cats(":"); safecats(localipstr); + cats(":"); safecats(localportstr); + cats(" "); if (remotehost) safecats(remotehost); + cats(":"); safecats(remoteipstr); + cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s); + cats(":"); safecats(remoteportstr); + if (flagdeny == 2) { cats(" ip connection limit:"); cats(strnum2); cats(" exceeded"); } + cats("\n"); + buffer_putflush(buffer_2,tmp.s,tmp.len); + } + + if (flagdeny) _exit(100); + + if (gid) if (prot_gid(gid) == -1) + logmsg(WHO,111,FATAL,"unable to set gid"); + if (uid) if (prot_uid(uid) == -1) + logmsg(WHO,111,FATAL,"unable to set uid"); + + close(pi[1]); close(po[0]); close(sslctl[0]); + + sig_uncatch(sig_child); + sig_unblock(sig_child); + sig_uncatch(sig_term); + sig_uncatch(sig_pipe); + + if (fcntl(sslctl[1],F_SETFD,0) == -1) + logmsg(WHO,111,FATAL,"unable to clear close-on-exec flag"); + strnum[fmt_ulong(strnum,sslctl[1])] = 0; + env("SSLCTLFD",strnum); + + if (fcntl(pi[0],F_SETFD,0) == -1) + logmsg(WHO,111,FATAL,"unable to clear close-on-exec flag"); + strnum[fmt_ulong(strnum,pi[0])] = 0; + env("SSLREADFD",strnum); + + if (fcntl(po[1],F_SETFD,0) == -1) + logmsg(WHO,111,FATAL,"unable to clear close-on-exec flag"); + strnum[fmt_ulong(strnum,po[1])] = 0; + env("SSLWRITEFD",strnum); + + if (flagsslwait) { + if (fd_copy(0,t) == -1) + logmsg(WHO,111,FATAL,"unable to set up descriptor 0"); + if (fd_copy(1,t) == -1) + logmsg(WHO,111,FATAL,"unable to set up descriptor 1"); + } else { + if (fd_move(0,pi[0]) == -1) + logmsg(WHO,111,FATAL,"unable to set up descriptor 0"); + if (fd_move(1,po[1]) == -1) + logmsg(WHO,111,FATAL,"unable to set up descriptor 1"); + } + + if (flagkillopts) + socket_ipoptionskill(t); + + if (!flagdelay) + socket_tcpnodelay(t); + + if (*banner) { + buffer_init(&bo,buffer_unixwrite,1,bspace,sizeof(bspace)); + if (buffer_putsflush(&bo,banner) == -1) + logmsg(WHO,111,FATAL,"unable to print banner"); + } + + if (!flagsslwait) { + ssl_cmd = flagsslenv ? 'Y' : 'y'; + if (write(sslctl[1],&ssl_cmd,1) < 1) + logmsg(WHO,111,FATAL,"unable to start TLS"); + if (flagsslenv) { + while ((j = read(sslctl[1],envbuf,8192)) > 0) { + stralloc_catb(&ssl_env,envbuf,j); + if (ssl_env.len >= 2 && ssl_env.s[ssl_env.len - 2] == 0 && ssl_env.s[ssl_env.len - 1] == 0) + break; + } + if (j < 0) + logmsg(WHO,111,FATAL,"unable to read TLS environment"); + pathexec_multienv(&ssl_env); + } + } + + pathexec(prog); + logmsg(WHO,111,FATAL,B("unable to run: ",*prog)); +} + +/* ---------------------------- parent */ + +void usage(void) +{ + logmsg(WHO,100,USAGE,"sslserver \ +[ -1346UXpPhHrRoOdDqQvVIeEsSnNmzZ ] \ +[ -c limit ] \ +[ -y iprules.cdb ] \ +[ -x rules.cdb ] \ +[ -B banner ] \ +[ -g gid ] \ +[ -u uid ] \ +[ -b backlog ] \ +[ -l localname ] \ +[ -t timeout ] \ +[ -I interface ] \ +[ -T ssltimeout ] \ +[ -w progtimeout ] \ +host port program"); +} + +int flag1 = 0; +int flag3 = 0; +unsigned long backlog = 20; + +void printstatus(void) +{ + if (verbosity < 2) return; + strnum[fmt_ulong(strnum,numchildren)] = 0; + strnum2[fmt_ulong(strnum2,limit)] = 0; + strnum3[fmt_ulong(strnum3,maxconip)] = 0; + log_who(WHO,B("status: ",strnum,"/",strnum2,"/",strnum3)); +} + +void sigterm(void) +{ + _exit(0); +} + +void sigchld(void) +{ + int wstat; + int pid; + + while ((pid = wait_nohang(&wstat)) > 0) { + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,pid + 1)] = 0; + strnum2[fmt_ulong(strnum2,wstat)] = 0; + log_who(WHO,B("ended by ",strnum," status ",strnum2)); + } + if (maxconip) ipchild_clear(remoteip); + if (numchildren) --numchildren; + printstatus(); + } +} + +void read_passwd(void) { + if (!password.len) { + buffer_init(&bo,buffer_unixread,3,bspace,sizeof(bspace)); + if (getln(&bo,&password,&match,'\0') == -1) + logmsg(WHO,111,ERROR,"unable to read password"); + close(3); + if (match) --password.len; + } +} + +int passwd_cb(char *buff,int size,int rwflag,void *userdata) { + if (size < password.len) + logmsg(WHO,111,ERROR,"password too long"); + + byte_copy(buff,password.len,password.s); + return password.len; +} + +int main(int argc,char * const *argv) { + int opt; + struct servent *se; + char *x; + unsigned long u = 0; + int j; + int s; + int t; + int ipflag = 0; + + while ((opt = getopt(argc,argv,"1346dDvVqQhHrRUXx:y:t:T:u:g:l:b:B:c:pPoOIEeSsw:nNzZm")) != opteof) + switch(opt) { + case 'b': scan_ulong(optarg,&backlog); break; + case 'c': scan_ulong(optarg,&limit); break; + case 'X': flagallownorules = 1; break; + case 'x': fnrules = optarg; break; + case 'y': fniprules = optarg; break; + case 'B': banner = optarg; break; + case 'd': flagdelay = 1; break; + case 'D': flagdelay = 0; break; + case 'v': verbosity = 2; break; + case 'V': verbosity = 3; break; + case 'q': verbosity = 0; break; + case 'Q': verbosity = 1; break; + case 'P': flagparanoid = 0; break; + case 'p': flagparanoid = 1; break; + case 'O': flagkillopts = 1; break; + case 'o': flagkillopts = 0; break; + case 'H': flagremotehost = 0; break; + case 'h': flagremotehost = 1; break; + case 'R': flagremoteinfo = 0; break; + case 'r': flagremoteinfo = 1; break; + case 't': scan_ulong(optarg,&timeout); break; + case 'T': scan_ulong(optarg,&ssltimeout); break; + case 'w': scan_uint(optarg,&progtimeout); break; + case 'U': x = env_get("UID"); if (x) scan_ulong(x,&uid); + x = env_get("GID"); if (x) scan_ulong(x,&gid); break; + case 'u': scan_ulong(optarg,&uid); break; + case 'g': scan_ulong(optarg,&gid); break; + case 'I': netif = socket_getifidx(optarg); break; + case 'l': localhost = optarg; break; + case '1': flag1 = 1; break; + case '3': flag3 = 1; break; + case '4': ipflag = 1; break; + case '6': ipflag = 2; break; + case 'Z': flagclientcert = 0; break; + case 'z': flagclientcert = 1; break; + case 'm': flagclientcert = 2; break; + case 'S': flagsslenv = 0; break; + case 's': flagsslenv = 1; break; + case 'E': flagtcpenv = 0; break; + case 'e': flagtcpenv = 1; break; + case 'n': flagsslwait = 1; break; + case 'N': flagsslwait = 0; break; + default: usage(); + } + argc -= optind; + argv += optind; + + if (!verbosity) buffer_2->fd = -1; + + hostname = *argv++; + if (!hostname || (str_equal((char *)hostname,""))) usage(); + if (str_equal((char *)hostname,"0")) hostname = thishost; + else if (str_equal((char *)hostname,":0")) { + flagdualstack = 1; + hostname = "::"; + } + + x = *argv++; + if (!x) usage(); + prog = argv; + if (!*argv) usage(); + if (!x[scan_ulong(x,&u)]) + localport = u; + else { + se = getservbyname(x,"tcp"); + if (!se) + logmsg(WHO,111,FATAL,B("unable to figure out port number for: ",x)); + uint16_unpack_big((char *)&se->s_port,&localport); + } + + if ((x = env_get("MAXCONIP"))) { scan_ulong(x,&u); maxconip = u; } + if (limit && maxconip > limit) maxconip = limit; + if (!child_readyplus(&children,limit)) drop_nomem(); + + if ((x = env_get("VERIFYDEPTH"))) { scan_ulong(x,&u); verifydepth = u; } + + if ((x = env_get("CAFILE"))) cafile = x; + if (cafile && str_equal((char *)cafile,"")) cafile = 0; + + if ((x = env_get("CCAFILE"))) ccafile = x; + if (ccafile && str_equal((char *)ccafile,"")) ccafile = 0; + if (ccafile && str_equal((char*)ccafile,"-")) flagclientcert = 0; + if (!flagclientcert) ccafile = 0; + + if ((x = env_get("CADIR"))) cadir = x; + if (cadir && str_equal((char *)cadir,"")) cadir= 0; + + if ((x = env_get("CERTCHAINFILE"))) certchainfile = x; + if (certchainfile && str_equal((char *)certchainfile,"")) certchainfile = 0; + + if ((x = env_get("CERTFILE"))) certfile = x; + if (certfile && str_equal((char *)certfile,"")) certfile = 0; + + if ((x = env_get("KEYFILE"))) keyfile = x; + if (keyfile && str_equal((char *)keyfile,"")) keyfile = 0; + + if ((x = env_get("DHFILE"))) dhfile = x; + if (dhfile && str_equal((char *)dhfile,"")) dhfile = 0; + + if ((x = env_get("CIPHERS"))) ciphers = x; + if (ciphers && str_equal((char *)ciphers,"")) ciphers = 0; + + sig_block(sig_child); + sig_catch(sig_child,sigchld); + sig_catch(sig_term,sigterm); + sig_ignore(sig_pipe); + + /* IP address only */ + + if (ip4_scan(hostname,localip)) { + if (!stralloc_copyb(&addresses,(char *)V4mappedprefix,12)) drop_nomem(); + if (!stralloc_catb(&addresses,localip,4)) drop_nomem(); + byte_copy(localip,16,addresses.s); + } else if (ip6_scan(hostname,localip)) { + if (!stralloc_copyb(&addresses,localip,16)) drop_nomem(); + byte_copy(localip,16,addresses.s); + } + + /* Asynchronous DNS IPv4/IPv6 Name qualification */ + + if (!addresses.len) { + if (!stralloc_copys(&tmp,hostname)) drop_nomem(); + if (dns_ip_qualify(&addresses,&fqdn,&tmp) < 0) + logmsg(WHO,111,FATAL,B("temporarily unable to figure out IP address for: ",(char *)hostname)); + + byte_copy(localip,16,addresses.s); + + for (j = 0; j < addresses.len; j += 16) { // Select best matching IP address + if (ipflag == 1 && !ip6_isv4mapped(addresses.s + j)) continue; + if (ipflag == 2 && !ip6_isv4mapped(addresses.s + j)) continue; + byte_copy(localip,16,addresses.s + j); + } + + } + if (addresses.len < 16) + logmsg(WHO,111,FATAL,B("no IP address for: ",(char *)hostname)); + + if (ip6_isv4mapped(localip)) + s = socket_tcp4(); + else + s = socket_tcp6(); + if (s == -1) + logmsg(WHO,111,FATAL,"unable to create socket"); + + if (ip6_isv4mapped(localip)) + localipstr[ip4_fmt(localipstr,localip + 12)] = 0; + else + localipstr[ip6_fmt(localipstr,localip)] = 0; + localportstr[fmt_ulong(localportstr,localport)] = 0; + + if (flagdualstack) + socket_dualstack(s); + if (socket_bind_reuse(s,localip,localport,netif) == -1) + logmsg(WHO,111,FATAL,B("unable to bind to: ",localipstr," port: ",localportstr)); + if (socket_local(s,localip,&localport,&netif) == -1) + logmsg(WHO,111,FATAL,B("unable to set local address/port: ",localipstr,"/",localportstr)); + if (socket_listen(s,backlog) == -1) + logmsg(WHO,111,FATAL,"unable to listen"); + ndelay_off(s); + + if (flag1) { + buffer_init(&bo,write,1,bspace,sizeof(bspace)); + buffer_puts(&bo,localipstr); + buffer_puts(&bo," : "); + buffer_puts(&bo,localportstr); + buffer_puts(&bo,"\n"); + buffer_flush(&bo); + } + + if (flag3) read_passwd(); + + ctx = ssl_server(); + ssl_errstr(); + if (!ctx) logmsg(WHO,111,FATAL,"unable to create TLS context"); + + if (certchainfile) { + switch (ssl_chainfile(ctx,certchainfile,keyfile,passwd_cb)) { + case -1: logmsg(WHO,111,ERROR,"unable to load certificate chain file"); + case -2: logmsg(WHO,111,ERROR,"unable to load key"); + case -3: logmsg(WHO,111,ERROR,"key does not match certificate"); + default: break; + } + } else { + switch (ssl_certkey(ctx,certfile,keyfile,passwd_cb)) { + case -1: logmsg(WHO,111,ERROR,"unable to load certificate"); + case -2: logmsg(WHO,111,ERROR,"unable to load key"); + case -3: logmsg(WHO,111,ERROR,"key does not match certificate"); + default: break; + } + } + + if (flagclientcert && !ssl_ca(ctx,cafile,cadir,verifydepth)) + logmsg(WHO,111,ERROR,"unable to load CA list"); + if (!ssl_cca(ctx,ccafile)) + logmsg(WHO,111,ERROR,"unable to load client CA list"); + if (!ssl_params_rsa(ctx,rsalen)) + logmsg(WHO,111,ERROR,"unable to set RSA parameters"); + if (!ssl_params_dh(ctx,dhfile)) + logmsg(WHO,111,ERROR,"unable to set DH parameters"); + if (!ssl_ciphers(ctx,ciphers)) + logmsg(WHO,111,ERROR,"unable to set cipher list"); + + if (verbosity >= 2) { + strnum[fmt_ulong(strnum,getpid())] = 0; + strnum2[fmt_ulong(strnum2,rsalen)] = 0; + log_who(WHO,B("ciphers ",strnum," ",(char *)ciphers)); + log_who(WHO,B("cafile ",strnum," ",(char *)cafile)); + log_who(WHO,B("ccafile ",strnum," ",(char *)ccafile)); + log_who(WHO,B("cadir ",strnum," ",(char *)cadir)); + log_who(WHO,B("certchainfile ",strnum," ",(char *)certchainfile)); + log_who(WHO,B("cert ",strnum," ",(char *)certfile)); + log_who(WHO,B("key ",strnum," ",(char *)keyfile)); + log_who(WHO,B("dhparam ",strnum," ",(char *)dhfile," ",strnum2)); + } + + close(0); open_read("/dev/null"); + close(1); open_append("/dev/null"); + + printstatus(); + + for (;;) { + while (numchildren >= limit) sig_pause(); + strnum[fmt_ulong(x,numchildren)] = 0; + + sig_unblock(sig_child); + t = socket_accept(s,remoteip,&remoteport,&netif); + sig_block(sig_child); + if (t == -1) continue; + + if (maxconip) { + ipchildren = ipchild_limit(remoteip,numchildren); + if (ipchildren >= maxconip) { + if (ip6_isv4mapped(remoteip)) + remoteipstr[ip4_fmt(remoteipstr,remoteip + 12)] = 0; + else + remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0; + + strnum[fmt_ulong(strnum,maxconip)] = 0; + logmsg(WHO,100,WARN,B("ip connection limit of ",strnum," exceeded for: ",remoteipstr)); + close(t); + continue; + } + ipchild_append(remoteip,numchildren); // needs to happen in parent + } + ++numchildren; + printstatus(); + + switch (fork()) { + case 0: + close(s); + doit(t); + logmsg(WHO,111,FATAL,B("unable to run: ",*argv)); + case -1: + if (maxconip) ipchild_clear(remoteip); --numchildren; + logmsg(WHO,111,FATAL,B("unable to fork: ",strnum)); + } + close(t); + } +} diff --git a/src/trycpp.c b/src/trycpp.c new file mode 100644 index 0000000..e4503d4 --- /dev/null +++ b/src/trycpp.c @@ -0,0 +1,9 @@ +/* Public domain. */ + +int main() +{ +#ifdef NeXT + printf("nextstep\n"); exit(0); +#endif + printf("unknown\n"); exit(0); +} diff --git a/src/trylsock.c b/src/trylsock.c new file mode 100644 index 0000000..c32bd40 --- /dev/null +++ b/src/trylsock.c @@ -0,0 +1,4 @@ +int main() +{ + ; +} diff --git a/src/trysgact.c b/src/trysgact.c new file mode 100644 index 0000000..e264ef2 --- /dev/null +++ b/src/trysgact.c @@ -0,0 +1,12 @@ +/* Public domain. */ + +#include <signal.h> + +main() +{ + struct sigaction sa; + sa.sa_handler = 0; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(0,&sa,(struct sigaction *) 0); +} diff --git a/src/trysgprm.c b/src/trysgprm.c new file mode 100644 index 0000000..a46c82c --- /dev/null +++ b/src/trysgprm.c @@ -0,0 +1,12 @@ +/* Public domain. */ + +#include <signal.h> + +main() +{ + sigset_t ss; + + sigemptyset(&ss); + sigaddset(&ss,SIGCHLD); + sigprocmask(SIG_SETMASK,&ss,(sigset_t *) 0); +} diff --git a/src/tryshsgr.c b/src/tryshsgr.c new file mode 100644 index 0000000..c5ed6d6 --- /dev/null +++ b/src/tryshsgr.c @@ -0,0 +1,16 @@ +/* Public domain. */ + +int main() +{ + short x[4]; + + x[0] = x[1] = 1; + if (getgroups(1,x) == 0) if (setgroups(1,x) == -1) _exit(1); + + if (getgroups(1,x) == -1) _exit(1); + if (x[1] != 1) _exit(1); + x[1] = 2; + if (getgroups(1,x) == -1) _exit(1); + if (x[1] != 2) _exit(1); + _exit(0); +} diff --git a/src/tryssl.c b/src/tryssl.c new file mode 100644 index 0000000..81dc4d1 --- /dev/null +++ b/src/tryssl.c @@ -0,0 +1,6 @@ +#include <openssl/ssl.h> + +int main() +{ + ; +} diff --git a/src/trysysel.c b/src/trysysel.c new file mode 100644 index 0000000..5be862d --- /dev/null +++ b/src/trysysel.c @@ -0,0 +1,11 @@ +/* Public domain. */ + +#include <sys/types.h> +#include <time.h> +#include <sys/time.h> +#include <sys/select.h> /* SVR4 silliness */ + +void foo() +{ + ; +} diff --git a/src/tryvfork.c b/src/tryvfork.c new file mode 100644 index 0000000..cc39699 --- /dev/null +++ b/src/tryvfork.c @@ -0,0 +1,4 @@ +main() +{ + vfork(); +} diff --git a/src/ucspissl.c b/src/ucspissl.c new file mode 100644 index 0000000..3cbd8b4 --- /dev/null +++ b/src/ucspissl.c @@ -0,0 +1,4 @@ +#include "ucspissl.h" + +int ssl_errno = 0; + diff --git a/src/ucspissl.h b/src/ucspissl.h new file mode 100644 index 0000000..5243689 --- /dev/null +++ b/src/ucspissl.h @@ -0,0 +1,70 @@ +/** + @file ucspissl.h + @author web, feh + @brief Header file to be used with sqmail; previously called ssl.h. (name clash) + + All OpenSSL/LibreSSL header files are called from here +*/ +#ifndef UCSPISSL_H +#define UCSPISSL_H + +#include "openssl/asn1.h" +#include "openssl/ec.h" +#include "openssl/err.h" +#include "openssl/evp.h" +#include "openssl/ssl.h" +#include "openssl/pem.h" +#include "openssl/rsa.h" +#include "openssl/opensslv.h" +#include "openssl/safestack.h" +#include "openssl/x509.h" +#include "openssl/x509v3.h" +#include "stralloc.h" + +#define SSLv2_DISABLE +#define SSLv3_DISABLE +// #define TLSv1_DISABLE +// #define TLSv1_1_DISABLE +// #define TLSv1_2_DISABLE +// #define TLSv1_3_DISABLE + +#define SSL_NAME_LEN 256 +#define SSL_RSA_LEN 4096 + +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) // 0xmnnffppsL +#define ssl_client() (ssl_context(SSLv23_client_method())) +#define ssl_server() (ssl_context(SSLv23_server_method())) +#else +#define ssl_client() (ssl_context(TLS_client_method())) +#define ssl_server() (ssl_context(TLS_server_method())) +#endif + +extern int ssl_errno; +extern int ssl_io(SSL *,int,int,unsigned int); +extern SSL_CTX *ssl_context(const SSL_METHOD *); +extern int ssl_timeoutconn(SSL *,unsigned int); +extern int ssl_timeoutaccept(SSL *,unsigned int); +extern SSL *ssl_new(SSL_CTX *,int); +extern int ssl_certkey(SSL_CTX *,const char *,const char *,pem_password_cb *); +extern int ssl_chainfile(SSL_CTX *,const char *,const char *,pem_password_cb *); +extern int ssl_ca(SSL_CTX *,const char *,const char *,int); +extern int ssl_cca(SSL_CTX *,const char *); +extern int ssl_ciphers(SSL_CTX *,const char *); +extern int ssl_verify(SSL *,const char *,stralloc *); +extern int ssl_params_rsa(SSL_CTX *,int); +extern int ssl_params_dh(SSL_CTX *,const char *); +extern int ssl_server_env(SSL *,stralloc *); +extern int ssl_client_env(SSL *,stralloc *); +extern int ssl_error(int (*)(const char *)); +extern char *ssl_error_str(int); + +#define ssl_errstr() (SSL_load_error_strings()) +#define ssl_free(ssl) (SSL_free((ssl))) +#define ssl_close(ssl) (close(SSL_get_fd((ssl)))) + +#define ssl_pending(ssl) (SSL_pending((ssl))) +#define ssl_shutdown(ssl) (SSL_shutdown((ssl))) +#define ssl_shutdown_pending(ssl) (SSL_get_shutdown((ssl)) & SSL_RECEIVED_SHUTDOWN) +#define ssl_shutdown_sent(ssl) (SSL_get_shutdown((ssl)) & SSL_SENT_SHUTDOWN) + +#endif diff --git a/src/warn-auto.sh b/src/warn-auto.sh new file mode 100644 index 0000000..36d2313 --- /dev/null +++ b/src/warn-auto.sh @@ -0,0 +1,2 @@ +#!/bin/sh +# WARNING: This file was auto-generated. Do not edit! diff --git a/src/warn-shsgr b/src/warn-shsgr new file mode 100644 index 0000000..37c351e --- /dev/null +++ b/src/warn-shsgr @@ -0,0 +1,3 @@ +Oops. Your getgroups() returned 0, and setgroups() failed; this means +that I can't reliably do my shsgr test. Please either ``make'' as root +or ``make'' while you're in one or more supplementary groups. diff --git a/src/x86cpuid.c b/src/x86cpuid.c new file mode 100644 index 0000000..f81c593 --- /dev/null +++ b/src/x86cpuid.c @@ -0,0 +1,40 @@ +/* Public domain. */ + +#include <signal.h> + +void nope() +{ + exit(1); +} + +int main() +{ + unsigned long x[4]; + unsigned long y[4]; + int i; + int j; + char c; + + signal(SIGILL,nope); + + x[0] = 0; + x[1] = 0; + x[2] = 0; + x[3] = 0; + + asm volatile(".byte 15;.byte 162" : "=a"(x[0]),"=b"(x[1]),"=c"(x[3]),"=d"(x[2]) : "0"(0) ); + if (!x[0]) return 0; + asm volatile(".byte 15;.byte 162" : "=a"(y[0]),"=b"(y[1]),"=c"(y[2]),"=d"(y[3]) : "0"(1) ); + + for (i = 1;i < 4;++i) + for (j = 0;j < 4;++j) { + c = x[i] >> (8 * j); + if (c < 32) c = 32; + if (c > 126) c = 126; + putchar(c); + } + + printf("-%08x-%08x\n",y[0],y[3]); + + return 0; +} |