Index: build/post.sh ================================================================== --- build/post.sh +++ build/post.sh Index: build/pre.sh ================================================================== --- build/pre.sh +++ build/pre.sh Index: gen_dh_params ================================================================== --- gen_dh_params +++ gen_dh_params Index: tests/remote.tcl ================================================================== --- tests/remote.tcl +++ tests/remote.tcl Index: tests/simpleClient.tcl ================================================================== --- tests/simpleClient.tcl +++ tests/simpleClient.tcl Index: tests/simpleServer.tcl ================================================================== --- tests/simpleServer.tcl +++ tests/simpleServer.tcl Index: tests/tlsIO.test ================================================================== --- tests/tlsIO.test +++ tests/tlsIO.test Index: tls.c ================================================================== --- tls.c +++ tls.c @@ -748,10 +748,11 @@ char *CAdir = NULL; char *DHparams = NULL; char *model = NULL; #ifndef OPENSSL_NO_TLSEXT char *servername = NULL; /* hostname for Server Name Indication */ + Tcl_Obj *alpn = NULL; #endif int ssl2 = 0, ssl3 = 0; int tls1 = 1, tls1_1 = 1, tls1_2 = 1, tls1_3 = 1; int proto = 0; int verify = 0, require = 0, request = 1; @@ -810,10 +811,11 @@ OPTBOOL( "-require", require); OPTBOOL( "-request", request); OPTBOOL( "-server", server); #ifndef OPENSSL_NO_TLSEXT OPTSTR( "-servername", servername); + OPTOBJ( "-alpn", alpn); #endif OPTBOOL( "-ssl2", ssl2); OPTBOOL( "-ssl3", ssl3); OPTBOOL( "-tls1", tls1); @@ -821,11 +823,11 @@ OPTBOOL( "-tls1.2", tls1_2); OPTBOOL( "-tls1.3", tls1_3); OPTBYTE("-cert", cert, cert_len); OPTBYTE("-key", key, key_len); - OPTBAD( "option", "-cadir, -cafile, -cert, -certfile, -cipher, -command, -dhparams, -key, -keyfile, -model, -password, -require, -request, -server, -servername, -ssl2, -ssl3, -tls1, -tls1.1, -tls1.2, or tls1.3"); + OPTBAD( "option", "-alpn, -cadir, -cafile, -cert, -certfile, -cipher, -command, -dhparams, -key, -keyfile, -model, -password, -require, -request, -server, -servername, -ssl2, -ssl3, -tls1, -tls1.1, -tls1.2, or tls1.3"); return TCL_ERROR; } if (request) verify |= SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_PEER; if (request && require) verify |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; @@ -958,10 +960,51 @@ (char *) NULL); Tls_Free((char *) statePtr); return TCL_ERROR; } } + if (alpn) { + /* Convert a Tcl list into a protocol-list in wire-format */ + unsigned char *protos, *p; + unsigned int protoslen = 0; + int i, len, cnt; + Tcl_Obj **list; + if (Tcl_ListObjGetElements(interp, alpn, &cnt, &list) != TCL_OK) { + Tls_Free((char *) statePtr); + return TCL_ERROR; + } + /* Determine the memory required for the protocol-list */ + for (i = 0; i < cnt; i++) { + Tcl_GetStringFromObj(list[i], &len); + if (len > 255) { + Tcl_AppendResult(interp, "alpn protocol name too long", + (char *) NULL); + Tls_Free((char *) statePtr); + return TCL_ERROR; + } + protoslen += 1 + len; + } + /* Build the complete protocol-list */ + protos = ckalloc(protoslen); + /* protocol-lists consist of 8-bit length-prefixed, byte strings */ + for (i = 0, p = protos; i < cnt; i++) { + char *str = Tcl_GetStringFromObj(list[i], &len); + *p++ = len; + memcpy(p, str, len); + p += len; + } + /* Note: This functions reverses the return value convention */ + if (SSL_set_alpn_protos(statePtr->ssl, protos, protoslen)) { + Tcl_AppendResult(interp, "failed to set alpn protocols", + (char *) NULL); + Tls_Free((char *) statePtr); + ckfree(protos); + return TCL_ERROR; + } + /* SSL_set_alpn_protos makes a copy of the protocol-list */ + ckfree(protos); + } #endif /* * SSL Callbacks */ @@ -1409,10 +1452,14 @@ X509 *peer; Tcl_Obj *objPtr; Tcl_Channel chan; char *channelName, *ciphers; int mode; +#ifndef OPENSSL_NO_TLSEXT + const unsigned char *proto; + unsigned int len; +#endif dprintf("Called"); switch (objc) { case 2: @@ -1423,10 +1470,11 @@ if (!strcmp (Tcl_GetString (objv[1]), "-local")) { channelName = Tcl_GetStringFromObj(objv[2], NULL); break; } /* else fall... */ + __attribute__((fallthrough)); default: Tcl_WrongNumArgs(interp, 1, objv, "?-local? channel"); return TCL_ERROR; } @@ -1466,10 +1514,18 @@ Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("cipher", -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_get_cipher(statePtr->ssl), -1)); } + +#ifndef OPENSSL_NO_TLSEXT + /* Report the selected protocol as a result of the negotiation */ + SSL_get0_alpn_selected(statePtr->ssl, &proto, &len); + Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("alpn", -1)); + Tcl_ListObjAppendElement(interp, objPtr, + Tcl_NewStringObj((char *)proto, (int)len)); +#endif Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("version", -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_get_version(statePtr->ssl), -1)); Index: tls.htm ================================================================== --- tls.htm +++ tls.htm @@ -147,10 +147,13 @@ server channels.
sbits n
The number of bits used for the session key.
certificate n
The PEM encoded certificate.
+
alpn protocol
+
The protocol selected after Application-Layer Protocol + Negotiation (ALPN).
version value
The protocol version used for the connection: SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2, unknown
@@ -163,10 +166,13 @@ setting session parameters for SSL handshake.
+
-alpn list
+
List of protocols to offer during Application-Layer + Protocol Negotiation (ALPN). For example: h2, http/1.1, etc.
-cadir dir
Provide the directory containing the CA certificates.
-cafile filename
Provide the CA file.
-certfile filename
Index: tls.tcl ================================================================== --- tls.tcl +++ tls.tcl @@ -44,10 +44,11 @@ {* -password iopts 1} {* -request iopts 1} {* -require iopts 1} {* -autoservername discardOpts 1} {* -servername iopts 1} + {* -alpn iopts 1} {* -ssl2 iopts 1} {* -ssl3 iopts 1} {* -tls1 iopts 1} {* -tls1.1 iopts 1} {* -tls1.2 iopts 1} Index: win/README.txt ================================================================== --- win/README.txt +++ win/README.txt @@ -1,64 +1,64 @@ - Windows DLL Build instructions using nmake build system - 2020-10-15 Harald.Oehlmann@elmicron.de - -Properties: -- 32 bit DLL -- VisualStudio 2015 -Note: Vuisual C++ 6 does not build OpenSSL (long long syntax error) -- Cygwin32 (temporary helper, please help to replace by tclsh) -- OpenSSL statically linked to TCLTLS DLL. -Note: Dynamic linking also works but results in a DLL dependeny on OPENSSL DLL's - -1) Build OpenSSL static libraries: - -OpenSSL source distribtution unpacked in: -c:\test\tcltls\Openssl_1_1_1h - -- Install Perl from http://strawberryperl.com/download/5.32.0.1/strawberry-perl-5.32.0.1-32bit.msi - to C:\perl - (ActivePerl failed due to missing 32 bit console module) -- Install NASM Assembler: - -https://www.nasm.us/pub/nasm/releasebuilds/2.15.05/win32/nasm-2.15.05-installer-x86.exe - to C:\Program Files (x86)\NASM - --> Visual Studio x86 native prompt. - -set Path=%PATH%;C:\Program Files (x86)\NASM;C:\Perl\perl\bin - -perl Configure VC-WIN32 --prefix=c:\test\tcltls\openssl --openssldir=c:\test\tcltls\openssldir no-shared no-filenames threads - -nmake -nmake test -namke install - -2) Build TCLTLS - -Unzip distribution in: -c:\test\tcltls\tcltls-1.7.22 - --> start cygwin bash prompt - -cd /cygdrive/c/test/tcltls/tcltls-1.7.22 -./gen_dh_params > dh_params.h - -od -A n -v -t xC < 'tls.tcl' > tls.tcl.h.new.1 -sed 's@[^0-9A-Fa-f]@@g;s@..@0x&, @g' < tls.tcl.h.new.1 > tls.tcl.h -rm -f tls.tcl.h.new.1 - --> Visual Studio x86 native prompt. - -cd C:\test\tcltls\tcltls-1.7.22\win - -nmake -f makefile.vc TCLDIR=c:\test\tcl8610 SSL_INSTALL_FOLDER=C:\test\tcltls\openssl - -nmake -f makefile.vc install TCLDIR=c:\test\tcl8610 INSTALLDIR=c:\test\tcltls SSL_INSTALL_FOLDER=C:\test\tcltls\openssl - -3) Test - -Start tclsh or wish - -lappend auto_path {C:\test\tcltls\tls1.7.22} -package require tls - + Windows DLL Build instructions using nmake build system + 2020-10-15 Harald.Oehlmann@elmicron.de + +Properties: +- 32 bit DLL +- VisualStudio 2015 +Note: Vuisual C++ 6 does not build OpenSSL (long long syntax error) +- Cygwin32 (temporary helper, please help to replace by tclsh) +- OpenSSL statically linked to TCLTLS DLL. +Note: Dynamic linking also works but results in a DLL dependeny on OPENSSL DLL's + +1) Build OpenSSL static libraries: + +OpenSSL source distribtution unpacked in: +c:\test\tcltls\Openssl_1_1_1h + +- Install Perl from http://strawberryperl.com/download/5.32.0.1/strawberry-perl-5.32.0.1-32bit.msi + to C:\perl + (ActivePerl failed due to missing 32 bit console module) +- Install NASM Assembler: + +https://www.nasm.us/pub/nasm/releasebuilds/2.15.05/win32/nasm-2.15.05-installer-x86.exe + to C:\Program Files (x86)\NASM + +-> Visual Studio x86 native prompt. + +set Path=%PATH%;C:\Program Files (x86)\NASM;C:\Perl\perl\bin + +perl Configure VC-WIN32 --prefix=c:\test\tcltls\openssl --openssldir=c:\test\tcltls\openssldir no-shared no-filenames threads + +nmake +nmake test +namke install + +2) Build TCLTLS + +Unzip distribution in: +c:\test\tcltls\tcltls-1.7.22 + +-> start cygwin bash prompt + +cd /cygdrive/c/test/tcltls/tcltls-1.7.22 +./gen_dh_params > dh_params.h + +od -A n -v -t xC < 'tls.tcl' > tls.tcl.h.new.1 +sed 's@[^0-9A-Fa-f]@@g;s@..@0x&, @g' < tls.tcl.h.new.1 > tls.tcl.h +rm -f tls.tcl.h.new.1 + +-> Visual Studio x86 native prompt. + +cd C:\test\tcltls\tcltls-1.7.22\win + +nmake -f makefile.vc TCLDIR=c:\test\tcl8610 SSL_INSTALL_FOLDER=C:\test\tcltls\openssl + +nmake -f makefile.vc install TCLDIR=c:\test\tcl8610 INSTALLDIR=c:\test\tcltls SSL_INSTALL_FOLDER=C:\test\tcltls\openssl + +3) Test + +Start tclsh or wish + +lappend auto_path {C:\test\tcltls\tls1.7.22} +package require tls + A small "1.7.22" showing up is hopefully the end of this long way... Index: win/makefile.vc ================================================================== --- win/makefile.vc +++ win/makefile.vc @@ -1,24 +1,24 @@ -# call nmake with additional parameter SSL_INSTALL_FOLDER= with the -# OpenSSL instalation folder following. - -PROJECT=tls -DOTVERSION = 1.7.22 - -PRJ_INCLUDES = -I"$(SSL_INSTALL_FOLDER)\include" -PRJ_DEFINES = -D NO_SSL2 -D NO_SSL3 -D _CRT_SECURE_NO_WARNINGS - -PRJ_LIBS = \ - "$(SSL_INSTALL_FOLDER)\lib\libssl.lib" \ - "$(SSL_INSTALL_FOLDER)\lib\libcrypto.lib" \ - WS2_32.LIB GDI32.LIB ADVAPI32.LIB CRYPT32.LIB USER32.LIB - -PRJ_OBJS = $(TMP_DIR)\tls.obj \ - $(TMP_DIR)\tlsBIO.obj \ - $(TMP_DIR)\tlsIO.obj \ - $(TMP_DIR)\tlsX509.obj - -!include "rules-ext.vc" -!include "targets.vc" - -pkgindex: default-pkgindex - +# call nmake with additional parameter SSL_INSTALL_FOLDER= with the +# OpenSSL instalation folder following. + +PROJECT=tls +DOTVERSION = 1.7.22 + +PRJ_INCLUDES = -I"$(SSL_INSTALL_FOLDER)\include" +PRJ_DEFINES = -D NO_SSL2 -D NO_SSL3 -D _CRT_SECURE_NO_WARNINGS + +PRJ_LIBS = \ + "$(SSL_INSTALL_FOLDER)\lib\libssl.lib" \ + "$(SSL_INSTALL_FOLDER)\lib\libcrypto.lib" \ + WS2_32.LIB GDI32.LIB ADVAPI32.LIB CRYPT32.LIB USER32.LIB + +PRJ_OBJS = $(TMP_DIR)\tls.obj \ + $(TMP_DIR)\tlsBIO.obj \ + $(TMP_DIR)\tlsIO.obj \ + $(TMP_DIR)\tlsX509.obj + +!include "rules-ext.vc" +!include "targets.vc" + +pkgindex: default-pkgindex + Index: win/targets.vc ================================================================== --- win/targets.vc +++ win/targets.vc @@ -1,98 +1,98 @@ -#------------------------------------------------------------- -*- makefile -*- -# targets.vc -- -# -# Part of the nmake based build system for Tcl and its extensions. -# This file defines some standard targets for the convenience of extensions -# and can be optionally included by the extension makefile. -# See TIP 477 (https://core.tcl-lang.org/tips/doc/trunk/tip/477.md) for docs. - -$(PROJECT): setup pkgindex $(PRJLIB) - -!ifdef PRJ_STUBOBJS -$(PROJECT): $(PRJSTUBLIB) -$(PRJSTUBLIB): $(PRJ_STUBOBJS) - $(LIBCMD) $** - -$(PRJ_STUBOBJS): - $(CCSTUBSCMD) %s -!endif # PRJ_STUBOBJS - -!ifdef PRJ_MANIFEST -$(PROJECT): $(PRJLIB).manifest -$(PRJLIB).manifest: $(PRJ_MANIFEST) - @nmakehlp -s << $** >$@ -@MACHINE@ $(MACHINE:IX86=X86) -<< -!endif - -!if "$(PROJECT)" != "tcl" && "$(PROJECT)" != "tk" -$(PRJLIB): $(PRJ_OBJS) $(RESFILE) -!if $(STATIC_BUILD) - $(LIBCMD) $** -!else - $(DLLCMD) $** - $(_VC_MANIFEST_EMBED_DLL) -!endif - -@del $*.exp -!endif - -!if "$(PRJ_HEADERS)" != "" && "$(PRJ_OBJS)" != "" -$(PRJ_OBJS): $(PRJ_HEADERS) -!endif - -# If parent makefile has defined stub objects, add their installation -# to the default install -!if "$(PRJ_STUBOBJS)" != "" -default-install: default-install-stubs -!endif - -# Unlike the other default targets, these cannot be in rules.vc because -# the executed command depends on existence of macro PRJ_HEADERS_PUBLIC -# that the parent makefile will not define until after including rules-ext.vc -!if "$(PRJ_HEADERS_PUBLIC)" != "" -default-install: default-install-headers -default-install-headers: - @echo Installing headers to '$(INCLUDE_INSTALL_DIR)' - @for %f in ($(PRJ_HEADERS_PUBLIC)) do @$(COPY) %f "$(INCLUDE_INSTALL_DIR)" -!endif - -!if "$(DISABLE_STANDARD_TARGETS)" == "" -DISABLE_STANDARD_TARGETS = 0 -!endif - -!if "$(DISABLE_TARGET_setup)" == "" -DISABLE_TARGET_setup = 0 -!endif -!if "$(DISABLE_TARGET_install)" == "" -DISABLE_TARGET_install = 0 -!endif -!if "$(DISABLE_TARGET_clean)" == "" -DISABLE_TARGET_clean = 0 -!endif -!if "$(DISABLE_TARGET_test)" == "" -DISABLE_TARGET_test = 0 -!endif -!if "$(DISABLE_TARGET_shell)" == "" -DISABLE_TARGET_shell = 0 -!endif - -!if !$(DISABLE_STANDARD_TARGETS) -!if !$(DISABLE_TARGET_setup) -setup: default-setup -!endif -!if !$(DISABLE_TARGET_install) -install: default-install -!endif -!if !$(DISABLE_TARGET_clean) -clean: default-clean -realclean: hose -hose: default-hose -distclean: realclean default-distclean -!endif -!if !$(DISABLE_TARGET_test) -test: default-test -!endif -!if !$(DISABLE_TARGET_shell) -shell: default-shell -!endif -!endif # DISABLE_STANDARD_TARGETS +#------------------------------------------------------------- -*- makefile -*- +# targets.vc -- +# +# Part of the nmake based build system for Tcl and its extensions. +# This file defines some standard targets for the convenience of extensions +# and can be optionally included by the extension makefile. +# See TIP 477 (https://core.tcl-lang.org/tips/doc/trunk/tip/477.md) for docs. + +$(PROJECT): setup pkgindex $(PRJLIB) + +!ifdef PRJ_STUBOBJS +$(PROJECT): $(PRJSTUBLIB) +$(PRJSTUBLIB): $(PRJ_STUBOBJS) + $(LIBCMD) $** + +$(PRJ_STUBOBJS): + $(CCSTUBSCMD) %s +!endif # PRJ_STUBOBJS + +!ifdef PRJ_MANIFEST +$(PROJECT): $(PRJLIB).manifest +$(PRJLIB).manifest: $(PRJ_MANIFEST) + @nmakehlp -s << $** >$@ +@MACHINE@ $(MACHINE:IX86=X86) +<< +!endif + +!if "$(PROJECT)" != "tcl" && "$(PROJECT)" != "tk" +$(PRJLIB): $(PRJ_OBJS) $(RESFILE) +!if $(STATIC_BUILD) + $(LIBCMD) $** +!else + $(DLLCMD) $** + $(_VC_MANIFEST_EMBED_DLL) +!endif + -@del $*.exp +!endif + +!if "$(PRJ_HEADERS)" != "" && "$(PRJ_OBJS)" != "" +$(PRJ_OBJS): $(PRJ_HEADERS) +!endif + +# If parent makefile has defined stub objects, add their installation +# to the default install +!if "$(PRJ_STUBOBJS)" != "" +default-install: default-install-stubs +!endif + +# Unlike the other default targets, these cannot be in rules.vc because +# the executed command depends on existence of macro PRJ_HEADERS_PUBLIC +# that the parent makefile will not define until after including rules-ext.vc +!if "$(PRJ_HEADERS_PUBLIC)" != "" +default-install: default-install-headers +default-install-headers: + @echo Installing headers to '$(INCLUDE_INSTALL_DIR)' + @for %f in ($(PRJ_HEADERS_PUBLIC)) do @$(COPY) %f "$(INCLUDE_INSTALL_DIR)" +!endif + +!if "$(DISABLE_STANDARD_TARGETS)" == "" +DISABLE_STANDARD_TARGETS = 0 +!endif + +!if "$(DISABLE_TARGET_setup)" == "" +DISABLE_TARGET_setup = 0 +!endif +!if "$(DISABLE_TARGET_install)" == "" +DISABLE_TARGET_install = 0 +!endif +!if "$(DISABLE_TARGET_clean)" == "" +DISABLE_TARGET_clean = 0 +!endif +!if "$(DISABLE_TARGET_test)" == "" +DISABLE_TARGET_test = 0 +!endif +!if "$(DISABLE_TARGET_shell)" == "" +DISABLE_TARGET_shell = 0 +!endif + +!if !$(DISABLE_STANDARD_TARGETS) +!if !$(DISABLE_TARGET_setup) +setup: default-setup +!endif +!if !$(DISABLE_TARGET_install) +install: default-install +!endif +!if !$(DISABLE_TARGET_clean) +clean: default-clean +realclean: hose +hose: default-hose +distclean: realclean default-distclean +!endif +!if !$(DISABLE_TARGET_test) +test: default-test +!endif +!if !$(DISABLE_TARGET_shell) +shell: default-shell +!endif +!endif # DISABLE_STANDARD_TARGETS