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();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -296,12 +299,12 @@ bool PDFSignatureFactory::sign(const PDFCertificateEntry& certificateEntry, QStr
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
else
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
return signImpl_Win(certificateEntry, password, data, result);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
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");
|
||||
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;
|
||||
QByteArray testData(reinterpret_cast<const char*>(pointer), context->cbCertEncoded);
|
||||
const unsigned char* pointer = pCertContext->pbCertEncoded;
|
||||
QByteArray testData(reinterpret_cast<const char*>(pointer), pCertContext->cbCertEncoded);
|
||||
|
||||
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{};
|
||||
if (CryptAcquireCertificatePrivateKey(context, CRYPT_ACQUIRE_SILENT_FLAG, nullptr, &hCryptProv, NULL, NULL))
|
||||
{
|
||||
HCRYPTHASH hHash{};
|
||||
CRYPT_SIGN_MESSAGE_PARA SignParams{};
|
||||
BYTE* pbSignedBlob = nullptr;
|
||||
DWORD cbSignedBlob = 0;
|
||||
PCCERT_CONTEXT pCertContextArray[1] = { pCertContext };
|
||||
|
||||
CryptCreateHash(hCryptProv, CALG_SHA_256, 0, 0, &hHash);
|
||||
if (!hHash)
|
||||
{
|
||||
CryptCreateHash(hCryptProv, CALG_SHA1, 0, 0, &hHash);
|
||||
}
|
||||
const BYTE* pbDataToBeSigned = (const BYTE*)data.constData();
|
||||
DWORD cbDataToBeSigned = (DWORD)data.size();
|
||||
|
||||
if (hHash)
|
||||
{
|
||||
const BYTE* pDataToSign = reinterpret_cast<const BYTE*>(data.constData());
|
||||
const DWORD dwDataLen = data.size();
|
||||
// Nastavení parametrů pro podpis
|
||||
SignParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
|
||||
SignParams.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
|
||||
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
|
||||
if (CryptHashData(hHash, pDataToSign, dwDataLen, 0))
|
||||
{
|
||||
DWORD dwSigLen = 0;
|
||||
const BYTE* rgpbToBeSigned[1] = {pbDataToBeSigned};
|
||||
DWORD rgcbToBeSigned[1] = {cbDataToBeSigned};
|
||||
|
||||
// Retrieve length of signature
|
||||
if (CryptSignHash(hHash, AT_KEYEXCHANGE, NULL, 0, NULL, &dwSigLen))
|
||||
// Retrieve signed message size
|
||||
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
|
||||
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);
|
||||
result = QByteArray((const char*)pbSignedBlob, cbSignedBlob);
|
||||
success = true;
|
||||
}
|
||||
delete[] pbSignature;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CryptDestroyHash(hHash);
|
||||
}
|
||||
delete[] pbSignedBlob;
|
||||
|
||||
CryptReleaseContext(hCryptProv, 0);
|
||||
}
|
||||
|
||||
CertFreeCertificateContext(context);
|
||||
CertFreeCertificateContext(pCertContext);
|
||||
}
|
||||
|
||||
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(data);
|
||||
Q_UNUSED(result);
|
||||
Q_UNUSED(isDetermineLengthOnly);
|
||||
#endif
|
||||
|
||||
return success;
|
||||
|
|
|
@ -59,10 +59,16 @@ public:
|
|||
class PDF4QTLIBCORESHARED_EXPORT PDFSignatureFactory
|
||||
{
|
||||
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:
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue