diff options
Diffstat (limited to 'tests/auto/network/ssl/qsslsocket')
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/.gitignore | 1 | ||||
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/certs/aspiriniks.ca.crt | 22 | ||||
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/certs/fake-login.live.com.key | 15 | ||||
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/certs/fake-login.live.com.pem | 19 | ||||
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/certs/fluke.cert | 75 | ||||
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/certs/fluke.key | 15 | ||||
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/certs/qt-test-server-cacert.pem | 17 | ||||
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/qsslsocket.pro | 48 | ||||
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/ssl.tar.gz | bin | 0 -> 36299 bytes | |||
-rw-r--r-- | tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp | 2097 |
10 files changed, 2309 insertions, 0 deletions
diff --git a/tests/auto/network/ssl/qsslsocket/.gitignore b/tests/auto/network/ssl/qsslsocket/.gitignore new file mode 100644 index 0000000000..f2319a97eb --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/.gitignore @@ -0,0 +1 @@ +tst_qsslsocket diff --git a/tests/auto/network/ssl/qsslsocket/certs/aspiriniks.ca.crt b/tests/auto/network/ssl/qsslsocket/certs/aspiriniks.ca.crt new file mode 100644 index 0000000000..36436b6248 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/aspiriniks.ca.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDnDCCAoQCCQDV3otC4hs2KTANBgkqhkiG9w0BAQUFADCBjzELMAkGA1UEBhMC +Tk8xDTALBgNVBAgTBE9zbG8xDTALBgNVBAcTBE9zbG8xDzANBgNVBAoTBlRUIEFT +QTEOMAwGA1UECxMFUVQgU1cxHDAaBgNVBAMTE2FzcGlyaW5pa3MudHJvbGwubm8x +IzAhBgkqhkiG9w0BCQEWFGFiYWJpY0B0cm9sbHRlY2guY29tMB4XDTA4MTEwMTA4 +NTcyOFoXDTA5MTEwMTA4NTcyOFowgY8xCzAJBgNVBAYTAk5PMQ0wCwYDVQQIEwRP +c2xvMQ0wCwYDVQQHEwRPc2xvMQ8wDQYDVQQKEwZUVCBBU0ExDjAMBgNVBAsTBVFU +IFNXMRwwGgYDVQQDExNhc3BpcmluaWtzLnRyb2xsLm5vMSMwIQYJKoZIhvcNAQkB +FhRhYmFiaWNAdHJvbGx0ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAMV2bMD1DN3DMgbxU3DXw2i7EWGDXcWjTDtdHvqgIb+9nHqo3MJSrzJy +qgEPoOsXqswMla9wDPZAsWv5gVAmVSqpy2lfEgfY7LaSHiGD75seF7zIy+CxREHW +DofHXpJGGJpBCZEKQt2HfHu3+yAYNPucN78tWNZAcPbUg5tfxMZeepRimAZNIxBI +93SDrl/f9Ka7hvPSzUQsnp8hfdpHlFPFznKfD6yPrjxgz2mT9efavJ4DhtyIa4m+ +paiX515CidDz4A8CFxKZbYvuqq1ilibF/si2so9VhALC77ZcAJP1IMuT8T+WUCxq +skJqiSCncl0Hgr+ba8MDGF9UQYowgjMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +KcJuNUHvjB8ok3cnTmQEeF0LPPkgj28Tqb5TFB8xpVfRI+wvTYsHsmGdOKCgYJ3a +7VflIsr63ojG8/rXK8H/cx2o2f2Hr3liJdi1UnoLDDRjBqGGz7JNuMreYokPvIbm +eP01mVyK4PO2iYRwHUIAw5eeB1vMWKX2z95MupD+HRLtmGyaLALg8aQxj5N84Ewl +eU2PQfhv8A1wj7aL17kfEUxDerQ1kUzlThJMV1J8Dl0l4C9N8evQkelROJU00i46 +oJikA8BW6EpgbnGyNyyj5Loy4wLPKew9nTS8MCJ5xPMQc0urbY/VzuOeUK7WQof7 +xOFSsRAVyQv+yqgmcZMCtg== +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/fake-login.live.com.key b/tests/auto/network/ssl/qsslsocket/certs/fake-login.live.com.key new file mode 100644 index 0000000000..692a7bd85d --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/fake-login.live.com.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDOtxdvMa0VHUQYG5q7Tsi1Jj4qKEJppyZEkmuRXOi0fDbd1SwE +bwHrLGMvDO6OMrYBbq3WDNrtnIfF9CvzUOEch+gjr4hEVQqecU5fb45Wor7yNel3 +/C/gxfbzuXHrsj/gUjNghL2i10+c2NW+hUo/sWO6OusaBT6d6s7ee+YBcQIDAQAB +AoGAb8cVhu0HuLkgjyCuJMbPRRUu3ED02Iin6sB6JhplQuNAD+grayJTmUVhRJnr +jTziqhedLHe7Em1oBaSo92MutfMpXvWiccSlbNygI61VgmrJpVB+qIN5H9cQc9ql +Zymc+nIPa1+i5rsrOzlpUytTh7AsbZ27QG4tQXR/kQejEiECQQD6BgTxBeT8D7x9 +DuukoBaSCkLwx7U7P1NXx15EI3lA1nO51t6UHfvk/jGPp8Sl4wv4alJ7AQxr5uQ/ +vC3kzA/1AkEA06gNu10se8pe3n8qL2RRt+FmVjHkQdD9Mm2Dx9oWCs2A4wOSOrlo +6/nKYF1CaQNYn9HgsNbHVEUpnICVO18qDQJBALEw/uOJ1+TDikPfBSWgxx4s45Ad +GNWqZXh6NNZ5hX9r/IwiOZAjR9fcRmeW8IjYRi2BvH6sGY+HDRAWXzgdXtkCQCma +dOiJTf8fLjqp4E7kdzOfuI/kyqstOze4Uxjrgz2oW1dEEnA8laUcumzqp+0gXUE8 +7d+UuCWWWrGKjMrYz9kCQQDh5E5+b6Djn082Jo6gvyuXWC5eXju6IdmihlJ2SMzD +s2y3IDjOUtTeQQRDymLneteMz0ha79KeUp6VnAvZCOVe +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/fake-login.live.com.pem b/tests/auto/network/ssl/qsslsocket/certs/fake-login.live.com.pem new file mode 100644 index 0000000000..429f95187c --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/fake-login.live.com.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDjCCAnegAwIBAgIRALC3Ez7Qlvm1b66RyHS9OsAwDQYJKoZIhvcNAQEFBQAw +XjELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGElu +dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEXMBUGA1UEAxMObG9naW4ubGl2ZS5jb20w +HhcNMTEwMzI1MTMyODUwWhcNMTEwNDI0MTMyODUwWjBeMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMRcwFQYDVQQDEw5sb2dpbi5saXZlLmNvbTCBnzANBgkqhkiG9w0BAQEF +AAOBjQAwgYkCgYEAzrcXbzGtFR1EGBuau07ItSY+KihCaacmRJJrkVzotHw23dUs +BG8B6yxjLwzujjK2AW6t1gza7ZyHxfQr81DhHIfoI6+IRFUKnnFOX2+OVqK+8jXp +d/wv4MX287lx67I/4FIzYIS9otdPnNjVvoVKP7FjujrrGgU+nerO3nvmAXECAwEA +AaOByzCByDAdBgNVHQ4EFgQUpSOEcmtkQITvBdM2IDfcXnJ0FCAwgZgGA1UdIwSB +kDCBjYAUpSOEcmtkQITvBdM2IDfcXnJ0FCChYqRgMF4xCzAJBgNVBAYTAkFVMRMw +EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0 +eSBMdGQxFzAVBgNVBAMTDmxvZ2luLmxpdmUuY29tghEAsLcTPtCW+bVvrpHIdL06 +wDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAD+2HT4GSHHKCdbl9VkX +zsl+D+drMm2b0ksxz9SgPihP7aW50EEIJDEEihNMTa27mhpeOXHc/sLqDi4ECUao +/0Ns/5uoVuAIrAKCydmtPsonVFh9XWjyrfUzPOHAc9p2bmJ1i9a3kTsLB6jlrVDO +VufGzsowHlHZ0TtKf5omojU5 +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/fluke.cert b/tests/auto/network/ssl/qsslsocket/certs/fluke.cert new file mode 100644 index 0000000000..069fa6b341 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/fluke.cert @@ -0,0 +1,75 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=NO, ST=Oslo, L=Nydalen, O=Nokia Corporation and/or its subsidiary(-ies), OU=Development, CN=fluke.troll.no/emailAddress=ahanssen@trolltech.com + Validity + Not Before: Dec 4 01:10:32 2007 GMT + Not After : Apr 21 01:10:32 2035 GMT + Subject: C=NO, ST=Oslo, O=Nokia Corporation and/or its subsidiary(-ies), OU=Development, CN=fluke.troll.no + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:a7:c8:a0:4a:c4:19:05:1b:66:ba:32:e2:d2:f1: + 1c:6f:17:82:e4:39:2e:01:51:90:db:04:34:32:11: + 21:c2:0d:6f:59:d8:53:90:54:3f:83:8f:a9:d3:b3: + d5:ee:1a:9b:80:ae:c3:25:c9:5e:a5:af:4b:60:05: + aa:a0:d1:91:01:1f:ca:04:83:e3:58:1c:99:32:45: + 84:70:72:58:03:98:4a:63:8b:41:f5:08:49:d2:91: + 02:60:6b:e4:64:fe:dd:a0:aa:74:08:e9:34:4c:91: + 5f:12:3d:37:4d:54:2c:ad:7f:5b:98:60:36:02:8c: + 3b:f6:45:f3:27:6a:9b:94:9d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 21:85:04:3D:23:01:66:E5:F7:9F:1A:84:24:8A:AF:0A:79:F4:E5:AC + X509v3 Authority Key Identifier: + DirName:/C=NO/ST=Oslo/L=Nydalen/O=Nokia Corporation and/or its subsidiary(-ies)/OU=Development/CN=fluke.troll.no/emailAddress=ahanssen@trolltech.com + serial:8E:A8:B4:E8:91:B7:54:2E + + Signature Algorithm: sha1WithRSAEncryption + 6d:57:5f:d1:05:43:f0:62:05:ec:2a:71:a5:dc:19:08:f2:c4: + a6:bd:bb:25:d9:ca:89:01:0e:e4:cf:1f:c1:8c:c8:24:18:35: + 53:59:7b:c0:43:b4:32:e6:98:b2:a6:ef:15:05:0b:48:5f:e1: + a0:0c:97:a9:a1:77:d8:35:18:30:bc:a9:8f:d3:b7:54:c7:f1: + a9:9e:5d:e6:19:bf:f6:3c:5b:2b:d8:e4:3e:62:18:88:8b:d3: + 24:e1:40:9b:0c:e6:29:16:62:ab:ea:05:24:70:36:aa:55:93: + ef:02:81:1b:23:10:a2:04:eb:56:95:75:fc:f8:94:b1:5d:42: + c5:3f:36:44:85:5d:3a:2e:90:46:8a:a2:b9:6f:87:ae:0c:15: + 40:19:31:90:fc:3b:25:bb:ae:f1:66:13:0d:85:90:d9:49:34: + 8f:f2:5d:f9:7a:db:4d:5d:27:f6:76:9d:35:8c:06:a6:4c:a3: + b1:b2:b6:6f:1d:d7:a3:00:fd:72:eb:9e:ea:44:a1:af:21:34: + 7d:c7:42:e2:49:91:19:8b:c0:ad:ba:82:80:a8:71:70:f4:35: + 31:91:63:84:20:95:e9:60:af:64:8b:cc:ff:3d:8a:76:74:3d: + c8:55:6d:e4:8e:c3:2b:1c:e8:42:18:ae:9f:e6:6b:9c:34:06: + ec:6a:f2:c3 +-----BEGIN CERTIFICATE----- +MIIEEzCCAvugAwIBAgIBADANBgkqhkiG9w0BAQUFADCBnDELMAkGA1UEBhMCTk8x +DTALBgNVBAgTBE9zbG8xEDAOBgNVBAcTB055ZGFsZW4xFjAUBgNVBAoTDVRyb2xs +dGVjaCBBU0ExFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5mbHVrZS50 +cm9sbC5ubzElMCMGCSqGSIb3DQEJARYWYWhhbnNzZW5AdHJvbGx0ZWNoLmNvbTAe +Fw0wNzEyMDQwMTEwMzJaFw0zNTA0MjEwMTEwMzJaMGMxCzAJBgNVBAYTAk5PMQ0w +CwYDVQQIEwRPc2xvMRYwFAYDVQQKEw1Ucm9sbHRlY2ggQVNBMRQwEgYDVQQLEwtE +ZXZlbG9wbWVudDEXMBUGA1UEAxMOZmx1a2UudHJvbGwubm8wgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBAKfIoErEGQUbZroy4tLxHG8XguQ5LgFRkNsENDIRIcIN +b1nYU5BUP4OPqdOz1e4am4CuwyXJXqWvS2AFqqDRkQEfygSD41gcmTJFhHByWAOY +SmOLQfUISdKRAmBr5GT+3aCqdAjpNEyRXxI9N01ULK1/W5hgNgKMO/ZF8ydqm5Sd +AgMBAAGjggEaMIIBFjAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM +IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUIYUEPSMBZuX3nxqEJIqv +Cnn05awwgbsGA1UdIwSBszCBsKGBoqSBnzCBnDELMAkGA1UEBhMCTk8xDTALBgNV +BAgTBE9zbG8xEDAOBgNVBAcTB055ZGFsZW4xFjAUBgNVBAoTDVRyb2xsdGVjaCBB +U0ExFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5mbHVrZS50cm9sbC5u +bzElMCMGCSqGSIb3DQEJARYWYWhhbnNzZW5AdHJvbGx0ZWNoLmNvbYIJAI6otOiR +t1QuMA0GCSqGSIb3DQEBBQUAA4IBAQBtV1/RBUPwYgXsKnGl3BkI8sSmvbsl2cqJ +AQ7kzx/BjMgkGDVTWXvAQ7Qy5piypu8VBQtIX+GgDJepoXfYNRgwvKmP07dUx/Gp +nl3mGb/2PFsr2OQ+YhiIi9Mk4UCbDOYpFmKr6gUkcDaqVZPvAoEbIxCiBOtWlXX8 ++JSxXULFPzZEhV06LpBGiqK5b4euDBVAGTGQ/Dslu67xZhMNhZDZSTSP8l35ettN +XSf2dp01jAamTKOxsrZvHdejAP1y657qRKGvITR9x0LiSZEZi8CtuoKAqHFw9DUx +kWOEIJXpYK9ki8z/PYp2dD3IVW3kjsMrHOhCGK6f5mucNAbsavLD +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/fluke.key b/tests/auto/network/ssl/qsslsocket/certs/fluke.key new file mode 100644 index 0000000000..9d1664d609 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/fluke.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCnyKBKxBkFG2a6MuLS8RxvF4LkOS4BUZDbBDQyESHCDW9Z2FOQ +VD+Dj6nTs9XuGpuArsMlyV6lr0tgBaqg0ZEBH8oEg+NYHJkyRYRwclgDmEpji0H1 +CEnSkQJga+Rk/t2gqnQI6TRMkV8SPTdNVCytf1uYYDYCjDv2RfMnapuUnQIDAQAB +AoGANFzLkanTeSGNFM0uttBipFT9F4a00dqHz6JnO7zXAT26I5r8sU1pqQBb6uLz +/+Qz5Zwk8RUAQcsMRgJetuPQUb0JZjF6Duv24hNazqXBCu7AZzUenjafwmKC/8ri +KpX3fTwqzfzi//FKGgbXQ80yykSSliDL3kn/drATxsLCgQECQQDXhEFWLJ0vVZ1s +1Ekf+3NITE+DR16X+LQ4W6vyEHAjTbaNWtcTKdAWLA2l6N4WAAPYSi6awm+zMxx4 +VomVTsjdAkEAx0z+e7natLeFcrrq8pbU+wa6SAP1VfhQWKitxL1e7u/QO90NCpxE +oQYKzMkmmpOOFjQwEMAy1dvFMbm4LHlewQJAC/ksDBaUcQHHqjktCtrUb8rVjAyW +A8lscckeB2fEYyG5J6dJVaY4ClNOOs5yMDS2Afk1F6H/xKvtQ/5CzInA/QJATDub +K+BPU8jO9q+gpuIi3VIZdupssVGmCgObVCHLakG4uO04y9IyPhV9lA9tALtoIf4c +VIvv5fWGXBrZ48kZAQJBAJmVCdzQxd9LZI5vxijUCj5EI4e+x5DRqVUvyP8KCZrC +AiNyoDP85T+hBZaSXK3aYGpVwelyj3bvo1GrTNwNWLw= +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/qt-test-server-cacert.pem b/tests/auto/network/ssl/qsslsocket/certs/qt-test-server-cacert.pem new file mode 100644 index 0000000000..25bd4046e8 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/qt-test-server-cacert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICrTCCAhYCCQCdDn5rci6VDjANBgkqhkiG9w0BAQQFADCBmjEOMAwGA1UEChMF +Tm9raWExFDASBgNVBAsTC1F0IFNvZnR3YXJlMSIwIAYJKoZIhvcNAQkBFhNub2Jv +ZHlAbm9kb21haW4ub3JnMQ0wCwYDVQQHEwRPc2xvMQ0wCwYDVQQIEwRPc2xvMQsw +CQYDVQQGEwJOTzEjMCEGA1UEAxMacXQtdGVzdC1zZXJ2ZXIucXQtdGVzdC1uZXQw +HhcNMDkwNzEwMDc0MTIzWhcNMTkwNzA4MDc0MTIzWjCBmjEOMAwGA1UEChMFTm9r +aWExFDASBgNVBAsTC1F0IFNvZnR3YXJlMSIwIAYJKoZIhvcNAQkBFhNub2JvZHlA +bm9kb21haW4ub3JnMQ0wCwYDVQQHEwRPc2xvMQ0wCwYDVQQIEwRPc2xvMQswCQYD +VQQGEwJOTzEjMCEGA1UEAxMacXQtdGVzdC1zZXJ2ZXIucXQtdGVzdC1uZXQwgZ8w +DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM2q22/WNMmn8cC+5EEYGeICySLmp9W6 +Ay6eKHr0Xxp3X3epETuPfvAuxp7rOtkS18EMUegkUj8jw0IMEcbyHKFC/rTCaYOt +93CxGBXMIChiMPAsFeYzGa/D6xzAkfcRaJRQ+Ek3CDLXPnXfo7xpABXezYcPXAJr +gsgBfWrwHdxzAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAy7YOLCZABQy2Ygkchq1I ++TUpvMn+gLwAyW8TNErM1V4lNY2+K78RawzKx3SqM97ymCy4TD45EA3A2gmi32NI +xSKBNjFyzngUqsXBdcSasALiowlZCiJrGwlGX5qCkBlxXvJeUEbuJLPYVl5FBjXZ +6o00K4cSPCqtqUez7WSmDZU= +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/qsslsocket.pro b/tests/auto/network/ssl/qsslsocket/qsslsocket.pro new file mode 100644 index 0000000000..1f5c7f6aaf --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/qsslsocket.pro @@ -0,0 +1,48 @@ +load(qttest_p4) + +SOURCES += tst_qsslsocket.cpp +!wince*:win32:LIBS += -lws2_32 +QT += core-private network-private +QT -= gui + +TARGET = tst_qsslsocket + +win32 { + CONFIG(debug, debug|release) { + DESTDIR = debug +} else { + DESTDIR = release + } +} + +# OpenSSL support +contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { + symbian { + INCLUDEPATH *= $$OS_LAYER_SSL_SYSTEMINCLUDE + } else { + include($$QT_SOURCE_TREE/config.tests/unix/openssl/openssl.pri) + } + # Add optional SSL libs + LIBS += $$OPENSSL_LIBS +} + +wince* { + DEFINES += SRCDIR=\\\"./\\\" + + certFiles.files = certs ssl.tar.gz + certFiles.path = . + DEPLOYMENT += certFiles +} else:symbian { + DEFINES += QSSLSOCKET_CERTUNTRUSTED_WORKAROUND + TARGET.EPOCHEAPSIZE="0x100 0x3000000" + TARGET.CAPABILITY=NetworkServices ReadUserData + + certFiles.files = certs ssl.tar.gz + certFiles.path = . + DEPLOYMENT += certFiles + INCLUDEPATH *= $$MW_LAYER_SYSTEMINCLUDE # Needed for e32svr.h in S^3 envs +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} + +requires(contains(QT_CONFIG,private_tests)) diff --git a/tests/auto/network/ssl/qsslsocket/ssl.tar.gz b/tests/auto/network/ssl/qsslsocket/ssl.tar.gz Binary files differnew file mode 100644 index 0000000000..b59af51f46 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/ssl.tar.gz diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp new file mode 100644 index 0000000000..6b7720308d --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -0,0 +1,2097 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtCore/qthread.h> +#include <QtNetwork/qhostaddress.h> +#include <QtNetwork/qhostinfo.h> +#include <QtNetwork/qnetworkproxy.h> +#include <QtNetwork/qsslcipher.h> +#include <QtNetwork/qsslconfiguration.h> +#include <QtNetwork/qsslkey.h> +#include <QtNetwork/qsslsocket.h> +#include <QtNetwork/qtcpserver.h> +#include <QtTest/QtTest> + +#include <QNetworkProxy> +#include <QAuthenticator> + +#include "private/qhostinfo_p.h" +#ifndef QT_NO_OPENSSL +#include "private/qsslsocket_openssl_p.h" +#include "private/qsslsocket_openssl_symbols_p.h" +#endif + +#include "../../../network-settings.h" + +Q_DECLARE_METATYPE(QAbstractSocket::SocketState) +Q_DECLARE_METATYPE(QAbstractSocket::SocketError) +#ifndef QT_NO_OPENSSL +Q_DECLARE_METATYPE(QSslSocket::SslMode) +typedef QList<QSslError::SslError> SslErrorList; +Q_DECLARE_METATYPE(SslErrorList) +Q_DECLARE_METATYPE(QSslError) +Q_DECLARE_METATYPE(QSsl::SslProtocol) +Q_DECLARE_METATYPE(QSslConfiguration) +#endif + +#if defined Q_OS_HPUX && defined Q_CC_GNU +// This error is delivered every time we try to use the fluke CA +// certificate. For now we work around this bug. Task 202317. +#define QSSLSOCKET_CERTUNTRUSTED_WORKAROUND +#endif + +#ifdef Q_OS_SYMBIAN +#define SRCDIR "" +#endif + +#ifndef QT_NO_OPENSSL +class QSslSocketPtr: public QSharedPointer<QSslSocket> +{ +public: + inline QSslSocketPtr(QSslSocket *ptr = 0) + : QSharedPointer<QSslSocket>(ptr) + { } + + inline operator QSslSocket *() const { return data(); } +}; +#endif + +class tst_QSslSocket : public QObject +{ + Q_OBJECT + + int proxyAuthCalled; + +public: + tst_QSslSocket(); + virtual ~tst_QSslSocket(); + + static void enterLoop(int secs) + { + ++loopLevel; + QTestEventLoop::instance().enterLoop(secs); + } + + static bool timeout() + { + return QTestEventLoop::instance().timeout(); + } + +#ifndef QT_NO_OPENSSL + QSslSocketPtr newSocket(); +#endif + +public slots: + void initTestCase_data(); + void init(); + void cleanup(); + void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth); + +#ifndef QT_NO_OPENSSL +private slots: + void constructing(); + void simpleConnect(); + void simpleConnectWithIgnore(); + + // API tests + void sslErrors_data(); + void sslErrors(); + void addCaCertificate(); + void addCaCertificates(); + void addCaCertificates2(); + void ciphers(); + void connectToHostEncrypted(); + void connectToHostEncryptedWithVerificationPeerName(); + void sessionCipher(); + void flush(); + void isEncrypted(); + void localCertificate(); + void mode(); + void peerCertificate(); + void peerCertificateChain(); + void privateKey(); + void privateKeyOpaque(); + void protocol(); + void protocolServerSide_data(); + void protocolServerSide(); + void setCaCertificates(); + void setLocalCertificate(); + void setPrivateKey(); + void setSocketDescriptor(); + void setSslConfiguration_data(); + void setSslConfiguration(); + void waitForEncrypted(); + void waitForEncryptedMinusOne(); + void waitForConnectedEncryptedReadyRead(); + void startClientEncryption(); + void startServerEncryption(); + void addDefaultCaCertificate(); + void addDefaultCaCertificates(); + void addDefaultCaCertificates2(); + void defaultCaCertificates(); + void defaultCiphers(); + void resetDefaultCiphers(); + void setDefaultCaCertificates(); + void setDefaultCiphers(); + void supportedCiphers(); + void systemCaCertificates(); + void wildcardCertificateNames(); + void wildcard(); + void setEmptyKey(); + void spontaneousWrite(); + void setReadBufferSize(); + void setReadBufferSize_task_250027(); + void waitForMinusOne(); + void verifyMode(); + void verifyDepth(); + void peerVerifyError(); + void disconnectFromHostWhenConnecting(); + void disconnectFromHostWhenConnected(); + void resetProxy(); + void ignoreSslErrorsList_data(); + void ignoreSslErrorsList(); + void ignoreSslErrorsListWithSlot_data(); + void ignoreSslErrorsListWithSlot(); + void readFromClosedSocket(); + void writeBigChunk(); + void blacklistedCertificates(); + void setEmptyDefaultConfiguration(); + void versionAccessors(); + + static void exitLoop() + { + // Safe exit - if we aren't in an event loop, don't + // exit one. + if (loopLevel > 0) { + --loopLevel; + QTestEventLoop::instance().exitLoop(); + } + } + +protected slots: + void ignoreErrorSlot() + { + socket->ignoreSslErrors(); + } + void untrustedWorkaroundSlot(const QList<QSslError> &errors) + { + if (errors.size() == 1 && + (errors.first().error() == QSslError::CertificateUntrusted || + errors.first().error() == QSslError::SelfSignedCertificate)) + socket->ignoreSslErrors(); + } + void ignoreErrorListSlot(const QList<QSslError> &errors); + +private: + QSslSocket *socket; + QList<QSslError> storedExpectedSslErrors; +#endif // QT_NO_OPENSSL +private: + static int loopLevel; +}; + +int tst_QSslSocket::loopLevel = 0; + +tst_QSslSocket::tst_QSslSocket() +{ +#ifndef QT_NO_OPENSSL + qRegisterMetaType<QList<QSslError> >("QList<QSslError>"); + qRegisterMetaType<QSslError>("QSslError"); + qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState"); + qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError"); + qRegisterMetaType<QAbstractSocket::SocketState>("QSslSocket::SslMode"); +#endif + Q_SET_DEFAULT_IAP +} + +tst_QSslSocket::~tst_QSslSocket() +{ +} + +enum ProxyTests { + NoProxy = 0x00, + Socks5Proxy = 0x01, + HttpProxy = 0x02, + TypeMask = 0x0f, + + NoAuth = 0x00, + AuthBasic = 0x10, + AuthNtlm = 0x20, + AuthMask = 0xf0 +}; + +void tst_QSslSocket::initTestCase_data() +{ + QTest::addColumn<bool>("setProxy"); + QTest::addColumn<int>("proxyType"); + + QTest::newRow("WithoutProxy") << false << 0; + QTest::newRow("WithSocks5Proxy") << true << int(Socks5Proxy); + QTest::newRow("WithSocks5ProxyAuth") << true << int(Socks5Proxy | AuthBasic); + + QTest::newRow("WithHttpProxy") << true << int(HttpProxy); + QTest::newRow("WithHttpProxyBasicAuth") << true << int(HttpProxy | AuthBasic); + // uncomment the line below when NTLM works +// QTest::newRow("WithHttpProxyNtlmAuth") << true << int(HttpProxy | AuthNtlm); +} + +void tst_QSslSocket::init() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) { + QFETCH_GLOBAL(int, proxyType); + QString fluke = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(); + QNetworkProxy proxy; + + switch (proxyType) { + case Socks5Proxy: + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, fluke, 1080); + break; + + case Socks5Proxy | AuthBasic: + proxy = QNetworkProxy(QNetworkProxy::Socks5Proxy, fluke, 1081); + break; + + case HttpProxy | NoAuth: + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3128); + break; + + case HttpProxy | AuthBasic: + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3129); + break; + + case HttpProxy | AuthNtlm: + proxy = QNetworkProxy(QNetworkProxy::HttpProxy, fluke, 3130); + break; + } + QNetworkProxy::setApplicationProxy(proxy); + } + + qt_qhostinfo_clear_cache(); +} + +void tst_QSslSocket::cleanup() +{ + QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy); +} + +#ifndef QT_NO_OPENSSL +QSslSocketPtr tst_QSslSocket::newSocket() +{ + QSslSocket *socket = new QSslSocket; + + proxyAuthCalled = 0; + connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + Qt::DirectConnection); + + return QSslSocketPtr(socket); +} +#endif + +void tst_QSslSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth) +{ + ++proxyAuthCalled; + auth->setUser("qsockstest"); + auth->setPassword("password"); +} + +#ifndef QT_NO_OPENSSL + +void tst_QSslSocket::constructing() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocket socket; + + QCOMPARE(socket.state(), QSslSocket::UnconnectedState); + QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode); + QVERIFY(!socket.isEncrypted()); + QCOMPARE(socket.bytesAvailable(), qint64(0)); + QCOMPARE(socket.bytesToWrite(), qint64(0)); + QVERIFY(!socket.canReadLine()); + QVERIFY(socket.atEnd()); + QCOMPARE(socket.localCertificate(), QSslCertificate()); + QCOMPARE(socket.sslConfiguration(), QSslConfiguration::defaultConfiguration()); + QCOMPARE(socket.errorString(), QString("Unknown error")); + char c = '\0'; + QVERIFY(!socket.getChar(&c)); + QCOMPARE(c, '\0'); + QVERIFY(!socket.isOpen()); + QVERIFY(!socket.isReadable()); + QVERIFY(socket.isSequential()); + QVERIFY(!socket.isTextModeEnabled()); + QVERIFY(!socket.isWritable()); + QCOMPARE(socket.openMode(), QIODevice::NotOpen); + QVERIFY(socket.peek(2).isEmpty()); + QCOMPARE(socket.pos(), qint64(0)); + QVERIFY(!socket.putChar('c')); + QVERIFY(socket.read(2).isEmpty()); + QCOMPARE(socket.read(0, 0), qint64(-1)); + QVERIFY(socket.readAll().isEmpty()); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::readLine: Called with maxSize < 2"); + QCOMPARE(socket.readLine(0, 0), qint64(-1)); + char buf[10]; + QCOMPARE(socket.readLine(buf, sizeof(buf)), qint64(-1)); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::seek: The device is not open"); + QVERIFY(!socket.reset()); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::seek: The device is not open"); + QVERIFY(!socket.seek(2)); + QCOMPARE(socket.size(), qint64(0)); + QVERIFY(!socket.waitForBytesWritten(10)); + QVERIFY(!socket.waitForReadyRead(10)); + QCOMPARE(socket.write(0, 0), qint64(-1)); + QCOMPARE(socket.write(QByteArray()), qint64(-1)); + QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError); + QVERIFY(!socket.flush()); + QVERIFY(!socket.isValid()); + QCOMPARE(socket.localAddress(), QHostAddress()); + QCOMPARE(socket.localPort(), quint16(0)); + QCOMPARE(socket.peerAddress(), QHostAddress()); + QVERIFY(socket.peerName().isEmpty()); + QCOMPARE(socket.peerPort(), quint16(0)); + QCOMPARE(socket.proxy().type(), QNetworkProxy::DefaultProxy); + QCOMPARE(socket.readBufferSize(), qint64(0)); + QCOMPARE(socket.socketDescriptor(), -1); + QCOMPARE(socket.socketType(), QAbstractSocket::TcpSocket); + QVERIFY(!socket.waitForConnected(10)); + QTest::ignoreMessage(QtWarningMsg, "QSslSocket::waitForDisconnected() is not allowed in UnconnectedState"); + QVERIFY(!socket.waitForDisconnected(10)); + QCOMPARE(socket.protocol(), QSsl::SecureProtocols); + + QSslConfiguration savedDefault = QSslConfiguration::defaultConfiguration(); + + // verify that changing the default config doesn't affect this socket + // (on Unix, the ca certs might be empty, depending on whether we load + // them on demand or not, so set them explicitly) + socket.setCaCertificates(QSslSocket::systemCaCertificates()); + QSslSocket::setDefaultCaCertificates(QList<QSslCertificate>()); + QSslSocket::setDefaultCiphers(QList<QSslCipher>()); + QVERIFY(!socket.caCertificates().isEmpty()); + QVERIFY(!socket.ciphers().isEmpty()); + + // verify the default as well: + QVERIFY(QSslConfiguration::defaultConfiguration().caCertificates().isEmpty()); + QVERIFY(QSslConfiguration::defaultConfiguration().ciphers().isEmpty()); + + QSslConfiguration::setDefaultConfiguration(savedDefault); +} + +void tst_QSslSocket::simpleConnect() +{ + if (!QSslSocket::supportsSsl()) + return; + + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + QSslSocket socket; + QSignalSpy connectedSpy(&socket, SIGNAL(connected())); + QSignalSpy hostFoundSpy(&socket, SIGNAL(hostFound())); + QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected())); + QSignalSpy connectionEncryptedSpy(&socket, SIGNAL(encrypted())); + QSignalSpy sslErrorsSpy(&socket, SIGNAL(sslErrors(const QList<QSslError> &))); + + connect(&socket, SIGNAL(connected()), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(disconnected()), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(modeChanged(QSslSocket::SslMode)), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(encrypted()), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(exitLoop())); + + // Start connecting + socket.connectToHost(QtNetworkSettings::serverName(), 993); + QCOMPARE(socket.state(), QAbstractSocket::HostLookupState); + enterLoop(10); + + // Entered connecting state +#ifndef Q_OS_SYMBIAN + QCOMPARE(socket.state(), QAbstractSocket::ConnectingState); + QCOMPARE(connectedSpy.count(), 0); +#endif + QCOMPARE(hostFoundSpy.count(), 1); + QCOMPARE(disconnectedSpy.count(), 0); + enterLoop(10); + + // Entered connected state + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode); + QVERIFY(!socket.isEncrypted()); + QCOMPARE(connectedSpy.count(), 1); + QCOMPARE(hostFoundSpy.count(), 1); + QCOMPARE(disconnectedSpy.count(), 0); + + // Enter encrypted mode + socket.startClientEncryption(); + QCOMPARE(socket.mode(), QSslSocket::SslClientMode); + QVERIFY(!socket.isEncrypted()); + QCOMPARE(connectionEncryptedSpy.count(), 0); + QCOMPARE(sslErrorsSpy.count(), 0); + + // Starting handshake + enterLoop(10); + QCOMPARE(sslErrorsSpy.count(), 1); + QCOMPARE(connectionEncryptedSpy.count(), 0); + QVERIFY(!socket.isEncrypted()); + QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState); +} + +void tst_QSslSocket::simpleConnectWithIgnore() +{ + if (!QSslSocket::supportsSsl()) + return; + + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + QSslSocket socket; + this->socket = &socket; + QSignalSpy encryptedSpy(&socket, SIGNAL(encrypted())); + QSignalSpy sslErrorsSpy(&socket, SIGNAL(sslErrors(const QList<QSslError> &))); + + connect(&socket, SIGNAL(readyRead()), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(encrypted()), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(connected()), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot())); + connect(&socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(exitLoop())); + + // Start connecting + socket.connectToHost(QtNetworkSettings::serverName(), 993); + QVERIFY(socket.state() != QAbstractSocket::UnconnectedState); // something must be in progress + enterLoop(10); + + // Start handshake + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + socket.startClientEncryption(); + enterLoop(10); + + // Done; encryption should be enabled. + QCOMPARE(sslErrorsSpy.count(), 1); + QVERIFY(socket.isEncrypted()); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + QCOMPARE(encryptedSpy.count(), 1); + + // Wait for incoming data + if (!socket.canReadLine()) + enterLoop(10); + + QByteArray data = socket.readAll(); + socket.disconnectFromHost(); + QVERIFY2(QtNetworkSettings::compareReplyIMAPSSL(data), data.constData()); +} + +void tst_QSslSocket::sslErrors_data() +{ + QTest::addColumn<QString>("host"); + QTest::addColumn<int>("port"); + QTest::addColumn<SslErrorList>("expected"); + + QTest::newRow(qPrintable(QtNetworkSettings::serverLocalName())) + << QtNetworkSettings::serverLocalName() + << 993 + << (SslErrorList() << QSslError::HostNameMismatch + << QSslError::SelfSignedCertificate); +} + +void tst_QSslSocket::sslErrors() +{ + QFETCH(QString, host); + QFETCH(int, port); + QFETCH(SslErrorList, expected); + + QSslSocketPtr socket = newSocket(); + socket->connectToHostEncrypted(host, port); + if (!socket->waitForConnected()) + QEXPECT_FAIL("imap.trolltech.com", "server not open to internet", Continue); + socket->waitForEncrypted(5000); + + SslErrorList output; + foreach (QSslError error, socket->sslErrors()) { + output << error.error(); + } + +#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND + if (output.count() && output.last() == QSslError::CertificateUntrusted) + output.takeLast(); +#endif + QCOMPARE(output, expected); +} + +void tst_QSslSocket::addCaCertificate() +{ + if (!QSslSocket::supportsSsl()) + return; +} + +void tst_QSslSocket::addCaCertificates() +{ + if (!QSslSocket::supportsSsl()) + return; +} + +void tst_QSslSocket::addCaCertificates2() +{ + if (!QSslSocket::supportsSsl()) + return; +} + +void tst_QSslSocket::ciphers() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocket socket; + QCOMPARE(socket.ciphers(), QSslSocket::supportedCiphers()); + socket.setCiphers(QList<QSslCipher>()); + QVERIFY(socket.ciphers().isEmpty()); + socket.setCiphers(socket.defaultCiphers()); + QCOMPARE(socket.ciphers(), QSslSocket::supportedCiphers()); + socket.setCiphers(socket.defaultCiphers()); + QCOMPARE(socket.ciphers(), QSslSocket::supportedCiphers()); + + // Task 164356 + socket.setCiphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); +} + +void tst_QSslSocket::connectToHostEncrypted() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocketPtr socket = newSocket(); + this->socket = socket; + QVERIFY(socket->addCaCertificates(QLatin1String(SRCDIR "certs/qt-test-server-cacert.pem"))); +#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND + connect(socket, SIGNAL(sslErrors(QList<QSslError>)), + this, SLOT(untrustedWorkaroundSlot(QList<QSslError>))); +#endif + + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + + // This should pass unconditionally when using fluke's CA certificate. + // or use untrusted certificate workaround + QVERIFY2(socket->waitForEncrypted(10000), qPrintable(socket->errorString())); + + socket->disconnectFromHost(); + QVERIFY(socket->waitForDisconnected()); + + QCOMPARE(socket->mode(), QSslSocket::SslClientMode); + + socket->connectToHost(QtNetworkSettings::serverName(), 13); + + QCOMPARE(socket->mode(), QSslSocket::UnencryptedMode); + + QVERIFY(socket->waitForDisconnected()); +} + +void tst_QSslSocket::connectToHostEncryptedWithVerificationPeerName() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocketPtr socket = newSocket(); + this->socket = socket; + + socket->addCaCertificates(QLatin1String(SRCDIR "certs/qt-test-server-cacert.pem")); +#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND + connect(socket, SIGNAL(sslErrors(QList<QSslError>)), + this, SLOT(untrustedWorkaroundSlot(QList<QSslError>))); +#endif + + // connect to the server with its local name, but use the full name for verification. + socket->connectToHostEncrypted(QtNetworkSettings::serverLocalName(), 443, QtNetworkSettings::serverName()); + + // This should pass unconditionally when using fluke's CA certificate. + QVERIFY2(socket->waitForEncrypted(10000), qPrintable(socket->errorString())); + + socket->disconnectFromHost(); + QVERIFY(socket->waitForDisconnected()); + + QCOMPARE(socket->mode(), QSslSocket::SslClientMode); +} + +void tst_QSslSocket::sessionCipher() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocketPtr socket = newSocket(); + this->socket = socket; + connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); + QVERIFY(socket->sessionCipher().isNull()); + socket->connectToHost(QtNetworkSettings::serverName(), 443 /* https */); + QVERIFY(socket->waitForConnected(10000)); + QVERIFY(socket->sessionCipher().isNull()); + socket->startClientEncryption(); + QVERIFY(socket->waitForEncrypted(5000)); + QVERIFY(!socket->sessionCipher().isNull()); + QVERIFY(QSslSocket::supportedCiphers().contains(socket->sessionCipher())); + socket->disconnectFromHost(); + QVERIFY(socket->waitForDisconnected()); +} + +void tst_QSslSocket::flush() +{ +} + +void tst_QSslSocket::isEncrypted() +{ +} + +void tst_QSslSocket::localCertificate() +{ + if (!QSslSocket::supportsSsl()) + return; + + // This test does not make 100% sense yet. We just set some local CA/cert/key and use it + // to authenticate ourselves against the server. The server does not actually check this + // values. This test should just run the codepath inside qsslsocket_openssl.cpp + + QSslSocketPtr socket = newSocket(); + QList<QSslCertificate> localCert = QSslCertificate::fromPath(SRCDIR "certs/qt-test-server-cacert.pem"); + socket->setCaCertificates(localCert); + socket->setLocalCertificate(QLatin1String(SRCDIR "certs/fluke.cert")); + socket->setPrivateKey(QLatin1String(SRCDIR "certs/fluke.key")); + + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY(socket->waitForEncrypted(10000)); +} + +void tst_QSslSocket::mode() +{ +} + +void tst_QSslSocket::peerCertificate() +{ +} + +void tst_QSslSocket::peerCertificateChain() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocketPtr socket = newSocket(); + this->socket = socket; + + QList<QSslCertificate> caCertificates = QSslCertificate::fromPath(QLatin1String(SRCDIR "certs/qt-test-server-cacert.pem")); + QVERIFY(caCertificates.count() == 1); + socket->addCaCertificates(caCertificates); +#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND + connect(socket, SIGNAL(sslErrors(QList<QSslError>)), + this, SLOT(untrustedWorkaroundSlot(QList<QSslError>))); +#endif + + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QCOMPARE(socket->mode(), QSslSocket::UnencryptedMode); + QVERIFY(socket->peerCertificateChain().isEmpty()); + QVERIFY2(socket->waitForEncrypted(10000), qPrintable(socket->errorString())); + + QList<QSslCertificate> certChain = socket->peerCertificateChain(); + QVERIFY(certChain.count() > 0); + QCOMPARE(certChain.first(), socket->peerCertificate()); + + socket->disconnectFromHost(); + QVERIFY(socket->waitForDisconnected()); + + // connect again to a different server + socket->connectToHostEncrypted("trolltech.com", 443); + socket->ignoreSslErrors(); + QCOMPARE(socket->mode(), QSslSocket::UnencryptedMode); + QVERIFY(socket->peerCertificateChain().isEmpty()); + QVERIFY2(socket->waitForEncrypted(10000), qPrintable(socket->errorString())); + + QCOMPARE(socket->peerCertificateChain().first(), socket->peerCertificate()); + QVERIFY(socket->peerCertificateChain() != certChain); + + socket->disconnectFromHost(); + QVERIFY(socket->waitForDisconnected()); + + // now do it again back to the original server + socket->connectToHost(QtNetworkSettings::serverName(), 443); + QCOMPARE(socket->mode(), QSslSocket::UnencryptedMode); + QVERIFY(socket->peerCertificateChain().isEmpty()); + QVERIFY2(socket->waitForConnected(10000), "Network timeout"); + + socket->startClientEncryption(); + QVERIFY2(socket->waitForEncrypted(10000), qPrintable(socket->errorString())); + + QCOMPARE(socket->peerCertificateChain().first(), socket->peerCertificate()); + QVERIFY(socket->peerCertificateChain() == certChain); + + socket->disconnectFromHost(); + QVERIFY(socket->waitForDisconnected()); +} + +void tst_QSslSocket::privateKey() +{ +} + +void tst_QSslSocket::privateKeyOpaque() +{ + if (!QSslSocket::supportsSsl()) + return; + + QFile file(SRCDIR "certs/fluke.key"); + QVERIFY(file.open(QIODevice::ReadOnly)); + QSslKey key(file.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + QVERIFY(!key.isNull()); + + EVP_PKEY *pkey = q_EVP_PKEY_new(); + q_EVP_PKEY_set1_RSA(pkey, reinterpret_cast<RSA *>(key.handle())); + + // This test does not make 100% sense yet. We just set some local CA/cert/key and use it + // to authenticate ourselves against the server. The server does not actually check this + // values. This test should just run the codepath inside qsslsocket_openssl.cpp + + QSslSocketPtr socket = newSocket(); + QList<QSslCertificate> localCert = QSslCertificate::fromPath(SRCDIR "certs/qt-test-server-cacert.pem"); + socket->setCaCertificates(localCert); + socket->setLocalCertificate(QLatin1String(SRCDIR "certs/fluke.cert")); + socket->setPrivateKey(QSslKey(reinterpret_cast<Qt::HANDLE>(pkey))); + + socket->setPeerVerifyMode(QSslSocket::QueryPeer); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY(socket->waitForEncrypted(10000)); +} + +void tst_QSslSocket::protocol() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocketPtr socket = newSocket(); + this->socket = socket; + QList<QSslCertificate> certs = QSslCertificate::fromPath(SRCDIR "certs/qt-test-server-cacert.pem"); + + socket->setCaCertificates(certs); +#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND + connect(socket, SIGNAL(sslErrors(QList<QSslError>)), + this, SLOT(untrustedWorkaroundSlot(QList<QSslError>))); +#endif + + QCOMPARE(socket->protocol(), QSsl::SecureProtocols); + { + // Fluke allows SSLv3. + socket->setProtocol(QSsl::SslV3); + QCOMPARE(socket->protocol(), QSsl::SslV3); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString())); + QCOMPARE(socket->protocol(), QSsl::SslV3); + socket->abort(); + QCOMPARE(socket->protocol(), QSsl::SslV3); + socket->connectToHost(QtNetworkSettings::serverName(), 443); + QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); + socket->startClientEncryption(); + QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString())); + QCOMPARE(socket->protocol(), QSsl::SslV3); + socket->abort(); + } + { + // Fluke allows TLSV1. + socket->setProtocol(QSsl::TlsV1); + QCOMPARE(socket->protocol(), QSsl::TlsV1); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString())); + QCOMPARE(socket->protocol(), QSsl::TlsV1); + socket->abort(); + QCOMPARE(socket->protocol(), QSsl::TlsV1); + socket->connectToHost(QtNetworkSettings::serverName(), 443); + QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); + socket->startClientEncryption(); + QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString())); + QCOMPARE(socket->protocol(), QSsl::TlsV1); + socket->abort(); + } + { + // Fluke allows SSLV2. + socket->setProtocol(QSsl::SslV2); + QCOMPARE(socket->protocol(), QSsl::SslV2); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY(socket->waitForEncrypted()); + QCOMPARE(socket->protocol(), QSsl::SslV2); + socket->abort(); + QCOMPARE(socket->protocol(), QSsl::SslV2); + socket->connectToHost(QtNetworkSettings::serverName(), 443); + QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); + socket->startClientEncryption(); + QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString())); + socket->abort(); + } + { + // Fluke allows SSLV3, so it allows AnyProtocol. + socket->setProtocol(QSsl::AnyProtocol); + QCOMPARE(socket->protocol(), QSsl::AnyProtocol); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY(socket->waitForEncrypted()); + QCOMPARE(socket->protocol(), QSsl::AnyProtocol); + socket->abort(); + QCOMPARE(socket->protocol(), QSsl::AnyProtocol); + socket->connectToHost(QtNetworkSettings::serverName(), 443); + QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); + socket->startClientEncryption(); + QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString())); + QCOMPARE(socket->protocol(), QSsl::AnyProtocol); + socket->abort(); + } + { + // Fluke allows SSLV3, so it allows NoSslV2 + socket->setProtocol(QSsl::TlsV1SslV3); + QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY(socket->waitForEncrypted()); + QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3); + socket->abort(); + QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3); + socket->connectToHost(QtNetworkSettings::serverName(), 443); + QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); + socket->startClientEncryption(); + QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString())); + QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3); + socket->abort(); + } +} + +class SslServer : public QTcpServer +{ + Q_OBJECT +public: + SslServer(const QString &keyFile = SRCDIR "certs/fluke.key", const QString &certFile = SRCDIR "certs/fluke.cert") + : socket(0), + protocol(QSsl::TlsV1), + m_keyFile(keyFile), + m_certFile(certFile) { } + QSslSocket *socket; + QSsl::SslProtocol protocol; + QString m_keyFile; + QString m_certFile; + +protected: + void incomingConnection(int socketDescriptor) + { + socket = new QSslSocket(this); + socket->setProtocol(protocol); + connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot())); + + QFile file(m_keyFile); + QVERIFY(file.open(QIODevice::ReadOnly)); + QSslKey key(file.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + QVERIFY(!key.isNull()); + socket->setPrivateKey(key); + + QList<QSslCertificate> localCert = QSslCertificate::fromPath(m_certFile); + QVERIFY(!localCert.isEmpty()); + QVERIFY(localCert.first().handle()); + socket->setLocalCertificate(localCert.first()); + + QVERIFY(socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState)); + QVERIFY(!socket->peerAddress().isNull()); + QVERIFY(socket->peerPort() != 0); + QVERIFY(!socket->localAddress().isNull()); + QVERIFY(socket->localPort() != 0); + + socket->startServerEncryption(); + } + +protected slots: + void ignoreErrorSlot() + { + socket->ignoreSslErrors(); + } +}; + +void tst_QSslSocket::protocolServerSide_data() +{ + + QTest::addColumn<QSsl::SslProtocol>("serverProtocol"); + QTest::addColumn<QSsl::SslProtocol>("clientProtocol"); + QTest::addColumn<bool>("works"); + + QTest::newRow("ssl2-ssl2") << QSsl::SslV2 << QSsl::SslV2 << false; // no idea why it does not work, but we don't care about SSL 2 + QTest::newRow("ssl3-ssl3") << QSsl::SslV3 << QSsl::SslV3 << true; + QTest::newRow("tls1-tls1") << QSsl::TlsV1 << QSsl::TlsV1 << true; + QTest::newRow("tls1ssl3-tls1ssl3") << QSsl::TlsV1SslV3 << QSsl::TlsV1SslV3 << true; + QTest::newRow("any-any") << QSsl::AnyProtocol << QSsl::AnyProtocol << true; + QTest::newRow("secure-secure") << QSsl::SecureProtocols << QSsl::SecureProtocols << true; + + QTest::newRow("ssl2-ssl3") << QSsl::SslV2 << QSsl::SslV3 << false; + QTest::newRow("ssl2-tls1") << QSsl::SslV2 << QSsl::TlsV1 << false; + QTest::newRow("ssl2-tls1ssl3") << QSsl::SslV2 << QSsl::TlsV1SslV3 << false; + QTest::newRow("ssl2-secure") << QSsl::SslV2 << QSsl::SecureProtocols << false; + QTest::newRow("ssl2-any") << QSsl::SslV2 << QSsl::AnyProtocol << false; // no idea why it does not work, but we don't care about SSL 2 + + QTest::newRow("ssl3-ssl2") << QSsl::SslV3 << QSsl::SslV2 << false; + QTest::newRow("ssl3-tls1") << QSsl::SslV3 << QSsl::TlsV1 << false; + QTest::newRow("ssl3-tls1ssl3") << QSsl::SslV3 << QSsl::TlsV1SslV3 << true; + QTest::newRow("ssl3-secure") << QSsl::SslV3 << QSsl::SecureProtocols << true; + QTest::newRow("ssl3-any") << QSsl::SslV3 << QSsl::AnyProtocol << false; // we wont set a SNI header here because we connect to a + // numerical IP, so OpenSSL will send a SSL 2 handshake + + QTest::newRow("tls1-ssl2") << QSsl::TlsV1 << QSsl::SslV2 << false; + QTest::newRow("tls1-ssl3") << QSsl::TlsV1 << QSsl::SslV3 << false; + QTest::newRow("tls1-tls1ssl3") << QSsl::TlsV1 << QSsl::TlsV1SslV3 << true; + QTest::newRow("tls1-secure") << QSsl::TlsV1 << QSsl::SecureProtocols << true; + QTest::newRow("tls1-any") << QSsl::TlsV1 << QSsl::AnyProtocol << false; // we wont set a SNI header here because we connect to a + // numerical IP, so OpenSSL will send a SSL 2 handshake + + QTest::newRow("tls1ssl3-ssl2") << QSsl::TlsV1SslV3 << QSsl::SslV2 << false; + QTest::newRow("tls1ssl3-ssl3") << QSsl::TlsV1SslV3 << QSsl::SslV3 << true; + QTest::newRow("tls1ssl3-tls1") << QSsl::TlsV1SslV3 << QSsl::TlsV1 << true; + QTest::newRow("tls1ssl3-secure") << QSsl::TlsV1SslV3 << QSsl::SecureProtocols << true; + QTest::newRow("tls1ssl3-any") << QSsl::TlsV1SslV3 << QSsl::AnyProtocol << true; + + QTest::newRow("secure-ssl2") << QSsl::SecureProtocols << QSsl::SslV2 << false; + QTest::newRow("secure-ssl3") << QSsl::SecureProtocols << QSsl::SslV3 << true; + QTest::newRow("secure-tls1") << QSsl::SecureProtocols << QSsl::TlsV1 << true; + QTest::newRow("secure-tls1ssl3") << QSsl::SecureProtocols << QSsl::TlsV1SslV3 << true; + QTest::newRow("secure-any") << QSsl::SecureProtocols << QSsl::AnyProtocol << true; + + QTest::newRow("any-ssl2") << QSsl::AnyProtocol << QSsl::SslV2 << false; // no idea why it does not work, but we don't care about SSL 2 + QTest::newRow("any-ssl3") << QSsl::AnyProtocol << QSsl::SslV3 << true; + QTest::newRow("any-tls1") << QSsl::AnyProtocol << QSsl::TlsV1 << true; + QTest::newRow("any-tls1ssl3") << QSsl::AnyProtocol << QSsl::TlsV1SslV3 << true; + QTest::newRow("any-secure") << QSsl::AnyProtocol << QSsl::SecureProtocols << true; +} + +void tst_QSslSocket::protocolServerSide() +{ + if (!QSslSocket::supportsSsl()) { + qWarning("SSL not supported, skipping test"); + return; + } + + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + QFETCH(QSsl::SslProtocol, serverProtocol); + SslServer server; + server.protocol = serverProtocol; + QVERIFY(server.listen()); + + QEventLoop loop; + QTimer::singleShot(5000, &loop, SLOT(quit())); + + QSslSocketPtr client = new QSslSocket; + socket = client; + QFETCH(QSsl::SslProtocol, clientProtocol); + socket->setProtocol(clientProtocol); + // upon SSL wrong version error, error will be triggered, not sslErrors + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &loop, SLOT(quit())); + connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot())); + connect(client, SIGNAL(encrypted()), &loop, SLOT(quit())); + + client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + + loop.exec(); + + QFETCH(bool, works); + QAbstractSocket::SocketState expectedState = (works) ? QAbstractSocket::ConnectedState : QAbstractSocket::UnconnectedState; + QCOMPARE(client->state(), expectedState); + QCOMPARE(client->isEncrypted(), works); +} + +void tst_QSslSocket::setCaCertificates() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocket socket; + QCOMPARE(socket.caCertificates(), QSslSocket::defaultCaCertificates()); + socket.setCaCertificates(QSslCertificate::fromPath(SRCDIR "certs/qt-test-server-cacert.pem")); + QCOMPARE(socket.caCertificates().size(), 1); + socket.setCaCertificates(socket.defaultCaCertificates()); + QCOMPARE(socket.caCertificates(), QSslSocket::defaultCaCertificates()); +} + +void tst_QSslSocket::setLocalCertificate() +{ +} + +void tst_QSslSocket::setPrivateKey() +{ +} + +void tst_QSslSocket::setSocketDescriptor() +{ + if (!QSslSocket::supportsSsl()) + return; + + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + SslServer server; + QVERIFY(server.listen()); + + QEventLoop loop; + QTimer::singleShot(5000, &loop, SLOT(quit())); + + QSslSocketPtr client = new QSslSocket; + socket = client; + connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot())); + connect(client, SIGNAL(encrypted()), &loop, SLOT(quit())); + + client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); + + loop.exec(); + + QCOMPARE(client->state(), QAbstractSocket::ConnectedState); + QVERIFY(client->isEncrypted()); + QVERIFY(!client->peerAddress().isNull()); + QVERIFY(client->peerPort() != 0); + QVERIFY(!client->localAddress().isNull()); + QVERIFY(client->localPort() != 0); +} + +void tst_QSslSocket::setSslConfiguration_data() +{ + QTest::addColumn<QSslConfiguration>("configuration"); + QTest::addColumn<bool>("works"); + + QTest::newRow("empty") << QSslConfiguration() << false; + QSslConfiguration conf = QSslConfiguration::defaultConfiguration(); + QTest::newRow("default") << conf << false; // does not contain test server cert + QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(SRCDIR "certs/qt-test-server-cacert.pem"); + conf.setCaCertificates(testServerCert); + QTest::newRow("set-root-cert") << conf << true; + conf.setProtocol(QSsl::SecureProtocols); + QTest::newRow("secure") << conf << true; +} + +void tst_QSslSocket::setSslConfiguration() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocketPtr socket = newSocket(); + QFETCH(QSslConfiguration, configuration); + socket->setSslConfiguration(configuration); + this->socket = socket; + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QFETCH(bool, works); + QCOMPARE(socket->waitForEncrypted(10000), works); + if (works) { + socket->disconnectFromHost(); + QVERIFY2(socket->waitForDisconnected(), qPrintable(socket->errorString())); + } +} + +void tst_QSslSocket::waitForEncrypted() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocketPtr socket = newSocket(); + this->socket = socket; + + connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot())); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + + QVERIFY(socket->waitForEncrypted(10000)); +} + +void tst_QSslSocket::waitForEncryptedMinusOne() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocketPtr socket = newSocket(); + this->socket = socket; + + connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot())); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + + QVERIFY(socket->waitForEncrypted(-1)); +} + +void tst_QSslSocket::waitForConnectedEncryptedReadyRead() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocketPtr socket = newSocket(); + this->socket = socket; + + connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot())); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 993); + +#ifdef Q_OS_SYMBIAN + QVERIFY(socket->waitForConnected(10000)); + QVERIFY(socket->waitForEncrypted(10000)); + + // dont forget to login + QCOMPARE((int) socket->write("USER ftptest\r\n"), 14); + QCOMPARE((int) socket->write("PASS ftP2Ptf\r\n"), 14); + + QVERIFY(socket->waitForReadyRead(10000)); + QVERIFY(!socket->peerCertificate().isNull()); + QVERIFY(!socket->peerCertificateChain().isEmpty()); +#else + QVERIFY(socket->waitForConnected(10000)); + QVERIFY(socket->waitForEncrypted(10000)); + QVERIFY(socket->waitForReadyRead(10000)); + QVERIFY(!socket->peerCertificate().isNull()); + QVERIFY(!socket->peerCertificateChain().isEmpty()); +#endif +} + +void tst_QSslSocket::startClientEncryption() +{ +} + +void tst_QSslSocket::startServerEncryption() +{ +} + +void tst_QSslSocket::addDefaultCaCertificate() +{ + if (!QSslSocket::supportsSsl()) + return; + + // Reset the global CA chain + QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates()); + + QList<QSslCertificate> flukeCerts = QSslCertificate::fromPath(SRCDIR "certs/qt-test-server-cacert.pem"); + QCOMPARE(flukeCerts.size(), 1); + QList<QSslCertificate> globalCerts = QSslSocket::defaultCaCertificates(); + QVERIFY(!globalCerts.contains(flukeCerts.first())); + QSslSocket::addDefaultCaCertificate(flukeCerts.first()); + QCOMPARE(QSslSocket::defaultCaCertificates().size(), globalCerts.size() + 1); + QVERIFY(QSslSocket::defaultCaCertificates().contains(flukeCerts.first())); + + // Restore the global CA chain + QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates()); +} + +void tst_QSslSocket::addDefaultCaCertificates() +{ +} + +void tst_QSslSocket::addDefaultCaCertificates2() +{ +} + +void tst_QSslSocket::defaultCaCertificates() +{ + if (!QSslSocket::supportsSsl()) + return; + + QList<QSslCertificate> certs = QSslSocket::defaultCaCertificates(); + QVERIFY(certs.size() > 1); + QCOMPARE(certs, QSslSocket::systemCaCertificates()); +} + +void tst_QSslSocket::defaultCiphers() +{ +} + +void tst_QSslSocket::resetDefaultCiphers() +{ +} + +void tst_QSslSocket::setDefaultCaCertificates() +{ +} + +void tst_QSslSocket::setDefaultCiphers() +{ +} + +void tst_QSslSocket::supportedCiphers() +{ + if (!QSslSocket::supportsSsl()) + return; + + QList<QSslCipher> ciphers = QSslSocket::supportedCiphers(); + QVERIFY(ciphers.size() > 1); + + QSslSocket socket; + QCOMPARE(socket.supportedCiphers(), ciphers); + QCOMPARE(socket.defaultCiphers(), ciphers); + QCOMPARE(socket.ciphers(), ciphers); +} + +void tst_QSslSocket::systemCaCertificates() +{ + if (!QSslSocket::supportsSsl()) + return; + + QList<QSslCertificate> certs = QSslSocket::systemCaCertificates(); + QVERIFY(certs.size() > 1); + QCOMPARE(certs, QSslSocket::defaultCaCertificates()); +} + +void tst_QSslSocket::wildcardCertificateNames() +{ + // Passing CN matches + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("www.example.com"), QString("www.example.com")), true ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("*.example.com"), QString("www.example.com")), true ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("xxx*.example.com"), QString("xxxwww.example.com")), true ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("f*.example.com"), QString("foo.example.com")), true ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("192.168.0.0"), QString("192.168.0.0")), true ); + + // Failing CN matches + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("xxx.example.com"), QString("www.example.com")), false ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("*"), QString("www.example.com")), false ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("*.*.com"), QString("www.example.com")), false ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("*.example.com"), QString("baa.foo.example.com")), false ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("f*.example.com"), QString("baa.example.com")), false ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("*.com"), QString("example.com")), false ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("*fail.com"), QString("example.com")), false ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("*.example."), QString("www.example.")), false ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("*.example."), QString("www.example")), false ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString(""), QString("www")), false ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("*"), QString("www")), false ); + QCOMPARE( QSslSocketBackendPrivate::isMatchingHostname(QString("*.168.0.0"), QString("192.168.0.0")), false ); +} + +void tst_QSslSocket::wildcard() +{ + QSKIP("TODO: solve wildcard problem", SkipAll); + + if (!QSslSocket::supportsSsl()) + return; + + // Fluke runs an apache server listening on port 4443, serving the + // wildcard fluke.*.troll.no. The DNS entry for + // fluke.wildcard.dev.troll.no, served by ares (root for dev.troll.no), + // returns the CNAME fluke.troll.no for this domain. The web server + // responds with the wildcard, and QSslSocket should accept that as a + // valid connection. This was broken in 4.3.0. + QSslSocketPtr socket = newSocket(); + socket->addCaCertificates(QLatin1String("certs/aspiriniks.ca.crt")); + this->socket = socket; +#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND + connect(socket, SIGNAL(sslErrors(QList<QSslError>)), + this, SLOT(untrustedWorkaroundSlot(QList<QSslError>))); +#endif + socket->connectToHostEncrypted(QtNetworkSettings::wildcardServerName(), 4443); + + QVERIFY2(socket->waitForEncrypted(3000), qPrintable(socket->errorString())); + + QSslCertificate certificate = socket->peerCertificate(); + QCOMPARE(certificate.subjectInfo(QSslCertificate::CommonName), QString(QtNetworkSettings::serverLocalName() + ".*." + QtNetworkSettings::serverDomainName())); + QCOMPARE(certificate.issuerInfo(QSslCertificate::CommonName), QtNetworkSettings::serverName()); + + socket->close(); +} + +class SslServer2 : public QTcpServer +{ +protected: + void incomingConnection(int socketDescriptor) + { + QSslSocket *socket = new QSslSocket(this); + socket->ignoreSslErrors(); + + // Only set the certificate + QList<QSslCertificate> localCert = QSslCertificate::fromPath(SRCDIR "certs/fluke.cert"); + QVERIFY(!localCert.isEmpty()); + QVERIFY(localCert.first().handle()); + socket->setLocalCertificate(localCert.first()); + + QVERIFY(socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState)); + + socket->startServerEncryption(); + } +}; + +void tst_QSslSocket::setEmptyKey() +{ + if (!QSslSocket::supportsSsl()) + return; + + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + SslServer2 server; + server.listen(); + + QSslSocket socket; + socket.connectToHostEncrypted("127.0.0.1", server.serverPort()); + + QTestEventLoop::instance().enterLoop(2); + + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError); +} + +void tst_QSslSocket::spontaneousWrite() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + SslServer server; + QSslSocket *receiver = new QSslSocket(this); + connect(receiver, SIGNAL(readyRead()), SLOT(exitLoop())); + + // connect two sockets to each other: + QVERIFY(server.listen(QHostAddress::LocalHost)); + receiver->connectToHost("127.0.0.1", server.serverPort()); + QVERIFY(receiver->waitForConnected(5000)); + QVERIFY(server.waitForNewConnection(0)); + + QSslSocket *sender = server.socket; + QVERIFY(sender); + QVERIFY(sender->state() == QAbstractSocket::ConnectedState); + receiver->setObjectName("receiver"); + sender->setObjectName("sender"); + receiver->ignoreSslErrors(); + receiver->startClientEncryption(); + + // SSL handshake: + connect(receiver, SIGNAL(encrypted()), SLOT(exitLoop())); + enterLoop(1); + QVERIFY(!timeout()); + QVERIFY(sender->isEncrypted()); + QVERIFY(receiver->isEncrypted()); + + // make sure there's nothing to be received on the sender: + while (sender->waitForReadyRead(10) || receiver->waitForBytesWritten(10)) {} + + // spontaneously write something: + QByteArray data("Hello World"); + sender->write(data); + + // check if the other side receives it: + enterLoop(1); + QVERIFY(!timeout()); + QCOMPARE(receiver->bytesAvailable(), qint64(data.size())); + QCOMPARE(receiver->readAll(), data); +} + +void tst_QSslSocket::setReadBufferSize() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + SslServer server; + QSslSocket *receiver = new QSslSocket(this); + connect(receiver, SIGNAL(readyRead()), SLOT(exitLoop())); + + // connect two sockets to each other: + QVERIFY(server.listen(QHostAddress::LocalHost)); + receiver->connectToHost("127.0.0.1", server.serverPort()); + QVERIFY(receiver->waitForConnected(5000)); + QVERIFY(server.waitForNewConnection(0)); + + QSslSocket *sender = server.socket; + QVERIFY(sender); + QVERIFY(sender->state() == QAbstractSocket::ConnectedState); + receiver->setObjectName("receiver"); + sender->setObjectName("sender"); + receiver->ignoreSslErrors(); + receiver->startClientEncryption(); + + // SSL handshake: + connect(receiver, SIGNAL(encrypted()), SLOT(exitLoop())); + enterLoop(1); + QVERIFY(!timeout()); + QVERIFY(sender->isEncrypted()); + QVERIFY(receiver->isEncrypted()); + + QByteArray data(2048, 'b'); + receiver->setReadBufferSize(39 * 1024); // make it a non-multiple of the data.size() + + // saturate the incoming buffer + while (sender->state() == QAbstractSocket::ConnectedState && + receiver->state() == QAbstractSocket::ConnectedState && + receiver->bytesAvailable() < receiver->readBufferSize()) { + sender->write(data); + //qDebug() << receiver->bytesAvailable() << "<" << receiver->readBufferSize() << (receiver->bytesAvailable() < receiver->readBufferSize()); + + while (sender->bytesToWrite()) + QVERIFY(sender->waitForBytesWritten(10)); + + // drain it: + while (receiver->bytesAvailable() < receiver->readBufferSize() && + receiver->waitForReadyRead(10)) {} + } + + //qDebug() << sender->bytesToWrite() << "bytes to write"; + //qDebug() << receiver->bytesAvailable() << "bytes available"; + + // send a bit more + sender->write(data); + sender->write(data); + sender->write(data); + sender->write(data); + QVERIFY(sender->waitForBytesWritten(10)); + + qint64 oldBytesAvailable = receiver->bytesAvailable(); + + // now unset the read buffer limit and iterate + receiver->setReadBufferSize(0); + enterLoop(1); + QVERIFY(!timeout()); + + QVERIFY(receiver->bytesAvailable() > oldBytesAvailable); +} + +class SetReadBufferSize_task_250027_handler : public QObject { + Q_OBJECT +public slots: + void readyReadSlot() { + QTestEventLoop::instance().exitLoop(); + } + void waitSomeMore(QSslSocket *socket) { + QTime t; + t.start(); + while (!socket->encryptedBytesAvailable()) { + QCoreApplication::processEvents(QEventLoop::AllEvents | QEventLoop::WaitForMoreEvents, 250); + if (t.elapsed() > 1000 || socket->state() != QAbstractSocket::ConnectedState) + return; + } + } +}; + +void tst_QSslSocket::setReadBufferSize_task_250027() +{ + // do not execute this when a proxy is set. + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + QSslSocketPtr socket = newSocket(); + socket->setReadBufferSize(1000); // limit to 1 kb/sec + socket->ignoreSslErrors(); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->ignoreSslErrors(); + QVERIFY(socket->waitForConnected(10*1000)); + QVERIFY(socket->waitForEncrypted(10*1000)); + + // exit the event loop as soon as we receive a readyRead() + SetReadBufferSize_task_250027_handler setReadBufferSize_task_250027_handler; + connect(socket, SIGNAL(readyRead()), &setReadBufferSize_task_250027_handler, SLOT(readyReadSlot())); + + // provoke a response by sending a request + socket->write("GET /qtest/fluke.gif HTTP/1.0\n"); // this file is 27 KB + socket->write("Host: "); + socket->write(QtNetworkSettings::serverName().toLocal8Bit().constData()); + socket->write("\n"); + socket->write("Connection: close\n"); + socket->write("\n"); + socket->flush(); + + QTestEventLoop::instance().enterLoop(10); + setReadBufferSize_task_250027_handler.waitSomeMore(socket); + QByteArray firstRead = socket->readAll(); + // First read should be some data, but not the whole file + QVERIFY(firstRead.size() > 0 && firstRead.size() < 20*1024); + + QTestEventLoop::instance().enterLoop(10); + setReadBufferSize_task_250027_handler.waitSomeMore(socket); + QByteArray secondRead = socket->readAll(); + // second read should be some more data + QVERIFY(secondRead.size() > 0); + + socket->close(); +} + +class SslServer3 : public QTcpServer +{ + Q_OBJECT +public: + SslServer3() : socket(0) { } + QSslSocket *socket; + +protected: + void incomingConnection(int socketDescriptor) + { + socket = new QSslSocket(this); + connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot())); + + QFile file(SRCDIR "certs/fluke.key"); + QVERIFY(file.open(QIODevice::ReadOnly)); + QSslKey key(file.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + QVERIFY(!key.isNull()); + socket->setPrivateKey(key); + + QList<QSslCertificate> localCert = QSslCertificate::fromPath(SRCDIR "certs/fluke.cert"); + QVERIFY(!localCert.isEmpty()); + QVERIFY(localCert.first().handle()); + socket->setLocalCertificate(localCert.first()); + + QVERIFY(socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState)); + QVERIFY(!socket->peerAddress().isNull()); + QVERIFY(socket->peerPort() != 0); + QVERIFY(!socket->localAddress().isNull()); + QVERIFY(socket->localPort() != 0); + } + +protected slots: + void ignoreErrorSlot() + { + socket->ignoreSslErrors(); + } +}; + +class ThreadedSslServer: public QThread +{ + Q_OBJECT +public: + QSemaphore dataReadSemaphore; + int serverPort; + bool ok; + + ThreadedSslServer() : serverPort(-1), ok(false) + { } + + ~ThreadedSslServer() + { + if (isRunning()) wait(2000); + QVERIFY(ok); + } + +signals: + void listening(); + +protected: + void run() + { + // if all goes well (no timeouts), this thread will sleep for a total of 500 ms + // (i.e., 5 times 100 ms, one sleep for each operation) + + SslServer3 server; + server.listen(QHostAddress::LocalHost); + serverPort = server.serverPort(); + emit listening(); + + // delayed acceptance: + QTest::qSleep(100); +#ifndef Q_OS_SYMBIAN + bool ret = server.waitForNewConnection(2000); +#else + bool ret = server.waitForNewConnection(20000); +#endif + Q_UNUSED(ret); + + // delayed start of encryption + QTest::qSleep(100); + QSslSocket *socket = server.socket; + if (!socket || !socket->isValid()) + return; // error + socket->ignoreSslErrors(); + socket->startServerEncryption(); + if (!socket->waitForEncrypted(2000)) + return; // error + + // delayed reading data + QTest::qSleep(100); + if (!socket->waitForReadyRead(2000)) + return; // error + socket->readAll(); + dataReadSemaphore.release(); + + // delayed sending data + QTest::qSleep(100); + socket->write("Hello, World"); + while (socket->bytesToWrite()) + if (!socket->waitForBytesWritten(2000)) + return; // error + + // delayed replying (reading then sending) + QTest::qSleep(100); + if (!socket->waitForReadyRead(2000)) + return; // error + socket->write("Hello, World"); + while (socket->bytesToWrite()) + if (!socket->waitForBytesWritten(2000)) + return; // error + + // delayed disconnection: + QTest::qSleep(100); + socket->disconnectFromHost(); + if (!socket->waitForDisconnected(2000)) + return; // error + + delete socket; + ok = true; + } +}; + +void tst_QSslSocket::waitForMinusOne() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + ThreadedSslServer server; + connect(&server, SIGNAL(listening()), SLOT(exitLoop())); + + // start the thread and wait for it to be ready + server.start(); + enterLoop(1); + QVERIFY(!timeout()); + + // connect to the server + QSslSocket socket; + QTest::qSleep(100); + socket.connectToHost("127.0.0.1", server.serverPort); + QVERIFY(socket.waitForConnected(-1)); + socket.ignoreSslErrors(); + socket.startClientEncryption(); + + // first verification: this waiting should take 200 ms + QVERIFY2(socket.waitForEncrypted(-1), qPrintable(socket.errorString())); + QVERIFY(socket.isEncrypted()); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + QCOMPARE(socket.bytesAvailable(), Q_INT64_C(0)); + + // second verification: write and make sure the other side got it (100 ms) + socket.write("How are you doing?"); + QVERIFY(socket.bytesToWrite() != 0); + QVERIFY(socket.waitForBytesWritten(-1)); + QVERIFY(server.dataReadSemaphore.tryAcquire(1, 2000)); + + // third verification: it should wait for 100 ms: + QVERIFY(socket.waitForReadyRead(-1)); + QVERIFY(socket.isEncrypted()); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + QVERIFY(socket.bytesAvailable() != 0); + + // fourth verification: deadlock prevention: + // we write and then wait for reading; the other side needs to receive before + // replying (100 ms delay) + socket.write("I'm doing just fine!"); + QVERIFY(socket.bytesToWrite() != 0); + QVERIFY(socket.waitForReadyRead(-1)); + + // fifth verification: it should wait for 200 ms more + QVERIFY(socket.waitForDisconnected(-1)); +} + +class VerifyServer : public QTcpServer +{ + Q_OBJECT +public: + VerifyServer() : socket(0) { } + QSslSocket *socket; + +protected: + void incomingConnection(int socketDescriptor) + { + socket = new QSslSocket(this); + + socket->setPrivateKey(SRCDIR "certs/fluke.key"); + socket->setLocalCertificate(SRCDIR "certs/fluke.cert"); + socket->setSocketDescriptor(socketDescriptor); + socket->startServerEncryption(); + } +}; + +void tst_QSslSocket::verifyMode() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + QSslSocket socket; + QCOMPARE(socket.peerVerifyMode(), QSslSocket::AutoVerifyPeer); + socket.setPeerVerifyMode(QSslSocket::VerifyNone); + QCOMPARE(socket.peerVerifyMode(), QSslSocket::VerifyNone); + socket.setPeerVerifyMode(QSslSocket::VerifyNone); + socket.setPeerVerifyMode(QSslSocket::VerifyPeer); + QCOMPARE(socket.peerVerifyMode(), QSslSocket::VerifyPeer); + + socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY(!socket.waitForEncrypted()); + + QList<QSslError> expectedErrors = QList<QSslError>() + << QSslError(QSslError::SelfSignedCertificate, socket.peerCertificate()); + QCOMPARE(socket.sslErrors(), expectedErrors); + socket.abort(); + + VerifyServer server; + server.listen(); + + QSslSocket clientSocket; + clientSocket.connectToHostEncrypted("127.0.0.1", server.serverPort()); + clientSocket.ignoreSslErrors(); + + QEventLoop loop; + QTimer::singleShot(5000, &loop, SLOT(quit())); + connect(&clientSocket, SIGNAL(encrypted()), &loop, SLOT(quit())); + loop.exec(); + + QVERIFY(clientSocket.isEncrypted()); + QVERIFY(server.socket->sslErrors().isEmpty()); +} + +void tst_QSslSocket::verifyDepth() +{ + QSslSocket socket; + QCOMPARE(socket.peerVerifyDepth(), 0); + socket.setPeerVerifyDepth(1); + QCOMPARE(socket.peerVerifyDepth(), 1); + QTest::ignoreMessage(QtWarningMsg, "QSslSocket::setPeerVerifyDepth: cannot set negative depth of -1"); + socket.setPeerVerifyDepth(-1); + QCOMPARE(socket.peerVerifyDepth(), 1); +} + +void tst_QSslSocket::peerVerifyError() +{ + QSslSocketPtr socket = newSocket(); + QSignalSpy sslErrorsSpy(socket, SIGNAL(sslErrors(QList<QSslError>))); + QSignalSpy peerVerifyErrorSpy(socket, SIGNAL(peerVerifyError(QSslError))); + + socket->connectToHostEncrypted(QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(), 443); + QVERIFY(!socket->waitForEncrypted(10000)); + QVERIFY(!peerVerifyErrorSpy.isEmpty()); + QVERIFY(!sslErrorsSpy.isEmpty()); + QCOMPARE(qVariantValue<QSslError>(peerVerifyErrorSpy.last().at(0)).error(), QSslError::HostNameMismatch); + QCOMPARE(qVariantValue<QList<QSslError> >(sslErrorsSpy.at(0).at(0)).size(), peerVerifyErrorSpy.size()); +} + +void tst_QSslSocket::disconnectFromHostWhenConnecting() +{ + QSslSocketPtr socket = newSocket(); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 993); + socket->ignoreSslErrors(); + socket->write("XXXX LOGOUT\r\n"); + QAbstractSocket::SocketState state = socket->state(); + // without proxy, the state will be HostLookupState; + // with proxy, the state will be ConnectingState. + QVERIFY(socket->state() == QAbstractSocket::HostLookupState || + socket->state() == QAbstractSocket::ConnectingState); + socket->disconnectFromHost(); + // the state of the socket must be the same before and after calling + // disconnectFromHost() + QCOMPARE(state, socket->state()); + QVERIFY(socket->state() == QAbstractSocket::HostLookupState || + socket->state() == QAbstractSocket::ConnectingState); + QVERIFY(socket->waitForDisconnected(10000)); + QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState); + // we did not call close, so the socket must be still open + QVERIFY(socket->isOpen()); + QCOMPARE(socket->bytesToWrite(), qint64(0)); + + // dont forget to login + QCOMPARE((int) socket->write("USER ftptest\r\n"), 14); + +} + +void tst_QSslSocket::disconnectFromHostWhenConnected() +{ + QSslSocketPtr socket = newSocket(); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 993); + socket->ignoreSslErrors(); +#ifndef Q_OS_SYMBIAN + QVERIFY(socket->waitForEncrypted(5000)); +#else + QVERIFY(socket->waitForEncrypted(10000)); +#endif + socket->write("XXXX LOGOUT\r\n"); + QCOMPARE(socket->state(), QAbstractSocket::ConnectedState); + socket->disconnectFromHost(); + QCOMPARE(socket->state(), QAbstractSocket::ClosingState); +#ifdef Q_OS_SYMBIAN + // I don't understand how socket->waitForDisconnected can work on other platforms + // since socket->write will end to: + // QMetaObject::invokeMethod(this, "_q_flushWriteBuffer", Qt::QueuedConnection); + // In order that _q_flushWriteBuffer will be called the eventloop need to run + // If we just call waitForDisconnected, which blocks the whole thread how that can happen? + connect(socket, SIGNAL(disconnected()), this, SLOT(exitLoop())); + enterLoop(5); + QVERIFY(!timeout()); +#else + QVERIFY(socket->waitForDisconnected(5000)); +#endif + QCOMPARE(socket->bytesToWrite(), qint64(0)); +} + +void tst_QSslSocket::resetProxy() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + // check fix for bug 199941 + + QNetworkProxy goodProxy(QNetworkProxy::NoProxy); + QNetworkProxy badProxy(QNetworkProxy::HttpProxy, "thisCannotWorkAbsolutelyNotForSure", 333); + + // make sure the connection works, and then set a nonsense proxy, and then + // make sure it does not work anymore + QSslSocket socket; + socket.addCaCertificates(QLatin1String(SRCDIR "certs/qt-test-server-cacert.pem")); + socket.setProxy(goodProxy); + socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY2(socket.waitForConnected(10000), qPrintable(socket.errorString())); + socket.abort(); + socket.setProxy(badProxy); + socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY(! socket.waitForConnected(10000)); + + // dont forget to login + QCOMPARE((int) socket.write("USER ftptest\r\n"), 14); + QCOMPARE((int) socket.write("PASS password\r\n"), 15); + + enterLoop(10); + + // now the other way round: + // set the nonsense proxy and make sure the connection does not work, + // and then set the right proxy and make sure it works + QSslSocket socket2; + socket2.addCaCertificates(QLatin1String(SRCDIR "certs/qt-test-server-cacert.pem")); + socket2.setProxy(badProxy); + socket2.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY(! socket2.waitForConnected(10000)); + socket2.abort(); + socket2.setProxy(goodProxy); + socket2.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY2(socket2.waitForConnected(10000), qPrintable(socket.errorString())); +} + +void tst_QSslSocket::ignoreSslErrorsList_data() +{ + QTest::addColumn<QList<QSslError> >("expectedSslErrors"); + QTest::addColumn<int>("expectedSslErrorSignalCount"); + + // construct the list of errors that we will get with the SSL handshake and that we will ignore + QList<QSslError> expectedSslErrors; + // fromPath gives us a list of certs, but it actually only contains one + QList<QSslCertificate> certs = QSslCertificate::fromPath(QLatin1String(SRCDIR "certs/qt-test-server-cacert.pem")); + QSslError rightError(QSslError::SelfSignedCertificate, certs.at(0)); + QSslError wrongError(QSslError::SelfSignedCertificate); + + + QTest::newRow("SSL-failure-empty-list") << expectedSslErrors << 1; + expectedSslErrors.append(wrongError); + QTest::newRow("SSL-failure-wrong-error") << expectedSslErrors << 1; + expectedSslErrors.append(rightError); + QTest::newRow("allErrorsInExpectedList1") << expectedSslErrors << 0; + expectedSslErrors.removeAll(wrongError); + QTest::newRow("allErrorsInExpectedList2") << expectedSslErrors << 0; + expectedSslErrors.removeAll(rightError); + QTest::newRow("SSL-failure-empty-list-again") << expectedSslErrors << 1; +} + +void tst_QSslSocket::ignoreSslErrorsList() +{ + QSslSocket socket; + connect(&socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + +// this->socket = &socket; + QSslCertificate cert; + + QFETCH(QList<QSslError>, expectedSslErrors); + socket.ignoreSslErrors(expectedSslErrors); + + QFETCH(int, expectedSslErrorSignalCount); + QSignalSpy sslErrorsSpy(&socket, SIGNAL(error(QAbstractSocket::SocketError))); + + socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + + bool expectEncryptionSuccess = (expectedSslErrorSignalCount == 0); + QCOMPARE(socket.waitForEncrypted(10000), expectEncryptionSuccess); + QCOMPARE(sslErrorsSpy.count(), expectedSslErrorSignalCount); +} + +void tst_QSslSocket::ignoreSslErrorsListWithSlot_data() +{ + ignoreSslErrorsList_data(); +} + +// this is not a test, just a slot called in the test below +void tst_QSslSocket::ignoreErrorListSlot(const QList<QSslError> &) +{ + socket->ignoreSslErrors(storedExpectedSslErrors); +} + +void tst_QSslSocket::ignoreSslErrorsListWithSlot() +{ + QSslSocket socket; + this->socket = &socket; + + QFETCH(QList<QSslError>, expectedSslErrors); + // store the errors to ignore them later in the slot connected below + storedExpectedSslErrors = expectedSslErrors; + connect(&socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(&socket, SIGNAL(sslErrors(const QList<QSslError> &)), + this, SLOT(ignoreErrorListSlot(const QList<QSslError> &))); + socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + + QFETCH(int, expectedSslErrorSignalCount); + bool expectEncryptionSuccess = (expectedSslErrorSignalCount == 0); + QCOMPARE(socket.waitForEncrypted(10000), expectEncryptionSuccess); +} + +// make sure a closed socket has no bytesAvailable() +// related to https://bugs.webkit.org/show_bug.cgi?id=28016 +void tst_QSslSocket::readFromClosedSocket() +{ + QSslSocketPtr socket = newSocket(); + socket->ignoreSslErrors(); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + socket->ignoreSslErrors(); + socket->waitForConnected(); + socket->waitForEncrypted(); + // provoke a response by sending a request + socket->write("GET /qtest/fluke.gif HTTP/1.1\n"); + socket->write("Host: "); + socket->write(QtNetworkSettings::serverName().toLocal8Bit().constData()); + socket->write("\n"); + socket->write("\n"); + socket->waitForBytesWritten(); + socket->waitForReadyRead(); + QVERIFY(socket->state() == QAbstractSocket::ConnectedState); + QVERIFY(socket->bytesAvailable()); + socket->close(); + QVERIFY(!socket->bytesAvailable()); + QVERIFY(!socket->bytesToWrite()); + QVERIFY(socket->state() == QAbstractSocket::UnconnectedState); +} + +void tst_QSslSocket::writeBigChunk() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocketPtr socket = newSocket(); + this->socket = socket; + + connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot())); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + + QByteArray data; + data.resize(1024*1024*10); // 10 MB + // init with garbage. needed so ssl cannot compress it in an efficient way. + for (size_t i = 0; i < data.size() / sizeof(int); i++) { + int r = qrand(); + data.data()[i*sizeof(int)] = r; + } + + QVERIFY(socket->waitForEncrypted(10000)); + QString errorBefore = socket->errorString(); + + int ret = socket->write(data.constData(), data.size()); + QVERIFY(data.size() == ret); + + // spin the event loop once so QSslSocket::transmit() gets called + QCoreApplication::processEvents(); + QString errorAfter = socket->errorString(); + + // no better way to do this right now since the error is the same as the default error. + if (socket->errorString().startsWith(QLatin1String("Unable to write data"))) + { + qWarning() << socket->error() << socket->errorString(); + QFAIL("Error while writing! Check if the OpenSSL BIO size is limited?!"); + } + // also check the error string. If another error (than UnknownError) occurred, it should be different than before + QVERIFY(errorBefore == errorAfter); + + // check that everything has been written to OpenSSL + QVERIFY(socket->bytesToWrite() == 0); + + socket->close(); +} + +void tst_QSslSocket::blacklistedCertificates() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + SslServer server(SRCDIR "certs/fake-login.live.com.key", SRCDIR "certs/fake-login.live.com.pem"); + QSslSocket *receiver = new QSslSocket(this); + connect(receiver, SIGNAL(readyRead()), SLOT(exitLoop())); + + // connect two sockets to each other: + QVERIFY(server.listen(QHostAddress::LocalHost)); + receiver->connectToHost("127.0.0.1", server.serverPort()); + QVERIFY(receiver->waitForConnected(5000)); + QVERIFY(server.waitForNewConnection(0)); + + QSslSocket *sender = server.socket; + QVERIFY(sender); + QVERIFY(sender->state() == QAbstractSocket::ConnectedState); + receiver->setObjectName("receiver"); + sender->setObjectName("sender"); + receiver->startClientEncryption(); + + connect(receiver, SIGNAL(sslErrors(QList<QSslError>)), SLOT(exitLoop())); + connect(receiver, SIGNAL(encrypted()), SLOT(exitLoop())); + enterLoop(1); + QList<QSslError> sslErrors = receiver->sslErrors(); + QVERIFY(sslErrors.count() > 0); + // there are more errors (self signed cert and hostname mismatch), but we only care about the blacklist error + QCOMPARE(sslErrors.at(0).error(), QSslError::CertificateBlacklisted); +} + +void tst_QSslSocket::setEmptyDefaultConfiguration() +{ + // used to produce a crash in QSslConfigurationPrivate::deepCopyDefaultConfiguration, QTBUG-13265 + + if (!QSslSocket::supportsSsl()) + return; + + QSslConfiguration emptyConf; + QSslConfiguration::setDefaultConfiguration(emptyConf); + + QSslSocketPtr socket = newSocket(); + connect(socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(ignoreErrorSlot())); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + QVERIFY2(!socket->waitForEncrypted(4000), qPrintable(socket->errorString())); +} + +void tst_QSslSocket::versionAccessors() +{ + if (!QSslSocket::supportsSsl()) + return; + + qDebug() << QSslSocket::sslLibraryVersionString(); + qDebug() << QString::number(QSslSocket::sslLibraryVersionNumber(), 16); +} + +#endif // QT_NO_OPENSSL + +QTEST_MAIN(tst_QSslSocket) +#include "tst_qsslsocket.moc" |