Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qx509_schannel.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6#include "qx509_schannel_p.h"
7
8#include <QtCore/private/qsystemerror_p.h>
9#include <QtNetwork/private/qsslcertificate_p.h>
10
11#include <memory>
12
14
15namespace QTlsPrivate {
16
18
20{
21 if (certificateContext)
22 CertFreeCertificateContext(certificateContext);
23}
24
26{
27 auto key = std::make_unique<TlsKeySchannel>(QSsl::PublicKey);
30
31 return key.release();
32}
33
35{
36 return Qt::HANDLE(certificateContext);
37}
38
40{
41 QByteArray derData = QByteArray((const char *)certificateContext->pbCertEncoded,
42 certificateContext->cbCertEncoded);
43 QSslCertificate certificate(derData, QSsl::Der);
44 if (!certificate.isNull()) {
45 auto *certBackend = QTlsBackend::backend<X509CertificateSchannel>(certificate);
46 Q_ASSERT(certBackend);
47 certBackend->certificateContext = CertDuplicateCertificateContext(certificateContext);
48 }
49 return certificate;
50}
51
53 QList<QSslCertificate> *caCertificates,
54 const QByteArray &passPhrase)
55{
56 // These are required
60
61 QByteArray pkcs12data = device->readAll();
62 if (pkcs12data.size() == 0)
63 return false;
64
65 CRYPT_DATA_BLOB dataBlob;
66 dataBlob.cbData = pkcs12data.size();
67 dataBlob.pbData = reinterpret_cast<BYTE*>(pkcs12data.data());
68
69 const auto password = QString::fromUtf8(passPhrase);
70
71 const DWORD flags = (CRYPT_EXPORTABLE | PKCS12_NO_PERSIST_KEY | PKCS12_PREFER_CNG_KSP);
72
73 auto certStore = QHCertStorePointer(PFXImportCertStore(&dataBlob,
74 reinterpret_cast<LPCWSTR>(password.utf16()),
75 flags));
76
77 if (!certStore) {
78 qCWarning(lcTlsBackendSchannel, "Failed to import PFX data: %s",
79 qPrintable(QSystemError::windowsString()));
80 return false;
81 }
82
83 // first extract the certificate with the private key
84 const auto certContext = QPCCertContextPointer(CertFindCertificateInStore(certStore.get(),
85 X509_ASN_ENCODING |
86 PKCS_7_ASN_ENCODING,
87 0,
88 CERT_FIND_HAS_PRIVATE_KEY,
89 nullptr, nullptr));
90
91 if (!certContext) {
92 qCWarning(lcTlsBackendSchannel, "Failed to find certificate in PFX store: %s",
93 qPrintable(QSystemError::windowsString()));
94 return false;
95 }
96
97 *cert = QSslCertificate_from_CERT_CONTEXT(certContext.get());
98
99 // retrieve the private key for the certificate
100 NCRYPT_KEY_HANDLE keyHandle = {};
101 DWORD keyHandleSize = sizeof(keyHandle);
102 if (!CertGetCertificateContextProperty(certContext.get(), CERT_NCRYPT_KEY_HANDLE_PROP_ID,
103 &keyHandle, &keyHandleSize)) {
104 qCWarning(lcTlsBackendSchannel, "Failed to find private key handle in certificate context: %s",
105 qPrintable(QSystemError::windowsString()));
106 return false;
107 }
108
109 SECURITY_STATUS securityStatus = ERROR_SUCCESS;
110
111 // we need the 'NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG' to make NCryptExportKey succeed
112 DWORD policy = (NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG);
113 DWORD policySize = sizeof(policy);
114
115 securityStatus = NCryptSetProperty(keyHandle, NCRYPT_EXPORT_POLICY_PROPERTY,
116 reinterpret_cast<BYTE*>(&policy), policySize, 0);
117 if (securityStatus != ERROR_SUCCESS) {
118 qCWarning(lcTlsBackendSchannel, "Failed to update export policy of private key: 0x%x",
119 static_cast<unsigned int>(securityStatus));
120 return false;
121 }
122
123 DWORD blobSize = {};
124 securityStatus = NCryptExportKey(keyHandle, {}, BCRYPT_RSAFULLPRIVATE_BLOB,
125 nullptr, nullptr, 0, &blobSize, 0);
126 if (securityStatus != ERROR_SUCCESS) {
127 qCWarning(lcTlsBackendSchannel, "Failed to retrieve private key size: 0x%x",
128 static_cast<unsigned int>(securityStatus));
129 return false;
130 }
131
132 std::vector<BYTE> blob(blobSize);
133 securityStatus = NCryptExportKey(keyHandle, {}, BCRYPT_RSAFULLPRIVATE_BLOB,
134 nullptr, blob.data(), blobSize, &blobSize, 0);
135 if (securityStatus != ERROR_SUCCESS) {
136 qCWarning(lcTlsBackendSchannel, "Failed to retrieve private key from certificate: 0x%x",
137 static_cast<unsigned int>(securityStatus));
138 return false;
139 }
140
141 DWORD privateKeySize = {};
142
143 if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, CNG_RSA_PRIVATE_KEY_BLOB,
144 blob.data(), nullptr, &privateKeySize)) {
145 qCWarning(lcTlsBackendSchannel, "Failed to encode private key to key info: %s",
146 qPrintable(QSystemError::windowsString()));
147 return false;
148 }
149
150 std::vector<BYTE> privateKeyData(privateKeySize);
151
152 CRYPT_PRIVATE_KEY_INFO privateKeyInfo = {};
153 privateKeyInfo.Algorithm.pszObjId = const_cast<PSTR>(szOID_RSA_RSA);
154 privateKeyInfo.PrivateKey.cbData = privateKeySize;
155 privateKeyInfo.PrivateKey.pbData = privateKeyData.data();
156
157 if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
158 CNG_RSA_PRIVATE_KEY_BLOB, blob.data(),
159 privateKeyInfo.PrivateKey.pbData, &privateKeyInfo.PrivateKey.cbData)) {
160 qCWarning(lcTlsBackendSchannel, "Failed to encode private key to key info: %s",
161 qPrintable(QSystemError::windowsString()));
162 return false;
163 }
164
165
166 DWORD derSize = {};
167
168 if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
169 &privateKeyInfo, nullptr, &derSize)) {
170 qCWarning(lcTlsBackendSchannel, "Failed to encode key info to DER format: %s",
171 qPrintable(QSystemError::windowsString()));
172
173 return false;
174 }
175
177
178 if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
179 &privateKeyInfo, reinterpret_cast<BYTE*>(derData.data()), &derSize)) {
180 qCWarning(lcTlsBackendSchannel, "Failed to encode key info to DER format: %s",
181 qPrintable(QSystemError::windowsString()));
182
183 return false;
184 }
185
187 if (key->isNull()) {
188 qCWarning(lcTlsBackendSchannel, "Failed to parse private key from DER format");
189 return false;
190 }
191
192 // fetch all the remaining certificates as CA certificates
193 if (caCertificates) {
194 PCCERT_CONTEXT caCertContext = nullptr;
195 while ((caCertContext = CertFindCertificateInStore(certStore.get(),
196 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
197 0, CERT_FIND_ANY, nullptr, caCertContext))) {
198 if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
199 certContext->pCertInfo, caCertContext->pCertInfo))
200 continue; // ignore the certificate with private key
201
202 auto caCertificate = QSslCertificate_from_CERT_CONTEXT(caCertContext);
203
204 caCertificates->append(caCertificate);
205 }
206 }
207
208 return true;
209}
210
211} // namespace QTlsPrivate
212
214
IOBluetoothDevice * device
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
\inmodule QtCore \reentrant
Definition qiodevice.h:34
The QSslCertificate class provides a convenient API for an X509 certificate.
bool isNull() const
Returns true if this is a null certificate (i.e., a certificate with no contents); otherwise returns ...
The QSslKey class provides an interface for private and public keys.
Definition qsslkey.h:23
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
TlsKey is an abstract class, that allows a TLS plugin to provide an underlying implementation for the...
TlsKey * publicKey() const override
Qt::HANDLE handle() const override
static bool importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert, QList< QSslCertificate > *caCertificates, const QByteArray &passPhrase)
static QSslCertificate QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext)
@ PublicKey
Definition qssl.h:24
@ PrivateKey
Definition qssl.h:23
@ Rsa
Definition qssl.h:36
@ Opaque
Definition qssl.h:35
@ Der
Definition qssl.h:30
Combined button and popup list for selecting options.
Namespace containing onternal types that TLS backends implement.
void * HANDLE
constexpr Initialization Uninitialized
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define qCWarning(category,...)
GLuint64 key
GLbitfield flags
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qPrintable(string)
Definition qstring.h:1531
std::unique_ptr< const CERT_CONTEXT, QPCCertContextDeleter > QPCCertContextPointer
Definition qwincrypt_p.h:51
std::unique_ptr< void, QHCertStoreDeleter > QHCertStorePointer
Definition qwincrypt_p.h:41
QSizePolicy policy
QList< QSslCertificate > cert
[0]