diff options
Diffstat (limited to 'tests/auto/network/ssl/qsslsocket')
8 files changed, 723 insertions, 82 deletions
diff --git a/tests/auto/network/ssl/qsslsocket/certs/bogus-ca.crt b/tests/auto/network/ssl/qsslsocket/certs/bogus-ca.crt new file mode 100644 index 0000000000..cf5893e98d --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/bogus-ca.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMzCCAhugAwIBAgIJAJBdFtmKuuELMA0GCSqGSIb3DQEBCwUAMC8xGjAYBgNV +BAoMEUJvZ3VzIENvcnBvcmF0aW9uMREwDwYDVQQDDAhCb2d1cyBDQTAgFw0xNTAx +MzAxNzM0NDdaGA8yMTE1MDEwNjE3MzQ0N1owLzEaMBgGA1UECgwRQm9ndXMgQ29y +cG9yYXRpb24xETAPBgNVBAMMCEJvZ3VzIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAnXt/X69lmfvWampP88f20yNs1VZroG9VjdR4GaJM6pbWu5Wn +SYBfS81osnHC7dTW2FvKZUGnz7KX+ImkbE2qUvj6yTeFu6ILj3o+8ws7A4iOTkiH +84CHb6T/HxWO5fW6mS5v+tvPDp3rQ7JpPVYvoh7dSv8X1+JCdDmkepRveN6Pzo47 +9VFVC0oscc5I4Y0wPwnaXZ4X26vmRfbhqtoKL57lz1lJ0R6bvLC9mf4DGFPx7WXQ +eOtlKX2dtuKj+Cl3vyHff6gHNMKM0bq3KfsT+vDO6eIs/ayqVRdd0XBIMj+bZYd9 +7QI/+3XTNR3TwTisrjo71XZtHdA1DkcMaSGoJwIDAQABo1AwTjAdBgNVHQ4EFgQU +xVZK4BIjBgmluCLIespCbne4BIUwHwYDVR0jBBgwFoAUxVZK4BIjBgmluCLIespC +bne4BIUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAgZn6odHr2y1G +1OStblBdsXNxmsW7WzhLUYFUhSzBw9KS/O7uG2HAFLwJNM4sQHeuc0JjxqXG5n7s +mGbmWpUYt8+KJDRnUssmKwwg2u6Rqp+0I9leCk9KTtYpXX7d9wprSsgwjQKhTEeQ +fNImbNR6Br7GDO7Om2MnOALvZmp0KJgUFIH0J630LJTrsrTvwfX7wKhYb1wgud5N +SXdGjBuJxKK3Y0VBMsbqwI0y+wHIYE+qLzlFWNRHmKaYeGtg0T8CVK6XWUrLcjcr +rQINqW3rb1OlWF7YZ5dg7vXoZrza6YSQLWha6/FQMCaKtJHxIE1NBw0ZXK6txnkI +f4HXoPvSGg== +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/bogus-ca.key b/tests/auto/network/ssl/qsslsocket/certs/bogus-ca.key new file mode 100644 index 0000000000..1c2db7932e --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/bogus-ca.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAnXt/X69lmfvWampP88f20yNs1VZroG9VjdR4GaJM6pbWu5Wn +SYBfS81osnHC7dTW2FvKZUGnz7KX+ImkbE2qUvj6yTeFu6ILj3o+8ws7A4iOTkiH +84CHb6T/HxWO5fW6mS5v+tvPDp3rQ7JpPVYvoh7dSv8X1+JCdDmkepRveN6Pzo47 +9VFVC0oscc5I4Y0wPwnaXZ4X26vmRfbhqtoKL57lz1lJ0R6bvLC9mf4DGFPx7WXQ +eOtlKX2dtuKj+Cl3vyHff6gHNMKM0bq3KfsT+vDO6eIs/ayqVRdd0XBIMj+bZYd9 +7QI/+3XTNR3TwTisrjo71XZtHdA1DkcMaSGoJwIDAQABAoIBAGKkKmJq4L8UyXca +ZD4UcHxL4i221e9GDVarURbtXDRMivAwivo1GHvIi93J+Ak0meYniJzoBQ7JlPsu +a/kSpK8YGS3UQ0YF+CvErI1b6XkLHefW8qEJTswVk1+LB1jvFBRCzA1bhVRogiaD +J/wtceSgZIhHRE4LAQj/2hCVzUTtV6Zr0GIJGjB7hdF9MHGlTwkPrkjvERlK/PTc +dVjyNbinYGJNA2i701u/atplH2eSBUresMhHu3AZUUXZKfFQ2m07FDBNAtsoYNnO +d17EXDaoQRDVWSP83GN4b/hpmngvHl1fuFBZ1ms375FNPQo/K33QBaUsLsqiIS/v +k3LBkeECgYEAyqv5dkgte9c2mxT5zUQySr1fDms4nwZTth8477jRnOZND1M9VoIv +1EjBfxq3y7gJVd34VWYeCxNBYwK8C45SDXtlU9X2hLeKWU6yfdegyxv950P5AahT +J80YtYSez+mTLPOC42GeTg7l01NXlTHmPpraIkdNniHc8bqyAEK9w+kCgYEAxuuO +Ln84GkAm1gr6gyFkOMVwVEfszKjRGIqp4BnSwM9bFgWvhyj4jpr+bpe4gQKQQE5q +E/GoxYOtdZ3yYupd2Ki0irGhhm3u0ywgmbomurOw46AInONWcHTU6kZY/dd8wfvW +8YcmFq/LNupwFOEw18mKaQXygMnUYci+uOSw0Y8CgYEAkcX0XjE4FdUL/6usqQme +KsfesR5J0YfZeism5rXGftXfI2C5w5lMEaJrGqL7A9pRTKOlVLdocIrfAvoaiy1I +s03H6e8Bqx/gsK+8DmujybNOgqMPXTPW68/HL/g9ykm0hCZ6RFYYaQiqIb/WRQdp +FiqHLxSeLVkp8+xWz30xxNECgYAA7P23Z64qKRxFKL3ruE8QGJMiQUdv2GVIuPR7 +b4NUlGJ3IsWjWmR1vXDrsNcR+qITOoox15ESgj9facHEBhUzue1FK/h1eLOA1ha8 +wGoHumhbVtZTbJdtZI3NHVCytbsF6Bci/p8FwgGvGr40yquAhZaYUIfFY6sSXW3N +zHqqLwKBgQCUGrePDhjjUZZNQya0TQZ95HL8OQB2e9bx8RwypYdC3pAZ6uDfl+Ne +IZoA8EoDHVbsxDXmLTGil/kyvmYBnzvkVz/yMyFm/7I0zXEOr8bTgqE5wJ8BMGSp +yil5jDoN28KL6D+HsDsWUEOvvHieDYP3cxfpZWiQuWIZ6gfDDVjIwQ== +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/bogus-client.crt b/tests/auto/network/ssl/qsslsocket/certs/bogus-client.crt new file mode 100644 index 0000000000..c9d43ce662 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/bogus-client.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/zCCAeegAwIBAgIBADANBgkqhkiG9w0BAQsFADAvMRowGAYDVQQKDBFCb2d1 +cyBDb3Jwb3JhdGlvbjERMA8GA1UEAwwIQm9ndXMgQ0EwIBcNMTUwMTMwMTczNTI0 +WhgPMjExNTAxMDYxNzM1MjRaMDMxGjAYBgNVBAoMEUJvZ3VzIENvcnBvcmF0aW9u +MRUwEwYDVQQDDAxCb2d1cyBDbGllbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDa28y3b2qcrFTjr3GIgjx78qlbRZomBt/A//ZW5qx00+QXT30bu8F0 +jCfHaBTDSnabP86856C/kL1d6oRtc7jmaxNoj39uRh3NcV3VmFEiLI9XmJ0gOIBN +vMQ0voi4gvRBzjFMnVOFML8FePV4OUX1QUZK4eAvZCsDhaJv1cCEERsfcttv7X31 +CT3+a3geZsb0cMDqicq/uaX2IONhqoNYwGlmgF+bWICIxJmEnaK3e/LnKKpvvfTt +n2M0Fx0W4150HSZxQ9Iz6fQQ8oLNn3qNL5i9377XKpck2uxC39yt5WXK2d5m8xBF +5+qwMMqlEW4LoE/dTU9mJ1lZLwV7m7QJAgMBAAGjIDAeMAkGA1UdEwQCMAAwEQYJ +YIZIAYb4QgEBBAQDAgeAMA0GCSqGSIb3DQEBCwUAA4IBAQBBeGwXbU/WRLkfxDoI +Js2nPqzpfEXAcrJhurHKlm/wMIHnHHhTM69O7yTl/VUdKIXPzC1bGkAiSBQo+51B +SJkyWo3vt47g8rqAnUs4oM+bPD2t1YkJVeGLu+Nfw5SHlc+HdojdAcpKtnCbqtrd +vnV4QyB70nxKXC3jmWVBu/jeim0RzUacO+lF9vRPqwnlDINopx8ZpEjaXxABtaQA +cVUosFGEPRjOYAbw9j4fK7J7EXh/124j81OfawkfaMMDt2EedmSdlhPy+Io7VaBo +ho+39cX/oO3Ek+C9v+4aGF7rgp3VyKOGtC5rIy+YiwjcI09pRVPuqEqXC6C4nQcS +SjjF +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/bogus-client.key b/tests/auto/network/ssl/qsslsocket/certs/bogus-client.key new file mode 100644 index 0000000000..f676af73d4 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/bogus-client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA2tvMt29qnKxU469xiII8e/KpW0WaJgbfwP/2VuasdNPkF099 +G7vBdIwnx2gUw0p2mz/OvOegv5C9XeqEbXO45msTaI9/bkYdzXFd1ZhRIiyPV5id +IDiATbzENL6IuIL0Qc4xTJ1ThTC/BXj1eDlF9UFGSuHgL2QrA4Wib9XAhBEbH3Lb +b+199Qk9/mt4HmbG9HDA6onKv7ml9iDjYaqDWMBpZoBfm1iAiMSZhJ2it3vy5yiq +b7307Z9jNBcdFuNedB0mcUPSM+n0EPKCzZ96jS+Yvd++1yqXJNrsQt/creVlytne +ZvMQRefqsDDKpRFuC6BP3U1PZidZWS8Fe5u0CQIDAQABAoIBAQDOzZlA0CgWiYTh +bLvEOQQ8Pw0msLs7KY2vCm7UqL3W2w4RtMvMM/tWTMWd2EyeSLOQeZe5ysmLmpJF +tz+RSSMzn4REbiwEoH6yzWfUWEx6FU8Rf6UheCJM0o04Jb59U0jJEbRl59eu6GPo +IOcaxkvDtv1b7tnvDiDTACiAsqNqZhs54QlqwpadSYe4QgK9KH0WxqBzLpXr8eEq +ZV1uuuNpaf+mitVaJhXHyVt7Od1yPfohbTYaXjko3xt3BcStt4tzRZkGQk2kjMWd +d53wqcFlc+zxSW9/ogLr+TCDttTEa1oV+JLpXLkV5J0/saf/LYw96r6f98XhLrd1 +5otsbQ+dAoGBAP0nCzd6otnuUsLX+dz0ed61zDzyTVBXLxuOOvDpuPItVUKPI8yZ +mwveIm97/4u50HGSWUgLR5v+ABfMVG/DqkEP50dDbIhQ2uBhkR5xVgSlZSiZ7S03 +1AErADaeViphKjfAuHraGgC6SRv8HBZadbYW+ZQRVTF6IRJmstiLNJIDAoGBAN1S +AYtYhH0tJSQxyL+sdeuPGhY5RDdlSeLRAStpoGjmaOC4Rc8uDsts2xuInkCcTW2y +nogoR5YxFvcly3vGL5kOzLuscLbueqkz/rbTlZPruqL7fMyPI7Y3YgGER5XNwPpE ++DlW1fu2aE42WUU49mkUNaT2WBtOLnbZKShAWKoDAoGAOGZfeF/JMnaHV8OYdmK9 +WCH2u8lb8j9KToBUn2HjA4mYCjkrx6SdR3qY/2+H0pB2YScy3vssXBOt3591XGUi +ZFZvt4/M+V3SNdVm6HplqKlUrUQF9GIQyKXU6VZDajO1nTBBqZU339ug+Cwl8dD7 +krLxrcxix6AnCBt7UwVIlBMCgYEAydQADogxgknKJiC0Vn86pg9BFeUxXWckIxDA +hUt0+lSsbcn993qkCUUC5zAGSRuAzLnoMnixF7k6nTW9Q+mu/GBvufH+dAQ0ndsJ +vMZlEJkXAYxf+dfLFF+bI5DzCxywkEqXJwsWZs6ofjK35BWXOKoyZXY1UOlSHBXb +n5ZWhOsCgYBRLqEjUehkZfqjZj8VClyPQ/6bAgtfjMRqpgsLgvqG9gBraDs4DXJr +K8Ac3+vCP8rqVwIUC0iu/5MFX75WJ7Go7wbAg7m91P9tmzSiLEm5H1toXJpla6nv +oLZW+jN9O1BaVow8f2qIEJMjHnDbuZnMPQlMGUD+g2tNgczfxT3MOA== +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/bogus-server.crt b/tests/auto/network/ssl/qsslsocket/certs/bogus-server.crt new file mode 100644 index 0000000000..7e59f6128d --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/bogus-server.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/zCCAeegAwIBAgIBATANBgkqhkiG9w0BAQsFADAvMRowGAYDVQQKDBFCb2d1 +cyBDb3Jwb3JhdGlvbjERMA8GA1UEAwwIQm9ndXMgQ0EwIBcNMTUwMTMxMTc0MjI3 +WhgPMjExNTAxMDcxNzQyMjdaMDMxGjAYBgNVBAoMEUJvZ3VzIENvcnBvcmF0aW9u +MRUwEwYDVQQDDAxCb2d1cyBTZXJ2ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCv899JQxy/mpaQzscopmoKOkgbmwGwty1KiTpT09MU1+gtMHCfhmVp +nAiNIlQlDa+5mjhvyy1fSf+mgdjnvT5pdUAro633gfCv318EViwYsvA7/0ZumFqU +UyPWw4/2of/ZfJv2ewzMLoYEDKiLcXxInBsMlt5Lr7IBS8SNitDU+TAM7HLEIkMz +c0JpxY09H707tO8G3e93yfB5l8H+JdeEdPe+7PDfnsZZuMmaImiNYRByPTTuGvrN +I9I+OxcE4ZOMMNb3mzAoEFnyfHiCO2ehHl58y0a49ayAKJdP/FV3n2LtL/Zc5Ilq +b3VJgaShevrfIiItURjOAjDA9B95hYuZAgMBAAGjIDAeMAkGA1UdEwQCMAAwEQYJ +YIZIAYb4QgEBBAQDAgZAMA0GCSqGSIb3DQEBCwUAA4IBAQBhTqwD3HxamZGopq0K +r8KUdtliiPwo4GBFp0zg6VdSxo01WfpwFGOaeKNmV0JadtJ1DhcsdIUv2OvrxiWQ +1n0IGHULeazQnst1q1t/Vlup3IggKTGCLi8yd3acY8tr2wj9lGjWhsR+BcrCUTEB +BCpIsQiFA8+PTf/8SHuzMokDBP+j02fWCqwR749H4NDQgqrFsgzxLDA69XgvkNM3 ++HOsOR/QxeYIp54mqPnsNVhzV0JbpQpF4j9R5kMI/bsPmWH6W0GbSSyA07o8iVw7 +eqPbwHnIlHXzafvaGmF0QituAzU0nPgMc9OMxuoqacBSmSvmSdMmh///vr7O2KHO +7s+g +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/bogus-server.key b/tests/auto/network/ssl/qsslsocket/certs/bogus-server.key new file mode 100644 index 0000000000..bda8dae678 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/bogus-server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAr/PfSUMcv5qWkM7HKKZqCjpIG5sBsLctSok6U9PTFNfoLTBw +n4ZlaZwIjSJUJQ2vuZo4b8stX0n/poHY570+aXVAK6Ot94Hwr99fBFYsGLLwO/9G +bphalFMj1sOP9qH/2Xyb9nsMzC6GBAyoi3F8SJwbDJbeS6+yAUvEjYrQ1PkwDOxy +xCJDM3NCacWNPR+9O7TvBt3vd8nweZfB/iXXhHT3vuzw357GWbjJmiJojWEQcj00 +7hr6zSPSPjsXBOGTjDDW95swKBBZ8nx4gjtnoR5efMtGuPWsgCiXT/xVd59i7S/2 +XOSJam91SYGkoXr63yIiLVEYzgIwwPQfeYWLmQIDAQABAoIBAHVRJJLjpZp3h2a8 +CHypIND69TM60hCywgcNoo9cEES4hL0ErEMhSCL3f5giyHoAOyeElZasoO8FFuk9 +cJNrUd7c59FxDECYKhQJ2n+4uSQqwxUt6xc4jESTfrTmpemrMD0h4ZehifHmH0M5 +8XMwUs7TDxIA0e0jE4vbqg05/m3RMHoeJ4W5K4dMxkJbjmyjjCr8aT8WP/KSTABS +YQPql0rs6WL5Q2s1I/i3I4qIS4CKk8Ym7O5/Wk1fxbCh2ABL2PhW8PZDzvsFYo2T +cwX0cc0EILBc3tOG11Iua6mK8y9Zz1BpUT02ZvGaPf9R6vI0Shk1yWbZ0NYLx0MH +Zu8HIYECgYEA5awzjNcnDYQY9f6C/0TNj54Z8I7UFmGJX7XhPVVMceNieUiLvrsH +Zmf4Q51PLM1iz0S2qGA/c7lngHDXwFe++MANIK7KNwL2LtPF/83mYgBUxBKJaNHD +4B/6CCitjSwAfMNBnE70zg0F9chqy+9p+fTEwUFW6Y4y9U5jO4kw5HECgYEAxB8+ +YYMUGeIt9TnMKrC2YK/o8jo+5ZEOpEIPwleeAIUMujVVonu3TX2nKos2MgaZg/F0 +OpvDlcQZqb4Em73ctf3ZgBYEs9tt2qdB5qGlg4Hs2wyfgKUPQGLX2RseUQCYsOWT +cPPKvYDTZ6yhW6gGBd5ufl5tnG93CsIpcNV1DakCgYEAwByZhi6V4Q1k36eDpcjE +dWRW6ExghVQS17dIb8hAyGbeAPs4wVKqbvN6y/vytVQbWapta0wO51rng51gKuh6 +upHSqUrrpLZafHLyBPYSxljmjpe+zqnfwUKeH2L/QL3UroeZAwlcZlqoaJ27D1j0 ++XrPdaOU8onagCyQfsVT21ECgYAafW3blezdIiO6/7eH/J5lqNz5+swMDe/AV/vw +8AyzXUU+0X1jmPpFSTePE4aaczHBFJfyYp+kVvxwZO4Say6olkUOe+resEDCS90m +3aaRgLcRTz8sDR9mPvOQq40Iu9/j5N5pX0R/HCtx0WtqCePmXwjloLOFcbjOhzM5 +vls1IQKBgEF8DEk8T4ycjwBXC3U7Duj9jPL815417BAHdGstLP1yNcI05ubN2T56 +ITbf625YS7OdtYfrf1/jBnUVXsJspsQqkOUB97M224CVWI+vJiv8jPX+KCnR7/Zh +A/7OrtZ6FCzLyBeu/2p1NHAttqSUqu9t6wCeeBcelnAUcrjfLmlw +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslsocket/qsslsocket.pro b/tests/auto/network/ssl/qsslsocket/qsslsocket.pro index 6e34b23f6c..07774d1847 100644 --- a/tests/auto/network/ssl/qsslsocket/qsslsocket.pro +++ b/tests/auto/network/ssl/qsslsocket/qsslsocket.pro @@ -30,6 +30,4 @@ wince* { DEFINES += SRCDIR=\\\"$$PWD/\\\" } -linux-*:system(". /etc/lsb-release && [ $DISTRIB_CODENAME = oneiric ]"):DEFINES+=UBUNTU_ONEIRIC # QTBUG-24234 - requires(contains(QT_CONFIG,private_tests)) diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index a355cfeb17..f4d3555531 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -1,7 +1,8 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2014 Governikus GmbH & Co. KG. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** @@ -10,9 +11,9 @@ ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser @@ -23,15 +24,15 @@ ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ - +#include <QtCore/qglobal.h> #include <QtCore/qthread.h> #include <QtNetwork/qhostaddress.h> #include <QtNetwork/qhostinfo.h> @@ -41,27 +42,42 @@ #include <QtNetwork/qsslkey.h> #include <QtNetwork/qsslsocket.h> #include <QtNetwork/qtcpserver.h> +#include <QtNetwork/qsslpresharedkeyauthenticator.h> #include <QtTest/QtTest> #include <QNetworkProxy> #include <QAuthenticator> #include "private/qhostinfo_p.h" +#include "private/qiodevice_p.h" // for QIODEVICE_BUFFERSIZE + +#include "../../../network-settings.h" + #ifndef QT_NO_SSL +#ifndef QT_NO_OPENSSL #include "private/qsslsocket_openssl_p.h" #include "private/qsslsocket_openssl_symbols_p.h" -#include "private/qsslconfiguration_p.h" #endif +#include "private/qsslsocket_p.h" +#include "private/qsslconfiguration_p.h" -#include "../../../network-settings.h" - -#ifndef QT_NO_SSL Q_DECLARE_METATYPE(QSslSocket::SslMode) typedef QList<QSslError::SslError> SslErrorList; Q_DECLARE_METATYPE(SslErrorList) Q_DECLARE_METATYPE(QSslError) +Q_DECLARE_METATYPE(QSslKey) Q_DECLARE_METATYPE(QSsl::SslProtocol) +Q_DECLARE_METATYPE(QSslSocket::PeerVerifyMode); +typedef QSharedPointer<QSslSocket> QSslSocketPtr; + +// Non-OpenSSL backends are not able to report a specific error code +// for self-signed certificate for certificates. +#ifndef QT_NO_OPENSSL +#define FLUKE_CERTIFICATE_ERROR QSslError::SelfSignedCertificate +#else +#define FLUKE_CERTIFICATE_ERROR QSslError::CertificateUntrusted #endif +#endif // QT_NO_SSL #if defined Q_OS_HPUX && defined Q_CC_GNU // This error is delivered every time we try to use the fluke CA @@ -69,9 +85,14 @@ Q_DECLARE_METATYPE(QSsl::SslProtocol) #define QSSLSOCKET_CERTUNTRUSTED_WORKAROUND #endif -#ifndef QT_NO_SSL -typedef QSharedPointer<QSslSocket> QSslSocketPtr; -#endif +// Use this cipher to force PSK key sharing. +// Also, it's a cipher w/o auth, to check that we emit the signals warning +// about the identity of the peer. +static const QString PSK_CIPHER_WITHOUT_AUTH = QStringLiteral("PSK-AES256-CBC-SHA"); +static const quint16 PSK_SERVER_PORT = 4433; +static const QByteArray PSK_CLIENT_PRESHAREDKEY = QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f"); +static const QByteArray PSK_SERVER_IDENTITY_HINT = QByteArrayLiteral("QtTestServerHint"); +static const QByteArray PSK_CLIENT_IDENTITY = QByteArrayLiteral("Client_identity"); class tst_QSslSocket : public QObject { @@ -96,6 +117,19 @@ public: #ifndef QT_NO_SSL QSslSocketPtr newSocket(); + +#ifndef QT_NO_OPENSSL + enum PskConnectTestType { + PskConnectDoNotHandlePsk, + PskConnectEmptyCredentials, + PskConnectWrongCredentials, + PskConnectWrongIdentity, + PskConnectWrongPreSharedKey, + PskConnectRightCredentialsPeerVerifyFailure, + PskConnectRightCredentialsVerifyPeer, + PskConnectRightCredentialsDoNotVerifyPeer, + }; +#endif #endif public slots: @@ -168,7 +202,6 @@ private slots: void waitForMinusOne(); void verifyMode(); void verifyDepth(); - void peerVerifyError(); void disconnectFromHostWhenConnecting(); void disconnectFromHostWhenConnected(); void resetProxy(); @@ -190,8 +223,15 @@ private slots: void qtbug18498_peek2(); void dhServer(); void ecdhServer(); + void verifyClientCertificate_data(); + void verifyClientCertificate(); void setEmptyDefaultConfiguration(); // this test should be last +#ifndef QT_NO_OPENSSL + void simplePskConnect_data(); + void simplePskConnect(); +#endif + static void exitLoop() { // Safe exit - if we aren't in an event loop, don't @@ -224,6 +264,12 @@ private: static int loopLevel; }; +#ifndef QT_NO_SSL +#ifndef QT_NO_OPENSSL +Q_DECLARE_METATYPE(tst_QSslSocket::PskConnectTestType) +#endif +#endif + int tst_QSslSocket::loopLevel = 0; tst_QSslSocket::tst_QSslSocket() @@ -233,6 +279,11 @@ tst_QSslSocket::tst_QSslSocket() qRegisterMetaType<QSslError>("QSslError"); qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState"); qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError"); + +#ifndef QT_NO_OPENSSL + qRegisterMetaType<QSslPreSharedKeyAuthenticator *>(); + qRegisterMetaType<tst_QSslSocket::PskConnectTestType>(); +#endif #endif } @@ -546,37 +597,53 @@ 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); + QString name = QtNetworkSettings::serverLocalName(); + QTest::newRow(qPrintable(name)) << name << 993; + + name = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(); + QTest::newRow(qPrintable(name)) << name << 443; } void tst_QSslSocket::sslErrors() { QFETCH(QString, host); QFETCH(int, port); - QFETCH(SslErrorList, expected); QSslSocketPtr socket = newSocket(); + QSignalSpy sslErrorsSpy(socket.data(), SIGNAL(sslErrors(QList<QSslError>))); + QSignalSpy peerVerifyErrorSpy(socket.data(), SIGNAL(peerVerifyError(QSslError))); + socket->connectToHostEncrypted(host, port); if (!socket->waitForConnected()) - QEXPECT_FAIL("imap.trolltech.com", "server not open to internet", Continue); - socket->waitForEncrypted(5000); + QSKIP("Skipping flaky test - See QTBUG-29941"); + socket->waitForEncrypted(10000); - SslErrorList output; - foreach (QSslError error, socket->sslErrors()) { - output << error.error(); - } + // check the SSL errors contain HostNameMismatch and an error due to + // the certificate being self-signed + SslErrorList sslErrors; + foreach (const QSslError &err, socket->sslErrors()) + sslErrors << err.error(); + qSort(sslErrors); + QVERIFY(sslErrors.contains(QSslError::HostNameMismatch)); + QVERIFY(sslErrors.contains(FLUKE_CERTIFICATE_ERROR)); -#ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND - if (output.count() && output.last() == QSslError::CertificateUntrusted) - output.takeLast(); -#endif - QCOMPARE(output, expected); + // check the same errors were emitted by sslErrors + QVERIFY(!sslErrorsSpy.isEmpty()); + SslErrorList emittedErrors; + foreach (const QSslError &err, qvariant_cast<QList<QSslError> >(sslErrorsSpy.first().first())) + emittedErrors << err.error(); + qSort(emittedErrors); + QCOMPARE(sslErrors, emittedErrors); + + // check the same errors were emitted by peerVerifyError + QVERIFY(!peerVerifyErrorSpy.isEmpty()); + SslErrorList peerErrors; + const QList<QVariantList> &peerVerifyList = peerVerifyErrorSpy; + foreach (const QVariantList &args, peerVerifyList) + peerErrors << qvariant_cast<QSslError>(args.first()).error(); + qSort(peerErrors); + QCOMPARE(sslErrors, peerErrors); } void tst_QSslSocket::addCaCertificate() @@ -929,7 +996,7 @@ void tst_QSslSocket::protocol() socket->abort(); } #endif -#ifndef OPENSSL_NO_SSL2 +#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) { // qt-test-server allows SSLV2. socket->setProtocol(QSsl::SslV2); @@ -996,12 +1063,17 @@ public: const QString &certFile = SRCDIR "certs/fluke.cert", const QString &interFile = QString()) : socket(0), + ignoreSslErrors(true), + peerVerifyMode(QSslSocket::AutoVerifyPeer), protocol(QSsl::TlsV1_0), m_keyFile(keyFile), m_certFile(certFile), m_interFile(interFile) { } QSslSocket *socket; + QString addCaCertificates; + bool ignoreSslErrors; + QSslSocket::PeerVerifyMode peerVerifyMode; QSsl::SslProtocol protocol; QString m_keyFile; QString m_certFile; @@ -1012,8 +1084,10 @@ protected: void incomingConnection(qintptr socketDescriptor) { socket = new QSslSocket(this); + socket->setPeerVerifyMode(peerVerifyMode); socket->setProtocol(protocol); - connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); + if (ignoreSslErrors) + connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); QFile file(m_keyFile); QVERIFY(file.open(QIODevice::ReadOnly)); @@ -1021,6 +1095,14 @@ protected: QVERIFY(!key.isNull()); socket->setPrivateKey(key); + // Add CA certificates to verify client certificate + if (!addCaCertificates.isEmpty()) { + QList<QSslCertificate> caCert = QSslCertificate::fromPath(addCaCertificates); + QVERIFY(!caCert.isEmpty()); + QVERIFY(!caCert.first().isNull()); + socket->addCaCertificates(caCert); + } + // If we have a cert issued directly from the CA if (m_interFile.isEmpty()) { QList<QSslCertificate> localCert = QSslCertificate::fromPath(m_certFile); @@ -1066,7 +1148,7 @@ void tst_QSslSocket::protocolServerSide_data() QTest::addColumn<QSsl::SslProtocol>("clientProtocol"); QTest::addColumn<bool>("works"); -#ifndef OPENSSL_NO_SSL2 +#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("ssl2-ssl2") << QSsl::SslV2 << QSsl::SslV2 << false; // no idea why it does not work, but we don't care about SSL 2 #endif QTest::newRow("ssl3-ssl3") << QSsl::SslV3 << QSsl::SslV3 << true; @@ -1075,7 +1157,7 @@ void tst_QSslSocket::protocolServerSide_data() QTest::newRow("any-any") << QSsl::AnyProtocol << QSsl::AnyProtocol << true; QTest::newRow("secure-secure") << QSsl::SecureProtocols << QSsl::SecureProtocols << true; -#ifndef OPENSSL_NO_SSL2 +#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("ssl2-ssl3") << QSsl::SslV2 << QSsl::SslV3 << false; QTest::newRow("ssl2-tls1.0") << QSsl::SslV2 << QSsl::TlsV1_0 << false; QTest::newRow("ssl2-tls1ssl3") << QSsl::SslV2 << QSsl::TlsV1SslV3 << false; @@ -1083,33 +1165,33 @@ void tst_QSslSocket::protocolServerSide_data() QTest::newRow("ssl2-any") << QSsl::SslV2 << QSsl::AnyProtocol << false; // no idea why it does not work, but we don't care about SSL 2 #endif -#ifndef OPENSSL_NO_SSL2 +#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("ssl3-ssl2") << QSsl::SslV3 << QSsl::SslV2 << false; #endif QTest::newRow("ssl3-tls1.0") << QSsl::SslV3 << QSsl::TlsV1_0 << false; QTest::newRow("ssl3-tls1ssl3") << QSsl::SslV3 << QSsl::TlsV1SslV3 << true; QTest::newRow("ssl3-secure") << QSsl::SslV3 << QSsl::SecureProtocols << false; -#ifndef OPENSSL_NO_SSL2 +#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("ssl3-any") << QSsl::SslV3 << QSsl::AnyProtocol << false; // we won't set a SNI header here because we connect to a // numerical IP, so OpenSSL will send a SSL 2 handshake #else QTest::newRow("ssl3-any") << QSsl::SslV3 << QSsl::AnyProtocol << true; #endif -#ifndef OPENSSL_NO_SSL2 +#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("tls1.0-ssl2") << QSsl::TlsV1_0 << QSsl::SslV2 << false; #endif QTest::newRow("tls1.0-ssl3") << QSsl::TlsV1_0 << QSsl::SslV3 << false; QTest::newRow("tls1-tls1ssl3") << QSsl::TlsV1_0 << QSsl::TlsV1SslV3 << true; QTest::newRow("tls1.0-secure") << QSsl::TlsV1_0 << QSsl::SecureProtocols << true; -#ifndef OPENSSL_NO_SSL2 +#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("tls1.0-any") << QSsl::TlsV1_0 << QSsl::AnyProtocol << false; // we won't set a SNI header here because we connect to a // numerical IP, so OpenSSL will send a SSL 2 handshake #else QTest::newRow("tls1.0-any") << QSsl::TlsV1_0 << QSsl::AnyProtocol << true; #endif -#ifndef OPENSSL_NO_SSL2 +#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("tls1ssl3-ssl2") << QSsl::TlsV1SslV3 << QSsl::SslV2 << false; #endif QTest::newRow("tls1ssl3-ssl3") << QSsl::TlsV1SslV3 << QSsl::SslV3 << true; @@ -1117,7 +1199,7 @@ void tst_QSslSocket::protocolServerSide_data() QTest::newRow("tls1ssl3-secure") << QSsl::TlsV1SslV3 << QSsl::SecureProtocols << true; QTest::newRow("tls1ssl3-any") << QSsl::TlsV1SslV3 << QSsl::AnyProtocol << true; -#ifndef OPENSSL_NO_SSL2 +#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("secure-ssl2") << QSsl::SecureProtocols << QSsl::SslV2 << false; #endif QTest::newRow("secure-ssl3") << QSsl::SecureProtocols << QSsl::SslV3 << false; @@ -1125,7 +1207,7 @@ void tst_QSslSocket::protocolServerSide_data() QTest::newRow("secure-tls1ssl3") << QSsl::SecureProtocols << QSsl::TlsV1SslV3 << true; QTest::newRow("secure-any") << QSsl::SecureProtocols << QSsl::AnyProtocol << true; -#ifndef OPENSSL_NO_SSL2 +#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) QTest::newRow("any-ssl2") << QSsl::AnyProtocol << QSsl::SslV2 << false; // no idea why it does not work, but we don't care about SSL 2 #endif QTest::newRow("any-ssl3") << QSsl::AnyProtocol << QSsl::SslV3 << true; @@ -1950,7 +2032,7 @@ void tst_QSslSocket::verifyMode() QSKIP("Skipping flaky test - See QTBUG-29941"); QList<QSslError> expectedErrors = QList<QSslError>() - << QSslError(QSslError::SelfSignedCertificate, socket.peerCertificate()); + << QSslError(FLUKE_CERTIFICATE_ERROR, socket.peerCertificate()); QCOMPARE(socket.sslErrors(), expectedErrors); socket.abort(); @@ -1981,34 +2063,6 @@ void tst_QSslSocket::verifyDepth() QCOMPARE(socket.peerVerifyDepth(), 1); } -void tst_QSslSocket::peerVerifyError() -{ - QSslSocketPtr socket = newSocket(); - QSignalSpy sslErrorsSpy(socket.data(), SIGNAL(sslErrors(QList<QSslError>))); - QSignalSpy peerVerifyErrorSpy(socket.data(), SIGNAL(peerVerifyError(QSslError))); - - socket->connectToHostEncrypted(QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(), 443); - if (socket->waitForEncrypted(10000)) - QSKIP("Skipping flaky test - See QTBUG-29941"); - - // check HostNameMismatch was emitted by peerVerifyError - QVERIFY(!peerVerifyErrorSpy.isEmpty()); - SslErrorList peerErrors; - const QList<QVariantList> &peerVerifyList = peerVerifyErrorSpy; - foreach (const QVariantList &args, peerVerifyList) - peerErrors << qvariant_cast<QSslError>(args.first()).error(); - QVERIFY(peerErrors.contains(QSslError::HostNameMismatch)); - - // check HostNameMismatch was emitted by sslErrors - QVERIFY(!sslErrorsSpy.isEmpty()); - SslErrorList sslErrors; - foreach (const QSslError &err, qvariant_cast<QList<QSslError> >(sslErrorsSpy.first().first())) - sslErrors << err.error(); - QVERIFY(peerErrors.contains(QSslError::HostNameMismatch)); - - QCOMPARE(sslErrors.size(), peerErrors.size()); -} - void tst_QSslSocket::disconnectFromHostWhenConnecting() { QSslSocketPtr socket = newSocket(); @@ -2105,8 +2159,8 @@ void tst_QSslSocket::ignoreSslErrorsList_data() 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); + QSslError rightError(FLUKE_CERTIFICATE_ERROR, certs.at(0)); + QSslError wrongError(FLUKE_CERTIFICATE_ERROR); QTest::newRow("SSL-failure-empty-list") << expectedSslErrors << 1; @@ -2368,8 +2422,8 @@ void tst_QSslSocket::resume_data() QTest::newRow("ignoreAllErrors") << true << QList<QSslError>() << true; QList<QSslCertificate> certs = QSslCertificate::fromPath(QLatin1String(SRCDIR "certs/qt-test-server-cacert.pem")); - QSslError rightError(QSslError::SelfSignedCertificate, certs.at(0)); - QSslError wrongError(QSslError::SelfSignedCertificate); + QSslError rightError(FLUKE_CERTIFICATE_ERROR, certs.at(0)); + QSslError wrongError(FLUKE_CERTIFICATE_ERROR); errorsList.append(wrongError); QTest::newRow("ignoreSpecificErrors-Wrong") << true << errorsList << false; errorsList.clear(); @@ -2747,6 +2801,140 @@ void tst_QSslSocket::ecdhServer() QVERIFY(client->state() == QAbstractSocket::ConnectedState); } +void tst_QSslSocket::verifyClientCertificate_data() +{ + QTest::addColumn<QSslSocket::PeerVerifyMode>("peerVerifyMode"); + QTest::addColumn<QList<QSslCertificate> >("clientCerts"); + QTest::addColumn<QSslKey>("clientKey"); + QTest::addColumn<bool>("works"); + + // no certificate + QList<QSslCertificate> noCerts; + QSslKey noKey; + + QTest::newRow("NoCert:AutoVerifyPeer") << QSslSocket::AutoVerifyPeer << noCerts << noKey << true; + QTest::newRow("NoCert:QueryPeer") << QSslSocket::QueryPeer << noCerts << noKey << true; + QTest::newRow("NoCert:VerifyNone") << QSslSocket::VerifyNone << noCerts << noKey << true; + QTest::newRow("NoCert:VerifyPeer") << QSslSocket::VerifyPeer << noCerts << noKey << false; + + // self-signed certificate + QList<QSslCertificate> flukeCerts = QSslCertificate::fromPath(SRCDIR "certs/fluke.cert"); + QCOMPARE(flukeCerts.size(), 1); + + QFile flukeFile(SRCDIR "certs/fluke.key"); + QVERIFY(flukeFile.open(QIODevice::ReadOnly)); + QSslKey flukeKey(flukeFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + QVERIFY(!flukeKey.isNull()); + + QTest::newRow("SelfSignedCert:AutoVerifyPeer") << QSslSocket::AutoVerifyPeer << flukeCerts << flukeKey << true; + QTest::newRow("SelfSignedCert:QueryPeer") << QSslSocket::QueryPeer << flukeCerts << flukeKey << true; + QTest::newRow("SelfSignedCert:VerifyNone") << QSslSocket::VerifyNone << flukeCerts << flukeKey << true; + QTest::newRow("SelfSignedCert:VerifyPeer") << QSslSocket::VerifyPeer << flukeCerts << flukeKey << false; + + // valid certificate, but wrong usage (server certificate) + QList<QSslCertificate> serverCerts = QSslCertificate::fromPath(SRCDIR "certs/bogus-server.crt"); + QCOMPARE(serverCerts.size(), 1); + + QFile serverFile(SRCDIR "certs/bogus-server.key"); + QVERIFY(serverFile.open(QIODevice::ReadOnly)); + QSslKey serverKey(serverFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + QVERIFY(!serverKey.isNull()); + + QTest::newRow("ValidServerCert:AutoVerifyPeer") << QSslSocket::AutoVerifyPeer << serverCerts << serverKey << true; + QTest::newRow("ValidServerCert:QueryPeer") << QSslSocket::QueryPeer << serverCerts << serverKey << true; + QTest::newRow("ValidServerCert:VerifyNone") << QSslSocket::VerifyNone << serverCerts << serverKey << true; + QTest::newRow("ValidServerCert:VerifyPeer") << QSslSocket::VerifyPeer << serverCerts << serverKey << false; + + // valid certificate, correct usage (client certificate) + QList<QSslCertificate> validCerts = QSslCertificate::fromPath(SRCDIR "certs/bogus-client.crt"); + QCOMPARE(validCerts.size(), 1); + + QFile validFile(SRCDIR "certs/bogus-client.key"); + QVERIFY(validFile.open(QIODevice::ReadOnly)); + QSslKey validKey(validFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + QVERIFY(!validKey.isNull()); + + QTest::newRow("ValidClientCert:AutoVerifyPeer") << QSslSocket::AutoVerifyPeer << validCerts << validKey << true; + QTest::newRow("ValidClientCert:QueryPeer") << QSslSocket::QueryPeer << validCerts << validKey << true; + QTest::newRow("ValidClientCert:VerifyNone") << QSslSocket::VerifyNone << validCerts << validKey << true; + QTest::newRow("ValidClientCert:VerifyPeer") << QSslSocket::VerifyPeer << validCerts << validKey << true; + + // valid certificate, correct usage (client certificate), with chain + validCerts += QSslCertificate::fromPath(SRCDIR "certs/bogus-ca.crt"); + QCOMPARE(validCerts.size(), 2); + + QTest::newRow("ValidClientCert:AutoVerifyPeer") << QSslSocket::AutoVerifyPeer << validCerts << validKey << true; + QTest::newRow("ValidClientCert:QueryPeer") << QSslSocket::QueryPeer << validCerts << validKey << true; + QTest::newRow("ValidClientCert:VerifyNone") << QSslSocket::VerifyNone << validCerts << validKey << true; + QTest::newRow("ValidClientCert:VerifyPeer") << QSslSocket::VerifyPeer << validCerts << validKey << true; +} + +void tst_QSslSocket::verifyClientCertificate() +{ +#ifdef QT_SECURETRANSPORT + // We run both client and server on the same machine, + // this means, client can update keychain with client's certificates, + // and server later will use the same certificates from the same + // keychain thus making tests fail (wrong number of certificates, + // success instead of failure etc.). + QSKIP("This test can not work with Secure Transport"); +#endif + if (!QSslSocket::supportsSsl()) { + qWarning("SSL not supported, skipping test"); + return; + } + + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + QFETCH(QSslSocket::PeerVerifyMode, peerVerifyMode); + SslServer server; + server.addCaCertificates = QLatin1String(SRCDIR "certs/bogus-ca.crt"); + server.ignoreSslErrors = false; + server.peerVerifyMode = peerVerifyMode; + QVERIFY(server.listen()); + + QEventLoop loop; + QTimer::singleShot(5000, &loop, SLOT(quit())); + + QFETCH(QList<QSslCertificate>, clientCerts); + QFETCH(QSslKey, clientKey); + QSslSocketPtr client(new QSslSocket); + client->setLocalCertificateChain(clientCerts); + client->setPrivateKey(clientKey); + socket = client.data(); + + connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); + connect(socket, SIGNAL(disconnected()), &loop, SLOT(quit())); + connect(socket, 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; + + // check server socket + QVERIFY(server.socket); + + QCOMPARE(int(server.socket->state()), int(expectedState)); + QCOMPARE(server.socket->isEncrypted(), works); + + if (peerVerifyMode == QSslSocket::VerifyNone || clientCerts.isEmpty()) { + QVERIFY(server.socket->peerCertificate().isNull()); + QVERIFY(server.socket->peerCertificateChain().isEmpty()); + } else { + QCOMPARE(server.socket->peerCertificate(), clientCerts.first()); + QCOMPARE(server.socket->peerCertificateChain(), clientCerts); + } + + // check client socket + QCOMPARE(int(client->state()), int(expectedState)); + QCOMPARE(client->isEncrypted(), works); +} + void tst_QSslSocket::setEmptyDefaultConfiguration() // this test should be last, as it has some side effects { // used to produce a crash in QSslConfigurationPrivate::deepCopyDefaultConfiguration, QTBUG-13265 @@ -2757,14 +2945,330 @@ void tst_QSslSocket::setEmptyDefaultConfiguration() // this test should be last, QSslConfiguration emptyConf; QSslConfiguration::setDefaultConfiguration(emptyConf); - QSslSocketPtr socket = newSocket(); - connect(socket.data(), SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); + QSslSocketPtr client = newSocket(); + socket = client.data(); + + connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); QFETCH_GLOBAL(bool, setProxy); if (setProxy && socket->waitForEncrypted(4000)) QSKIP("Skipping flaky test - See QTBUG-29941"); } +#ifndef QT_NO_OPENSSL +class PskProvider : public QObject +{ + Q_OBJECT + +public: + explicit PskProvider(QObject *parent = 0) + : QObject(parent) + { + } + + void setIdentity(const QByteArray &identity) + { + m_identity = identity; + } + + void setPreSharedKey(const QByteArray &psk) + { + m_psk = psk; + } + +public slots: + void providePsk(QSslPreSharedKeyAuthenticator *authenticator) + { + QVERIFY(authenticator); + QCOMPARE(authenticator->identityHint(), PSK_SERVER_IDENTITY_HINT); + QVERIFY(authenticator->maximumIdentityLength() > 0); + QVERIFY(authenticator->maximumPreSharedKeyLength() > 0); + + if (!m_identity.isEmpty()) { + authenticator->setIdentity(m_identity); + QCOMPARE(authenticator->identity(), m_identity); + } + + if (!m_psk.isEmpty()) { + authenticator->setPreSharedKey(m_psk); + QCOMPARE(authenticator->preSharedKey(), m_psk); + } + } + +private: + QByteArray m_identity; + QByteArray m_psk; +}; + +void tst_QSslSocket::simplePskConnect_data() +{ + QTest::addColumn<PskConnectTestType>("pskTestType"); + QTest::newRow("PskConnectDoNotHandlePsk") << PskConnectDoNotHandlePsk; + QTest::newRow("PskConnectEmptyCredentials") << PskConnectEmptyCredentials; + QTest::newRow("PskConnectWrongCredentials") << PskConnectWrongCredentials; + QTest::newRow("PskConnectWrongIdentity") << PskConnectWrongIdentity; + QTest::newRow("PskConnectWrongPreSharedKey") << PskConnectWrongPreSharedKey; + QTest::newRow("PskConnectRightCredentialsPeerVerifyFailure") << PskConnectRightCredentialsPeerVerifyFailure; + QTest::newRow("PskConnectRightCredentialsVerifyPeer") << PskConnectRightCredentialsVerifyPeer; + QTest::newRow("PskConnectRightCredentialsDoNotVerifyPeer") << PskConnectRightCredentialsDoNotVerifyPeer; +} + +void tst_QSslSocket::simplePskConnect() +{ + QFETCH(PskConnectTestType, pskTestType); + QSKIP("This test requires change 1f8cab2c3bcd91335684c95afa95ae71e00a94e4 on the network test server, QTQAINFRA-917"); + + if (!QSslSocket::supportsSsl()) + QSKIP("No SSL support"); + + bool pskCipherFound = false; + const QList<QSslCipher> supportedCiphers = QSslSocket::supportedCiphers(); + foreach (const QSslCipher &cipher, supportedCiphers) { + if (cipher.name() == PSK_CIPHER_WITHOUT_AUTH) { + pskCipherFound = true; + break; + } + } + + if (!pskCipherFound) + QSKIP("SSL implementation does not support the necessary PSK cipher(s)"); + + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + QSKIP("This test must not be going through a proxy"); + + QSslSocket socket; + this->socket = &socket; + + QSignalSpy connectedSpy(&socket, SIGNAL(connected())); + QVERIFY(connectedSpy.isValid()); + + QSignalSpy hostFoundSpy(&socket, SIGNAL(hostFound())); + QVERIFY(hostFoundSpy.isValid()); + + QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected())); + QVERIFY(disconnectedSpy.isValid()); + + QSignalSpy connectionEncryptedSpy(&socket, SIGNAL(encrypted())); + QVERIFY(connectionEncryptedSpy.isValid()); + + QSignalSpy sslErrorsSpy(&socket, SIGNAL(sslErrors(QList<QSslError>))); + QVERIFY(sslErrorsSpy.isValid()); + + QSignalSpy socketErrorsSpy(&socket, SIGNAL(error(QAbstractSocket::SocketError))); + QVERIFY(socketErrorsSpy.isValid()); + + QSignalSpy peerVerifyErrorSpy(&socket, SIGNAL(peerVerifyError(QSslError))); + QVERIFY(peerVerifyErrorSpy.isValid()); + + QSignalSpy pskAuthenticationRequiredSpy(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*))); + QVERIFY(pskAuthenticationRequiredSpy.isValid()); + + 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(sslErrors(QList<QSslError>)), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(peerVerifyError(QSslError)), this, SLOT(exitLoop())); + connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(exitLoop())); + + // force a PSK cipher w/o auth + socket.setCiphers(PSK_CIPHER_WITHOUT_AUTH); + + PskProvider provider; + + switch (pskTestType) { + case PskConnectDoNotHandlePsk: + // don't connect to the provider + break; + + case PskConnectEmptyCredentials: + // connect to the psk provider, but don't actually provide any PSK nor identity + connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*))); + break; + + case PskConnectWrongCredentials: + // provide totally wrong credentials + provider.setIdentity(PSK_CLIENT_IDENTITY.left(PSK_CLIENT_IDENTITY.length() - 1)); + provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY.left(PSK_CLIENT_PRESHAREDKEY.length() - 1)); + connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*))); + break; + + case PskConnectWrongIdentity: + // right PSK, wrong identity + provider.setIdentity(PSK_CLIENT_IDENTITY.left(PSK_CLIENT_IDENTITY.length() - 1)); + provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY); + connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*))); + break; + + case PskConnectWrongPreSharedKey: + // right identity, wrong PSK + provider.setIdentity(PSK_CLIENT_IDENTITY); + provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY.left(PSK_CLIENT_PRESHAREDKEY.length() - 1)); + connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*))); + break; + + case PskConnectRightCredentialsPeerVerifyFailure: + // right identity, right PSK, but since we can't verify the other peer, we'll fail + provider.setIdentity(PSK_CLIENT_IDENTITY); + provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY); + connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*))); + break; + + case PskConnectRightCredentialsVerifyPeer: + // right identity, right PSK, verify the peer (but ignore the failure) and establish the connection + provider.setIdentity(PSK_CLIENT_IDENTITY); + provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY); + connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*))); + connect(&socket, SIGNAL(peerVerifyError(QSslError)), this, SLOT(ignoreErrorSlot())); + break; + + case PskConnectRightCredentialsDoNotVerifyPeer: + // right identity, right PSK, do not verify the peer and establish the connection + provider.setIdentity(PSK_CLIENT_IDENTITY); + provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY); + connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*))); + socket.setPeerVerifyMode(QSslSocket::VerifyNone); + break; + } + + // check the peer verification mode + switch (pskTestType) { + case PskConnectDoNotHandlePsk: + case PskConnectEmptyCredentials: + case PskConnectWrongCredentials: + case PskConnectWrongIdentity: + case PskConnectWrongPreSharedKey: + case PskConnectRightCredentialsPeerVerifyFailure: + case PskConnectRightCredentialsVerifyPeer: + QCOMPARE(socket.peerVerifyMode(), QSslSocket::AutoVerifyPeer); + break; + + case PskConnectRightCredentialsDoNotVerifyPeer: + QCOMPARE(socket.peerVerifyMode(), QSslSocket::VerifyNone); + break; + } + + // Start connecting + socket.connectToHost(QtNetworkSettings::serverName(), PSK_SERVER_PORT); + QCOMPARE(socket.state(), QAbstractSocket::HostLookupState); + enterLoop(10); + + // Entered connecting state + QCOMPARE(socket.state(), QAbstractSocket::ConnectingState); + QCOMPARE(connectedSpy.count(), 0); + 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); + QCOMPARE(peerVerifyErrorSpy.count(), 0); + + // Start handshake. + enterLoop(10); + + // We must get the PSK signal in all cases + QCOMPARE(pskAuthenticationRequiredSpy.count(), 1); + + switch (pskTestType) { + case PskConnectDoNotHandlePsk: + case PskConnectEmptyCredentials: + case PskConnectWrongCredentials: + case PskConnectWrongIdentity: + case PskConnectWrongPreSharedKey: + // Handshake failure + QCOMPARE(socketErrorsSpy.count(), 1); + QCOMPARE(qvariant_cast<QAbstractSocket::SocketError>(socketErrorsSpy.at(0).at(0)), QAbstractSocket::SslHandshakeFailedError); + QCOMPARE(sslErrorsSpy.count(), 0); + QCOMPARE(peerVerifyErrorSpy.count(), 0); + QCOMPARE(connectionEncryptedSpy.count(), 0); + QVERIFY(!socket.isEncrypted()); + break; + + case PskConnectRightCredentialsPeerVerifyFailure: + // Peer verification failure + QCOMPARE(socketErrorsSpy.count(), 1); + QCOMPARE(qvariant_cast<QAbstractSocket::SocketError>(socketErrorsSpy.at(0).at(0)), QAbstractSocket::SslHandshakeFailedError); + QCOMPARE(sslErrorsSpy.count(), 1); + QCOMPARE(peerVerifyErrorSpy.count(), 1); + QCOMPARE(connectionEncryptedSpy.count(), 0); + QVERIFY(!socket.isEncrypted()); + break; + + case PskConnectRightCredentialsVerifyPeer: + // Peer verification failure, but ignore it and keep connecting + QCOMPARE(socketErrorsSpy.count(), 0); + QCOMPARE(sslErrorsSpy.count(), 1); + QCOMPARE(peerVerifyErrorSpy.count(), 1); + QCOMPARE(connectionEncryptedSpy.count(), 1); + QVERIFY(socket.isEncrypted()); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + break; + + case PskConnectRightCredentialsDoNotVerifyPeer: + // No peer verification => no failure + QCOMPARE(socketErrorsSpy.count(), 0); + QCOMPARE(sslErrorsSpy.count(), 0); + QCOMPARE(peerVerifyErrorSpy.count(), 0); + QCOMPARE(connectionEncryptedSpy.count(), 1); + QVERIFY(socket.isEncrypted()); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + break; + } + + // check writing + switch (pskTestType) { + case PskConnectDoNotHandlePsk: + case PskConnectEmptyCredentials: + case PskConnectWrongCredentials: + case PskConnectWrongIdentity: + case PskConnectWrongPreSharedKey: + case PskConnectRightCredentialsPeerVerifyFailure: + break; + + case PskConnectRightCredentialsVerifyPeer: + case PskConnectRightCredentialsDoNotVerifyPeer: + socket.write("Hello from Qt TLS/PSK!"); + QVERIFY(socket.waitForBytesWritten()); + break; + } + + // disconnect + switch (pskTestType) { + case PskConnectDoNotHandlePsk: + case PskConnectEmptyCredentials: + case PskConnectWrongCredentials: + case PskConnectWrongIdentity: + case PskConnectWrongPreSharedKey: + case PskConnectRightCredentialsPeerVerifyFailure: + break; + + case PskConnectRightCredentialsVerifyPeer: + case PskConnectRightCredentialsDoNotVerifyPeer: + socket.disconnectFromHost(); + enterLoop(10); + break; + } + + QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState); + QCOMPARE(disconnectedSpy.count(), 1); +} +#endif // QT_NO_OPENSSL + #endif // QT_NO_SSL QTEST_MAIN(tst_QSslSocket) |