52bool X509CertificateSchannel::importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
53 QList<QSslCertificate> *caCertificates,
54 const QByteArray &passPhrase)
61 QByteArray pkcs12data = device->readAll();
62 if (pkcs12data.size() == 0)
65 CRYPT_DATA_BLOB dataBlob;
66 dataBlob.cbData = pkcs12data.size();
67 dataBlob.pbData =
reinterpret_cast<BYTE*>(pkcs12data.data());
69 const auto password = QString::fromUtf8(passPhrase);
71 const DWORD flags = (CRYPT_EXPORTABLE | PKCS12_NO_PERSIST_KEY | PKCS12_PREFER_CNG_KSP);
73 auto certStore = QHCertStorePointer(PFXImportCertStore(&dataBlob,
74 reinterpret_cast<LPCWSTR>(password.utf16()),
78 qCWarning(lcTlsBackendSchannel,
"Failed to import PFX data: %s",
79 qPrintable(QSystemError::windowsString()));
84 const auto certContext = QPCCertContextPointer(CertFindCertificateInStore(certStore.get(),
88 CERT_FIND_HAS_PRIVATE_KEY,
92 qCWarning(lcTlsBackendSchannel,
"Failed to find certificate in PFX store: %s",
93 qPrintable(QSystemError::windowsString()));
97 *cert = QSslCertificate_from_CERT_CONTEXT(certContext.get());
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()));
109 SECURITY_STATUS securityStatus = ERROR_SUCCESS;
112 DWORD policy = (NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG);
113 DWORD policySize =
sizeof(policy);
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));
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));
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));
141 DWORD privateKeySize = {};
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()));
150 std::vector<BYTE> privateKeyData(privateKeySize);
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();
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()));
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()));
176 QByteArray derData(derSize, Qt::Uninitialized);
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()));
186 *key = QSslKey(derData, QSsl::Rsa, QSsl::Der, QSsl::PrivateKey);
188 qCWarning(lcTlsBackendSchannel,
"Failed to parse private key from DER format");
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))
202 auto caCertificate = QSslCertificate_from_CERT_CONTEXT(caCertContext);
204 caCertificates->append(caCertificate);