Commit 30287d2d655e1a9fe476477b6c74b62f816f37d6

Authored by Jay Berkenbilt
1 parent 5e3bad2f

Allow OS-provided secure random to be disabled

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,
@@ -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 &quot;$BUILD_INTERNAL_LIBS&quot; = &quot;0&quot;; then @@ -71,7 +86,7 @@ if test &quot;$BUILD_INTERNAL_LIBS&quot; = &quot;0&quot;; 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&lt;/option&gt; @@ -1851,6 +1851,31 @@ outfile.pdf&lt;/option&gt;
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>