mirror of https://github.com/JakubMelka/PDF4QT.git
Issue #55: Fix signing documents using Windows Certificate Store
This commit is contained in:
parent
56f5c4abcf
commit
d974912b05
|
@ -245,7 +245,10 @@ bool PDFCertificateManager::isCertificateValid(const PDFCertificateEntry& certif
|
||||||
return pkcs12data.isEmpty();
|
return pkcs12data.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PDFSignatureFactory::sign(const PDFCertificateEntry& certificateEntry, QString password, QByteArray data, QByteArray& result)
|
bool PDFSignatureFactory::sign(const PDFCertificateEntry& certificateEntry,
|
||||||
|
QString password,
|
||||||
|
QByteArray data,
|
||||||
|
QByteArray& result)
|
||||||
{
|
{
|
||||||
QByteArray pkcs12Data = certificateEntry.pkcs12;
|
QByteArray pkcs12Data = certificateEntry.pkcs12;
|
||||||
|
|
||||||
|
@ -296,12 +299,12 @@ bool PDFSignatureFactory::sign(const PDFCertificateEntry& certificateEntry, QStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
return signImpl_Win(certificateEntry, password, data, result);
|
return signImpl_Win(certificateEntry, password, data, result);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -327,12 +330,12 @@ bool pdf::PDFSignatureFactory::signImpl_Win(const pdf::PDFCertificateEntry& cert
|
||||||
HCERTSTORE certStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY");
|
HCERTSTORE certStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY");
|
||||||
if (certStore)
|
if (certStore)
|
||||||
{
|
{
|
||||||
PCCERT_CONTEXT context = nullptr;
|
PCCERT_CONTEXT pCertContext = nullptr;
|
||||||
|
|
||||||
while (context = CertEnumCertificatesInStore(certStore, context))
|
while (pCertContext = CertEnumCertificatesInStore(certStore, pCertContext))
|
||||||
{
|
{
|
||||||
const unsigned char* pointer = context->pbCertEncoded;
|
const unsigned char* pointer = pCertContext->pbCertEncoded;
|
||||||
QByteArray testData(reinterpret_cast<const char*>(pointer), context->cbCertEncoded);
|
QByteArray testData(reinterpret_cast<const char*>(pointer), pCertContext->cbCertEncoded);
|
||||||
|
|
||||||
if (testData == certificateEntry.info.getCertificateData())
|
if (testData == certificateEntry.info.getCertificateData())
|
||||||
{
|
{
|
||||||
|
@ -340,54 +343,61 @@ bool pdf::PDFSignatureFactory::signImpl_Win(const pdf::PDFCertificateEntry& cert
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context)
|
if (pCertContext)
|
||||||
{
|
{
|
||||||
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv{};
|
CRYPT_SIGN_MESSAGE_PARA SignParams{};
|
||||||
if (CryptAcquireCertificatePrivateKey(context, CRYPT_ACQUIRE_SILENT_FLAG, nullptr, &hCryptProv, NULL, NULL))
|
BYTE* pbSignedBlob = nullptr;
|
||||||
{
|
DWORD cbSignedBlob = 0;
|
||||||
HCRYPTHASH hHash{};
|
PCCERT_CONTEXT pCertContextArray[1] = { pCertContext };
|
||||||
|
|
||||||
CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &hHash);
|
const BYTE* pbDataToBeSigned = (const BYTE*)data.constData();
|
||||||
if (!hHash)
|
DWORD cbDataToBeSigned = (DWORD)data.size();
|
||||||
{
|
|
||||||
CryptCreateHash(hCryptProv, CALG_SHA1, 0, 0, &hHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hHash)
|
// Nastavení parametrů pro podpis
|
||||||
{
|
SignParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
|
||||||
const BYTE* pDataToSign = reinterpret_cast<const BYTE*>(data.constData());
|
SignParams.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
|
||||||
const DWORD dwDataLen = data.size();
|
SignParams.pSigningCert = pCertContext;
|
||||||
|
SignParams.HashAlgorithm.pszObjId = (LPSTR)szOID_RSA_SHA256RSA;
|
||||||
|
SignParams.HashAlgorithm.Parameters.cbData = 0;
|
||||||
|
SignParams.HashAlgorithm.Parameters.pbData = NULL;
|
||||||
|
SignParams.cMsgCert = 1;
|
||||||
|
SignParams.rgpMsgCert = pCertContextArray;
|
||||||
|
pCertContextArray[0] = pCertContext;
|
||||||
|
|
||||||
// Hash the data
|
const BYTE* rgpbToBeSigned[1] = {pbDataToBeSigned};
|
||||||
if (CryptHashData(hHash, pDataToSign, dwDataLen, 0))
|
DWORD rgcbToBeSigned[1] = {cbDataToBeSigned};
|
||||||
{
|
|
||||||
DWORD dwSigLen = 0;
|
|
||||||
|
|
||||||
// Retrieve length of signature
|
// Retrieve signed message size
|
||||||
if (CryptSignHash(hHash, AT_KEYEXCHANGE, NULL, 0, NULL, &dwSigLen))
|
CryptSignMessage(
|
||||||
|
&SignParams,
|
||||||
|
TRUE,
|
||||||
|
1,
|
||||||
|
rgpbToBeSigned,
|
||||||
|
rgcbToBeSigned,
|
||||||
|
NULL,
|
||||||
|
&cbSignedBlob
|
||||||
|
);
|
||||||
|
|
||||||
|
pbSignedBlob = new BYTE[cbSignedBlob];
|
||||||
|
|
||||||
|
// Create digital signature
|
||||||
|
if (CryptSignMessage(
|
||||||
|
&SignParams,
|
||||||
|
TRUE,
|
||||||
|
1,
|
||||||
|
rgpbToBeSigned,
|
||||||
|
rgcbToBeSigned,
|
||||||
|
pbSignedBlob,
|
||||||
|
&cbSignedBlob
|
||||||
|
))
|
||||||
{
|
{
|
||||||
// Allocate memory for signature
|
result = QByteArray((const char*)pbSignedBlob, cbSignedBlob);
|
||||||
BYTE* pbSignature = new BYTE[dwSigLen];
|
|
||||||
if(pbSignature != nullptr)
|
|
||||||
{
|
|
||||||
// Sign the hash
|
|
||||||
if(CryptSignHash(hHash, AT_KEYEXCHANGE, NULL, 0, pbSignature, &dwSigLen))
|
|
||||||
{
|
|
||||||
result = QByteArray(reinterpret_cast<const char*>(pbSignature), dwSigLen);
|
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
delete[] pbSignature;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CryptDestroyHash(hHash);
|
delete[] pbSignedBlob;
|
||||||
}
|
|
||||||
|
|
||||||
CryptReleaseContext(hCryptProv, 0);
|
CertFreeCertificateContext(pCertContext);
|
||||||
}
|
|
||||||
|
|
||||||
CertFreeCertificateContext(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CertCloseStore(certStore, CERT_CLOSE_STORE_FORCE_FLAG);
|
CertCloseStore(certStore, CERT_CLOSE_STORE_FORCE_FLAG);
|
||||||
|
@ -397,6 +407,7 @@ bool pdf::PDFSignatureFactory::signImpl_Win(const pdf::PDFCertificateEntry& cert
|
||||||
Q_UNUSED(password);
|
Q_UNUSED(password);
|
||||||
Q_UNUSED(data);
|
Q_UNUSED(data);
|
||||||
Q_UNUSED(result);
|
Q_UNUSED(result);
|
||||||
|
Q_UNUSED(isDetermineLengthOnly);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
|
|
@ -59,10 +59,16 @@ public:
|
||||||
class PDF4QTLIBCORESHARED_EXPORT PDFSignatureFactory
|
class PDF4QTLIBCORESHARED_EXPORT PDFSignatureFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool sign(const PDFCertificateEntry& certificateEntry, QString password, QByteArray data, QByteArray& result);
|
static bool sign(const PDFCertificateEntry& certificateEntry,
|
||||||
|
QString password,
|
||||||
|
QByteArray data,
|
||||||
|
QByteArray& result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool signImpl_Win(const PDFCertificateEntry& certificateEntry, QString password, QByteArray data, QByteArray& result);
|
static bool signImpl_Win(const PDFCertificateEntry& certificateEntry,
|
||||||
|
QString password,
|
||||||
|
QByteArray data,
|
||||||
|
QByteArray& result);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
Loading…
Reference in New Issue