[Libreoffice-commits] core.git: 2 commits - vcl/Library_vcl.mk vcl/source
Tor Lillqvist
tml at collabora.com
Fri Dec 5 06:24:44 PST 2014
vcl/Library_vcl.mk | 4
vcl/source/gdi/pdfwriter_impl.cxx | 220 ++++++++++++++++++++++++++++++++++++--
2 files changed, 212 insertions(+), 12 deletions(-)
New commits:
commit 7e3c931786c3cbe83ee170b8b0746d141b520ce6
Author: Tor Lillqvist <tml at collabora.com>
Date: Fri Dec 5 16:06:08 2014 +0200
fdo#87030: PDF signing using Windows API, work in progress
Started writing a Windows version of PDFWriterImpl::finalizeSignature(). The
certificate we get from the selection dialog (in xmlsecurity) is from the
Windows built-in store anyway, so it is pointless to try to use it with
NSS. (See bug for longer discussion.)
So far it was pretty straightforward. The WinCrypt API seems clean and easy to
use. But for some reason the CryptSignHash() call fails with "Keyset does not
exist" (NTE_BAD_KEYSET). What am I missing?
Anyway, comitting this now as it does compile and doesn't make things worse.
Change-Id: I0941995ad6e22c5487c6e6fe0084d3df0b2341c7
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 1adccab..7c8ccb5 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -60,7 +60,8 @@ $(eval $(call gb_Library_use_custom_headers,vcl,\
$(eval $(call gb_Library_use_externals,vcl,\
jpeg \
- nss3 \
+ $(if $(filter-out WNT,$(OS)), \
+ nss3) \
libeot \
))
@@ -674,6 +675,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
$(eval $(call gb_Library_use_system_win32_libs,vcl,\
advapi32 \
+ crypt32 \
gdi32 \
gdiplus \
glu32 \
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index f8cc4a2..b459a8d 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -68,8 +68,8 @@
#include "pdfwriter_impl.hxx"
-#if !defined(ANDROID) && !defined(IOS)
-// NSS header files for PDF signing support
+#if !defined(ANDROID) && !defined(IOS) && !defined(_WIN32)
+// NSS headers for PDF signing
#include "nss.h"
#include "cert.h"
#include "hasht.h"
@@ -78,6 +78,13 @@
#include "cmst.h"
#endif
+#ifdef _WIN32
+// WinCrypt headers for PDF signing
+#include <prewin.h>
+#include <wincrypt.h>
+#include <postwin.h>
+#endif
+
#include <config_eot.h>
#if ENABLE_EOT
@@ -5971,6 +5978,8 @@ bool PDFWriterImpl::emitSignature()
return true;
}
+#if !defined(ANDROID) && !defined(IOS) && !defined(_WIN32)
+
char *PDFSigningPKCS7PasswordCallback(PK11SlotInfo * /*slot*/, PRBool /*retry*/, void *arg)
{
return (char *)arg;
@@ -5987,6 +5996,39 @@ namespace {
};
}
+#endif
+
+#ifdef _WIN32
+
+namespace {
+
+OUString WindowsError(DWORD nErrorCode)
+{
+ LPWSTR pMsgBuf;
+
+ if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ nErrorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPWSTR)&pMsgBuf,
+ 0,
+ NULL) == 0)
+ return OUString::number(nErrorCode, 16);
+
+ if (pMsgBuf[wcslen(pMsgBuf)-1] == '\n')
+ pMsgBuf[wcslen(pMsgBuf)-1] = '\0';
+
+ OUString result(pMsgBuf);
+
+ LocalFree(pMsgBuf);
+
+ return result;
+}
+
+}
+
+#endif
+
bool PDFWriterImpl::finalizeSignature()
{
@@ -6021,7 +6063,7 @@ bool PDFWriterImpl::finalizeSignature()
sal_Int8* n_derArray = derEncoded.getArray();
sal_Int32 n_derLength = derEncoded.getLength();
- NSS_NoDB_Init(".");
+#ifndef _WIN32
CERTCertificate *cert = CERT_DecodeCertFromPackage(reinterpret_cast<char *>(n_derArray), n_derLength);
@@ -6170,6 +6212,170 @@ bool PDFWriterImpl::finalizeSignature()
CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, nOffset)) );
return true;
+
+#else
+
+ PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, reinterpret_cast<const BYTE*>(n_derArray), n_derLength);
+ if (pCertContext == NULL)
+ {
+ SAL_WARN("vcl.pdfwriter", "CertCreateCertificateContext failed: " << WindowsError(GetLastError()));
+ return false;
+ }
+
+#if SAL_LOG_INFO
+ DWORD nProperty(0);
+ bool first(true);
+ while ((nProperty = CertEnumCertificateContextProperties(pCertContext, nProperty)) != 0)
+ {
+ if (first)
+ SAL_INFO("vcl.pdfwriter", "Certificate context properties:");
+ first = false;
+#if 0
+ DWORD nSize(0);
+ if (!CertGetCertificateContextProperty(pCertContext, nProperty, NULL, &nSize))
+ SAL_INFO("vcl.pdfwriter", " " << "(missing?) " << std::hex << nProperty);
+ else
+ {
+ boost::scoped_array<char> aData(new char[nSize]);
+ if (!CertGetCertificateContextProperty(pCertContext, nProperty, aData.get(), &nSize))
+ SAL_INFO("vcl.pdfwriter", " " << "(missing?) " << std::hex:: << nProperty);
+ else
+ SAL_INFO("vcl.pdfwriter", " " << CertificatePropertyNameAndData(nProperty, aData, nSize));
+ }
+#else
+ SAL_INFO("vcl.pdfwriter", " " << std::hex << nProperty);
+#endif
+ }
+#endif
+
+ // Prepare buffer and calculate PDF file digest
+ CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, 0)) );
+
+ HCRYPTPROV hCryptProvider;
+ if (!CryptAcquireContext(&hCryptProvider, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ {
+ SAL_WARN("vcl.pdfwriter", "CryptAcquireContext failed: " << WindowsError(GetLastError()));
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ HCRYPTHASH hHash;
+ if (!CryptCreateHash(hCryptProvider, CALG_SHA1, 0, 0, &hHash))
+ {
+ SAL_WARN("vcl.pdfwriter", "CryptCreateHash failed: " << WindowsError(GetLastError()));
+ CryptReleaseContext(hCryptProvider, 0);
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ DWORD nHashSize;
+ DWORD nHashSizeLen(sizeof(DWORD));
+ if (!CryptGetHashParam(hHash, HP_HASHSIZE, reinterpret_cast<BYTE *>(&nHashSize), &nHashSizeLen, 0))
+ {
+ SAL_WARN("vcl.pdfwriter", "CryptGetHashParam failed: " << WindowsError(GetLastError()));
+ CryptDestroyHash(hHash);
+ CryptReleaseContext(hCryptProvider, 0);
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ assert(nHashSizeLen == sizeof(DWORD));
+ assert(nHashSize == 20);
+
+ boost::scoped_array<char> buffer(new char[m_nSignatureContentOffset + 1]);
+ sal_uInt64 bytesRead;
+
+ //FIXME: Check if SHA1 is calculated from the correct byterange
+ CHECK_RETURN( (osl::File::E_None == m_aFile.read(buffer.get(), m_nSignatureContentOffset - 1 , bytesRead)) );
+ if (bytesRead != (sal_uInt64)m_nSignatureContentOffset - 1)
+ SAL_WARN("vcl.pdfwriter", "PDF Signing: First buffer read failed!");
+
+ if (!CryptHashData(hHash, reinterpret_cast<const BYTE *>(buffer.get()), bytesRead, 0))
+ {
+ SAL_WARN("vcl.pdfwriter", "CryptHashData failed: " << WindowsError(GetLastError()));
+ CryptDestroyHash(hHash);
+ CryptReleaseContext(hCryptProvider, 0);
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, m_nSignatureContentOffset + MAX_SIGNATURE_CONTENT_LENGTH + 1)) );
+ buffer.reset(new char[nLastByteRangeNo + 1]);
+ CHECK_RETURN( (osl::File::E_None == m_aFile.read(buffer.get(), nLastByteRangeNo, bytesRead)) );
+ if (bytesRead != (sal_uInt64) nLastByteRangeNo)
+ SAL_WARN("vcl.pdfwriter", "PDF Signing: Second buffer read failed!");
+
+ if (!CryptHashData(hHash, reinterpret_cast<const BYTE *>(buffer.get()), bytesRead, 0))
+ {
+ SAL_WARN("vcl.pdfwriter", "CryptHashData failed: " << WindowsError(GetLastError()));
+ CryptDestroyHash(hHash);
+ CryptReleaseContext(hCryptProvider, 0);
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+#if 0 // We don't actualy need the hash bytes
+ unsigned char aHash[20];
+ if (!CryptGetHashParam(hHash, HP_HASHVAL, aHash, &nHashSize, 0))
+ {
+ SAL_WARN("vcl.pdfwriter", "CryptGetHashParam failed: " << WindowsError(GetLastError()));
+ CryptDestroyHash(hHash);
+ CryptReleaseContext(hCryptProvider, 0);
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ if (nHashSize != 20)
+ {
+ SAL_WARN("vcl.pdfwriter", "CryptGetHashParam returned unexpected size hash value: " << nHashSize);
+ CryptDestroyHash(hHash);
+ CryptReleaseContext(hCryptProvider, 0);
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+#endif
+
+ OString pass = OUStringToOString( m_aContext.SignPassword, RTL_TEXTENCODING_UTF8 );
+
+ DWORD nSigLen(0);
+ if (!CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, NULL, &nSigLen))
+ {
+ SAL_WARN("vcl.pdfwriter", "CryptSignHash failed: " << WindowsError(GetLastError()));
+ CryptDestroyHash(hHash);
+ CryptReleaseContext(hCryptProvider, 0);
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ boost::scoped_array<BYTE> pSig(new BYTE[nSigLen]);
+ if (!CryptSignHash(hHash, AT_SIGNATURE, NULL, 0, pSig.get(), &nSigLen))
+ {
+ SAL_WARN("vcl.pdfwriter", "CryptSignHash failed: " << WindowsError(GetLastError()));
+ CryptDestroyHash(hHash);
+ CryptReleaseContext(hCryptProvider, 0);
+ CertFreeCertificateContext(pCertContext);
+ return false;
+ }
+
+ // Release resources
+ CryptDestroyHash(hHash);
+ CryptReleaseContext(hCryptProvider, 0);
+ CertFreeCertificateContext(pCertContext);
+
+ OStringBuffer cms_hexbuffer;
+
+ for (unsigned int i = 0; i < nSigLen ; i++)
+ appendHex(pSig[i], cms_hexbuffer);
+
+ // Set file pointer to the m_nSignatureContentOffset, we're ready to overwrite PKCS7 object
+ nWritten = 0;
+ CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, m_nSignatureContentOffset)) );
+ m_aFile.write(cms_hexbuffer.getStr(), cms_hexbuffer.getLength(), nWritten);
+
+ CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, nOffset)) );
+
+ return true;
+#endif
}
#endif
commit c4cc31b5b55019aabad4045c8174b45e1b27073a
Author: Tor Lillqvist <tml at collabora.com>
Date: Fri Dec 5 11:50:30 2014 +0200
Remove noise SAL_WARNs that were not warnings, just informative messages
SAL_DEBUG is what should be used for stuff like that (and not committed).
Change-Id: I08505418bf9b55082e0d7672b85f3f76262dbad0
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 565d290..f8cc4a2 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6031,8 +6031,6 @@ bool PDFWriterImpl::finalizeSignature()
return false;
}
- SAL_WARN("vcl.pdfwriter", "PDF Signing: Certificate Subject: " << cert->subjectName << "\n\tCertificate Issuer: " << cert->issuerName);
-
// Prepare buffer and calculate PDF file digest
CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, 0)) );
@@ -6137,8 +6135,6 @@ bool PDFWriterImpl::finalizeSignature()
return false;
}
- SAL_WARN("vcl.pdfwriter","PKCS7 Object created successfully!");
-
SECItem cms_output;
cms_output.data = 0;
cms_output.len = 0;
@@ -6153,22 +6149,18 @@ bool PDFWriterImpl::finalizeSignature()
SAL_WARN("vcl.pdfwriter", "PDF Signing: can't start DER encoder.");
return false;
}
- SAL_WARN("vcl.pdfwriter", "PDF Signing: Started DER encoding.");
if (NSS_CMSEncoder_Finish(cms_ecx) != SECSuccess)
{
SAL_WARN("vcl.pdfwriter", "PDF Signing: can't finish DER encoder.");
return false;
}
- SAL_WARN("vcl.pdfwriter", "PDF Signing: Finished DER encoding.");
OStringBuffer cms_hexbuffer;
for (unsigned int i = 0; i < cms_output.len ; i++)
appendHex(cms_output.data[i], cms_hexbuffer);
- SAL_WARN("vcl.pdfwriter","PKCS7 object encoded successfully!");
-
// Set file pointer to the m_nSignatureContentOffset, we're ready to overwrite PKCS7 object
nWritten = 0;
CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, m_nSignatureContentOffset)) );
More information about the Libreoffice-commits
mailing list