winrt: Add partial SSL key support
This allows for opening of public key files. It does not, however, support opening private keys (or decrypting/encrypting them). This is due to limitations in the native API. Nearly all public key tests pass (the native API doesn't support the 40-bit key in the test set). The private key tests are expected to fail. Task-number: QTBUG-40688 Change-Id: Id8f2f1ae6526540736ceb2e5371f6a5d80c4ba7b Reviewed-by: Richard J. Moore <rich@kde.org> Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
This commit is contained in:
parent
cec893e4f0
commit
8c864ac498
@ -42,41 +42,153 @@
|
||||
#include "qsslkey.h"
|
||||
#include "qsslkey_p.h"
|
||||
|
||||
#include <QtCore/qfunctions_winrt.h>
|
||||
|
||||
#include <wrl.h>
|
||||
#include <windows.security.cryptography.h>
|
||||
#include <windows.security.cryptography.core.h>
|
||||
#include <windows.security.cryptography.certificates.h>
|
||||
#include <windows.storage.streams.h>
|
||||
#include <robuffer.h>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace Microsoft::WRL::Wrappers;
|
||||
using namespace ABI::Windows::Foundation;
|
||||
using namespace ABI::Windows::Security::Cryptography;
|
||||
using namespace ABI::Windows::Security::Cryptography::Certificates;
|
||||
using namespace ABI::Windows::Security::Cryptography::Core;
|
||||
using namespace ABI::Windows::Storage::Streams;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
struct SslKeyGlobal
|
||||
{
|
||||
SslKeyGlobal()
|
||||
{
|
||||
HRESULT hr;
|
||||
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_CryptographicBuffer).Get(),
|
||||
&bufferFactory);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
||||
ComPtr<IAsymmetricKeyAlgorithmProviderStatics> keyProviderFactory;
|
||||
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Core_AsymmetricKeyAlgorithmProvider).Get(),
|
||||
&keyProviderFactory);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
||||
ComPtr<IAsymmetricAlgorithmNamesStatics> algorithmNames;
|
||||
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Security_Cryptography_Core_AsymmetricAlgorithmNames).Get(),
|
||||
&algorithmNames);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
||||
HString algorithmName;
|
||||
// The algorithm name doesn't matter for imports, so just use PKCS1
|
||||
hr = algorithmNames->get_RsaPkcs1(algorithmName.GetAddressOf());
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
hr = keyProviderFactory->OpenAlgorithm(algorithmName.Get(), &keyProvider);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
ComPtr<ICryptographicBufferStatics> bufferFactory;
|
||||
ComPtr<IAsymmetricKeyAlgorithmProvider> keyProvider;
|
||||
};
|
||||
Q_GLOBAL_STATIC(SslKeyGlobal, g)
|
||||
|
||||
// Use the opaque struct for key storage
|
||||
struct EVP_PKEY {
|
||||
ComPtr<ICryptographicKey> key;
|
||||
};
|
||||
|
||||
void QSslKeyPrivate::clear(bool deep)
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
isNull = true;
|
||||
|
||||
if (opaque) {
|
||||
if (deep) {
|
||||
delete opaque;
|
||||
opaque = 0;
|
||||
} else {
|
||||
opaque->key.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase,
|
||||
bool deepClear)
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
Q_UNUSED(passPhrase);
|
||||
|
||||
clear(deepClear);
|
||||
|
||||
if (der.isEmpty())
|
||||
return;
|
||||
|
||||
if (type != QSsl::PublicKey) {
|
||||
qWarning("The WinRT SSL backend does not support importing private keys.");
|
||||
return;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
ComPtr<IBuffer> buffer;
|
||||
hr = g->bufferFactory->CreateFromByteArray(der.length(), (BYTE *)der.data(), &buffer);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
|
||||
if (!opaque)
|
||||
opaque = new EVP_PKEY;
|
||||
|
||||
hr = g->keyProvider->ImportDefaultPublicKeyBlob(buffer.Get(), &opaque->key);
|
||||
RETURN_VOID_IF_FAILED("Failed to import public key");
|
||||
|
||||
isNull = false;
|
||||
}
|
||||
|
||||
void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
|
||||
bool deepClear)
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
decodeDer(derFromPem(pem), passPhrase, deepClear);
|
||||
}
|
||||
|
||||
int QSslKeyPrivate::length() const
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
return -1;
|
||||
if (isNull)
|
||||
return -1;
|
||||
|
||||
Q_ASSERT(opaque && opaque->key);
|
||||
HRESULT hr;
|
||||
UINT32 keySize;
|
||||
hr = opaque->key->get_KeySize(&keySize);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
return keySize;
|
||||
}
|
||||
|
||||
QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
return QByteArray();
|
||||
Q_UNUSED(passPhrase);
|
||||
QByteArray result;
|
||||
if (isNull)
|
||||
return result;
|
||||
|
||||
Q_ASSERT(opaque && opaque->key);
|
||||
HRESULT hr;
|
||||
ComPtr<IBuffer> buffer;
|
||||
hr = opaque->key->ExportDefaultPublicKeyBlobType(&buffer);
|
||||
RETURN_IF_FAILED("Failed to export key", return result);
|
||||
|
||||
ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteAccess;
|
||||
hr = buffer.As(&byteAccess);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
char *data;
|
||||
hr = byteAccess->Buffer(reinterpret_cast<byte **>(&data));
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
UINT32 size;
|
||||
hr = buffer->get_Length(&size);
|
||||
Q_ASSERT_SUCCEEDED(hr);
|
||||
result = pemFromDer(QByteArray::fromRawData(data, size));
|
||||
return result;
|
||||
}
|
||||
|
||||
Qt::HANDLE QSslKeyPrivate::handle() const
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
return 0;
|
||||
return opaque ? opaque->key.Get() : 0;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -47,6 +47,14 @@
|
||||
#include <QtNetwork/qhostaddress.h>
|
||||
#include <QtNetwork/qnetworkproxy.h>
|
||||
|
||||
#ifdef Q_OS_WINRT
|
||||
#define WINRT_EXPECT_FAILURES \
|
||||
if (type == QSsl::PrivateKey) \
|
||||
QEXPECT_FAIL("", "No support for private keys on WinRT: QTBUG-40688", Abort); \
|
||||
if (strstr(QTest::currentDataTag(), "rsa-pub-40")) \
|
||||
QEXPECT_FAIL("", "Weak public keys are not supported on WinRT", Abort);
|
||||
#endif
|
||||
|
||||
class tst_QSslKey : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -171,6 +179,10 @@ void tst_QSslKey::constructor()
|
||||
QFETCH(QSsl::KeyType, type);
|
||||
QFETCH(QSsl::EncodingFormat, format);
|
||||
|
||||
#ifdef Q_OS_WINRT
|
||||
WINRT_EXPECT_FAILURES
|
||||
#endif
|
||||
|
||||
QByteArray encoded = readFile(absFilePath);
|
||||
QSslKey key(encoded, algorithm, format, type);
|
||||
QVERIFY(!key.isNull());
|
||||
@ -232,6 +244,10 @@ void tst_QSslKey::length()
|
||||
QFETCH(int, length);
|
||||
QFETCH(QSsl::EncodingFormat, format);
|
||||
|
||||
#ifdef Q_OS_WINRT
|
||||
WINRT_EXPECT_FAILURES
|
||||
#endif
|
||||
|
||||
QByteArray encoded = readFile(absFilePath);
|
||||
QSslKey key(encoded, algorithm, format, type);
|
||||
QVERIFY(!key.isNull());
|
||||
@ -253,6 +269,10 @@ void tst_QSslKey::toPemOrDer()
|
||||
QFETCH(QSsl::KeyType, type);
|
||||
QFETCH(QSsl::EncodingFormat, format);
|
||||
|
||||
#ifdef Q_OS_WINRT
|
||||
WINRT_EXPECT_FAILURES
|
||||
#endif
|
||||
|
||||
QByteArray encoded = readFile(absFilePath);
|
||||
QSslKey key(encoded, algorithm, format, type);
|
||||
QVERIFY(!key.isNull());
|
||||
@ -297,6 +317,10 @@ void tst_QSslKey::toEncryptedPemOrDer()
|
||||
QFETCH(QSsl::EncodingFormat, format);
|
||||
QFETCH(QString, password);
|
||||
|
||||
#ifdef Q_OS_WINRT
|
||||
WINRT_EXPECT_FAILURES
|
||||
#endif
|
||||
|
||||
QByteArray plain = readFile(absFilePath);
|
||||
QSslKey key(plain, algorithm, format, type);
|
||||
QVERIFY(!key.isNull());
|
||||
@ -374,6 +398,9 @@ void tst_QSslKey::passphraseChecks()
|
||||
QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "WRONG!");
|
||||
QVERIFY(key.isNull()); // wrong passphrase => should not be able to decode key
|
||||
}
|
||||
#ifdef Q_OS_WINRT
|
||||
QEXPECT_FAIL("", "The WinRT backend does not support private key imports: QTBUG-40688", Abort);
|
||||
#endif
|
||||
{
|
||||
if (!keyFile.isOpen())
|
||||
keyFile.open(QIODevice::ReadOnly);
|
||||
|
Loading…
x
Reference in New Issue
Block a user