diff options
Diffstat (limited to 'tls/tests')
-rw-r--r-- | tls/tests/all.tcl | 56 | ||||
-rw-r--r-- | tls/tests/certs/README.txt | 9 | ||||
-rw-r--r-- | tls/tests/certs/ca.pem | 18 | ||||
-rw-r--r-- | tls/tests/certs/client.key | 15 | ||||
-rw-r--r-- | tls/tests/certs/client.pem | 14 | ||||
-rw-r--r-- | tls/tests/certs/client.req | 11 | ||||
-rw-r--r-- | tls/tests/certs/file.srl | 1 | ||||
-rw-r--r-- | tls/tests/certs/privkey.pem | 18 | ||||
-rw-r--r-- | tls/tests/certs/server.key | 15 | ||||
-rw-r--r-- | tls/tests/certs/server.pem | 14 | ||||
-rw-r--r-- | tls/tests/certs/server.req | 11 | ||||
-rw-r--r-- | tls/tests/ciphers.test | 159 | ||||
-rw-r--r-- | tls/tests/keytest1.tcl | 23 | ||||
-rw-r--r-- | tls/tests/keytest2.tcl | 8 | ||||
-rwxr-xr-x | tls/tests/remote.tcl | 185 | ||||
-rwxr-xr-x | tls/tests/simpleClient.tcl | 113 | ||||
-rwxr-xr-x | tls/tests/simpleServer.tcl | 90 | ||||
-rwxr-xr-x | tls/tests/tlsIO.test | 2072 |
18 files changed, 2832 insertions, 0 deletions
diff --git a/tls/tests/all.tcl b/tls/tests/all.tcl new file mode 100644 index 0000000..aeb37a8 --- /dev/null +++ b/tls/tests/all.tcl @@ -0,0 +1,56 @@ +# all.tcl -- +# +# This file contains a top-level script to run all of the Tcl +# tests. Execute it by invoking "source all.test" when running tcltest +# in this directory. +# +# Copyright (c) 1998-2000 by Ajuba Solutions. +# All rights reserved. +# +# RCS: @(#) $Id: all.tcl,v 1.5 2000/08/15 18:45:01 hobbs Exp $ + +if {[lsearch [namespace children] ::tcltest] == -1} { + package require tcltest + namespace import ::tcltest::* +} + +set ::tcltest::testSingleFile false +set ::tcltest::testsDirectory [file dir [info script]] + +# We should ensure that the testsDirectory is absolute. +# This was introduced in Tcl 8.3+'s tcltest, so we need a catch. +catch {::tcltest::normalizePath ::tcltest::testsDirectory} + +puts stdout "Tests running in interp: [info nameofexecutable]" +puts stdout "Tests running in working dir: $::tcltest::testsDirectory" +if {[llength $::tcltest::skip] > 0} { + puts stdout "Skipping tests that match: $::tcltest::skip" +} +if {[llength $::tcltest::match] > 0} { + puts stdout "Only running tests that match: $::tcltest::match" +} + +if {[llength $::tcltest::skipFiles] > 0} { + puts stdout "Skipping test files that match: $::tcltest::skipFiles" +} +if {[llength $::tcltest::matchFiles] > 0} { + puts stdout "Only sourcing test files that match: $::tcltest::matchFiles" +} + +set timeCmd {clock format [clock seconds]} +puts stdout "Tests began at [eval $timeCmd]" + +# source each of the specified tests +foreach file [lsort [::tcltest::getMatchingFiles]] { + set tail [file tail $file] + puts stdout $tail + if {[catch {source $file} msg]} { + puts stdout $msg + } +} + +# cleanup +puts stdout "\nTests ended at [eval $timeCmd]" +::tcltest::cleanupTests 1 +return + diff --git a/tls/tests/certs/README.txt b/tls/tests/certs/README.txt new file mode 100644 index 0000000..74beaa9 --- /dev/null +++ b/tls/tests/certs/README.txt @@ -0,0 +1,9 @@ +These files were generated with openssl v0.9.6a-engine based on the +instructions at http://www-itg.lbl.gov/~boverhof/openssl_certs.html. +The file names match the examples used above. + +The PEM password is 'sample' with the basic CA info being: + +subject=/C=CA/ST=British Columbia/L=Vancouver/O=Sample Certs Intl + +These are for testing use only. diff --git a/tls/tests/certs/ca.pem b/tls/tests/certs/ca.pem new file mode 100644 index 0000000..b64683d --- /dev/null +++ b/tls/tests/certs/ca.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC2jCCAkOgAwIBAgIBADANBgkqhkiG9w0BAQQFADBYMQswCQYDVQQGEwJDQTEZ +MBcGA1UECBMQQnJpdGlzaCBDb2x1bWJpYTESMBAGA1UEBxMJVmFuY291dmVyMRow +GAYDVQQKExFTYW1wbGUgQ2VydHMgSW50bDAeFw0wMTA2MjEyMDI2MDRaFw0wMTA3 +MjEyMDI2MDRaMFgxCzAJBgNVBAYTAkNBMRkwFwYDVQQIExBCcml0aXNoIENvbHVt +YmlhMRIwEAYDVQQHEwlWYW5jb3V2ZXIxGjAYBgNVBAoTEVNhbXBsZSBDZXJ0cyBJ +bnRsMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJeHe1yfuw7YCx6nZ4hcyl +qe1JgOXSMqAzHwfHf/EdGtQUhsfsmgx9cZCKgtuZaoRKidl60MFeW2zq12ORuPUB +w90mQh46KDPRNWm1jViI/xmKUY+so6F5P/c6aA0QYqcpDhM7GgMvaAbEuY70gQ0l +uhxMv75mKMWC4RuzFyVVjwIDAQABo4GzMIGwMB0GA1UdDgQWBBTwwtcIvZ/wpImV +VC/e3C/I9qXWVTCBgAYDVR0jBHkwd4AU8MLXCL2f8KSJlVQv3twvyPal1lWhXKRa +MFgxCzAJBgNVBAYTAkNBMRkwFwYDVQQIExBCcml0aXNoIENvbHVtYmlhMRIwEAYD +VQQHEwlWYW5jb3V2ZXIxGjAYBgNVBAoTEVNhbXBsZSBDZXJ0cyBJbnRsggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEANprDWDEI9/UUkIL4kxvK8Woy +akWYabFR3s2RnxwCMDi0d7eKh+8k+NHLjD1FnWt9VNmub3sd8+PdTMk41PlLfroG +lCAd31HnYqoi498ivgpczwFj3BQSssmhld+aCFyE83KVIeMuP55fcp44vxQuEmcn +EWnH66cMUxI1D3jcQWE= +-----END CERTIFICATE----- diff --git a/tls/tests/certs/client.key b/tls/tests/certs/client.key new file mode 100644 index 0000000..6c27df7 --- /dev/null +++ b/tls/tests/certs/client.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDByy+QiN7Gde+Pf6Wvjk4OZlXfbV68mzmLh/xrXIdGQL5KqRhi +ydUZSUU87TZ/poZAFGA8kds0pmD1TWy4lGiJjoU5pxeIvl8d08Sqbh6Srxv1CKJm +J7RIp4RvEpviOSaDUC0wkLMvAAaAu2ZpNEncsotV4eSaE/WhvCHamBjpSwIDAQAB +AoGAP0q48h+Bgpep8dfiqP91BsbtbNcvhbG8jZGQIxBJLeyfOYsYZ8s7SdLgRhHD +JtWgKvV8qMuKKBvetr7erznpGdHcDDw1wutL2PagET756BjAtxcZ0lEx129eXThH +10+09QEbSlO9XRd1OvAdLCb80H97+jZXMVJ6eb/uMuVzUMECQQDzikOjJLK678fa +haesVYBqmsFAihGIUK+7Ki1F8wS6/oKLHWKDdFYoI/3Zve0qdFGFdvZicFqLAjKl +QOXxBGrpAkEAy7Vf1nmp8FAj2p1/0383EuIhjmMjQw2SHYMbTaCwbnYGJrPoeMwE +dwaaWwfgmXFeoc6lzBRUeDVz2EE6EyzqEwJBAO9XR4eSrlAHDFsWlSVJVg3ujtO1 +nOthmIKRPbML1O9M5tB/DWzxLSb/0B9ohyb8740Bz7wIfQM2Ir3DXPeThtkCQQDH +zSYrHznnUzNXgZOWxfgmtVVkayhy5CSkfauSAEIMlgaCf4NMuA7JD9jl4FwTJHdF +DYLhIC+ZmBP/0Do+BJexAkEAjrF928xMKcsrVmr7zlEhl+4B75kDkXm8TDV42PQI +WzmYuHZHwWZApU42VVlWEToIog2s0RVBOyHdiQsNwrL6Rw== +-----END RSA PRIVATE KEY----- diff --git a/tls/tests/certs/client.pem b/tls/tests/certs/client.pem new file mode 100644 index 0000000..4dcafe4 --- /dev/null +++ b/tls/tests/certs/client.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICHzCCAYgCAQEwDQYJKoZIhvcNAQEEBQAwWDELMAkGA1UEBhMCQ0ExGTAXBgNV +BAgTEEJyaXRpc2ggQ29sdW1iaWExEjAQBgNVBAcTCVZhbmNvdXZlcjEaMBgGA1UE +ChMRU2FtcGxlIENlcnRzIEludGwwHhcNMDEwNjIxMjAyOTU4WhcNMDEwNzIxMjAy +OTU4WjBYMQswCQYDVQQGEwJDQTEZMBcGA1UECBMQQnJpdGlzaCBDb2x1bWJpYTES +MBAGA1UEBxMJVmFuY291dmVyMRowGAYDVQQKExFTYW1wbGUgQ2VydHMgSW50bDCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwcsvkIjexnXvj3+lr45ODmZV321e +vJs5i4f8a1yHRkC+SqkYYsnVGUlFPO02f6aGQBRgPJHbNKZg9U1suJRoiY6FOacX +iL5fHdPEqm4ekq8b9QiiZie0SKeEbxKb4jkmg1AtMJCzLwAGgLtmaTRJ3LKLVeHk +mhP1obwh2pgY6UsCAwEAATANBgkqhkiG9w0BAQQFAAOBgQC9llXASadBxwkaEIZ7 +bmCYMWIB6+jjxa0YCY2jYgqCslny/bkLgIuxIcxf83ouFfXU52r/mq04jfuRfyRt +zCT8C+Z9nhKHdHA0cVYJ+tNuZfssQ+cFHUfjDOsCEFTJ1OoooafnIHpPXub1FcYr +SCLdcK0BwPbCcJUZrIHwu3Nu7g== +-----END CERTIFICATE----- diff --git a/tls/tests/certs/client.req b/tls/tests/certs/client.req new file mode 100644 index 0000000..2bdc56e --- /dev/null +++ b/tls/tests/certs/client.req @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBmDCCAQECAQAwWDELMAkGA1UEBhMCQ0ExGTAXBgNVBAgTEEJyaXRpc2ggQ29s +dW1iaWExEjAQBgNVBAcTCVZhbmNvdXZlcjEaMBgGA1UEChMRU2FtcGxlIENlcnRz +IEludGwwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMHLL5CI3sZ1749/pa+O +Tg5mVd9tXrybOYuH/Gtch0ZAvkqpGGLJ1RlJRTztNn+mhkAUYDyR2zSmYPVNbLiU +aImOhTmnF4i+Xx3TxKpuHpKvG/UIomYntEinhG8Sm+I5JoNQLTCQsy8ABoC7Zmk0 +Sdyyi1Xh5JoT9aG8IdqYGOlLAgMBAAGgADANBgkqhkiG9w0BAQQFAAOBgQB8xq+d +On5JqJBZcc9rW70jmSU7AlSZ48UQlmNmlUSj4YznWUCbDawEfHWv0Xpfho+bio+L +hFuzt0WsotTW1sboFpG3csHyCpGmIxw5Lacv2x5+dDx0jRbyI426+CUn+ZPv5pv8 +iiVrlyiX2P3jifQjhv39Kgbs5cOr/Ic8KKz5rg== +-----END CERTIFICATE REQUEST----- diff --git a/tls/tests/certs/file.srl b/tls/tests/certs/file.srl new file mode 100644 index 0000000..9e22bcb --- /dev/null +++ b/tls/tests/certs/file.srl @@ -0,0 +1 @@ +02 diff --git a/tls/tests/certs/privkey.pem b/tls/tests/certs/privkey.pem new file mode 100644 index 0000000..423b9ed --- /dev/null +++ b/tls/tests/certs/privkey.pem @@ -0,0 +1,18 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,E5670F088D470CF8 + +j53yMhP9QC8ZElMlyTENZ9rI6mq9hjQepTGBhku8W0JuGIDSQTbDieGNJ7myTLEo +AckDGFndIPMJFxz3GU2OYZ40sZE7CL6lkc5JsgSvt2QEp5qK30l9Ij6NnXN/BfpQ +ETliDPzDNWD0ILM43C2J/sNwgwu2SgAMj7BIn2adNuT5AN1nNXdxUg+tbGrEeH39 +eiHKTBRS+40t6KMxW1ftl85zl6WRSRM+3/URdNKUbVq0DQmpFpXT1XcKGxv4GVao +X4jyj6pE5L610cIiT3vy0qK3B3UKsQNOE8Z7aTV9eKvGk7F4LVSQpFz+DDgv/nLb +f2CLIR75MAv7FhcD/Ko+RzxfExPJB0BBsYZGarZcyd1R3rVl/rQAmd+xnZZfM5kV +iRtl7ux8NldaFkZ7XU71ZkLIiivHPDEY6gKWXe3ANsXzVxSO3Zh9okT1P7jyMaNt +Ucz7xD0T7+hnmIV4EU10h849o99F37eN3Ygjjy2xZmMsCfs/Qaem1mlJF0d87472 +7pZcOd+PgBpV2W2O9NTerd6+TPhyqGhgtucrQLID7B+eheLXaexAjgBYwHv9LbOo +uCYPS9s4DBJgvoPhz+IZ/PEZVpY/w5QJ9DsBe0xOv+KWWt9KdcA0SWRYtJUznNSS +YX3eVKZD0C3d5hgr0vSDUe/p6nsgvubHH/v/9EbruXql6PCVu0akO34n+91374pi +85G3EWEuzUwxmKDCr228W5NB2bqFet9CgtHycnQ8cjM61AYpLZx4iTCxH8s6m+lY +WRr1sFm38il8oTODZTQ6o/w91RELhyMd9MTJUZNEqqsgN4y0/r7Dww== +-----END RSA PRIVATE KEY----- diff --git a/tls/tests/certs/server.key b/tls/tests/certs/server.key new file mode 100644 index 0000000..c95d6c5 --- /dev/null +++ b/tls/tests/certs/server.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDCE6cHPOkPnOSpobuRDKTLcvjdmh1vAYmwOvXLcBkpN+PkN443 +2KURytg0rw4w7+HDS+KV13pAF5D5mSl/OOsfwQzi/dQKSVF0zlbz5L7rcBqIt2cG +Xz7gsX8VRMycXH0XC3QAAZUW32zYeo0G28uCttAh6wt8YCKu99+TNhRIWQIDAQAB +AoGAaMHQ48BGEO5gIwwwwW+wuDycBom8n4GV/7EjoaclfbE0aqhuNMjU+RCjuXRQ +Vav2EcOxT65ax6Ow1nmNA6YGi1GUAcktgMmY+Cl72iVyEqz8kUwUS1TBj0EqysCW +E57CJo6S9Htnhq9/qrJL1LvW2iH9mWobZnMbI6+jN8C/eTECQQDmrnS72ZzNJcLc +yU9uahH5BaX2vUWpWdurjYend3L9sHII3hZznYTOBn5a4kCfF2CD1FYlL7LMuV4q +qab8O5QNAkEA12CzTV3lpK8LOFX5CTT4gM5XAZvP0+YiThnRrGh15JRgZoV6Larn +X+Tvk8qYGRZdjILnNaOCqp9j3z7Mpvt2fQJAR+Z6dg6m4/5wFTcd7fFbtr1+9EAc +VWOvp3IOpTEDA3WapY7reo/PVBQMEDHTKIM1zwFA9IhAd7UTV8LXTGkZhQJAVUBU +mLojDRWwdkMpiShreOiz7dIT6Ic+avWzVfAfQjQtGEebPfpZDU8cOb7Gh5+ftd+W +z1eCgDEJIjPEZBBDLQJBAKnXJh9w47et8NZHsXjdqV/nWiZ2uzxijbEBCQTgLhcT +e4oSQidcpEPRAB5jsCZAa5czv74kDIRqYCjFL8fAT+4= +-----END RSA PRIVATE KEY----- diff --git a/tls/tests/certs/server.pem b/tls/tests/certs/server.pem new file mode 100644 index 0000000..a5d9614 --- /dev/null +++ b/tls/tests/certs/server.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICHzCCAYgCAQAwDQYJKoZIhvcNAQEEBQAwWDELMAkGA1UEBhMCQ0ExGTAXBgNV +BAgTEEJyaXRpc2ggQ29sdW1iaWExEjAQBgNVBAcTCVZhbmNvdXZlcjEaMBgGA1UE +ChMRU2FtcGxlIENlcnRzIEludGwwHhcNMDEwNjIxMjAyODUyWhcNMDEwNzIxMjAy +ODUyWjBYMQswCQYDVQQGEwJDQTEZMBcGA1UECBMQQnJpdGlzaCBDb2x1bWJpYTES +MBAGA1UEBxMJVmFuY291dmVyMRowGAYDVQQKExFTYW1wbGUgQ2VydHMgSW50bDCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwhOnBzzpD5zkqaG7kQyky3L43Zod +bwGJsDr1y3AZKTfj5DeON9ilEcrYNK8OMO/hw0vildd6QBeQ+ZkpfzjrH8EM4v3U +CklRdM5W8+S+63AaiLdnBl8+4LF/FUTMnFx9Fwt0AAGVFt9s2HqNBtvLgrbQIesL +fGAirvffkzYUSFkCAwEAATANBgkqhkiG9w0BAQQFAAOBgQBXJZfVMqZw9T4EgXQo +nM0geAByeqyOCoR+4dPv4hipf/c1m8sZgG1SxrXVThey4i4UkZenKz+VlPGDX0++ +sJBKod+aa24wcR5IQBTDuxzwduwuKkbjzGG+zdBXjOgxdcLxw7ozNciSSALYVnez +0uX7n/lAP92SlcEXhoUroMjeLQ== +-----END CERTIFICATE----- diff --git a/tls/tests/certs/server.req b/tls/tests/certs/server.req new file mode 100644 index 0000000..b7b9d26 --- /dev/null +++ b/tls/tests/certs/server.req @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBmDCCAQECAQAwWDELMAkGA1UEBhMCQ0ExGTAXBgNVBAgTEEJyaXRpc2ggQ29s +dW1iaWExEjAQBgNVBAcTCVZhbmNvdXZlcjEaMBgGA1UEChMRU2FtcGxlIENlcnRz +IEludGwwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMITpwc86Q+c5Kmhu5EM +pMty+N2aHW8BibA69ctwGSk34+Q3jjfYpRHK2DSvDjDv4cNL4pXXekAXkPmZKX84 +6x/BDOL91ApJUXTOVvPkvutwGoi3ZwZfPuCxfxVEzJxcfRcLdAABlRbfbNh6jQbb +y4K20CHrC3xgIq7335M2FEhZAgMBAAGgADANBgkqhkiG9w0BAQQFAAOBgQBsiv9V +OdF/lp3ovGfYj3DF3QyfH6p0fCuUADKgReLKOilMDPR77WE/kExxqRR9dTzlTY4n +dEmvzfmV3Vbj8KKs3L9NoLo6vF/ZeSt+RyJQlJblzXuFqxMlpZJoYcFSZO1E0Jl8 +iHe6QMOI58MBe/waEPxvIyFo2L30wScEyy/Ynw== +-----END CERTIFICATE REQUEST----- diff --git a/tls/tests/ciphers.test b/tls/tests/ciphers.test new file mode 100644 index 0000000..f79eec1 --- /dev/null +++ b/tls/tests/ciphers.test @@ -0,0 +1,159 @@ +# Commands covered: tls::ciphers +# +# This file contains a collection of tests for one or more of the Tcl +# built-in commands. Sourcing this file into Tcl runs the tests and +# generates output for errors. No output means no errors were found. +# + +# All rights reserved. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# + +if {[lsearch [namespace children] ::tcltest] == -1} { + package require tcltest + namespace import ::tcltest::* +} + +# The build dir is added as the first element of $PATH +set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + +package require tls + +# One of these should == 1, depending on what type of ssl library +# tls was compiled against. (RSA BSAFE SSL-C or OpenSSL). +# +set ::tcltest::testConstraints(rsabsafe) 0 +set ::tcltest::testConstraints(openssl) [string match "OpenSSL*" [tls::version]] + +set ::EXPECTEDCIPHERS(rsabsafe) { + EDH-DSS-RC4-SHA + EDH-RSA-DES-CBC3-SHA + EDH-DSS-DES-CBC3-SHA + DES-CBC3-SHA + RC4-SHA + RC4-MD5 + EDH-RSA-DES-CBC-SHA + EDH-DSS-DES-CBC-SHA + DES-CBC-SHA + EXP-EDH-DSS-DES-56-SHA + EXP-EDH-DSS-RC4-56-SHA + EXP-DES-56-SHA + EXP-RC4-56-SHA + EXP-EDH-RSA-DES-CBC-SHA + EXP-EDH-DSS-DES-CBC-SHA + EXP-DES-CBC-SHA + EXP-RC2-CBC-MD5 + EXP-RC4-MD5 +} + +set ::EXPECTEDCIPHERS(openssl) { + AES128-SHA + AES256-SHA + DES-CBC-SHA + DES-CBC3-SHA + DHE-DSS-AES128-SHA + DHE-DSS-AES256-SHA + DHE-DSS-RC4-SHA + DHE-RSA-AES128-SHA + DHE-RSA-AES256-SHA + EDH-DSS-DES-CBC-SHA + EDH-DSS-DES-CBC3-SHA + EDH-RSA-DES-CBC-SHA + EDH-RSA-DES-CBC3-SHA + EXP-DES-CBC-SHA + EXP-EDH-DSS-DES-CBC-SHA + EXP-EDH-RSA-DES-CBC-SHA + EXP-RC2-CBC-MD5 + EXP-RC4-MD5 + EXP1024-DES-CBC-SHA + EXP1024-DHE-DSS-DES-CBC-SHA + EXP1024-DHE-DSS-RC4-SHA + EXP1024-RC2-CBC-MD5 + EXP1024-RC4-MD5 + EXP1024-RC4-SHA + IDEA-CBC-SHA + RC4-MD5 + RC4-SHA +} + +set ::EXPECTEDCIPHERS(openssl0.9.8) { + DHE-RSA-AES256-SHA + DHE-DSS-AES256-SHA + AES256-SHA + EDH-RSA-DES-CBC3-SHA + EDH-DSS-DES-CBC3-SHA + DES-CBC3-SHA + DHE-RSA-AES128-SHA + DHE-DSS-AES128-SHA + AES128-SHA + IDEA-CBC-SHA + RC4-SHA + RC4-MD5 + EDH-RSA-DES-CBC-SHA + EDH-DSS-DES-CBC-SHA + DES-CBC-SHA + EXP-EDH-RSA-DES-CBC-SHA + EXP-EDH-DSS-DES-CBC-SHA + EXP-DES-CBC-SHA + EXP-RC2-CBC-MD5 + EXP-RC4-MD5 +} + +set version "" +if {[string match "OpenSSL*" [tls::version]]} { + regexp {OpenSSL ([\d\.]+)} [tls::version] -> version +} +if {![info exists ::EXPECTEDCIPHERS(openssl$version)]} { + set version "" +} + +proc listcompare {wants haves} { + array set want {} + array set have {} + foreach item $wants { set want($item) 1 } + foreach item $haves { set have($item) 1 } + foreach item [lsort -dictionary [array names have]] { + if {[info exists want($item)]} { + unset want($item) have($item) + } + } + if {[array size want] || [array size have]} { + return [list MISSING [array names want] UNEXPECTED [array names have]] + } +} + +test ciphers-1.1 {Tls::ciphers for ssl3} {rsabsafe} { + # This will fail if you compiled against OpenSSL. + # Change the constraint setting above. + listcompare $::EXPECTEDCIPHERS(rsabsafe) [tls::ciphers ssl3] +} {} + +test ciphers-1.2 {Tls::ciphers for tls1} {rsabsafe} { + # This will fail if you compiled against OpenSSL. + # Change the constraint setting above. + listcompare $::EXPECTEDCIPHERS(rsabsafe) [tls::ciphers tls1] +} {} + +test ciphers-1.3 {Tls::ciphers for ssl3} {openssl} { + # This will fail if you compiled against RSA bsafe or with a + # different set of defines than the default. + # Change the constraint setting above. + listcompare $::EXPECTEDCIPHERS(openssl$version) [tls::ciphers ssl3] +} {} + +# This version of the test is correct for OpenSSL only. +# An equivalent test for the RSA BSAFE SSL-C is earlier in this file. + +test ciphers-1.4 {Tls::ciphers for tls1} {openssl} { + # This will fail if you compiled against RSA bsafe or with a + # different set of defines than the default. + # Change the constraint setting in all.tcl + listcompare $::EXPECTEDCIPHERS(openssl$version) [tls::ciphers tls1] +} {} + + +# cleanup +::tcltest::cleanupTests +return diff --git a/tls/tests/keytest1.tcl b/tls/tests/keytest1.tcl new file mode 100644 index 0000000..4076d69 --- /dev/null +++ b/tls/tests/keytest1.tcl @@ -0,0 +1,23 @@ +#!/bin/sh
+# The next line is executed by /bin/sh, but not tcl \
+exec tclsh "$0" ${1+"$@"}
+
+package require tls
+
+proc creadable {s} {
+ puts "LINE=[gets $s]"
+ after 2000
+ exit
+}
+
+proc myserv {s args} {
+ fileevent $s readable [list creadable $s]
+}
+
+tls::misc req 1024 $keyfile $certfile [list C CCC ST STTT L LLLL O OOOO OU OUUUU CN CNNNN Email some@email.com days 730 serial 12]
+
+tls::socket -keyfile $keyfile -certfile $certfile -server myserv 12300
+
+puts "Now run keytest2.tcl"
+vwait forever
+
diff --git a/tls/tests/keytest2.tcl b/tls/tests/keytest2.tcl new file mode 100644 index 0000000..7b717d6 --- /dev/null +++ b/tls/tests/keytest2.tcl @@ -0,0 +1,8 @@ +package require tls + +set s [tls::socket 127.0.0.1 12300] +puts $s "A line" +flush $s +puts [join [tls::status $s] \n] +exit + diff --git a/tls/tests/remote.tcl b/tls/tests/remote.tcl new file mode 100755 index 0000000..5e454bb --- /dev/null +++ b/tls/tests/remote.tcl @@ -0,0 +1,185 @@ +# This file contains Tcl code to implement a remote server that can be +# used during testing of Tcl socket code. This server is used by some +# of the tests in socket.test. +# +# Source this file in the remote server you are using to test Tcl against. +# +# Copyright (c) 1995-1996 Sun Microsystems, Inc. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: remote.tcl,v 1.6 2004/02/11 22:41:25 razzell Exp $ + +# load tls package +package require tls + +# Initialize message delimitor + +# Initialize command array +catch {unset command} +set command(0) "" +set callerSocket "" + +# Detect whether we should print out connection messages etc. +# set VERBOSE 1 +if {![info exists VERBOSE]} { + set VERBOSE 0 +} + +proc __doCommands__ {l s} { + global callerSocket VERBOSE + + if {$VERBOSE} { + puts "--- Server executing the following for socket $s:" + puts $l + puts "---" + } + if {0} { + set fd [open remoteServer.log a] + catch {puts $fd "skey: $serverKey"} + puts $fd "--- Server executing the following for socket $s:" + puts $fd $l + puts $fd "---" + close $fd + } + set callerSocket $s + if {[catch {uplevel #0 $l} msg]} { + if {0} { + set fd [open remoteServer.log a] + puts $fd "error: $msg" + close $fd + } + list error $msg + } else { + list success $msg + } +} + +proc __readAndExecute__ {s} { + global command VERBOSE + + set l [gets $s] + if {[string compare $l "--Marker--Marker--Marker--"] == 0} { + if {[info exists command($s)]} { + puts $s [list error incomplete_command] + } + puts $s "--Marker--Marker--Marker--" + return + } + if {[string compare $l ""] == 0} { + if {[eof $s]} { + if {$VERBOSE} { + puts "Server closing $s, eof from client" + } + close $s + } + return + } + append command($s) $l "\n" + if {[info complete $command($s)]} { + set cmds $command($s) + unset command($s) + puts $s [__doCommands__ $cmds $s] + } + if {[eof $s]} { + if {$VERBOSE} { + puts "Server closing $s, eof from client" + } + close $s + } +} + +proc __accept__ {s a p} { + global VERBOSE + + if {$VERBOSE} { + puts "Server accepts new connection from $a:$p on $s" + } + tls::handshake $s + fileevent $s readable [list __readAndExecute__ $s] + fconfigure $s -buffering line -translation crlf +} + +set serverIsSilent 0 +for {set i 0} {$i < $argc} {incr i} { + if {[string compare -serverIsSilent [lindex $argv $i]] == 0} { + set serverIsSilent 1 + break + } +} +if {![info exists serverPort]} { + if {[info exists env(serverPort)]} { + set serverPort $env(serverPort) + } +} +if {![info exists serverPort]} { + for {set i 0} {$i < $argc} {incr i} { + if {[string compare -port [lindex $argv $i]] == 0} { + if {$i < [expr $argc - 1]} { + set serverPort [lindex $argv [expr $i + 1]] + } + break + } + } +} +if {![info exists serverPort]} { + set serverPort 8048 +} + +if {![info exists serverAddress]} { + if {[info exists env(serverAddress)]} { + set serverAddress $env(serverAddress) + } +} +if {![info exists serverAddress]} { + for {set i 0} {$i < $argc} {incr i} { + if {[string compare -address [lindex $argv $i]] == 0} { + if {$i < [expr $argc - 1]} { + set serverAddress [lindex $argv [expr $i + 1]] + } + break + } + } +} +if {![info exists serverAddress]} { + set serverAddress 0.0.0.0 +} + +if {$serverIsSilent == 0} { + set l "Remote server listening on port $serverPort, IP $serverAddress." + puts "" + puts $l + for {set c [string length $l]} {$c > 0} {incr c -1} {puts -nonewline "-"} + puts "" + puts "" + puts "You have set the Tcl variables serverAddress to $serverAddress and" + puts "serverPort to $serverPort. You can set these with the -address and" + puts "-port command line options, or as environment variables in your" + puts "shell." + puts "" + puts "NOTE: The tests will not work properly if serverAddress is set to" + puts "\"localhost\" or 127.0.0.1." + puts "" + puts "When you invoke tcltest to run the tests, set the variables" + puts "remoteServerPort to $serverPort and remoteServerIP to" + puts "[info hostname]. You can set these as environment variables" + puts "from the shell. The tests will not work properly if you set" + puts "remoteServerIP to \"localhost\" or 127.0.0.1." + puts "" + puts -nonewline "Type Ctrl-C to terminate--> " + flush stdout +} + +set certsDir [file join [file dirname [info script]] certs] +set serverCert [file join $certsDir server.pem] +set caCert [file join $certsDir cacert.pem] +set serverKey [file join $certsDir server.key] +if {[catch {set serverSocket \ + [tls::socket -myaddr $serverAddress -server __accept__ \ + -cafile $caCert -certfile $serverCert -keyfile $serverKey \ + $serverPort]} msg]} { + puts "Server on $serverAddress:$serverPort cannot start: $msg" +} else { + vwait __server_wait_variable__ +} diff --git a/tls/tests/simpleClient.tcl b/tls/tests/simpleClient.tcl new file mode 100755 index 0000000..6325ff1 --- /dev/null +++ b/tls/tests/simpleClient.tcl @@ -0,0 +1,113 @@ +#!/bin/sh +# The next line is executed by /bin/sh, but not tcl \ +exec tclsh8.3 "$0" ${1+"$@"} + +package require tls + +set dir [file join [file dirname [info script]] ../tests/certs] +set OPTS(-cafile) [file join $dir ca.pem] +set OPTS(-cert) [file join $dir client.pem] +set OPTS(-key) [file join $dir client.key] + +set OPTS(-host) lorax +set OPTS(-port) 2468 +set OPTS(-debug) 1 +set OPTS(-count) 8 +set OPTS(-parallel) 1 + +foreach {key val} $argv { + if {![info exists OPTS($key)]} { + puts stderr "Usage: $argv0 ?options?\ + \n\t-debug boolean Debugging on or off ($OPTS(-debug))\ + \n\t-cafile file Cert. Auth. File ($OPTS(-cafile))\ + \n\t-client file Client Cert ($OPTS(-cert))\ + \n\t-ckey file Client Key ($OPTS(-key))\ + \n\t-count num No of sync. connections to make per client ($OPTS(-count))\ + \n\t-parallel num No of parallel clients to run ($OPTS(-parallel))\ + \n\t-host hostname Server hostname ($OPTS(-host))\ + \n\t-port num Server port ($OPTS(-port))" + exit + } + set OPTS($key) $val +} + +if {$OPTS(-parallel) > 1} { + # If they wanted parallel, we just spawn ourselves several times + # with the right args. + + set cmd [info nameofexecutable] + set script [info script] + for {set i 0} {$i < $OPTS(-parallel)} {incr i} { + eval [list exec $cmd $script] [array get OPTS] [list -parallel 0] & + } + exit +} + +# Local handler for any background errors. +proc bgerror {msg} { puts "BGERROR: $msg" } + +# debugging helper code +proc shortstr {str} { + return "[string replace $str 10 end ...] [string length $str]b" +} +proc dputs {msg} { if {$::OPTS(-debug)} { puts stderr $msg ; flush stderr } } + +set OPTS(openports) 0 + +# Define what we want to feed down the pipe +set megadata [string repeat [string repeat A 76]\n 1000] + +proc drain {chan} { + global OPTS + if {[catch {read $chan} data]} { + #dputs "EOF $chan ([shortstr $data])" + incr OPTS(openports) -1 + catch {close $chan} + return + } + #if {$data != ""} { dputs "got $chan ([shortstr $data])" } + if {[string match *CLOSE\n $data]} { + dputs "CLOSE $chan" + incr OPTS(openports) -1 + close $chan + return + } elseif {[eof $chan]} { + # client gone or finished + dputs "EOF $chan" + incr OPTS(openports) -1 + close $chan + return + } +} + +proc feed {sock} { + dputs "feed $sock ([shortstr $::megadata])" + puts $sock $::megadata + flush $sock + puts $sock CLOSE + flush $sock + fileevent $sock writable {} +} + +proc go {} { + global OPTS + for {set num $OPTS(-count)} {$num > 0} {incr num -1} { + set sock [tls::socket $OPTS(-host) $OPTS(-port)] + incr OPTS(openports) + fconfigure $sock -blocking 0 -buffersize 4096 + fileevent $sock writable [list feed $sock ] + fileevent $sock readable [list drain $sock] + dputs "created $sock" + } + while {1} { + # Make sure to wait until all our sockets close down. + vwait OPTS(openports) + if {$OPTS(openports) == 0} { + exit 0 + } + } +} + +tls::init -cafile $OPTS(-cafile) -certfile $OPTS(-cert) -keyfile $OPTS(-key) + +go diff --git a/tls/tests/simpleServer.tcl b/tls/tests/simpleServer.tcl new file mode 100755 index 0000000..4450d28 --- /dev/null +++ b/tls/tests/simpleServer.tcl @@ -0,0 +1,90 @@ +#!/bin/sh +# The next line is executed by /bin/sh, but not tcl \ +exec tclsh8.3 "$0" ${1+"$@"} + +package require tls + +set dir [file join [file dirname [info script]] ../tests/certs] +set OPTS(-cafile) [file join $dir ca.pem] +set OPTS(-cert) [file join $dir server.pem] +set OPTS(-key) [file join $dir server.key] + +set OPTS(-port) 2468 +set OPTS(-debug) 1 +set OPTS(-require) 1 + +foreach {key val} $argv { + if {![info exists OPTS($key)]} { + puts stderr "Usage: $argv0 ?options?\ + \n\t-debug boolean Debugging on or off ($OPTS(-debug))\ + \n\t-cafile file Cert. Auth. File ($OPTS(-cafile))\ + \n\t-cert file Server Cert ($OPTS(-cert))\ + \n\t-key file Server Key ($OPTS(-key))\ + \n\t-require boolean Require Certification ($OPTS(-require))\ + \n\t-port num Port to listen on ($OPTS(-port))" + exit + } + set OPTS($key) $val +} + +# Catch any background errors. +proc bgerror {msg} { puts stderr "BGERROR: $msg" } + +# debugging helper code +proc shortstr {str} { + return "[string replace $str 10 end ...] [string length $str]b" +} +proc dputs {msg} { if {$::OPTS(-debug)} { puts stderr $msg ; flush stderr } } + +# As a response we just echo the data sent to us. +# +proc respond {chan} { + if {[catch {read $chan} data]} { + #dputs "EOF $chan ([shortstr $data)" + catch {close $chan} + return + } + #if {$data != ""} { dputs "got $chan ([shortstr $data])" } + if {[eof $chan]} { + # client gone or finished + dputs "EOF $chan" + close $chan ;# release the port + return + } + puts -nonewline $chan $data + flush $chan + #dputs "sent $chan ([shortstr $data])" +} + +# Once connection is established, we need to ensure handshake. +# +proc handshake {s cmd} { + if {[eof $s]} { + dputs "handshake eof $s" + close $s + } elseif {[catch {tls::handshake $s} result]} { + # Some errors are normal. Specifically, I (hobbs) believe that + # TLS throws EAGAINs when it may not need to (or is inappropriate). + dputs "handshake error $s: $result" + } elseif {$result == 1} { + # Handshake complete + dputs "handshake complete $s" + fileevent $s readable [list $cmd $s] + } +} + +# Callback proc to accept a connection from a client. +# +proc accept { chan ip port } { + dputs "[info level 0] [fconfigure $chan]" + fconfigure $chan -blocking 0 + fileevent $chan readable [list handshake $chan respond] +} + +tls::init -cafile $OPTS(-cafile) -certfile $OPTS(-cert) -keyfile $OPTS(-key) +set chan [tls::socket -server accept -require $OPTS(-require) $OPTS(-port)] + +puts "Server waiting connection on $chan ($OPTS(-port))" +puts [fconfigure $chan] + +vwait __forever__ diff --git a/tls/tests/tlsIO.test b/tls/tests/tlsIO.test new file mode 100755 index 0000000..e1d855a --- /dev/null +++ b/tls/tests/tlsIO.test @@ -0,0 +1,2072 @@ +# Commands tested in this file: socket. -*- tcl -*- +# +# This file contains a collection of tests for one or more of the Tcl +# built-in commands. Sourcing this file into Tcl runs the tests and +# generates output for errors. No output means no errors were found. +# +# Copyright (c) 1994-1996 Sun Microsystems, Inc. +# Copyright (c) 1998-2000 Ajuba Solutions. +# +# See the file "license.terms" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# RCS: @(#) $Id: tlsIO.test,v 1.24 2015/06/06 09:07:08 apnadkarni Exp $ + +# Running socket tests with a remote server: +# ------------------------------------------ +# +# Some tests in socket.test depend on the existence of a remote server to +# which they connect. The remote server must be an instance of tcltest and it +# must run the script found in the file "remote.tcl" in this directory. You +# can start the remote server on any machine reachable from the machine on +# which you want to run the socket tests, by issuing: +# +# tcltest remote.tcl -port 8048 # Or choose another port number. +# +# If the machine you are running the remote server on has several IP +# interfaces, you can choose which interface the server listens on for +# connections by specifying the -address command line flag, so: +# +# tcltest remote.tcl -address your.machine.com +# +# These options can also be set by environment variables. On Unix, you can +# type these commands to the shell from which the remote server is started: +# +# shell% setenv serverPort 8048 +# shell% setenv serverAddress your.machine.com +# +# and subsequently you can start the remote server with: +# +# tcltest remote.tcl +# +# to have it listen on port 8048 on the interface your.machine.com. +# +# When the server starts, it prints out a detailed message containing its +# configuration information, and it will block until killed with a Ctrl-C. +# Once the remote server exists, you can run the tests in socket.test with +# the server by setting two Tcl variables: +# +# % set remoteServerIP <name or address of machine on which server runs> +# % set remoteServerPort 8048 +# +# These variables are also settable from the environment. On Unix, you can: +# +# shell% setenv remoteServerIP machine.where.server.runs +# shell% setenv remoteServerPort 8048 +# +# The preamble of the socket.test file checks to see if the variables are set +# either in Tcl or in the environment; if they are, it attempts to connect to +# the server. If the connection is successful, the tests using the remote +# server will be performed; otherwise, it will attempt to start the remote +# server (via exec) on platforms that support this, on the local host, +# listening at port 8048. If all fails, a message is printed and the tests +# using the remote server are not performed. + +proc dputs {msg} { return ; puts stderr $msg ; flush stderr } + +if {[lsearch [namespace children] ::tcltest] == -1} { + package require tcltest + namespace import -force ::tcltest::* +} + +# The build dir is added as the first element of $PATH +set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] +# Load the tls package +package require tls 1.6 + +set tlsServerPort 8048 + +# Specify where the certificates are + +set certsDir [file join [file dirname [info script]] certs] +set serverCert [file join $certsDir server.pem] +set clientCert [file join $certsDir client.pem] +set caCert [file join $certsDir ca.pem] +set serverKey [file join $certsDir server.key] +set clientKey [file join $certsDir client.key] + +# Some tests require the testthread and exec commands + +set ::tcltest::testConstraints(testthread) \ + [expr {[info commands testthread] != {}}] +set ::tcltest::testConstraints(exec) [expr {[info commands exec] != {}}] + +# +# If remoteServerIP or remoteServerPort are not set, check in the +# environment variables for externally set values. +# + +if {![info exists remoteServerIP]} { + if {[info exists env(remoteServerIP)]} { + set remoteServerIP $env(remoteServerIP) + } +} +if {![info exists remoteServerPort]} { + if {[info exists env(remoteServerPort)]} { + set remoteServerPort $env(remoteServerPort) + } else { + if {[info exists remoteServerIP]} { + set remoteServerPort $tlsServerPort + } + } +} + +proc do_handshake {s {type readable} {cmd {}} args} { + if {[eof $s]} { + close $s + dputs "handshake: eof" + set ::do_handshake "eof" + } elseif {[catch {tls::handshake $s} result]} { + # Some errors are normal. + dputs "handshake: $result" + } elseif {$result == 1} { + # Handshake complete + if {[llength $args]} { eval [list fconfigure $s] $args } + if {$cmd == ""} { + fileevent $s $type "" + } else { + fileevent $s $type "$cmd [list $s]" + } + dputs "handshake: complete" + set ::do_handshake "complete" + } else { + dputs "handshake: in progress" + } +} + +# +# Check if we're supposed to do tests against the remote server +# + +set doTestsWithRemoteServer 1 +if {![info exists remoteServerIP] && ($tcl_platform(platform) != "macintosh")} { + set remoteServerIP 127.0.0.1 +} +if {($doTestsWithRemoteServer == 1) && (![info exists remoteServerPort])} { + set remoteServerPort $tlsServerPort +} + +# Attempt to connect to a remote server if one is already running. If it +# is not running or for some other reason the connect fails, attempt to +# start the remote server on the local host listening on port 8048. This +# is only done on platforms that support exec (i.e. not on the Mac). On +# platforms that do not support exec, the remote server must be started +# by the user before running the tests. + +set remoteProcChan "" +set commandSocket "" +if {$doTestsWithRemoteServer} { + catch {close $commandSocket} + if {[catch {set commandSocket [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + $remoteServerIP $remoteServerPort]}] != 0} { + if {[info commands exec] == ""} { + set noRemoteTestReason "can't exec" + set doTestsWithRemoteServer 0 + } else { + set remoteServerIP 127.0.0.1 + set remoteFile [file join [pwd] remote.tcl] + if {[catch {set remoteProcChan \ + [open "|[list $::tcltest::tcltest $remoteFile \ + -serverIsSilent -port $remoteServerPort \ + -address $remoteServerIP]" w+]} msg] == 0} { + after 1000 + if {[catch {set commandSocket [tls::socket -cafile $caCert \ + -certfile $clientCert -keyfile $clientKey \ + $remoteServerIP $remoteServerPort]} msg] == 0} { + fconfigure $commandSocket -translation crlf -buffering line + } else { + set noRemoteTestReason $msg + set doTestsWithRemoteServer 0 + } + } else { + set noRemoteTestReason "$msg $::tcltest::tcltest" + set doTestsWithRemoteServer 0 + } + } + } else { + fconfigure $commandSocket -translation crlf -buffering line + } +} + +# Some tests are run only if we are doing testing against a remote server. +set ::tcltest::testConstraints(doTestsWithRemoteServer) $doTestsWithRemoteServer +if {$doTestsWithRemoteServer == 0} { + if {[string first s $::tcltest::verbose] != -1} { + puts "Skipping tests with remote server. See tests/socket.test for" + puts "information on how to run remote server." + puts "Reason for not doing remote tests: $noRemoteTestReason" + } +} + +# +# If we do the tests, define a command to send a command to the +# remote server. +# + +if {$doTestsWithRemoteServer == 1} { + proc sendCommand {c} { + global commandSocket + + if {[eof $commandSocket]} { + error "remote server disappeared" + } + + if {[catch {puts $commandSocket $c} msg]} { + error "remote server disappeared: $msg" + } + if {[catch {puts $commandSocket "--Marker--Marker--Marker--"} msg]} { + error "remote server disappeared: $msg" + } + + set resp "" + while {1} { + set line [gets $commandSocket] + if {[eof $commandSocket]} { + error "remote server disappeared" + } + if {[string compare $line "--Marker--Marker--Marker--"] == 0} { + if {[string compare [lindex $resp 0] error] == 0} { + error [lindex $resp 1] + } else { + return [lindex $resp 1] + } + } else { + append resp $line "\n" + } + } + } + + sendCommand [list proc dputs [info args dputs] [info body dputs]] + + proc sendCertValues {} { + # We need to be able to send certificate values that normalize + # filenames across platforms + sendCommand { + set certsDir [file join [file dirname [info script]] certs] + set serverCert [file join $certsDir server.pem] + set clientCert [file join $certsDir client.pem] + set caCert [file join $certsDir cacert.pem] + set serverKey [file join $certsDir server.key] + set clientKey [file join $certsDir client.key] + } + } +} + +test tlsIO-1.1 {arg parsing for socket command} {socket} { + list [catch {tls::socket -server} msg] $msg +} {1 {wrong # args: should be "tls::socket -server command ?options? port"}} + +test tlsIO-1.2 {arg parsing for socket command} {socket} { + list [catch {tls::socket -server foo} msg] $msg +} {1 {wrong # args: should be "tls::socket -server command ?options? port"}} + +test tlsIO-1.3 {arg parsing for socket command} {socket} { + list [catch {tls::socket -myaddr} msg] $msg +} {1 {wrong # args: should be "tls::socket ?options? host port"}} + +test tlsIO-1.4 {arg parsing for socket command} {socket} { + list [catch {tls::socket -myaddr 127.0.0.1} msg] $msg +} {1 {wrong # args: should be "tls::socket ?options? host port"}} + +test tlsIO-1.5 {arg parsing for socket command} {socket} { + list [catch {tls::socket -myport} msg] $msg +} {1 {wrong # args: should be "tls::socket ?options? host port"}} + +test tlsIO-1.6 {arg parsing for socket command} {socket} { + list [catch {tls::socket -myport xxxx} msg] $msg +} {1 {wrong # args: should be "tls::socket ?options? host port"}} + +test tlsIO-1.7 {arg parsing for socket command} {socket} { + list [catch {tls::socket -myport 2522} msg] $msg +} {1 {wrong # args: should be "tls::socket ?options? host port"}} + +test tlsIO-1.8 {arg parsing for socket command} {socket} { + list [catch {tls::socket -froboz} msg] $msg +} {1 {wrong # args: should be "tls::socket ?options? host port"}} + +test tlsIO-1.9 {arg parsing for socket command} {socket} { + list [catch {tls::socket -server foo -myport 2521 3333} msg] $msg +} {1 {wrong # args: should be "tls::socket -server command ?options? port"}} + +test tlsIO-1.10 {arg parsing for socket command} {socket} { + list [catch {tls::socket host 2528 -junk} msg] $msg +} {1 {wrong # args: should be "tls::socket ?options? host port"}} + +test tlsIO-1.11 {arg parsing for socket command} {socket} { + list [catch {tls::socket -server callback 2520 --} msg] $msg +} {1 {wrong # args: should be "tls::socket -server command ?options? port"}} + +test tlsIO-1.12 {arg parsing for socket command} {socket} { + list [catch {tls::socket foo badport} msg] $msg +} {1 {expected integer but got "badport"}} + +test tlsIO-2.1 {tcp connection} {socket stdio} { + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + set timer [after 2000 "set x timed_out"] + } + puts $f "set f \[tls::socket -server accept -certfile $serverCert -cafile $caCert -keyfile $serverKey 8828 \]" + puts $f { + proc accept {file addr port} { + global x + set x done + close $file + } + puts ready + vwait x + after cancel $timer + close $f + puts $x + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r] + gets $f x + if {[catch {tls::socket -certfile $clientCert -cafile $caCert \ + -keyfile $clientKey 127.0.0.1 8828} msg]} { + set x $msg + } else { + lappend x [gets $f] + close $msg + } + lappend x [gets $f] + close $f + set x +} {ready done {}} + +if [info exists port] { + incr port +} else { + set port [expr {$tlsServerPort + [pid]%1024}] +} + +test tlsIO-2.2 {tcp connection with client port specified} {socket stdio} { + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + set timer [after 2000 "set x done"] + } + puts $f "set f \[tls::socket -server accept -certfile $serverCert -cafile $caCert -keyfile $serverKey 8829 \]" + puts $f { + proc accept {sock addr port} { + global x + puts "[gets $sock] $port" + close $sock + set x done + } + puts ready + vwait x + after cancel $timer + close $f + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r] + gets $f x + global port + if {[catch {tls::socket -myport $port \ + -certfile $clientCert -cafile $caCert \ + -keyfile $clientKey 127.0.0.1 8829} sock]} { + set x $sock + catch {close [tls::socket 127.0.0.1 8829]} + } else { + puts $sock hello + flush $sock + lappend x [gets $f] + close $sock + } + close $f + set x +} [list ready "hello $port"] + +test tlsIO-2.3 {tcp connection with client interface specified} {socket stdio} { + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + set timer [after 2000 "set x done"] + } + puts $f "set f \[tls::socket -server accept -certfile $serverCert -cafile $caCert -keyfile $serverKey 8830 \]" + puts $f { + proc accept {sock addr port} { + global x + puts "[gets $sock] $addr" + close $sock + set x done + } + puts ready + vwait x + after cancel $timer + close $f + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r] + gets $f x + if {[catch {tls::socket -myaddr 127.0.0.1 \ + -certfile $clientCert -cafile $caCert \ + -keyfile $clientKey 127.0.0.1 8830} sock]} { + set x $sock + } else { + puts $sock hello + catch {flush $sock} + lappend x [gets $f] + close $sock + } + close $f + set x +} {ready {hello 127.0.0.1}} + +test tlsIO-2.4 {tcp connection with server interface specified} {socket stdio} { + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + set timer [after 2000 "set x done"] + } + puts $f "set f \[tls::socket -server accept -certfile $serverCert -cafile $caCert -keyfile $serverKey -myaddr [info hostname] 8831 \]" + puts $f { + proc accept {sock addr port} { + global x + puts "[gets $sock]" + close $sock + set x done + } + puts ready + vwait x + after cancel $timer + close $f + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r] + gets $f x + if {[catch {tls::socket -certfile $clientCert -cafile $caCert \ + -keyfile $clientKey [info hostname] 8831} sock]} { + set x $sock + } else { + puts $sock hello + flush $sock + lappend x [gets $f] + close $sock + } + close $f + set x +} {ready hello} + +test tlsIO-2.5 {tcp connection with redundant server port} {socket stdio} { + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + set timer [after 2000 "set x done"] + } + puts $f "set f \[tls::socket -server accept -certfile $serverCert -cafile $caCert -keyfile $serverKey 8832 \]" + puts $f { + proc accept {sock addr port} { + global x + puts "[gets $sock]" + close $sock + set x done + } + puts ready + vwait x + after cancel $timer + close $f + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r] + gets $f x + if {[catch {tls::socket -certfile $clientCert -cafile $caCert \ + -keyfile $clientKey 127.0.0.1 8832} sock]} { + set x $sock + } else { + puts $sock hello + flush $sock + lappend x [gets $f] + close $sock + } + close $f + set x +} {ready hello} +test tlsIO-2.6 {tcp connection} {socket} { + set status ok + if {![catch {set sock [tls::socket 127.0.0.1 8833]}]} { + if {![catch {gets $sock}]} { + set status broken + } + close $sock + } + set status +} ok + +test tlsIO-2.7 {echo server, one line} {socket stdio} { + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + set timer [after 2000 "set x done"] + } + puts $f "set f \[tls::socket -server accept -certfile $serverCert -cafile $caCert -keyfile $serverKey 8834 \]" + puts $f { + proc accept {s a p} { + fileevent $s readable [list echo $s] + fconfigure $s -translation lf -buffering line + } + proc echo {s} { + set l [gets $s] + if {[eof $s]} { + global x + close $s + set x done + } else { + puts $s $l + } + } + puts ready + vwait x + after cancel $timer + close $f + puts done + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r] + gets $f + set s [tls::socket -certfile $clientCert -cafile $caCert \ + -keyfile $clientKey 127.0.0.1 8834] + fconfigure $s -buffering line -translation lf + puts $s "hello abcdefghijklmnop" + after 1000 + set x [gets $s] + close $s + set y [gets $f] + close $f + list $x $y +} {{hello abcdefghijklmnop} done} + +test tlsIO-2.8 {echo server, loop 50 times, single connection} {socket stdio} { + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + } + puts $f "set f \[tls::socket -server accept -certfile $serverCert -cafile $caCert -keyfile $serverKey 8835 \]" + puts $f { + proc accept {s a p} { + fileevent $s readable [list echo $s] + fconfigure $s -buffering line + } + proc echo {s} { + global i + set l [gets $s] + if {[eof $s]} { + global x + close $s + set x done + } else { + incr i + puts $s $l + } + } + set i 0 + puts ready + set timer [after 20000 "set x done"] + vwait x + after cancel $timer + close $f + puts "done $i" + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r] + gets $f + set s [tls::socket -certfile $clientCert -cafile $caCert \ + -keyfile $clientKey 127.0.0.1 8835] + fconfigure $s -buffering line + catch { + for {set x 0} {$x < 50} {incr x} { + puts $s "hello abcdefghijklmnop" + gets $s + } + } + close $s + catch {set x [gets $f]} + close $f + set x +} {done 50} + +test tlsIO-2.9 {socket conflict} {socket stdio} { + set s [tls::socket -server accept 8828] + removeFile script + set f [open script w] + puts -nonewline $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + tls::socket -server accept 8828 + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r] + gets $f + after 100 + set x [list [catch {close $f} msg] [string range $msg 0 43]] + close $s + set x +} {1 {couldn't open socket: address already in use}} + +test tlsIO-2.10 {close on accept, accepted socket lives} {socket} { + set done 0 + set timer [after 20000 "set done timed_out"] + set ss [tls::socket -server accept -certfile $serverCert -cafile $caCert \ + -keyfile $serverKey 8830] + proc accept {s a p} { + global ss + close $ss + fileevent $s readable "readit $s" + fconfigure $s -trans lf + } + proc readit {s} { + global done + gets $s + close $s + set done 1 + } + set cs [tls::socket -certfile $clientCert -cafile $caCert \ + -keyfile $clientKey [info hostname] 8830] + close $cs + + vwait done + after cancel $timer + set done +} 1 + +test tlsIO-2.11 {detecting new data} {socket} { + proc accept {s a p} { + global sock + # when doing an in-process client/server test, both sides need + # to be non-blocking for the TLS handshake. Also make sure + # to return the channel to line buffering mode. + fconfigure $s -blocking 0 -buffering line + set sock $s + fileevent $s readable [list do_handshake $s] + } + + set s [tls::socket -server accept \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey 8400] + set sock "" + set s2 [tls::socket -certfile $clientCert -cafile $caCert \ + -keyfile $clientKey 127.0.0.1 8400] + # when doing an in-process client/server test, both sides need + # to be non-blocking for the TLS handshake Also make sure to + # return the channel to line buffering mode (TLS sets it to 'none'). + fconfigure $s2 -blocking 0 -buffering line + vwait sock + puts $s2 one + flush $s2 + # need update to complete TLS handshake in-process + update + after 500 + fconfigure $sock -blocking 0 + set result a:[gets $sock] + lappend result b:[gets $sock] + fconfigure $sock -blocking 1 + puts $s2 two + flush $s2 + fconfigure $sock -blocking 0 + lappend result c:[gets $sock] + fconfigure $sock -blocking 1 + close $s2 + close $s + close $sock + set result +} {a:one b: c:two} + +test tlsIO-2.12 {tcp connection; no certificates specified} \ + {socket stdio unixOnly} { + # There is a debug assertion on Windows/SSL that causes a crash when the + # certificate isn't specified. + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + set timer [after 2000 "set x timed_out"] + set f [tls::socket -server accept 8828] + proc accept {file addr port} { + global x + set x done + close $file + } + puts ready + vwait x + after cancel $timer + close $f + puts $x + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r] + gets $f x + if {[catch {tls::socket 127.0.0.1 8828} msg]} { + set x $msg + } else { + lappend x [gets $f] + close $msg + } + lappend x [gets $f] + close $f + set x +} {ready done {}} + +test tlsIO-3.1 {socket conflict} {socket stdio} { + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + } + puts $f "set f \[tls::socket -server accept -certfile $serverCert -cafile $caCert -keyfile $serverKey 8828 \]" + puts $f { + puts ready + gets stdin + close $f + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r+] + gets $f + set x [list [catch {tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + -server accept 8828} msg] \ + $msg] + puts $f bye + close $f + set x +} {1 {couldn't open socket: address already in use}} + +test tlsIO-3.2 {server with several clients} {socket stdio} { + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + set t1 [after 30000 "set x timed_out"] + set t2 [after 31000 "set x timed_out"] + set t3 [after 32000 "set x timed_out"] + set counter 0 + } + puts $f "set s \[tls::socket -server accept -certfile $serverCert -cafile $caCert -keyfile $serverKey 8828 \]" + puts $f { + proc accept {s a p} { + fileevent $s readable [list echo $s] + fconfigure $s -buffering line + } + proc echo {s} { + global x + set l [gets $s] + if {[eof $s]} { + close $s + set x done + } else { + puts $s $l + } + } + puts ready + vwait x + after cancel $t1 + vwait x + after cancel $t2 + vwait x + after cancel $t3 + close $s + puts $x + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r+] + set x [gets $f] + set s1 [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + 127.0.0.1 8828] + fconfigure $s1 -buffering line + set s2 [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + 127.0.0.1 8828] + fconfigure $s2 -buffering line + set s3 [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + 127.0.0.1 8828] + fconfigure $s3 -buffering line + for {set i 0} {$i < 100} {incr i} { + puts $s1 hello,s1 + gets $s1 + puts $s2 hello,s2 + gets $s2 + puts $s3 hello,s3 + gets $s3 + } + close $s1 + close $s2 + close $s3 + lappend x [gets $f] + close $f + set x +} {ready done} + +test tlsIO-4.1 {server with several clients} {socket stdio} { + # have seen intermittent hangs on Windows + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + gets stdin + } + puts $f "set s \[tls::socket -certfile $clientCert -cafile $caCert -keyfile $clientKey 127.0.0.1 8828 \]" + puts $f { + fconfigure $s -buffering line + for {set i 0} {$i < 100} {incr i} { + puts $s hello + gets $s + } + close $s + puts bye + gets stdin + } + close $f + set p1 [open "|[list $::tcltest::tcltest script]" r+] + fconfigure $p1 -buffering line + set p2 [open "|[list $::tcltest::tcltest script]" r+] + fconfigure $p2 -buffering line + set p3 [open "|[list $::tcltest::tcltest script]" r+] + fconfigure $p3 -buffering line + proc accept {s a p} { + fconfigure $s -buffering line + fileevent $s readable [list echo $s] + } + proc echo {s} { + global x + set l [gets $s] + if {[eof $s]} { + close $s + set x done + } else { + puts $s $l + } + } + set t1 [after 30000 "set x timed_out"] + set t2 [after 31000 "set x timed_out"] + set t3 [after 32000 "set x timed_out"] + set s [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8828] + puts $p1 open + puts $p2 open + puts $p3 open + vwait x + vwait x + vwait x + after cancel $t1 + after cancel $t2 + after cancel $t3 + close $s + set l "" + lappend l [list p1 [gets $p1] $x] + lappend l [list p2 [gets $p2] $x] + lappend l [list p3 [gets $p3] $x] + puts $p1 bye + puts $p2 bye + puts $p3 bye + close $p1 + close $p2 + close $p3 + set l +} {{p1 bye done} {p2 bye done} {p3 bye done}} + +test tlsIO-4.2 {byte order problems, socket numbers, htons} {socket} { + set x ok + if {[catch {tls::socket -server dodo 0x3000} msg]} { + set x $msg + } else { + close $msg + } + set x +} ok + +test tlsIO-5.1 {byte order problems, socket numbers, htons} \ + {socket unixOnly notRoot} { + set x {couldn't open socket: not owner} + if {![catch {tls::socket -server dodo 0x1} msg]} { + set x {htons problem, should be disallowed, are you running as SU?} + close $msg + } + set x +} {couldn't open socket: not owner} +test tlsIO-5.2 {byte order problems, socket numbers, htons} {socket} { + set x {couldn't open socket: port number too high} + if {![catch {tls::socket -server dodo 0x10000} msg]} { + set x {port resolution problem, should be disallowed} + close $msg + } + set x +} {couldn't open socket: port number too high} +test tlsIO-5.3 {byte order problems, socket numbers, htons} \ + {socket unixOnly notRoot} { + set x {couldn't open socket: not owner} + if {![catch {tls::socket -server dodo 21} msg]} { + set x {htons problem, should be disallowed, are you running as SU?} + close $msg + } + set x +} {couldn't open socket: not owner} + +test tlsIO-6.1 {accept callback error} {socket stdio} { + # There is a debug assertion on Windows/SSL that causes a crash when the + # certificate isn't specified. + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + gets stdin + } + puts $f [list tls::socket -cafile $caCert 127.0.0.1 8848] + close $f + set f [open "|[list $::tcltest::tcltest script]" r+] + proc bgerror args { + global x + set x $args + } + proc accept {s a p} {expr 10 / 0} + set s [tls::socket -server accept \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey 8848] + puts $f hello + close $f + set timer [after 10000 "set x timed_out"] + vwait x + after cancel $timer + close $s + rename bgerror {} + set x +} {{divide by zero}} + +test tlsIO-7.1 {testing socket specific options} {socket stdio} { + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + } + puts $f [list tls::socket -server accept \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey 8820] + puts $f { + proc accept args { + global x + set x done + } + puts ready + set timer [after 10000 "set x timed_out"] + vwait x + after cancel $timer + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r] + gets $f + set s [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + 127.0.0.1 8820] + set p [fconfigure $s -peername] + close $s + close $f + set l "" + lappend l [string compare [lindex $p 0] 127.0.0.1] + lappend l [string compare [lindex $p 2] 8820] + lappend l [llength $p] +} {0 0 3} + +test tlsIO-7.2 {testing socket specific options} {socket stdio} { + removeFile script + set f [open script w] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + } + puts $f "tls::socket -server accept -certfile $serverCert -cafile $caCert -keyfile $serverKey 8821" + puts $f { + proc accept args { + global x + set x done + } + puts ready + set timer [after 10000 "set x timed_out"] + vwait x + after cancel $timer + } + close $f + set f [open "|[list $::tcltest::tcltest script]" r] + gets $f + set s [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + 127.0.0.1 8821] + set p [fconfigure $s -sockname] + close $s + close $f + set l "" + lappend l [llength $p] + lappend l [lindex $p 0] + lappend l [string equal [lindex $p 2] 8821] +} {3 127.0.0.1 0} + +test tlsIO-7.3 {testing socket specific options} {socket} { + set s [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8822] + set l [llength [fconfigure $s]] + close $s + update + # A bug fixed in fconfigure for 8.3.4+ make this return 14 normally, + # but 12 in older versions. + expr {$l >= 12 && (($l % 2) == 0)} +} 1 + +# bug report #5812 fconfigure doesn't return value for '-sockname' + +test tlsIO-7.4 {testing socket specific options} {socket} { + set s [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8823] + proc accept {s a p} { + global x + set x [fconfigure $s -sockname] + close $s + } + set s1 [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + [info hostname] 8823] + set timer [after 10000 "set x timed_out"] + vwait x + after cancel $timer + close $s + close $s1 + set l "" + lappend l [lindex $x 2] [llength $x] +} {8823 3} + +# bug report #5812 fconfigure doesn't return value for '-sockname' + +test tlsIO-7.5 {testing socket specific options} {socket unixOrPc} { + set s [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8829] + proc accept {s a p} { + global x + set x [fconfigure $s -sockname] + close $s + } + set s1 [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + 127.0.0.1 8829] + set timer [after 10000 "set x timed_out"] + vwait x + after cancel $timer + close $s + close $s1 + set l "" + lappend l [lindex $x 0] [lindex $x 2] [llength $x] +} {127.0.0.1 8829 3} + +test tlsIO-8.1 {testing -async flag on sockets} {socket} { + # NOTE: This test may fail on some Solaris 2.4 systems. + # See notes in Tcl's socket.test. + set s [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8830] + proc accept {s a p} { + global x + # when doing an in-process client/server test, both sides need + # to be non-blocking for the TLS handshake. Also make sure + # to return the channel to line buffering mode. + fconfigure $s -blocking 0 -buffering line + puts $s bye + # Only OpenSSL 0.9.5a on Windows seems to need the after (delayed) + # close, but it works just the same for all others. -hobbs + after 500 close $s + set x done + } + set s1 [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + -async [info hostname] 8830] + # when doing an in-process client/server test, both sides need + # to be non-blocking for the TLS handshake Also make sure to + # return the channel to line buffering mode (TLS sets it to 'none'). + fconfigure $s1 -blocking 0 -buffering line + vwait x + # TLS handshaking needs one byte from the client... + puts $s1 a + # need update to complete TLS handshake in-process + update + set z [gets $s1] + close $s + close $s1 + set z +} bye + +test tlsIO-9.1 {testing spurious events} {socket} { + set len 0 + set spurious 0 + set done 0 + proc readlittle {s} { + global spurious done len + set l [read $s 1] + if {[string length $l] == 0} { + if {![eof $s]} { + incr spurious + } else { + close $s + set done 1 + } + } else { + incr len [string length $l] + } + } + proc accept {s a p} { + fconfigure $s -blocking 0 + fileevent $s readable [list do_handshake $s readable readlittle \ + -buffering none] + } + set s [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8831] + set c [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + [info hostname] 8831] + # This differs from socket-9.1 in that both sides need to be + # non-blocking because of TLS' required handshake + fconfigure $c -blocking 0 + puts -nonewline $c 01234567890123456789012345678901234567890123456789 + close $c + set timer [after 10000 "set done timed_out"] + vwait done + after cancel $timer + close $s + list $spurious $len +} {0 50} + +test tlsIO-9.2 {testing async write, fileevents, flush on close} {socket} { + set firstblock [string repeat a 31] + set secondblock [string repeat b 65535] + proc accept {s a p} { + fconfigure $s -blocking 0 + fileevent $s readable [list do_handshake $s readable readable \ + -translation lf -buffersize 16384 -buffering line] + } + proc readable {s} { + set l [gets $s] + dputs "got \"[string replace $l 10 end-3 ...]\" \ + ([string length $l]) from $s" + fileevent $s readable {} + after 1000 respond $s + } + proc respond {s} { + global firstblock + dputs "send \"[string replace $firstblock 10 end-3 ...]\" \ + ([string length $firstblock]) down $s" + puts -nonewline $s $firstblock + after 1000 writedata $s + } + proc writedata {s} { + global secondblock + dputs "send \"[string replace $secondblock 10 end-3 ...]\" \ + ([string length $secondblock]) down $s" + puts -nonewline $s $secondblock + close $s + } + set s [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8832] + set c [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + [info hostname] 8832] + fconfigure $c -blocking 0 -trans lf -buffering line + set count 0 + puts $c hello + proc readit {s} { + global count done + set data [read $s] + dputs "read \"[string replace $data 10 end-3 ...]\" \ + ([string length $data]) from $s" + incr count [string length $data] + if {[eof $s]} { + close $s + set done 1 + } + } + fileevent $c readable "readit $c" + set done 0 + set timer [after 10000 "set done timed_out"] + vwait done + after cancel $timer + close $s + list $count $done +} {65566 1} + +test tlsIO-9.3 {testing EOF stickyness} {unexplainedFailure socket} { + # HOBBS: never worked correctly + proc count_to_eof {s} { + global count done timer + set l [gets $s] + if {[eof $s]} { + incr count + if {$count > 9} { + close $s + set done true + set count {eof is sticky} + after cancel $timer + } + } + } + proc timerproc {} { + global done count c + set done true + set count {timer went off, eof is not sticky} + close $c + } + set count 0 + set done false + proc write_then_close {s} { + puts $s bye + close $s + } + proc accept {s a p} { + fconfigure $s -blocking 0 -buffering line -translation lf + fileevent $s writable [list do_handshake $s writable write_then_close \ + -buffering line -translation lf] + } + set s [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8833] + set c [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + [info hostname] 8833] + fconfigure $c -blocking 0 -buffering line -translation lf + fileevent $c readable "count_to_eof $c" + set timer [after 2000 timerproc] + vwait done + close $s + set count +} {eof is sticky} + +removeFile script + +test tlsIO-10.1 {testing socket accept callback error handling} {socket} { + set goterror 0 + proc bgerror args {global goterror; set goterror 1} + set s [tls::socket -cafile $caCert -server accept 8898] + proc accept {s a p} {close $s; error} + set c [tls::socket -cafile $caCert 127.0.0.1 8898] + vwait goterror + close $s + close $c + set goterror +} 1 + +test tlsIO-11.1 {tcp connection} {socket doTestsWithRemoteServer} { + sendCertValues + sendCommand { + set socket9_1_test_server [tls::socket -server accept \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey 8834] + proc accept {s a p} { + tls::handshake $s + puts $s done + close $s + } + } + set s [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + $remoteServerIP 8834] + set r [gets $s] + close $s + sendCommand {close $socket9_1_test_server} + set r +} done + +test tlsIO-11.2 {client specifies its port} {socket doTestsWithRemoteServer} { + if {[info exists port]} { + incr port + } else { + set port [expr {$tlsServerPort + [pid]%1024}] + } + sendCertValues + sendCommand { + set socket9_2_test_server [tls::socket -server accept \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey 8835] + proc accept {s a p} { + tls::handshake $s + puts $s $p + close $s + } + } + set s [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + -myport $port $remoteServerIP 8835] + set r [gets $s] + close $s + sendCommand {close $socket9_2_test_server} + if {$r == $port} { + set result ok + } else { + set result broken + } + set result +} ok + +test tlsIO-11.3 {trying to connect, no server} {socket doTestsWithRemoteServer} { + set status ok + if {![catch {set s [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + $remoteServerIp 8836]}]} { + if {![catch {gets $s}]} { + set status broken + } + close $s + } + set status +} ok + +test tlsIO-11.4 {remote echo, one line} {socket doTestsWithRemoteServer} { + sendCertValues + sendCommand { + set socket10_6_test_server [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8836] + proc accept {s a p} { + tls::handshake $s + fileevent $s readable [list echo $s] + fconfigure $s -buffering line -translation crlf + } + proc echo {s} { + set l [gets $s] + if {[eof $s]} { + close $s + } else { + puts $s $l + } + } + } + set f [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + $remoteServerIP 8836] + fconfigure $f -translation crlf -buffering line + puts $f hello + set r [gets $f] + close $f + sendCommand {close $socket10_6_test_server} + set r +} hello + +test tlsIO-11.5 {remote echo, 50 lines} {socket doTestsWithRemoteServer} { + sendCertValues + sendCommand { + set socket10_7_test_server [tls::socket -server accept \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey 8836] + proc accept {s a p} { + tls::handshake $s + fileevent $s readable [list echo $s] + fconfigure $s -buffering line -translation crlf + } + proc echo {s} { + set l [gets $s] + if {[eof $s]} { + close $s + } else { + puts $s $l + } + } + } + set f [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + $remoteServerIP 8836] + fconfigure $f -translation crlf -buffering line + for {set cnt 0} {$cnt < 50} {incr cnt} { + puts $f "hello, $cnt" + if {[string compare [gets $f] "hello, $cnt"] != 0} { + break + } + } + close $f + sendCommand {close $socket10_7_test_server} + set cnt +} 50 + +# Macintosh sockets can have more than one server per port +if {$tcl_platform(platform) == "macintosh"} { + set conflictResult {0 8836} +} else { + set conflictResult {1 {couldn't open socket: address already in use}} +} + +test tlsIO-11.6 {socket conflict} {socket doTestsWithRemoteServer} { + set s1 [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8836] + if {[catch {set s2 [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8836]} msg]} { + set result [list 1 $msg] + } else { + set result [list 0 [lindex [fconfigure $s2 -sockname] 2]] + close $s2 + } + close $s1 + set result +} $conflictResult + +test tlsIO-11.7 {server with several clients} {socket doTestsWithRemoteServer} { + sendCertValues + sendCommand { + set socket10_9_test_server [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8836] + proc accept {s a p} { + fconfigure $s -buffering line + fileevent $s readable [list echo $s] + } + proc echo {s} { + set l [gets $s] + if {[eof $s]} { + close $s + } else { + puts $s $l + } + } + } + set s1 [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + $remoteServerIP 8836] + fconfigure $s1 -buffering line + set s2 [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + $remoteServerIP 8836] + fconfigure $s2 -buffering line + set s3 [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + $remoteServerIP 8836] + fconfigure $s3 -buffering line + for {set i 0} {$i < 100} {incr i} { + puts $s1 hello,s1 + gets $s1 + puts $s2 hello,s2 + gets $s2 + puts $s3 hello,s3 + gets $s3 + } + close $s1 + close $s2 + close $s3 + sendCommand {close $socket10_9_test_server} + set i +} 100 + +test tlsIO-11.8 {client with several servers} {socket doTestsWithRemoteServer} { + sendCertValues + sendCommand { + tls::init -certfile $serverCert -cafile $caCert -keyfile $serverKey + set s1 [tls::socket -server "accept 4003" 4003] + set s2 [tls::socket -server "accept 4004" 4004] + set s3 [tls::socket -server "accept 4005" 4005] + proc handshake {s mp} { + if {[eof $s]} { + close $s + } elseif {[catch {tls::handshake $s} result]} { + # Some errors are normal. + } elseif {$result == 1} { + # Handshake complete + fileevent $s readable "" + puts $s $mp + close $s + } + } + proc accept {mp s a p} { + # These have to accept non-blocking, because the handshaking + # order isn't deterministic + fconfigure $s -blocking 0 -buffering line + fileevent $s readable [list handshake $s $mp] + } + } + tls::init -certfile $clientCert -cafile $caCert -keyfile $clientKey + set s1 [tls::socket $remoteServerIP 4003] + set s2 [tls::socket $remoteServerIP 4004] + set s3 [tls::socket $remoteServerIP 4005] + set l "" + lappend l [gets $s1] [gets $s1] [eof $s1] [gets $s2] [gets $s2] [eof $s2] \ + [gets $s3] [gets $s3] [eof $s3] + close $s1 + close $s2 + close $s3 + sendCommand { + close $s1 + close $s2 + close $s3 + } + set l +} {4003 {} 1 4004 {} 1 4005 {} 1} + +test tlsIO-11.9 {accept callback error} {socket doTestsWithRemoteServer} { + set s [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8836] + proc accept {s a p} {expr 10 / 0} + proc bgerror args { + global x + set x $args + } + sendCertValues + if {[catch {sendCommand { + set peername [fconfigure $callerSocket -peername] + set s [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + [lindex $peername 0] 8836] + close $s + }} msg]} { + close $s + error $msg + } + set timer [after 10000 "set x timed_out"] + vwait x + after cancel $timer + close $s + rename bgerror {} + set x +} {{divide by zero}} + +test tlsIO-11.10 {testing socket specific options} {socket doTestsWithRemoteServer} { + sendCertValues + sendCommand { + set socket10_12_test_server [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8836] + proc accept {s a p} {close $s} + } + set s [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + $remoteServerIP 8836] + set p [fconfigure $s -peername] + set n [fconfigure $s -sockname] + set l "" + lappend l [lindex $p 2] [llength $p] [llength $p] + close $s + sendCommand {close $socket10_12_test_server} + set l +} {8836 3 3} + +test tlsIO-11.11 {testing spurious events} {socket doTestsWithRemoteServer} { + # remote equivalent of 9.1 + sendCertValues + sendCommand { + set socket_test_server [tls::socket -server accept \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey 8836] + proc handshake {s} { + if {[eof $s]} { + close $s + } elseif {[catch {tls::handshake $s} result]} { + # Some errors are normal. + } elseif {$result == 1} { + # Handshake complete + fileevent $s writable "" + after 100 writesome $s + } + } + proc accept {s a p} { + fconfigure $s -translation "auto lf" + fileevent $s writable [list handshake $s] + } + proc writesome {s} { + for {set i 0} {$i < 100} {incr i} { + puts $s "line $i from remote server" + } + close $s + } + } + set len 0 + set spurious 0 + set done 0 + proc readlittle {s} { + global spurious done len + set l [read $s 1] + if {[string length $l] == 0} { + if {![eof $s]} { + incr spurious + } else { + close $s + set done 1 + } + } else { + incr len [string length $l] + } + } + set c [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + $remoteServerIP 8836] + # Get the buffering corrected + fconfigure $c -buffering line + # Put a byte into the client pipe to trigger TLS handshaking + puts $c a + fileevent $c readable [list readlittle $c] + set timer [after 10000 "set done timed_out"] + vwait done + after cancel $timer + sendCommand {close $socket_test_server} + list $spurious $len +} {0 2690} + +test tlsIO-11.12 {testing EOF stickyness} {unexplainedFailure socket doTestsWithRemoteServer} { + # remote equivalent of 9.3 + # HOBBS: never worked correctly + set counter 0 + set done 0 + proc count_up {s} { + global counter done after_id + set l [gets $s] + if {[eof $s]} { + incr counter + if {$counter > 9} { + set done {EOF is sticky} + after cancel $after_id + close $s + } + } + } + proc timed_out {} { + global c done + set done {timed_out, EOF is not sticky} + close $c + } + sendCertValues + sendCommand { + set socket10_14_test_server [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8836] + proc accept {s a p} { + tls::handshake $s + after 100 close $s + } + } + set c [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + $remoteServerIP 8836] + fileevent $c readable "count_up $c" + set after_id [after 1000 timed_out] + vwait done + sendCommand {close $socket10_14_test_server} + set done +} {EOF is sticky} + +test tlsIO-11.13 {testing async write, async flush, async close} \ + {socket doTestsWithRemoteServer} { + proc readit {s} { + global count done + set l [read $s] + incr count [string length $l] + if {[eof $s]} { + close $s + set done 1 + } + } + sendCertValues + sendCommand { + set firstblock [string repeat a 31] + set secondblock [string repeat b 65535] + set l [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8845] + proc accept {s a p} { + tls::handshake $s + fconfigure $s -blocking 0 -translation lf -buffersize 16384 \ + -buffering line + fileevent $s readable "readable $s" + } + proc readable {s} { + set l [gets $s] + fileevent $s readable {} + after 1000 respond $s + } + proc respond {s} { + global firstblock + puts -nonewline $s $firstblock + after 1000 writedata $s + } + proc writedata {s} { + global secondblock + puts -nonewline $s $secondblock + close $s + } + } + set s [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + $remoteServerIP 8845] + fconfigure $s -blocking 0 -translation lf -buffering line + set count 0 + puts $s hello + fileevent $s readable "readit $s" + set timer [after 10000 "set done timed_out"] + vwait done + after cancel $timer + sendCommand {close $l} + set count +} 65566 + +proc getdata {type file} { + # Read handler on the accepted socket. + global x + global failed + set status [catch {read $file} data] + if {$status != 0} { + set x "read failed, error was $data" + catch { close $file } + } elseif {[string compare {} $data]} { + } elseif {[fblocked $file]} { + } elseif {[eof $file]} { + if {$failed} { + set x "$type socket was inherited" + } else { + set x "$type socket was not inherited" + } + catch { close $file } + } else { + set x {impossible case} + catch { close $file } + } + return +} + +test tlsIO-12.1 {testing inheritance of server sockets} {socket exec} { + makeFile {} script1 + makeFile {} script2 + + # Script1 is just a 10 second delay. If the server socket + # is inherited, it will be held open for 10 seconds + + set f [open script1 w] + puts $f { + after 10000 exit + vwait forever + } + close $f + + # Script2 creates the server socket, launches script1, + # waits a second, and exits. The server socket will now + # be closed unless script1 inherited it. + + set f [open script2 w] + puts $f [list set tclsh $::tcltest::tcltest] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + } + puts $f "set f \[tls::socket -server accept \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey 8828\]" + puts $f { + proc accept { file addr port } { + close $file + } + exec $tclsh script1 & + close $f + after 1000 exit + vwait forever + } + close $f + + # Launch script2 and wait 5 seconds + + exec $::tcltest::tcltest script2 & + after 5000 { set ok_to_proceed 1 } + vwait ok_to_proceed + + # If we can still connect to the server, the socket got inherited. + + if {[catch {tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + 127.0.0.1 8828} msg]} { + set x {server socket was not inherited} + } else { + close $msg + set x {server socket was inherited} + } + + set x +} {server socket was not inherited} + +test tlsIO-12.2 {testing inheritance of client sockets} {socket exec} { + makeFile {} script1 + makeFile {} script2 + + # Script1 is just a 10 second delay. If the server socket + # is inherited, it will be held open for 10 seconds + + set f [open script1 w] + puts $f { + after 10000 exit + vwait forever + } + close $f + + # Script2 opens the client socket and writes to it. It then + # launches script1 and exits. If the child process inherited the + # client socket, the socket will still be open. + + set f [open script2 w] + puts $f [list set tclsh $::tcltest::tcltest] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + } + puts $f "set f \[tls::socket -certfile $clientCert -cafile $caCert \ + -keyfile $clientKey 127.0.0.1 8829\]" + puts $f { + exec $tclsh script1 & + puts $f testing + flush $f + after 1000 exit + vwait forever + } + close $f + + # Create the server socket + + set server [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8829] + proc accept { file host port } { + # When the client connects, establish the read handler + global server + close $server + fconfigure $file -blocking 0 + fileevent $file readable [list do_handshake $file readable \ + [list getdata client] -buffering line] + return + } + + # If the socket doesn't hit end-of-file in 5 seconds, the + # script1 process must have inherited the client. + + set failed 0 + after 5000 [list set failed 1] + + # Launch the script2 process + + exec $::tcltest::tcltest script2 & + + vwait x + if {!$failed} { + vwait failed + } + set x +} {client socket was not inherited} + +test tlsIO-12.3 {testing inheritance of accepted sockets} \ + {socket exec unixOnly} { + makeFile {} script1 + makeFile {} script2 + + set f [open script1 w] + puts $f { + after 10000 exit + vwait forever + } + close $f + + set f [open script2 w] + puts $f [list set tclsh $::tcltest::tcltest] + puts $f { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + } + puts $f "set f \[tls::socket -server accept \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey 8930\]" + puts $f { + proc accept { file host port } { + global tclsh + fconfigure $file -buffering line + puts $file {test data on socket} + exec $tclsh script1 & + after 1000 exit + } + vwait forever + } + close $f + + # Launch the script2 process and connect to it. See how long + # the socket stays open + + exec $::tcltest::tcltest script2 & + + after 2000 set ok_to_proceed 1 + vwait ok_to_proceed + + set f [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + 127.0.0.1 8930] + fconfigure $f -buffering full -blocking 0 + # We need to put a byte into the read queue, otherwise the + # TLS handshake doesn't finish + puts $f a; flush $f + fileevent $f readable [list getdata accepted $f] + + # If the socket is still open after 5 seconds, the script1 process + # must have inherited the accepted socket. + + set failed 0 + after 5000 set failed 1 + + vwait x + set x +} {accepted socket was not inherited} + +test tlsIO-13.1 {Testing use of shared socket between two threads} \ + {socket testthread} { + # HOBBS: never tested + removeFile script + threadReap + + makeFile { + set auto_path [linsert $auto_path 0 [lindex [split $env(PATH) ";:"] 0]] + package require tls + set f [tls::socket -server accept 8828] + proc accept {s a p} { + fileevent $s readable [list echo $s] + fconfigure $s -buffering line + } + proc echo {s} { + global i + set l [gets $s] + if {[eof $s]} { + global x + close $s + set x done + } else { + incr i + puts $s $l + } + } + set i 0 + vwait x + close $f + + # thread cleans itself up. + testthread exit + } script + + # create a thread + set serverthread [testthread create { source script } ] + update + + after 1000 + set s [tls::socket 127.0.0.1 8828] + fconfigure $s -buffering line + + catch { + puts $s "hello" + gets $s result + } + close $s + update + + after 2000 + lappend result [threadReap] + + set result + +} {hello 1} + +test tlsIO-14.1 {test tls::unimport} {socket} { + list [catch {tls::unimport} msg] $msg +} {1 {wrong # args: should be "tls::unimport channel"}} +test tlsIO-14.2 {test tls::unimport} {socket} { + list [catch {tls::unimport foo bar} msg] $msg +} {1 {wrong # args: should be "tls::unimport channel"}} +test tlsIO-14.3 {test tls::unimport} {socket} { + list [catch {tls::unimport bogus} msg] $msg +} {1 {can not find channel named "bogus"}} +test tlsIO-14.4 {test tls::unimport} {socket} { + # stdin can take different names as the "top" channel + list [catch {tls::unimport stdin} msg] \ + [string match {bad channel "*": not a TLS channel} $msg] +} {1 1} +test tlsIO-14.5 {test tls::unimport} {socket} { + set len 0 + set spurious 0 + set done 0 + proc readlittle {s} { + global spurious done len + set l [read $s 1] + if {[string length $l] == 0} { + if {![eof $s]} { + incr spurious + } else { + close $s + set done 1 + } + } else { + incr len [string length $l] + } + } + proc accept {s a p} { + fconfigure $s -blocking 0 + fileevent $s readable [list do_handshake $s readable readlittle \ + -buffering none] + } + set s [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -server accept 8831] + set c [tls::socket \ + -certfile $clientCert -cafile $caCert -keyfile $clientKey \ + [info hostname] 8831] + # only the client gets tls::import + set res [tls::unimport $c] + list $res [catch {close $c} err] $err \ + [catch {close $s} err] $err +} {{} 0 {} 0 {}} + +test tls-bug58-1.0 {test protocol negotiation failure} {socket} { + # Following code is based on what was reported in bug #58. Prior + # to fix the program would crash with a segfault. + proc Accept {sock args} { + fconfigure $sock -blocking 0; + fileevent $sock readable [list Handshake $sock] + } + proc Handshake {sock} { + set ::done HAND + catch {tls::handshake $sock} msg + set ::done $msg + } + # NOTE: when doing an in-process client/server test, both sides need + # to be non-blocking for the TLS handshake + + # Server - Only accept TLS 1 or higher + set s [tls::socket \ + -certfile $serverCert -cafile $caCert -keyfile $serverKey \ + -request 0 -require 0 -ssl2 0 -ssl3 0 -tls1 1 -tls1.1 1 -tls1.2 1 \ + -server Accept 8831] + # Client - Only propose SSL3 + set c [tls::socket -async \ + -cafile $caCert \ + -request 0 -require 0 -ssl2 0 -ssl3 1 -tls1 0 -tls1.1 0 -tls1.2 0 \ + [info hostname] 8831] + fconfigure $c -blocking 0 + puts $c a ; flush $c + after 5000 [list set ::done timeout] + vwait ::done + set ::done +} {handshake failed: wrong version number} + +# cleanup +if {[string match sock* $commandSocket] == 1} { + puts $commandSocket exit + flush $commandSocket +} +catch {close $commandSocket} +catch {close $remoteProcChan} +::tcltest::cleanupTests +flush stdout +return |