diff options
author | Andrew Knight <andrew.knight@digia.com> | 2014-08-12 12:21:57 +0300 |
---|---|---|
committer | Andrew Knight <andrew.knight@digia.com> | 2014-08-13 21:09:51 +0200 |
commit | 8c864ac49861b397a6d3e8b4a93c39b1ed373644 (patch) | |
tree | c82b95c1d52892397f59f50c3fc9be8f43b69d41 /src/network/ssl/qsslkey_winrt.cpp | |
parent | cec893e4f0d6480a9b3e38af38c7b887a29f206d (diff) |
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>
Diffstat (limited to 'src/network/ssl/qsslkey_winrt.cpp')
-rw-r--r-- | src/network/ssl/qsslkey_winrt.cpp | 130 |
1 files changed, 121 insertions, 9 deletions
diff --git a/src/network/ssl/qsslkey_winrt.cpp b/src/network/ssl/qsslkey_winrt.cpp index 1e416a8c09..1c625081a4 100644 --- a/src/network/ssl/qsslkey_winrt.cpp +++ b/src/network/ssl/qsslkey_winrt.cpp @@ -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 |