Allow OS-provided secure random to be disabled

This commit is contained in:
Jay Berkenbilt 2013-11-30 12:25:01 -05:00
parent 5e3bad2f86
commit 30287d2d65
6 changed files with 105 additions and 13 deletions

View File

@ -9,6 +9,13 @@
OS-provided or insecure random number generation. See
documentation for 5.1.0 for details.
* Add configure option --enable-os-secure-random (enabled by
default). Pass --disable-os-secure-random or define
SKIP_OS_SECURE_RANDOM to avoid attempts to use the operating
system-provided secure random number generation. This can be
especially useful on Windows if you wish to avoid any dependency
on Microsoft's cryptography system.
2013-11-29 Jay Berkenbilt <ejb@ql.org>
* If NO_GET_ENVIRONMENT is #defined, for Windows only,

46
README
View File

@ -196,17 +196,41 @@ packages for qpdf enable this option, for example.
Random Number Generation
========================
When the qpdf detects either the Windows cryptography API or the
existence of /dev/urandom, /dev/arandom, or /dev/random, it uses them
to generate cryptography secure random numbers. If none of these
conditions are true, the build will fail with an error. It is
possible to configure qpdf with the --enable-insecure-random option,
in which case it will generate random numbers with stdlib's random()
or rand() calls instead. These random numbers are not cryptography
secure, but the qpdf library is fully functional using them. Using
non-secure random numbers means that it's easier in some cases to
guess encryption keys. If you're not generating encrypted files,
there's no advantage to using secure random numbers.
By default, when the qpdf detects either the Windows cryptography API
or the existence of /dev/urandom, /dev/arandom, or /dev/random, it
uses them to generate cryptography secure random numbers. If none of
these conditions are true, the build will fail with an error. This
behavior can be modified in several ways:
* If you configure with --disable-os-secure-random or define
SKIP_OS_SECURE_RANDOM, qpdf will not attempt to use Windows
cryptography or the random device. You must either supply your own
random data provider or allow use of insecure random numbers.
* If you configure qpdf with the --enable-insecure-random option or
define USE_INSECURE_RANDOM, qpdf will try insecure random numbers
if OS-provided secure random numbers are disabled. This is not a
fallback. In order for insecure random numbers to be used, you
must also disable OS secure random numbers since, otherwise,
failure to find OS secure random numbers is a compile error. The
insecure random number source is stdlib's random() or rand() calls.
These random numbers are not cryptography secure, but the qpdf
library is fully functional using them. Using non-secure random
numbers means that it's easier in some cases to guess encryption
keys. If you're not generating encrypted files, there's no
advantage to using secure random numbers.
* In all cases, you may supply your own random data provider. To do
this, derive a class from qpdf/RandomDataProvider (since 5.1.0) and
call QUtil::setRandomDataProvider before you create any QPDF
objects. If you supply your own random data provider, it will
always be used even if support for one of the other random data
providers is compiled in. If you wish to avoid any possibility of
your build of qpdf from using anything but a user-supplied random
data provider, you can define SKIP_OS_SECURE_RANDOM and not
USE_INSECURE_RANDOM. In this case, qpdf will throw a runtime error
if any attempt is made to generate random numbers and no random
data provider has been supplied.
If you are building qpdf on a platform that qpdf doesn't know how to
generate secure random numbers on, a patch would be welcome.

View File

