Qt 6.x
The Qt SDK
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
45 auto *certBackend = QTlsBackend::backend<X509CertificateSchannel>(certificate);
46 Q_ASSERT(certBackend);
47 certBackend->certificateContext = CertDuplicateCertificateContext(certificateContext);
48 return certificate;
49}
50
52 QList<QSslCertificate> *caCertificates,
53 const QByteArray &passPhrase)
54{
55 // These are required
59
60 QByteArray pkcs12data = device->readAll();
61 if (pkcs12data.size() == 0)
62 return false;
63
64 CRYPT_DATA_BLOB dataBlob;
65 dataBlob.cbData = pkcs12data.size();
66 dataBlob.pbData = reinterpret_cast<BYTE*>(pkcs12data.data());
67
68 const auto password = QString::fromUtf8(passPhrase);
69
70 const DWORD flags = (CRYPT_EXPORTABLE | PKCS12_NO_PERSIST_KEY | PKCS12_PREFER_CNG_KSP);
71
72 auto certStore = QHCertStorePointer(PFXImportCertStore(&dataBlob,
73 reinterpret_cast<LPCWSTR>(password.utf16()),
74 flags));
75
76 if (!certStore) {
77 qCWarning(lcTlsBackendSchannel, "Failed to import PFX data: %s",
78 qPrintable(QSystemError::windowsString()));
79 return false;
80 }
81
82 // first extract the certificate with the private key
83 const auto certContext = QPCCertContextPointer(CertFindCertificateInStore(certStore.get(),
84 X509_ASN_ENCODING |
85 PKCS_7_ASN_ENCODING,
86 0,
87 CERT_FIND_HAS_PRIVATE_KEY,
88 nullptr, nullptr));
89
90 if (!certContext) {
91 qCWarning(lcTlsBackendSchannel, "Failed to find certificate in PFX store: %s",
92 qPrintable(QSystemError::windowsString()));
93 return false;
94 }
95
96 *cert = QSslCertificate_from_CERT_CONTEXT(certContext.get());
97
98 // retrieve the private key for the certificate
99 NCRYPT_KEY_HANDLE keyHandle = {};
100 DWORD keyHandleSize = sizeof(keyHandle);
101 if (!CertGetCertificateContextProperty(certContext.get(), CERT_NCRYPT_KEY_HANDLE_PROP_ID,
102 &keyHandle, &keyHandleSize)) {
103 qCWarning(lcTlsBackendSchannel, "Failed to find private key handle in certificate context: %s",
104 qPrintable(QSystemError::windowsString()));
105 return false;
106 }
107
108 SECURITY_STATUS securityStatus = ERROR_SUCCESS;
109
110 // we need the 'NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG' to make NCryptExportKey succeed
111 DWORD policy = (NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG);
112 DWORD policySize = sizeof(policy);
113
114 securityStatus = NCryptSetProperty(keyHandle, NCRYPT_EXPORT_POLICY_PROPERTY,
115 reinterpret_cast<BYTE*>(&policy), policySize, 0);
116 if (securityStatus != ERROR_SUCCESS) {
117 qCWarning(lcTlsBackendSchannel, "Failed to update export policy of private key: 0x%x",
118 static_cast<unsigned int>(securityStatus));
119 return false;
120 }
121
122 DWORD blobSize = {};
123 securityStatus = NCryptExportKey(keyHandle, {}, BCRYPT_RSAFULLPRIVATE_BLOB,
124 nullptr, nullptr, 0, &blobSize, 0);
125 if (securityStatus != ERROR_SUCCESS) {
126 qCWarning(lcTlsBackendSchannel, "Failed to retrieve private key size: 0x%x",
127 static_cast<unsigned int>(securityStatus));
128 return false;
129 }
130
131 std::vector<BYTE> blob(blobSize);
132 securityStatus = NCryptExportKey(keyHandle, {}, BCRYPT_RSAFULLPRIVATE_BLOB,
133 nullptr, blob.data(), blobSize, &blobSize, 0);
134 if (securityStatus != ERROR_SUCCESS) {
135 qCWarning(lcTlsBackendSchannel, "Failed to retrieve private key from certificate: 0x%x",
136 static_cast<unsigned int>(securityStatus));
137 return false;
138 }
139
140 DWORD privateKeySize = {};
141
142 if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, CNG_RSA_PRIVATE_KEY_BLOB,
143 blob.data(), nullptr, &privateKeySize)) {
144 qCWarning(lcTlsBackendSchannel, "Failed to encode private key to key info: %s",
145 qPrintable(QSystemError::windowsString()));
146 return false;
147 }
148
149 std::vector<BYTE> privateKeyData(privateKeySize);
150
151 CRYPT_PRIVATE_KEY_INFO privateKeyInfo = {};
152 privateKeyInfo.Algorithm.pszObjId = const_cast<PSTR>(szOID_RSA_RSA);
153 privateKeyInfo.PrivateKey.cbData = privateKeySize;
154 privateKeyInfo.PrivateKey.pbData = privateKeyData.data();
155
156 if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
157 CNG_RSA_PRIVATE_KEY_BLOB, blob.data(),
158 privateKeyInfo.PrivateKey.pbData, &privateKeyInfo.PrivateKey.cbData)) {
159 qCWarning(lcTlsBackendSchannel, "Failed to encode private key to key info: %s",
160 qPrintable(QSystemError::windowsString()));
161 return false;
162 }
163
164
165 DWORD derSize = {};
166
167 if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
168 &privateKeyInfo, nullptr, &derSize)) {
169 qCWarning(lcTlsBackendSchannel, "Failed to encode key info to DER format: %s",
170 qPrintable(QSystemError::windowsString()));
171
172 return false;
173 }
174
176
177 if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
178 &privateKeyInfo, reinterpret_cast<BYTE*>(derData.data()), &derSize)) {
179 qCWarning(lcTlsBackendSchannel, "Failed to encode key info to DER format: %s",
180 qPrintable(QSystemError::windowsString()));
181
182 return false;
183 }
184
186 if (key->isNull()) {
187 qCWarning(lcTlsBackendSchannel, "Failed to parse private key from DER format");
188 return false;
189 }
190
191 // fetch all the remaining certificates as CA certificates
192 if (caCertificates) {
193 PCCERT_CONTEXT caCertContext = nullptr;
194 while ((caCertContext = CertFindCertificateInStore(certStore.get(),
195 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
196 0, CERT_FIND_ANY, nullptr, caCertContext))) {
197 if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
198 certContext->pCertInfo, caCertContext->pCertInfo))
199 continue; // ignore the certificate with private key
200
201 auto caCertificate = QSslCertificate_from_CERT_CONTEXT(caCertContext);
202
203 caCertificates->append(caCertificate);
204 }
205 }
206
207 return true;
208}
209
210} // namespace QTlsPrivate
211
213
IOBluetoothDevice * device
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:534
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
\inmodule QtCore \reentrant
Definition qiodevice.h:34
Definition qlist.h:74
void append(parameter_type t)
Definition qlist.h:441
The QSslCertificate class provides a convenient API for an X509 certificate.
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:5857
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:21
@ PrivateKey
Definition qssl.h:20
@ Rsa
Definition qssl.h:31
@ Opaque
Definition qssl.h:30
@ Der
Definition qssl.h:26
Combined button and popup list for selecting options.
Namespace containing onternal types that TLS backends implement.
void * HANDLE
constexpr Initialization Uninitialized
#define qCWarning(category,...)
GLuint64 key
GLbitfield flags
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qPrintable(string)
Definition qstring.h:1391
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]