summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJannis Hoffmann <jannis@fehcom.de>2024-07-14 21:28:19 +0200
committerJannis Hoffmann <jannis@fehcom.de>2024-07-14 21:28:19 +0200
commit1087d4df2a7342d2832ba3bab1843bf4a3040775 (patch)
tree96cd6ea198cc542f29c0660d5e5f7083af84d711
add version 0.12.10HEADmaster
-rw-r--r--INSTALL123
-rw-r--r--README.md48
-rw-r--r--conf-cadir4
-rw-r--r--conf-cafile3
-rw-r--r--conf-cc3
-rw-r--r--conf-ccafile3
-rw-r--r--conf-ccperl7
-rw-r--r--conf-certchainfile3
-rw-r--r--conf-certfile3
-rw-r--r--conf-ciphers16
-rw-r--r--conf-dhfile7
-rw-r--r--conf-home4
-rw-r--r--conf-keyfile3
-rw-r--r--conf-ld4
-rw-r--r--conf-ldperl7
-rw-r--r--conf-man4
-rw-r--r--conf-perl3
-rw-r--r--conf-qlibs3
-rw-r--r--conf-rsa3
-rw-r--r--conf-ssl12
-rw-r--r--conf-ssllib11
-rw-r--r--doc/CHAIN-SSL54
-rw-r--r--doc/CHANGES341
-rw-r--r--doc/LICENSE70
-rwxr-xr-xdoc/README.rts78
-rw-r--r--doc/TLSVERSION_CIPHERSUITES62
-rw-r--r--doc/TLS_1_336
-rw-r--r--doc/TODO7
-rw-r--r--doc/UCSPI-SSL48
-rw-r--r--etc/127.0.0.1.pwbin0 -> 9 bytes
-rw-r--r--etc/127.0.0.1_cert.pem17
-rw-r--r--etc/127.0.0.1_key.pem8
-rw-r--r--etc/127.0.0.1_key.pem.plain5
-rw-r--r--etc/::1.pwbin0 -> 9 bytes
-rw-r--r--etc/::1_cert.pem18
-rw-r--r--etc/::1_key.pem8
-rw-r--r--etc/::1_key.pem.plain5
-rw-r--r--etc/README.certs.md281
-rw-r--r--etc/chain4.pem32
-rw-r--r--etc/chain6.pem33
-rw-r--r--etc/dh2048.pem8
-rw-r--r--etc/localhost.pwbin0 -> 9 bytes
-rw-r--r--etc/localhost_cert.pem18
-rw-r--r--etc/localhost_key.pem8
-rw-r--r--etc/localhost_key.pem.plain5
-rw-r--r--etc/rootCA_cert.pem15
-rw-r--r--man/Makefile44
-rw-r--r--man/Makefile.mandoc44
-rw-r--r--man/TARGETS7
-rw-r--r--man/https@.157
-rw-r--r--man/sslcat.148
-rw-r--r--man/sslclient.1254
-rw-r--r--man/sslconnect.155
-rw-r--r--man/sslhandle.1578
-rw-r--r--man/sslserver.1657
-rw-r--r--man/ucspi-tls.261
-rw-r--r--package/build1
-rw-r--r--package/command-cp3
-rw-r--r--package/command-ln4
-rw-r--r--package/commands-base7
-rw-r--r--package/commands-sslperl1
-rw-r--r--package/commands-sys1
-rwxr-xr-xpackage/compile88
-rw-r--r--package/files164
-rwxr-xr-xpackage/install5
-rwxr-xr-xpackage/man125
-rw-r--r--package/path1
-rwxr-xr-xpackage/report10
-rwxr-xr-xpackage/rts76
-rwxr-xr-xpackage/run2
-rwxr-xr-xpackage/upgrade109
-rw-r--r--package/version1
-rw-r--r--src/Makefile351
-rw-r--r--src/TARGETS62
-rw-r--r--src/auto-str.c42
-rw-r--r--src/auto_cadir.h6
-rw-r--r--src/auto_cafile.h6
-rw-r--r--src/auto_ccafile.h6
-rw-r--r--src/auto_certchainfile.h6
-rw-r--r--src/auto_certfile.h6
-rw-r--r--src/auto_ciphers.h6
-rw-r--r--src/auto_dhfile.h6
-rw-r--r--src/auto_keyfile.h6
-rw-r--r--src/chkshsgr.c14
-rw-r--r--src/choose.sh18
-rw-r--r--src/coe.c9
-rw-r--r--src/coe.h8
-rw-r--r--src/exit.h6
-rw-r--r--src/exp.base325
-rw-r--r--src/exp.it0
-rw-r--r--src/exp.sslperl105
-rw-r--r--src/find-systype.sh151
-rw-r--r--src/fork.h19
-rw-r--r--src/fork.h29
-rw-r--r--src/hassgact.h13
-rw-r--r--src/hassgact.h24
-rw-r--r--src/hassgprm.h13
-rw-r--r--src/hassgprm.h24
-rw-r--r--src/hasshsgr.h13
-rw-r--r--src/hasshsgr.h24
-rw-r--r--src/haswaitp.h13
-rw-r--r--src/haswaitp.h24
-rw-r--r--src/https@.sh15
-rw-r--r--src/ip4_bit.c101
-rw-r--r--src/ip6_bit.c180
-rw-r--r--src/ip_bit.h15
-rw-r--r--src/it-base=d7
-rw-r--r--src/it-sslperl=d1
-rw-r--r--src/it-sys=d1
-rw-r--r--src/it=d1
-rw-r--r--src/print-ar.sh14
-rw-r--r--src/print-cc.sh62
-rw-r--r--src/print-ccperl.sh10
-rw-r--r--src/print-dl.sh14
-rw-r--r--src/print-ld.sh18
-rw-r--r--src/print-ldperl.sh10
-rw-r--r--src/print-perlembed.sh10
-rw-r--r--src/remoteinfo.c102
-rw-r--r--src/remoteinfo.h9
-rw-r--r--src/rts.base329
-rw-r--r--src/rts.it197
-rw-r--r--src/rts.sslperl157
-rw-r--r--src/rules.c141
-rw-r--r--src/rules.h9
-rw-r--r--src/select.h112
-rw-r--r--src/select.h213
-rw-r--r--src/ssl_ca.c11
-rw-r--r--src/ssl_cca.c18
-rw-r--r--src/ssl_certkey.c19
-rw-r--r--src/ssl_chainfile.c24
-rw-r--r--src/ssl_ciphers.c21
-rw-r--r--src/ssl_context.c34
-rw-r--r--src/ssl_env.c435
-rw-r--r--src/ssl_error.c12
-rw-r--r--src/ssl_io.c269
-rw-r--r--src/ssl_new.c16
-rw-r--r--src/ssl_params.c80
-rw-r--r--src/ssl_timeout.c125
-rw-r--r--src/ssl_verify.c63
-rw-r--r--src/sslcat.sh9
-rw-r--r--src/sslclient.c449
-rw-r--r--src/sslconnect.sh9
-rw-r--r--src/sslhandle.c887
-rw-r--r--src/sslperl.c105
-rw-r--r--src/sslprint.c411
-rw-r--r--src/sslserver.c991
-rw-r--r--src/trycpp.c9
-rw-r--r--src/trylsock.c4
-rw-r--r--src/trysgact.c12
-rw-r--r--src/trysgprm.c12
-rw-r--r--src/tryshsgr.c16
-rw-r--r--src/tryssl.c6
-rw-r--r--src/trysysel.c11
-rw-r--r--src/tryvfork.c4
-rw-r--r--src/ucspissl.c4
-rw-r--r--src/ucspissl.h70
-rw-r--r--src/warn-auto.sh2
-rw-r--r--src/warn-shsgr3
-rw-r--r--src/x86cpuid.c40
159 files changed, 10628 insertions, 0 deletions
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..5630cf6
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,123 @@
+Installation supplements
+------------------------
+
+Caution: You need to have fehQlibs installed!
+
+Within the ./src directory you find some conf-* files for your adjustments:
+
+1. Customization
+- conf-man (man page target) => /usr/share/man
+
+2. Compilation - files are autogenerated
+- conf-cc (don't need to be touched)
+- conf-ccperl (no adjustments required)
+- conf-ldperl (no adjustments required)
+
+Note: The current version detects the AMD64 environment
+and the possible support for dynamic load libraries.
+
+3. Installation dependencies & default - autogenerated
+- conf-qlibs (the fehQlibs install directory; default: /usr/local/qlibs)
+- conf-perl (no adjustments required)
+- conf-ssl (default; add path to inlcude alternative or additional openssl header file)
+- conf-ssllib (default; the cryto libs to include)
+
+ Note: If you installed OpenSSL 1.1.1b at /usr/local customizations are included as sample.
+
+4. Certificate and key file handling -- these are parms declared for each server; thus may stay empty/untouched.
+ Default values MAY be provided as:
+- conf-cafile
+- conf-ccafile
+- conf-certfile
+- conf-certchainfile
+- conf-ciphers (a current sample is provided, but not active)
+- conf-dhfile (you may use the 'dh2048.pem' in ucspi-ssl's ./etc dir)
+- conf-keyfile
+
+5. Installation procedure
+ Usually, you just install the package with
+
+- package/install
+
+or -- in case the Perl install failes --
+
+- package/install base
+(- package/man)
+
+6. Testing
+- package/rts -- or --
+- package/rts base (if Perl is not installed/working).
+
+ The etc/ directory includes some X.509 certs and keyfiles
+ for testing. Have a look at those !
+
+7. ucspi-tcp dependencies
+ The vanilla ucspi-tcp-0.88 package from Dan Bernstein does not support
+ building 'tcprules' with CIDR support.
+
+ Download and install 'ucspi-tcp6' from
+ http://www.fehcom.de/ipnet/ucspi-tcp6.html.
+
+8. Compatibility
+ This version has been successfully tested against:
+
+- OpenSSL 1.0.2j, 1.1.0c, 1.1.1b-s, 1.1.1t,
+ 3.0.0, 3.0.7, 3.1.0, 3.1.3, 3.2.0-alpha2
+- LibreSSL 2.5.4, 2.6.0, 2.7.0, 2.9.1
+ 3.6.0, 3.7.0, 3.7.2
+
+ Other intermittend releases are expected to work as well.
+
+ You can sucessfully use ucspi-ssl with 'foreign' *SSL installations.
+ Apart from the header files used open compilation, the execution
+ requires a tailored LD_LIBRARY_PATH pointing to the *SSL libs.
+ This can be done in the run script calling ie. sslserver together
+ with the application. Otherwise, the ssl* modules will always
+ use the default libraries; which may not work.
+ See src/rts.it for a sample given LibreSSL.
+
+
+9. LibreSSL
+ LibreSSL has has different understanding of
+
+- how to work with CIPHER_SUITES and
+- how to use the 'libssl' and 'libcrypto'.
+
+ libssl and libcrypto are enumerated (eg. libssl.so.52).
+ In case you are building ucspi-ssl based on static libs,
+ you need to do the following in the LibreSSL dir:
+
+- ln -s ssl/.libs/libssl.a .
+- ln -s crypto/.libs/libcrypto.a .
+
+10. OpenSSL 3.0/3.1/3.2
+ OpenSSL have changed their APIs significantly.
+ The current ucspi-ssl includes deprecated calls:
+ - RSA_new(), RSA_generate_key_ex(), RSA_free()
+ - PEM_read_bio_DHparams(), EC_KEY_new_by_curve_name(), EC_KEY_free()
+
+ In case you install openssl-3.x.y, you not only need to
+ - modify conf-ssl and conf-ssllib
+ but also to inlude libssl.so.3 in your library path:
+ (1) export LD_LIBRARY_PATH=<path>/opensssl-3.x.y
+ (2) include that path to your standard lib path or
+ (3) copy libssl.so.3 to your standard lib path.
+
+ A check would show the statically linked OpenSSL libs like this:
+
+ $ export LD_LIBRARY_PATH=/home/ucspi/_SSL/openssl-3.0.7
+
+ $ ldd sslserver
+
+ sslserver:
+ libssl.so.3 => /home/ucspi/_SSL/openssl-3.0.7/libssl.so.3 (0x800260000)
+ libcrypto.so.3 => /home/ucspi/_SSL/openssl-3.0.7/libcrypto.so.3 (0x80030b000)
+ libc.so.7 => /lib/libc.so.7 (0x800745000)
+ libthr.so.3 => /lib/libthr.so.3 (0x800b4f000)
+
+ Verify everything is working while perfoming the tests:
+
+- package/rts !!
+
+Erwin Hoffmann, October 2023
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e983f25
--- /dev/null
+++ b/README.md
@@ -0,0 +1,48 @@
+/*! \mainpage
+
+ucspi-ssl-0.12
+==============
+
+ucspi-ssl is a joined project of William Baxter
+(Copyright 2001 SuperScript Technology, Inc.) and me (FEHCom).
+
+ucspi-ssl home page
+-------------------
+
+- https://www.superscript.com/
+- https://www.fehcom.de/ipnet/ucspi-ssl.html
+
+Requirements
+------------
+
+- OpenSSL or LibreSSL providing crypto services.
+- fehQlibs(>=17) need to be installed (usually located at /usr/local)
+ for network and DNS services.
+
+Installation and Customization
+------------------------------
+
+- Read INSTALL for installation instructions.
+- Read doc/CERTS for the X.509 certificates shipped.
+- Read doc/CHAIN-SSL how to configure X.509 chaining support.
+
+Changelog and Internals
+-----------------------
+
+- Read doc/CHANGES for changes and bug fixes.
+- Read doc/UCSPI-SSL to find some internal information.
+- Read doc/TLS_1_3 how to use an OpenSSL/LibreSSL version providing TLS 1.3 support.
+- Read doc/TLSVERSION_CIPHERSUITES how to tweak TLS version and cipher suites.
+- Read doc/TODO what is missing still.
+- Read INSTALL if you like to use ucspi-ssl with OpenSSL 3.x exceptionally.
+
+Cryptomaterial and X.509 certs
+------------------------------
+
+- In the directory ./etc you will find some X.509 certificate, key files
+ and other crypto material required for a first setup.
+- All X.509 certificates use now ECC crypto instead of RSA.
+- Read etc/README.certs.md.
+
+
+Erwin Hoffmann, October 2023.
diff --git a/conf-cadir b/conf-cadir
new file mode 100644
index 0000000..80d386a
--- /dev/null
+++ b/conf-cadir
@@ -0,0 +1,4 @@
+/usr/local/ssl/certs
+
+# This is the ucspi-ssl CA directory.
+# An empty name means no certificate directory is compiled in.
diff --git a/conf-cafile b/conf-cafile
new file mode 100644
index 0000000..f8d31bd
--- /dev/null
+++ b/conf-cafile
@@ -0,0 +1,3 @@
+
+# This is the ucspi-ssl CA file.
+# An empty name means no certificate file is compiled in.
diff --git a/conf-cc b/conf-cc
new file mode 100644
index 0000000..24b6cfd
--- /dev/null
+++ b/conf-cc
@@ -0,0 +1,3 @@
+cc -O2 -g -Wall
+
+# This will be used to compile .c files.
diff --git a/conf-ccafile b/conf-ccafile
new file mode 100644
index 0000000..d0ab55b
--- /dev/null
+++ b/conf-ccafile
@@ -0,0 +1,3 @@
+
+# This is the ucspi-ssl client CA file.
+# An empty name means no client certificate file is compiled in.
diff --git a/conf-ccperl b/conf-ccperl
new file mode 100644
index 0000000..e411971
--- /dev/null
+++ b/conf-ccperl
@@ -0,0 +1,7 @@
+auto
+
+# The compiler arguments required for sslperl.
+# All arguments must appear on a single line.
+# If the word "auto" appears, use the output from
+
+#=> `head -1 conf-perl` -MExtUtils::Embed -e ccopts
diff --git a/conf-certchainfile b/conf-certchainfile
new file mode 100644
index 0000000..fcb6825
--- /dev/null
+++ b/conf-certchainfile
@@ -0,0 +1,3 @@
+
+# This is the sslserver certificate file.
+# An empty name means no certificate file is compiled in.
diff --git a/conf-certfile b/conf-certfile
new file mode 100644
index 0000000..fcb6825
--- /dev/null
+++ b/conf-certfile
@@ -0,0 +1,3 @@
+
+# This is the sslserver certificate file.
+# An empty name means no certificate file is compiled in.
diff --git a/conf-ciphers b/conf-ciphers
new file mode 100644
index 0000000..c4399d6
--- /dev/null
+++ b/conf-ciphers
@@ -0,0 +1,16 @@
+
+# This is the list of ciphers to use. Sample for TLS < 1.3:
+
+ALL:!EXP:!MD5:!RC4:!ADH:!DES:!3DES:!PSK:!aNULL
+
+# This is the list of ciphers to use. Sample for TLS 1.3:
+
+TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384
+
+Comment:
+
+a) CHACHA20_POLY1305 has preference (hardest to break)
+b) AES_128_GCM comes next (-> GCM is 128 bit only!)
+c) AES_256_GCM is last (AES is mostly HW accelerated)
+
+# An empty name means use the ciphers compiled into openssl.
diff --git a/conf-dhfile b/conf-dhfile
new file mode 100644
index 0000000..19fb6d0
--- /dev/null
+++ b/conf-dhfile
@@ -0,0 +1,7 @@
+/package/host/superscript.com/net/ucspi-ssl/etc/dh1024.pem
+
+# This is ucspi-ssl's DH parameter file.
+
+# /usr/local/ssl/pem/dh1024.pem
+
+# This is OpenSSL's DH default parameter file.
diff --git a/conf-home b/conf-home
new file mode 100644
index 0000000..a68e872
--- /dev/null
+++ b/conf-home
@@ -0,0 +1,4 @@
+/usr/local
+
+This is the ucspi-ssl home directory. Programs will be installed in
+.../bin.
diff --git a/conf-keyfile b/conf-keyfile
new file mode 100644
index 0000000..69f26ed
--- /dev/null
+++ b/conf-keyfile
@@ -0,0 +1,3 @@
+
+# This is the sslserver key file.
+# An empty name means no key file is compiled in.
diff --git a/conf-ld b/conf-ld
new file mode 100644
index 0000000..a01f6d3
--- /dev/null
+++ b/conf-ld
@@ -0,0 +1,4 @@
+cc -s
+
+# This will be used to link .o files into an executable.
+# The '-m64' option will be inclucded automatically.
diff --git a/conf-ldperl b/conf-ldperl
new file mode 100644
index 0000000..83ed11b
--- /dev/null
+++ b/conf-ldperl
@@ -0,0 +1,7 @@
+auto
+
+# The loader arguments required for tcpperl.
+# All arguments must appear on a single line.
+# If the word "auto" appears, use the output from
+
+#=> `head -1 conf-perl` -MExtUtils::Embed -e ldopts
diff --git a/conf-man b/conf-man
new file mode 100644
index 0000000..944b0af
--- /dev/null
+++ b/conf-man
@@ -0,0 +1,4 @@
+
+/usr/share/man
+
+# Directories to install man pages - if no manpath is available
diff --git a/conf-perl b/conf-perl
new file mode 100644
index 0000000..79d4318
--- /dev/null
+++ b/conf-perl
@@ -0,0 +1,3 @@
+perl
+
+# How to run perl when searching for compiler and loader options.
diff --git a/conf-qlibs b/conf-qlibs
new file mode 100644
index 0000000..8d1fd94
--- /dev/null
+++ b/conf-qlibs
@@ -0,0 +1,3 @@
+/usr/local/qlibs
+
+# This is the path to your qlibs directory
diff --git a/conf-rsa b/conf-rsa
new file mode 100644
index 0000000..480a5c9
--- /dev/null
+++ b/conf-rsa
@@ -0,0 +1,3 @@
+2048
+
+# The length of the RSA key
diff --git a/conf-ssl b/conf-ssl
new file mode 100644
index 0000000..3ed85f8
--- /dev/null
+++ b/conf-ssl
@@ -0,0 +1,12 @@
+-I/usr/local/openssl-3.0.7/include/
+
+# using the system default it could stay empty; otherwise check for that
+
+-I/usr/local/openssl-3.0.7/include/
+-I/home/ucspi/_SSL/libressl-3.7.2/include/
+
+-I/usr/kerberos/include
+
+# This will be used to include headers from a different version,
+# or if openssl requires additional support, e.g. kerberos support on RedHat Linux.
+
diff --git a/conf-ssllib b/conf-ssllib
new file mode 100644
index 0000000..0f2cf61
--- /dev/null
+++ b/conf-ssllib
@@ -0,0 +1,11 @@
+-L/usr/local/openssl-3.0.7 -lssl -lcrypto
+
+-lssl -lcrypto
+
+# These are samples for OpenSSL and LibreSSL to be semi-statically linked
+
+-L/home/ucspi/_SSL/libressl-3.7.2/ssl/.libs -L/home/ucspi/_SSL/libressl-3.7.2/crypto/.libs -lssl -lcrypto
+-L/usr/local/openssl-3.0.7 -lssl -lcrypto
+
+# This will be used to add SSL and crypto support by the given library path (-L)
+# In case the ssl and crypto lib is not in your lib path, use LD_LIBRARY_PATH additionally upon call!
diff --git a/doc/CHAIN-SSL b/doc/CHAIN-SSL
new file mode 100644
index 0000000..9180ae2
--- /dev/null
+++ b/doc/CHAIN-SSL
@@ -0,0 +1,54 @@
+SSL UCSPI Certificate Chain Support
+-----------------------------------
+
+Scope:
+-----
+
+This version of UCSPI-SSL allows the SSL server to issue certificate chains.
+In this case, the SSL client does not need to verify the certificates on
+his own behalf, rather the client uses the presented certificates from the server.
+However, the final root certificate has to be known by the client.
+
+
+Usage:
+-----
+
+1. Concatinate all relevant X.509 certifcates in one file.
+ The first one is the certificate of the server, the last one
+ should be the root certificate.
+
+2. Tell the sslserver the name and location of this file.
+ Use the environment variable CERTCHAINFILE.
+
+3. Provide a separate keyfile for your own (the first certificate)
+ employing the environment variable KEYFILE.
+
+4. If this variable variable is present, it takes precedence over
+ CERTFILE.
+
+
+UI considerations:
+-----------------
+
+a) Providing a particular cipher for sslclient is now facilited with
+ option "-z cipher" instead of "-C cipher".
+
+b) Reversely, the location of the certificate chain file is available
+ via option "-C certchainfile".
+
+c) For sslserver use the environment variable CERTCHAINFILE.
+
+
+Security considerations:
+-----------------------
+
+Your own keyfile can be password protected.
+
+
+Performance considerations:
+--------------------------
+
+The server needs to open one thread per certificate.
+Thus, the server carries the burden to provide the certificates.
+
+Erwin Hoffmann - 2011-02-16
diff --git a/doc/CHANGES b/doc/CHANGES
new file mode 100644
index 0000000..9510cdb
--- /dev/null
+++ b/doc/CHANGES
@@ -0,0 +1,341 @@
+20011209
+ Initial release.
+ version: 0.50
+
+20021207
+ Convert to new build project.
+ Update libraries.
+ Correct load ordering for ssl programs.
+
+20030118
+ Option to set TCP environment variables.
+ Option to set SSL environment variables a la mod_perl.
+ Added sslperl.
+ Correct closure handling in ssl_io.c.
+
+20030128
+ Correct setting of TCPREMOTEINFO.
+
+20040127
+ Improved env tracking in handlers.
+ Updated tests.
+
+20040204
+ Clean up signal handling, process usage.
+
+20040209
+ Added nN options to sslclient.
+
+20040313
+ Added conf-ssl.
+ Version 0.65.
+
+20040317
+ Delete conf-home.
+ Permit nN opts in sslclient.
+ Version 0.66.
+
+20040320
+ Allow sslclient to avoid server verification.
+ Support cipher selection.
+ Correct execution botch in sslperl.
+ Clean up ssl_io and signal interaction.
+ Version 0.67.
+
+20040502
+ Read SSL setup info before dropping privilege.
+ Version 0.68.
+
+20050417
+ Don't fail on setsid if already group leader (Gabriel Russell).
+ Add compatibility macros for older Perl.
+ Don't leak pointer returned from eval_pv.
+ Support for partial testing.
+ Remove dependency on daemontools from rts.
+
+20050515
+ Partial-install bug fix in package/upgrade.
+
+20050605
+ Don't lose file descriptors in sslclient (Paul Jarc).
+
+20050610
+ Close socket for deny rule (Fred Lindberg).
+
+20050703
+ Revise ssl_io.
+ Free ssl object in sslhandle.c.
+ Add progtimeout option.
+
+20050717
+ Version 0.70.
+
+20090811
+ Included ucspi-ssl-0.70_ucspitls-0.6.patch (STARTTLS support)
+ originally designed and provided by Scott Gifford (FEH).
+
+20100319
+ Added Certchain support for sslserver and sslclient (FEH).
+
+20120217
+ Integration and added man-pages (FEH).
+ Version 0.80.
+
+20120921
+ Synced with ucspi-tcp6-0.95.
+ Version 0.82
+
+20121003
+ Fixed integration bug in ssl_very.c.
+ Included patches from Peter Conrad.
+ Version 0.83.
+
+20121005
+ Bug fix in sslserver. Several small
+ corrections.
+ Version 0.83a
+
+20121019
+ Fix for large X509 serial numbers on x86 (tx. Peter Conrad).
+ SAN DNSname has precedence over CN in subject.
+ Re-edited man pages and rts tests.
+ Version 0.84.
+
+20130602
+ Added IPv6 support (tx. to Felix von Leitner and Brandon Turner).
+ UI: Changed sslserver client cert call from '-i/-I' to '-z/-Z'
+ for compatibility reasons.
+ Added '-4/-6' support for client scripts.
+ Version 0.90.
+
+20130804
+ Added output environment variables TCP6* for sslserver.
+ sslperl, sslhandle, and sslprint are not IPv6 ready yet.
+ Version 0.91 test.
+
+20130910
+ Added IPv6 capabilities to sslhandle, sslprint, sslperl.
+ Changed verification of X.509 certs.
+ Removed obsolete socket_4 calls in sslserver.
+ Version 0.92 beta.
+
+20140112
+ Streamlined code with ucspi-tcp6-1.00.
+ Supplied new certs with customized SAN.
+ Make rts working (at least some how).
+
+20140331
+ Added support for personalized client certs.
+ New option '-m' in sslserver, complementing '-z'.
+ CCAFILE='-' disables client cert request.
+ Version 0.94 beta.
+
+20141221
+ Added verbose log output for SSL connection informations.
+ Version 0.95a beta.
+
+20140208
+ Fixed wrongly nested CONNECT error code for sslclient.c
+ producing wrong warning messages while connecting to
+ an IPv4 address.
+ Added call of '-ldl' in ssl.lib.
+ Version 0.95b beta.
+
+20151101
+ Mitigation of SSL connection hanging during
+ coincident change of daylight-saving settings.
+
+20160228
+ Fixed bug in sslserver's dnsip lookup in case of paranoid settings
+ and additonal existance of IPv6 AAAA records for incoming IPv4 connection.
+ Version 0.96.
+
+20160802
+ Serveral fixes from 'troy@' included to cope with compiler errors and
+ to solve a bug in function getbitasaddress in ip4_bit.c (= ucspi-tcp6-1.02).
+ Reordered conf-* variables in main dir to allow easier generation of
+ packages (i.e. RPM). Fixed script to identify different HW architecture
+ and OS. This version works in 32 bit mode on Raspian Linux / RasPi 7.
+
+ Added ECDH capabilites (tx to Frank Bergmann for the patches).
+ Version 0.97.
+
+20161226
+ Added compatibility with LibreSSL.
+ Fixed missing negative return call treatment from 'poll' (tx Frank Bergmann).
+ Tentative 'emake' fix for Gentoo build.
+ Version 0.98a.
+
+20170209
+ Added OpenSSL 1.1 tweaks -- works under Debian (9) 'Stretch'.
+ Version 0.99.
+
+20170308
+ Included PID in sslserver + sslhandle abend logs in case of SSL failure.
+ Version 0.99a.
+
+20170617
+ Convenience release: Removed references to 'gcc' and used 'cc' instead.
+ Version 0.99b.
+
+20170712
+ Convenience release: Added `correct` pid display in error log.
+
+20171028
+ Fixed cosmetic bug in sslserver displaying parent and not child pid in log.
+ Tx Bruce Guenter.
+
+20171105
+ Clean ups.
+
+20180811
+ Fixed missing 'return 0' in ssl_params.c for ECDH handshake (tx. J.W.).
+ Version 0.99e
+
+----
+
+20180809
+ Complete refurbish based on fehQlibs.
+ Native handling of IPv4/IPv6 address for sslclient.
+ Version 0.10
+
+20180810
+ Added experimental 'ecdhparam' file.
+ Version 0.10.1
+
+20180816
+ Removed experimental 'ecdhparam' handling -- OpenSSL does not support it.
+ fehQlibs-08 required.
+ Version 0.10.2
+
+20181010
+ Finished TLS 1.3 integration (based on OpenSSL 1.1.1).
+ Removed compiler flags for ECDH -- now required.
+ fehQlibs-09 based.
+ Version 0.10.6
+
+20181109
+ Better handling of read EAGAIN (sslserver may hang).
+ Include socket_dualstack option (required for OS with IPv6_V6ONLY).
+ fehQlibs-10 required.
+ Version 0.10.7
+
+20190318
+ Added dualstack handling for servers applying the
+ pseudo IP address ':0' on call (common now for all servers).
+ Tailored TLS error handling for EAGAIN end error codes.
+ Rewrote IPv4 CIDR address evaluation for rules.
+ Version 0.10.8
+
+20190505
+ Fixed broken evaluation of CIDR and IPv6 addresses;
+ adjusted with ucspi-tcp6-1.10.5.
+ Improved compatibility with LibreSSL and included description.
+ Version 0.10.9
+
+20190608
+ Added DSA/DSS (+ECC) signature verification additionally to RSA.
+ Added compatibility with fehQlibs-12.
+ Version 0.10.10
+
+20190728
+ Compatibility improvements for the forthcoming s/qmail.
+ Fixed potential stack corruption in sslclient/sslhande/sslserver
+ while assigning hostname => 0.
+ Improved OpenSSL + LibreSSL compatibility:
+ LibreSSL 2.5 to 2.9 is working
+ OpenSSL 1.0.2 to 1.1.1 is working
+ Added SNI for sslclient.
+ Fixes for sslhandle.
+ Included new CIPHERLIST API for ssl_ciphers.
+ Removed dependency on conf-tcpbin; modules are expected to be in the path.
+ Modules rts.base and rts.sslperl are working now.
+ Version 0.10.11
+
+20190810
+ Added compatibility with fehQlibs-13.
+ Fixed wrong behavior of sslserver/sslclient given a local or remote IPv4
+ address. sslhandle is now an own program (man sslhandle.3).
+ Code streamlined with ucspi-tcp6-1.11.0.
+
+20191012
+ Removed paranthesis from host in https@: [$host]:$port -> $host:port. Tx, A.E.
+ Version 0.11.0
+
+20191021
+ Fixed TLSv1* macro's names in ucspissl.h to match ssl_context.c.
+20191107
+ Clearified usage of 'SSL_CTX_set_ciphersuites()' in ssl_ciphers.c.
+ Version 0.11.1
+202002117
+ Adopted some fixes contributed by Alan S. (mtx):
+ DNS IP Name qualification; X.509 DNS name matching; certs are only read on demand.
+ Support of STARTTLS in sslclient is postponed to next minor version.
+ Version 0.11.2
+20200221
+ Straightend error codes and exiting for sslserver/sslhandle instead of dropping
+ the session in case of errors.
+ Version 0.11.3
+20200303
+ Fixed iopause return value evaluation in remoteinfo.c.
+20200323
+ Removed return call evaluation of iopause in ssl_io.c and ssl_timeout.c
+ Not clear, whether this is resulting the polling.
+ Version 0.11.4
+20200730
+ Added pollmax limit to sslserver and sslhandle.
+ sslclient streamlined with tcpclient. fehQlibs-15 are required.
+ Version 0.11.5
+20200920
+ GCC 10 compliance enforced; removed it-perl from basic install.
+ Version 0.11.6a
+20210319
+ fehQlibs-17 changes included regarding socket interface.
+ Synced with ucspi-tcp6-1.12.3 providing MAXCONIP capabilities.
+ Successful integration tests for OpenSSL 3.0.0-alpha13 and LibreSSL 3.3.1.
+ Version 0.12.1
+20210325
+ Fixed sslserver's binding to IPv4/IPv6 addresses; code aligned with tcpserver.
+ Version 0.12.2
+20211017
+ sslhandle to bind to IPv4 sockets, if told so.
+ Compatibility tests with OpenSSL 3.0. Still preliminary.
+ Version 0.12.3
+20220824
+ Fixed early logmsg() call in sslserver.
+ Version 0.12.3
+20221228
+ Checked compatibility with LibreSSL 3.6/3.7.
+ The selected ciphers are now shown during start of sslserver/sslhandle.
+ Fixed duplicate symbol in sslhandle (Who).
+ Version 0.12.4
+20230403
+ Included tests on tai_now in ssl_timeout.c and removed obsolete pollmax variables.
+ ssl_io.c closes TLS connection gracefully upon SSL_ERROR_SSL recognition
+ and not continue looping.
+ Version 0.12.5
+20230403
+ ssl_io uses now two specific return codes under condition 'BOMB' avoiding unnecessary
+ error messages in case of TLS client termination.
+ Version 0.12.6
+20230529
+ sslserver MAXCONIP feature is working now from the cdb read by the children.
+ MAXCONIP works even the general limit is 0.
+ Fixed wrong '-m' option for sslserver.
+ Added ip and port information in case sslserver/sslclient can't bind to local addresses.
+ Tweaked rts to include external load libraries.
+ Version 0.12.7
+20231010
+ Added new x509 certs and key material; all ECC now.
+ Fixed wrong evaluation of peer cert in ssl_verify (none-critical).
+ Version 0.12.8
+20231128
+ Included IP info in sslserver's TLS error messages for a quick lookup.
+ Fixed sslhandle's wrong if nesting.
+ sslserver return FATAL (and not ERROR) in case TLS is requested but missing.
+ Enhanced compatibility with OpenSSL 3.x.y.
+ Version 0.12.9
+20231204
+ Added argument '-y cdb' to sslserver in order to allow a rule checking
+ for IP addresses prior of the DNS/IDENT lookup (to cope with DDos attacks).
+ Version 0.12.10
diff --git a/doc/LICENSE b/doc/LICENSE
new file mode 100644
index 0000000..aea2c94
--- /dev/null
+++ b/doc/LICENSE
@@ -0,0 +1,70 @@
+AUTHOR
+======
+
+Author:
+ Dr. Erwin Hoffmann - FEHCom Germany
+Web-Site:
+ https://www.fehcom.de/ipnet/ucspi-ssl.html
+E-Mail:
+ feh@fehcom.de
+
+CONTRIBUTIONS
+=============
+
+ucspi-ssl is based on William E. Baxter's (superscript.com) version used by permission:
+ https://www.superscript.com/
+which is put into the Public Domain.
+
+ucspi-ssl uses enhancements from Scott Gifford's and Charly Brady's API
+to support STARTTLS communication:
+ https://github.com/scottgifford/ucspi-ssl
+License state unknown
+
+LICENSE
+=======
+
+Given these restrictions:
+
+ucspi-ssl is free software placed into the Public Domain.
+
+This includes:
+ You can download and use ucspi-ssl (and parts of it) as you like.
+ You can modify the source code without notification to or permission by the author.
+Please check:
+ http://www.cr.yp.to/softwarelaw.html
+Note:
+ ucspi-ssl depends on third party software with different
+ license and/or distribution conditions; in particular
+ - OpenSSL
+ - LibreSSL
+
+
+DEPENDENCIES
+============
+
+ucspi-ssl depends on the following package:
+ - fehQlibs found on https://www/ipnet/qlibs.html
+which is Public Domain as well.
+
+
+Note:
+-----
+
+The author of the program may unsolicitedly change the dependencies.
+Thus, it is your obligation to follow and consider any changes!
+
+
+FITNESS
+=======
+
+The author does not guarantee a specific fitness of ucspi-ssl.
+If you use ucspi-ssl, it's on your own risk.
+
+
+DISTRIBUTION
+============
+
+ucspi-ssl may be included in ports and packages under the following conditions:
+ The port/package has to show the current version number of ucspi-ssl.
+ This license file has to be included in the distribution.
+
diff --git a/doc/README.rts b/doc/README.rts
new file mode 100755
index 0000000..60ef73b
--- /dev/null
+++ b/doc/README.rts
@@ -0,0 +1,78 @@
+Rudimentary Test System (RTS)
+=============================
+
+History
+-------
+
+Starting with ucspi-tcp, DJB introduced a script called 'rts.test'
+to do some unit/system tests for the modules included in here.
+
+This piece of software was never documented nor its purpose was defined.
+William Baxter modified it to work with ucspi-ssl.
+DJB used it in the release of djbdns.
+
+
+Components
+----------
+
+Within (slash)package 'rts' consists of the following pieces:
+
+ a) package/rts [component] is a generic shell script.
+ b) src/rts.[it], src/rts.[component] are the scripts containing the specific unit tests.
+ src/rts.it is usually the supervising script,
+ while src/rts.base includes typically the 'basic' unit tests,
+ src/rts.[component] is optional.
+ c) src/exp.[it], src.[bases] and perhaps src/exp.[component]
+ include the expected results (adapted).
+
+While [it] and [base] are mandatory, any further [component] needs
+to be defined by the (slash)package installation.
+
+
+Defaults and Adjustments
+------------------------
+
+ 1. In order to use rts, the binaries are expected to be install
+ at their default directories.
+ 2. Since ucspi-ssl depends on *SSL libraries, the shared libs
+ shall be available in their default locations.
+ 3. If you use custom installed *SSL libs, you need to modify
+ the LD_LIBRARY_PATH. See the file rts.base to get the idea.
+
+
+Invocation
+----------
+
+'rts' is typically called after a successful compilation and installation.
+The $PATH variable includes the current directory of the executed rts.it (./compile).
+In order to test the included modules one calls:
+
+ package/rts --> all tests are done (including optional)
+ package/rts base --> basic unit tests
+ package/rts [component] --> optional component test
+
+
+Results
+-------
+
+The script rts.[component] is executed in
+
+ ./compile/rts-temp
+
+to be raised upon call. The results are written to
+
+ ./compile/out.[component]
+
+and then diff'ed against exp.[component], cleaned up for trivial
+run dependencies (like port numbers) and the difference is displayed.
+
+If there is no difference, nothing is displayed => working as expected.
+
+However, even if differences are given, they may be due to environment/call
+dependencies (like process ids) resulting in some mangled output.
+
+In case package/rts is called again, the previous results are overwritten.
+
+
+--eh (May, 2023).
+
diff --git a/doc/TLSVERSION_CIPHERSUITES b/doc/TLSVERSION_CIPHERSUITES
new file mode 100644
index 0000000..645e44a
--- /dev/null
+++ b/doc/TLSVERSION_CIPHERSUITES
@@ -0,0 +1,62 @@
+TLS Version & Cipher Suites
+---------------------------
+
+ucspi-ssl provides two hooks to adjust the TLS version and the Cipher Suite:
+
+1. Client and Server (sslclient, sslhandle, sslserver):
+
+The TLS/SSL protocol versions
+
+- SSLv2 and
+- SSLv3
+
+are disabled in ucspissl.h.
+
+- TLSv1 is already included here, but is still commented out.
+
+
+2. The Cipher Suite accepted by the Server (sslhandle, sslserver)
+
+a) Pre-TLS 1.3
+
+Here, you can adjust the settings by means of CIPHER environment variables.
+Some typical choices:
+
+#CIPHERS="'TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH'"
+#CIPHERS="TLSv1+HIGH:!SSLv2:!MD5"
+CIPHERS="TLSv1.2+HIGH:TLSv1.1+HIGH:!TLSv1+HIGH:!aNULL:!eNULL:@STRENGTH"
+
+This variable can be statically defined for all connections or used
+as environment variable specified with the tcprule database.
+
+OpenSSL supports even very old and inscure crypto primites like MD5 or DES;
+however under current circumstances they are not negotiated.
+
+b) TLS 1.3
+
+While previous TLS understand some phrasings like 'DEFAULT', 'HIGH' in TLS 1.3
+a new API and a new scheme is used
+(https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_cipher_list.html):
+
+>> An empty list is permissible. The default value for the this setting is:
+
+ "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256" <<
+
+This means 'TLS_AES_256_GCM_SHA384' has priority. However, you can tweak this to:
+
+ "TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
+
+thus, the first choice is CHACHA20. In case AES_256 is present, it has
+precedence over CHACHA20.
+
+Remember: In any case, only ECDHE is used as handshake protocol.
+
+
+3. Online Resources
+
+OpenSSL: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_cipher_list.html
+
+LibreSSL: https://fossies.org/linux/libressl/man/SSL_CTX_set_cipher_list.3
+
+
+--eh, Oktober 2023.
diff --git a/doc/TLS_1_3 b/doc/TLS_1_3
new file mode 100644
index 0000000..51c7c42
--- /dev/null
+++ b/doc/TLS_1_3
@@ -0,0 +1,36 @@
+Installing ucspi-ssl with TLS 1.3 support
+-----------------------------------------
+
+ucspi-ssl-0.10 can use TLS 1.3 capabilities alongside
+with your system's previous *SSL installation:
+
+a) OpenSSL 1.1.1:
+
+- Download OpenSSL and untar OpenSSL at some path; ie. /usr/local.
+- Execute./conf && make. Don't do 'make install'!!
+
+- conf-ssl: Include path to the header files via -I <path>.
+ (-I/usr/local/openssl-1.1.1/include)
+- conf-ssllib: Include path to the libraries via -L <path>.
+ (-L/usr/local/openssl-1.1.1 -lssl -lcrypto)
+
+b) LibreSSL 2.9.x:
+
+Download LibreSSL and untar LibreSSL at some path; ie. /usr/local.
+Execute./conf && make. Don't do 'make install'!!
+Do a
+ ln -s ssl/.libs/libssl.so .
+ ln -s crypto/.libs/libcrypto.so .
+in the LibreSSL main directory.
+
+- conf-ssl: Include path to the header files via -I <path>.
+ (-I/usr/local/libressl-2.9.1/include)
+- conf-ssllib: Include path to the libraries via -L <path>.
+ (-L/usr/local/libressl-2.9.1 -lssl -lcrypto)
+
+
+
+Recompile ucspi-ssl.
+This should be it.
+
+E. Hoffmann, September 2019.
diff --git a/doc/TODO b/doc/TODO
new file mode 100644
index 0000000..1c9da9b
--- /dev/null
+++ b/doc/TODO
@@ -0,0 +1,7 @@
+Program like stunnel (web).
+Rules tests (web).
+CRL support (feh).
+OCSPI support (feh).
+DANE support (feh).
+SSL connection caching (feh).
+Migrate whole openssl stuff to wolfssl (bergmann).
diff --git a/doc/UCSPI-SSL b/doc/UCSPI-SSL
new file mode 100644
index 0000000..69bd25e
--- /dev/null
+++ b/doc/UCSPI-SSL
@@ -0,0 +1,48 @@
+SSL UCSPI protocol definition
+Copyright 2001
+SuperScript Technology, Inc. sst@superscript.com
+
+This document defines the SSL protocol for UCSPI-1996 tools. An SSL
+client communicates with an SSL server, on the same machine or on a
+different machine, via the TCP/IP protocol through an Internet-domain
+socket. The descriptors passed to a SSL UCSPI application are copies of
+that socket, dup()ed from a single connect() or accept().
+
+[address] consists of two arguments: [hostname] [port].
+
+There are three possibilities for [hostname]: the number 0, referring to
+the local host; a dotted-decimal IP address, such as 192.48.96.5; or a
+name understood by the system's resolver, such as mail.uu.net. SSL UCSPI
+servers use only the first IP address from the resolver; SSL UCSPI
+clients try each address in turn.
+
+There are three possibilities for [port]: a positive numeric TCP port
+number, such as 25; the number 0, which permits selection of any port
+number; or a name understood by the system's getservbyname(), such as
+smtp.
+
+The client and server set up the following environment variables:
+
+ PROTO: the string SSL
+ SSLLOCALIP: the dotted-decimal IP address of the local host
+ SSLLOCALPORT: the local SSL port number, in decimal
+ SSLREMOTEIP: the dotted-decimal IP address of the remote host
+ SSLREMOTEPORT: the remote SSL port number, in decimal
+ SSLLOCALHOST, if possible: the resolver's name for SSLLOCALIP
+ SSLREMOTEHOST, if possible: the resolver's name for SSLREMOTEIP
+ SSLREMOTEINFO, if possible: the result of a 931/1413/IDENT/TAP query
+
+Uppercase letters in SSLLOCALHOST and SSLREMOTEHOST are converted to
+lowercase. SSLREMOTEINFO is a connection-specific string supplied by the
+remote host via 931/1413/IDENT/TAP.
+
+SSL UCSPI tools take a -R option to turn off 931/1413/IDENT/TAP
+querying, and a -r option to turn it back on. SSL UCSPI tools take a -I
+option to turn off checking for a client certificate, and a -i option to
+turn it back on. SSL UCSPI clients take a -p [locport] option to
+require a particular TCP port on the local side of the connection. SSL
+UCSPI servers take a -1 option to print the local port number (in
+decimal, followed by a newline) to descriptor 1 before closing
+descriptor 1 and after preparing to receive connections. SSL UCSPI
+servers and clients take a -3 option to read a null-terminated key
+password from file descriptor 3.
diff --git a/etc/127.0.0.1.pw b/etc/127.0.0.1.pw
new file mode 100644
index 0000000..c85ca4d
--- /dev/null
+++ b/etc/127.0.0.1.pw
Binary files differ
diff --git a/etc/127.0.0.1_cert.pem b/etc/127.0.0.1_cert.pem
new file mode 100644
index 0000000..47de390
--- /dev/null
+++ b/etc/127.0.0.1_cert.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwjCCAmmgAwIBAgIUdQHW4sgGy2mrH8B4218AK8rDcDwwCgYIKoZIzj0EAwIw
+bjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxETAP
+BgNVBAMTCGxvb3BiYWNrMB4XDTIzMDkyMDEzMDUxNFoXDTI4MTIwMjEzMDUxNFow
+bjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxETAP
+BgNVBAMTCGxvb3BiYWNrMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmDn4CQK9
+gXsdTyM0LrBcl7d3mL3Xiu3X0Eglwf+mpJeP/FYABJsUuj/b03bUUwdjIGH7xoj6
+CQa5f4XSz3ooAKOB5DCB4TAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNVHSUE
+DDAKBggrBgEFBQcDATAaBgNVHREEEzARhwR/AAABgglsb2NhbGhvc3QwgZUGA1Ud
+IwSBjTCBiqFypHAwbjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREw
+DwYDVQQHEwhCcm9va2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxh
+Ym9yYXRvcnkxETAPBgNVBAMTCGxvb3BiYWNrghR1AdbiyAbLaasfwHjbXwArysNw
+PDAKBggqhkjOPQQDAgNHADBEAiBbOFAkXh9D1CSt641D7Nsr9QS7eArxMLBebWls
+3QBXnwIgK7EmciEPznKaXXcTB8n9NwQUvMDaM0lqpE0XyEgENqA=
+-----END CERTIFICATE-----
diff --git a/etc/127.0.0.1_key.pem b/etc/127.0.0.1_key.pem
new file mode 100644
index 0000000..983f8ec
--- /dev/null
+++ b/etc/127.0.0.1_key.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,AB1B9F788B65B4711CF737FDFB536BE4
+
+DX4AvhWLBwAAW6qoW6N52rKo3DfBAHkHXY+DEj7GvxHyqXEedzvUXJhFpd9U/MR2
+F/TzuTjTtKRJmTI7ULdRT90/GDch9DybL7abZiCfSPqA1gl/S2E1ewhUb7O8Iz7n
+Z+1v+lYOWDznfmSbqyJCUZmz9QI2rASj2dApyeVJlCA=
+-----END EC PRIVATE KEY-----
diff --git a/etc/127.0.0.1_key.pem.plain b/etc/127.0.0.1_key.pem.plain
new file mode 100644
index 0000000..010f8dc
--- /dev/null
+++ b/etc/127.0.0.1_key.pem.plain
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEINvQSFUQX4cojQJ/TkdGAqecoOEI8m/V9UzKBkJTQn1HoAoGCCqGSM49
+AwEHoUQDQgAEmDn4CQK9gXsdTyM0LrBcl7d3mL3Xiu3X0Eglwf+mpJeP/FYABJsU
+uj/b03bUUwdjIGH7xoj6CQa5f4XSz3ooAA==
+-----END EC PRIVATE KEY-----
diff --git a/etc/::1.pw b/etc/::1.pw
new file mode 100644
index 0000000..c85ca4d
--- /dev/null
+++ b/etc/::1.pw
Binary files differ
diff --git a/etc/::1_cert.pem b/etc/::1_cert.pem
new file mode 100644
index 0000000..d67aea7
--- /dev/null
+++ b/etc/::1_cert.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIICzzCCAnWgAwIBAgIUBtVH6POMnmJlLyH0MuUJvpKtTy8wCgYIKoZIzj0EAwIw
+bjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxETAP
+BgNVBAMTCGxvb3BiYWNrMB4XDTIzMDkyMDEzMDU1MloXDTI4MTIwMjEzMDU1Mlow
+bjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxETAP
+BgNVBAMTCGxvb3BiYWNrMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELAT3LgqE
+fyay4gJstMSag4n6qWIW+A4lTS2coTdKpDruQu+4MU/hlJTI8RvtYPwE7Qvn69uT
+rQUkOASI37tMMKOB8DCB7TAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNVHSUE
+DDAKBggrBgEFBQcDATAmBgNVHREEHzAdhxAAAAAAAAAAAAAAAAAAAAABgglsb2Nh
+bGhvc3QwgZUGA1UdIwSBjTCBiqFypHAwbjELMAkGA1UEBhMCVVMxETAPBgNVBAgT
+CE5ldyBZb3JrMREwDwYDVQQHEwhCcm9va2x5bjEmMCQGA1UEChMddWNzcGktc3Ns
+IHJlc2VhcmNoIGxhYm9yYXRvcnkxETAPBgNVBAMTCGxvb3BiYWNrghQG1Ufo84ye
+YmUvIfQy5Qm+kq1PLzAKBggqhkjOPQQDAgNIADBFAiEAhMpsgcfPqkPFz+OVfEOn
+CT6ateSu6FWl2j9uUzeV3OoCIDWDHBu9jp6M676IDqnBIwDTl+fK6s11AJuJLH+J
+yqzP
+-----END CERTIFICATE-----
diff --git a/etc/::1_key.pem b/etc/::1_key.pem
new file mode 100644
index 0000000..cf6fdc5
--- /dev/null
+++ b/etc/::1_key.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,BBE021D3F3B68368FA5295064A41EC65
+
+6N0F4500DFvZAX4dQ1VAxk+gFvZaIYFuawF5YYEVwNY3/DwM71r1XsH7nGyThKN7
+4ZisRFIZ8qOXVl8pDxomQlaW3yMut0JUYoTf5mZhulMhDLNBUM4xhmuRbXqReKA4
+krTUgazSMpz74VoKdZHmWdjqABru9kgWnS28BhmBPS4=
+-----END EC PRIVATE KEY-----
diff --git a/etc/::1_key.pem.plain b/etc/::1_key.pem.plain
new file mode 100644
index 0000000..e27f00e
--- /dev/null
+++ b/etc/::1_key.pem.plain
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIMe4kJ7pk/Uc+9D/1XmQtGwMW1OUFxYSZrntSrXBMoFRoAoGCCqGSM49
+AwEHoUQDQgAELAT3LgqEfyay4gJstMSag4n6qWIW+A4lTS2coTdKpDruQu+4MU/h
+lJTI8RvtYPwE7Qvn69uTrQUkOASI37tMMA==
+-----END EC PRIVATE KEY-----
diff --git a/etc/README.certs.md b/etc/README.certs.md
new file mode 100644
index 0000000..05487d1
--- /dev/null
+++ b/etc/README.certs.md
@@ -0,0 +1,281 @@
+/*! \mainpage
+
+README.certs
+============
+
+1. X.509 Certs and key files
+----------------------------
+
+In this directory you will find:
+
+a) rootCA_cert.pem -- ECC root CA PEM file; almost 10 years valid
+b) rootCA_key.pem -- encypted corresponding key file for signing - password 12345
+c) rootCA_key.pem.plain -- unencypted corresponding key file for signing
+
+e) ::1_cert.pem -- ECC IPv6 localhost PEM cert
+f) ::1_key.pem -- encrypted corresponding key file for authentication - password testcert
+g) ::1_key.pem.plain -- unencrypted corresponding key file for authentication
+
+h) 127.0.0.1_cert.pem -- ECC IPv4 localhost PEM cert
+i) 127.0.0.1_key.pem -- enrypted corresponding key file for authentication - password testcert
+j) 127.0.0.1_key.pem.plain -- unencrypted corresponding key file for authentication
+
+k) localhost_cert.pem -- ECC generic localhost PEM cert
+l) localhost.pem -- encrypted corresponding key file for authentication - password testcert
+m) localhost.pem -- unencrypted corresponding key file for authentication
+
+n) chain6.pem -- chained ::1_cert.pam + rootCA_cert.pem
+o) chain4.pem -- chained 127.0.0.1_cert.pam + rootCA_cert.pem
+
+p) dh2048.pem -- Diffie-Hellman parameter file with 2048 bit
+
+All x509 certs are generated by means of the ECC prime256v1 algorithm.
+CA cert validity: About 10 years from September 2023.
+Other certs valdity is about 5 years starting at September 2023.
+
+2. Usage
+--------
+
+These x509 certs and key files are provided to allow an initial
+setup and test of UCSPI-SSL's sslserver and companions.
+
+The use of ECC signatures requires OpenSSL > 1.1.1 or LibreSSL > 3.3.1.
+
+3. rootCA_cert.pem
+------------------
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 2a:33:3a:76:03:ac:7a:0f:23:38:0a:5c:e3:43:f2:9d:74:9d:ae:99
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: C = US, ST = New York, L = Brooklyn, O = ucspi-ssl research laboratory, CN = ucspi-ssl research ca
+ Validity
+ Not Before: Sep 20 13:04:38 2023 GMT
+ Not After : Oct 17 13:04:38 2033 GMT
+ Subject: C = US, ST = New York, L = Brooklyn, O = ucspi-ssl research laboratory, CN = ucspi-ssl research ca
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (256 bit)
+ pub:
+ 04:74:87:e3:06:ee:44:a1:7b:4c:ca:d4:d9:13:fa:
+ d2:8a:4c:08:42:84:ae:3f:f9:97:9d:c2:49:48:ad:
+ 0f:3d:ba:c2:26:df:28:22:45:63:7c:fe:28:b1:e1:
+ 90:1d:33:4f:62:3f:b0:ff:0c:04:52:0b:75:1b:6b:
+ 72:76:a1:00:07
+ ASN1 OID: prime256v1
+ NIST CURVE: P-256
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ A5:33:0C:F4:15:5B:BD:10:6A:71:A2:79:EB:00:77:8C:7A:30:35:83
+ X509v3 Authority Key Identifier:
+ keyid:A5:33:0C:F4:15:5B:BD:10:6A:71:A2:79:EB:00:77:8C:7A:30:35:83
+
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: ecdsa-with-SHA256
+ 30:45:02:21:00:99:53:0a:1c:5f:b2:1c:80:c0:05:17:05:f7:
+ 75:96:28:87:bd:c3:d5:ca:2f:bf:a4:17:5e:66:ac:bb:4f:68:
+ 50:02:20:37:25:2a:62:2e:5d:31:8f:d7:71:3a:4d:b9:39:6b:
+ f8:02:5a:50:7b:c9:74:33:11:57:24:a9:2b:7a:39:37:b6
+-----BEGIN CERTIFICATE-----
+MIICSzCCAfGgAwIBAgIUKjM6dgOseg8jOApc40PynXSdrpkwCgYIKoZIzj0EAwIw
+ezELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxHjAc
+BgNVBAMTFXVjc3BpLXNzbCByZXNlYXJjaCBjYTAeFw0yMzA5MjAxMzA0MzhaFw0z
+MzEwMTcxMzA0MzhaMHsxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazER
+MA8GA1UEBxMIQnJvb2tseW4xJjAkBgNVBAoTHXVjc3BpLXNzbCByZXNlYXJjaCBs
+YWJvcmF0b3J5MR4wHAYDVQQDExV1Y3NwaS1zc2wgcmVzZWFyY2ggY2EwWTATBgcq
+hkjOPQIBBggqhkjOPQMBBwNCAAR0h+MG7kShe0zK1NkT+tKKTAhChK4/+ZedwklI
+rQ89usIm3ygiRWN8/iix4ZAdM09iP7D/DARSC3Uba3J2oQAHo1MwUTAdBgNVHQ4E
+FgQUpTMM9BVbvRBqcaJ56wB3jHowNYMwHwYDVR0jBBgwFoAUpTMM9BVbvRBqcaJ5
+6wB3jHowNYMwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEAmVMK
+HF+yHIDABRcF93WWKIe9w9XKL7+kF15mrLtPaFACIDclKmIuXTGP13E6Tbk5a/gC
+WlB7yXQzEVckqSt6OTe2
+-----END CERTIFICATE-----
+
+4. ::1_cert.pem
+---------------
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 06:d5:47:e8:f3:8c:9e:62:65:2f:21:f4:32:e5:09:be:92:ad:4f:2f
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: C = US, ST = New York, L = Brooklyn, O = ucspi-ssl research laboratory, CN = loopback
+ Validity
+ Not Before: Sep 20 13:05:52 2023 GMT
+ Not After : Dec 2 13:05:52 2028 GMT
+ Subject: C = US, ST = New York, L = Brooklyn, O = ucspi-ssl research laboratory, CN = loopback
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (256 bit)
+ pub:
+ 04:2c:04:f7:2e:0a:84:7f:26:b2:e2:02:6c:b4:c4:
+ 9a:83:89:fa:a9:62:16:f8:0e:25:4d:2d:9c:a1:37:
+ 4a:a4:3a:ee:42:ef:b8:31:4f:e1:94:94:c8:f1:1b:
+ ed:60:fc:04:ed:0b:e7:eb:db:93:ad:05:24:38:04:
+ 88:df:bb:4c:30
+ ASN1 OID: prime256v1
+ NIST CURVE: P-256
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 Key Usage:
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ X509v3 Subject Alternative Name:
+ IP Address:0:0:0:0:0:0:0:1, DNS:localhost
+ X509v3 Authority Key Identifier:
+ DirName:/C=US/ST=New York/L=Brooklyn/O=ucspi-ssl research laboratory/CN=loopback
+ serial:06:D5:47:E8:F3:8C:9E:62:65:2F:21:F4:32:E5:09:BE:92:AD:4F:2F
+
+ Signature Algorithm: ecdsa-with-SHA256
+ 30:45:02:21:00:84:ca:6c:81:c7:cf:aa:43:c5:cf:e3:95:7c:
+ 43:a7:09:3e:9a:b5:e4:ae:e8:55:a5:da:3f:6e:53:37:95:dc:
+ ea:02:20:35:83:1c:1b:bd:8e:9e:8c:eb:be:88:0e:a9:c1:23:
+ 00:d3:97:e7:ca:ea:cd:75:00:9b:89:2c:7f:89:ca:ac:cf
+-----BEGIN CERTIFICATE-----
+MIICzzCCAnWgAwIBAgIUBtVH6POMnmJlLyH0MuUJvpKtTy8wCgYIKoZIzj0EAwIw
+bjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxETAP
+BgNVBAMTCGxvb3BiYWNrMB4XDTIzMDkyMDEzMDU1MloXDTI4MTIwMjEzMDU1Mlow
+bjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxETAP
+BgNVBAMTCGxvb3BiYWNrMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELAT3LgqE
+fyay4gJstMSag4n6qWIW+A4lTS2coTdKpDruQu+4MU/hlJTI8RvtYPwE7Qvn69uT
+rQUkOASI37tMMKOB8DCB7TAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNVHSUE
+DDAKBggrBgEFBQcDATAmBgNVHREEHzAdhxAAAAAAAAAAAAAAAAAAAAABgglsb2Nh
+bGhvc3QwgZUGA1UdIwSBjTCBiqFypHAwbjELMAkGA1UEBhMCVVMxETAPBgNVBAgT
+CE5ldyBZb3JrMREwDwYDVQQHEwhCcm9va2x5bjEmMCQGA1UEChMddWNzcGktc3Ns
+IHJlc2VhcmNoIGxhYm9yYXRvcnkxETAPBgNVBAMTCGxvb3BiYWNrghQG1Ufo84ye
+YmUvIfQy5Qm+kq1PLzAKBggqhkjOPQQDAgNIADBFAiEAhMpsgcfPqkPFz+OVfEOn
+CT6ateSu6FWl2j9uUzeV3OoCIDWDHBu9jp6M676IDqnBIwDTl+fK6s11AJuJLH+J
+yqzP
+-----END CERTIFICATE-----
+
+5. 127.0.0.1_cert.pem
+---------------------
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 75:01:d6:e2:c8:06:cb:69:ab:1f:c0:78:db:5f:00:2b:ca:c3:70:3c
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: C = US, ST = New York, L = Brooklyn, O = ucspi-ssl research laboratory, CN = loopback
+ Validity
+ Not Before: Sep 20 13:05:14 2023 GMT
+ Not After : Dec 2 13:05:14 2028 GMT
+ Subject: C = US, ST = New York, L = Brooklyn, O = ucspi-ssl research laboratory, CN = loopback
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (256 bit)
+ pub:
+ 04:98:39:f8:09:02:bd:81:7b:1d:4f:23:34:2e:b0:
+ 5c:97:b7:77:98:bd:d7:8a:ed:d7:d0:48:25:c1:ff:
+ a6:a4:97:8f:fc:56:00:04:9b:14:ba:3f:db:d3:76:
+ d4:53:07:63:20:61:fb:c6:88:fa:09:06:b9:7f:85:
+ d2:cf:7a:28:00
+ ASN1 OID: prime256v1
+ NIST CURVE: P-256
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 Key Usage:
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ X509v3 Subject Alternative Name:
+ IP Address:127.0.0.1, DNS:localhost
+ X509v3 Authority Key Identifier:
+ DirName:/C=US/ST=New York/L=Brooklyn/O=ucspi-ssl research laboratory/CN=loopback
+ serial:75:01:D6:E2:C8:06:CB:69:AB:1F:C0:78:DB:5F:00:2B:CA:C3:70:3C
+
+ Signature Algorithm: ecdsa-with-SHA256
+ 30:44:02:20:5b:38:50:24:5e:1f:43:d4:24:ad:eb:8d:43:ec:
+ db:2b:f5:04:bb:78:0a:f1:30:b0:5e:6d:69:6c:dd:00:57:9f:
+ 02:20:2b:b1:26:72:21:0f:ce:72:9a:5d:77:13:07:c9:fd:37:
+ 04:14:bc:c0:da:33:49:6a:a4:4d:17:c8:48:04:36:a0
+-----BEGIN CERTIFICATE-----
+MIICwjCCAmmgAwIBAgIUdQHW4sgGy2mrH8B4218AK8rDcDwwCgYIKoZIzj0EAwIw
+bjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxETAP
+BgNVBAMTCGxvb3BiYWNrMB4XDTIzMDkyMDEzMDUxNFoXDTI4MTIwMjEzMDUxNFow
+bjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxETAP
+BgNVBAMTCGxvb3BiYWNrMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmDn4CQK9
+gXsdTyM0LrBcl7d3mL3Xiu3X0Eglwf+mpJeP/FYABJsUuj/b03bUUwdjIGH7xoj6
+CQa5f4XSz3ooAKOB5DCB4TAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNVHSUE
+DDAKBggrBgEFBQcDATAaBgNVHREEEzARhwR/AAABgglsb2NhbGhvc3QwgZUGA1Ud
+IwSBjTCBiqFypHAwbjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREw
+DwYDVQQHEwhCcm9va2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxh
+Ym9yYXRvcnkxETAPBgNVBAMTCGxvb3BiYWNrghR1AdbiyAbLaasfwHjbXwArysNw
+PDAKBggqhkjOPQQDAgNHADBEAiBbOFAkXh9D1CSt641D7Nsr9QS7eArxMLBebWls
+3QBXnwIgK7EmciEPznKaXXcTB8n9NwQUvMDaM0lqpE0XyEgENqA=
+-----END CERTIFICATE-----
+
+6. localhost_cert.pem
+---------------------
+
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 7a:6a:2a:23:7c:b4:99:26:bd:19:ee:88:72:b4:1c:8e:4d:3b:5a:40
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: C = US, ST = New York, L = Brooklyn, O = ucspi-ssl research laboratory, CN = localhost
+ Validity
+ Not Before: Sep 20 13:06:24 2023 GMT
+ Not After : Dec 2 13:06:24 2028 GMT
+ Subject: C = US, ST = New York, L = Brooklyn, O = ucspi-ssl research laboratory, CN = localhost
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (256 bit)
+ pub:
+ 04:13:bc:51:f1:ce:42:39:a5:da:fd:81:e7:4d:03:
+ fd:3d:93:9d:63:ce:d7:32:0c:1b:c1:f3:1a:43:84:
+ f4:c5:db:79:c9:7e:e5:3d:ad:de:ca:66:fd:f5:a7:
+ 1c:80:18:20:b6:c6:b1:18:76:30:0a:3f:5f:ac:ca:
+ a4:90:d4:8b:b0
+ ASN1 OID: prime256v1
+ NIST CURVE: P-256
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 Key Usage:
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Client Authentication
+ X509v3 Subject Alternative Name:
+ DNS:localhost, IP Address:0.0.0.0, IP Address:0:0:0:0:0:0:0:0
+ X509v3 Authority Key Identifier:
+ DirName:/C=US/ST=New York/L=Brooklyn/O=ucspi-ssl research laboratory/CN=localhost
+ serial:7A:6A:2A:23:7C:B4:99:26:BD:19:EE:88:72:B4:1C:8E:4D:3B:5A:40
+
+ Signature Algorithm: ecdsa-with-SHA256
+ 30:45:02:20:71:4c:08:c1:2a:7e:31:a9:33:5a:92:cb:da:81:
+ 85:ed:74:66:38:f8:5b:f1:55:1c:e4:bb:ba:3e:4e:83:76:fb:
+ 02:21:00:d3:82:51:6f:87:b0:32:14:1e:e0:f0:8c:43:cf:1c:
+ f2:2b:ca:70:a9:d3:26:55:00:91:94:29:87:06:8d:3e:3e
+-----BEGIN CERTIFICATE-----
+MIIC2DCCAn6gAwIBAgIUemoqI3y0mSa9Ge6IcrQcjk07WkAwCgYIKoZIzj0EAwIw
+bzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxEjAQ
+BgNVBAMTCWxvY2FsaG9zdDAeFw0yMzA5MjAxMzA2MjRaFw0yODEyMDIxMzA2MjRa
+MG8xCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazERMA8GA1UEBxMIQnJv
+b2tseW4xJjAkBgNVBAoTHXVjc3BpLXNzbCByZXNlYXJjaCBsYWJvcmF0b3J5MRIw
+EAYDVQQDEwlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQTvFHx
+zkI5pdr9gedNA/09k51jztcyDBvB8xpDhPTF23nJfuU9rd7KZv31pxyAGCC2xrEY
+djAKP1+syqSQ1Iuwo4H3MIH0MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1Ud
+JQQMMAoGCCsGAQUFBwMCMCwGA1UdEQQlMCOCCWxvY2FsaG9zdIcEAAAAAIcQAAAA
+AAAAAAAAAAAAAAAAADCBlgYDVR0jBIGOMIGLoXOkcTBvMQswCQYDVQQGEwJVUzER
+MA8GA1UECBMITmV3IFlvcmsxETAPBgNVBAcTCEJyb29rbHluMSYwJAYDVQQKEx11
+Y3NwaS1zc2wgcmVzZWFyY2ggbGFib3JhdG9yeTESMBAGA1UEAxMJbG9jYWxob3N0
+ghR6aiojfLSZJr0Z7ohytByOTTtaQDAKBggqhkjOPQQDAgNIADBFAiBxTAjBKn4x
+qTNaksvagYXtdGY4+FvxVRzku7o+ToN2+wIhANOCUW+HsDIUHuDwjEPPHPIrynCp
+0yZVAJGUKYcGjT4+
+-----END CERTIFICATE-----
diff --git a/etc/chain4.pem b/etc/chain4.pem
new file mode 100644
index 0000000..e077b1f
--- /dev/null
+++ b/etc/chain4.pem
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIICwzCCAmmgAwIBAgIUN7BRYDaZRn7lfl1+YKNJkUjn94MwCgYIKoZIzj0EAwIw
+bjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxETAP
+BgNVBAMTCGxvb3BiYWNrMB4XDTIzMDkyMDA5MjAxMVoXDTI4MDgyNDA5MjAxMVow
+bjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxETAP
+BgNVBAMTCGxvb3BiYWNrMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEB8Bd3b6g
+C+BJ7scSs8A4RWIJEDIszPNUfe7WekTLeZQ+d0zotI662zN4L/4w347Np259Lltj
+scIAK21VW0A6cqOB5DCB4TAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNVHSUE
+DDAKBggrBgEFBQcDATAaBgNVHREEEzARhwR/AAABgglsb2NhbGhvc3QwgZUGA1Ud
+IwSBjTCBiqFypHAwbjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREw
+DwYDVQQHEwhCcm9va2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxh
+Ym9yYXRvcnkxETAPBgNVBAMTCGxvb3BiYWNrghQ3sFFgNplGfuV+XX5go0mRSOf3
+gzAKBggqhkjOPQQDAgNIADBFAiBufnYWcxTdLx+lq8G+53FGUML6XQD8CIwaDiLu
+2RRo7wIhAKf7UAarBn5jM43Pk/uMM7apYl26hJqwHxfWmSRg39nH
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICSjCCAfGgAwIBAgIUVEurfE97+agqBpy4eFwmRtox8mIwCgYIKoZIzj0EAwIw
+ezELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxHjAc
+BgNVBAMTFXVjc3BpLXNzbCByZXNlYXJjaCBjYTAeFw0yMzA5MjAwOTEwMzJaFw0z
+MzEwMTcwOTEwMzJaMHsxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazER
+MA8GA1UEBxMIQnJvb2tseW4xJjAkBgNVBAoTHXVjc3BpLXNzbCByZXNlYXJjaCBs
+YWJvcmF0b3J5MR4wHAYDVQQDExV1Y3NwaS1zc2wgcmVzZWFyY2ggY2EwWTATBgcq
+hkjOPQIBBggqhkjOPQMBBwNCAASLB+0+8+OjIMt8d9b3APWKJg2m/3Awz2i+yQbM
+ueuZcBl2iJ5ARw8SLdGP2HlXqD21S2Odky4n1tFyenAinFsxo1MwUTAdBgNVHQ4E
+FgQU1Oskvg3Ho/3cpocdtSzwMO9iclEwHwYDVR0jBBgwFoAU1Oskvg3Ho/3cpocd
+tSzwMO9iclEwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNHADBEAiBsFlRi
+cqi7FdZW3D/W/PGrJh746xrgyRl9xaUdRilroQIgJM49nsvckrAPw/2blYHBV/H8
+/RwE/Jr8CGVYICGy030=
+-----END CERTIFICATE-----
diff --git a/etc/chain6.pem b/etc/chain6.pem
new file mode 100644
index 0000000..a4e59fc
--- /dev/null
+++ b/etc/chain6.pem
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIICzzCCAnWgAwIBAgIUBtVH6POMnmJlLyH0MuUJvpKtTy8wCgYIKoZIzj0EAwIw
+bjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxETAP
+BgNVBAMTCGxvb3BiYWNrMB4XDTIzMDkyMDEzMDU1MloXDTI4MTIwMjEzMDU1Mlow
+bjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxETAP
+BgNVBAMTCGxvb3BiYWNrMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELAT3LgqE
+fyay4gJstMSag4n6qWIW+A4lTS2coTdKpDruQu+4MU/hlJTI8RvtYPwE7Qvn69uT
+rQUkOASI37tMMKOB8DCB7TAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNVHSUE
+DDAKBggrBgEFBQcDATAmBgNVHREEHzAdhxAAAAAAAAAAAAAAAAAAAAABgglsb2Nh
+bGhvc3QwgZUGA1UdIwSBjTCBiqFypHAwbjELMAkGA1UEBhMCVVMxETAPBgNVBAgT
+CE5ldyBZb3JrMREwDwYDVQQHEwhCcm9va2x5bjEmMCQGA1UEChMddWNzcGktc3Ns
+IHJlc2VhcmNoIGxhYm9yYXRvcnkxETAPBgNVBAMTCGxvb3BiYWNrghQG1Ufo84ye
+YmUvIfQy5Qm+kq1PLzAKBggqhkjOPQQDAgNIADBFAiEAhMpsgcfPqkPFz+OVfEOn
+CT6ateSu6FWl2j9uUzeV3OoCIDWDHBu9jp6M676IDqnBIwDTl+fK6s11AJuJLH+J
+yqzP
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICSzCCAfGgAwIBAgIUKjM6dgOseg8jOApc40PynXSdrpkwCgYIKoZIzj0EAwIw
+ezELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxHjAc
+BgNVBAMTFXVjc3BpLXNzbCByZXNlYXJjaCBjYTAeFw0yMzA5MjAxMzA0MzhaFw0z
+MzEwMTcxMzA0MzhaMHsxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazER
+MA8GA1UEBxMIQnJvb2tseW4xJjAkBgNVBAoTHXVjc3BpLXNzbCByZXNlYXJjaCBs
+YWJvcmF0b3J5MR4wHAYDVQQDExV1Y3NwaS1zc2wgcmVzZWFyY2ggY2EwWTATBgcq
+hkjOPQIBBggqhkjOPQMBBwNCAAR0h+MG7kShe0zK1NkT+tKKTAhChK4/+ZedwklI
+rQ89usIm3ygiRWN8/iix4ZAdM09iP7D/DARSC3Uba3J2oQAHo1MwUTAdBgNVHQ4E
+FgQUpTMM9BVbvRBqcaJ56wB3jHowNYMwHwYDVR0jBBgwFoAUpTMM9BVbvRBqcaJ5
+6wB3jHowNYMwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEAmVMK
+HF+yHIDABRcF93WWKIe9w9XKL7+kF15mrLtPaFACIDclKmIuXTGP13E6Tbk5a/gC
+WlB7yXQzEVckqSt6OTe2
+-----END CERTIFICATE-----
diff --git a/etc/dh2048.pem b/etc/dh2048.pem
new file mode 100644
index 0000000..74bf248
--- /dev/null
+++ b/etc/dh2048.pem
@@ -0,0 +1,8 @@
+-----BEGIN DH PARAMETERS-----
+MIIBCAKCAQEAqnI4e0GO/I2aCHDei9aycopVzMcfvf/JK4gcxrzvAbCfj6EwPYIc
+iJZB1+lkAvF3ab1EOgsxRdYB4Yq/s1ThM7H2oEH3yQqN20zPsF3M5neEHPJS0SBb
+hQPQchY3BFe8U4Y279FVLTC8G1zabBewRjLSiuUNIQKogbaFMtGco2HLbqDJ01kY
+DY95WDU7oSb2FPa7u8+rQUYLgR3fRjIXD35cDd/WeS8fUWidUhlR4X9K2AXq5d8s
+Ew1x3fPmwTNi1bP9438oMKPzrVpY9TsvEJMkOMYsfOJlL1dQ8Az/aKR+5oxYX3pm
+gUKBYrLHlbPtmW6a2UUWQCJIAJ/gcBBiywIBAg==
+-----END DH PARAMETERS-----
diff --git a/etc/localhost.pw b/etc/localhost.pw
new file mode 100644
index 0000000..c85ca4d
--- /dev/null
+++ b/etc/localhost.pw
Binary files differ
diff --git a/etc/localhost_cert.pem b/etc/localhost_cert.pem
new file mode 100644
index 0000000..3a72347
--- /dev/null
+++ b/etc/localhost_cert.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC2DCCAn6gAwIBAgIUemoqI3y0mSa9Ge6IcrQcjk07WkAwCgYIKoZIzj0EAwIw
+bzELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxEjAQ
+BgNVBAMTCWxvY2FsaG9zdDAeFw0yMzA5MjAxMzA2MjRaFw0yODEyMDIxMzA2MjRa
+MG8xCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazERMA8GA1UEBxMIQnJv
+b2tseW4xJjAkBgNVBAoTHXVjc3BpLXNzbCByZXNlYXJjaCBsYWJvcmF0b3J5MRIw
+EAYDVQQDEwlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQTvFHx
+zkI5pdr9gedNA/09k51jztcyDBvB8xpDhPTF23nJfuU9rd7KZv31pxyAGCC2xrEY
+djAKP1+syqSQ1Iuwo4H3MIH0MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1Ud
+JQQMMAoGCCsGAQUFBwMCMCwGA1UdEQQlMCOCCWxvY2FsaG9zdIcEAAAAAIcQAAAA
+AAAAAAAAAAAAAAAAADCBlgYDVR0jBIGOMIGLoXOkcTBvMQswCQYDVQQGEwJVUzER
+MA8GA1UECBMITmV3IFlvcmsxETAPBgNVBAcTCEJyb29rbHluMSYwJAYDVQQKEx11
+Y3NwaS1zc2wgcmVzZWFyY2ggbGFib3JhdG9yeTESMBAGA1UEAxMJbG9jYWxob3N0
+ghR6aiojfLSZJr0Z7ohytByOTTtaQDAKBggqhkjOPQQDAgNIADBFAiBxTAjBKn4x
+qTNaksvagYXtdGY4+FvxVRzku7o+ToN2+wIhANOCUW+HsDIUHuDwjEPPHPIrynCp
+0yZVAJGUKYcGjT4+
+-----END CERTIFICATE-----
diff --git a/etc/localhost_key.pem b/etc/localhost_key.pem
new file mode 100644
index 0000000..3a43e19
--- /dev/null
+++ b/etc/localhost_key.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,54AAA04CB6E610C382C85398143D9141
+
+OXjBuAb3HPOKmTMPbL6vTPgH/4U2JrSjpINRz2a36m8zrpNtWxR/afhuxEEjoOos
+eOi7VncvCBQmfPCkRQ9Qz2dBk4BIiLyKuHvnIfmjnwpMZNkcvGk0DxasL0pIB0AS
+OAhrQXlq/p+PFzQzbHJcwxKIcMZlHwZxYvBucxh/5OA=
+-----END EC PRIVATE KEY-----
diff --git a/etc/localhost_key.pem.plain b/etc/localhost_key.pem.plain
new file mode 100644
index 0000000..62cf3bb
--- /dev/null
+++ b/etc/localhost_key.pem.plain
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIEtSI0464/pczgdCvhrMkRw/wj3W3vw2RIUNgt6e0uT+oAoGCCqGSM49
+AwEHoUQDQgAEE7xR8c5COaXa/YHnTQP9PZOdY87XMgwbwfMaQ4T0xdt5yX7lPa3e
+ymb99accgBggtsaxGHYwCj9frMqkkNSLsA==
+-----END EC PRIVATE KEY-----
diff --git a/etc/rootCA_cert.pem b/etc/rootCA_cert.pem
new file mode 100644
index 0000000..ed02b49
--- /dev/null
+++ b/etc/rootCA_cert.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICSzCCAfGgAwIBAgIUKjM6dgOseg8jOApc40PynXSdrpkwCgYIKoZIzj0EAwIw
+ezELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhCcm9v
+a2x5bjEmMCQGA1UEChMddWNzcGktc3NsIHJlc2VhcmNoIGxhYm9yYXRvcnkxHjAc
+BgNVBAMTFXVjc3BpLXNzbCByZXNlYXJjaCBjYTAeFw0yMzA5MjAxMzA0MzhaFw0z
+MzEwMTcxMzA0MzhaMHsxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazER
+MA8GA1UEBxMIQnJvb2tseW4xJjAkBgNVBAoTHXVjc3BpLXNzbCByZXNlYXJjaCBs
+YWJvcmF0b3J5MR4wHAYDVQQDExV1Y3NwaS1zc2wgcmVzZWFyY2ggY2EwWTATBgcq
+hkjOPQIBBggqhkjOPQMBBwNCAAR0h+MG7kShe0zK1NkT+tKKTAhChK4/+ZedwklI
+rQ89usIm3ygiRWN8/iix4ZAdM09iP7D/DARSC3Uba3J2oQAHo1MwUTAdBgNVHQ4E
+FgQUpTMM9BVbvRBqcaJ56wB3jHowNYMwHwYDVR0jBBgwFoAUpTMM9BVbvRBqcaJ5
+6wB3jHowNYMwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEAmVMK
+HF+yHIDABRcF93WWKIe9w9XKL7+kF15mrLtPaFACIDclKmIuXTGP13E6Tbk5a/gC
+WlB7yXQzEVckqSt6OTe2
+-----END CERTIFICATE-----
diff --git a/man/Makefile b/man/Makefile
new file mode 100644
index 0000000..82c9f4e
--- /dev/null
+++ b/man/Makefile
@@ -0,0 +1,44 @@
+# Don't edit Makefile! Use ../conf-* for configuration.
+
+SHELL=/bin/sh
+
+default: one two
+
+https@.0: \
+https@.1
+ nroff -man https@.1 > https@.0
+
+sslcat.0: \
+sslcat.1
+ nroff -man sslcat.1 > sslcat.0
+
+sslclient.0: \
+sslclient.1
+ nroff -man sslclient.1 > sslclient.0
+
+sslconnect.0: \
+sslconnect.1
+ nroff -man sslconnect.1 > sslconnect.0
+
+sslhandle.0: \
+sslhandle.1
+ nroff -man sslhandle.1 > sslhandle.0
+
+sslserver.0: \
+sslserver.1
+ nroff -man sslserver.1 > sslserver.0
+
+clean: \
+TARGETS
+ rm -f `cat TARGETS`
+ gzip -q -d *.gz
+
+ucspi-tls.0: \
+ucspi-tls.2
+ nroff -man ucspi-tls.2 > ucspi-tls.0
+
+one: \
+https@.0 sslcat.0 sslclient.0 sslconnect.0 sslserver.0 sslhandle.0
+
+two: \
+ucspi-tls.0
diff --git a/man/Makefile.mandoc b/man/Makefile.mandoc
new file mode 100644
index 0000000..343da1b
--- /dev/null
+++ b/man/Makefile.mandoc
@@ -0,0 +1,44 @@
+# Don't edit Makefile! Use ../conf-* for configuration.
+
+SHELL=/bin/sh
+
+default: one two
+
+https@.0: \
+https@.1
+ mandoc -man https@.1 > https@.0
+
+sslcat.0: \
+sslcat.1
+ mandoc -man sslcat.1 > sslcat.0
+
+sslclient.0: \
+sslclient.1
+ mandoc -man sslclient.1 > sslclient.0
+
+sslconnect.0: \
+sslconnect.1
+ mandoc -man sslconnect.1 > sslconnect.0
+
+sslhandle.0: \
+sslhandle.1
+ mandoc -man sslhandle.1 > sslhandle.0
+
+sslserver.0: \
+sslserver.1
+ mandoc -man sslserver.1 > sslserver.0
+
+clean: \
+TARGETS
+ rm -f `cat TARGETS`
+ gzip -q -d *.gz
+
+ucspi-tls.0: \
+ucspi-tls.2
+ mandoc -man ucspi-tls.2 > ucspi-tls.0
+
+one: \
+https@.0 sslcat.0 sslclient.0 sslconnect.0 sslserver.0 sslhandle.0
+
+two: \
+ucspi-tls.0
diff --git a/man/TARGETS b/man/TARGETS
new file mode 100644
index 0000000..7bb7ddb
--- /dev/null
+++ b/man/TARGETS
@@ -0,0 +1,7 @@
+https@.0
+sslcat.0
+sslclient.0
+sslconnect.0
+sslhandle.0
+sslserver.0
+ucspi-tls.0
diff --git a/man/https@.1 b/man/https@.1
new file mode 100644
index 0000000..eccd29f
--- /dev/null
+++ b/man/https@.1
@@ -0,0 +1,57 @@
+.TH https@ 1
+.SH NAME
+https@ \- simple HTTPS client
+.SH SYNOPSIS
+.B https@
+.I host
+[
+.I page
+.I port
+.I args
+]
+.SH DESCRIPTION
+.B https@
+connects via the IP[v4|v6] protocol to
+.I host
+on
+.I port
+via TCP, and then attempts an SSL connection. It sends the request:
+
+.EX
+ GET /page HTTP/1.0
+ Host: host
+.EE
+
+and prints the body of the response, removing the CR from the end of each line.
+
+If
+.I port
+is not supplied,
+.B https@
+uses TCP port 443 (HTTPS).
+
+If
+.I page
+is not supplied,
+.B https@
+asks for / from
+.IR host .
+
+If
+.I host is not supplied,
+.B https@
+connects to the local host.
+
+If
+.I args
+are supplied, they are passed to
+.B https@
+unmodified.
+.SH SEE ALSO
+sslserver(1),
+sslclient(1),
+sslconnect(1),
+sslcat(1),
+tcp-environ(5).
+.SH REFERENCE
+http://httpd.apache.org/docs/2.4/mod/mod_ssl.html
diff --git a/man/sslcat.1 b/man/sslcat.1
new file mode 100644
index 0000000..786d80e
--- /dev/null
+++ b/man/sslcat.1
@@ -0,0 +1,48 @@
+.TH sslcat 1
+.SH sslcat
+sslcat \- simple ssl upload of a file with verbose output
+.SH SYNOPSIS
+.B sslcat
+[
+.I host
+.I port
+.I args
+]
+.SH DESCRIPTION
+.B sslcat
+connects via the IP[v4|v6] protocol to
+.I host
+on
+.I port
+via TCP, and then attempts an SSL connection while
+sending the data available on file descriptor 6
+to the server.
+It prints any data it receives.
+.B sslcat
+can be used to transfer binary data.
+It does no conversion other than SSL encoding and decoding.
+
+If
+.I port
+is not supplied,
+.B sslcat
+uses TCP port 443 (HTTPS).
+
+If
+.I host
+is not supplied,
+.B sslcat
+connects to the local host.
+
+If
+.I args
+are supplied, they are passed to
+.B sslclient
+unmodified.
+
+.SH SEE ALSO
+sslserver(1),
+sslclient(1),
+sslcat(1),
+https@(1),
+tcp-environ(5)
diff --git a/man/sslclient.1 b/man/sslclient.1
new file mode 100644
index 0000000..7ef0041
--- /dev/null
+++ b/man/sslclient.1
@@ -0,0 +1,254 @@
+.TH sslclient 1
+.SH NAME
+sslclient \- setup a TLS client connection
+.SH SYNOPSIS
+.B sslclient
+[
+.I opts
+]
+.I host
+.I port
+.I prog
+.SH DESCRIPTION
+.I opts
+is a series of getopt-style options,
+.I host
+is a host name for the client to connect to, and
+.I prog
+is one or more arguments specifying a program to run
+for each successful connection.
+
+.B sslclient
+attempts to connect to a TCP server at
+.I host
+.IR port .
+The server's address is given by
+.I host
+and
+.IR port .
+.I host
+may be
+.IR 0 ,
+which is identical to
+.IR 127.0.0.1 ,
+or
+.IR ::1
+referring to the IPv6 loopback address,
+a compactified IPv6 address,
+a dotted-decimal IPv4 address,
+or a host name.
+If a host name is given,
+.B sslclient
+facilitates a DNS lookup and tries each address in turn.
+
+If the connection succeeds,
+.B sslclient
+runs
+.IR prog ,
+with file descriptors 6 and 7 reading from and
+writing to a child process ssl.
+The ssl process attempts an SSL connect via the network.
+If it succeeds, it translates data between
+.I prog
+and the network, performing any necessary SSL encoding and decoding.
+
+Before running
+.I prog,
+.B sslclient
+sets certain environment variables.
+.SH OPTIONS
+.B General Options:
+.TP
+.B \-q
+Quiet. Do not print error messages.
+.TP
+.B \-Q
+(Default.) Print error messages.
+.TP
+.B \-v
+Verbose. Print error messages and status messages.
+.P
+.B Connection options:
+.TP
+.B \-4
+Use IPv4 sockets for connections and DNS queries.
+.TP
+.B \-6
+Force IPv6 mode for connections and set up in UCSPI environment variables.
+.TP
+.B \-T \fIx+y
+Give up on the connection attempt or SSL connection attempt after
+.I x+y
+seconds. The default value is: 2+58. When a
+.I host
+has several IP addresses,
+.B sslclient
+tries to connect to the first IP address, waits
+.I x
+seconds, tries to connect to the second IP address, waits
+- Ix
+seconds, etc.; then it retries each address that timed out, waiting
+.I y
+seconds per address. You may omit
+.I +y
+to skip the second try.
+.TP
+.B \-i \fIlocalip
+Use
+.I localip
+as the IP address for the local side of the connection; quit if
+.I localip
+is not available. Normally
+.B sslclient
+lets the operating system choose an address.
+.TP
+.B \-p \fIlocalport
+Use
+.I localport
+as the TCP port for the local side of the connection; quit if
+.I localport
+is not available. Normally
+.B sslclient
+lets the operating system choose a port.
+.TP
+.B \-d
+Delay sending data for a fraction of a second whenever
+the remote host is responding slowly.
+This is currently the default, but it may not be in the future;
+if you want it, set it explicitly.
+.TP
+.B \-D
+Never delay sending data; enable TCP_NODELAY.
+.TP
+.B \-I \fIifname
+Use
+.I ifname
+as the local network interface. This is only defined for IPv6 sockets
+and needed if you use link-local IPv6 addresses.
+.TP
+.B \-M
+(Default.) No Server Name Indications are present.
+.TP
+.B \-m
+Employ Server Name Indication (SNI) for
+the given
+.I hostname
+in the Client Helo.
+
+\fINote\fR: You can use \fIDNSCACHEIP\fR to set the DNS resolver IP dynamically.
+
+.P
+.B X509 certificate handling:
+.TP
+.B \-3
+Read a null-terminated
+.I key password
+from file descriptor 3.
+.TP
+.B \-a \fIcafile
+Override the compiled-in CA file name.
+The CA file contains the list of CAs used to verify the server certificate.
+.TP
+.B \-A \fIcadir
+Override the compiled-in CA directory name.
+The CA directory contains certificates files used
+to verify the client certificate. This list augments the list from
+.I \-a \fIcafile.
+.TP
+.B \-c \fIcertfile
+Use the client certificate in
+.IR certfile .
+.TP
+.B \-k \fIkeyfile
+Use the client certificate key in
+.IR keyfile .
+.TP
+.B \-V \fIverifydepth
+Verify the server certificate chain to depth
+.IR verifydepth .
+The default value is 1.
+.TP
+.B \-z \fIciphers
+Use the cipher list specified in
+.IR ciphers .
+.TP
+.B \-x
+(Default.) Verify the server certificate.
+.TP
+.B \-X
+Do not verify the server certificate.
+.TP
+.B \-n
+(Default.) Verify that the server host name matches
+the FQDN provided in the certificate.
+.TP
+.B \-N
+Do not verify that the server host name matches
+the FQDN provided in the certificate.
+.P
+.B Data-gathering options:
+.TP
+.B \-h
+(Default.) Look up the remote host name in DNS
+to set the environment variable $SSLREMOTEHOST.
+.TP
+.B \-H
+Do not look up the remote host name in DNS;
+remove the environment variable $SSLREMOTEHOST.
+.TP
+.B \-l \fIlocalname
+Do not look up the local host name in DNS; use
+.I localname
+for the environment variable $SSLLOCALHOST.
+A common choice for
+.I localname
+is
+.I 0
+or
+.IR :: .
+.TP
+.B \-r
+Attempt to obtain $SSLREMOTEINFO from the remote host.
+.TP
+.B \-R
+(Default.) Do not attempt to obtain $SSLREMOTEINFO from the remote host.
+.TP
+.B \-t \fIn
+Give up on the $SSLREMOTEINFO connection attempt after
+.I n
+seconds. The default value is: 26.
+.TP
+.B \-w \fIn
+Give up on a connection or program after waiting
+.I n
+seconds for read or write. The default value is: 3600.
+.TP
+.B \-s
+Store client and server certificate information in the environment, a la mod_ssl.
+.TP
+.B \-S
+(Default.) Do not store client and server certificate information in the environment.
+.TP
+.B \-e
+Set protocol environment a la
+.BR tcpserver .
+Set $PROTO, $TCPLOCALIP, $TCPLOCALPORT, $TCPLOCALHOST, $TCPREMOTEIP,
+$TCPREMOTEPORT, $TCPREMOTEHOST, and $TCPREMOTEINFO
+from the corresponding $SSL variables.
+.TP
+.B \-E
+(Default.) Do not set any
+.B tcpserver
+environment variables.
+.SH SEE ALSO
+sslserver(1),
+sslhandle(1),
+sslconnect(1),
+sslcat(1),
+https@(1),
+ucspi-tls(2),
+tcpclient(1),
+tcpserver(1),
+tcp-environ(5).
+.SH REFERENCE
+http://httpd.apache.org/docs/2.4/mod/mod_ssl.html
diff --git a/man/sslconnect.1 b/man/sslconnect.1
new file mode 100644
index 0000000..9888e23
--- /dev/null
+++ b/man/sslconnect.1
@@ -0,0 +1,55 @@
+.TH sslconnect 1
+.SH sslconnect
+sslconnect \- simple sslclient with verbose output
+.SH SYNOPSIS
+.B sslconnect
+[
+.I host
+.I port
+.I args
+]
+.SH DESCRIPTION
+.B sslconnect
+connects via the IP[v4|v6] protocol to
+.I host on
+.I port
+using TCP, and attempts an SSL connection.
+It sends its standard input to the server,
+printing a CR after each LF, and prints any data
+it receives from the server to standard output.
+.B sslconnect
+can be used to fetch binary data.
+It does no conversion other than SSL encoding
+and decoding on received data.
+
+If
+.I host
+is not supplied,
+.B sslconnect
+connects to the local host.
+
+If
+.I port
+is not supplied,
+.B sslconnect
+uses TCP port 465 (SMTPS) and thus is
+complementary to
+.BR mconnect .
+
+If
+.I args
+are supplied, they are passed to
+.B sslclient
+unmodified.
+
+Unlike a standard SMTP(S) client,
+.B sslconnect
+does not perform a DNS MX lookup,
+thus the FQDN or IP rof the MTA must be specified.
+.SH SEE ALSO
+sslserver(1),
+sslhandle(1),
+sslclient(1),
+sslcat(1),
+https@(1),
+tcp-environ(5)
diff --git a/man/sslhandle.1 b/man/sslhandle.1
new file mode 100644
index 0000000..8ca1b1f
--- /dev/null
+++ b/man/sslhandle.1
@@ -0,0 +1,578 @@
+.TH sslhandle 1
+.SH NAME
+sslhandle \- preforking TLS server
+.SH SYNOPSIS
+.B sslhandle
+[
+.I opts
+]
+.I host
+.I port
+.I prog
+.SH DESCRIPTION
+.I opts
+is a series of getopt-style options,
+.I host
+is a host name or IP address,
+.I port
+is a TCP port, and
+.I prog
+is one or more arguments specifying a program
+to run for each accepted connection.
+The
+.I server
+subroutine is called within a loop, with one iteration per request
+listening to
+.I \-c \fIn
+incoming connections simultanously.
+It must release any resources allocated to handle a particular request before returning to its caller.
+
+The server's address is given by
+.I host
+and
+.IR port .
+
+.SH BINDINGS
+.B sslhandle
+will be attached to the primary IP address of
+.I host
+while the host name is fed through qualification using
+.IR dns_ip6_qualify .
+If
+.I host
+is given as dotted decimal IPv4 or compactified IPv6
+address,
+.B sslhandle
+will bind uniquely to those. In order to bind
+.B sslhandle
+to a LLU IPv6 address (ie. fe80::a:b:c) additionally the interface name
+.B \-I\fIifname
+has to be provided.
+
+\fINote\fR: The kernel might use temporary changing SLAAC addresses.
+
+.B sslhandle
+can be instructed to be multi-homing capable while binding
+to all available IP addresses. Now
+.I host
+is given as
+.I 0.0.0.0
+or
+.IR :: .
+
+Further,
+.B sslhandle
+can be forced to provide dual-stack capabilities, thus allowing
+IPv4 and IPv6 clients to attach to the same instance once
+.I host
+equals ':0' as pseudo IP address.
+
+.I port
+may be a numeric port number
+or a port name. If
+.I port
+is 0,
+.B sslhandle
+will choose a free port.
+
+.SH SERVING
+.B sslhandle
+listens for connections from TCP clients.
+Typically, for each connection, it runs
+.IR prog ,
+with file descriptor 0 reading from,
+and file descriptor 1 writing to a child process
+.IR ssl .
+The
+.I ssl
+process attempts an SSL accept via the network.
+If it succeeds, it translates data between
+.I prog
+and the network, performing any necessary SSL encoding and decoding.
+Before running
+.IR prog ,
+.B sslhandle
+reads and sets certain environment variables.
+
+.B sslhandle
+exists, if the parent process receives a SIGTERM.
+.SH OPTIONS
+.B General Options:
+.TP
+.B \-q
+Quiet. Do not print error messages.
+.TP
+.B \-Q
+(Default.) Print error messages.
+.TP
+.B \-v
+Verbose. Print error messages and status messages.
+.TP
+.B \-V
+Print additional verbose SSL connection informations (protocol and cipher).
+
+.P
+.B Connection options:
+.TP
+.B \-1
+After preparing to receive connections,
+print the local port number to standard output.
+.TP
+.B \-4
+Use IPv4 sockets for connections.
+.TP
+.B \-6
+Use IPv6 connections. This will set \fIPROTO\fR to \fBTCP6\fR and put
+IPv6 addresses in \fITCP6LOCALIP\fR and \fITCP6REMOTEIP\fR.
+.TP
+.B \-c \fIn
+Do not handle more than
+.I n
+simultaneous connections.
+If there are
+.I n
+simultaneous connections copies of
+.I prog
+running, defer acceptance of a new connection until one copy finishes.
+.I n
+must be a positive integer. The default value is 40.
+.TP
+.B \-x \fIcdb
+Follow the rules compiled into
+.I cdb
+by
+.BR tcprules .
+These rules may specify setting environment variables
+or rejecting connections from bad sources.
+You can rerun
+.B tcprules
+to change the rules while
+.B sslhandle
+is running.
+.TP
+.B \-X
+With
+.B \-x \fIcdb,
+allow connections even if
+.B \-I cdb
+does not exist. Normally
+.B sslhandle
+will drop the connection if
+.I cdb
+does not exist.
+.TP
+.B \-B \fIbanner
+Write
+.I banner
+to the network immediately after each SSL connection is made. The
+.I banner
+is subject to SSL encryption.
+.TP
+.B \-f \fIlockfile
+Additional filename given for locking. If
+.I lockfile
+is provided and not exclusive readable
+.B sslhandle
+will not start.
+Utilize this option if your accept system call suffers from the thundering herd problem.
+.TP
+.B \-g \fIgid
+Switch group ID to
+.I gid
+after preparing to receive connections.
+.I gid
+must be a positive integer.
+.TP
+.B \-u \fIuid
+Switch user ID to
+.I uid
+after preparing to receive connections.
+.I uid
+must be a positive integer.
+.TP
+.B \-U
+Same as
+.B \-g
+$GID
+.B \-u
+$UID. Typically, $GID and $UID are set by
+.BR envuidgid .
+.TP
+.B \-I \fIifname
+Bind to the network interface
+.I ifname
+("eth0" on Linux, for example). This is only defined and needed for
+IPv6 link-local addresses.
+.TP
+.B \-b \fIn
+Allow a backlog of approximately
+.I n
+pending connections.
+.TP
+.B \-o
+Leave IP options alone. If the client is sending packets
+along an IP source route, send packets back along the same route.
+.TP
+.B \-O
+(Default.) Kill IP options.
+A client can still use source routing to connect and to send data,
+but packets will be sent back along the default route.
+.TP
+.B \-d
+Delay sending data for a fraction of a second whenever the
+remote host is responding slowly. This is currently the default,
+but it may not be in the future; if you want it, set it explicitly.
+.TP
+.B \-D
+Never delay sending data; enable TCP_NODELAY.
+.TP
+.B \-t \fIn
+Give up on the $SSLREMOTEINFO connection attempt after
+.I n
+seconds. The default value is: 26.
+.TP
+.B \-T \fIn
+Give up on the SSL connection attempt after
+.I n
+seconds. The default value is: 26.
+.TP
+.B \-w \fIn
+Give up on a connection or program after waiting
+.I n
+seconds for read or write. The default value is: 3600.
+
+.P
+.B SSL and TLS connection options:
+.TP
+.B \-s
+Store client and server certificate information in the environment, a la
+.IR mod_ssl .
+.TP
+.B \-S
+(Default.) Do not store client and server certificate information in the environment.
+
+.P
+.B X509 certificate and encryption options:
+.TP
+.B \-3
+Read a null-terminated
+.I key password
+from file descriptor
+.IR 3 .
+.TP
+.B \-m
+(Mail.) Require valid client certificates, but don't check for matching FQDN.
+.TP
+.B \-z
+(Host.) Require valid client certificates and match FQDN (if given) against SAN/DN.
+.TP
+.B \-Z
+(Default.) Do not require client certificates.
+
+.P
+.B Data-gathering options:
+.TP
+.B \-h
+(Default.) Look up the remote host name in DNS to set the
+environment variable $SSLREMOTEHOST.
+In this case, additionally the CN/SAN in the X509 certificate can be
+checked, provided, the option
+.B \-z
+is set.
+.TP
+.B \-H
+Do not look up the remote host name in DNS;
+remove the environment variable $SSLREMOTEHOST.
+To avoid loops, you must use this option for servers on TCP port 53.
+.TP
+.B \-p
+Paranoid. After looking up the remote host name in DNS,
+look up the IP addresses in DNS for that host name,
+and remove the environment variable $SSLREMOTEHOST
+if none of the addresses match the client's IP address.
+.TP
+.B \-P
+(Default.) Not paranoid.
+.TP
+.B \-l \fIlocalname
+Do not look up the local host name in DNS; use
+.I localname
+for the environment variable $SSLLOCALHOST.
+A common choice for
+.I localname
+is 0. To avoid loops, you must use this option for servers on TCP port 53.
+.TP
+.B \-r
+Attempt to obtain $SSLREMOTEINFO from the remote host.
+.TP
+.B \-R
+(Default.) Do not attempt to obtain $SSLREMOTEINFO from the remote host.
+To avoid loops, you must use this option for servers on TCP ports 53 and 113.
+.TP
+.B \-e
+Set protocol environment a la
+.B tcpserver .
+Set $TCPLOCALIP, $TCPLOCALPORT, $TCPLOCALHOST, $TCPREMOTEIP,
+$TCPREMOTEPORT, $TCPREMOTEHOST, and $TCPREMOTEINFO as well as for IPv6
+connections additionally $TCP6REMOTEIP, $TCP6RMEOTEHOST, and $TCP6REMOTEINFO
+from the current $SSL environment (see below).
+.TP
+.B \-E
+(Default.) Do not set any
+.B tcpserver
+environment variables.
+.SH "DNS RESOLVER SETTINGS"
+Use \fI$DNSCACHEIP\fR to set the DNS resolver IP dynamically
+irrespectively from the settings in
+.IR /etc/resolv.conf .
+If the environment variable \fI$LOCALDOMAIN\fR is populated,
+this name will be appended to unqualified host names.
+Additional rewriting of local to public names is facilitated
+in case the file
+.I /etc/dnswritefile
+exists and is populated, or alternatively the environment
+variable \fI$DNSREWRITEFILE\fR points to a differnent file.
+.SH "SSL ENVIRONMENT VARIABLES READ"
+These variables define the run-time environment of
+.B sslhandle
+and are used to specify X509 certificates and keyfile per connection.
+.TP
+.B $SSL_USER=\fIname
+The user, reading the certificates and keyfile.
+.TP
+.B $SSL_GROUP=\fIgroup
+The respective user group.
+.TP
+.B $SSL_UID=\fIuid
+The numerical UID of the $SSL_USER.
+.TP
+.B $SSL_CHROOT=\fIpath
+Perform reading of certificates and keyfile in a $SSL_CHROOT jail.
+.TP
+.B $CAFILE=\fIpath
+If set, overrides the compiled-in CA file name.
+The CA file contains the list of CAs used to verify the client certificate.
+Certificates in $CAFILE are processed when the server starts.
+.TP
+.B $CADIR=\fIpath
+If set, overrides the compiled-in CA directory name.
+The CA directory contains certificates files used to verify the client certificate.
+This list augments the list from $CAFILE.
+Certificates in $CADIR are processed during certificate verification.
+.TP
+.B $CERTFILE=\fIpath
+If set, overrides the compiled-in certificate file name.
+The server presents this certificate to clients.
+.TP
+.B $CERTCHAINFILE=\fIpath
+If set, overrides the compiled-in certificate chainfile name.
+The server presents this list of certificats to clients.
+.I Note:
+Providing $CERTCHAINFILE has precedence over $CERTFILE.
+Certificates in this file needs to be 'ordered' starting from the
+uppermost root certificates and placing your host's certificate at the end.
+.TP
+.B $CIPHERS=\fIstring
+If set, override the compiled-in SSL cipher list
+defining the security level for the connection.
+A typical choice would be 'TLSv1+HIGH:!SSLv2:!MD5'.
+.TP
+.B $DHFILE=\fIpath
+If set, overrides the compiled-in DH parameter file name.
+.TP
+.B $KEYFILE=\fIpath
+If set, overrides the compiled-in key file name.
+The key is used when loading the server certificate.
+Setting $KEYFILE to the empty instructs the server
+not to use a
+.I keyfile
+when loading it's certificate.
+.TP
+.B $VERIFYDEPTH=\fIn
+If set, overrides the compiled-in verification depth. Default: 1.
+.TP
+.B $CCAFILE=\fIpath
+If set, overrides the compiled-in client CA file name for client certificate request.
+The client CA file contains the list of CAs sent to the client
+when requesting a client certificate.
+.I Note:
+Setting of $CCAFILE is required while using the option
+.IR \-z
+or
+.IR \-m.
+However, declaring
+.B $CCAFILE="-"
+disables (on a per-connection base) the client certificate request.
+.TP
+.B $CCAVERIFY
+If set,
+.B sslhandle
+requests a valid client certificate on a per-connection base, unlike the general
+option
+.IR \-z .
+.SH "SSL ENVIRONMENT VARAIBLES SET"
+In case
+.B sslhandle
+is called with the option
+.BR \-e ,
+the following
+.I mod_ssl
+environment variables are provided:
+.TP
+.B SSL_PROTOCOL
+The TLS protocol version (SSLv3, TLSv1, ...).
+.TP
+.B SSL_SESSION_ID
+The hex-encoded SSL session id.
+.TP
+.B SSL_CIPHER
+The cipher specification name.
+.TP
+.B SSL_CIPHER_USEKEYSIZE
+Number of cipher bits (actually used).
+.TP
+.B SSL_CIPHER_ALGKEYSIZE
+Number of cipher bits (possible).
+.TP
+.B SSL_VERSION_INTERFACE
+The mod_ssl program version.
+.TP
+.B SSL_VERSION_LIBRARY
+The OpenSSL program version.
+.TP
+.B SSL_CLIENT_M_VERSION
+The version of the client certificate.
+.TP
+.B SSL_CLIENT_M_SERIAL
+The serial of the client certificate.
+.TP
+.B SSL_CLIENT_S_DN
+Subject DN in client's certificate.
+.TP
+.B SSL_CLIENT_S_DN_x509
+Component of client's Subject DN.
+.TP
+.B SSL_CLIENT_I_DN
+Issuer DN of client's certificate.
+.TP
+.B SSL_CLIENT_I_DN_x509
+Component of client's Issuer DN.
+.TP
+.B SSL_CLIENT_V_START
+Validity of client's certificate (start time).
+.TP
+.B SSL_CLIENT_V_END
+Validity of client's certificate (end time).
+.TP
+.B SSL_CLIENT_A_SIG
+Algorithm used for the signature of client's certificate.
+.TP
+.B SSL_CLIENT_A_KEY
+Algorithm used for the public key of client's certificate.
+.TP
+.B SSL_CLIENT_CERT
+PEM-encoded client certificate.
+.TP
+.B SSL_CLIENT_CERT_CHAIN \fIn
+PEM-encoded certificates in client certificate chain.
+.TP
+.B SSL_CLIENT_VERIFY
+NONE, SUCCESS, GENEROUS or FAILED:reason.
+.TP
+.B SSL_SERVER_M_SERIAL
+The serial of the server certificate.
+.TP
+.B SSL_SERVER_S_DN
+Subject DN in server's certificate.
+.TP
+.B SSL_SERVER_S_DN_x509
+Component of server's Subject DN.
+.TP
+.B SSL_SERVER_I_DN
+Issuer DN of server's certificate.
+.TP
+.B SSL_SERVER_I_DN_x509
+Component of server's Issuer DN.
+.TP
+.B SSL_SERVER_V_START
+Validity of server's certificate (start time).
+.TP
+.B SSL_SERVER_V_END
+Validity of server's certificate (end time).
+.TP
+.B SSL_SERVER_A_SIG
+Algorithm used for the signature of server's certificate.
+.TP
+.B SSL_SERVER_A_KEY
+Algorithm used for the public key of server's certificate.
+.TP
+.B SSL_SERVER_CERT
+PEM-encoded server certificate.
+.P
+For $SSL_CLIENT_x_DN_x509 and $SSL_SERVER_x_DN_x509,
+x509 denotes a component of the DN:
+C, ST, L, O, OU, CN, T, I, G, S, D, UID, Email.
+
+.P
+Other SSL environment variables set:
+.P
+.BR PROTO,
+.BR SSLLOCALHOST,
+.BR SSLLOCALIP,
+.BR SSLLOCALPORT,
+.BR SSLREMOTEHOST,
+.BR SSLREMOTEINFO,
+.BR SSLREMOTEIP,
+.BR SSLREMOTEPORT.
+
+.P
+TCP environment variables set:
+.P
+.BR TCPLOCALHOST,
+.BR TCPLOCALIP,
+.BR TCPLOCALPORT,
+.BR TCPREMOTEHOST,
+.BR TCPREMOTEINFO,
+.BR TCPREMOTEIP,
+.BR TCPREMOTEPORT.
+
+.P
+TCP6 environment variables set:
+.P
+.BR TCP6INTERFACE,
+.BR TCP6LOCALHOST,
+.BR TCP6LOCALIP,
+.BR TCP6LOCALPORT,
+.BR TCP6REMOTEHOST,
+.BR TCP6REMOTEIP,
+.BR TCP6REMOTEPORT.
+.SH "LOGGING AND ERROR MESSAGES"
+.B sslhandle
+prints information about individual connections
+in case
+.I -v
+or
+.I -V
+is specified as argument.
+TLS error messages are provided if possible:
+.TP
+.B unable to speak TLS for pid: ... DH lib
+TLS handshake failure.
+.TP
+.B unable to accept TLS for pid: ...
+The remote socket was prematurely closed.
+.P
+.SH "SEE ALSO"
+sslserver(1),
+sslclient(1),
+sslconnect(1),
+sslcat(1),
+https@(1),
+ucspi-tls(2),
+tcprules(1),
+tcprulescheck(1),
+tcpserver(1),
+tcp-environ(5)
+.SH REFERENCE
+http://httpd.apache.org/docs/2.4/mod/mod_ssl.html
+http://www.superscript.com/ucspi-ssl/prefork.html
diff --git a/man/sslserver.1 b/man/sslserver.1
new file mode 100644
index 0000000..2d31845
--- /dev/null
+++ b/man/sslserver.1
@@ -0,0 +1,657 @@
+.TH sslserver 1
+.SH NAME
+sslserver \- accept TLS connections and setup SSL CTX
+.SH SYNOPSIS
+.B sslserver
+[
+.I opts
+]
+.I host
+.I port
+.I prog
+.SH DESCRIPTION
+.I opts
+is a series of getopt-style options,
+.I host
+is a host name or IP address,
+.I port
+is a TCP port, and
+.I prog
+is one or more arguments specifying a program
+to run for each accepted connection.
+
+The server's address is given by
+.I host
+and
+.IR port .
+.SH BINDINGS
+.B sslserver
+will be attached to the primary IP address of
+.I host
+while the host name is fed through qualification using
+.IR dns_ip6_qualify .
+If
+.I host
+is given as dotted decimal IPv4 or compactified IPv6
+address,
+.B sslserver
+will bind uniquely to those. In order to bind
+.B sslserver
+to a LLU IPv6 address (ie. fe80::a:b:c) additionally the interface name
+.B \-I\fIifname
+has to be provided.
+
+\fINote\fR: The kernel might use temporary changing SLAAC addresses.
+
+.B sslserver
+can be instructed to be multi-homing capable while binding
+to all available IP addresses. Now
+.I host
+is given as
+.I 0.0.0.0
+or
+.IR :: .
+
+Further,
+.B sslserver
+can be forced to provide dual-stack capabilities, thus allowing
+IPv4 and IPv6 clients to attach to the same instance once
+.I host
+equals ':0' as pseudo IP address.
+
+.I port
+may be a numeric port number
+or a port name. If
+.I port
+is 0,
+.B sslserver
+will choose a free port.
+.SH SERVING
+.B sslserver
+listens for connections from TCP clients.
+Typically, for each connection, it runs
+.IR prog ,
+with file descriptor 0 reading from,
+and file descriptor 1 writing to a child process
+.IR ssl .
+If however
+.B sslserver
+is called with the option
+.IR \-n ,
+it communcates with
+.I prog
+on mutually chosen, arbitrary file descriptors.
+.I prog
+needs to support the UCSPI-TLS API.
+The
+.I ssl
+process attempts an SSL accept via the network.
+If it succeeds, it translates data between
+.I prog
+and the network, performing any necessary SSL encoding and decoding.
+Before running
+.IR prog ,
+.B sslserver
+reads and sets certain environment variables.
+
+.B sslserver
+exits when it receives SIGTERM.
+.SH OPTIONS
+.B General Options:
+.TP
+.B \-q
+Quiet. Do not print error messages.
+.TP
+.B \-Q
+(Default.) Print error messages.
+.TP
+.B \-v
+Verbose. Print error and status messages.
+.TP
+.B \-V
+Print additional verbose SSL connection informations (protocol and cipher).
+
+.P
+.B Connection options:
+.TP
+.B \-1
+After preparing to receive connections,
+print the local port number to standard output.
+.TP
+.B \-4
+Use IPv4 sockets for connections.
+.TP
+.B \-6
+Use IPv6 connections. This will set \fIPROTO\fR to \fBTCP6\fR and put
+IPv6 addresses in \fITCP6LOCALIP\fR and \fITCP6REMOTEIP\fR.
+.TP
+.B \-c \fIn
+Do not handle more than
+.I n
+simultaneous connections.
+If there are
+.I n
+simultaneous connections copies of
+.I prog
+running, defer acceptance of a new connection until one copy finishes.
+.I n
+must be a positive integer. The default value is 40.
+.TP
+.B \-x \fIcdb
+Follow the rules compiled into
+.I cdb
+by
+.BR tcprules .
+These rules may specify setting environment variables
+or rejecting connections from bad sources.
+You can rerun
+.B tcprules
+to change the rules while
+.B sslserver
+is running.
+.TP
+.B \-X
+With
+.B \-x \fIcdb,
+allow connections even if
+.I cdb
+does not exist. Normally
+.B sslserver
+will drop the connection if
+.I cdb
+does not exist.
+.TP
+.B \-y \fIcdb
+Evaluate and follow IP rules compiled into
+.I cdb
+prior of doing a \fIDNS\fR or \fIIDENT\fR lookup.
+A shared \fIcdb\fR is possible.
+.TP
+.B \-B \fIbanner
+Write
+.I banner
+to the network immediately after each SSL connection is made. The
+.I banner
+is subject to SSL encryption.
+.TP
+.B \-g \fIgid
+Switch group ID to
+.I gid
+after preparing to receive connections.
+.I gid
+must be a positive integer.
+.TP
+.B \-u \fIuid
+Switch user ID to
+.I uid
+after preparing to receive connections.
+.I uid
+must be a positive integer.
+.TP
+.B \-U
+Same as
+.B \-g
+$GID
+.B \-u
+$UID. Typically, $GID and $UID are set by
+.BR envuidgid .
+.TP
+.B \-I \fIifname
+Bind to the network interface
+.I ifname
+("eth0" on Linux, for example). This is only defined and needed for
+IPv6 link-local addresses.
+.TP
+.B \-b \fIn
+Allow a backlog of approximately
+.I n
+pending connections.
+.TP
+.B \-o
+Leave IP options alone. If the client is sending packets
+along an IP source route, send packets back along the same route.
+.TP
+.B \-O
+(Default.) Kill IP options.
+A client can still use source routing to connect and to send data,
+but packets will be sent back along the default route.
+.TP
+.B \-d
+Delay sending data for a fraction of a second whenever the
+remote host is responding slowly. This is currently the default,
+but it may not be in the future; if you want it, set it explicitly.
+.TP
+.B \-D
+Never delay sending data; enable TCP_NODELAY.
+.TP
+.B \-t \fIn
+Give up on the $SSLREMOTEINFO connection attempt after
+.I n
+seconds. The default value is: 26.
+.TP
+.B \-T \fIn
+Give up on the SSL connection attempt after
+.I n
+seconds. The default value is: 26.
+.TP
+.B \-w \fIn
+Give up on a connection or program after waiting
+.I n
+seconds for read or write. The default value is: 3600.
+
+.P
+.B SSL and TLS connection options:
+.TP
+.B \-n
+Delay setup of SSL environment until a STARTTLS/STLS command
+has been issued by the client.
+.TP
+.B \-N
+(Default.) Setup the SSL environment immediately.
+.TP
+.B \-s
+Store client and server certificate information in the environment, a la
+.IR mod_ssl .
+.TP
+.B \-S
+(Default.) Do not store client and server certificate information in the environment.
+
+.P
+.B X509 certificate and encryption options:
+.TP
+.B \-3
+Read a null-terminated
+.I key password
+from file descriptor
+.IR 3 .
+.TP
+.B \-m
+(Mail.) Require valid client certificates, but don't check for matching FQDN.
+.TP
+.B \-z
+(Host.) Require valid client certificates and match FQDN (if given) against SAN/DN.
+.TP
+.B \-Z
+(Default.) Do not require client certificates.
+
+.P
+.B Data-gathering options:
+.TP
+.B \-h
+(Default.) Look up the remote host name in DNS to set the
+environment variable $SSLREMOTEHOST.
+In this case, additionally the CN/SAN in the X509 certificate can be
+checked, provided, the option
+.B \-z
+is set.
+.TP
+.B \-H
+Do not look up the remote host name in DNS;
+remove the environment variable $SSLREMOTEHOST.
+To avoid loops, you must use this option for servers on TCP port 53.
+.TP
+.B \-p
+Paranoid. After looking up the remote host name in DNS,
+look up the IP addresses in DNS for that host name,
+and remove the environment variable $SSLREMOTEHOST
+if none of the addresses match the client's IP address.
+.TP
+.B \-P
+(Default.) Not paranoid.
+.TP
+.B \-l \fIlocalname
+Do not look up the local host name in DNS; use
+.I localname
+for the environment variable $SSLLOCALHOST.
+A common choice for
+.I localname
+is 0. To avoid loops, you must use this option for servers on TCP port 53.
+.TP
+.B \-r
+Attempt to obtain $SSLREMOTEINFO from the remote host.
+.TP
+.B \-R
+(Default.) Do not attempt to obtain $SSLREMOTEINFO from the remote host.
+To avoid loops, you must use this option for servers on TCP ports 53 and 113.
+.TP
+.B \-e
+Set protocol environment a la
+.B tcpserver .
+Set $TCPLOCALIP, $TCPLOCALPORT, $TCPLOCALHOST, $TCPREMOTEIP,
+$TCPREMOTEPORT, $TCPREMOTEHOST, and $TCPREMOTEINFO as well as for IPv6
+connections additionally $TCP6LOCALIP, $TCP6LOCALPORT, $TCP6LOCALHOST
+together with $TCP6REMOTEIP, $TCP6REMOTEPORT, $TCP6RMEOTEHOST and
+$TCP6INTERFACE from the current $SSL environment (see below).
+.TP
+.B \-E
+(Default.) Do not set any
+.B tcpserver
+environment variables.
+.SH "DNS RESOLVER SETTINGS"
+Use \fI$DNSCACHEIP\fR to set the DNS resolver IP dynamically
+irrespectively from the settings in
+.IR /etc/resolv.conf .
+If the environment variable \fI$LOCALDOMAIN\fR is populated,
+this name will be appended to unqualified host names.
+Additional rewriting of local to public names is facilitated
+in case the file
+.I /etc/dnswritefile
+exists and is populated, or alternatively the environment
+variable \fI$DNSREWRITEFILE\fR points to a differnent file.
+.SH "ENVIRONMENT VARIABLES READ"
+.B sslserver
+acknowledges the environment variable
+.I MAXCONIP="n"
+where
+.I n
+is the number of
+.B sslserver
+children spawned for a particular remote IP address.
+.I n
+is restricted to the general connection limit
+.I c
+provided as call argument.
+.I MAXCONIP
+is typically defined in
+.BR sslserver 's
+cdb for a given condition and thus only active meeting those.
+.I MAXCONIP
+defaults
+.I 0
+meaning no restriction.
+.SH "SSL ENVIRONMENT VARIABLES READ"
+These variables define the run-time environment of
+.B sslserver
+and are used to specify X509 certificates and keyfile per connection.
+.TP
+.B $SSL_USER=\fIname
+The user, reading the certificates and keyfile.
+.TP
+.B $SSL_GROUP=\fIgroup
+The respective user group.
+.TP
+.B $SSL_UID=\fIuid
+The numerical UID of the $SSL_USER.
+.TP
+.B $SSL_CHROOT=\fIpath
+Perform reading of certificates and keyfile in a $SSL_CHROOT jail.
+.TP
+.B $CAFILE=\fIpath
+If set, overrides the compiled-in CA file name.
+The CA file contains the list of CAs used to verify the client certificate.
+Certificates in $CAFILE are processed when the server starts.
+.TP
+.B $CADIR=\fIpath
+If set, overrides the compiled-in CA directory name.
+The CA directory contains certificates files used to verify the client certificate.
+This list augments the list from $CAFILE.
+Certificates in $CADIR are processed during certificate verification.
+.TP
+.B $CERTFILE=\fIpath
+If set, overrides the compiled-in certificate file name.
+The server presents this certificate to clients.
+.TP
+.B $CERTCHAINFILE=\fIpath
+If set, overrides the compiled-in certificate chainfile name.
+The server presents this list of certificats to clients.
+.I Note:
+Providing $CERTCHAINFILE has precedence over $CERTFILE.
+Certificates in this file needs to be 'ordered' starting from the
+uppermost root certificates and placing your host's certificate at the end.
+.TP
+.B $CIPHERS=\fIstring
+If set, override the compiled-in SSL cipher list
+defining the security level for the connection.
+A typical choice would be 'TLSv1+HIGH:!SSLv2:!MD5'.
+.TP
+.B $DHFILE=\fIpath
+If set, overrides the compiled-in DH parameter file name.
+.TP
+.B $KEYFILE=\fIpath
+If set, overrides the compiled-in key file name.
+The key is used when loading the server certificate.
+Setting $KEYFILE to the empty instructs the server
+not to use a
+.I keyfile
+when loading it's certificate.
+.TP
+.B $VERIFYDEPTH=\fIn
+If set, overrides the compiled-in verification depth. Default: 1.
+.TP
+.B $CCAFILE=\fIpath
+If set, overrides the compiled-in client CA file name for client certificate request.
+The client CA file contains the list of CAs sent to the client
+when requesting a client certificate.
+.I Note:
+Setting of $CCAFILE is required while using the option
+.IR \-z
+or
+.IR \-m.
+However, declaring
+.B $CCAFILE="-"
+disables (on a per-connection base) the client certificate request.
+.TP
+.B $CCAVERIFY
+If set,
+.B sslserver
+requests a valid client certificate on a per-connection base, unlike the general
+option
+.IR \-z .
+.SH "SSL ENVIRONMENT VARAIBLES SET"
+In case
+.B sslserver
+is called with the option
+.BR \-e ,
+the following
+.I mod_ssl
+environment variables are provided:
+.TP
+.B SSL_PROTOCOL
+The TLS protocol version (SSLv3, TLSv1, ...).
+.TP
+.B SSL_SESSION_ID
+The hex-encoded SSL session id.
+.TP
+.B SSL_CIPHER
+The cipher specification name.
+.TP
+.B SSL_CIPHER_USEKEYSIZE
+Number of cipher bits (actually used).
+.TP
+.B SSL_CIPHER_ALGKEYSIZE
+Number of cipher bits (possible).
+.TP
+.B SSL_VERSION_INTERFACE
+The mod_ssl program version.
+.TP
+.B SSL_VERSION_LIBRARY
+The OpenSSL program version.
+.TP
+.B SSL_CLIENT_M_VERSION
+The version of the client certificate.
+.TP
+.B SSL_CLIENT_M_SERIAL
+The serial of the client certificate.
+.TP
+.B SSL_CLIENT_S_DN
+Subject DN in client's certificate.
+.TP
+.B SSL_CLIENT_S_DN_x509
+Component of client's Subject DN.
+.TP
+.B SSL_CLIENT_I_DN
+Issuer DN of client's certificate.
+.TP
+.B SSL_CLIENT_I_DN_x509
+Component of client's Issuer DN.
+.TP
+.B SSL_CLIENT_V_START
+Validity of client's certificate (start time).
+.TP
+.B SSL_CLIENT_V_END
+Validity of client's certificate (end time).
+.TP
+.B SSL_CLIENT_A_SIG
+Algorithm used for the signature of client's certificate.
+.TP
+.B SSL_CLIENT_A_KEY
+Algorithm used for the public key of client's certificate.
+.TP
+.B SSL_CLIENT_CERT
+PEM-encoded client certificate.
+.TP
+.B SSL_CLIENT_CERT_CHAIN \fIn
+PEM-encoded certificates in client certificate chain.
+.TP
+.B SSL_CLIENT_VERIFY
+NONE, SUCCESS, GENEROUS or FAILED:reason.
+.TP
+.B SSL_SERVER_M_SERIAL
+The serial of the server certificate.
+.TP
+.B SSL_SERVER_S_DN
+Subject DN in server's certificate.
+.TP
+.B SSL_SERVER_S_DN_x509
+Component of server's Subject DN.
+.TP
+.B SSL_SERVER_I_DN
+Issuer DN of server's certificate.
+.TP
+.B SSL_SERVER_I_DN_x509
+Component of server's Issuer DN.
+.TP
+.B SSL_SERVER_V_START
+Validity of server's certificate (start time).
+.TP
+.B SSL_SERVER_V_END
+Validity of server's certificate (end time).
+.TP
+.B SSL_SERVER_A_SIG
+Algorithm used for the signature of server's certificate.
+.TP
+.B SSL_SERVER_A_KEY
+Algorithm used for the public key of server's certificate.
+.TP
+.B SSL_SERVER_CERT
+PEM-encoded server certificate.
+.P
+For \fBSSL_CLIENT_x_DN_x509\fR and \fBSSL_SERVER_x_DN_x509\fR,
+x509 denotes a component of the DN:
+C, ST, L, O, OU, CN, T, I, G, S, D, UID, Email.
+
+.P
+Other SSL environment variables set:
+.P
+.BR PROTO,
+.BR SSLLOCALHOST,
+.BR SSLLOCALIP,
+.BR SSLLOCALPORT,
+.BR SSLREMOTEHOST,
+.BR SSLREMOTEINFO,
+.BR SSLREMOTEIP,
+.BR SSLREMOTEPORT.
+
+.P
+TCP environment variables set:
+.P
+.BR TCPLOCALHOST,
+.BR TCPLOCALIP,
+.BR TCPLOCALPORT,
+.BR TCPREMOTEHOST,
+.BR TCPREMOTEINFO,
+.BR TCPREMOTEIP,
+.BR TCPREMOTEPORT.
+
+.P
+TCP6 environment variables set:
+.P
+.BR TCP6INTERFACE,
+.BR TCP6LOCALHOST,
+.BR TCP6LOCALIP,
+.BR TCP6LOCALPORT,
+.BR TCP6REMOTEHOST,
+.BR TCP6REMOTEIP,
+.BR TCP6REMOTEPORT.
+.SH "LOGGING AND ERROR MESSAGES"
+.B sslserver
+prints particular state information for individual connections in case
+.I -v
+is specified. Here, the
+local and remote IP addresses and port together
+with the number of used/available/ip connection limited children:
+
+.EX
+ sslserver: status 1/40/0
+ sslserver: pid xxxx from <ip>
+ sslserver: [ok|deny] xxxx <local>:<localip>:<localport> <remotehost>:<remoteip>:<remoteport>
+ sslserver: ended by xyz status nnnn
+.EE
+
+If
+.I MAXCONIP
+is given as global environment variable, one may encounter:
+
+.EX
+ sslserver: status z/40/<maxconip>
+ sslserver: WARNING ip connection limit of <maxconip> exceeded for: <remoteip>
+.EE
+
+Rather, if
+.I MAXCONIP
+is read from the cdb, the following message might appear:
+
+.EX
+ sslserver: status 1/40/0
+ sslserver: pid xxxx from <ip>
+ sslserver: deny xxxx ... ip connection limit:<maxconip> exceeded
+ sslserver: ended by xyz status nnnn
+.EE
+
+In all cases, the resolved host names depends on the usage of
+.IR l ,
+.I -h
+and
+.IR -p .
+If
+.I -V
+is instead given as argument, lines like
+
+.EX
+ sslserver: tls xxxx accept TLSv1.2:ECDH-RSA-AES256-GCM-SHA384
+ sslserver: tls xxxx accept TLSv1.3:TLS_CHACHA20_POLY1305_SHA256
+.EE
+
+show additionally the negotiated cipher suite.
+.P
+.B Error and particular messages
+.P
+TLS error messages are provided, if possible:
+.TP
+.I sslerver: error: (111) unable to speak TLS from: ... for pid: ... DH lib
+.P
+TLS handshake failure.
+.TP
+.I sslserver: error: (111) unable to accept TLS from: ... for pid: ... system lib
+.P
+The remote socket was prematurely closed; usually because
+the X.509 cert was not accepted by the client.
+.TP
+.I sslserver: info: valid client cert received for pid: <pid>
+.P
+A client X.509 cert has been accepted for
+mutual authentication.
+.P
+.SH "SEE ALSO"
+sslhandle(1),
+sslclient(1),
+sslconnect(1),
+sslcat(1),
+https@(1),
+ucspi-tls(2),
+tcprules(1),
+tcprulescheck(1),
+tcpserver(1),
+tcp-environ(5)
+.SH REFERENCE
+http://httpd.apache.org/docs/2.4/mod/mod_ssl.html
diff --git a/man/ucspi-tls.2 b/man/ucspi-tls.2
new file mode 100644
index 0000000..a3d8639
--- /dev/null
+++ b/man/ucspi-tls.2
@@ -0,0 +1,61 @@
+.TH ucspi-tls 2
+.SH NAME
+UCSPI-TLS \- advanced and secure communication between server and prog
+.SH DESCRIPTON
+A
+.B UCSPI-TLS
+enhanced server makes optional SSL services available to the
+client by providing three file descriptors: a
+.I control socket,
+a
+.I reading pipe,
+and a
+.I writing pipe.
+
+The file descriptor number of the control socket will be in the
+environment variable $SSLCTLFD.
+
+The file descriptor number of the reading pipe will be in the
+environment variable $SSLREADFD, and the file descriptor number of the
+writing pipe will be in the environment variable $SSLWRITEFD.
+
+It's possible for all three of these file descriptors to be the same.
+
+.SH USAGE
+.B UCSPI-TLS
+provides standard IN and OUT (file descriptors 0 and 1)
+to connected directly to the socket, for unencrypted communication.
+
+The
+.I control socket
+must accept at least these two commands:
+.TP
+.B y
+Start TLS.
+.TP
+.B Y
+Start TLS, and send optional SSL connection information
+back over the control socket.
+.P
+The SSL connection information will be in the in the form of an
+environment string, with zero or more environment variables,
+terminated by two ASCII NULL's. Each environment variable is stored
+as "VAR=val\0", and an additional trailing \0 is used to indicate
+the end of all environment variables. If there are no variables to
+set, "\0\0" should be used.
+
+When TLS is started, the
+.B UCSPI-TLS
+enabled server will take control of the socket,
+and the application is expected to switch to the file descriptors in
+$SSLREADFD and $SSLWRITEFD for all future communications.
+Using the regular socket after activating TLS will
+probably just confuse the client.
+.SH REFERENCE
+Where possible, the environment variables set should be the same
+ones as Apache's
+.I mod_ssl:
+
+http://httpd.apache.org/docs-2.4/mod/mod_ssl.html
+.SH CREDITS
+Scott Gifford, Charlie Brady
diff --git a/package/build b/package/build
new file mode 100644
index 0000000..bac2ceb
--- /dev/null
+++ b/package/build
@@ -0,0 +1 @@
+20231204180637
diff --git a/package/command-cp b/package/command-cp
new file mode 100644
index 0000000..1083552
--- /dev/null
+++ b/package/command-cp
@@ -0,0 +1,3 @@
+
+Directories to copy commands into, one per line.
+The first empty line terminates the list.
diff --git a/package/command-ln b/package/command-ln
new file mode 100644
index 0000000..3a56315
--- /dev/null
+++ b/package/command-ln
@@ -0,0 +1,4 @@
+/usr/local/bin
+
+Directories to soft link commands into, one per line.
+The first empty line terminates the list.
diff --git a/package/commands-base b/package/commands-base
new file mode 100644
index 0000000..a1d0820
--- /dev/null
+++ b/package/commands-base
@@ -0,0 +1,7 @@
+sslclient
+sslserver
+https@
+sslcat
+sslconnect
+sslprint
+sslhandle
diff --git a/package/commands-sslperl b/package/commands-sslperl
new file mode 100644
index 0000000..68065ca
--- /dev/null
+++ b/package/commands-sslperl
@@ -0,0 +1 @@
+sslperl
diff --git a/package/commands-sys b/package/commands-sys
new file mode 100644
index 0000000..fa5d3e9
--- /dev/null
+++ b/package/commands-sys
@@ -0,0 +1 @@
+sysdeps
diff --git a/package/compile b/package/compile
new file mode 100755
index 0000000..9deb12c
--- /dev/null
+++ b/package/compile
@@ -0,0 +1,88 @@
+#!/bin/sh
+shout() { echo "compile: $@" >&2; }
+barf() { shout "fatal: $@"; exit 111; }
+safe() { "$@" || barf "cannot $@"; }
+umask 022
+[ -d package ] || barf "no package directory"
+[ -d src ] || barf "no src directory"
+
+here=`env - PATH=$PATH pwd`
+
+safe mkdir -p compile command
+[ -h compile/src ] || safe ln -s $here/src compile/src
+
+for i in `ls src`
+do
+ [ -h compile/$i ] || safe ln -s src/$i compile/$i
+done
+
+for i in `sed -e '/^it-/!d' -e 's/^it-//' < compile/it=d`
+do
+ all="$all $i"
+done
+other="`grep -v '^it-' compile/it=d`"
+usage() { shout "usage: package/rts [ [-]$all ]"; exit 100; }
+targets=""
+if [ $# -eq 0 ]
+then
+ targets="$all"
+else
+ if [ "$1" = "-" ]
+ then
+ shift
+ suppress=":"
+ for i in ${1+"$@"}
+ do
+ case "$all " in
+ *\ $i\ *)
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ suppress="$suppress$i:"
+ done
+ for i in $all
+ do
+ case "$suppress" in
+ *:$i:*)
+ ;;
+ *)
+ targets="$targets $i"
+ ;;
+ esac
+ done
+ else
+ for i in ${1+"$@"}
+ do
+ case "$all " in
+ *\ $i\ *)
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ targets="$targets $i"
+ done
+ fi
+fi
+
+[ "X$all" != "X" ] && [ "X$targets" = "X" ] && usage
+
+commands=
+for i in $targets
+do
+ commands="$commands `cat package/commands-$i`"
+done
+
+safe cd compile
+safe make $other `echo "$targets" | sed -e 's/ / it-/g'`
+safe cd $here
+
+for i in $commands
+do
+ safe rm -f command/$i'{new}'
+ safe cp -p compile/$i command/$i'{new}'
+ safe mv -f command/$i'{new}' command/$i
+done
+
diff --git a/package/files b/package/files
new file mode 100644
index 0000000..e867db0
--- /dev/null
+++ b/package/files
@@ -0,0 +1,164 @@
+conf-cadir
+conf-cafile
+conf-cc
+conf-ccafile
+conf-ccperl
+conf-certchainfile
+conf-certfile
+conf-ciphers
+conf-dhfile
+conf-home
+conf-keyfile
+conf-ld
+conf-ldperl
+conf-man
+conf-perl
+conf-qlibs
+conf-rsa
+conf-ssl
+conf-ssllib
+INSTALL
+README.md
+doc
+doc/CHAIN-SSL
+doc/CHANGES
+doc/LICENSE
+doc/README.rts
+doc/UCSPI-SSL
+doc/TLS_1_3
+doc/TLSVERSION_CIPHERSUITES
+doc/TODO
+etc
+etc/README.certs.md
+etc/127.0.0.1_cert.pem
+etc/127.0.0.1_key.pem
+etc/127.0.0.1_key.pem.plain
+etc/127.0.0.1.pw
+etc/::1_cert.pem
+etc/::1_key.pem
+etc/::1_key.pem.plain
+etc/::1.pw
+etc/chain4.pem
+etc/chain6.pem
+etc/dh2048.pem
+etc/localhost_cert.pem
+etc/localhost_key.pem
+etc/localhost_key.pem.plain
+etc/localhost.pw
+etc/rootCA_cert.pem
+man
+man/Makefile
+man/Makefile.mandoc
+man/TARGETS
+man/https@.1
+man/sslcat.1
+man/sslclient.1
+man/sslconnect.1
+man/sslhandle.1
+man/sslserver.1
+man/ucspi-tls.2
+package
+package/command-cp
+package/command-ln
+package/commands-base
+package/commands-sys
+package/commands-sslperl
+package/build
+package/compile
+package/files
+package/install
+package/man
+package/path
+package/report
+package/rts
+package/run
+package/upgrade
+package/version
+src
+src/Makefile
+src/TARGETS
+src/auto-str.c
+src/auto_cadir.h
+src/auto_cafile.h
+src/auto_ccafile.h
+src/auto_certchainfile.h
+src/auto_certfile.h
+src/auto_ciphers.h
+src/auto_dhfile.h
+src/auto_keyfile.h
+src/chkshsgr.c
+src/choose.sh
+src/coe.c
+src/coe.h
+src/exp.base
+src/exp.it
+src/exp.sslperl
+src/exit.h
+src/find-systype.sh
+src/fork.h1
+src/fork.h2
+src/hassgact.h1
+src/hassgact.h2
+src/hassgprm.h1
+src/hassgprm.h2
+src/hasshsgr.h1
+src/hasshsgr.h2
+src/haswaitp.h1
+src/haswaitp.h2
+src/https@.sh
+src/ip_bit.h
+src/ip4_bit.c
+src/ip6_bit.c
+src/it-base=d
+src/it-sslperl=d
+src/it-sys=d
+src/it=d
+src/print-ar.sh
+src/print-cc.sh
+src/print-ccperl.sh
+src/print-dl.sh
+src/print-ld.sh
+src/print-ldperl.sh
+src/print-perlembed.sh
+src/remoteinfo.c
+src/remoteinfo.h
+src/rts.base
+src/rts.it
+src/rts.sslperl
+src/rules.c
+src/rules.h
+src/select.h1
+src/select.h2
+src/ssl_ca.c
+src/ssl_cca.c
+src/ssl_certkey.c
+src/ssl_chainfile.c
+src/ssl_ciphers.c
+src/ssl_context.c
+src/ssl_env.c
+src/ssl_error.c
+src/ssl_io.c
+src/ssl_new.c
+src/ssl_params.c
+src/ssl_timeout.c
+src/ssl_verify.c
+src/sslcat.sh
+src/sslclient.c
+src/sslconnect.sh
+src/sslhandle.c
+src/sslperl.c
+src/sslprint.c
+src/sslserver.c
+src/trycpp.c
+src/trylsock.c
+src/trysgact.c
+src/trysgprm.c
+src/tryshsgr.c
+src/tryssl.c
+src/trysysel.c
+src/tryvfork.c
+src/ucspissl.c
+src/ucspissl.h
+src/warn-auto.sh
+src/warn-shsgr
+src/x86cpuid.c
diff --git a/package/install b/package/install
new file mode 100755
index 0000000..58a2f08
--- /dev/null
+++ b/package/install
@@ -0,0 +1,5 @@
+#!/bin/sh -e
+package/compile ${1+"$@"}
+package/upgrade ${1+"$@"}
+package/man ${1+"$@"}
+package/run ${1+"$@"}
diff --git a/package/man b/package/man
new file mode 100755
index 0000000..6213c77
--- /dev/null
+++ b/package/man
@@ -0,0 +1,125 @@
+#!/bin/sh
+shout() { echo "$0: $@" >&2; }
+barf() { shout "fatal: $@"; exit 111; }
+safe() { "$@" || barf "cannot $@"; }
+
+here=`env - PATH=$PATH pwd`
+me=`echo $here | awk -F/ '{print $NF}'`
+unix=`uname -a | cut -d' ' -f1 | tr [a-z] [A-Z]`
+mandir=""
+usemanpath=0
+usemandoc=0
+
+if [ `which manpath` 2>/dev/null ]
+then
+ usemanpath=1
+fi
+
+if [ `which mandoc` 2>/dev/null ]
+then
+ usemandoc=1
+ shout "Using mandoc facility for man files."
+fi
+
+safe umask 022
+[ -d man ] || barf "no man directory"
+
+if [ -f conf-man ]
+then
+ mandir=`head -1 conf-man`
+ if [ -d "$mandir" ]
+ then
+ shout "Setting manual man-dir: $mandir."
+ else
+ if [ $usemanpath -eq 0 ]
+ then
+ barf "`manpath` not available; use conf-man instead."
+ fi
+ mandir=`manpath | awk -F: '{print $1}'`
+ if [ -d "$mandir" ]
+ then
+ shout "Setting manpath man-dir: $mandir."
+ else
+ barf "can't determine man-path directory."
+ fi
+ fi
+else
+ barf "can't determine man-path directory."
+ exit 1
+fi
+
+cd man
+if [ $usemandoc -eq 1 ]
+then
+ safe make -f Makefile.mandoc
+else
+ safe make
+fi
+
+if [ $usemandoc -eq 0 ]
+then
+ shout "Installing ${me} compressed man-files in ${mandir}."
+else
+ shout "Installing ${me} un-compressed man-files in ${mandir}."
+fi
+
+for i in `ls *[1-8]`
+do
+ all="$all $i"
+done
+
+for manfile in $all
+do
+ dir="man`echo $manfile | awk -F. '{print $NF}'`"
+ [ -d $mandir/$dir ] || safe mkdir $mandir/$dir
+ if [ $usemandoc -eq 0 ]
+ then
+ safe gzip $manfile && \
+ cp "$manfile.gz" "$mandir/$dir/$manfile.gz"
+ else
+ safe cp "$manfile" "$mandir/$dir/$manfile"
+ fi
+done
+
+## nroff: Required for old catman systems only
+
+if [ $usemandoc -eq 0 ]
+then
+ shout "Installing ${me} nroff'ed man-files in ${mandir}/catX."
+
+ all=""
+ for i in `ls *0`
+ do
+ all="$all $i"
+ done
+
+ for manfile in $all
+ do
+ catname=`echo $manfile | awk -F. '{print $1}'`
+ catfiles=`ls -1 ${catname}* | grep -v '.0' | grep -v '.9'`
+
+ for catfile in $catfiles
+ do
+ dir="$mandir/cat`echo $catfile | awk -F. '{print $(NF-1)}'`"
+ safe mkdir -p $dir
+ safe cp "$manfile" "$dir/$manfile"
+ done
+ done
+else
+ if [ `which makewhatis` 2>/dev/null ]
+ then
+ makewhatis $mandir
+ shout "Installing ${me} mandoc files in db (makewhatis)."
+ elif [ `which catman` 2>/dev/null ]
+ then
+ catman $mandir
+ shout "Installing ${me} mandoc files in db (catman)."
+ else
+ man -w $mandir
+ shout "Installing ${me} mandoc files in db (man -w)."
+ fi
+fi
+
+cd ..
+
+exit 0
diff --git a/package/path b/package/path
new file mode 100644
index 0000000..feda59c
--- /dev/null
+++ b/package/path
@@ -0,0 +1 @@
+host/superscript.com/net
diff --git a/package/report b/package/report
new file mode 100755
index 0000000..1d3ec0a
--- /dev/null
+++ b/package/report
@@ -0,0 +1,10 @@
+#!/bin/sh -e
+test -d compile || ( echo 'Wrong working directory.'; exit 1 )
+here=`env - PATH=$PATH pwd`
+( echo ucspi-ssl-`head -1 package/version`
+ echo $here
+ if test -r compile/sysdeps
+ then
+ cat compile/sysdeps
+ fi
+) | mail feh@fehcom.de
diff --git a/package/rts b/package/rts
new file mode 100755
index 0000000..b585d1a
--- /dev/null
+++ b/package/rts
@@ -0,0 +1,76 @@
+#!/bin/sh
+shout() { echo "rts: $@" >&2; }
+barf() { shout "fatal: $@"; exit 111; }
+safe() { "$@" || barf "cannot $@"; }
+
+umask 022
+[ -d package ] || barf "no package directory"
+[ -d src ] || barf "no src directory"
+[ -d compile ] || barf "no compile directory"
+[ -d etc ] || barf "no etc directory"
+
+for i in `sed -e '/^it-/!d' -e 's/^it-//' < compile/it=d`
+do
+ all="$all $i"
+done
+usage() { shout "usage: package/rts [ [-]$all ]"; exit 100; }
+
+targets=""
+if [ $# -eq 0 ]
+then
+ targets="$all"
+else
+ if [ "$1" = "-" ]
+ then
+ shift
+ suppress=":"
+ for i in ${1+"$@"}
+ do
+ case "$all " in
+ *\ $i\ *)
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ suppress="$suppress$i:"
+ done
+ for i in $all
+ do
+ case "$suppress" in
+ *:$i:*)
+ ;;
+ *)
+ targets="$targets $i"
+ ;;
+ esac
+ done
+ else
+ for i in ${1+"$@"}
+ do
+ case "$all " in
+ *\ $i\ *)
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ targets="$targets $i"
+ done
+ fi
+fi
+
+[ "X$all" != "X" ] && [ "X$targets" = "X" ] && usage
+
+export here=`env - PATH=$PATH pwd`
+safe cd compile
+PATH="$here/compile:/command:$PATH"
+export PATH
+. $here/compile/rts.it > $here/compile/out.it 2>&1
+cat -v $here/compile/out.it | diff - $here/compile/exp.it
+for i in $targets
+do
+ export here
+ . $here/compile/rts.$i 2>&1 | cat -v > $here/compile/out.$i
+ diff $here/compile/out.$i $here/compile/exp.$i
+done
diff --git a/package/run b/package/run
new file mode 100755
index 0000000..f11f4e1
--- /dev/null
+++ b/package/run
@@ -0,0 +1,2 @@
+#!/bin/sh -e
+exit 0
diff --git a/package/upgrade b/package/upgrade
new file mode 100755
index 0000000..cc3ead0
--- /dev/null
+++ b/package/upgrade
@@ -0,0 +1,109 @@
+#!/bin/sh
+shout() { echo "upgrade: $@" >&2; }
+barf() { shout "fatal: $@"; exit 111; }
+safe() { "$@" || barf "cannot $@"; }
+
+umask 022
+[ -d package ] || barf "no package directory"
+[ -d src ] || barf "no src directory"
+
+for i in `sed -e '/^it-/!d' -e 's/^it-//' < compile/it=d`
+do
+ all="$all $i"
+done
+usage() { shout "usage: package/upgrade [ [-]$all ]"; exit 100; }
+targets=""
+if [ $# -eq 0 ]
+then
+ for i in $all
+ do
+ targets="$all"
+ done
+else
+ if [ "$1" = "-" ]
+ then
+ shift
+ suppress=":"
+ for i in ${1+"$@"}
+ do
+ case "$all " in
+ *\ $i\ *)
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ suppress="$suppress$i:"
+ done
+ for i in $all
+ do
+ case "$suppress" in
+ *:$i:*)
+ ;;
+ *)
+ targets="$targets $i"
+ ;;
+ esac
+ done
+ else
+ for i in ${1+"$@"}
+ do
+ case "$all " in
+ *\ $i\ *)
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ targets="$targets $i"
+ done
+ fi
+fi
+
+[ "X$targets" = "X" ] && barf "no targets"
+
+version="`head -1 package/version`"
+here="`pwd`"
+command="`echo $here | sed -e 's/-'$version'$//'`/command"
+package="`basename $here | sed -e 's/-'$version'$//'`"
+echo "symlink $package -> $package-$version"
+safe rm -f $package
+safe ln -s $package-$version $package
+safe mv -f $package ..
+
+commands=
+for i in $targets
+do
+ commands="$commands `cat package/commands-$i`"
+done
+
+if [ -r package/command-cp ]
+then
+ for i in `sed -e '/^$/q' < package/command-cp`
+ do
+ echo "copying commands into $i"
+ safe mkdir -p $i
+ for j in $commands
+ do
+ safe rm -f $i/$j'{new}'
+ safe cp -p command/$j $i/$j'{new}'
+ safe mv -f $i/$j'{new}' $i/$j
+ done
+ done
+fi
+
+if [ -r package/command-ln ]
+then
+ for i in `sed -e '/^$/q' < package/command-ln`
+ do
+ echo "linking commands into $i"
+ safe mkdir -p $i
+ for j in $commands
+ do
+ safe rm -f $i/$j'{new}'
+ safe ln -s $command/$j $i/$j'{new}'
+ safe mv -f $i/$j'{new}' $i/$j
+ done
+ done
+fi
+
diff --git a/package/version b/package/version
new file mode 100644
index 0000000..54dbed4
--- /dev/null
+++ b/package/version
@@ -0,0 +1 @@
+0.12.10
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;
+}