@ -26,11 +26,26 @@ AC_ARG_ENABLE(insecure-random,
fi], [qpdf_INSECURE_RANDOM=0])
if test "$qpdf_INSECURE_RANDOM" = "1"; then
AC_MSG_RESULT(yes)
AC_DEFINE([USE_INSECURE_RANDOM], [1], [Whether to use inscure random numbers])
AC_DEFINE([USE_INSECURE_RANDOM], [1], [Whether to use insecure random numbers])
else
AC_MSG_RESULT(no)
fi
AC_ARG_ENABLE(os-secure-random,
AS_HELP_STRING([--enable-os-secure-random],
[whether to try to use OS-provided secure random numbers (default is yes)]),
[if test "$enableval" = "yes"; then
qpdf_OS_SECURE_RANDOM=1;
else
qpdf_OS_SECURE_RANDOM=0;
fi], [qpdf_OS_SECURE_RANDOM=1])
if test "$qpdf_OS_SECURE_RANDOM" = "1"; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_DEFINE([SKIP_OS_SECURE_RANDOM], [1], [Whether to suppres use of OS-provided secure random numbers])
fi
AX_RANDOM_DEVICE
USE_EXTERNAL_LIBS=0
@ -71,7 +86,7 @@ if test "$BUILD_INTERNAL_LIBS" = "0"; then
AC_SEARCH_LIBS(pcre_compile,pcre,,[MISSING_PCRE=1; MISSING_ANY=1])
fi
if test "x$qpdf_INSECURE_RANDOM" != "x1"; then
if test "x$qpdf_OS_SECURE_RANDOM" = "x1"; then
OLIBS=$LIBS
LIBS="$LIBS Advapi32.lib"
AC_MSG_CHECKING(for Advapi32 library)

View File

@ -19,6 +19,22 @@ SecureRandomDataProvider::~SecureRandomDataProvider()
{
}
#ifdef SKIP_OS_SECURE_RANDOM
void
SecureRandomDataProvider::provideRandomData(unsigned char* data, size_t len)
{
throw std::logic_error("SecureRandomDataProvider::provideRandomData called when support was not compiled in");
}
RandomDataProvider*
SecureRandomDataProvider::getInstance()
{
return 0;
}
#else
#ifdef _WIN32
class WindowsCryptProvider
@ -84,3 +100,5 @@ SecureRandomDataProvider::getInstance()
static SecureRandomDataProvider instance;
return &instance;
}
#endif

View File

@ -1,4 +1,5 @@
#include <qpdf/QUtil.hh>
#include <qpdf/qpdf-config.h>
#include <qpdf/InsecureRandomDataProvider.hh>
#include <qpdf/SecureRandomDataProvider.hh>
#include <iostream>
@ -36,6 +37,7 @@ int main()
{
std::cout << "fail: two insecure randoms were the same\n";
}
#ifndef SKIP_OS_SECURE_RANDOM
SecureRandomDataProvider srdp;
srdp.provideRandomData(reinterpret_cast<unsigned char*>(&r1), 4);
srdp.provideRandomData(reinterpret_cast<unsigned char*>(&r2), 4);
@ -43,6 +45,7 @@ int main()
{
std::cout << "fail: two secure randoms were the same\n";
}
#endif
BogusRandomDataProvider brdp;
QUtil::setRandomDataProvider(&brdp);
r1 = QUtil::random();

View File

@ -1851,6 +1851,31 @@ outfile.pdf</option>
preserved as clear-text if it is that way in the original file.
</para>
</sect1>
<sect1 id="ref.random-numbers">
<title>Random Number Generation</title>
<para>
QPDF generates random numbers to support generation of encrypted
data. Versions prior to 5.0.1 used <function>random</function> or
<function>rand</function> from <filename>stdlib</filename> to
generate random numbers. Version 5.0.1, if available, used
operating system-provided secure random number generation instead,
enabling use of <filename>stdlib</filename> random number
generation only if enabled by a compile-time option. Starting in
version 5.1.0, use of insecure random numbers was disabled unless
enabled at compile time. Starting in version 5.1.0, it is also
possible for you to disable use of OS-provided secure random
numbers. This is especially useful on Windows if you want to
avoid a dependency on Microsoft's cryptography API. In this case,
you must provide your own random data provider. Regardless of how
you compile qpdf, starting in version 5.1.0, it is possible for
you to provide your own random data provider at runtime. This
would enable you to use some software-based secure pseudorandom
number generator and to avoid use of whatever the operating system
provides. For details on how to do this, please refer to the
top-level README file in the source distribution and to comments
in <filename>QUtil.hh</filename>.
</para>
</sect1>
<sect1 id="ref.adding-and-remove-pages">
<title>Adding and Removing Pages</title>
<para>