summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2019-03-04 16:11:20 +0100
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2019-03-08 05:36:14 +0000
commit01a54342521de9994ef54f4a01916b8782c685f6 (patch)
tree0e461db5863612954c47385f0fb1f61c87b36cb3
parentf91aae6397378f7f86a3dd320f4e2caa3843a5de (diff)
QSslKey - add a support for AES encrypted keys
for SecureTransport backend. OpenSSL, while reading RSA/DSA, is internally calling EVP_BytesToKey that essentially does the same thing this patch does in 'deriveAesKey' and thus able to correctly decrypt whatever it first encrypted (while generating/ encrypting keys). Fixes: QTBUG-54422 Change-Id: Ia9f7599c5b19bf364c179f2abd2aab7ea5359a65 Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
-rw-r--r--src/network/ssl/qsslkey_mac.cpp8
-rw-r--r--src/network/ssl/qsslkey_openssl.cpp8
-rw-r--r--src/network/ssl/qsslkey_p.h5
-rw-r--r--src/network/ssl/qsslkey_qt.cpp48
-rw-r--r--src/network/ssl/qsslkey_schannel.cpp1
-rw-r--r--tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes128.pem30
-rw-r--r--tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes192.pem30
-rw-r--r--tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes256.pem30
-rw-r--r--tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp20
9 files changed, 173 insertions, 7 deletions
diff --git a/src/network/ssl/qsslkey_mac.cpp b/src/network/ssl/qsslkey_mac.cpp
index b0f726a2e6..814fe1c4bc 100644
--- a/src/network/ssl/qsslkey_mac.cpp
+++ b/src/network/ssl/qsslkey_mac.cpp
@@ -66,7 +66,13 @@ static QByteArray wrapCCCrypt(CCOperation ccOp,
blockSize = kCCBlockSizeRC2;
ccAlgorithm = kCCAlgorithmRC2;
break;
- };
+ case QSslKeyPrivate::Aes128Cbc:
+ case QSslKeyPrivate::Aes192Cbc:
+ case QSslKeyPrivate::Aes256Cbc:
+ blockSize = kCCBlockSizeAES128;
+ ccAlgorithm = kCCAlgorithmAES;
+ break;
+ }
size_t plainLength = 0;
QByteArray plain(data.size() + blockSize, 0);
CCCryptorStatus status = CCCrypt(
diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp
index 99c1a39c73..dfb80bd829 100644
--- a/src/network/ssl/qsslkey_openssl.cpp
+++ b/src/network/ssl/qsslkey_openssl.cpp
@@ -333,6 +333,14 @@ static QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data,
type = q_EVP_rc2_cbc();
#endif
break;
+ case QSslKeyPrivate::Aes128Cbc:
+ case QSslKeyPrivate::Aes192Cbc:
+ case QSslKeyPrivate::Aes256Cbc:
+ // Just to avoid compiler warnings/errors. OpenSSL uses a different
+ // codepath when reading encrypted keys, and they all correctly
+ // deduce the cipher and know how to derive a key.
+ Q_UNREACHABLE();
+ break;
}
if (type == nullptr)
diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h
index 06403b5479..1f2b59904a 100644
--- a/src/network/ssl/qsslkey_p.h
+++ b/src/network/ssl/qsslkey_p.h
@@ -105,7 +105,10 @@ public:
enum Cipher {
DesCbc,
DesEde3Cbc,
- Rc2Cbc
+ Rc2Cbc,
+ Aes128Cbc,
+ Aes192Cbc,
+ Aes256Cbc
};
Q_AUTOTEST_EXPORT static QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv);
diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp
index 5ebd8ac3bd..61251b641b 100644
--- a/src/network/ssl/qsslkey_qt.cpp
+++ b/src/network/ssl/qsslkey_qt.cpp
@@ -124,6 +124,37 @@ static int numberOfBits(const QByteArray &modulus)
return bits;
}
+static QByteArray deriveAesKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase, const QByteArray &iv)
+{
+ // This is somewhat simplified and shortened version of what OpenSSL does.
+ // See, for example, EVP_BytesToKey for the "algorithm" itself and elsewhere
+ // in their code for what they pass as arguments to EVP_BytesToKey when
+ // deriving encryption keys (when reading/writing pems files with encrypted
+ // keys).
+
+ Q_ASSERT(iv.size() >= 8);
+
+ QCryptographicHash hash(QCryptographicHash::Md5);
+
+ QByteArray data(passPhrase);
+ data.append(iv.data(), 8); // AKA PKCS5_SALT_LEN in OpenSSL.
+
+ hash.addData(data);
+
+ if (cipher == QSslKeyPrivate::Aes128Cbc)
+ return hash.result();
+
+ QByteArray key(hash.result());
+ hash.reset();
+ hash.addData(key);
+ hash.addData(data);
+
+ if (cipher == QSslKeyPrivate::Aes192Cbc)
+ return key.append(hash.result().constData(), 8);
+
+ return key.append(hash.result());
+}
+
static QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase, const QByteArray &iv)
{
QByteArray key;
@@ -145,6 +176,10 @@ static QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &pas
case QSslKeyPrivate::Rc2Cbc:
key = hash.result();
break;
+ case QSslKeyPrivate::Aes128Cbc:
+ case QSslKeyPrivate::Aes192Cbc:
+ case QSslKeyPrivate::Aes256Cbc:
+ return deriveAesKey(cipher, passPhrase, iv);
}
return key;
}
@@ -378,6 +413,15 @@ void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhra
cipher = DesEde3Cbc;
} else if (dekInfo.first() == "RC2-CBC") {
cipher = Rc2Cbc;
+// TODO: Add SChannel version too!
+#ifdef QT_SECURETRANSPORT
+ } else if (dekInfo.first() == "AES-128-CBC") {
+ cipher = Aes128Cbc;
+ } else if (dekInfo.first() == "AES-192-CBC") {
+ cipher = Aes192Cbc;
+ } else if (dekInfo.first() == "AES-256-CBC") {
+ cipher = Aes256Cbc;
+#endif // QT_SECURETRANSPORT
} else {
clear(deepClear);
return;
@@ -554,6 +598,10 @@ static EncryptionData readPbes2(const QVector<QAsn1Element> &element, const QByt
return {};
break;
} // @todo(?): case (RC5 , AES)
+ case QSslKeyPrivate::Cipher::Aes128Cbc:
+ case QSslKeyPrivate::Cipher::Aes192Cbc:
+ case QSslKeyPrivate::Cipher::Aes256Cbc:
+ Q_UNREACHABLE();
}
if (Q_LIKELY(keyDerivationAlgorithm == PKCS5_PBKDF2_ENCRYPTION_OID)) {
diff --git a/src/network/ssl/qsslkey_schannel.cpp b/src/network/ssl/qsslkey_schannel.cpp
index 5694068860..9dfbc87e9a 100644
--- a/src/network/ssl/qsslkey_schannel.cpp
+++ b/src/network/ssl/qsslkey_schannel.cpp
@@ -57,6 +57,7 @@ const wchar_t *getName(QSslKeyPrivate::Cipher cipher)
return BCRYPT_3DES_ALGORITHM;
case QSslKeyPrivate::Cipher::Rc2Cbc:
return BCRYPT_RC2_ALGORITHM;
+ default:;
}
Q_UNREACHABLE();
}
diff --git a/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes128.pem b/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes128.pem
new file mode 100644
index 0000000000..1a8751874e
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes128.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,A2A6F6BA67CFB2A992BA4FD3A0984B59
+
+L5G1mwcXwW30lFty1HaEHlswFXAGk9+qf0TdYYNAAvVrsTMgfMq/6xM5XWo3IgbN
+gG4K6T57gQkAywn+upqMHobB+7qc3DRzYlrm89gb74gHOe95l/iUJp4ii+ROLcmY
+fg/vNmDSB/D0eM91WfwId7ticYD29+BUbbnqSYyY2S7K7DytYLpXqg3u335GYCdT
+JwOsgcgbOICytkgK6c9ZDF3IrkzvWospVuiG5IfpLQkUXlJO3YGJ/oGf1BXnRd/b
+kTzUiimUVunX62muHaUXKkAmXS8FCdB0puI+52pzLJ5FHdFxCcnwSG09TmoXbwwa
+KoNM+IshNHPBGM7QxflVbSDxDaF1FWLwWSb8+Fhb2fTpfEGMxRCQ8HB1ZeMV4E5W
+DSiNhih8ziC0k957ZYv8iuLanoM1YYIdToHeBwjyBJA836eIcq/ElY2QtKUq5PRw
++sU1BdG+f9rf4iAPHpgWZAKFmJ42ya71bEEVAmfysAOPuc4hpn3SsDTtihm9RKc9
+l7LWJHaTnTu6yJA+vMJwAmPWg+IdG5vntbb93X4cgl5ZadBySRtv37wWyQPnQcFh
+ytX8z2CJNIFJb0ik8bXc39zOxExoTu/o86IuVJ87jFdS1wz3PRek6dJdl15icx76
+yAT0YB2/ZlRcRrO9hSm0D6P+sLOh//dyhhFAlUrDxqrKngI3KF4kgIrSlva3wmx2
+t16SiUKu6FGQZk6/KYOV27Cy+8UJEqlrNJzy+wSFi26d6e6xWTIR2ItzQCxhYDmq
+Tpx0Mh0ml2+bgrKRoDAL5z6UNy0Pc6bYQjvMznIeiuGvL8bAKTDUFwbmrZqNScsl
+tW7yNZG9iSJnAZGMTxuOhSvJRpQkxIcLICd+lsUxWZ2YvFxtSORuRNSwaC7oxtTD
+gIXV08ayoDbDmcguqTXWuCxtguxNANjhsUOetNHL8iP8QFrzAd5Ith9FgASCIBJJ
+3X7vL2YGc3E6DlAJE01loqySU/cnu6/zQapLB9BIzdtoLliwdrJ7PS8FSsBDfZ2X
+i6/7gb1jxYkJAS1NqrUMJw6BphRAwF8ny+FtPJ23Oaf+1vRIGiHsh8qw6XBfwFw9
+vtsUUL19r+8zMpvIB6gf34TLuM7AW7idu3c/486EWgZBDL3mOTd3fsyADKv/HCk7
+c8M2dsafxI6QkTlWsB8G5vkZ8lCGKHjrmPWjfD7NXi+CvXIrDY+gOeVN3PlQCU/2
+zF2vIxKtR0CXuxLzIjFhIgTYR5G5ZnddMmHeVkZdPRl7szGtrxOA4QGJQ6ZT4W2e
+O1whVU2KB0aBYskhClimapM5ypRkcNQ97cUR6/iNgdgSLqxGHCGeMR9bEyLl7/wr
+M0XeDjdVfm/Tj548oHgb0SKLsfL6nnKwqB2viKj81moK9A/wO1Ec9RNaw0jtp2j3
+VIUnPj0GqEjnkHc2jWY2yt4SD6e2AZHwLyWi1q3pixZo1CFiEgFXxwNyYwyeJ6jV
+CJHPRzoNjZ8dkvgRjsXdnWwN316JBNVcH8k7CCmg/8Gq3yAojXG1z8VJZ06GHckd
+meCL1t89OgwIAmIsysKu7+DrKtSlhkQclZmdG6IrQzuPKaHzTPTDgg3ef3jQ4YQO
+-----END RSA PRIVATE KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes192.pem b/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes192.pem
new file mode 100644
index 0000000000..db74877a5a
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes192.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CBC,B408346ADE790F8CF0C902A4F0712B34
+
+SwzPBGxmwW2JddOyug1LrWjlZn8siSp5yezjK1x/z2+J2r/vvH8OjGnA387tFtae
+WVTmhT1ixQXMDI1UJuKx0gzrG2449c+BUVe2VXFPLZ2ocSgoXbBpVkfhEqtLAn91
+MSOpQMxvobQKltKhxgXGvuBJwhwfT7yK5HamohFGbxLUh4Dh+NBXwoYH4Qt+kM7C
+kV8VIKvkr/QAL/SRxNoY8rVResPgYvUjdtiGSNZ6CZhNRu42Q2FqbH817cE0NDsN
+il/xvWu4T/6VY1KpwMad/v6BhO45EeKz7YjbF/3Y5jj2JV9r45uf79lM9htMBw0d
+L+Cc3YHeFffgU8NZo0+iUoroXcb7mjWNmgYksbkaZPbLG383YXAXwbkQS7zDMVIx
+QhXn9w+78hNmEV/7PQ8mGXHEFwnfSR05phXoj8IyL5v0grRMA2dsjfxCgfQjH+kc
+Miwr5pD/Flw175OpPFCb2qladdTKoIWiVShspbteoRC0EuiWHzkl5z6Tneyb/sam
+yduLmSYD+RA6OBgUPY95Xm4AowlFFsuV/fxYZ53rFf4cZn9Z6VBVmvIEmapV7CtB
+JzyIVclocwM0ag5u/esdEt/jndJq9chZlIsDS30y3gP6Rlqk5mj90DAs98l28FVG
+WY9jP0babk8mxjYCcnAy7ikUc0D+vJVO6OTmfO3dkGjLpMBM6OlvfhN/0qeXrMDI
+nU2qOshUrVna2kRe6FrcvosFTD8wvQ1/BjmCp1iWWsGdc/q1BqI3pgOlgq3TYfl6
+iUJoji3V2iexH+GPkHsrs+kii1clsO2tgIP7doIooSVkcTsRTHHxKeeHn3qL2028
+pTvieIFD/T4biLZ9Q8sX3XWiHNmXZlCx8lX8MDjTavWES8gY4H5Sr6FjRMy1qpZY
+5w1aAyJ9YZ0J/jLPmFxt8mWgqHPiPlrQkryBBE3l1MSQ/hCEwlf9dP8a+ayINfd7
+3yNkHKjZ5fuoA+TZUQb/fyVM5o1zJ8ML01PaXWrMEgr3b36QL+Ivo2Rpnp9FpwuH
+E405cwCEy5fNSyhHFqqatCbsPl80nkP8OpW6jdWvNy9u0Ap9PS+MbHGq/pfkaazl
+fbKGOckrENzEXi6Uj/yY/0sMtbTJuC70n09X3edHyhl/RJPPUoNnwDM5W1FHfS3r
+qqSOl/r3y5pEErRdBpR4wEgB7DCLBALGDPfXNAAga4ez/Z2X9Zj234+4ZbUzWoLN
+1ER0QYyxLN7oz1qMA15J7nRyRIhDXNlXjyISOqy26T6/d4X0M+6RhNWfT/MHAjJ8
+6ogoGlQUITV3gPO4R6+FGZMF4R6zZXuKVtOXyzRwWnCLfo4gzBHmq+5mmCjGWRq8
+rSSkc6334bYuZOaEoR5EM5sh6ewkjSDPRrKR7EHO02YbiscyT/99TwT5pdIOPK3u
+2T6/40fSmCWQyBLuWxV9CMD+rB/q8Ja5KisEseck7PgI2pMmHfiD5yQXhKR9eDrB
+sRqZxjgRYxup+/0CIBshL8s1R88xelhXyIKyqFfVudM09yAZxEJLQhpDZ27g45ea
+FMX2Ve+ah2NjYBgzAhwKouWg5RyWb6X99NsrCEU75fn/ek86LGs3FxRgB4Uv7Udv
+-----END RSA PRIVATE KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes256.pem b/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes256.pem
new file mode 100644
index 0000000000..3d96b3166e
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/rsa-with-passphrase-aes256.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,0F2F4695C8FFA35F4076FA0273A3A4E3
+
+GCnMcAhhGuNkJ7SSMBrgNOaDfRtG22J0mdf/0VbrMOJF40P13YBjN3Kd6LpTqBya
+TCIaxQqtfjH1ffhJk8qhwG7uJFGgcY9i0dkrEYklgThzTVqHp7FsQ2jjgJs5HKpc
+euuVD1bxtuc9qI2hq4miA7Z/uDe3M34n+3xcpqccWS1dLFNFZ+fIDwIazfDCu3ah
+fUQHDeWLwOqYiQxhUjjrHpZkI1FE2JYZFaf4zIagIIgzI2O+33fgbrTSoeN5meRs
+F7V2fhDpyEoIlchwAmp6HE6ngtKP4Ecju00yn99AO42fn097yEVwvGFClQTaIzur
+aPEtuKZ4kdc/lmzL2tqNcZckq28ZxpeMq0Fgdcpeg5sDcut811scOjQLFs551On1
+j3E1WfiLoBLKgd9cgmCrZb8hMO+UjcCaV7Jv3T9vDrbvhWs/YhTTwo8UFVplh7Vx
+R1h3cKfzlbtOC5WHXGNK5dBu7SnpEk0+pscY5cxTrzN0odjMbbsjZQmKDZXbmZON
+USzG3Qtafm6Nw/jwQeIjeqaxSho6xGdadTteGaURw6iGio3h0c6/dHayCsxye4tk
+vODa0ZdJASwVh1605qDk9n/iYUT5B46KJCYwO/iN2kUmOcUcZeBqEfV1GfRmepZJ
+bwM4sipzE15hOJ5DKSkHWnSlByRMAdSrMxZWraKUczn5frEBAqEFLlBAvf/FnjWa
+yZJitgryCI2Y2bww1DEMnTCX345kUQIFmmjbzTIXnM28gW+fR3Br9dCf2FAsLNKr
+tru1cYXocPaCUHEqS+XZqVb6BQVQ11YAAde0+x9RknJgsBc9Y7TLobaDBvrV5/nK
+T3vm8el08upum6qPTPh6Z0zBbjx4sp6DYT977N1dYeH4n+0JqcSwIeZg/VAdG0RL
+GzgZVADpiRlStmy65W95KExBjbO0tRTVk/nB1U1nfLbsswp9EKxXgwtpE/ECeTOi
+hzeJBSsXGZ/ZXu/y+NlIu0B/GasFbfrHKslSSrUPTjGEtaEbLNiOEu2Etu3lRcMZ
+oDtMxgNR0TUgCS5nte8lLauYYfB6IuxZXpvJdcI5ushqdOJvvYgJ9Yb2ZPlY8Bt5
+C92Ga69aPcMYk24BPpe15eBbXMsFF8RF+CprVoUPCc+PcuROtxdt+rqoqjQeZPmV
+WQqq+pT2bychpwD7U5jxQnu4u2m+zeBXyk80euBbwEld9BCgfk9mFj6CdBJSEiGV
+qL0ivxd3mDaIKPGd5tcbrOMK2uD7duZY7FrQpAYgryoQJoUHccL7cr9fDC75akHg
+AbrG1+vAYEla/y+SlOg5VTHhiuIl17ZGMViXSqh7iqnnD0dNsZ/HDvk3XouhNxQy
+RQmfdqyIqLuAcfWwQxCQ2E/oMUIHjNhyYmfLVLVGsfxuevMa1eJv7rZ5vIkD2Vpe
+4VveZkNDSpCCNqnvub8+bMW+UXyzbxEZbK5PLkRp7cvtKdA5CUbTlT4060IV0YZ1
+vfMtzXRw8JDD9c1F1WF14afk+y9kvZN88XOH12bSKj+Re06Xx7OzuYU8fclq/pZB
+UZVtRETFnLgb8neMuz3vCoPWK/DSHDZGAAicxq7vTljyoU/QP71Dw7UJIAuYx6Mc
+-----END RSA PRIVATE KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp b/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp
index d24fafb77b..195f052266 100644
--- a/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp
+++ b/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp
@@ -466,15 +466,25 @@ void tst_QSslKey::toEncryptedPemOrDer()
void tst_QSslKey::passphraseChecks_data()
{
QTest::addColumn<QString>("fileName");
-
- QTest::newRow("DES") << (testDataDir + "rsa-with-passphrase-des.pem");
- QTest::newRow("3DES") << (testDataDir + "rsa-with-passphrase-3des.pem");
- QTest::newRow("RC2") << (testDataDir + "rsa-with-passphrase-rc2.pem");
+ QTest::addColumn<QByteArray>("passphrase");
+
+ const QByteArray pass("123");
+ const QByteArray aesPass("1234");
+
+ QTest::newRow("DES") << QString(testDataDir + "rsa-with-passphrase-des.pem") << pass;
+ QTest::newRow("3DES") << QString(testDataDir + "rsa-with-passphrase-3des.pem") << pass;
+ QTest::newRow("RC2") << QString(testDataDir + "rsa-with-passphrase-rc2.pem") << pass;
+#if (!defined(QT_NO_OPENSSL) && !defined(OPENSSL_NO_AES)) || defined(QT_SECURETRANSPORT)
+ QTest::newRow("AES128") << QString(testDataDir + "rsa-with-passphrase-aes128.pem") << aesPass;
+ QTest::newRow("AES192") << QString(testDataDir + "rsa-with-passphrase-aes192.pem") << aesPass;
+ QTest::newRow("AES256") << QString(testDataDir + "rsa-with-passphrase-aes256.pem") << aesPass;
+#endif
}
void tst_QSslKey::passphraseChecks()
{
QFETCH(QString, fileName);
+ QFETCH(QByteArray, passphrase);
QFile keyFile(fileName);
QVERIFY(keyFile.exists());
@@ -507,7 +517,7 @@ void tst_QSslKey::passphraseChecks()
keyFile.open(QIODevice::ReadOnly);
else
keyFile.reset();
- QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "123");
+ QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, passphrase);
QVERIFY(!key.isNull()); // correct passphrase
}
}