Commit 30287d2d655e1a9fe476477b6c74b62f816f37d6
1 parent
5e3bad2f
Allow OS-provided secure random to be disabled
Showing
6 changed files
with
105 additions
and
13 deletions
ChangeLog
| @@ -9,6 +9,13 @@ | @@ -9,6 +9,13 @@ | ||
| 9 | OS-provided or insecure random number generation. See | 9 | OS-provided or insecure random number generation. See |
| 10 | documentation for 5.1.0 for details. | 10 | documentation for 5.1.0 for details. |
| 11 | 11 | ||
| 12 | + * Add configure option --enable-os-secure-random (enabled by | ||
| 13 | + default). Pass --disable-os-secure-random or define | ||
| 14 | + SKIP_OS_SECURE_RANDOM to avoid attempts to use the operating | ||
| 15 | + system-provided secure random number generation. This can be | ||
| 16 | + especially useful on Windows if you wish to avoid any dependency | ||
| 17 | + on Microsoft's cryptography system. | ||
| 18 | + | ||
| 12 | 2013-11-29 Jay Berkenbilt <ejb@ql.org> | 19 | 2013-11-29 Jay Berkenbilt <ejb@ql.org> |
| 13 | 20 | ||
| 14 | * If NO_GET_ENVIRONMENT is #defined, for Windows only, | 21 | * If NO_GET_ENVIRONMENT is #defined, for Windows only, |
README
| @@ -196,17 +196,41 @@ packages for qpdf enable this option, for example. | @@ -196,17 +196,41 @@ packages for qpdf enable this option, for example. | ||
| 196 | Random Number Generation | 196 | Random Number Generation |
| 197 | ======================== | 197 | ======================== |
| 198 | 198 | ||
| 199 | -When the qpdf detects either the Windows cryptography API or the | ||
| 200 | -existence of /dev/urandom, /dev/arandom, or /dev/random, it uses them | ||
| 201 | -to generate cryptography secure random numbers. If none of these | ||
| 202 | -conditions are true, the build will fail with an error. It is | ||
| 203 | -possible to configure qpdf with the --enable-insecure-random option, | ||
| 204 | -in which case it will generate random numbers with stdlib's random() | ||
| 205 | -or rand() calls instead. These random numbers are not cryptography | ||
| 206 | -secure, but the qpdf library is fully functional using them. Using | ||
| 207 | -non-secure random numbers means that it's easier in some cases to | ||
| 208 | -guess encryption keys. If you're not generating encrypted files, | ||
| 209 | -there's no advantage to using secure random numbers. | 199 | +By default, when the qpdf detects either the Windows cryptography API |
| 200 | +or the existence of /dev/urandom, /dev/arandom, or /dev/random, it | ||
| 201 | +uses them to generate cryptography secure random numbers. If none of | ||
| 202 | +these conditions are true, the build will fail with an error. This | ||
| 203 | +behavior can be modified in several ways: | ||
| 204 | + | ||
| 205 | + * If you configure with --disable-os-secure-random or define | ||
| 206 | + SKIP_OS_SECURE_RANDOM, qpdf will not attempt to use Windows | ||
| 207 | + cryptography or the random device. You must either supply your own | ||
| 208 | + random data provider or allow use of insecure random numbers. | ||
| 209 | + | ||
| 210 | + * If you configure qpdf with the --enable-insecure-random option or | ||
| 211 | + define USE_INSECURE_RANDOM, qpdf will try insecure random numbers | ||
| 212 | + if OS-provided secure random numbers are disabled. This is not a | ||
| 213 | + fallback. In order for insecure random numbers to be used, you | ||
| 214 | + must also disable OS secure random numbers since, otherwise, | ||
| 215 | + failure to find OS secure random numbers is a compile error. The | ||
| 216 | + insecure random number source is stdlib's random() or rand() calls. | ||
| 217 | + These random numbers are not cryptography secure, but the qpdf | ||
| 218 | + library is fully functional using them. Using non-secure random | ||
| 219 | + numbers means that it's easier in some cases to guess encryption | ||
| 220 | + keys. If you're not generating encrypted files, there's no | ||
| 221 | + advantage to using secure random numbers. | ||
| 222 | + | ||
| 223 | + * In all cases, you may supply your own random data provider. To do | ||
| 224 | + this, derive a class from qpdf/RandomDataProvider (since 5.1.0) and | ||
| 225 | + call QUtil::setRandomDataProvider before you create any QPDF | ||
| 226 | + objects. If you supply your own random data provider, it will | ||
| 227 | + always be used even if support for one of the other random data | ||
| 228 | + providers is compiled in. If you wish to avoid any possibility of | ||
| 229 | + your build of qpdf from using anything but a user-supplied random | ||
| 230 | + data provider, you can define SKIP_OS_SECURE_RANDOM and not | ||
| 231 | + USE_INSECURE_RANDOM. In this case, qpdf will throw a runtime error | ||
| 232 | + if any attempt is made to generate random numbers and no random | ||
| 233 | + data provider has been supplied. | ||
| 210 | 234 | ||
| 211 | If you are building qpdf on a platform that qpdf doesn't know how to | 235 | If you are building qpdf on a platform that qpdf doesn't know how to |
| 212 | generate secure random numbers on, a patch would be welcome. | 236 | generate secure random numbers on, a patch would be welcome. |
configure.ac
| @@ -26,11 +26,26 @@ AC_ARG_ENABLE(insecure-random, | @@ -26,11 +26,26 @@ AC_ARG_ENABLE(insecure-random, | ||
| 26 | fi], [qpdf_INSECURE_RANDOM=0]) | 26 | fi], [qpdf_INSECURE_RANDOM=0]) |
| 27 | if test "$qpdf_INSECURE_RANDOM" = "1"; then | 27 | if test "$qpdf_INSECURE_RANDOM" = "1"; then |
| 28 | AC_MSG_RESULT(yes) | 28 | AC_MSG_RESULT(yes) |
| 29 | - AC_DEFINE([USE_INSECURE_RANDOM], [1], [Whether to use inscure random numbers]) | 29 | + AC_DEFINE([USE_INSECURE_RANDOM], [1], [Whether to use insecure random numbers]) |
| 30 | else | 30 | else |
| 31 | AC_MSG_RESULT(no) | 31 | AC_MSG_RESULT(no) |
| 32 | fi | 32 | fi |
| 33 | 33 | ||
| 34 | +AC_ARG_ENABLE(os-secure-random, | ||
| 35 | + AS_HELP_STRING([--enable-os-secure-random], | ||
| 36 | + [whether to try to use OS-provided secure random numbers (default is yes)]), | ||
| 37 | + [if test "$enableval" = "yes"; then | ||
| 38 | + qpdf_OS_SECURE_RANDOM=1; | ||
| 39 | + else | ||
| 40 | + qpdf_OS_SECURE_RANDOM=0; | ||
| 41 | + fi], [qpdf_OS_SECURE_RANDOM=1]) | ||
| 42 | +if test "$qpdf_OS_SECURE_RANDOM" = "1"; then | ||
| 43 | + AC_MSG_RESULT(yes) | ||
| 44 | +else | ||
| 45 | + AC_MSG_RESULT(no) | ||
| 46 | + AC_DEFINE([SKIP_OS_SECURE_RANDOM], [1], [Whether to suppres use of OS-provided secure random numbers]) | ||
| 47 | +fi | ||
| 48 | + | ||
| 34 | AX_RANDOM_DEVICE | 49 | AX_RANDOM_DEVICE |
| 35 | 50 | ||
| 36 | USE_EXTERNAL_LIBS=0 | 51 | USE_EXTERNAL_LIBS=0 |
| @@ -71,7 +86,7 @@ if test "$BUILD_INTERNAL_LIBS" = "0"; then | @@ -71,7 +86,7 @@ if test "$BUILD_INTERNAL_LIBS" = "0"; then | ||
| 71 | AC_SEARCH_LIBS(pcre_compile,pcre,,[MISSING_PCRE=1; MISSING_ANY=1]) | 86 | AC_SEARCH_LIBS(pcre_compile,pcre,,[MISSING_PCRE=1; MISSING_ANY=1]) |
| 72 | fi | 87 | fi |
| 73 | 88 | ||
| 74 | -if test "x$qpdf_INSECURE_RANDOM" != "x1"; then | 89 | +if test "x$qpdf_OS_SECURE_RANDOM" = "x1"; then |
| 75 | OLIBS=$LIBS | 90 | OLIBS=$LIBS |
| 76 | LIBS="$LIBS Advapi32.lib" | 91 | LIBS="$LIBS Advapi32.lib" |
| 77 | AC_MSG_CHECKING(for Advapi32 library) | 92 | AC_MSG_CHECKING(for Advapi32 library) |
libqpdf/SecureRandomDataProvider.cc
| @@ -19,6 +19,22 @@ SecureRandomDataProvider::~SecureRandomDataProvider() | @@ -19,6 +19,22 @@ SecureRandomDataProvider::~SecureRandomDataProvider() | ||
| 19 | { | 19 | { |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | +#ifdef SKIP_OS_SECURE_RANDOM | ||
| 23 | + | ||
| 24 | +void | ||
| 25 | +SecureRandomDataProvider::provideRandomData(unsigned char* data, size_t len) | ||
| 26 | +{ | ||
| 27 | + throw std::logic_error("SecureRandomDataProvider::provideRandomData called when support was not compiled in"); | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +RandomDataProvider* | ||
| 31 | +SecureRandomDataProvider::getInstance() | ||
| 32 | +{ | ||
| 33 | + return 0; | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +#else | ||
| 37 | + | ||
| 22 | #ifdef _WIN32 | 38 | #ifdef _WIN32 |
| 23 | 39 | ||
| 24 | class WindowsCryptProvider | 40 | class WindowsCryptProvider |
| @@ -84,3 +100,5 @@ SecureRandomDataProvider::getInstance() | @@ -84,3 +100,5 @@ SecureRandomDataProvider::getInstance() | ||
| 84 | static SecureRandomDataProvider instance; | 100 | static SecureRandomDataProvider instance; |
| 85 | return &instance; | 101 | return &instance; |
| 86 | } | 102 | } |
| 103 | + | ||
| 104 | +#endif |
libtests/random.cc
| 1 | #include <qpdf/QUtil.hh> | 1 | #include <qpdf/QUtil.hh> |
| 2 | +#include <qpdf/qpdf-config.h> | ||
| 2 | #include <qpdf/InsecureRandomDataProvider.hh> | 3 | #include <qpdf/InsecureRandomDataProvider.hh> |
| 3 | #include <qpdf/SecureRandomDataProvider.hh> | 4 | #include <qpdf/SecureRandomDataProvider.hh> |
| 4 | #include <iostream> | 5 | #include <iostream> |
| @@ -36,6 +37,7 @@ int main() | @@ -36,6 +37,7 @@ int main() | ||
| 36 | { | 37 | { |
| 37 | std::cout << "fail: two insecure randoms were the same\n"; | 38 | std::cout << "fail: two insecure randoms were the same\n"; |
| 38 | } | 39 | } |
| 40 | +#ifndef SKIP_OS_SECURE_RANDOM | ||
| 39 | SecureRandomDataProvider srdp; | 41 | SecureRandomDataProvider srdp; |
| 40 | srdp.provideRandomData(reinterpret_cast<unsigned char*>(&r1), 4); | 42 | srdp.provideRandomData(reinterpret_cast<unsigned char*>(&r1), 4); |
| 41 | srdp.provideRandomData(reinterpret_cast<unsigned char*>(&r2), 4); | 43 | srdp.provideRandomData(reinterpret_cast<unsigned char*>(&r2), 4); |
| @@ -43,6 +45,7 @@ int main() | @@ -43,6 +45,7 @@ int main() | ||
| 43 | { | 45 | { |
| 44 | std::cout << "fail: two secure randoms were the same\n"; | 46 | std::cout << "fail: two secure randoms were the same\n"; |
| 45 | } | 47 | } |
| 48 | +#endif | ||
| 46 | BogusRandomDataProvider brdp; | 49 | BogusRandomDataProvider brdp; |
| 47 | QUtil::setRandomDataProvider(&brdp); | 50 | QUtil::setRandomDataProvider(&brdp); |
| 48 | r1 = QUtil::random(); | 51 | r1 = QUtil::random(); |
manual/qpdf-manual.xml
| @@ -1851,6 +1851,31 @@ outfile.pdf</option> | @@ -1851,6 +1851,31 @@ outfile.pdf</option> | ||
| 1851 | preserved as clear-text if it is that way in the original file. | 1851 | preserved as clear-text if it is that way in the original file. |
| 1852 | </para> | 1852 | </para> |
| 1853 | </sect1> | 1853 | </sect1> |
| 1854 | + <sect1 id="ref.random-numbers"> | ||
| 1855 | + <title>Random Number Generation</title> | ||
| 1856 | + <para> | ||
| 1857 | + QPDF generates random numbers to support generation of encrypted | ||
| 1858 | + data. Versions prior to 5.0.1 used <function>random</function> or | ||
| 1859 | + <function>rand</function> from <filename>stdlib</filename> to | ||
| 1860 | + generate random numbers. Version 5.0.1, if available, used | ||
| 1861 | + operating system-provided secure random number generation instead, | ||
| 1862 | + enabling use of <filename>stdlib</filename> random number | ||
| 1863 | + generation only if enabled by a compile-time option. Starting in | ||
| 1864 | + version 5.1.0, use of insecure random numbers was disabled unless | ||
| 1865 | + enabled at compile time. Starting in version 5.1.0, it is also | ||
| 1866 | + possible for you to disable use of OS-provided secure random | ||
| 1867 | + numbers. This is especially useful on Windows if you want to | ||
| 1868 | + avoid a dependency on Microsoft's cryptography API. In this case, | ||
| 1869 | + you must provide your own random data provider. Regardless of how | ||
| 1870 | + you compile qpdf, starting in version 5.1.0, it is possible for | ||
| 1871 | + you to provide your own random data provider at runtime. This | ||
| 1872 | + would enable you to use some software-based secure pseudorandom | ||
| 1873 | + number generator and to avoid use of whatever the operating system | ||
| 1874 | + provides. For details on how to do this, please refer to the | ||
| 1875 | + top-level README file in the source distribution and to comments | ||
| 1876 | + in <filename>QUtil.hh</filename>. | ||
| 1877 | + </para> | ||
| 1878 | + </sect1> | ||
| 1854 | <sect1 id="ref.adding-and-remove-pages"> | 1879 | <sect1 id="ref.adding-and-remove-pages"> |
| 1855 | <title>Adding and Removing Pages</title> | 1880 | <title>Adding and Removing Pages</title> |
| 1856 | <para> | 1881 | <para> |