mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-06 17:25:24 +08:00
qt 6.5.1 original
This commit is contained in:
19
tests/auto/network/ssl/qocsp/CMakeLists.txt
Normal file
19
tests/auto/network/ssl/qocsp/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qocsp Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qocsp
|
||||
SOURCES
|
||||
tst_qocsp.cpp
|
||||
LIBRARIES
|
||||
Qt::Network
|
||||
Qt::NetworkPrivate
|
||||
)
|
||||
|
||||
qt_internal_extend_target(tst_qocsp CONDITION QT_FEATURE_openssl_linked
|
||||
LIBRARIES
|
||||
WrapOpenSSL::WrapOpenSSL
|
||||
)
|
24
tests/auto/network/ssl/qocsp/certs/alice.crt
Normal file
24
tests/auto/network/ssl/qocsp/certs/alice.crt
Normal file
@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEGDCCAwCgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBjjELMAkGA1UEBhMCTk8x
|
||||
DTALBgNVBAgMBE9zbG8xEjAQBgNVBAcMCU9zbG8gQ2l0eTETMBEGA1UECgwKVGhl
|
||||
IFF0IENBMTENMAsGA1UECwwEUVRDTjERMA8GA1UEAwwIY2ExcXQuaW8xJTAjBgkq
|
||||
hkiG9w0BCQEWFnRpbXVyLnBvY2hlcHRzb3ZAcXQuaW8wHhcNMTgxMTIyMTEwNjE4
|
||||
WhcNMjgxMTE5MTEwNjE4WjCBkjELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8x
|
||||
EjAQBgNVBAcMCU9zbG8gQ2l0eTEdMBsGA1UECgwUVGhlIEZhbW91cyBBbGljZSBM
|
||||
dGQxDTALBgNVBAsMBEdPQUExEjAQBgNVBAMMCWFsaWNlLm9yZzEeMBwGCSqGSIb3
|
||||
DQEJARYPYWxpY2VAYWxpY2Uub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||
CgKCAQEAtuGDR9oIEkK57xlxq/xc3u7B1ni4pdoyhf9r+pkgmu591qp2kl3Xcq3W
|
||||
Ve5Z553orAUCAExPlKfFV+CYYAedSgsDYlKk8DN+f/n+hkG6Wl2qyFzHgl+mvPwa
|
||||
eDqdVMIcDHGhSljALi9AqsN4lbrUhSxiyuPhAwl82WB0EIucmBs1NxSSZgFPRBLG
|
||||
Uzy9WvtQFq1qtn795PVIUsNg68qZQ9BvRduOQAr3bg3anoYqytthWnzLWKri2QR4
|
||||
Z4Y0mvcbT/PZwhtcFZzDXG3Hvc7k3AroAbWoSghMEgok9TW9grKYkW2d5cpQTP+l
|
||||
ptkB6yZ06MY9/uCdYzhm8eu2RgVndwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCG
|
||||
SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E
|
||||
FgQUQz2PuE4VuqHtZYTvVLr4+0IuHTUwHwYDVR0jBBgwFoAUeBcnAkU7sTqm7i2Q
|
||||
vTxwgr0nQ0QwDQYJKoZIhvcNAQELBQADggEBABGGmo1vUAXKQm9kowvUtjDpEIIY
|
||||
TpT+KqiUBOgJg5fGn6a63vBn5GMA6eT948ywi9ZU2M9dIXJCM+bdqjXeOtt4bBPZ
|
||||
xz6DcBPW9CoTR4CV1muNa95WIXzAHatq3XYG041ddMf41WG7QIdQsojBYEG0IYlv
|
||||
PQx+B+m2cu7A04aI2tCS8aUh7Xc9wRilJ+h/FlYFFQzgyEKsd7CFgkyxG/sLyFNH
|
||||
skYYk/DLlmaWa+YScHYB5kAk8StoETeMI2LLs7rgJmchi8eAxjLroYDUhQclUjqz
|
||||
vlNM+4GvcF5RluyuEXFOZVdmQahkXcyu0Q3yxvsBbnDglmbb2YHPl/blB7w=
|
||||
-----END CERTIFICATE-----
|
28
tests/auto/network/ssl/qocsp/certs/alice.key
Normal file
28
tests/auto/network/ssl/qocsp/certs/alice.key
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC24YNH2ggSQrnv
|
||||
GXGr/Fze7sHWeLil2jKF/2v6mSCa7n3WqnaSXddyrdZV7lnnneisBQIATE+Up8VX
|
||||
4JhgB51KCwNiUqTwM35/+f6GQbpaXarIXMeCX6a8/Bp4Op1UwhwMcaFKWMAuL0Cq
|
||||
w3iVutSFLGLK4+EDCXzZYHQQi5yYGzU3FJJmAU9EEsZTPL1a+1AWrWq2fv3k9UhS
|
||||
w2DryplD0G9F245ACvduDdqehirK22FafMtYquLZBHhnhjSa9xtP89nCG1wVnMNc
|
||||
bce9zuTcCugBtahKCEwSCiT1Nb2CspiRbZ3lylBM/6Wm2QHrJnToxj3+4J1jOGbx
|
||||
67ZGBWd3AgMBAAECggEADbzU+sHDF3QRuYdExbGYXFq9DtpUrIi+gNhWCSYVj+3Y
|
||||
YBa//3CzLXcngZ78++wdvUZHBzS0SatspJRHffc0doprP6iLoUuM9hoWZ4lqcT1W
|
||||
BeUKS53ZzZp2do+Yn/RQ3RJwFkCidxWvmuRCG6VEL5jM9wa1MWA2E7IuJcwHAFny
|
||||
WIByosje5Qrd7eXDuVoqr1hjJ2UxIjIJ8Zgg3EE9wVUyJE3PU1HLz2AefonYRwbL
|
||||
XlzNgnj0c9Ti9ejfyon+jTnpslLKtPal2kxyGoKPAngadAhCzqSaCWggACm7R8Ge
|
||||
pZ0Y0pV7QReEgjfFd4D3qOqLRQZVJOMDb3vJu2/rsQKBgQDfKjfSpUweBM9li7GS
|
||||
xXbDpC3Y8zQ2VY+2SvgYoYiYU/Y6YenxhKM1XDbWZxhxS8GVfCUAESFDOTZcMvdi
|
||||
QEbG1uEmuCn1ksvrC2y54rtd8WDppcS0vJxCrU4nZG0v9IjVKp67B8EpBpAQeNb1
|
||||
tR6ByT2fLJu5+WU2S7OxqX7uLwKBgQDRyfKvrCQgdJOQlJlHOv1y1hN8WY51A8P/
|
||||
JbDXoun3PCPd+JczvFXCUh3ZLXqUEAX2qDOBD1pBM62EN6/A9ukO4mcMd8uYIet6
|
||||
nR4nVqXUjWuzXe6eo913lTDQrIOGWpViTc8fnvFlwBPfwzxbZNx38HZbw0L0nT7d
|
||||
8TE/JxLROQKBgQC4Kzo4b8vadjPGZLueGbICkQp5IXR0ZrYcRdBrW1vEAn6Q/d84
|
||||
PzMFxV1IIXrNfSx8NiC+5mQh+yQ+gJ0iC1OdoxXag1+1V3lMN3h6C4B/bcWB7Rjh
|
||||
40m9yRJXdgyZ59/Is8ydIzAosE7SGTelPNy5VR+yrfiySPxbC6x3MR8cZwKBgQCq
|
||||
PVTg1bIjXDZ7NvsDYI1XaP07BXmi30FnhXByLFPsOzNn51jbtNNq8zQhjtRP3ojY
|
||||
VjolWw4EpykBiCbpUfRiDbtN1NC0TaJHR8S2a4v6ZiCl123R8mu/pKOOUtAQcOWU
|
||||
dkvD/zkpNqtqA4axK7H06n9Bi7yDwC7J7/Xkp5KPkQKBgFDprXrXg4zvIsxbXYZ3
|
||||
2bCaxyhBXNKcGwtWbbLfJcOwHJPns/abGkYIJ0NbMZX1LwTDfQWmC+8YKKvIlbKG
|
||||
S2uk5H4qzupR4XN6YJ7SCHlGv2z0vxVjV7aWc1TME2iZQoBuO1urxPZwHd/euruo
|
||||
kluWh1KV5XnWjBSYjZpiXxWl
|
||||
-----END PRIVATE KEY-----
|
24
tests/auto/network/ssl/qocsp/certs/ca1.crt
Normal file
24
tests/auto/network/ssl/qocsp/certs/ca1.crt
Normal file
@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID9DCCAtygAwIBAgIJAMQbE3657KDYMA0GCSqGSIb3DQEBCwUAMIGOMQswCQYD
|
||||
VQQGEwJOTzENMAsGA1UECAwET3NsbzESMBAGA1UEBwwJT3NsbyBDaXR5MRMwEQYD
|
||||
VQQKDApUaGUgUXQgQ0ExMQ0wCwYDVQQLDARRVENOMREwDwYDVQQDDAhjYTFxdC5p
|
||||
bzElMCMGCSqGSIb3DQEJARYWdGltdXIucG9jaGVwdHNvdkBxdC5pbzAeFw0xODEx
|
||||
MjIxMDIxMTNaFw0yODExMTkxMDIxMTNaMIGOMQswCQYDVQQGEwJOTzENMAsGA1UE
|
||||
CAwET3NsbzESMBAGA1UEBwwJT3NsbyBDaXR5MRMwEQYDVQQKDApUaGUgUXQgQ0Ex
|
||||
MQ0wCwYDVQQLDARRVENOMREwDwYDVQQDDAhjYTFxdC5pbzElMCMGCSqGSIb3DQEJ
|
||||
ARYWdGltdXIucG9jaGVwdHNvdkBxdC5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAOCs3AV7sDKHJUJcm7a0OqnShIvoB1qv6UcOmlBmUzGl5GzX90Jz
|
||||
7jYJoOPjxjNyRxMOsOReB1ZcSuIAjkdAEfFMaVe6j7qKTJ5ycTVY/fVoxyxsSNuI
|
||||
xOJ6RCEjLHcxONEbkN/xI8LMdVko3m4P10r5GxwrgyPvpa87Yq5+XJ1BPWJyKbD7
|
||||
Tqpn3dvZUj0/POsMUTT7Q7VXOfDlZj58XWAC6ECTqJauhGFMhiwgqOn2Qo1W0QjV
|
||||
DkGqRTdgIAM6Rv2cSRxgnflwW5QZ8kWUV81h/yx4cck/D9TcVxjr3Pvy6aJ/U41u
|
||||
d4XJQgwCj4LJi4msw1S0CvZWmz+2BKxcbRsCAwEAAaNTMFEwHQYDVR0OBBYEFHgX
|
||||
JwJFO7E6pu4tkL08cIK9J0NEMB8GA1UdIwQYMBaAFHgXJwJFO7E6pu4tkL08cIK9
|
||||
J0NEMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADp1kqDRcyVG
|
||||
BdMge+Il10IjbpzzSjAoZiqiw69V99LiHW9ePbxG4AmliE6Za60GE5PCXOLjJh/5
|
||||
efgnIbybbyIOIT9iK4TXWLw2XW+rMY51c0RAxp2h/sc+5CZ0F0I811F5VUHXg2qR
|
||||
U7C2zbzqAimN8TBm6FRe7NFQfqLCrsuFJjSc3obrqKQcpvRwxMk6NpkdoemzqLmY
|
||||
lrBrTaeVbZ4ix3srVPvXRm9TdiC+JuuFmvulMfe+/wwnhb+dwT3JUC+EIq/Uf5Wb
|
||||
g8lvB4ntitL8NLQ2hFGqYuoFNIGs6tRN71ohk+/ONqe9wJhcI9QAruPOvsg+8J0H
|
||||
uGooX7PUNHg=
|
||||
-----END CERTIFICATE-----
|
28
tests/auto/network/ssl/qocsp/certs/ca1.key
Normal file
28
tests/auto/network/ssl/qocsp/certs/ca1.key
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDgrNwFe7AyhyVC
|
||||
XJu2tDqp0oSL6Adar+lHDppQZlMxpeRs1/dCc+42CaDj48YzckcTDrDkXgdWXEri
|
||||
AI5HQBHxTGlXuo+6ikyecnE1WP31aMcsbEjbiMTiekQhIyx3MTjRG5Df8SPCzHVZ
|
||||
KN5uD9dK+RscK4Mj76WvO2KuflydQT1icimw+06qZ93b2VI9PzzrDFE0+0O1Vznw
|
||||
5WY+fF1gAuhAk6iWroRhTIYsIKjp9kKNVtEI1Q5BqkU3YCADOkb9nEkcYJ35cFuU
|
||||
GfJFlFfNYf8seHHJPw/U3FcY69z78umif1ONbneFyUIMAo+CyYuJrMNUtAr2Vps/
|
||||
tgSsXG0bAgMBAAECggEBAL1RCwjXw42gEUZM8KzQS0pD6IpXVrMU3ZWReXhb8Kg6
|
||||
KDOK+3+UXlpMXLUKfj1lgvxM+cNEdBxSIoszerARDc1s3KseufOui4dL2ZbhSQVc
|
||||
Z9BH4lCSe4x3CCeAEvzQjhatirMY51BCpnMdm+fUE07KfwyKobNLQSpZ+Pod4f5i
|
||||
oQbOiZYfRfU2quaWIsVb/a5IiUD0gG0KS9O5wX6VigVeFRpOPHT4YCQ1qds4HqQq
|
||||
PKQtkLq0mo6beXCfXWrJ5Nc0QOIFlgSAHkeRR7zLK8MlaerwZ5YdeJIWuPM9l9H+
|
||||
34FVkHle1rPN6dJf7EPwWxn1PceFe3QYn1GHoiMmXfkCgYEA/U6iQypbLEKLmLbt
|
||||
XTvhV1FVDQM42BX+ATNQ8Wro0ybdyzM+d4271uAUGTF1Zvxndv22p+JOmldWveAR
|
||||
0iVK4mvrs25ACg27Bz3LiUaQB2OyYrj9M7TLgQ47gYEhwgnsSniFyrMcptNyIfW5
|
||||
GoB1N00EKiCvHyWo5LK6kRZt5QcCgYEA4xBOC/Otc9lTp24iSVA8Y7XJ+nlypFtc
|
||||
pehf262jH11wEkWskmc9aP/kpxt9fUrDxf3YIOqITR4mMNn184P1WywHAQF7Adfd
|
||||
3r5YBMVaanuaMsSuAZOJGyvuk2BE6328IKdE+3emndzXuQdDf0X2TUznwdKe9AzZ
|
||||
qadCBLfUpk0CgYAgDKbzIJTQkMrg06RMu5rTVXMRZmr2zDGLLVb8dK5oqO4/G4i3
|
||||
z7MIiOmCFoPoN99PauKFc1jGpm5PL96RXC6RX14/IZ/wpbQYQnVSNR9cD/0uCIHg
|
||||
3OsytP5KcHA5ANBoy78B2o+xe+dg7JozBDXQfWodem0t37Hy3bpFSTU2WQKBgETY
|
||||
qcFn9hydNYcblpvCDz1wXjhq4H7DENlhFseF42LcMuHnbEbLtMwEYrDkXe1CYQ/E
|
||||
QubgFcnELXI8dB2M0jT9qXX9m+1YJXanIgr4R8zngz6HcfcaY8TwUhsvYlZAvmzs
|
||||
KrdQdR2CW4pHkIijjuWrPs3+7aEz0D9nblX94yU1AoGATVCfQOwmEMFHg33luMMt
|
||||
0lTOHsar6g1O5vz0ZPZ1NjJF9Qe3+T7B4n4gq9pLwfi7Ohoa4CDmt0nKmy56dBha
|
||||
5LM8mzw+PaH9a3pP93caS6k/X68TLOp7fwvnzP6HTjtis2sdYzVma6ghEF0zRdQr
|
||||
6nWMI6Kx2kFaNdzKSHzxP5A=
|
||||
-----END PRIVATE KEY-----
|
28
tests/auto/network/ssl/qocsp/certs/infbob.key
Normal file
28
tests/auto/network/ssl/qocsp/certs/infbob.key
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDkF2BuPlkQa3Ox
|
||||
JxnbQ+gy1mAxaGGzfnmGocraxVSKSssX3zSkeIrWB1kW3diOtIZ1jovYftHGsqoB
|
||||
F5k6fN9dr37mFIZnilF6Bq0seYjNUl6I0d7Cf3NJSf7TG5+P+dAyNLN8aXILctY8
|
||||
krlSe4ysb++9xgawt2DYL3I0LBd+W27hd2BlfcmB4g2X3zOasjZM8F5HSBxF5e7f
|
||||
fVaUmCC8S4jdXUQEbUNFk6HufDwDhP1gMtoGKHusWOdI5O6cQAfUUmRLSfi/jWoe
|
||||
KLPafbj7KIcA8+YojOvub2guNpO42h9fc83/gCkkBJhwXNdIQjRUnz6Lu05kDTG9
|
||||
X28gbX9TAgMBAAECggEBAN9xCxVUXJmaOb6ciFblIi3TFm6wS62zw0chbgB8eQH0
|
||||
nRoonYBVWeSrVBnzf7bkoCe/Wb3fFo+o7KOfQ4spUwOK7SxlhPkfZgu9SJ4d/Obu
|
||||
vw8XUTqF8iEkrM6P6/L2DX9xYzcIcSFIARlbvtJPmBJAocHtoRYyvltpt13mp6kt
|
||||
/LVYR4qFAWRpPR6rnjlXEjfrE9taHWgIJEjwMj+IcTjnGiS1rX1T/JNhjRxsRJwU
|
||||
qxqhYmeenNymyUJxS2B806EcG3UAJu63dK61VXN1dtPhS3FqjeR//GRlmy14n7RW
|
||||
ZQAuT9dPB/WzUZVzEcOgTwe/+XsPTSfz7gpaoffgMJECgYEA/43xZRi48Dfp3tdq
|
||||
qwwLf6Ya9pB2zb3XE8MUQhxsrygzL5ngZhmr2m0LgGCf5fXa983G6wzA6sOdpvve
|
||||
jFAlBZYbWaYnvog9QIFcTj0S6PahGTBaR7PSNzK0UzoHYexYVCkyzQl1O2hktazd
|
||||
Cankh/6IlAFkKbUSDqAwc07jNCkCgYEA5H0tNXpcDN6JTgKNe8YHM0GjZB+qGEoL
|
||||
7YZbFlANjO9pOPY6JMQ3+DbOoruIH97CIyVYokuH0qRAfjm5LNiVYECFVFZRnGFb
|
||||
BNPOPAnPJPISDF66zjW0KLMYCykJAHQ4SpHUPcJ6JnfBr76s/xSbNI9qnhpy3QYI
|
||||
ATkqOrP25xsCgYEAy3pjmJGEv5BloM942VSv2yWRFn2UeuELXWrYuIMVbqndh6tH
|
||||
50PNeA+XNtK4vktx3Bl2pzTybnrvDkRBwQsXT0lj4Y/Q2X509uWJb6plYiTtxLah
|
||||
S7I8UUMIHbR4qFmdQvXCw0sikvjeJ2HKZaVml3ntmZs5+5N3GzolGcrYUXECgYEA
|
||||
pPsBnsCoIJ66s7pCIKIfZtI5QT1f20P0EuDVemn5Ls9bwcaAuzV3WGFymKwiISj+
|
||||
MtRviFhTTTROYRYa8Be+3A4ad4gQS4M8bmLlYhKPIJUtlQL9jZHXcR/H9578ofhJ
|
||||
AQcFIkb/XjFQiC58yX4+hxgbGufsEk2dkAyPwm1ZlQsCgYBTjnraJbYSz1v3MQKx
|
||||
fHm9eHki/ODR3lWiCYYnnW3AwRa7AXS4ZiSw78wzkUX2XTJbE6JlEUH4M9DMzr4y
|
||||
QBwKmx+3u+Im4WcZ889jo6XrF0X9mXRmY25+gr2ypTbKZjT8FCYcXIgiOxITLXZh
|
||||
Bmn7KZcsdaPxSFn05ASEanLNqA==
|
||||
-----END PRIVATE KEY-----
|
49
tests/auto/network/ssl/qocsp/certs/infbobchain.crt
Normal file
49
tests/auto/network/ssl/qocsp/certs/infbobchain.crt
Normal file
@ -0,0 +1,49 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjjELMAkGA1UEBhMCTk8x
|
||||
DTALBgNVBAgMBE9zbG8xEjAQBgNVBAcMCU9zbG8gQ2l0eTETMBEGA1UECgwKVGhl
|
||||
IFF0IENBMTENMAsGA1UECwwEUVRDTjERMA8GA1UEAwwIY2ExcXQuaW8xJTAjBgkq
|
||||
hkiG9w0BCQEWFnRpbXVyLnBvY2hlcHRzb3ZAcXQuaW8wHhcNMTgxMTIyMTAyOTM3
|
||||
WhcNMjgxMTE5MTAyOTM3WjCBmDELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8x
|
||||
EjAQBgNVBAcMCU9zbG8gQ2l0eTEkMCIGA1UECgwbVGhlIEluZmFtb3VzIFNuZWFr
|
||||
eSBCb2IgTHRkMQwwCgYDVQQLDANCREExEzARBgNVBAMMCmluZmJvYi5jb20xHTAb
|
||||
BgkqhkiG9w0BCQEWDmJvYkBpbmZib2IuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEA5Bdgbj5ZEGtzsScZ20PoMtZgMWhhs355hqHK2sVUikrLF980
|
||||
pHiK1gdZFt3YjrSGdY6L2H7RxrKqAReZOnzfXa9+5hSGZ4pRegatLHmIzVJeiNHe
|
||||
wn9zSUn+0xufj/nQMjSzfGlyC3LWPJK5UnuMrG/vvcYGsLdg2C9yNCwXfltu4Xdg
|
||||
ZX3JgeINl98zmrI2TPBeR0gcReXu331WlJggvEuI3V1EBG1DRZOh7nw8A4T9YDLa
|
||||
Bih7rFjnSOTunEAH1FJkS0n4v41qHiiz2n24+yiHAPPmKIzr7m9oLjaTuNofX3PN
|
||||
/4ApJASYcFzXSEI0VJ8+i7tOZA0xvV9vIG1/UwIDAQABo3sweTAJBgNVHRMEAjAA
|
||||
MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd
|
||||
BgNVHQ4EFgQUloqk6Iihkkcxp85jAzeUPGVmapkwHwYDVR0jBBgwFoAUeBcnAkU7
|
||||
sTqm7i2QvTxwgr0nQ0QwDQYJKoZIhvcNAQELBQADggEBAGCdYFNskTzMilRtmw+v
|
||||
oJQM3mc6LdYYuADCuh8O/GKaqUnE7V2XnMBYWMN93eeN9VXmK2yAZaQU1J6ruP1S
|
||||
pLMzJ8hbQej+sm+XAHVxAtr34KmEC50gIn1cB/sRKxHMombbNl7EK44puFU7q58P
|
||||
zBz5lTXXTfA954D/ijEMMSDvIZ25me6vrGPMj1LX/wC6CWadSr9IxAO9HQVQQqwv
|
||||
AbbqrCvMSMv633/f1EYU8Q6jhUCTlnin4pXtriOnqi+6MZICaYRCUgV224Rs3OUS
|
||||
jmrbOeoaZUpmOVmuoYXWeexe229G2KGiEIgnSBEk5OLFHCeZ8++WJ5/SLHt8MBLc
|
||||
O0w=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID9DCCAtygAwIBAgIJAMQbE3657KDYMA0GCSqGSIb3DQEBCwUAMIGOMQswCQYD
|
||||
VQQGEwJOTzENMAsGA1UECAwET3NsbzESMBAGA1UEBwwJT3NsbyBDaXR5MRMwEQYD
|
||||
VQQKDApUaGUgUXQgQ0ExMQ0wCwYDVQQLDARRVENOMREwDwYDVQQDDAhjYTFxdC5p
|
||||
bzElMCMGCSqGSIb3DQEJARYWdGltdXIucG9jaGVwdHNvdkBxdC5pbzAeFw0xODEx
|
||||
MjIxMDIxMTNaFw0yODExMTkxMDIxMTNaMIGOMQswCQYDVQQGEwJOTzENMAsGA1UE
|
||||
CAwET3NsbzESMBAGA1UEBwwJT3NsbyBDaXR5MRMwEQYDVQQKDApUaGUgUXQgQ0Ex
|
||||
MQ0wCwYDVQQLDARRVENOMREwDwYDVQQDDAhjYTFxdC5pbzElMCMGCSqGSIb3DQEJ
|
||||
ARYWdGltdXIucG9jaGVwdHNvdkBxdC5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAOCs3AV7sDKHJUJcm7a0OqnShIvoB1qv6UcOmlBmUzGl5GzX90Jz
|
||||
7jYJoOPjxjNyRxMOsOReB1ZcSuIAjkdAEfFMaVe6j7qKTJ5ycTVY/fVoxyxsSNuI
|
||||
xOJ6RCEjLHcxONEbkN/xI8LMdVko3m4P10r5GxwrgyPvpa87Yq5+XJ1BPWJyKbD7
|
||||
Tqpn3dvZUj0/POsMUTT7Q7VXOfDlZj58XWAC6ECTqJauhGFMhiwgqOn2Qo1W0QjV
|
||||
DkGqRTdgIAM6Rv2cSRxgnflwW5QZ8kWUV81h/yx4cck/D9TcVxjr3Pvy6aJ/U41u
|
||||
d4XJQgwCj4LJi4msw1S0CvZWmz+2BKxcbRsCAwEAAaNTMFEwHQYDVR0OBBYEFHgX
|
||||
JwJFO7E6pu4tkL08cIK9J0NEMB8GA1UdIwQYMBaAFHgXJwJFO7E6pu4tkL08cIK9
|
||||
J0NEMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADp1kqDRcyVG
|
||||
BdMge+Il10IjbpzzSjAoZiqiw69V99LiHW9ePbxG4AmliE6Za60GE5PCXOLjJh/5
|
||||
efgnIbybbyIOIT9iK4TXWLw2XW+rMY51c0RAxp2h/sc+5CZ0F0I811F5VUHXg2qR
|
||||
U7C2zbzqAimN8TBm6FRe7NFQfqLCrsuFJjSc3obrqKQcpvRwxMk6NpkdoemzqLmY
|
||||
lrBrTaeVbZ4ix3srVPvXRm9TdiC+JuuFmvulMfe+/wwnhb+dwT3JUC+EIq/Uf5Wb
|
||||
g8lvB4ntitL8NLQ2hFGqYuoFNIGs6tRN71ohk+/ONqe9wJhcI9QAruPOvsg+8J0H
|
||||
uGooX7PUNHg=
|
||||
-----END CERTIFICATE-----
|
28
tests/auto/network/ssl/qocsp/certs/ss1-private.key
Normal file
28
tests/auto/network/ssl/qocsp/certs/ss1-private.key
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC4bXcfIjweShLx
|
||||
6jBTKu/i5sXmlwTH9Z4PTzQ1VteKyEIDlnW5ocVWqRgBrvz3NlTFkDKkQXshkXyE
|
||||
JyVZFbAPCfGsroZVISpFhUmJbPMBNn3SyGEU+sxWIpOZOKmG5tel6B4Bt5TWsRHL
|
||||
mtU8Pv/APsz+i9JhgE25ksGhx16MqvdRv/xNGleF8qe+hDOeiNF3/lNv2hYb/MvD
|
||||
1F73FBoDVnqty/VXXOJFb7elLE4ArXsTN/hip42Lbl1guYvnqnTZFhCHwMzRu4qc
|
||||
3FTlemumfJpacpRnqVw2TURA5SdpTp9NYIxygEGNY201meNEjAEyg8GeFkAgu99R
|
||||
LPQT+rTNAgMBAAECggEAPQEIfCXo2OQLrDWY0onLW7SWFZYyoKngJJRAYrxdA60G
|
||||
GQW13zdhfS7ln/jv+B3ioI74EVkPj6T+GQCR3AvOdssFQ+dey93yi5hxIKIHJ4mM
|
||||
ySI66qOi34MEa5RQjyzgfCJxeoPtGa7sgfqvOgRkuISNbk11w4abLx0aK5c08TY0
|
||||
JdeoWWhATaFZXl782Aw2FwGPTwOIf7GB09BJS3qUqlMT9fowLmWO10jOKkNtvcnT
|
||||
2mAqT5cdZG1ffT5+f0JETPCbBPhhyE7VyYEVQfqTkRnEoz3hcZvjx91jD527+CSL
|
||||
Qhg7zZu2oakyJQvpHETZ6cgrs7uDEiol7ARANezwyQKBgQDmapxV/qIOd5WFDVXw
|
||||
lGt+dsELBBdMhvzr4A9eZdIZiXu48rdFG0XoECo5BKpXa1+ISr2od0U0YODrJrws
|
||||
OHxHhlxGjJFs8kFteUPHyEZv6/rvkbA+xc0Uw04NnDRHBLK8VvX7MBWfvTqLN4bK
|
||||
sZsMblscRBtEpFpN1fiJgnNASwKBgQDM56lBugtueBV9M4C/JF2is96d14ue3Y4i
|
||||
SgMnHY18D3ru+KDuxPYoIs5Yos2vDWK2k8754WZ+WNXokjRoYPiFbeBPpI9NudJs
|
||||
BUJz/sLJHjs3a4HrQs3hCuufczNxq9wQnALQHCMEqeBUTYCu/1+zYgwAu3Z/R8rJ
|
||||
jKgexl+gRwKBgGrLCNCWpze7VzKGvsk1kSjZE5nueHoAqqMMgzMGUD2DyjMrU6QV
|
||||
Au6O53Lr5aOE4Y9CzOqS9SFUsYprtpVsTLW94XDVX+W11ntN1At5mKPxJKn6xUwi
|
||||
022HI9sNBfHQjKLcTz/vxmX2B3dU8gVqEenOEC5mppjG8A/ZV0ssigxHAoGAfGsG
|
||||
OSSwoElGMxm8yVNZj9vMBufEnZhGH8f1FiE5seTsboKFpbXvCfvoc6WXYv2rvNUP
|
||||
TmdxBrMGYAu2ytJm1Q4cr/9qDHYSsQiYizpcKCa1KjebUbDktgsde1pGGHWUUHmK
|
||||
s7cCBGjqEAZnZtslzxRv2Vn639pF5hAEXXtywS0CgYAUIjhp43qgtbQdZMX7xbVR
|
||||
lT26aq7NguCtt7njpgkhqc0HThb3I8ImrhNSDcS0/T9dPU70vt0ceruyRXmwX5hA
|
||||
l28i5GzF5ufaRQdcsSR9u+P67nD5sTZBesbejXFySis5EC/97A4XZvkSfY4DQSZ+
|
||||
u8JJPZUlb2kGAHRpmxvpDA==
|
||||
-----END PRIVATE KEY-----
|
25
tests/auto/network/ssl/qocsp/certs/ss1.crt
Normal file
25
tests/auto/network/ssl/qocsp/certs/ss1.crt
Normal file
@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEKzCCAxOgAwIBAgIJAOO/b5uLSmT8MA0GCSqGSIb3DQEBBQUAMIGqMQswCQYD
|
||||
VQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzESMBAGA1UECgwJ
|
||||
VGhlIFF0IENBMScwJQYDVQQLDB5SJkQgKGZha2UgY2VydGlmaWNhdGVzIGlzc3Vl
|
||||
cikxGTAXBgNVBAMMEFRpbXVyIFBvY2hlcHRzb3YxJTAjBgkqhkiG9w0BCQEWFnRp
|
||||
bXVyLnBvY2hlcHRzb3ZAcXQuaW8wIBcNMTgxMTE3MDUxNDA1WhgPMjExODEwMjQw
|
||||
NTE0MDVaMIGqMQswCQYDVQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwE
|
||||
T3NsbzESMBAGA1UECgwJVGhlIFF0IENBMScwJQYDVQQLDB5SJkQgKGZha2UgY2Vy
|
||||
dGlmaWNhdGVzIGlzc3VlcikxGTAXBgNVBAMMEFRpbXVyIFBvY2hlcHRzb3YxJTAj
|
||||
BgkqhkiG9w0BCQEWFnRpbXVyLnBvY2hlcHRzb3ZAcXQuaW8wggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQC4bXcfIjweShLx6jBTKu/i5sXmlwTH9Z4PTzQ1
|
||||
VteKyEIDlnW5ocVWqRgBrvz3NlTFkDKkQXshkXyEJyVZFbAPCfGsroZVISpFhUmJ
|
||||
bPMBNn3SyGEU+sxWIpOZOKmG5tel6B4Bt5TWsRHLmtU8Pv/APsz+i9JhgE25ksGh
|
||||
x16MqvdRv/xNGleF8qe+hDOeiNF3/lNv2hYb/MvD1F73FBoDVnqty/VXXOJFb7el
|
||||
LE4ArXsTN/hip42Lbl1guYvnqnTZFhCHwMzRu4qc3FTlemumfJpacpRnqVw2TURA
|
||||
5SdpTp9NYIxygEGNY201meNEjAEyg8GeFkAgu99RLPQT+rTNAgMBAAGjUDBOMB0G
|
||||
A1UdDgQWBBSyHPlJr6BrpwMY7Sxg2R3CpQR7UzAfBgNVHSMEGDAWgBSyHPlJr6Br
|
||||
pwMY7Sxg2R3CpQR7UzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBD
|
||||
o86xp1WwvX6mYzF94ifZlkq1aDN6/njj2B9fvJCtygfqq6b9BrQJ0hNeqRh8OaIh
|
||||
v2YmjbdUaoYguHmUxL+SeS67Sp8QBoSwdU5x0i8ygrigBrbb3myNqN6hGvpGy9E0
|
||||
B8PnVDt9DaOCunaMyGNPMLNPVGYULmberGtxV9wilcH4Q6WZrk9IhuyfqeBZtBYM
|
||||
IcjV3OKdUv/ggu2IZSN7njKcgr+uyPt0Ymo9GozJSTdnN/E4hsRgzcgzCMf2fxzj
|
||||
nGcsDRQ4L1R8p1zDlduxmmk42zGCGz3duFX7dijAxJWirS8Zsea4aooLgDQYT/zI
|
||||
8hKd3KC3knLhPcxFKiUg
|
||||
-----END CERTIFICATE-----
|
814
tests/auto/network/ssl/qocsp/tst_qocsp.cpp
Normal file
814
tests/auto/network/ssl/qocsp/tst_qocsp.cpp
Normal file
@ -0,0 +1,814 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
#include <QTestEventLoop>
|
||||
|
||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||
|
||||
#include "../shared/qopenssl_symbols.h"
|
||||
|
||||
#include <QtNetwork/qsslcertificate.h>
|
||||
#include <QtNetwork/qocspresponse.h>
|
||||
#include <QtNetwork/qtcpserver.h>
|
||||
#include <QtNetwork/qsslerror.h>
|
||||
#include <QtNetwork/qsslkey.h>
|
||||
#include <QtNetwork/qssl.h>
|
||||
|
||||
#include <QtCore/qsharedpointer.h>
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qfileinfo.h>
|
||||
#include <QtCore/qstring.h>
|
||||
#include <QtCore/qfile.h>
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qdir.h>
|
||||
|
||||
#include <openssl/ocsp.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
// NOTE: the word 'subject' in the code below means the subject of a status request,
|
||||
// so in general it's our peer's certificate we are asking about.
|
||||
|
||||
using SslError = QT_PREPEND_NAMESPACE(QSslError);
|
||||
using VectorOfErrors = QT_PREPEND_NAMESPACE(QList<SslError>);
|
||||
using Latin1String = QT_PREPEND_NAMESPACE(QLatin1String);
|
||||
|
||||
Q_DECLARE_METATYPE(SslError)
|
||||
Q_DECLARE_METATYPE(Latin1String)
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
using OcspResponse = QSharedPointer<OCSP_RESPONSE>;
|
||||
using BasicResponse = QSharedPointer<OCSP_BASICRESP>;
|
||||
using SingleResponse = QSharedPointer<OCSP_SINGLERESP>;
|
||||
using CertId = QSharedPointer<OCSP_CERTID>;
|
||||
using EvpKey = QSharedPointer<EVP_PKEY>;
|
||||
using Asn1Time = QSharedPointer<ASN1_TIME>;
|
||||
using CertificateChain = QList<QSslCertificate>;
|
||||
using NativeX509Ptr = X509 *;
|
||||
|
||||
class X509Stack {
|
||||
public:
|
||||
explicit X509Stack(const QList<QSslCertificate> &chain);
|
||||
|
||||
~X509Stack();
|
||||
|
||||
int size() const;
|
||||
X509 *operator[](int index) const;
|
||||
operator STACK_OF(X509) *() const;
|
||||
|
||||
private:
|
||||
OPENSSL_STACK *stack = nullptr;
|
||||
|
||||
Q_DISABLE_COPY(X509Stack)
|
||||
};
|
||||
|
||||
X509Stack::X509Stack(const QList<QSslCertificate> &chain)
|
||||
{
|
||||
if (!chain.size())
|
||||
return;
|
||||
|
||||
stack = q_OPENSSL_sk_new_null();
|
||||
if (!stack)
|
||||
return;
|
||||
|
||||
for (const QSslCertificate &cert : chain) {
|
||||
X509 *nativeCert = NativeX509Ptr(cert.handle());
|
||||
if (!nativeCert)
|
||||
continue;
|
||||
q_OPENSSL_sk_push(stack, nativeCert);
|
||||
q_X509_up_ref(nativeCert);
|
||||
}
|
||||
}
|
||||
|
||||
X509Stack::~X509Stack()
|
||||
{
|
||||
if (stack)
|
||||
q_OPENSSL_sk_pop_free(stack, reinterpret_cast<void(*)(void*)>(q_X509_free));
|
||||
}
|
||||
|
||||
int X509Stack::size() const
|
||||
{
|
||||
if (stack)
|
||||
return q_OPENSSL_sk_num(stack);
|
||||
return 0;
|
||||
}
|
||||
|
||||
X509 *X509Stack::operator[](int index) const
|
||||
{
|
||||
return NativeX509Ptr(q_OPENSSL_sk_value(stack, index));
|
||||
}
|
||||
|
||||
X509Stack::operator STACK_OF(X509) *() const
|
||||
{
|
||||
return reinterpret_cast<STACK_OF(X509)*>(stack);
|
||||
}
|
||||
|
||||
struct OcspTimeStamp
|
||||
{
|
||||
OcspTimeStamp() = default;
|
||||
OcspTimeStamp(long secondsBeforeNow, long secondsAfterNow);
|
||||
|
||||
static Asn1Time timeToAsn1Time(long adjustment);
|
||||
|
||||
Asn1Time thisUpdate;
|
||||
Asn1Time nextUpdate;
|
||||
};
|
||||
|
||||
OcspTimeStamp::OcspTimeStamp(long secondsBeforeNow, long secondsAfterNow)
|
||||
{
|
||||
Asn1Time start = timeToAsn1Time(secondsBeforeNow);
|
||||
Asn1Time end = timeToAsn1Time(secondsAfterNow);
|
||||
if (start.data() && end.data()) {
|
||||
thisUpdate.swap(start);
|
||||
nextUpdate.swap(end);
|
||||
}
|
||||
}
|
||||
|
||||
Asn1Time OcspTimeStamp::timeToAsn1Time(long adjustment)
|
||||
{
|
||||
if (ASN1_TIME *adjusted = q_X509_gmtime_adj(nullptr, adjustment))
|
||||
return Asn1Time(adjusted, q_ASN1_TIME_free);
|
||||
return Asn1Time{};
|
||||
}
|
||||
|
||||
struct OcspResponder
|
||||
{
|
||||
OcspResponder(const OcspTimeStamp &stamp, const CertificateChain &subjs,
|
||||
const CertificateChain &respChain, const QSslKey &respPKey);
|
||||
|
||||
QByteArray buildResponse(int responseStatus, int certificateStatus) const;
|
||||
static EvpKey privateKeyToEVP_PKEY(const QSslKey &privateKey);
|
||||
static CertId certificateToCertId(X509 *subject, X509 *issuer);
|
||||
static QByteArray responseToDer(OCSP_RESPONSE *response);
|
||||
|
||||
OcspTimeStamp timeStamp;
|
||||
// Plural, we can send a 'wrong' BasicResponse containing more than
|
||||
// 1 SingleResponse.
|
||||
X509Stack subjects;
|
||||
X509Stack responderChain;
|
||||
QSslKey responderKey;
|
||||
};
|
||||
|
||||
OcspResponder::OcspResponder(const OcspTimeStamp &stamp, const CertificateChain &subjs,
|
||||
const CertificateChain &respChain, const QSslKey &respPKey)
|
||||
: timeStamp(stamp),
|
||||
subjects(subjs),
|
||||
responderChain(respChain),
|
||||
responderKey(respPKey)
|
||||
{
|
||||
}
|
||||
|
||||
QByteArray OcspResponder::buildResponse(int responseStatus, int certificateStatus) const
|
||||
{
|
||||
if (responseStatus != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
|
||||
OCSP_RESPONSE *response = q_OCSP_response_create(responseStatus, nullptr);
|
||||
if (!response)
|
||||
return {};
|
||||
const OcspResponse rGuard(response, q_OCSP_RESPONSE_free);
|
||||
return responseToDer(response);
|
||||
}
|
||||
|
||||
Q_ASSERT(subjects.size() && responderChain.size() && responderKey.handle());
|
||||
|
||||
const EvpKey nativeKey = privateKeyToEVP_PKEY(responderKey);
|
||||
if (!nativeKey.data())
|
||||
return {};
|
||||
|
||||
OCSP_BASICRESP *basicResponse = q_OCSP_BASICRESP_new();
|
||||
if (!basicResponse)
|
||||
return {};
|
||||
const BasicResponse brGuard(basicResponse, q_OCSP_BASICRESP_free);
|
||||
|
||||
for (int i = 0, e = subjects.size(); i < e; ++i) {
|
||||
X509 *subject = subjects[i];
|
||||
Q_ASSERT(subject);
|
||||
CertId certId = certificateToCertId(subject, responderChain[0]);
|
||||
if (!certId.data())
|
||||
return {};
|
||||
|
||||
// NOTE: we do not own this 'singleResponse':
|
||||
ASN1_TIME *revisionTime = certificateStatus == V_OCSP_CERTSTATUS_REVOKED ?
|
||||
timeStamp.thisUpdate.data() : nullptr;
|
||||
|
||||
if (!q_OCSP_basic_add1_status(basicResponse, certId.data(), certificateStatus, 0, revisionTime,
|
||||
timeStamp.thisUpdate.data(), timeStamp.nextUpdate.data())) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (q_OCSP_basic_sign(basicResponse, responderChain[0], nativeKey.data(), q_EVP_sha1(),
|
||||
responderChain, 0) != 1) {
|
||||
return {};
|
||||
}
|
||||
|
||||
OCSP_RESPONSE *ocspResponse = q_OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, basicResponse);
|
||||
if (!ocspResponse)
|
||||
return {};
|
||||
const OcspResponse rGuard(ocspResponse, q_OCSP_RESPONSE_free);
|
||||
return responseToDer(ocspResponse);
|
||||
}
|
||||
|
||||
EvpKey OcspResponder::privateKeyToEVP_PKEY(const QSslKey &privateKey)
|
||||
{
|
||||
const EvpKey nullKey;
|
||||
if (privateKey.isNull() || privateKey.algorithm() != QSsl::Rsa) {
|
||||
// We use only RSA keys in this auto-test, since we test OCSP only,
|
||||
// not handshake/TLS in general.
|
||||
return nullKey;
|
||||
}
|
||||
|
||||
EVP_PKEY *nativeKey = q_EVP_PKEY_new();
|
||||
if (!nativeKey)
|
||||
return nullKey;
|
||||
|
||||
const EvpKey keyGuard(nativeKey, q_EVP_PKEY_free);
|
||||
if (!q_EVP_PKEY_set1_RSA(nativeKey, reinterpret_cast<RSA *>(privateKey.handle())))
|
||||
return nullKey;
|
||||
|
||||
return keyGuard;
|
||||
}
|
||||
|
||||
CertId OcspResponder::certificateToCertId(X509 *subject, X509 *issuer)
|
||||
{
|
||||
const CertId nullId;
|
||||
if (!subject || !issuer)
|
||||
return nullId;
|
||||
|
||||
const EVP_MD *digest = q_EVP_sha1();
|
||||
if (!digest)
|
||||
return nullId;
|
||||
|
||||
OCSP_CERTID *certId = q_OCSP_cert_to_id(digest, subject, issuer);
|
||||
if (!certId)
|
||||
return nullId;
|
||||
|
||||
return CertId(certId, q_OCSP_CERTID_free);
|
||||
}
|
||||
|
||||
QByteArray OcspResponder::responseToDer(OCSP_RESPONSE *response)
|
||||
{
|
||||
if (!response)
|
||||
return {};
|
||||
|
||||
const int derSize = q_i2d_OCSP_RESPONSE(response, nullptr);
|
||||
if (derSize <= 0)
|
||||
return {};
|
||||
|
||||
QByteArray derData(derSize, Qt::Uninitialized);
|
||||
unsigned char *pData = reinterpret_cast<unsigned char *>(derData.data());
|
||||
const int serializedSize = q_i2d_OCSP_RESPONSE(response, &pData);
|
||||
if (serializedSize != derSize)
|
||||
return {};
|
||||
|
||||
return derData;
|
||||
}
|
||||
|
||||
// The QTcpServer capable of sending OCSP status responses.
|
||||
class OcspServer : public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OcspServer(const CertificateChain &serverChain, const QSslKey &privateKey);
|
||||
|
||||
void configureResponse(const QByteArray &responseDer);
|
||||
QString hostName() const;
|
||||
QString peerVerifyName() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void internalServerError();
|
||||
|
||||
private:
|
||||
void incomingConnection(qintptr descriptor) override;
|
||||
|
||||
public:
|
||||
QSslConfiguration serverConfig;
|
||||
QSslSocket serverSocket;
|
||||
};
|
||||
|
||||
OcspServer::OcspServer(const CertificateChain &serverChain, const QSslKey &privateKey)
|
||||
{
|
||||
Q_ASSERT(serverChain.size());
|
||||
Q_ASSERT(!privateKey.isNull());
|
||||
|
||||
serverConfig = QSslConfiguration::defaultConfiguration();
|
||||
serverConfig.setLocalCertificateChain(serverChain);
|
||||
serverConfig.setPrivateKey(privateKey);
|
||||
}
|
||||
|
||||
void OcspServer::configureResponse(const QByteArray &responseDer)
|
||||
{
|
||||
serverConfig.setBackendConfigurationOption("Qt-OCSP-response", responseDer);
|
||||
}
|
||||
|
||||
QString OcspServer::hostName() const
|
||||
{
|
||||
// It's 'name' and not 'address' to be consistent with QSslSocket's naming style,
|
||||
// where it's connectToHostEncrypted(hostName, ...)
|
||||
const QHostAddress &addr = serverAddress();
|
||||
if (addr == QHostAddress::Any || addr == QHostAddress::AnyIPv4)
|
||||
return QStringLiteral("127.0.0.1");
|
||||
if (addr == QHostAddress::AnyIPv6)
|
||||
return QStringLiteral("::1");
|
||||
return addr.toString();
|
||||
}
|
||||
|
||||
QString OcspServer::peerVerifyName() const
|
||||
{
|
||||
const CertificateChain &localChain = serverConfig.localCertificateChain();
|
||||
if (localChain.isEmpty())
|
||||
return {};
|
||||
const auto cert = localChain.first();
|
||||
if (cert.isNull())
|
||||
return {};
|
||||
|
||||
const QStringList &names = cert.subjectInfo(QSslCertificate::CommonName);
|
||||
return names.isEmpty() ? QString{} : names.first();
|
||||
}
|
||||
|
||||
void OcspServer::incomingConnection(qintptr socketDescriptor)
|
||||
{
|
||||
close();
|
||||
|
||||
if (!serverSocket.setSocketDescriptor(socketDescriptor)) {
|
||||
emit internalServerError();
|
||||
return;
|
||||
}
|
||||
|
||||
serverSocket.setSslConfiguration(serverConfig);
|
||||
// Since we test a client, not a server, we don't care about any
|
||||
// possible errors on the server (QAbstractSocket or QSslSocket-related).
|
||||
// Thus, we don't connect to any error signal.
|
||||
serverSocket.startServerEncryption();
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
class tst_QOcsp : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
void initTestCase();
|
||||
|
||||
private slots:
|
||||
void connectSelfSigned();
|
||||
void badStatus_data();
|
||||
void badStatus();
|
||||
void multipleSingleResponses();
|
||||
void malformedResponse();
|
||||
void expiredResponse_data();
|
||||
void expiredResponse();
|
||||
void noNextUpdate();
|
||||
void wrongCertificateInResponse_data();
|
||||
void wrongCertificateInResponse();
|
||||
void untrustedResponder();
|
||||
|
||||
// OCSPTODO: more tests in future ...
|
||||
|
||||
private:
|
||||
void setupOcspClient(QSslSocket &clientSocket, const CertificateChain &trustedCAs,
|
||||
const QString &peerName);
|
||||
bool containsOcspErrors(const QList<QSslError> &errorsFound) const;
|
||||
static bool containsError(const QList<QSslError> &errors, QSslError::SslError code);
|
||||
static QByteArray goodResponse(const CertificateChain &subject, const CertificateChain &responder,
|
||||
const QSslKey &privateKey, long beforeNow = -1000, long afterNow = 1000);
|
||||
static bool loadPrivateKey(const QString &keyName, QSslKey &key);
|
||||
static CertificateChain issuerToChain(const CertificateChain &chain);
|
||||
static CertificateChain subjectToChain(const CertificateChain &chain);
|
||||
|
||||
static QString certDirPath;
|
||||
|
||||
void (QSslSocket::*tlsErrorsSignal)(const QList<QSslError> &) = &QSslSocket::sslErrors;
|
||||
void (QTestEventLoop::*exitLoopSlot)() = &QTestEventLoop::exitLoop;
|
||||
|
||||
const int handshakeTimeoutMS = 500;
|
||||
QTestEventLoop loop;
|
||||
|
||||
std::vector<QSslError::SslError> ocspErrorCodes = {QSslError::OcspNoResponseFound,
|
||||
QSslError::OcspMalformedRequest,
|
||||
QSslError::OcspMalformedResponse,
|
||||
QSslError::OcspInternalError,
|
||||
QSslError::OcspTryLater,
|
||||
QSslError::OcspSigRequred,
|
||||
QSslError::OcspUnauthorized,
|
||||
QSslError::OcspResponseCannotBeTrusted,
|
||||
QSslError::OcspResponseCertIdUnknown,
|
||||
QSslError::OcspResponseExpired,
|
||||
QSslError::OcspStatusUnknown};
|
||||
};
|
||||
|
||||
#define QCOMPARE_SINGLE_ERROR(sslSocket, expectedError) \
|
||||
const auto &tlsErrors = sslSocket.sslHandshakeErrors(); \
|
||||
QCOMPARE(tlsErrors.size(), 1); \
|
||||
QCOMPARE(tlsErrors[0].error(), expectedError)
|
||||
|
||||
#define QVERIFY_HANDSHAKE_WITHOUT_ERRORS(sslSocket) \
|
||||
QVERIFY(sslSocket.isEncrypted()); \
|
||||
QCOMPARE(sslSocket.state(), QAbstractSocket::ConnectedState); \
|
||||
QVERIFY(sslSocket.sslHandshakeErrors().isEmpty())
|
||||
|
||||
#define QDECLARE_CHAIN(object, chainFileName) \
|
||||
CertificateChain object = QSslCertificate::fromPath(certDirPath + QLatin1String(chainFileName)); \
|
||||
QVERIFY(object.size())
|
||||
|
||||
#define QDECLARE_PRIVATE_KEY(key, keyFileName) \
|
||||
QSslKey key; \
|
||||
QVERIFY(loadPrivateKey(QLatin1String(keyFileName), key))
|
||||
|
||||
QString tst_QOcsp::certDirPath;
|
||||
|
||||
void tst_QOcsp::initTestCase()
|
||||
{
|
||||
// I'm not testing feature here, I need 'openssl', since the test
|
||||
// is very OpenSSL-oriented:
|
||||
if (QSslSocket::activeBackend() != QStringLiteral("openssl"))
|
||||
QSKIP("This test requires the OpenSSL backend");
|
||||
|
||||
if (!qt_auto_test_resolve_OpenSSL_symbols())
|
||||
QSKIP("Failed to resolve OpenSSL symbols required by this test");
|
||||
|
||||
certDirPath = QFileInfo(QFINDTESTDATA("certs")).absolutePath();
|
||||
QVERIFY(certDirPath.size() > 0);
|
||||
certDirPath += QDir::separator() + QStringLiteral("certs") + QDir::separator();
|
||||
}
|
||||
|
||||
void tst_QOcsp::connectSelfSigned()
|
||||
{
|
||||
// This test may look a bit confusing, since we have essentially 1
|
||||
// self-signed certificate, which we trust for the purpose of this test,
|
||||
// but we also request its (the certificate's) status and then we sign
|
||||
// the status response using the same certificate and the corresponding
|
||||
// private key. Anyway, we test the very basic things here: we send
|
||||
// an OCSP status request, we verify the response (if server has sent it),
|
||||
// and detect errors (if any).
|
||||
QDECLARE_CHAIN(subjectChain, "ss1.crt");
|
||||
QDECLARE_CHAIN(responderChain, "ss1.crt");
|
||||
QDECLARE_PRIVATE_KEY(privateKey, "ss1-private.key");
|
||||
{
|
||||
// This server ignores our status request:
|
||||
const QSslError::SslError expectedError = QSslError::OcspNoResponseFound;
|
||||
|
||||
OcspServer server(subjectChain, privateKey);
|
||||
QVERIFY(server.listen());
|
||||
connect(&server, &OcspServer::internalServerError, &loop, exitLoopSlot);
|
||||
|
||||
QSslSocket clientSocket;
|
||||
QSslConfiguration clientConfig = QSslConfiguration::defaultConfiguration();
|
||||
auto roots = clientConfig.caCertificates();
|
||||
setupOcspClient(clientSocket, issuerToChain(subjectChain), server.peerVerifyName());
|
||||
clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort());
|
||||
loop.enterLoopMSecs(handshakeTimeoutMS);
|
||||
|
||||
QVERIFY(!clientSocket.isEncrypted());
|
||||
QCOMPARE_SINGLE_ERROR(clientSocket, expectedError);
|
||||
}
|
||||
{
|
||||
// Now the server will send a valid 'status: good' response.
|
||||
OcspServer server(subjectChain, privateKey);
|
||||
const QByteArray responseData(goodResponse(subjectChain, responderChain, privateKey));
|
||||
QVERIFY(responseData.size());
|
||||
server.configureResponse(responseData);
|
||||
QVERIFY(server.listen());
|
||||
|
||||
QSslSocket clientSocket;
|
||||
setupOcspClient(clientSocket, issuerToChain(subjectChain), server.peerVerifyName());
|
||||
clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort());
|
||||
loop.enterLoopMSecs(handshakeTimeoutMS);
|
||||
|
||||
QVERIFY_HANDSHAKE_WITHOUT_ERRORS(clientSocket);
|
||||
|
||||
const auto responses = clientSocket.ocspResponses();
|
||||
QCOMPARE(responses.size(), 1);
|
||||
const auto &response = responses.at(0);
|
||||
QVERIFY(response != QOcspResponse());
|
||||
const auto copy = response;
|
||||
QCOMPARE(copy, response);
|
||||
QVERIFY(qHash(response, 0) != 0);
|
||||
|
||||
QCOMPARE(response.revocationReason(), QOcspRevocationReason::None);
|
||||
QCOMPARE(response.certificateStatus(), QOcspCertificateStatus::Good);
|
||||
QCOMPARE(response.subject(), clientSocket.peerCertificate());
|
||||
QCOMPARE(response.responder(), clientSocket.peerCertificate());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QOcsp::badStatus_data()
|
||||
{
|
||||
QTest::addColumn<int>("responseStatus");
|
||||
QTest::addColumn<int>("certificateStatus");
|
||||
QTest::addColumn<QSslError>("expectedError");
|
||||
|
||||
QTest::addRow("malformed-request") << OCSP_RESPONSE_STATUS_MALFORMEDREQUEST << 1 << QSslError(QSslError::OcspMalformedRequest);
|
||||
QTest::addRow("internal-error") << OCSP_RESPONSE_STATUS_INTERNALERROR << 2 << QSslError(QSslError::OcspInternalError);
|
||||
QTest::addRow("try-later") << OCSP_RESPONSE_STATUS_TRYLATER << 3 << QSslError(QSslError::OcspTryLater);
|
||||
QTest::addRow("signed-request-require") << OCSP_RESPONSE_STATUS_SIGREQUIRED << 2 << QSslError(QSslError::OcspSigRequred);
|
||||
QTest::addRow("unauthorized-request") << OCSP_RESPONSE_STATUS_UNAUTHORIZED << 1 <<QSslError(QSslError::OcspUnauthorized);
|
||||
|
||||
QTest::addRow("certificate-revoked") << OCSP_RESPONSE_STATUS_SUCCESSFUL << V_OCSP_CERTSTATUS_REVOKED
|
||||
<< QSslError(QSslError::CertificateRevoked);
|
||||
QTest::addRow("status-unknown") << OCSP_RESPONSE_STATUS_SUCCESSFUL << V_OCSP_CERTSTATUS_UNKNOWN
|
||||
<< QSslError(QSslError::OcspStatusUnknown);
|
||||
}
|
||||
|
||||
void tst_QOcsp::badStatus()
|
||||
{
|
||||
// This test works with two types of 'bad' responses:
|
||||
// 1. 'Error messages' (the response's status is anything but SUCCESSFUL,
|
||||
// no information about the certificate itself, no signature);
|
||||
// 2. 'REVOKED' or 'UNKNOWN' status for a certificate in question.
|
||||
QFETCH(const int, responseStatus);
|
||||
QFETCH(const int, certificateStatus);
|
||||
QFETCH(const QSslError, expectedError);
|
||||
|
||||
QDECLARE_CHAIN(subjectChain, "infbobchain.crt");
|
||||
QCOMPARE(subjectChain.size(), 2);
|
||||
QDECLARE_CHAIN(responderChain, "ca1.crt");
|
||||
QDECLARE_PRIVATE_KEY(subjPrivateKey, "infbob.key");
|
||||
QDECLARE_PRIVATE_KEY(respPrivateKey, "ca1.key");
|
||||
|
||||
OcspServer server(subjectChain, subjPrivateKey);
|
||||
const OcspTimeStamp stamp(-1000, 1000);
|
||||
OcspResponder builder(stamp, subjectToChain(subjectChain), responderChain, respPrivateKey);
|
||||
const QByteArray response(builder.buildResponse(responseStatus, certificateStatus));
|
||||
QVERIFY(response.size());
|
||||
server.configureResponse(response);
|
||||
QVERIFY(server.listen());
|
||||
connect(&server, &OcspServer::internalServerError, &loop, exitLoopSlot);
|
||||
|
||||
QSslSocket clientSocket;
|
||||
setupOcspClient(clientSocket, issuerToChain(subjectChain), server.peerVerifyName());
|
||||
clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort());
|
||||
loop.enterLoopMSecs(handshakeTimeoutMS);
|
||||
|
||||
QVERIFY(!clientSocket.isEncrypted());
|
||||
QCOMPARE_SINGLE_ERROR(clientSocket, expectedError.error());
|
||||
}
|
||||
|
||||
void tst_QOcsp::multipleSingleResponses()
|
||||
{
|
||||
// We handle a response with more than one SingleResponse as malformed:
|
||||
const QSslError::SslError expectedError = QSslError::OcspMalformedResponse;
|
||||
|
||||
// Here we use subjectChain only to generate a response, the server
|
||||
// is configured with the responder chain (it's the same cert after all).
|
||||
QDECLARE_CHAIN(subjectChain, "ss1.crt");
|
||||
QDECLARE_CHAIN(responderChain, "ss1.crt");
|
||||
QDECLARE_PRIVATE_KEY(privateKey, "ss1-private.key");
|
||||
|
||||
// Let's have more than 1 certificate in a chain:
|
||||
subjectChain.append(subjectChain[0]);
|
||||
|
||||
OcspServer server(responderChain, privateKey);
|
||||
// Generate a BasicOCSPResponse containing 2 SingleResponses:
|
||||
const QByteArray response(goodResponse(subjectChain, responderChain, privateKey));
|
||||
QVERIFY(response.size());
|
||||
server.configureResponse(response);
|
||||
QVERIFY(server.listen());
|
||||
connect(&server, &OcspServer::internalServerError, &loop, exitLoopSlot);
|
||||
|
||||
QSslSocket clientSocket;
|
||||
setupOcspClient(clientSocket, issuerToChain(responderChain), server.peerVerifyName());
|
||||
clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort());
|
||||
loop.enterLoopMSecs(handshakeTimeoutMS);
|
||||
|
||||
QVERIFY(!clientSocket.isEncrypted());
|
||||
QCOMPARE_SINGLE_ERROR(clientSocket, expectedError);
|
||||
}
|
||||
|
||||
void tst_QOcsp::malformedResponse()
|
||||
{
|
||||
QDECLARE_CHAIN(serverChain, "ss1.crt");
|
||||
QDECLARE_PRIVATE_KEY(privateKey, "ss1-private.key");
|
||||
|
||||
OcspServer server(serverChain, privateKey);
|
||||
// Let's send some arbitrary bytes instead of DER and see what happens next:
|
||||
server.configureResponse("Sure, you can trust me, this cert was not revoked (I don't say it was issued at all)!");
|
||||
QVERIFY(server.listen());
|
||||
connect(&server, &OcspServer::internalServerError, &loop, exitLoopSlot);
|
||||
|
||||
QSslSocket clientSocket;
|
||||
setupOcspClient(clientSocket, issuerToChain(serverChain), server.peerVerifyName());
|
||||
clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort());
|
||||
loop.enterLoopMSecs(handshakeTimeoutMS);
|
||||
|
||||
QVERIFY(!clientSocket.isEncrypted());
|
||||
QCOMPARE(clientSocket.error(), QAbstractSocket::SslHandshakeFailedError);
|
||||
}
|
||||
|
||||
void tst_QOcsp::expiredResponse_data()
|
||||
{
|
||||
QTest::addColumn<long>("beforeNow");
|
||||
QTest::addColumn<long>("afterNow");
|
||||
|
||||
QTest::addRow("expired") << -2000L << -1000L;
|
||||
QTest::addRow("not-valid-yet") << 5000L << 10000L;
|
||||
QTest::addRow("next-before-this") << -1000L << -2000L;
|
||||
}
|
||||
|
||||
void tst_QOcsp::expiredResponse()
|
||||
{
|
||||
// We report different kinds of problems with [thisUpdate, nextUpdate]
|
||||
// as 'expired' (to keep it simple):
|
||||
const QSslError::SslError expectedError = QSslError::OcspResponseExpired;
|
||||
|
||||
QFETCH(const long, beforeNow);
|
||||
QFETCH(const long, afterNow);
|
||||
|
||||
QDECLARE_CHAIN(subjectChain, "ss1.crt");
|
||||
QDECLARE_CHAIN(responderChain, "ss1.crt");
|
||||
QDECLARE_PRIVATE_KEY(privateKey, "ss1-private.key");
|
||||
|
||||
OcspServer server(subjectChain, privateKey);
|
||||
const QByteArray response(goodResponse(subjectChain, responderChain, privateKey, beforeNow, afterNow));
|
||||
QVERIFY(response.size());
|
||||
server.configureResponse(response);
|
||||
QVERIFY(server.listen());
|
||||
connect(&server, &OcspServer::internalServerError, &loop, exitLoopSlot);
|
||||
|
||||
QSslSocket clientSocket;
|
||||
setupOcspClient(clientSocket, issuerToChain(subjectChain), server.peerVerifyName());
|
||||
clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort());
|
||||
loop.enterLoopMSecs(handshakeTimeoutMS);
|
||||
|
||||
QVERIFY(!clientSocket.isEncrypted());
|
||||
QCOMPARE_SINGLE_ERROR(clientSocket, expectedError);
|
||||
}
|
||||
|
||||
void tst_QOcsp::noNextUpdate()
|
||||
{
|
||||
// RFC2560, 2.4:
|
||||
// "If nextUpdate is not set, the responder is indicating that newer
|
||||
// revocation information is available all the time."
|
||||
//
|
||||
// This test is just to verify that we correctly handle such responses.
|
||||
QDECLARE_CHAIN(subjectChain, "ss1.crt");
|
||||
QDECLARE_CHAIN(responderChain, "ss1.crt");
|
||||
QDECLARE_PRIVATE_KEY(privateKey, "ss1-private.key");
|
||||
|
||||
OcspServer server(subjectChain, privateKey);
|
||||
OcspTimeStamp openRange(-1000, 0);
|
||||
openRange.nextUpdate.clear();
|
||||
const OcspResponder responder(openRange, subjectChain, responderChain, privateKey);
|
||||
const QByteArray response(responder.buildResponse(OCSP_RESPONSE_STATUS_SUCCESSFUL,
|
||||
V_OCSP_CERTSTATUS_GOOD));
|
||||
QVERIFY(response.size());
|
||||
server.configureResponse(response);
|
||||
QVERIFY(server.listen());
|
||||
connect(&server, &OcspServer::internalServerError, &loop, exitLoopSlot);
|
||||
|
||||
QSslSocket clientSocket;
|
||||
setupOcspClient(clientSocket, issuerToChain(subjectChain), server.peerVerifyName());
|
||||
clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort());
|
||||
loop.enterLoopMSecs(handshakeTimeoutMS);
|
||||
|
||||
QVERIFY_HANDSHAKE_WITHOUT_ERRORS(clientSocket);
|
||||
}
|
||||
|
||||
void tst_QOcsp::wrongCertificateInResponse_data()
|
||||
{
|
||||
QTest::addColumn<QLatin1String>("respChainName");
|
||||
QTest::addColumn<QLatin1String>("respKeyName");
|
||||
QTest::addColumn<QLatin1String>("wrongChainName");
|
||||
|
||||
QTest::addRow("same-CA-wrong-subject") << QLatin1String("ca1.crt") << QLatin1String("ca1.key")
|
||||
<< QLatin1String("alice.crt");
|
||||
QTest::addRow("wrong-CA-same-subject") << QLatin1String("ss1.crt") << QLatin1String("ss1-private.key")
|
||||
<< QLatin1String("alice.crt");
|
||||
QTest::addRow("wrong-CA-wrong-subject") << QLatin1String("ss1.crt") << QLatin1String("ss1-private.key")
|
||||
<< QLatin1String("ss1.crt");
|
||||
}
|
||||
|
||||
void tst_QOcsp::wrongCertificateInResponse()
|
||||
{
|
||||
QFETCH(const QLatin1String, respChainName);
|
||||
QFETCH(const QLatin1String, respKeyName);
|
||||
QFETCH(const QLatin1String, wrongChainName);
|
||||
// In this test, the server will send a valid response (correctly signed
|
||||
// by a trusted key/cert) but for a wrong certificate (not the one the
|
||||
// server presented to the client in the server's 'Certificate' message).
|
||||
const QSslError::SslError expectedError = QSslError::OcspResponseCertIdUnknown;
|
||||
|
||||
QDECLARE_CHAIN(subjectChain, "infbobchain.crt");
|
||||
QDECLARE_PRIVATE_KEY(subjectKey, "infbob.key");
|
||||
QDECLARE_CHAIN(responderChain, respChainName);
|
||||
QDECLARE_PRIVATE_KEY(responderKey, respKeyName);
|
||||
|
||||
QDECLARE_CHAIN(wrongChain, wrongChainName);
|
||||
|
||||
OcspServer server(subjectToChain(subjectChain), subjectKey);
|
||||
const QByteArray wrongResponse(goodResponse(wrongChain, responderChain, responderKey));
|
||||
QVERIFY(wrongResponse.size());
|
||||
server.configureResponse(wrongResponse);
|
||||
QVERIFY(server.listen());
|
||||
connect(&server, &OcspServer::internalServerError, &loop, exitLoopSlot);
|
||||
|
||||
QSslSocket clientSocket;
|
||||
setupOcspClient(clientSocket, issuerToChain(subjectChain), server.peerVerifyName());
|
||||
clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort());
|
||||
loop.enterLoopMSecs(handshakeTimeoutMS);
|
||||
|
||||
QVERIFY(!clientSocket.isEncrypted());
|
||||
QVERIFY(containsError(clientSocket.sslHandshakeErrors(), expectedError));
|
||||
}
|
||||
|
||||
void tst_QOcsp::untrustedResponder()
|
||||
{
|
||||
const QSslError::SslError expectedError = QSslError::OcspResponseCannotBeTrusted;
|
||||
|
||||
QDECLARE_CHAIN(subjectChain, "infbobchain.crt");
|
||||
QDECLARE_PRIVATE_KEY(subjectKey, "infbob.key");
|
||||
QDECLARE_CHAIN(responderChain, "ca1.crt");
|
||||
QDECLARE_PRIVATE_KEY(responderKey, "ca1.key");
|
||||
|
||||
OcspServer server(subjectChain, subjectKey);
|
||||
const QByteArray response(goodResponse(subjectToChain(subjectChain), responderChain, responderKey));
|
||||
QVERIFY(response.size());
|
||||
server.configureResponse(response);
|
||||
QVERIFY(server.listen());
|
||||
connect(&server, &OcspServer::internalServerError, &loop, exitLoopSlot);
|
||||
|
||||
QSslSocket clientSocket;
|
||||
setupOcspClient(clientSocket, {}, server.peerVerifyName());
|
||||
clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort());
|
||||
loop.enterLoopMSecs(handshakeTimeoutMS);
|
||||
|
||||
QVERIFY(!clientSocket.isEncrypted());
|
||||
QVERIFY(containsError(clientSocket.sslHandshakeErrors(), expectedError));
|
||||
}
|
||||
|
||||
void tst_QOcsp::setupOcspClient(QSslSocket &clientSocket, const CertificateChain &caCerts, const QString &name)
|
||||
{
|
||||
QSslConfiguration clientConfig = QSslConfiguration::defaultConfiguration();
|
||||
clientConfig.setOcspStaplingEnabled(true);
|
||||
|
||||
if (caCerts.size()) {
|
||||
auto roots = clientConfig.caCertificates();
|
||||
roots.append(caCerts);
|
||||
clientConfig.setCaCertificates(roots);
|
||||
}
|
||||
|
||||
clientSocket.setSslConfiguration(clientConfig);
|
||||
clientSocket.setPeerVerifyName(name);
|
||||
|
||||
connect(&clientSocket, &QAbstractSocket::errorOccurred, &loop, exitLoopSlot);
|
||||
connect(&clientSocket, tlsErrorsSignal, &loop, exitLoopSlot);
|
||||
connect(&clientSocket, &QSslSocket::encrypted, &loop, exitLoopSlot);
|
||||
}
|
||||
|
||||
bool tst_QOcsp::containsOcspErrors(const QList<QSslError> &errorsFound) const
|
||||
{
|
||||
for (auto code : ocspErrorCodes) {
|
||||
if (containsError(errorsFound, code))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool tst_QOcsp::containsError(const QList<QSslError> &errors, QSslError::SslError code)
|
||||
{
|
||||
const auto it = std::find_if(errors.begin(), errors.end(),
|
||||
[&code](const QSslError &other){return other.error() == code;});
|
||||
return it != errors.end();
|
||||
}
|
||||
|
||||
QByteArray tst_QOcsp::goodResponse(const CertificateChain &subject, const CertificateChain &responder,
|
||||
const QSslKey &privateKey, long beforeNow, long afterNow)
|
||||
{
|
||||
const OcspResponder builder(OcspTimeStamp(beforeNow, afterNow), subject, responder, privateKey);
|
||||
return builder.buildResponse(OCSP_RESPONSE_STATUS_SUCCESSFUL, V_OCSP_CERTSTATUS_GOOD);
|
||||
}
|
||||
|
||||
bool tst_QOcsp::loadPrivateKey(const QString &keyFileName, QSslKey &key)
|
||||
{
|
||||
QFile keyFile(certDirPath + keyFileName);
|
||||
if (!keyFile.open(QIODevice::ReadOnly))
|
||||
return false;
|
||||
key = QSslKey(keyFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
|
||||
return !key.isNull();
|
||||
}
|
||||
|
||||
CertificateChain tst_QOcsp::issuerToChain(const CertificateChain &chain)
|
||||
{
|
||||
// Here we presume that, if the chain isn't a single self-signed certificate, its second
|
||||
// entry is the issuer.
|
||||
const int length = chain.size();
|
||||
Q_ASSERT(length > 0);
|
||||
return CertificateChain() << chain[length > 1 ? 1 : 0];
|
||||
}
|
||||
|
||||
CertificateChain tst_QOcsp::subjectToChain(const CertificateChain &chain)
|
||||
{
|
||||
Q_ASSERT(chain.size());
|
||||
return CertificateChain() << chain[0];
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QTEST_MAIN(tst_QOcsp)
|
||||
|
||||
#include "tst_qocsp.moc"
|
Reference in New Issue
Block a user