podofo-svn Mailing List for PoDoFo
A PDF parsing, modification and creation library.
Brought to you by:
domseichter
This list is closed, nobody may subscribe to it.
2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(39) |
Jul
(42) |
Aug
(134) |
Sep
(48) |
Oct
(105) |
Nov
(19) |
Dec
(9) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
(48) |
Feb
(70) |
Mar
(26) |
Apr
(13) |
May
(49) |
Jun
(40) |
Jul
(49) |
Aug
(34) |
Sep
(49) |
Oct
(20) |
Nov
(71) |
Dec
(4) |
2008 |
Jan
(14) |
Feb
(2) |
Mar
(6) |
Apr
(24) |
May
(33) |
Jun
(36) |
Jul
(12) |
Aug
(26) |
Sep
(37) |
Oct
(35) |
Nov
(10) |
Dec
(15) |
2009 |
Jan
(4) |
Feb
(1) |
Mar
(9) |
Apr
(39) |
May
(14) |
Jun
(17) |
Jul
(46) |
Aug
(37) |
Sep
(3) |
Oct
(8) |
Nov
(7) |
Dec
(13) |
2010 |
Jan
(3) |
Feb
(18) |
Mar
(5) |
Apr
(23) |
May
(16) |
Jun
(19) |
Jul
(7) |
Aug
(29) |
Sep
(12) |
Oct
(43) |
Nov
(20) |
Dec
(14) |
2011 |
Jan
(22) |
Feb
(5) |
Mar
(36) |
Apr
(12) |
May
(2) |
Jun
(4) |
Jul
(3) |
Aug
(1) |
Sep
(4) |
Oct
(8) |
Nov
(2) |
Dec
(6) |
2012 |
Jan
(6) |
Feb
|
Mar
(2) |
Apr
|
May
(4) |
Jun
(2) |
Jul
(2) |
Aug
|
Sep
|
Oct
(2) |
Nov
|
Dec
(3) |
2013 |
Jan
|
Feb
(6) |
Mar
(3) |
Apr
(1) |
May
(24) |
Jun
(2) |
Jul
(12) |
Aug
(3) |
Sep
(1) |
Oct
(17) |
Nov
|
Dec
|
2014 |
Jan
(2) |
Feb
(1) |
Mar
(4) |
Apr
(11) |
May
(4) |
Jun
(47) |
Jul
(13) |
Aug
|
Sep
(4) |
Oct
|
Nov
|
Dec
|
2015 |
Jan
|
Feb
(2) |
Mar
(2) |
Apr
(2) |
May
(1) |
Jun
(2) |
Jul
(2) |
Aug
(2) |
Sep
(4) |
Oct
(7) |
Nov
(10) |
Dec
(2) |
2016 |
Jan
|
Feb
(2) |
Mar
|
Apr
(16) |
May
(45) |
Jun
(8) |
Jul
(6) |
Aug
(1) |
Sep
(3) |
Oct
(7) |
Nov
(13) |
Dec
(5) |
2017 |
Jan
(15) |
Feb
(4) |
Mar
(3) |
Apr
(8) |
May
(8) |
Jun
(5) |
Jul
(2) |
Aug
(1) |
Sep
(1) |
Oct
(2) |
Nov
|
Dec
(3) |
2018 |
Jan
(12) |
Feb
(17) |
Mar
(12) |
Apr
(16) |
May
(1) |
Jun
(1) |
Jul
(5) |
Aug
(5) |
Sep
(6) |
Oct
(3) |
Nov
(7) |
Dec
(3) |
2019 |
Jan
(4) |
Feb
(10) |
Mar
(5) |
Apr
(6) |
May
(12) |
Jun
(2) |
Jul
(3) |
Aug
(1) |
Sep
(1) |
Oct
|
Nov
|
Dec
|
2020 |
Jan
|
Feb
|
Mar
(8) |
Apr
|
May
(4) |
Jun
(2) |
Jul
|
Aug
(2) |
Sep
|
Oct
(3) |
Nov
|
Dec
(2) |
2021 |
Jan
(15) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(2) |
Aug
(10) |
Sep
|
Oct
|
Nov
(1) |
Dec
(1) |
2022 |
Jan
(1) |
Feb
|
Mar
(6) |
Apr
(5) |
May
(5) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2023 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(2) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Ulrich A. <Ulr...@t-...> - 2023-05-15 16:02:08
|
Sorry forgot to add the patch. Regards Uli Von: Ulrich Arnold <Ulr...@t-...> Gesendet: Montag, 15. Mai 2023 18:00 An: 'pod...@li...' <pod...@li...> Betreff: Patch for PoDoFo Build 2033 Hi! I think I found a small bug in the code for setting creation- and modification-date. At least in the WIN32-branch daylight-saving-time is not taken into account, resulting in Acrobat showing the time 1 hour off. According to Pdf-Docs 1.7 chapter 7.9.4 the time format is local time followed by the absolute difference to UTC. For Germany this would be +1h due to time zone, but +2h during active daylight-saving-time. Attached is the patch against build 2033. I don't know if it is necessary in the other branch too. Regards Uli |
From: Ulrich A. <Ulr...@t-...> - 2023-05-15 16:00:11
|
Hi! I think I found a small bug in the code for setting creation- and modification-date. At least in the WIN32-branch daylight-saving-time is not taken into account, resulting in Acrobat showing the time 1 hour off. According to Pdf-Docs 1.7 chapter 7.9.4 the time format is local time followed by the absolute difference to UTC. For Germany this would be +1h due to time zone, but +2h during active daylight-saving-time. Attached is the patch against build 2033. I don't know if it is necessary in the other branch too. Regards Uli |
From: <dom...@us...> - 2022-05-03 13:02:48
|
Revision: 2063 http://sourceforge.net/p/podofo/code/2063 Author: domseichter Date: 2022-05-03 13:02:45 +0000 (Tue, 03 May 2022) Log Message: ----------- test commit Modified Paths: -------------- podofo/trunk/README.html Modified: podofo/trunk/README.html =================================================================== --- podofo/trunk/README.html 2022-05-03 12:27:59 UTC (rev 2062) +++ podofo/trunk/README.html 2022-05-03 13:02:45 UTC (rev 2063) @@ -3,7 +3,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> -<title>PoDoFo Readme</title> + <title>PoDoFo Readme</title> </head> <body> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dom...@us...> - 2022-05-03 12:28:01
|
Revision: 2062 http://sourceforge.net/p/podofo/code/2062 Author: domseichter Date: 2022-05-03 12:27:59 +0000 (Tue, 03 May 2022) Log Message: ----------- Release branching Added Paths: ----------- podofo/branches/PODOFO_0_9_8_BRANCH/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dom...@us...> - 2022-05-03 12:27:27
|
Revision: 2061 http://sourceforge.net/p/podofo/code/2061 Author: domseichter Date: 2022-05-03 12:27:24 +0000 (Tue, 03 May 2022) Log Message: ----------- Tagging release 0.9.8 Added Paths: ----------- podofo/tags/RELEASE_0_9_8/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dom...@us...> - 2022-05-03 12:18:25
|
Revision: 2060 http://sourceforge.net/p/podofo/code/2060 Author: domseichter Date: 2022-05-03 12:18:23 +0000 (Tue, 03 May 2022) Log Message: ----------- Version bump to 0.9.8 Modified Paths: -------------- podofo/trunk/CMakeLists.txt Modified: podofo/trunk/CMakeLists.txt =================================================================== --- podofo/trunk/CMakeLists.txt 2022-05-03 06:43:03 UTC (rev 2059) +++ podofo/trunk/CMakeLists.txt 2022-05-03 12:18:23 UTC (rev 2060) @@ -12,7 +12,7 @@ SET(PODOFO_VERSION_MAJOR "0" CACHE STRING "Major part of PoDoFo version number") SET(PODOFO_VERSION_MINOR "9" CACHE STRING "Minor part of PoDoFo version number") -SET(PODOFO_VERSION_PATCH "7" CACHE STRING "Patchlevel part of PoDoFo version number") +SET(PODOFO_VERSION_PATCH "8" CACHE STRING "Patchlevel part of PoDoFo version number") SET(PODOFO_SOVERSION "${PODOFO_VERSION_MAJOR}.${PODOFO_VERSION_MINOR}.${PODOFO_VERSION_PATCH}") SET(PODOFO_LIBVERSION "${PODOFO_SOVERSION}") This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2022-05-03 06:43:05
|
Revision: 2059 http://sourceforge.net/p/podofo/code/2059 Author: mc-zyx Date: 2022-05-03 06:43:03 +0000 (Tue, 03 May 2022) Log Message: ----------- podofosign: Default to SHA512 and add argument to change the digest The OpenSSL defaults to SHA1, which is not good enough these days, thus default to SHA512. Also add a "-digest" argument to be able to change the digest algorithm on the fly. Modified Paths: -------------- podofo/trunk/tools/podofosign/podofosign.cpp Modified: podofo/trunk/tools/podofosign/podofosign.cpp =================================================================== --- podofo/trunk/tools/podofosign/podofosign.cpp 2022-04-28 05:19:22 UTC (rev 2058) +++ podofo/trunk/tools/podofosign/podofosign.cpp 2022-05-03 06:43:03 UTC (rev 2059) @@ -182,7 +182,7 @@ return true; } -static void sign_with_signer( PdfSignOutputDevice &signer, X509 *cert, EVP_PKEY *pkey ) +static void sign_with_signer( PdfSignOutputDevice &signer, X509 *cert, EVP_PKEY *pkey, const EVP_MD *md_digest ) { if( !cert ) PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "cert == NULL" ); @@ -211,7 +211,7 @@ } unsigned int flags = PKCS7_DETACHED | PKCS7_BINARY; - PKCS7 *pkcs7 = PKCS7_sign( cert, pkey, NULL, mem, flags ); + PKCS7 *pkcs7 = PKCS7_sign( cert, pkey, NULL, mem, flags | PKCS7_PARTIAL ); if( !pkcs7 ) { BIO_free( mem ); @@ -219,6 +219,14 @@ raise_podofo_error_with_opensslerror( "PKCS7_sign failed" ); } + if( !PKCS7_sign_add_signer( pkcs7, cert, pkey, md_digest, 0 )) + { + BIO_free( mem ); + PKCS7_free( pkcs7 ); + podofo_free( pBuffer ); + raise_podofo_error_with_opensslerror( "PKCS7_sign_add_signer failed" ); + } + while( len = signer.ReadForSignature( pBuffer, uBufferLen ), len > 0 ) { rc = BIO_write( mem, pBuffer, len ); @@ -298,6 +306,7 @@ std::cout << "The optional arguments:" << std::endl; std::cout << " -out [outputfile] ... an output file to save the signed document to; cannot be the same as the input file" << std::endl; std::cout << " -password [password] ... a password to unlock the private key file" << std::endl; + std::cout << " -digest [name] ... a digest name to use for the signature; default is SHA512" << std::endl; std::cout << " -reason [utf8-string] ... a UTF-8 encoded string with the reason of the signature; default reason is \"I agree\"" << std::endl; std::cout << " -sigsize [size] ... how many bytes to allocate for the signature; the default is derived from the certificate and private key file size" << std::endl; std::cout << " -field-name [name] ... field name to use; defaults to 'PoDoFoSignatureFieldXXX', where XXX is the object number" << std::endl; @@ -696,6 +705,7 @@ const char *certfile = NULL; const char *pkeyfile = NULL; const char *password = NULL; + const char *digest = NULL; const char *reason = "I agree"; const char *sigsizestr = NULL; const char *annot_units = "mm"; @@ -729,6 +739,10 @@ { value = &pkeyfile; } + else if( strcmp( argv[ii], "-digest" ) == 0 ) + { + value = &digest; + } else if( strcmp( argv[ii], "-password" ) == 0 ) { value = &password; @@ -896,6 +910,8 @@ if( sigsize > 0 ) min_signature_size = sigsize; + else + min_signature_size += 1024; int result = 0; PdfSignatureField *pSignField = NULL; @@ -903,6 +919,26 @@ try { + const EVP_MD *md_digest; + + if( digest != NULL ) + { + md_digest = EVP_get_digestbyname( digest ); + if( !md_digest ) + { + std::string err = "Unknown digest '"; + err += digest; + err += "'"; + PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidName, err.c_str() ); + } + } + else + { + md_digest = EVP_sha512(); + if( !md_digest ) + std::cerr << "Cannot get SHA512 digest, using default OpenSSL digest instead." << std::endl; + } + PdfMemDocument document; document.Load( inputfile, true ); @@ -1075,7 +1111,7 @@ // We seek at the beginning of the file signer.Seek( 0 ); - sign_with_signer( signer, cert, pkey ); + sign_with_signer( signer, cert, pkey, md_digest ); signer.Flush(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2022-04-28 05:19:24
|
Revision: 2058 http://sourceforge.net/p/podofo/code/2058 Author: mc-zyx Date: 2022-04-28 05:19:22 +0000 (Thu, 28 Apr 2022) Log Message: ----------- Patch by Wolfgang Stoeggl: Fix -Wmemset-elt-size warnings Multiply the number of elements (LF_FACESIZE) by the element size, which fixes the following warnings: src/podofo/doc/PdfFontCache.cpp:711:11: warning: 'memset' used with length equal to number of elements without multiplication by element size [-Wmemset-elt-size] 711 | memset(&(lf.lfFaceName), 0, LF_FACESIZE); src/podofo/doc/PdfFontCache.cpp:744:11: warning: 'memset' used with length equal to number of elements without multiplication by element size [-Wmemset-elt-size] 744 | memset(&(lf.lfFaceName), 0, LF_FACESIZE); Modified Paths: -------------- podofo/trunk/src/podofo/doc/PdfFontCache.cpp Modified: podofo/trunk/src/podofo/doc/PdfFontCache.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfFontCache.cpp 2022-04-28 05:12:46 UTC (rev 2057) +++ podofo/trunk/src/podofo/doc/PdfFontCache.cpp 2022-04-28 05:19:22 UTC (rev 2058) @@ -708,7 +708,7 @@ if (strlen(pszFontName) >= LF_FACESIZE) return NULL; - memset(&(lf.lfFaceName), 0, LF_FACESIZE); + memset(&(lf.lfFaceName), 0, sizeof(lf.lfFaceName[0]) * LF_FACESIZE); //strcpy( lf.lfFaceName, pszFontName ); /*int destLen =*/ MultiByteToWideChar (0, 0, pszFontName, -1, lf.lfFaceName, LF_FACESIZE); @@ -741,7 +741,7 @@ if (lFontNameLen == 0) PODOFO_RAISE_ERROR_INFO(ePdfError_InternalLogic, "Font name is empty"); - memset(&(lf.lfFaceName), 0, LF_FACESIZE); + memset(&(lf.lfFaceName), 0, sizeof(lf.lfFaceName[0]) * LF_FACESIZE); wcscpy( static_cast<wchar_t*>(lf.lfFaceName), pszFontName ); return GetWin32Font(itSorted, vecContainer, lf, bEmbedd, pEncoding, pSubsetting); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2022-04-28 05:12:48
|
Revision: 2057 http://sourceforge.net/p/podofo/code/2057 Author: mc-zyx Date: 2022-04-28 05:12:46 +0000 (Thu, 28 Apr 2022) Log Message: ----------- Patch by Wolfgang Stoeggl: Add missing guards to header files Modified Paths: -------------- podofo/trunk/src/podofo/base/PdfOutputStream.h podofo/trunk/src/podofo/base/util/PdfMutexImpl_noop.h podofo/trunk/src/podofo/base/util/PdfMutexImpl_pthread.h podofo/trunk/src/podofo/base/util/PdfMutexImpl_win32.h podofo/trunk/src/podofo/doc/PdfDifferenceEncoding.cpp podofo/trunk/test/PdfTest.h podofo/trunk/test/unit/cppunitextensions.h podofo/trunk/tools/podofocolor/lua_compat.h podofo/trunk/tools/podofoimg2pdf/ImageConverter.h podofo/trunk/tools/podofoimpose/lua_compat.h Modified: podofo/trunk/src/podofo/base/PdfOutputStream.h =================================================================== --- podofo/trunk/src/podofo/base/PdfOutputStream.h 2022-04-19 13:51:50 UTC (rev 2056) +++ podofo/trunk/src/podofo/base/PdfOutputStream.h 2022-04-28 05:12:46 UTC (rev 2057) @@ -163,6 +163,13 @@ inline pdf_long GetLength() const; /** + * \returns a const handle to the internal buffer. + * + * The returned buffer is still owned by the PdfMemoryOutputStream. + */ + inline const char* GetBuffer() const; + + /** * \returns a handle to the internal buffer. * * The internal buffer is now owned by the caller @@ -193,6 +200,14 @@ // ----------------------------------------------------- // // ----------------------------------------------------- +inline const char* PdfMemoryOutputStream::GetBuffer() const +{ + return m_pBuffer; +} + +// ----------------------------------------------------- +// +// ----------------------------------------------------- inline char* PdfMemoryOutputStream::TakeBuffer() { char* pBuffer = m_pBuffer; Modified: podofo/trunk/src/podofo/base/util/PdfMutexImpl_noop.h =================================================================== --- podofo/trunk/src/podofo/base/util/PdfMutexImpl_noop.h 2022-04-19 13:51:50 UTC (rev 2056) +++ podofo/trunk/src/podofo/base/util/PdfMutexImpl_noop.h 2022-04-28 05:12:46 UTC (rev 2057) @@ -31,6 +31,9 @@ * files in the program, then also delete it here. * ***************************************************************************/ +#ifndef PDFMUTEXIMPL_NOOP_H +#define PDFMUTEXIMPL_NOOP_H + #include "../PdfDefines.h" #include "../PdfDefinesPrivate.h" @@ -77,3 +80,5 @@ }; // Util }; // PoDoFo + +#endif // PDFMUTEXIMPL_NOOP_H Modified: podofo/trunk/src/podofo/base/util/PdfMutexImpl_pthread.h =================================================================== --- podofo/trunk/src/podofo/base/util/PdfMutexImpl_pthread.h 2022-04-19 13:51:50 UTC (rev 2056) +++ podofo/trunk/src/podofo/base/util/PdfMutexImpl_pthread.h 2022-04-28 05:12:46 UTC (rev 2057) @@ -31,6 +31,9 @@ * files in the program, then also delete it here. * ***************************************************************************/ +#ifndef PDFMUTEXIMPL_PTHREAD_H +#define PDFMUTEXIMPL_PTHREAD_H + #include "../PdfDefines.h" #include "../PdfDefinesPrivate.h" @@ -129,3 +132,5 @@ }; // Util }; // PoDoFo + +#endif // PDFMUTEXIMPL_PTHREAD_H Modified: podofo/trunk/src/podofo/base/util/PdfMutexImpl_win32.h =================================================================== --- podofo/trunk/src/podofo/base/util/PdfMutexImpl_win32.h 2022-04-19 13:51:50 UTC (rev 2056) +++ podofo/trunk/src/podofo/base/util/PdfMutexImpl_win32.h 2022-04-28 05:12:46 UTC (rev 2057) @@ -31,6 +31,9 @@ * files in the program, then also delete it here. * ***************************************************************************/ +#ifndef PDFMUTEXIMPL_WIN32_H +#define PDFMUTEXIMPL_WIN32_H + #include "../PdfDefines.h" #include "../PdfDefinesPrivate.h" @@ -121,3 +124,5 @@ }; // Util }; // PoDoFo + +#endif // PDFMUTEXIMPL_WIN32_H Modified: podofo/trunk/src/podofo/doc/PdfDifferenceEncoding.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfDifferenceEncoding.cpp 2022-04-19 13:51:50 UTC (rev 2056) +++ podofo/trunk/src/podofo/doc/PdfDifferenceEncoding.cpp 2022-04-28 05:12:46 UTC (rev 2057) @@ -2299,6 +2299,7 @@ bool PdfEncodingDifference::ContainsUnicodeValue( pdf_utf16be unicodeValue, char &rValue ) const { + printf ("%s:\n", __FUNCTION__); TCIVecDifferences it, end = m_vecDifferences.end(); for (it = m_vecDifferences.begin(); it != end; it++) { pdf_utf16be uv = it->unicodeValue; Modified: podofo/trunk/test/PdfTest.h =================================================================== --- podofo/trunk/test/PdfTest.h 2022-04-19 13:51:50 UTC (rev 2056) +++ podofo/trunk/test/PdfTest.h 2022-04-28 05:12:46 UTC (rev 2057) @@ -1,4 +1,7 @@ +#ifndef PDFTEST_H +#define PDFTEST_H + #include <podofo.h> /* Common defines needed in all tests */ @@ -20,3 +23,5 @@ #else #define PODOFO_UNIQUEU_PTR std::auto_ptr #endif + +#endif // PDFTEST_H Modified: podofo/trunk/test/unit/cppunitextensions.h =================================================================== --- podofo/trunk/test/unit/cppunitextensions.h 2022-04-19 13:51:50 UTC (rev 2056) +++ podofo/trunk/test/unit/cppunitextensions.h 2022-04-28 05:12:46 UTC (rev 2057) @@ -18,6 +18,9 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#ifndef CPPUNITEXTENSIONS_H +#define CPPUNITEXTENSIONS_H + #include <cppunit/extensions/HelperMacros.h> #include <new> #include <exception> @@ -98,3 +101,4 @@ #define EXPECT_DOUBLE_EQ(expected, actual, delta) CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta) #define ASSERT_DOUBLE_EQ(expected, actual, delta) CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta) +#endif // CPPUNITEXTENSIONS_H Modified: podofo/trunk/tools/podofocolor/lua_compat.h =================================================================== --- podofo/trunk/tools/podofocolor/lua_compat.h 2022-04-19 13:51:50 UTC (rev 2056) +++ podofo/trunk/tools/podofocolor/lua_compat.h 2022-04-28 05:12:46 UTC (rev 2057) @@ -1,3 +1,6 @@ +#ifndef LUA_COMPAT_H_COLOR +#define LUA_COMPAT_H_COLOR + extern "C" { #include "lua.h" // Note: If you're missing these, you're using lua 5.0 and haven't installed @@ -46,3 +49,5 @@ return luaL_getn(L, t); } #endif + +#endif // LUA_COMPAT_H_COLOR Modified: podofo/trunk/tools/podofoimg2pdf/ImageConverter.h =================================================================== --- podofo/trunk/tools/podofoimg2pdf/ImageConverter.h 2022-04-19 13:51:50 UTC (rev 2056) +++ podofo/trunk/tools/podofoimg2pdf/ImageConverter.h 2022-04-28 05:12:46 UTC (rev 2057) @@ -18,6 +18,9 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#ifndef IMAGECONVERTER_H +#define IMAGECONVERTER_H + #include <string> #include <vector> @@ -45,3 +48,5 @@ std::string m_sOutputFilename; bool m_bUseImageSize; }; + +#endif // IMAGECONVERTER_H Modified: podofo/trunk/tools/podofoimpose/lua_compat.h =================================================================== --- podofo/trunk/tools/podofoimpose/lua_compat.h 2022-04-19 13:51:50 UTC (rev 2056) +++ podofo/trunk/tools/podofoimpose/lua_compat.h 2022-04-28 05:12:46 UTC (rev 2057) @@ -1,3 +1,6 @@ +#ifndef LUA_COMPAT_H_IMPOSE +#define LUA_COMPAT_H_IMPOSE + extern "C" { #include "lua.h" // Note: If you're missing these, you're using lua 5.0 and haven't installed @@ -34,3 +37,5 @@ return lua_dofile(L, path); } #endif + +#endif // LUA_COMPAT_H_IMPOSE This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2022-04-19 13:51:52
|
Revision: 2056 http://sourceforge.net/p/podofo/code/2056 Author: mc-zyx Date: 2022-04-19 13:51:50 +0000 (Tue, 19 Apr 2022) Log Message: ----------- Patch by Wolfgang Stoeggl: Silence unknown pragma warnings under MINGW The "#pragma warning(disable : 28125)" is intended for Visual Studio (MSVC) builds. Check first, if _MSC_VER is defined. - This silences the following warnings, when compiling under Windows using gcc (MINGW): src/podofo/base/util/PdfMutexImpl_win32.h:90: warning: ignoring '#pragma warning ' [-Wunknown-pragmas] 90 | #pragma warning(disable : 28125) src/podofo/base/util/PdfMutexImpl_win32.h:96: warning: ignoring '#pragma warning ' [-Wunknown-pragmas] 96 | #pragma warning(default : 28125) Modified Paths: -------------- podofo/trunk/src/podofo/base/util/PdfMutexImpl_win32.h Modified: podofo/trunk/src/podofo/base/util/PdfMutexImpl_win32.h =================================================================== --- podofo/trunk/src/podofo/base/util/PdfMutexImpl_win32.h 2022-04-14 05:32:28 UTC (rev 2055) +++ podofo/trunk/src/podofo/base/util/PdfMutexImpl_win32.h 2022-04-19 13:51:50 UTC (rev 2056) @@ -86,13 +86,13 @@ // on Windows XP / Server 2003. The exception was eliminated in Windows Vista / Server 2008, // so don't warn if building for Vista or later. -#if ( WINVER >= _WIN32_WINNT_VISTA ) +#if defined(_MSC_VER) && ( WINVER >= _WIN32_WINNT_VISTA ) #pragma warning(disable : 28125) #endif InitializeCriticalSection( &m_cs ); -#if ( WINVER >= _WIN32_WINNT_VISTA ) +#if defined(_MSC_VER) && ( WINVER >= _WIN32_WINNT_VISTA ) #pragma warning(default : 28125) #endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2022-04-14 05:32:30
|
Revision: 2055 http://sourceforge.net/p/podofo/code/2055 Author: mc-zyx Date: 2022-04-14 05:32:28 +0000 (Thu, 14 Apr 2022) Log Message: ----------- Patch by Mark Rogers: Check that /DecodeParams values are in range (CVE-2018-20797) Modified Paths: -------------- podofo/trunk/src/podofo/base/PdfFiltersPrivate.cpp podofo/trunk/src/podofo/base/PdfMemoryManagement.cpp podofo/trunk/src/podofo/base/PdfMemoryManagement.h Modified: podofo/trunk/src/podofo/base/PdfFiltersPrivate.cpp =================================================================== --- podofo/trunk/src/podofo/base/PdfFiltersPrivate.cpp 2022-04-11 06:07:37 UTC (rev 2054) +++ podofo/trunk/src/podofo/base/PdfFiltersPrivate.cpp 2022-04-14 05:32:28 UTC (rev 2055) @@ -93,6 +93,14 @@ m_nBPC = static_cast<int>(pDecodeParms->GetKeyAsLong( "BitsPerComponent", 8L )); m_nColumns = static_cast<int>(pDecodeParms->GetKeyAsLong( "Columns", 1L )); m_nEarlyChange = static_cast<int>(pDecodeParms->GetKeyAsLong( "EarlyChange", 1L )); + + // check that input values are in range (CVE-2018-20797) + // ISO 32000-2008 specifies these values as all 1 or greater + // negative values for m_nColumns / m_nColors / m_nBPC result in huge podofo_calloc + if ( m_nColumns < 1 || m_nColors < 1 || m_nBPC < 1 ) + { + PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); + } if( m_nPredictor >= 10) { @@ -109,6 +117,18 @@ m_nBpp = (m_nBPC * m_nColors) >> 3; m_nRows = (m_nColumns * m_nColors * m_nBPC) >> 3; + // check for multiplication overflow on buffer sizes (e.g. if m_nBPC=2 and m_nColors=SIZE_MAX/2+1) + if ( podofo_multiplication_overflow( m_nBPC, m_nColors ) || podofo_multiplication_overflow( m_nColumns, m_nBPC * m_nColors ) ) + { + PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); + } + + // check that computed allocation sizes are > 0 (CVE-2018-20797) + if ( m_nRows < 1 || m_nBpp < 1 ) + { + PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); + } + m_pPrev = static_cast<char*>(podofo_calloc( m_nRows, sizeof(char) )); if( !m_pPrev ) { Modified: podofo/trunk/src/podofo/base/PdfMemoryManagement.cpp =================================================================== --- podofo/trunk/src/podofo/base/PdfMemoryManagement.cpp 2022-04-11 06:07:37 UTC (rev 2054) +++ podofo/trunk/src/podofo/base/PdfMemoryManagement.cpp 2022-04-14 05:32:28 UTC (rev 2055) @@ -113,21 +113,7 @@ if (nmemb == 0) nmemb = 1; - /* - This overflow check is from OpenBSD reallocarray.c, and is also used in GifLib 5.1.2 onwards. - - Very old versions of calloc() in NetBSD and OS X 10.4 just multiplied size*nmemb which can - overflow size_t and allocate much less memory than expected e.g. 2*(SIZE_MAX/2+1) = 2 bytes. - The calloc() overflow is also present in GCC 3.1.1, GNU Libc 2.2.5 and Visual C++ 6. - http://cert.uni-stuttgart.de/ticker/advisories/calloc.html - - MUL_NO_OVERFLOW is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX - if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW - */ - #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) - - if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && - nmemb > 0 && SIZE_MAX / nmemb < size) + if ( podofo_multiplication_overflow( nmemb, size ) ) { errno = ENOMEM; return NULL; @@ -167,6 +153,30 @@ free( buffer ); } +bool podofo_multiplication_overflow(size_t nmemb, size_t size) +{ + /* + This overflow check is from OpenBSD reallocarray.c, and is also used in GifLib 5.1.2 onwards. + + Very old versions of calloc() in NetBSD and OS X 10.4 just multiplied size*nmemb which can + overflow size_t and allocate much less memory than expected e.g. 2*(SIZE_MAX/2+1) = 2 bytes. + The calloc() overflow is also present in GCC 3.1.1, GNU Libc 2.2.5 and Visual C++ 6. + http://cert.uni-stuttgart.de/ticker/advisories/calloc.html + + MUL_NO_OVERFLOW is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ + #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) + + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && SIZE_MAX / nmemb < size) + { + return true; + } + + return false; +} + }; // OC 17.08.2010: Activate showing the correct source for Memory Leak Detection in Visual Studio: Modified: podofo/trunk/src/podofo/base/PdfMemoryManagement.h =================================================================== --- podofo/trunk/src/podofo/base/PdfMemoryManagement.h 2022-04-11 06:07:37 UTC (rev 2054) +++ podofo/trunk/src/podofo/base/PdfMemoryManagement.h 2022-04-14 05:32:28 UTC (rev 2055) @@ -75,6 +75,11 @@ */ PODOFO_API bool podofo_is_little_endian(); +/** + * Check if multiplying two numbers will overflow. This is crucial when calculating buffer sizes that are the product of two numbers/ + * \returns true if multiplication will overflow + */ +PODOFO_API bool podofo_multiplication_overflow( size_t nmemb, size_t size ); }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2022-04-11 06:07:39
|
Revision: 2054 http://sourceforge.net/p/podofo/code/2054 Author: mc-zyx Date: 2022-04-11 06:07:37 +0000 (Mon, 11 Apr 2022) Log Message: ----------- Patch by F.E.: Ignore "/Prev 0" in trailer Modified Paths: -------------- podofo/trunk/src/podofo/base/PdfParser.cpp Modified: podofo/trunk/src/podofo/base/PdfParser.cpp =================================================================== --- podofo/trunk/src/podofo/base/PdfParser.cpp 2022-03-12 17:45:24 UTC (rev 2053) +++ podofo/trunk/src/podofo/base/PdfParser.cpp 2022-04-11 06:07:37 UTC (rev 2054) @@ -546,12 +546,17 @@ if( trailer.GetDictionary().HasKey( "Prev" ) ) { - // Whenever we read a Prev key, - // we know that the file was updated. - m_nIncrementalUpdates++; - try { pdf_long lOffset = static_cast<pdf_long>(trailer.GetDictionary().GetKeyAsLong( "Prev", 0 )); + if( 0 == lOffset ) + { + PdfError::LogMessage( eLogSeverity_Warning, "XRef contents at offset %" PDF_FORMAT_INT64 " is invalid, skipping the read\n", static_cast<pdf_int64>( lOffset )); + return; + } + + // Whenever we read a Prev key (!= 0), + // we know that the file was updated. + m_nIncrementalUpdates++; if( m_visitedXRefOffsets.find( lOffset ) == m_visitedXRefOffsets.end() ) ReadXRefContents( lOffset ); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2022-03-12 17:45:27
|
Revision: 2053 http://sourceforge.net/p/podofo/code/2053 Author: mc-zyx Date: 2022-03-12 17:45:24 +0000 (Sat, 12 Mar 2022) Log Message: ----------- Add FontTest::testBig2Little() unit test It calls PdfFontTTFSubset.cpp:Big2Little(), even it is a void test for other arches than PODOFO_IS_LITTLE_ENDIAN. Modified Paths: -------------- podofo/trunk/test/unit/FontTest.cpp podofo/trunk/test/unit/FontTest.h Modified: podofo/trunk/test/unit/FontTest.cpp =================================================================== --- podofo/trunk/test/unit/FontTest.cpp 2022-03-12 17:06:02 UTC (rev 2052) +++ podofo/trunk/test/unit/FontTest.cpp 2022-03-12 17:45:24 UTC (rev 2053) @@ -189,3 +189,29 @@ } #endif + +void FontTest::testBig2Little() +{ + PdfMemDocument doc; + PoDoFo::PdfPage* pPage; + pPage = doc.CreatePage( PoDoFo::PdfPage::CreateStandardPageSize( PoDoFo::ePdfPageSize_A4, false ) ); + PdfPainter painter; + painter.SetPage( pPage ); + PdfFont * pFont = doc.CreateFontSubset( "Arial", false, false, false, PdfEncodingFactory::GlobalWinAnsiEncodingInstance()); + pFont->SetFontSize( 30.0 ); + painter.SetFont( pFont ); + PdfString str((const pdf_utf8*)"ěščř"); + painter.DrawText( 100.0, 700.0, str ); + painter.FinishPage(); + try + { + PdfOutputDevice output; + doc.Write( &output ); + } + catch( PoDoFo::PdfError &error ) + { + // it's okay to error this way + if( error.GetError() != ePdfError_UnsupportedFontFormat ) + throw; + } +} Modified: podofo/trunk/test/unit/FontTest.h =================================================================== --- podofo/trunk/test/unit/FontTest.h 2022-03-12 17:06:02 UTC (rev 2052) +++ podofo/trunk/test/unit/FontTest.h 2022-03-12 17:45:24 UTC (rev 2053) @@ -38,6 +38,7 @@ CPPUNIT_TEST( testFonts ); CPPUNIT_TEST( testCreateFontFtFace ); #endif + CPPUNIT_TEST( testBig2Little ); CPPUNIT_TEST_SUITE_END(); public: @@ -48,6 +49,7 @@ void testFonts(); void testCreateFontFtFace(); #endif + void testBig2Little(); private: #if defined(PODOFO_HAVE_FONTCONFIG) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2022-03-12 17:06:05
|
Revision: 2052 http://sourceforge.net/p/podofo/code/2052 Author: mc-zyx Date: 2022-03-12 17:06:02 +0000 (Sat, 12 Mar 2022) Log Message: ----------- Revert the previous commit (r2051) - it causes stack overflow Modified Paths: -------------- podofo/trunk/src/podofo/doc/PdfFontTTFSubset.cpp Modified: podofo/trunk/src/podofo/doc/PdfFontTTFSubset.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfFontTTFSubset.cpp 2022-03-12 16:43:57 UTC (rev 2051) +++ podofo/trunk/src/podofo/doc/PdfFontTTFSubset.cpp 2022-03-12 17:06:02 UTC (rev 2052) @@ -65,8 +65,7 @@ inline unsigned short Big2Little(unsigned short big) { - unsigned short little = Big2Little(*reinterpret_cast<unsigned short*>(&big)); - return *reinterpret_cast<short*>(&little); + return ((big << 8) & 0xFF00) | ((big >> 8) & 0x00FF); } inline short Big2Little(short big) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2022-03-12 16:43:59
|
Revision: 2051 http://sourceforge.net/p/podofo/code/2051 Author: mc-zyx Date: 2022-03-12 16:43:57 +0000 (Sat, 12 Mar 2022) Log Message: ----------- Patch by Michal Sudolsky: Fix undefined behavior in PdfFontTTFSubset.cpp:Big2Little Modified Paths: -------------- podofo/trunk/src/podofo/doc/PdfFontTTFSubset.cpp Modified: podofo/trunk/src/podofo/doc/PdfFontTTFSubset.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfFontTTFSubset.cpp 2022-03-12 16:36:59 UTC (rev 2050) +++ podofo/trunk/src/podofo/doc/PdfFontTTFSubset.cpp 2022-03-12 16:43:57 UTC (rev 2051) @@ -65,7 +65,8 @@ inline unsigned short Big2Little(unsigned short big) { - return ((big << 8) & 0xFF00) | ((big >> 8) & 0x00FF); + unsigned short little = Big2Little(*reinterpret_cast<unsigned short*>(&big)); + return *reinterpret_cast<short*>(&little); } inline short Big2Little(short big) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2022-03-12 16:37:02
|
Revision: 2050 http://sourceforge.net/p/podofo/code/2050 Author: mc-zyx Date: 2022-03-12 16:36:59 +0000 (Sat, 12 Mar 2022) Log Message: ----------- Patch by Andreas Brzesowsky: Add support for revision 6 encryption (PDF1.7 extension 8, PDF 2.0) Revision Links: -------------- http://sourceforge.net/p/podofo/code/6 Modified Paths: -------------- podofo/trunk/src/podofo/base/PdfEncrypt.cpp podofo/trunk/src/podofo/base/PdfEncrypt.h podofo/trunk/test/unit/EncryptTest.cpp podofo/trunk/test/unit/EncryptTest.h Modified: podofo/trunk/src/podofo/base/PdfEncrypt.cpp =================================================================== --- podofo/trunk/src/podofo/base/PdfEncrypt.cpp 2022-03-12 16:18:51 UTC (rev 2049) +++ podofo/trunk/src/podofo/base/PdfEncrypt.cpp 2022-03-12 16:36:59 UTC (rev 2050) @@ -45,7 +45,9 @@ typedef SSIZE_T ssize_t; #endif #include <stringprep.h> +#include <idn-free.h> // The entry point to the Windows memory de-allocation function #include <openssl/sha.h> +#include <openssl/aes.h> #endif // PODOFO_HAVE_LIBIDN #include <openssl/opensslconf.h> @@ -68,7 +70,8 @@ ePdfEncryptAlgorithm_RC4V2 | #endif // PODOFO_HAVE_OPENSSL_NO_RC4 ePdfEncryptAlgorithm_AESV2 | -ePdfEncryptAlgorithm_AESV3; +ePdfEncryptAlgorithm_AESV3 | +ePdfEncryptAlgorithm_AESV3R6; #else // PODOFO_HAVE_LIBIDN int PdfEncrypt::s_nEnabledEncryptionAlgorithms = #ifndef PODOFO_HAVE_OPENSSL_NO_RC4 @@ -527,7 +530,8 @@ break; #ifdef PODOFO_HAVE_LIBIDN case ePdfEncryptAlgorithm_AESV3: - pdfEncrypt = new PdfEncryptAESV3(userPassword, ownerPassword, protection); + case ePdfEncryptAlgorithm_AESV3R6: + pdfEncrypt = new PdfEncryptAESV3(userPassword, ownerPassword, protection, eAlgorithm); break; #endif // PODOFO_HAVE_LIBIDN #ifndef PODOFO_HAVE_OPENSSL_NO_RC4 @@ -631,14 +635,16 @@ pdfEncrypt = new PdfEncryptAESV2(oValue, uValue, pValue, encryptMetadata); } #ifdef PODOFO_HAVE_LIBIDN - else if( (lV == 5L) && (rValue == 5L) - && PdfEncrypt::IsEncryptionEnabled( ePdfEncryptAlgorithm_AESV3 ) ) + else if( (lV == 5L) && ( + ( rValue == 5L && PdfEncrypt::IsEncryptionEnabled( ePdfEncryptAlgorithm_AESV3 ) ) + || ( rValue == 6L && PdfEncrypt::IsEncryptionEnabled( ePdfEncryptAlgorithm_AESV3R6 ) ) ) ) { PdfString permsValue = pObject->GetDictionary().GetKey( PdfName("Perms") )->GetString(); PdfString oeValue = pObject->GetDictionary().GetKey( PdfName("OE") )->GetString(); PdfString ueValue = pObject->GetDictionary().GetKey( PdfName("UE") )->GetString(); - pdfEncrypt = new PdfEncryptAESV3(oValue, oeValue, uValue, ueValue, pValue, permsValue); + EPdfEncryptAlgorithm eAlgorithm = rValue == 6L ? ePdfEncryptAlgorithm_AESV3R6 : ePdfEncryptAlgorithm_AESV3; + pdfEncrypt = new PdfEncryptAESV3(oValue, oeValue, uValue, ueValue, pValue, permsValue, eAlgorithm); } #endif // PODOFO_HAVE_LIBIDN else @@ -658,7 +664,7 @@ if (rhs.m_eAlgorithm == ePdfEncryptAlgorithm_AESV2) pdfEncrypt = new PdfEncryptAESV2(rhs); #ifdef PODOFO_HAVE_LIBIDN - else if (rhs.m_eAlgorithm == ePdfEncryptAlgorithm_AESV3) + else if (rhs.m_eAlgorithm == ePdfEncryptAlgorithm_AESV3 || rhs.m_eAlgorithm == ePdfEncryptAlgorithm_AESV3R6) pdfEncrypt = new PdfEncryptAESV3(rhs); #endif // PODOFO_HAVE_LIBIDN #ifndef PODOFO_HAVE_OPENSSL_NO_RC4 @@ -1229,6 +1235,7 @@ case ePdfEncryptAlgorithm_AESV2: #ifdef PODOFO_HAVE_LIBIDN case ePdfEncryptAlgorithm_AESV3: + case ePdfEncryptAlgorithm_AESV3R6: #endif // PODOFO_HAVE_LIBIDN break; } @@ -1505,6 +1512,70 @@ memcpy( m_oeValue, static_cast<const PdfEncryptSHABase*>(ptr)->m_oeValue, sizeof(unsigned char) * 32 ); } +void PdfEncryptSHABase::ComputeHash(const unsigned char * pswd, int pswdLen, unsigned char salt[8], unsigned char uValue[48], unsigned char hashValue[32]) +{ + SHA256_CTX sha256; + SHA256_Init(&sha256); + if(pswdLen) + SHA256_Update(&sha256, pswd, pswdLen); + SHA256_Update(&sha256, salt, 8); + if(uValue) + SHA256_Update(&sha256, uValue, 48); + SHA256_Final(hashValue, &sha256); + + if(m_rValue > 5) // AES-256 according to PDF 1.7 Adobe Extension Level 8 (PDF 2.0) + { + SHA512_CTX sha384; + SHA512_CTX sha512; + AES_KEY aes; + int dataLen = 0; + int blockLen = 32; // Start with current SHA256 hash + unsigned char data[(127 + 64 + 48) * 64]; // 127 for password, 64 for hash up to SHA512, 48 for uValue + unsigned char block[64]; + memcpy(block, hashValue, 32); + + for(int i = 0; i < 64 || i < 32 + data[dataLen - 1]; ++i) + { + dataLen = pswdLen + blockLen; + memcpy(data, pswd, pswdLen); + memcpy(data + pswdLen, block, blockLen); + if (uValue) { + memcpy(data + dataLen, uValue, 48); + dataLen += 48; + } + for(int j = 1; j < 64; ++j) + memcpy(data + j * dataLen, data, dataLen); + dataLen *= 64; + + AES_set_encrypt_key(block, 128, &aes); + AES_cbc_encrypt(data, data, dataLen, &aes, block + 16, AES_ENCRYPT); + int sum = 0; + for(int j = 0; j < 16; ++j) + sum += data[j]; + blockLen = 32 + (sum % 3) * 16; + + if(blockLen == 32) { + SHA256_Init(&sha256); + SHA256_Update(&sha256, data, dataLen); + SHA256_Final(block, &sha256); + } + else if(blockLen == 48) + { + SHA384_Init(&sha384); + SHA384_Update(&sha384, data, dataLen); + SHA384_Final(block, &sha384); + } + else + { + SHA512_Init(&sha512); + SHA512_Update(&sha512, data, dataLen); + SHA512_Final(block, &sha512); + } + } + memcpy(hashValue, block, 32); + } +} + void PdfEncryptSHABase::ComputeUserKey(const unsigned char * userpswd, int len) { // Generate User Salts @@ -1520,13 +1591,8 @@ // Generate hash for U unsigned char hashValue[32]; - SHA256_CTX context; - SHA256_Init(&context); + ComputeHash(userpswd, len, vSalt, 0, hashValue); - SHA256_Update(&context, userpswd, len); - SHA256_Update(&context, vSalt, 8); - SHA256_Final(hashValue, &context); - // U = hash + validation salt + key salt memcpy(m_uValue, hashValue, 32); memcpy(m_uValue+32, vSalt, 8); @@ -1533,10 +1599,7 @@ memcpy(m_uValue+32+8, kSalt, 8); // Generate hash for UE - SHA256_Init(&context); - SHA256_Update(&context, userpswd, len); - SHA256_Update(&context, kSalt, 8); - SHA256_Final(hashValue, &context); + ComputeHash(userpswd, len, kSalt, 0, hashValue); // UE = AES-256 encoded file encryption key with key=hash // CBC mode, no padding, init vector=0 @@ -1585,12 +1648,7 @@ // Generate hash for O unsigned char hashValue[32]; - SHA256_CTX context; - SHA256_Init(&context); - SHA256_Update(&context, ownerpswd, len); - SHA256_Update(&context, vSalt, 8); - SHA256_Update(&context, m_uValue, 48); - SHA256_Final(hashValue, &context); + ComputeHash(ownerpswd, len, vSalt, m_uValue, hashValue); // O = hash + validation salt + key salt memcpy(m_oValue, hashValue, 32); @@ -1598,11 +1656,7 @@ memcpy(m_oValue+32+8, kSalt, 8); // Generate hash for OE - SHA256_Init(&context); - SHA256_Update(&context, ownerpswd, len); - SHA256_Update(&context, kSalt, 8); - SHA256_Update(&context, m_uValue, 48); - SHA256_Final(hashValue, &context); + ComputeHash(ownerpswd, len, kSalt, m_uValue, hashValue); // OE = AES-256 encoded file encryption key with key=hash // CBC mode, no padding, init vector=0 @@ -1650,7 +1704,9 @@ len = l > 127 ? 127 : l; memcpy(outBuf, password_sasl, len); - free(password_sasl); // Do not change to podofo_free, as memory is allocated by stringprep_profile + // password_sasl is allocated by stringprep_profile (libidn), so use idn_free + // (In Windows the libidn.dll could use an other heap and then the normal free or podofo_free will crash while debugging podofo.) + idn_free(password_sasl); } void @@ -1697,7 +1753,7 @@ PdfDictionary stdCf; rDictionary.AddKey( PdfName("V"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(5)) ); - rDictionary.AddKey( PdfName("R"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(5)) ); + rDictionary.AddKey( PdfName("R"), static_cast<pdf_int64>(m_rValue) ); rDictionary.AddKey( PdfName("Length"), static_cast<pdf_int64>(PODOFO_LL_LITERAL(256)) ); stdCf.AddKey( PdfName("CFM"), PdfName("AESV3") ); @@ -1774,7 +1830,7 @@ aes = &aes_local; #endif - int status = EVP_EncryptInit_ex(aes, EVP_aes_256_ecb(), NULL, m_encryptionKey, NULL); + int status = EVP_EncryptInit_ex(aes, EVP_aes_256_cbc(), NULL, m_encryptionKey, NULL); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing AES encryption engine" ); EVP_CIPHER_CTX_set_padding(aes, 0); // disable padding @@ -1806,21 +1862,13 @@ // Test 1: is it the user key ? unsigned char hashValue[32]; - SHA256_CTX context; - SHA256_Init(&context); - SHA256_Update(&context, pswd_sasl, pswdLen); // password - SHA256_Update(&context, m_uValue + 32, 8); // user Validation Salt - SHA256_Final(hashValue, &context); + ComputeHash(pswd_sasl, pswdLen, m_uValue + 32, 0, hashValue); // user Validation Salt ok = CheckKey(hashValue, m_uValue); if(!ok) { // Test 2: is it the owner key ? - SHA256_Init(&context); - SHA256_Update(&context, pswd_sasl, pswdLen); // password - SHA256_Update(&context, m_oValue + 32, 8); // owner Validation Salt - SHA256_Update(&context, m_uValue, 48); // U string - SHA256_Final(hashValue, &context); + ComputeHash(pswd_sasl, pswdLen, m_oValue + 32, m_uValue, hashValue); // owner Validation Salt ok = CheckKey(hashValue, m_oValue); @@ -1829,11 +1877,7 @@ m_ownerPass = password; // ISO 32000: "Compute an intermediate owner key by computing the SHA-256 hash of // the UTF-8 password concatenated with the 8 bytes of owner Key Salt, concatenated with the 48-byte U string." - SHA256_Init(&context); - SHA256_Update(&context, pswd_sasl, pswdLen); // password - SHA256_Update(&context, m_oValue + 40, 8); // owner Key Salt - SHA256_Update(&context, m_uValue, 48); // U string - SHA256_Final(hashValue, &context); + ComputeHash(pswd_sasl, pswdLen, m_oValue + 40, m_uValue, hashValue); // owner Key Salt // ISO 32000: "The 32-byte result is the key used to decrypt the 32-byte OE string using // AES-256 in CBC mode with no padding and an initialization vector of zero. @@ -1850,10 +1894,7 @@ m_userPass = password; // ISO 32000: "Compute an intermediate user key by computing the SHA-256 hash of // the UTF-8 password concatenated with the 8 bytes of user Key Salt" - SHA256_Init(&context); - SHA256_Update(&context, pswd_sasl, pswdLen); // password - SHA256_Update(&context, m_uValue + 40, 8); // user Key Salt - SHA256_Final(hashValue, &context); + ComputeHash(pswd_sasl, pswdLen, m_uValue + 40, 0, hashValue); // user Key Salt // ISO 32000: "The 32-byte result is the key used to decrypt the 32-byte UE string using // AES-256 in CBC mode with no padding and an initialization vector of zero. @@ -1890,18 +1931,22 @@ unsigned char* outStr, pdf_long &outLen) const { pdf_long offset = CalculateStreamOffset(); + if( inLen <= offset ) { // Is empty + outLen = 0; + return; + } const_cast<PdfEncryptAESV3*>(this)->BaseDecrypt(const_cast<unsigned char*>(m_encryptionKey), m_keyLength, inStr, &inStr[offset], inLen-offset, outStr, outLen); } -PdfEncryptAESV3::PdfEncryptAESV3( const std::string & userPassword, const std::string & ownerPassword, int protection) : PdfEncryptAESBase() +PdfEncryptAESV3::PdfEncryptAESV3( const std::string & userPassword, const std::string & ownerPassword, int protection, EPdfEncryptAlgorithm eAlgorithm) : PdfEncryptAESBase() { // setup object m_userPass = userPassword; m_ownerPass = ownerPassword; - m_eAlgorithm = ePdfEncryptAlgorithm_AESV3; + m_eAlgorithm = eAlgorithm == ePdfEncryptAlgorithm_AESV3R6 ? ePdfEncryptAlgorithm_AESV3R6 : ePdfEncryptAlgorithm_AESV3; - m_rValue = 5; + m_rValue = eAlgorithm == ePdfEncryptAlgorithm_AESV3R6 ? 6 : 5; m_eKeyLength = ePdfKeyLength_256; m_keyLength = ePdfKeyLength_256 / 8; @@ -1916,14 +1961,14 @@ m_pValue = PERMS_DEFAULT | protection; } -PdfEncryptAESV3::PdfEncryptAESV3(PdfString oValue,PdfString oeValue, PdfString uValue, PdfString ueValue, int pValue, PdfString permsValue) : PdfEncryptAESBase() +PdfEncryptAESV3::PdfEncryptAESV3(PdfString oValue,PdfString oeValue, PdfString uValue, PdfString ueValue, int pValue, PdfString permsValue, EPdfEncryptAlgorithm eAlgorithm) : PdfEncryptAESBase() { m_pValue = pValue; - m_eAlgorithm = ePdfEncryptAlgorithm_AESV3; + m_eAlgorithm = eAlgorithm == ePdfEncryptAlgorithm_AESV3R6 ? ePdfEncryptAlgorithm_AESV3R6 : ePdfEncryptAlgorithm_AESV3; m_eKeyLength = ePdfKeyLength_256; m_keyLength = ePdfKeyLength_256 / 8; - m_rValue = 5; + m_rValue = eAlgorithm == ePdfEncryptAlgorithm_AESV3R6 ? 6 : 5; memcpy( m_oValue, oValue.GetString(), 48 ); memcpy( m_oeValue, oeValue.GetString(), 32 ); memcpy( m_uValue, uValue.GetString(), 48 ); Modified: podofo/trunk/src/podofo/base/PdfEncrypt.h =================================================================== --- podofo/trunk/src/podofo/base/PdfEncrypt.h 2022-03-12 16:18:51 UTC (rev 2049) +++ podofo/trunk/src/podofo/base/PdfEncrypt.h 2022-03-12 16:36:59 UTC (rev 2050) @@ -120,6 +120,7 @@ ePdfEncryptAlgorithm_AESV2 = 4 ///< AES encryption with a 128 bit key (PDF1.6) #ifdef PODOFO_HAVE_LIBIDN ,ePdfEncryptAlgorithm_AESV3 = 8 ///< AES encryption with a 256 bit key (PDF1.7 extension 3) - Support added by P. Zent + ,ePdfEncryptAlgorithm_AESV3R6 = 16 ///< AES encryption with a 256 bit key, Revision 6 (PDF1.7 extension 8, PDF 2.0) #endif //PODOFO_HAVE_LIBIDN } EPdfEncryptAlgorithm; @@ -495,6 +496,9 @@ /// Compute encryption key to be used with AES-256 void ComputeEncryptionKey(); + /// Compute hash for password and salt with optional uValue + void ComputeHash(const unsigned char * pswd, int pswdLen, unsigned char salt[8], unsigned char uValue[48], unsigned char hashValue[32]); + /// Generate the U and UE entries void ComputeUserKey(const unsigned char * userpswd, int len); @@ -710,7 +714,7 @@ /* * Constructors of PdfEncryptAESV3 */ - PdfEncryptAESV3(PdfString oValue, PdfString oeValue, PdfString uValue, PdfString ueValue, int pValue, PdfString permsValue); + PdfEncryptAESV3(PdfString oValue, PdfString oeValue, PdfString uValue, PdfString ueValue, int pValue, PdfString permsValue, EPdfEncryptAlgorithm eAlgorithm = ePdfEncryptAlgorithm_AESV3); PdfEncryptAESV3( const PdfEncrypt & rhs ) : PdfEncryptSHABase(rhs) {} PdfEncryptAESV3( const std::string & userPassword, const std::string & ownerPassword, @@ -721,7 +725,8 @@ ePdfPermissions_FillAndSign | ePdfPermissions_Accessible | ePdfPermissions_DocAssembly | - ePdfPermissions_HighPrint + ePdfPermissions_HighPrint, + EPdfEncryptAlgorithm eAlgorithm = ePdfEncryptAlgorithm_AESV3 ); /* Modified: podofo/trunk/test/unit/EncryptTest.cpp =================================================================== --- podofo/trunk/test/unit/EncryptTest.cpp 2022-03-12 16:18:51 UTC (rev 2049) +++ podofo/trunk/test/unit/EncryptTest.cpp 2022-03-12 16:36:59 UTC (rev 2050) @@ -169,6 +169,20 @@ delete pEncrypt; } + +void EncryptTest::testAESV3R6() +{ + PdfEncrypt* pEncrypt = PdfEncrypt::CreatePdfEncrypt( "user", "podofo", m_protection, + PdfEncrypt::ePdfEncryptAlgorithm_AESV3R6, + PdfEncrypt::ePdfKeyLength_256 ); + + TestAuthenticate( pEncrypt, 256, 5 ); + // AES decryption is not yet implemented. + // Therefore we have to disable this test. + // TestEncrypt( pEncrypt ); + + delete pEncrypt; +} #endif // PODOFO_HAVE_LIBIDN void EncryptTest::TestAuthenticate( PdfEncrypt* pEncrypt, int PODOFO_UNUSED_PARAM(keyLength), int PODOFO_UNUSED_PARAM(rValue) ) @@ -335,6 +349,7 @@ CPPUNIT_ASSERT( PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_AESV2 ) ); #ifdef PODOFO_HAVE_LIBIDN CPPUNIT_ASSERT( PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_AESV3 ) ); + CPPUNIT_ASSERT( PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_AESV3R6 ) ); #endif // PODOFO_HAVE_LIBIDN int testAlgorithms = PdfEncrypt::ePdfEncryptAlgorithm_AESV2; @@ -342,7 +357,7 @@ testAlgorithms |= PdfEncrypt::ePdfEncryptAlgorithm_RC4V1 | PdfEncrypt::ePdfEncryptAlgorithm_RC4V2; #endif // PODOFO_HAVE_OPENSSL_NO_RC4 #ifdef PODOFO_HAVE_LIBIDN - testAlgorithms |= PdfEncrypt::ePdfEncryptAlgorithm_AESV3; + testAlgorithms |= PdfEncrypt::ePdfEncryptAlgorithm_AESV3 | PdfEncrypt::ePdfEncryptAlgorithm_AESV3R6; #endif // PODOFO_HAVE_LIBIDN CPPUNIT_ASSERT_EQUAL( testAlgorithms, PdfEncrypt::GetEnabledEncryptionAlgorithms() ); Modified: podofo/trunk/test/unit/EncryptTest.h =================================================================== --- podofo/trunk/test/unit/EncryptTest.h 2022-03-12 16:18:51 UTC (rev 2049) +++ podofo/trunk/test/unit/EncryptTest.h 2022-03-12 16:36:59 UTC (rev 2050) @@ -45,6 +45,7 @@ CPPUNIT_TEST( testAESV2 ); #ifdef PODOFO_HAVE_LIBIDN CPPUNIT_TEST( testAESV3 ); + CPPUNIT_TEST( testAESV3R6 ); #endif // PODOFO_HAVE_LIBIDN CPPUNIT_TEST( testLoadEncrypedFilePdfParser ); CPPUNIT_TEST( testLoadEncrypedFilePdfMemDocument ); @@ -67,6 +68,7 @@ void testAESV2(); #ifdef PODOFO_HAVE_LIBIDN void testAESV3(); + void testAESV3R6(); #endif // PODOFO_HAVE_LIBIDN void testLoadEncrypedFilePdfParser(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2022-03-12 16:18:54
|
Revision: 2049 http://sourceforge.net/p/podofo/code/2049 Author: mc-zyx Date: 2022-03-12 16:18:51 +0000 (Sat, 12 Mar 2022) Log Message: ----------- Patch by Mark Rogers: Add tests for stack overflow infinite recursion for CVE-2018-8002, CVE-2021-30470, CVE-2021-30471, CVE-2020-18971 Modified Paths: -------------- podofo/trunk/test/unit/ParserTest.cpp podofo/trunk/test/unit/ParserTest.h Modified: podofo/trunk/test/unit/ParserTest.cpp =================================================================== --- podofo/trunk/test/unit/ParserTest.cpp 2022-03-12 16:08:42 UTC (rev 2048) +++ podofo/trunk/test/unit/ParserTest.cpp 2022-03-12 16:18:51 UTC (rev 2049) @@ -1981,6 +1981,773 @@ } } +void ParserTest::testNestedArrays() +{ + // test valid stream + try + { + // generate an XRef stream with no deeply nested arrays + std::ostringstream oss; + size_t offsetStream; + size_t offsetEndstream; + + // XRef stream with 5 entries + size_t lengthXRefObject = 57; + size_t offsetXRefObject = oss.str().length(); + oss << "2 0 obj "; + oss << "<< /Type /XRef "; + oss << "/Length " << lengthXRefObject << " "; + oss << "/Index [2 2] "; + oss << "/Size 5 "; + oss << "/W [1 2 1] "; + oss << "/Filter /ASCIIHexDecode "; + oss << ">>\r\n"; + oss << "stream\r\n"; + offsetStream = oss.str().length(); + oss << "01 0E8A 0\r\n"; + oss << "02 0002 00\r\n"; + oss << "02 0002 01\r\n"; + oss << "02 0002 02\r\n"; + oss << "02 0002 03\r\n"; + offsetEndstream = oss.str().length(); + oss << "endstream\r\n"; + oss << "endobj\r\n"; + CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // hard-coded in /Length entry in XRef stream above + + // trailer + oss << "trailer << /Root 1 0 R /Size 3 >>\r\n"; + oss << "startxref " << offsetXRefObject << "\r\n"; + oss << "%EOF"; + + PoDoFo::PdfVecObjects objects; + PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() ); + + parser.SetupTrailer(); + parser.ReadXRefStreamContents( offsetXRefObject, false ); + // should succeed + } + catch ( PoDoFo::PdfError& error ) + { + CPPUNIT_FAIL( "Unexpected PdfError" ); + } + catch( std::exception& ex ) + { + CPPUNIT_FAIL( "Unexpected exception type" ); + } + + // CVE-2021-30470 - lots of [[[[[]]]]] brackets represent nested arrays which caused stack overflow + try + { + // generate an XRef stream with deeply nested arrays + std::ostringstream oss; + size_t offsetStream; + size_t offsetEndstream; + size_t maxNesting = getStackOverflowDepth(); // big enough to cause stack overflow + // XRef stream with 5 entries + size_t lengthXRefObject = 57; + size_t offsetXRefObject = oss.str().length(); + oss << "2 0 obj "; + oss << "<< /Type /XRef "; + oss << "/Length " << lengthXRefObject << " "; + oss << "/Index [2 2] "; + oss << "/Size 5 "; + oss << "/W [1 2 1] "; + + // output [[[[[[[[[[[0]]]]]]]]]]] + for ( size_t i = 0 ; i < maxNesting ; ++i ) + { + oss << "["; + } + oss << "0"; + for ( size_t i = 0 ; i < maxNesting ; ++i ) + { + oss << "]"; + } + oss << " "; + + oss << "/Filter /ASCIIHexDecode "; + oss << ">>\r\n"; + oss << "stream\r\n"; + offsetStream = oss.str().length(); + oss << "01 0E8A 0\r\n"; + oss << "02 0002 00\r\n"; + oss << "02 0002 01\r\n"; + oss << "02 0002 02\r\n"; + oss << "02 0002 03\r\n"; + offsetEndstream = oss.str().length(); + oss << "endstream\r\n"; + oss << "endobj\r\n"; + CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // hard-coded in /Length entry in XRef stream above + + // trailer + oss << "trailer << /Root 1 0 R /Size 3 >>\r\n"; + oss << "startxref " << offsetXRefObject << "\r\n"; + oss << "%EOF"; + + PoDoFo::PdfVecObjects objects; + PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() ); + + parser.SetupTrailer(); + parser.ReadXRefStreamContents( offsetXRefObject, false ); + CPPUNIT_FAIL( "Should throw exception" ); + } + catch ( PoDoFo::PdfError& error ) + { + // this must match the error value thrown by PdfRecursionGuard + CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef ); + } + catch( std::exception& ex ) + { + CPPUNIT_FAIL( "Unexpected exception type" ); + } +} + +void ParserTest::testNestedDictionaries() +{ + // test valid stream + try + { + // generate an XRef stream with no deeply nested dictionaries + std::ostringstream oss; + size_t offsetStream; + size_t offsetEndstream; + + // XRef stream with 5 entries + size_t lengthXRefObject = 57; + size_t offsetXRefObject = oss.str().length(); + oss << "2 0 obj "; + oss << "<< /Type /XRef "; + oss << "/Length " << lengthXRefObject << " "; + oss << "/Index [2 2] "; + oss << "/Size 5 "; + oss << "/W [1 2 1] "; + oss << "/Filter /ASCIIHexDecode "; + oss << ">>\r\n"; + oss << "stream\r\n"; + offsetStream = oss.str().length(); + oss << "01 0E8A 0\r\n"; + oss << "02 0002 00\r\n"; + oss << "02 0002 01\r\n"; + oss << "02 0002 02\r\n"; + oss << "02 0002 03\r\n"; + offsetEndstream = oss.str().length(); + oss << "endstream\r\n"; + oss << "endobj\r\n"; + CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // hard-coded in /Length entry in XRef stream above + + // trailer + oss << "trailer << /Root 1 0 R /Size 3 >>\r\n"; + oss << "startxref " << offsetXRefObject << "\r\n"; + oss << "%EOF"; + + PoDoFo::PdfVecObjects objects; + PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() ); + + parser.SetupTrailer(); + parser.ReadXRefStreamContents( offsetXRefObject, false ); + // should succeed + } + catch ( PoDoFo::PdfError& error ) + { + CPPUNIT_FAIL( "Unexpected PdfError" ); + } + catch( std::exception& ex ) + { + CPPUNIT_FAIL( "Unexpected exception type" ); + } + + // CVE-2021-30470 - lots of <<<>>> brackets represent nested dictionaries which caused stack overflow + try + { + // generate an XRef stream with deeply nested dictionaries + std::ostringstream oss; + size_t offsetStream; + size_t offsetEndstream; + size_t maxNesting = getStackOverflowDepth(); // big enough to cause stack overflow + // XRef stream with 5 entries + size_t lengthXRefObject = 57; + size_t offsetXRefObject = oss.str().length(); + oss << "2 0 obj "; + oss << "<< /Type /XRef "; + oss << "/Length " << lengthXRefObject << " "; + oss << "/Index [2 2] "; + oss << "/Size 5 "; + oss << "/W [1 2 1] "; + + // output << << << /Test 0 >> >> >> + for ( size_t i = 0 ; i < maxNesting ; ++i ) + { + oss << "<< "; + } + oss << " /Test 0"; + for ( size_t i = 0 ; i < maxNesting ; ++i ) + { + oss << " >>"; + } + oss << " "; + + oss << "/Filter /ASCIIHexDecode "; + oss << ">>\r\n"; + oss << "stream\r\n"; + offsetStream = oss.str().length(); + oss << "01 0E8A 0\r\n"; + oss << "02 0002 00\r\n"; + oss << "02 0002 01\r\n"; + oss << "02 0002 02\r\n"; + oss << "02 0002 03\r\n"; + offsetEndstream = oss.str().length(); + oss << "endstream\r\n"; + oss << "endobj\r\n"; + CPPUNIT_ASSERT( offsetEndstream-offsetStream-strlen("\r\n") == lengthXRefObject ); // hard-coded in /Length entry in XRef stream above + + // trailer + oss << "trailer << /Root 1 0 R /Size 3 >>\r\n"; + oss << "startxref " << offsetXRefObject << "\r\n"; + oss << "%EOF"; + + PoDoFo::PdfVecObjects objects; + PdfParserTestWrapper parser( &objects, oss.str().c_str(), oss.str().length() ); + + parser.SetupTrailer(); + parser.ReadXRefStreamContents( offsetXRefObject, false ); + CPPUNIT_FAIL( "Should throw exception" ); + } + catch ( PoDoFo::PdfError& error ) + { + // this must match the error value thrown by PdfRecursionGuard + CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef ); + } + catch( std::exception& ex ) + { + CPPUNIT_FAIL( "Unexpected exception type" ); + } +} + +void ParserTest::testNestedNameTree() +{ + // test for valid but deeply nested name tree + // maxDepth must be less than GetMaxObjectCount otherwise PdfParser::ResizeOffsets + // throws an error when reading the xref offsets table, and no outlines are read + std::ostringstream oss; + const long maxDepth = getStackOverflowDepth() - 6 - 1; + //const long maxDepth = 8; + const long numObjects = maxDepth + 6; + std::vector<size_t> offsets( numObjects ); + size_t xrefOffset = 0; + + offsets[0] = 0; + oss << "%PDF-1.0\r\n"; + + offsets[1] = oss.tellp(); + oss << "1 0 obj<</Type/Catalog /Pages 2 0 R /Names 4 0 R>>endobj "; + + offsets[2] = oss.tellp(); + oss << "2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj "; + + offsets[3] = oss.tellp(); + oss << "3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj "; + + // the name dictionary + offsets[4] = oss.tellp(); + oss << "4 0 obj<</Dests 5 0 R>>endobj "; + + // root of /Dests name tree + offsets[5] = oss.tellp(); + oss << "5 0 obj<</Kids [6 0 R]>>endobj "; + + // create name tree nested to maxDepth where each intermediate node has one child + // except single leaf node at maxDepth + for ( int obj = 6 ; obj < numObjects ; ++obj ) + { + offsets[obj] = oss.tellp(); + + if ( obj < numObjects - 1 ) + oss << obj << " 0 obj<</Kids [" << obj+1 << " 0 R] /Limits [(A) (Z)]>>endobj "; + else + oss << obj << " 0 obj<</Limits [(A) (Z)] /Names [ (A) (Avalue) (Z) (Zvalue) ] >>endobj "; + } + + // output xref table + oss << "\r\n"; + xrefOffset = oss.tellp(); + oss << "xref\r\n"; + oss << "0 " << numObjects << "\r\n"; + + oss << "0000000000 65535 f\r\n"; + + for ( size_t obj = 1 ; obj < offsets.size() ; ++obj ) + { + // write xref entries like + // "0000000010 00000 n\r\n" + char szXrefEntry[21]; + snprintf( szXrefEntry, 21, "%010zu 00000 n\r\n", offsets[obj] ); + + oss << szXrefEntry; + } + + oss << "trailer<</Size " << numObjects << "/Root 1 0 R>>\r\n"; + oss << "startxref\r\n"; + oss << xrefOffset << "\r\n"; + oss << "%%EOF"; + + try + { + PoDoFo::PdfMemDocument doc; + doc.LoadFromBuffer( oss.str().c_str(), oss.str().size(), true ); + + PoDoFo::PdfNamesTree* pNamesObj = doc.GetNamesTree( PoDoFo::ePdfDontCreateObject ); + if ( pNamesObj != nullptr ) + { + PoDoFo::PdfDictionary dict; + pNamesObj->ToDictionary( PoDoFo::PdfName( "Dests" ), dict ); + } + + CPPUNIT_FAIL( "Should throw exception" ); + } + catch ( PoDoFo::PdfError& error ) + { + // this must match the error value thrown by PdfRecursionGuard + CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef ); + } +} + +void ParserTest::testLoopingNameTree() +{ + std::string strNoLoop = + "%PDF-1.0\r\n" + "1 0 obj<</Type/Catalog/Pages 2 0 R /Names 4 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj 4 0 obj<</Dests 2 0 R>>endobj\r\n" + "xref\r\n" + "0 5\r\n" + "0000000000 65535 f\r\n" + "0000000010 00000 n\r\n" + "0000000066 00000 n\r\n" + "0000000115 00000 n\r\n" + "0000000161 00000 n\r\n" + "trailer<</Size 4/Root 1 0 R>>\r\n" + "startxref\r\n" + "192\r\n" + "%%EOF"; + + try + { + PoDoFo::PdfMemDocument doc; + doc.LoadFromBuffer( strNoLoop.c_str(), strNoLoop.size(), true ); + + PoDoFo::PdfNamesTree* pNamesObj = doc.GetNamesTree( PoDoFo::ePdfDontCreateObject ); + if ( pNamesObj != nullptr ) + { + PoDoFo::PdfDictionary dict; + pNamesObj->ToDictionary( PoDoFo::PdfName( "Dests" ), dict ); + } + + // should not throw + CPPUNIT_ASSERT( true ); + } + catch ( PoDoFo::PdfError& error ) + { + CPPUNIT_FAIL( "Unexpected PdfError" ); + } + + // CVE-2021-30471 /Dests points at pages tree root which has a /Kids entry loooping back to pages tree root + std::string strSelfLoop = + "%PDF-1.0\r\n" + "1 0 obj<</Type/Catalog/Pages 2 0 R /Names 4 0 R>>endobj 2 0 obj<</Type/Pages/Kids[2 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj 4 0 obj<</Dests 2 0 R>>endobj\r\n" + "xref\r\n" + "0 5\r\n" + "0000000000 65535 f\r\n" + "0000000010 00000 n\r\n" + "0000000066 00000 n\r\n" + "0000000115 00000 n\r\n" + "0000000161 00000 n\r\n" + "trailer<</Size 4/Root 1 0 R>>\r\n" + "startxref\r\n" + "192\r\n" + "%%EOF"; + + try + { + PoDoFo::PdfMemDocument doc; + doc.LoadFromBuffer( strSelfLoop.c_str(), strSelfLoop.size(), true ); + + PoDoFo::PdfNamesTree* pNamesObj = doc.GetNamesTree( PoDoFo::ePdfDontCreateObject ); + if ( pNamesObj != nullptr ) + { + PoDoFo::PdfDictionary dict; + pNamesObj->ToDictionary( PoDoFo::PdfName( "Dests" ), dict ); + } + + CPPUNIT_FAIL( "Should throw exception" ); + } + catch ( PoDoFo::PdfError& error ) + { + // this must match the error value thrown by PdfRecursionGuard + CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef ); + } + + // CVE-2021-30471 /Dests points at pages tree which has a /Kids entry loooping back to ancestor (document root) + std::string strAncestorLoop = + "%PDF-1.0\r\n" + "1 0 obj<</Type/Catalog/Pages 2 0 R /Names 4 0 R>>endobj 2 0 obj<</Type/Pages/Kids[1 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj 4 0 obj<</Dests 2 0 R>>endobj\r\n" + "xref\r\n" + "0 5\r\n" + "0000000000 65535 f\r\n" + "0000000010 00000 n\r\n" + "0000000066 00000 n\r\n" + "0000000115 00000 n\r\n" + "0000000161 00000 n\r\n" + "trailer<</Size 4/Root 1 0 R>>\r\n" + "startxref\r\n" + "192\r\n" + "%%EOF"; + + try + { + PoDoFo::PdfMemDocument doc; + doc.LoadFromBuffer( strAncestorLoop.c_str(), strAncestorLoop.size(), true ); + + PoDoFo::PdfNamesTree* pNamesObj = doc.GetNamesTree( PoDoFo::ePdfDontCreateObject ); + if ( pNamesObj != nullptr ) + { + PoDoFo::PdfDictionary dict; + pNamesObj->ToDictionary( PoDoFo::PdfName( "Dests" ), dict ); + } + + CPPUNIT_FAIL( "Should throw exception" ); + } + catch ( PoDoFo::PdfError& error ) + { + CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidDataType ); + } +} + +void ParserTest::testNestedPageTree() +{ + // test for valid but deeply nested page tree + // maxDepth must be less than GetMaxObjectCount otherwise PdfParser::ResizeOffsets + // throws an error when reading the xref offsets table, and no outlines are read + std::ostringstream oss; + const long maxDepth = getStackOverflowDepth() - 4 - 1; + const long numObjects = maxDepth + 4 ; + std::vector<size_t> offsets( numObjects ); + size_t xrefOffset = 0; + + offsets[0] = 0; + oss << "%PDF-1.0\r\n"; + + offsets[1] = oss.tellp(); + oss << "1 0 obj<</Type/Catalog /AcroForm 2 0 R /Pages 3 0 R>>endobj "; + + offsets[2] = oss.tellp(); + oss << "2 0 obj<</Type/AcroForm >>endobj "; + + offsets[3] = oss.tellp(); + oss << "3 0 obj<</Type/Pages /Kids [4 0 R] /Count 1 >>endobj "; + + // create pages tree nested to maxDepth where each node has one child + // except single leaf node at maxDepth + for ( int obj = 4 ; obj < numObjects ; ++obj ) + { + offsets[obj] = oss.tellp(); + + if ( obj < numObjects - 1 ) + oss << obj << " 0 obj<</Type/Pages /Kids [" << obj+1 << " 0 R] /Parent " << obj-1 << " 0 R /Count 1 >>endobj "; + else + oss << obj << " 0 obj<</Type/Page /Parent " << obj-1 << " 0 R >>endobj "; + } + + // output xref table + oss << "\r\n"; + xrefOffset = oss.tellp(); + oss << "xref\r\n"; + oss << "0 " << numObjects << "\r\n"; + + oss << "0000000000 65535 f\r\n"; + + for ( size_t obj = 1 ; obj < offsets.size() ; ++obj ) + { + // write xref entries like + // "0000000010 00000 n\r\n" + char szXrefEntry[21]; + snprintf( szXrefEntry, 21, "%010zu 00000 n\r\n", offsets[obj] ); + + oss << szXrefEntry; + } + + oss << "trailer<</Size " << numObjects << "/Root 1 0 R>>\r\n"; + oss << "startxref\r\n"; + oss << xrefOffset << "\r\n"; + oss << "%%EOF"; + + try + { + PoDoFo::PdfMemDocument doc; + doc.LoadFromBuffer( oss.str().c_str(), oss.str().size(), true ); + + for (int pageNo = 0; pageNo < doc.GetPageCount(); pageNo++) + { + PoDoFo::PdfPage* pPage = doc.GetPage( pageNo ); + CPPUNIT_ASSERT( pPage != NULL ); + } + + CPPUNIT_FAIL( "Should throw exception" ); + } + catch ( PoDoFo::PdfError& error ) + { + CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef ); + } +} + +void ParserTest::testLoopingPageTree() +{ + // test PDF without nested kids + std::string strNoLoop = + "%PDF-1.0\r\n" + "1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj\r\n" + "xref\r\n" + "0 4\r\n" + "0000000000 65535 f\r\n" + "0000000010 00000 n\r\n" + "0000000053 00000 n\r\n" + "0000000102 00000 n\r\n" + "trailer<</Size 4/Root 1 0 R>>\r\n" + "startxref\r\n" + "149\r\n" + "%%EOF"; + + try + { + PoDoFo::PdfMemDocument doc; + doc.LoadFromBuffer( strNoLoop.c_str(), strNoLoop.size(), true ); + + for (int pageNo = 0; pageNo < doc.GetPageCount(); pageNo++) + { + PoDoFo::PdfPage* pPage = doc.GetPage( pageNo ); + CPPUNIT_ASSERT( pPage != NULL ); + } + + // should not throw + CPPUNIT_ASSERT( true ); + } + catch ( PoDoFo::PdfError& error ) + { + CPPUNIT_FAIL( "Unexpected PdfError" ); + } + + // CVE-2021-30471 test for pages tree /Kids array that refer back to pages tree root + std::string strSelfLoop = + "%PDF-1.0\r\n" + "1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[2 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj\r\n" + "xref\r\n" + "0 4\r\n" + "0000000000 65535 f\r\n" + "0000000010 00000 n\r\n" + "0000000053 00000 n\r\n" + "0000000102 00000 n\r\n" + "trailer<</Size 4/Root 1 0 R>>\r\n" + "startxref\r\n" + "149\r\n" + "%%EOF"; + + try + { + PoDoFo::PdfMemDocument doc; + doc.LoadFromBuffer( strSelfLoop.c_str(), strSelfLoop.size(), true ); + + for (int pageNo = 0; pageNo < doc.GetPageCount(); pageNo++) + { + PoDoFo::PdfPage* pPage = doc.GetPage( pageNo ); + CPPUNIT_ASSERT( pPage == NULL ); + } + + CPPUNIT_FAIL( "Should throw exception" ); + + } + catch ( PoDoFo::PdfError& error ) + { + CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_PageNotFound ); + } + + // CVE-2021-30471 test for pages tree /Kids array that refer back to an ancestor (document root object) + std::string strAncestorLoop = + "%PDF-1.0\r\n" + "1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[1 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj\r\n" + "xref\r\n" + "0 4\r\n" + "0000000000 65535 f\r\n" + "0000000010 00000 n\r\n" + "0000000053 00000 n\r\n" + "0000000102 00000 n\r\n" + "trailer<</Size 4/Root 1 0 R>>\r\n" + "startxref\r\n" + "149\r\n" + "%%EOF"; + + try + { + PoDoFo::PdfMemDocument doc; + doc.LoadFromBuffer( strAncestorLoop.c_str(), strAncestorLoop.size(), true ); + + for (int pageNo = 0; pageNo < doc.GetPageCount(); pageNo++) + { + PoDoFo::PdfPage* pPage = doc.GetPage( pageNo ); + CPPUNIT_ASSERT( pPage == NULL ); + } + + // should return null for doc.GetPage and not throw + CPPUNIT_ASSERT( true ); + } + catch ( PoDoFo::PdfError& error ) + { + CPPUNIT_FAIL( "Unexpected PdfError" ); + } +} + +void ParserTest::testNestedOutlines() +{ + // test for valid but deeply nested outlines + // maxDepth must be less than GetMaxObjectCount otherwise PdfParser::ResizeOffsets + // throws an error when reading the xref offsets table, and no outlines are read + std::ostringstream oss; + const long maxDepth = getStackOverflowDepth() - 4 - 1; + const long numObjects = maxDepth + 4 ; + std::vector<size_t> offsets( numObjects ); + size_t xrefOffset = 0; + + offsets[0] = 0; + oss << "%PDF-1.0\r\n"; + + offsets[1] = oss.tellp(); + oss << "1 0 obj<</Type/Catalog /AcroForm 2 0 R /Outlines 3 0 R>>endobj "; + + offsets[2] = oss.tellp(); + oss << "2 0 obj<</Type/AcroForm >>endobj "; + + offsets[3] = oss.tellp(); + oss << "3 0 obj<</Type/Outlines /First 4 0 R /Count " << maxDepth << " /Last 5 0 R >>endobj "; + + // create outlines tree nested to maxDepth where each node has one child + // except single leaf node at maxDepth + for ( int obj = 4 ; obj < numObjects ; ++obj ) + { + offsets[obj] = oss.tellp(); + + if ( obj < numObjects - 1 ) + oss << obj << " 0 obj<</Title (Outline Item) /First " << obj+1 << " 0 R /Last " << obj+1 << " 0 R>>endobj "; + else + oss << obj << " 0 obj<</Title (Outline Item)>>endobj "; + } + + // output xref table + oss << "\r\n"; + xrefOffset = oss.tellp(); + oss << "xref\r\n"; + oss << "0 " << numObjects << "\r\n"; + + oss << "0000000000 65535 f\r\n"; + + for ( size_t obj = 1 ; obj < offsets.size() ; ++obj ) + { + // write xref entries like + // "0000000010 00000 n\r\n" + char szXrefEntry[21]; + snprintf( szXrefEntry, 21, "%010zu 00000 n\r\n", offsets[obj] ); + + oss << szXrefEntry; + } + + oss << "trailer<</Size " << numObjects << "/Root 1 0 R>>\r\n"; + oss << "startxref\r\n"; + oss << xrefOffset << "\r\n"; + oss << "%%EOF"; + + try + { + PoDoFo::PdfMemDocument doc; + doc.LoadFromBuffer( oss.str().c_str(), oss.str().size(), true ); + + // load should succeed, then GetOutlines goes recursive due to /Outlines deep nesting + PoDoFo::PdfOutlines* pOutlines = doc.GetOutlines(); + CPPUNIT_ASSERT_MESSAGE( "Should throw exception", pOutlines != nullptr ); + CPPUNIT_FAIL( "Should throw exception" ); + } + catch ( PoDoFo::PdfError& error ) + { + CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef ); + } +} + +void ParserTest::testLoopingOutlines() +{ + // CVE-2020-18971 - PdfOutlineItem /Next refers a preceding sibling + std::string strNextLoop = + "%PDF-1.0\r\n" + "1 0 obj<</Type/Catalog /AcroForm 2 0 R /Outlines 3 0 R>>endobj " + "2 0 obj<</Type/AcroForm >>endobj " + "3 0 obj<</Type/Outlines /First 4 0 R /Count 2 /Last 5 0 R >>endobj " + "4 0 obj<</Title (Outline Item 1) /Next 5 0 R>>endobj " + "5 0 obj<</Title (Outline Item 2) /Next 4 0 R>>endobj " // /Next loops back to previous outline item + "\r\n" + "xref\r\n" + "0 6\r\n" + "0000000000 65535 f\r\n" + "0000000010 00000 n\r\n" + "0000000073 00000 n\r\n" + "0000000106 00000 n\r\n" + "0000000173 00000 n\r\n" + "0000000226 00000 n\r\n" + "trailer<</Size 6/Root 1 0 R>>\r\n" + "startxref\r\n" + "281\r\n" + "%%EOF"; + + try + { + PoDoFo::PdfMemDocument doc; + doc.LoadFromBuffer( strNextLoop.c_str(), strNextLoop.size(), true ); + + // load should succeed, then GetOutlines goes recursive due to /Outlines loop + PoDoFo::PdfOutlines* pOutlines = doc.GetOutlines(); + CPPUNIT_ASSERT_MESSAGE( "Should throw exception", pOutlines != nullptr ); + CPPUNIT_FAIL( "Should throw exception" ); + } + catch ( PoDoFo::PdfError& error ) + { + CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef ); + } + + // https://sourceforge.net/p/podofo/tickets/25/ + std::string strSelfLoop = + "%PDF-1.0\r\n" + "1 0 obj<</Type/Catalog/Outlines 2 0 R>>endobj " + "2 0 obj<</Type/Outlines /First 2 0 R /Last 2 0 R /Count 1>>endobj" // /First and /Last loop to self + "\r\n" + "xref\r\n" + "0 3\r\n" + "0000000000 65535 f\r\n" + "0000000010 00000 n\r\n" + "0000000056 00000 n\r\n" + "trailer<</Size 3/Root 1 0 R>>\r\n" + "startxref\r\n" + "123\r\n" + "%%EOF"; + + try + { + PoDoFo::PdfMemDocument doc; + doc.LoadFromBuffer( strSelfLoop.c_str(), strSelfLoop.size(), true ); + + // load should succeed, then GetOutlines goes recursive due to /Outlines loop + PoDoFo::PdfOutlines* pOutlines = doc.GetOutlines(); + CPPUNIT_ASSERT_MESSAGE( "Should throw exception", pOutlines != nullptr ); + CPPUNIT_FAIL( "Should throw exception" ); + } + catch ( PoDoFo::PdfError& error ) + { + CPPUNIT_ASSERT( error.GetError() == PoDoFo::ePdfError_InvalidXRef ); + } +} + + void ParserTest::testRoundTripIndirectTrailerID() { std::ostringstream oss; @@ -2109,4 +2876,45 @@ return bCanTerminateProcess; } +size_t ParserTest::getStackOverflowDepth() +{ + // calculate stack overflow depth - need to do this because a value that consistently overflows a 64-bit stack + // doesn't work on 32-bit systems because they run out of heap in ReadObjects before they get a chance to overflow stack + // this is because sizeof(PdfParserObject) = 472 bytes (and there's one of these for every object read) + const size_t parserObjectSize = sizeof( PoDoFo::PdfParserObject ); +#if defined(_WIN64) + // 1 MB default stack size, 64-bit address space, Windows x64 ABI + // each stack frame has at least 4 64-bit stack params, 4 64-bit register params, plus 64-bit return address + // stack frame size increases if function contains local variables or more than 4 parameters + // see https://docs.microsoft.com/en-us/cpp/build/stack-usage?view=msvc-170 + const size_t stackSize = 1 * 1024 * 1024; + const size_t frameSize = sizeof( void* ) * (4 + 4 + 1); // 4 stack params + 4 register params + return address + const size_t maxFrames = stackSize / frameSize; // overflows at 14,563 recursive calls (or sooner if functions contain local variables) +#elif defined(_WIN32) + // 1 MB default stack size, 32-bit address space (can't allocate more than 2GB), Windows x86 thiscall calling convention + // each stack frame has at least 32-bit EBP and return address + // stack frame size increases if function contains local variables or any parameters + const size_t stackSize = 1 * 1024 * 1024; + const size_t frameSize = sizeof( void* ) * (1 + 1); // EBP and return address + const size_t maxFrames = stackSize / frameSize; // overflows at 131,072 recursive calls (or sooner if functions contain local variables or has parameters) +#else + // assume 8MB macOS / Linux default stack size, 64-bit address space, System V AMD64 ABI + // each stack frame has at least 64-bit EBP and return address + // stack frame size increases if function contains local variables or any parameters + const size_t stackSize = 8 * 1024 * 1024; + const size_t frameSize = sizeof( void* ) * (1 + 1); // EBP and return address + const size_t maxFrames = stackSize / frameSize; // overflows at 524,288 recursive calls (or sooner if functions contain local variables or has parameters) +#endif + + // add a few frames to sure we go beyond end of stack + const size_t overflowDepth = maxFrames + 1000; + + // overflowDepth must be less than GetMaxObjectCount otherwise PdfParser::ResizeOffsets + // throws an error when reading the xref offsets table, and no recursive calls are made + // must also be allocate less than half of address space to prevent out-of-memory exceptions + CPPUNIT_ASSERT( overflowDepth < static_cast <size_t> (PoDoFo::PdfParser::GetMaxObjectCount() ) ); + CPPUNIT_ASSERT( overflowDepth * parserObjectSize < std::numeric_limits<size_t>::max() / 2 ); + + return overflowDepth; +} Modified: podofo/trunk/test/unit/ParserTest.h =================================================================== --- podofo/trunk/test/unit/ParserTest.h 2022-03-12 16:08:42 UTC (rev 2048) +++ podofo/trunk/test/unit/ParserTest.h 2022-03-12 16:18:51 UTC (rev 2049) @@ -41,6 +41,14 @@ CPPUNIT_TEST( testReadXRefStreamContents ); CPPUNIT_TEST( testReadObjects ); CPPUNIT_TEST( testIsPdfFile ); + CPPUNIT_TEST( testNestedArrays ); + CPPUNIT_TEST( testNestedDictionaries ); + CPPUNIT_TEST( testNestedNameTree ); + CPPUNIT_TEST( testLoopingNameTree ); + CPPUNIT_TEST( testNestedPageTree ); + CPPUNIT_TEST( testLoopingPageTree ); + CPPUNIT_TEST( testNestedOutlines ); + CPPUNIT_TEST( testLoopingOutlines ); CPPUNIT_TEST( testRoundTripIndirectTrailerID ); CPPUNIT_TEST_SUITE_END(); @@ -78,11 +86,26 @@ //void testReadNextTrailer(); //void testCheckEOFMarker(); + // CVE-2018-8002, CVE-2021-30470 + void testNestedArrays(); + void testNestedDictionaries(); + + // CVE-2021-30471 + void testNestedNameTree(); + void testLoopingNameTree(); + void testNestedPageTree(); + void testLoopingPageTree(); + + // CVE-2020-18971 + void testNestedOutlines(); + void testLoopingOutlines(); + void testRoundTripIndirectTrailerID(); private: std::string generateXRefEntries( size_t count ); bool canOutOfMemoryKillUnitTests(); + size_t getStackOverflowDepth(); }; #endif // _PARSER_TEST_H_ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2022-03-12 16:08:44
|
Revision: 2048 http://sourceforge.net/p/podofo/code/2048 Author: mc-zyx Date: 2022-03-12 16:08:42 +0000 (Sat, 12 Mar 2022) Log Message: ----------- Patch by Mark Rogers: Refactored stack overflow recursion guard to fix CVE-2018-8002, CVE-2021-30470, CVE-2021-30471, CVE-2020-18971 Modified Paths: -------------- podofo/trunk/src/podofo/base/PdfParser.cpp podofo/trunk/src/podofo/base/PdfParser.h podofo/trunk/src/podofo/base/PdfTokenizer.cpp podofo/trunk/src/podofo/base/PdfTokenizer.h podofo/trunk/src/podofo/doc/PdfNamesTree.cpp podofo/trunk/src/podofo/doc/PdfOutlines.cpp podofo/trunk/src/podofo/doc/PdfPagesTree.cpp Modified: podofo/trunk/src/podofo/base/PdfParser.cpp =================================================================== --- podofo/trunk/src/podofo/base/PdfParser.cpp 2021-12-22 14:28:42 UTC (rev 2047) +++ podofo/trunk/src/podofo/base/PdfParser.cpp 2022-03-12 16:08:42 UTC (rev 2048) @@ -75,46 +75,7 @@ bool PdfParser::s_bIgnoreBrokenObjects = true; const long nMaxNumIndirectObjects = (1L << 23) - 1L; long PdfParser::s_nMaxObjects = nMaxNumIndirectObjects; - - -class PdfRecursionGuard -{ - // RAII recursion guard ensures m_nRecursionDepth is always decremented - // because the destructor is always called when control leaves a method - // via return or an exception. - // see http://en.cppreference.com/w/cpp/language/raii - // It's used like this in PdfParser methods - // PdfRecursionGuard guard(m_nRecursionDepth); - - public: - PdfRecursionGuard( int& nRecursionDepth ) - : m_nRecursionDepth(nRecursionDepth) - { - // be careful changing this limit - overflow limits depend on the OS, linker settings, and how much stack space compiler allocates - // 500 limit prevents overflow on Win7 with VC++ 2005 with default linker stack size (1000 caused overflow with same compiler/OS) - const int maxRecursionDepth = 500; - - ++m_nRecursionDepth; - - if ( m_nRecursionDepth > maxRecursionDepth ) - { - // avoid stack overflow on documents that have circular cross references in /Prev entries - // in trailer and XRef streams (possible via a chain of entries with a loop) - PODOFO_RAISE_ERROR( ePdfError_InvalidXRef ); - } - } - - ~PdfRecursionGuard() - { - --m_nRecursionDepth; - } - - private: - // must be a reference so that we modify m_nRecursionDepth in parent class - int& m_nRecursionDepth; -}; - PdfParser::PdfParser( PdfVecObjects* pVecObjects ) : PdfTokenizer(), m_vecObjects( pVecObjects ), m_bStrictParsing( false ) @@ -187,7 +148,6 @@ m_lLastEOFOffset = 0; m_nIncrementalUpdates = 0; - m_nRecursionDepth = 0; } void PdfParser::ParseFile( const char* pszFilename, bool bLoadOnDemand ) @@ -551,7 +511,7 @@ void PdfParser::ReadNextTrailer() { - PdfRecursionGuard guard(m_nRecursionDepth); + PdfTokenizer::RecursionGuard guard; // ReadXRefcontents has read the first 't' from "trailer" so just check for "railer" if( this->IsNextToken( "trailer" ) ) @@ -672,7 +632,7 @@ void PdfParser::ReadXRefContents( pdf_long lOffset, bool bPositionAtEnd ) { - PdfRecursionGuard guard(m_nRecursionDepth); + PdfTokenizer::RecursionGuard guard; pdf_int64 nFirstObject = 0; pdf_int64 nNumObjects = 0; @@ -939,7 +899,7 @@ void PdfParser::ReadXRefStreamContents( pdf_long lOffset, bool bReadOnlyTrailer ) { - PdfRecursionGuard guard(m_nRecursionDepth); + PdfTokenizer::RecursionGuard guard; m_device.Device()->Seek( lOffset ); Modified: podofo/trunk/src/podofo/base/PdfParser.h =================================================================== --- podofo/trunk/src/podofo/base/PdfParser.h 2021-12-22 14:28:42 UTC (rev 2047) +++ podofo/trunk/src/podofo/base/PdfParser.h 2022-03-12 16:08:42 UTC (rev 2048) @@ -602,7 +602,6 @@ bool m_bStrictParsing; int m_nIncrementalUpdates; - int m_nRecursionDepth; static bool s_bIgnoreBrokenObjects; Modified: podofo/trunk/src/podofo/base/PdfTokenizer.cpp =================================================================== --- podofo/trunk/src/podofo/base/PdfTokenizer.cpp 2021-12-22 14:28:42 UTC (rev 2047) +++ podofo/trunk/src/podofo/base/PdfTokenizer.cpp 2022-03-12 16:08:42 UTC (rev 2048) @@ -59,6 +59,48 @@ namespace PoDoFo { +// default stack sizes +// Windows: 1MB on x32, x64, ARM https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=msvc-160 +// Windows IIS: 512 KB for 64-bit worker processes, 256 KB for 32-bit worker processes +// macOS: 8MB on main thread, 512KB on secondary threads https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html +// iOS: 1MB on main thread, 512KB on secondary threads +// Modern Linux distros: usually 8MB on main and secondary threads (but setting ulimit RLIMIT_STACK to unlimited *reduces* the secondary stack size on most architectures: see https://man7.org/linux/man-pages/man3/pthread_create.3.html#NOTES ) +// the amount allocated on stack for local variables and function parameters varies between x86 and x64 +// in x86 pointers are 32-bit but all function parameters are on stack +// in x64 pointers are 64-bit but first 4 function params are passed in registers +// the biggest difference is between debug and non-debug stacks: a debug stack frame can be around 3x larger +// due to instrumentation like ASAN which put guard bytes around stack variables to detect buffer overflows + +const int maxRecursionDepthDefault = 256; +int PdfTokenizer::RecursionGuard::s_maxRecursionDepth = maxRecursionDepthDefault; + +#if defined(PODOFO_MULTI_THREAD) +thread_local int PdfTokenizer::RecursionGuard::s_nRecursionDepth = 0; // PoDoFo is multi-threaded and requires a C++11 compiler with thread_local support +#else +int PdfTokenizer::RecursionGuard::s_nRecursionDepth = 0; // PoDoFo is single-threaded +#endif + +void PdfTokenizer::RecursionGuard::Enter() +{ + ++s_nRecursionDepth; + + if ( s_nRecursionDepth > s_maxRecursionDepth ) + { + // avoid stack overflow on documents that have circular cross references, loops + // or very deeply nested structures, can happen with + // /Prev entries in trailer and XRef streams (possible via a chain of entries with a loop) + // /Kids entries that loop back to self or parent + // deeply nested Dictionary or Array objects (possible with lots of [[[[[[[[]]]]]]]] brackets) + // mutually recursive loops involving several objects are possible + PODOFO_RAISE_ERROR( ePdfError_InvalidXRef ); + } +} + +void PdfTokenizer::RecursionGuard::Exit() +{ + --s_nRecursionDepth; +} + namespace PdfTokenizerNameSpace{ static const int g_MapAllocLen = 256; @@ -392,6 +434,7 @@ void PdfTokenizer::GetNextVariant( const char* pszToken, EPdfTokenType eType, PdfVariant& rVariant, PdfEncrypt* pEncrypt ) { + PdfTokenizer::RecursionGuard guard; EPdfDataType eDataType = this->DetermineDataType( pszToken, eType, rVariant ); if( eDataType == ePdfDataType_Null || Modified: podofo/trunk/src/podofo/base/PdfTokenizer.h =================================================================== --- podofo/trunk/src/podofo/base/PdfTokenizer.h 2021-12-22 14:28:42 UTC (rev 2047) +++ podofo/trunk/src/podofo/base/PdfTokenizer.h 2022-03-12 16:08:42 UTC (rev 2048) @@ -58,6 +58,7 @@ typedef TTokenizerQueque::iterator TITokenizerQueque; typedef TTokenizerQueque::const_iterator TCITokenizerQueque; +class PdfObject; /** * A simple tokenizer for PDF files and PDF content streams @@ -71,6 +72,44 @@ virtual ~PdfTokenizer(); + class RecursionGuard + { + // RAII recursion guard ensures recursion depth is always decremented + // because the destructor is always called when control leaves a method + // via return or an exception. + // see http://en.cppreference.com/w/cpp/language/raii + + // It's used like this: + // PdfRecursionGuard guard; + + public: + RecursionGuard() { Enter(); } + ~RecursionGuard() { Exit(); } + + // set maximum recursion depth (set to 0 to disable recursion check) + static void SetMaxRecursionDepth( int32_t maxRecursionDepth ) + { + s_maxRecursionDepth = maxRecursionDepth; + } + + static int32_t GetMaxRecursionDepth() + { + return s_maxRecursionDepth; + } + + private: + void Enter(); + void Exit(); + + static int s_maxRecursionDepth; + + #if defined(PODOFO_MULTI_THREAD) + static thread_local int s_nRecursionDepth; // PoDoFo is multi-threaded and requires a C++11 compiler with thread_local support + #else + static int s_nRecursionDepth; // PoDoFo is single-threaded + #endif + }; + /** Reads the next token from the current file position * ignoring all comments. * Modified: podofo/trunk/src/podofo/doc/PdfNamesTree.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfNamesTree.cpp 2021-12-22 14:28:42 UTC (rev 2047) +++ podofo/trunk/src/podofo/doc/PdfNamesTree.cpp 2022-03-12 16:08:42 UTC (rev 2048) @@ -474,6 +474,8 @@ void PdfNamesTree::AddToDictionary( PdfObject* pObj, PdfDictionary & rDict ) { + PdfTokenizer::RecursionGuard guard; + if( pObj->GetDictionary().HasKey("Kids") ) { const PdfArray & kids = pObj->MustGetIndirectKey("Kids")->GetArray(); Modified: podofo/trunk/src/podofo/doc/PdfOutlines.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfOutlines.cpp 2021-12-22 14:28:42 UTC (rev 2047) +++ podofo/trunk/src/podofo/doc/PdfOutlines.cpp 2022-03-12 16:08:42 UTC (rev 2048) @@ -74,6 +74,7 @@ : PdfElement( NULL, pObject ), m_pParentOutline( pParentOutline ), m_pPrev( pPrevious ), m_pNext( NULL ), m_pFirst( NULL ), m_pLast( NULL ), m_pDestination( NULL ), m_pAction( NULL ) { + PdfTokenizer::RecursionGuard guard; PdfReference first, next; if( this->GetObject()->GetDictionary().HasKey( "First" ) ) Modified: podofo/trunk/src/podofo/doc/PdfPagesTree.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfPagesTree.cpp 2021-12-22 14:28:42 UTC (rev 2047) +++ podofo/trunk/src/podofo/doc/PdfPagesTree.cpp 2022-03-12 16:08:42 UTC (rev 2048) @@ -315,6 +315,8 @@ PdfObject* PdfPagesTree::GetPageNode( int nPageNum, PdfObject* pParent, PdfObjectList & rLstParents ) { + PdfTokenizer::RecursionGuard guard; + if( !pParent ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: Alberto I. <alb...@gm...> - 2022-01-26 15:53:41
|
Hi, can I create a fork? I would like make a contribution. Best regards, |
From: <mc...@us...> - 2021-12-22 14:28:44
|
Revision: 2047 http://sourceforge.net/p/podofo/code/2047 Author: mc-zyx Date: 2021-12-22 14:28:42 +0000 (Wed, 22 Dec 2021) Log Message: ----------- Patch by Michal Sudolsky: Fix an undefined behavior in Big2Little() This function sometimes takes negative values for example when contourCount is -1 (0xFFFF) which is udefined behavior "For negative a, the behavior of a << b is undefined.". Possible output from sanitizer: podofo/doc/PdfFontTTFSubset.cpp:73:18: runtime error: left shift of negative value -1 SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior podofo/doc/PdfFontTTFSubset.cpp:73:18 in inline short Big2Little(short big) { return ((big << 8) & 0xFF00) | ((big >> 8) & 0x00FF); } Called from here: GetData( ctx.ulGlyfTableOffset + ctx.glyphData.glyphAddress, &ctx.contourCount, __LENGTH_WORD); ctx.contourCount = Big2Little(ctx.contourCount); if (ctx.contourCount < 0) { /* skeep over numberOfContours, xMin, yMin, xMax and yMax */ LoadCompound(ctx, ctx.glyphData.glyphAddress + 5 * __LENGTH_WORD); Modified Paths: -------------- podofo/trunk/src/podofo/doc/PdfFontTTFSubset.cpp Modified: podofo/trunk/src/podofo/doc/PdfFontTTFSubset.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfFontTTFSubset.cpp 2021-11-08 09:39:46 UTC (rev 2046) +++ podofo/trunk/src/podofo/doc/PdfFontTTFSubset.cpp 2021-12-22 14:28:42 UTC (rev 2047) @@ -70,7 +70,7 @@ inline short Big2Little(short big) { - return ((big << 8) & 0xFF00) | ((big >> 8) & 0x00FF); + return Big2Little(static_cast<unsigned short>(big)); } #else #define Big2Little( x ) x This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2021-11-08 09:39:49
|
Revision: 2046 http://sourceforge.net/p/podofo/code/2046 Author: mc-zyx Date: 2021-11-08 09:39:46 +0000 (Mon, 08 Nov 2021) Log Message: ----------- Patch by Federico Kircheis: Let the PdfSignOutputDevice::AdjustByteRange() return the resulting array The adjusted byte range array can be used optionally by the caller to know where the signature is placed. Modified Paths: -------------- podofo/trunk/src/podofo/doc/PdfSignOutputDevice.cpp podofo/trunk/src/podofo/doc/PdfSignOutputDevice.h Modified: podofo/trunk/src/podofo/doc/PdfSignOutputDevice.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfSignOutputDevice.cpp 2021-08-19 17:00:45 UTC (rev 2045) +++ podofo/trunk/src/podofo/doc/PdfSignOutputDevice.cpp 2021-11-08 09:39:46 UTC (rev 2046) @@ -137,7 +137,7 @@ } } -void PdfSignOutputDevice::AdjustByteRange() +PdfArray PdfSignOutputDevice::AdjustByteRange() { if(!m_bBeaconFound) { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); @@ -185,6 +185,7 @@ m_pRealDevice->Seek(offset); m_pRealDevice->Write(sPosition.c_str(), sPosition.size()); + return arr; } size_t PdfSignOutputDevice::ReadForSignature(char* pBuffer, size_t lLen) Modified: podofo/trunk/src/podofo/doc/PdfSignOutputDevice.h =================================================================== --- podofo/trunk/src/podofo/doc/PdfSignOutputDevice.h 2021-08-19 17:00:45 UTC (rev 2045) +++ podofo/trunk/src/podofo/doc/PdfSignOutputDevice.h 2021-11-08 09:39:46 UTC (rev 2046) @@ -38,6 +38,7 @@ #include "../base/PdfOutputDevice.h" #include "../base/PdfData.h" #include "../base/PdfString.h" +#include "../base/PdfArray.h" namespace PoDoFo { @@ -83,7 +84,7 @@ /** Modify ByteRange entry according to signature position * */ - virtual void AdjustByteRange(); + virtual PdfArray AdjustByteRange(); /** Read data for signature */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2021-08-19 17:00:47
|
Revision: 2045 http://sourceforge.net/p/podofo/code/2045 Author: mc-zyx Date: 2021-08-19 17:00:45 +0000 (Thu, 19 Aug 2021) Log Message: ----------- Patch by Christopher Creutzig: PdfFontFactory: Ignore FontDescriptor when without Widths/FirstChar/LastChar Closes https://sourceforge.net/p/podofo/tickets/133/ Modified Paths: -------------- podofo/trunk/src/podofo/doc/PdfFontFactory.cpp Modified: podofo/trunk/src/podofo/doc/PdfFontFactory.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfFontFactory.cpp 2021-08-19 16:50:23 UTC (rev 2044) +++ podofo/trunk/src/podofo/doc/PdfFontFactory.cpp 2021-08-19 17:00:45 UTC (rev 2045) @@ -262,7 +262,12 @@ pEncoding = pObject->GetIndirectKey( "Encoding" ); // OC 13.08.2010: Handle missing FontDescriptor for the 14 standard fonts: - if( !pDescriptor ) + // CC 09.04.2021: Handle fonts with FontDescriptor, but without the then required + // additional fields as if FontDescriptor was absent as well. + if( !pDescriptor || + !pObject->GetIndirectKey( "Widths" ) || + !pObject->GetIndirectKey( "FirstChar" ) || + !pObject->GetIndirectKey( "LastChar" ) ) { // Check if its a PdfFontType1Base14 PdfObject* pBaseFont = NULL; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2021-08-19 16:50:25
|
Revision: 2044 http://sourceforge.net/p/podofo/code/2044 Author: mc-zyx Date: 2021-08-19 16:50:23 +0000 (Thu, 19 Aug 2021) Log Message: ----------- Patch by Christopher Creutzig: Prefer toUnicode within PdfDifferenceEncoding Closes https://sourceforge.net/p/podofo/tickets/107/ Modified Paths: -------------- podofo/trunk/src/podofo/doc/PdfDifferenceEncoding.cpp podofo/trunk/src/podofo/doc/PdfDifferenceEncoding.h podofo/trunk/src/podofo/doc/PdfEncodingObjectFactory.cpp podofo/trunk/src/podofo/doc/PdfFontFactory.cpp Modified: podofo/trunk/src/podofo/doc/PdfDifferenceEncoding.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfDifferenceEncoding.cpp 2021-08-18 17:46:20 UTC (rev 2043) +++ podofo/trunk/src/podofo/doc/PdfDifferenceEncoding.cpp 2021-08-19 16:50:23 UTC (rev 2044) @@ -2378,8 +2378,8 @@ Init(); } -PdfDifferenceEncoding::PdfDifferenceEncoding( PdfObject* pObject, bool bAutoDelete, bool bExplicitNames ) - : PdfEncoding( 0x00, 0xff ), PdfElement( NULL, pObject ), +PdfDifferenceEncoding::PdfDifferenceEncoding( PdfObject* pObject, bool bAutoDelete, bool bExplicitNames, PdfObject* pToUnicode ) + : PdfEncoding( 0x00, 0xff, pToUnicode ), PdfElement( NULL, pObject ), m_bAutoDelete( bAutoDelete ) { CreateID(); @@ -2580,6 +2580,17 @@ // issues so an API change is a Bad Thing (mabri: IMO at least) to do now. if( m_differences.Contains( static_cast<int>(pszInput[i]), name, value ) ) pszUtf16[i] = value; + if( m_bToUnicodeIsLoaded ) + { + value = GetUnicodeValue(pszInput[i]); + if (value != 0) { +#ifdef PODOFO_IS_LITTLE_ENDIAN + pszUtf16[i] = (value << 8) | (value >> 8 ); +#else + pszUtf16[i] = value; +#endif // PODOFO_IS_LITTLE_ENDIAN + } + } } PdfString ret( pszUtf16, lLen ); Modified: podofo/trunk/src/podofo/doc/PdfDifferenceEncoding.h =================================================================== --- podofo/trunk/src/podofo/doc/PdfDifferenceEncoding.h 2021-08-18 17:46:20 UTC (rev 2043) +++ podofo/trunk/src/podofo/doc/PdfDifferenceEncoding.h 2021-08-19 16:50:23 UTC (rev 2044) @@ -206,7 +206,9 @@ * \param bAutoDelete if true the encoding is deleted by its owning font * \param bExplicitNames if true, glyph names are meaningless explicit keys on the font (used for Type3 fonts) */ - PdfDifferenceEncoding( PdfObject* pObject, bool bAutoDelete = true, bool bExplicitNames = false ); + PdfDifferenceEncoding(PdfObject* pObject, bool bAutoDelete = true, + bool bExplicitNames = false, + PdfObject* pToUnicode = NULL); /** Convert a standard character name to a unicode code point * Modified: podofo/trunk/src/podofo/doc/PdfEncodingObjectFactory.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfEncodingObjectFactory.cpp 2021-08-18 17:46:20 UTC (rev 2043) +++ podofo/trunk/src/podofo/doc/PdfEncodingObjectFactory.cpp 2021-08-19 16:50:23 UTC (rev 2044) @@ -86,8 +86,7 @@ else if (pObject->IsDictionary ()) { - - return new PdfDifferenceEncoding (pObject, true, bExplicitNames); + return new PdfDifferenceEncoding (pObject, true, bExplicitNames, pToUnicode); } Modified: podofo/trunk/src/podofo/doc/PdfFontFactory.cpp =================================================================== --- podofo/trunk/src/podofo/doc/PdfFontFactory.cpp 2021-08-18 17:46:20 UTC (rev 2043) +++ podofo/trunk/src/podofo/doc/PdfFontFactory.cpp 2021-08-19 16:50:23 UTC (rev 2044) @@ -325,7 +325,7 @@ if ( pEncoding ) // FontDescriptor may only be present in PDF 1.5+ { const PdfEncoding* const pPdfEncoding = - PdfEncodingObjectFactory::CreateEncoding( pEncoding, NULL, true ); + PdfEncodingObjectFactory::CreateEncoding( pEncoding, pObject->GetIndirectKey("ToUnicode"), true ); pMetrics = new PdfFontMetricsObject( pObject, pDescriptor, pPdfEncoding ); pFont = new PdfFontType3( pMetrics, pPdfEncoding, pObject ); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2021-08-18 17:46:23
|
Revision: 2043 http://sourceforge.net/p/podofo/code/2043 Author: mc-zyx Date: 2021-08-18 17:46:20 +0000 (Wed, 18 Aug 2021) Log Message: ----------- Patch by Christopher Creutzig: Make it possible to return embedded NUL from PdfEncoding Closes https://sourceforge.net/p/podofo/tickets/105/ Modified Paths: -------------- podofo/trunk/src/podofo/base/PdfEncoding.cpp Modified: podofo/trunk/src/podofo/base/PdfEncoding.cpp =================================================================== --- podofo/trunk/src/podofo/base/PdfEncoding.cpp 2021-08-18 17:21:48 UTC (rev 2042) +++ podofo/trunk/src/podofo/base/PdfEncoding.cpp 2021-08-18 17:46:20 UTC (rev 2043) @@ -455,7 +455,7 @@ pszStringUtf16[lLen] = 0; - PdfString sStr( pszStringUtf16 ); + PdfString sStr( pszStringUtf16, lLen ); podofo_free( pszStringUtf16 ); return sStr; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mc...@us...> - 2021-08-18 17:21:51
|
Revision: 2042 http://sourceforge.net/p/podofo/code/2042 Author: mc-zyx Date: 2021-08-18 17:21:48 +0000 (Wed, 18 Aug 2021) Log Message: ----------- Patch by Chris: podofoimpose: Properly copy 'number' and 'null' objects In the /FontFile in the input document the /Length1, /Length2 and /Length3 had a reference to 'null' or a 'number' value. With the previous method of podofoimpose those references got messed up in the output document (wrong ref). The fix writes the correct references to 'number' and 'null' data types for the output document. Modified Paths: -------------- podofo/trunk/tools/podofoimpose/pdftranslator.cpp Modified: podofo/trunk/tools/podofoimpose/pdftranslator.cpp =================================================================== --- podofo/trunk/tools/podofoimpose/pdftranslator.cpp 2021-08-18 17:14:51 UTC (rev 2041) +++ podofo/trunk/tools/podofoimpose/pdftranslator.cpp 2021-08-18 17:21:48 UTC (rev 2042) @@ -285,6 +285,15 @@ { ret = targetDoc->GetObjects().CreateObject(obj->GetName()); } + else if ( obj->IsNumber() ) + { + ret = targetDoc->GetObjects().CreateObject(obj->GetNumber()); + } + else if ( obj->IsNull() ) + { + ret = targetDoc->GetObjects().CreateObject(); + ret->Clear(); + } else { ret = new PdfObject ( *obj );//targetDoc->GetObjects().CreateObject(*obj); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |