2017-06-30 15:03:35 +00:00
|
|
|
From 709e675cdf0c8f9b07507aad12400398f354cc90 Mon Sep 17 00:00:00 2001
|
2017-03-07 13:00:37 +00:00
|
|
|
From: Stephen Gallagher <sgallagh@redhat.com>
|
|
|
|
Date: Mon, 16 Jan 2017 09:19:43 -0500
|
2017-07-18 13:49:11 +00:00
|
|
|
Subject: [PATCH] Add OpenSSL support for digest and signatures
|
2017-03-07 13:00:37 +00:00
|
|
|
|
|
|
|
Autotools: add --with-crypto=openssl
|
|
|
|
This enables RPM to locate the appropriate flags for compiling
|
|
|
|
against OpenSSL for digest and hash functions.
|
|
|
|
|
|
|
|
This implementation changes the old behavior of
|
|
|
|
--with[out]-beecrypt toggling between beecrypt and nss. It will
|
|
|
|
now throw an error if attempting to use --with-beecrypt
|
|
|
|
indicating that the user should instead use --with-crypto=
|
|
|
|
|
|
|
|
See also:
|
|
|
|
https://github.com/rpm-software-management/rpm/issues/119
|
2017-03-16 15:37:08 +00:00
|
|
|
|
|
|
|
(cherry picked from commit 64028f9a1c25ada8ffc7a48775f526600edcbf85)
|
2017-06-30 15:03:35 +00:00
|
|
|
|
|
|
|
Conflicts:
|
|
|
|
Makefile.am
|
|
|
|
configure.ac
|
2017-03-07 13:00:37 +00:00
|
|
|
---
|
|
|
|
INSTALL | 27 +-
|
|
|
|
Makefile.am | 17 +-
|
2017-03-16 15:37:08 +00:00
|
|
|
configure.ac | 115 ++++++-
|
2017-03-07 13:00:37 +00:00
|
|
|
rpmio/Makefile.am | 6 +
|
|
|
|
rpmio/digest_openssl.c | 838 +++++++++++++++++++++++++++++++++++++++++++++++++
|
2017-03-16 15:37:08 +00:00
|
|
|
5 files changed, 982 insertions(+), 21 deletions(-)
|
2017-03-07 13:00:37 +00:00
|
|
|
create mode 100644 rpmio/digest_openssl.c
|
|
|
|
|
|
|
|
diff --git a/INSTALL b/INSTALL
|
|
|
|
index 60536e316..8eefef799 100644
|
|
|
|
--- a/INSTALL
|
|
|
|
+++ b/INSTALL
|
|
|
|
@@ -9,17 +9,34 @@ The libmagic (aka file) library for file type detection (used by rpmbuild).
|
|
|
|
The source for the file utility + library is available from
|
|
|
|
ftp://ftp.astron.com/pub/file/
|
|
|
|
|
|
|
|
-The NSS >= 3.12 library for encryption, and NSPR library which NSS uses.
|
|
|
|
-Both NSPR and NSS libraries and headers need to be installed during RPM
|
|
|
|
-compilation. As NSPR and NSS typically install their headers outside
|
|
|
|
-the regular include search path, you need to tell configure about this,
|
|
|
|
-eg something like:
|
|
|
|
+You will need a cryptographic library to support digests and signatures.
|
|
|
|
+This library may be Mozilla NSS, OpenSSL or beecrypt. Which library to use
|
|
|
|
+must be specified with the --with-crypto=[beecrypt|nss|openssl] argument
|
|
|
|
+to configure.
|
|
|
|
+
|
|
|
|
+If using the Mozilla NSS library for encyption (and NSPR library which
|
|
|
|
+NSS uses) it must be version 3.12 or later. Both NSPR and NSS libraries and
|
|
|
|
+headers need to be installed during RPM compilation. As NSPR and NSS
|
|
|
|
+typically install their headers outside the regular include search path,
|
|
|
|
+you need to tell configure about this, eg something like:
|
|
|
|
./configure <......> CPPFLAGS="-I/usr/include/nspr -I/usr/include/nss"
|
|
|
|
|
|
|
|
The NSPR and NSS libraries are available from
|
|
|
|
http://www.mozilla.org/projects/security/pki/nss/
|
|
|
|
http://www.mozilla.org/projects/nspr/
|
|
|
|
|
|
|
|
+If using the OpenSSL library for encryption, it must be version 1.0.2 or
|
|
|
|
+later. Note: when compiling against OpenSSL, there is a possible license
|
|
|
|
+incompatibility. For more details on this, see
|
|
|
|
+https://people.gnome.org/~markmc/openssl-and-the-gpl.html
|
|
|
|
+Some Linux distributions have different legal interpretations of this
|
|
|
|
+possible incompatibility. It is recommended to consult with a lawyer before
|
|
|
|
+building RPM against OpenSSL.
|
|
|
|
+Fedora: https://fedoraproject.org/wiki/Licensing:FAQ#What.27s_the_deal_with_the_OpenSSL_license.3F
|
|
|
|
+Debian: https://lists.debian.org/debian-legal/2002/10/msg00113.html
|
|
|
|
+
|
|
|
|
+The OpenSSL crypto library is available from https://www.openssl.org/
|
|
|
|
+
|
|
|
|
The Berkeley DB >= 4.3.x (4.5.x or newer recommended) is required for the
|
|
|
|
default database backend. BDB can be downloaded from
|
|
|
|
http://www.oracle.com/technology/software/products/berkeley-db/index.html
|
|
|
|
diff --git a/Makefile.am b/Makefile.am
|
2017-06-30 15:03:35 +00:00
|
|
|
index 1b77730aa..a5268030b 100644
|
2017-03-07 13:00:37 +00:00
|
|
|
--- a/Makefile.am
|
|
|
|
+++ b/Makefile.am
|
2017-03-16 15:37:08 +00:00
|
|
|
@@ -41,6 +41,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/build
|
|
|
|
AM_CPPFLAGS += -I$(top_srcdir)/lib
|
2017-03-07 13:00:37 +00:00
|
|
|
AM_CPPFLAGS += -I$(top_srcdir)/rpmio
|
|
|
|
AM_CPPFLAGS += @WITH_NSS_INCLUDE@
|
|
|
|
+AM_CPPFLAGS += @WITH_OPENSSL_INCLUDE@
|
|
|
|
AM_CPPFLAGS += @WITH_POPT_INCLUDE@
|
|
|
|
AM_CPPFLAGS += -I$(top_srcdir)/misc
|
|
|
|
AM_CPPFLAGS += -DLOCALEDIR="\"$(localedir)\""
|
2017-03-16 15:37:08 +00:00
|
|
|
@@ -113,45 +114,45 @@ rpm_SOURCES = rpmqv.c debug.h system.h
|
2017-03-07 13:00:37 +00:00
|
|
|
rpm_CPPFLAGS = $(AM_CPPFLAGS) -DIAM_RPMEIU -DIAM_RPMQ -DIAM_RPMV
|
|
|
|
rpm_LDADD = libcliutils.la
|
|
|
|
rpm_LDADD += lib/librpm.la rpmio/librpmio.la
|
2017-03-16 15:37:08 +00:00
|
|
|
-rpm_LDADD += @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
|
|
|
+rpm_LDADD += @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
2017-03-07 13:00:37 +00:00
|
|
|
|
|
|
|
rpmdb_SOURCES = rpmdb.c debug.h system.h
|
|
|
|
rpmdb_CPPFLAGS = $(AM_CPPFLAGS)
|
|
|
|
rpmdb_LDADD = libcliutils.la
|
|
|
|
rpmdb_LDADD += lib/librpm.la rpmio/librpmio.la
|
2017-03-16 15:37:08 +00:00
|
|
|
-rpmdb_LDADD += @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
|
|
|
+rpmdb_LDADD += @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
2017-03-07 13:00:37 +00:00
|
|
|
|
|
|
|
rpmkeys_SOURCES = rpmkeys.c debug.h system.h
|
|
|
|
rpmkeys_CPPFLAGS = $(AM_CPPFLAGS)
|
|
|
|
rpmkeys_LDADD = libcliutils.la
|
|
|
|
rpmkeys_LDADD += lib/librpm.la rpmio/librpmio.la
|
2017-03-16 15:37:08 +00:00
|
|
|
-rpmkeys_LDADD += @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
|
|
|
+rpmkeys_LDADD += @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
2017-03-07 13:00:37 +00:00
|
|
|
|
|
|
|
rpmsign_SOURCES = rpmsign.c debug.h system.h
|
|
|
|
rpmsign_CPPFLAGS = $(AM_CPPFLAGS)
|
|
|
|
rpmsign_LDADD = libcliutils.la
|
|
|
|
rpmsign_LDADD += sign/librpmsign.la lib/librpm.la rpmio/librpmio.la
|
2017-03-16 15:37:08 +00:00
|
|
|
-rpmsign_LDADD += @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
|
|
|
+rpmsign_LDADD += @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
2017-03-07 13:00:37 +00:00
|
|
|
|
|
|
|
rpmbuild_SOURCES = rpmbuild.c debug.h system.h
|
|
|
|
rpmbuild_CPPFLAGS = $(AM_CPPFLAGS)
|
|
|
|
rpmbuild_LDADD = libcliutils.la
|
|
|
|
rpmbuild_LDADD += build/librpmbuild.la lib/librpm.la rpmio/librpmio.la
|
2017-03-16 15:37:08 +00:00
|
|
|
-rpmbuild_LDADD += @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
|
|
|
+rpmbuild_LDADD += @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
2017-03-07 13:00:37 +00:00
|
|
|
|
|
|
|
rpmspec_SOURCES = rpmspec.c debug.h system.h
|
|
|
|
rpmspec_CPPFLAGS = $(AM_CPPFLAGS)
|
|
|
|
rpmspec_LDADD = libcliutils.la
|
|
|
|
rpmspec_LDADD += build/librpmbuild.la lib/librpm.la rpmio/librpmio.la
|
2017-03-16 15:37:08 +00:00
|
|
|
-rpmspec_LDADD += @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
|
|
|
+rpmspec_LDADD += @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
2017-03-07 13:00:37 +00:00
|
|
|
|
|
|
|
rpm2cpio_SOURCES = rpm2cpio.c debug.h system.h
|
|
|
|
rpm2cpio_LDADD = lib/librpm.la rpmio/librpmio.la
|
2017-03-16 15:37:08 +00:00
|
|
|
-rpm2cpio_LDADD += @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
|
|
|
+rpm2cpio_LDADD += @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
|
2017-03-07 13:00:37 +00:00
|
|
|
|
|
|
|
rpm2archive_SOURCES = rpm2archive.c debug.h system.h
|
|
|
|
rpm2archive_LDADD = lib/librpm.la rpmio/librpmio.la
|
2017-03-16 15:37:08 +00:00
|
|
|
-rpm2archive_LDADD += @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ @WITH_ARCHIVE_LIB@
|
|
|
|
+rpm2archive_LDADD += @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ @WITH_ARCHIVE_LIB@
|
2017-03-07 13:00:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
if LIBELF
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
2017-06-30 15:03:35 +00:00
|
|
|
index e6362535b..65052870a 100644
|
2017-03-07 13:00:37 +00:00
|
|
|
--- a/configure.ac
|
|
|
|
+++ b/configure.ac
|
2017-03-16 15:37:08 +00:00
|
|
|
@@ -243,18 +243,30 @@ AC_CHECK_HEADERS([dwarf.h], [
|
2017-03-07 13:00:37 +00:00
|
|
|
AM_CONDITIONAL(LIBDWARF,[test "$WITH_LIBDWARF" = yes])
|
|
|
|
|
|
|
|
#=================
|
|
|
|
+# Select crypto library
|
|
|
|
+AC_ARG_WITH(crypto,
|
|
|
|
+ [AC_HELP_STRING([--with-crypto=CRYPTO_LIB],
|
|
|
|
+ [The cryptographic library to use (nss|beecrypt|openssl). The default is nss.])
|
|
|
|
+ ],[],
|
|
|
|
+ [with_crypto=nss])
|
|
|
|
+
|
|
|
|
+# Refuse to proceed if someone specified --with-beecrypt (removed)
|
|
|
|
+AC_ARG_WITH(beecrypt,
|
|
|
|
+ [AC_HELP_STRING([--with-beecrypt (OBSOLETE)], [Obsolete argument. Use --with-crypto=beecrypt])
|
|
|
|
+ ],[AC_MSG_ERROR([--with-beecrypt no longer supported. Use --with-crypto=beecrypt])],
|
|
|
|
+ [])
|
|
|
|
+
|
|
|
|
# Check for beecrypt library if requested.
|
|
|
|
-AC_ARG_WITH(beecrypt, [ --with-beecrypt build with beecrypt support ],,[with_beecrypt=no])
|
|
|
|
AC_ARG_WITH(internal_beecrypt, [ --with-internal-beecrypt build with internal beecrypt library ],,[with_internal_beecrypt=no])
|
|
|
|
AM_CONDITIONAL([WITH_INTERNAL_BEECRYPT],[test "$with_internal_beecrypt" = yes])
|
|
|
|
if test "$with_internal_beecrypt" = yes ; then
|
|
|
|
- with_beecrypt=yes
|
|
|
|
+ with_crypto=beecrypt
|
|
|
|
fi
|
|
|
|
-AM_CONDITIONAL([WITH_BEECRYPT],[test "$with_beecrypt" = yes])
|
|
|
|
+AM_CONDITIONAL([WITH_BEECRYPT],[test "$with_crypto" = beecrypt])
|
|
|
|
|
|
|
|
WITH_BEECRYPT_INCLUDE=
|
|
|
|
WITH_BEECRYPT_LIB=
|
|
|
|
-if test "$with_beecrypt" = yes ; then
|
|
|
|
+if test "$with_crypto" = beecrypt ; then
|
|
|
|
AC_DEFINE(WITH_BEECRYPT, 1, [Build with beecrypt instead of nss3 support?])
|
|
|
|
if test "$with_internal_beecrypt" = yes ; then
|
|
|
|
WITH_BEECRYPT_INCLUDE="-I\$(top_srcdir)/beecrypt"
|
2017-03-16 15:37:08 +00:00
|
|
|
@@ -263,7 +275,7 @@ if test "$with_beecrypt" = yes ; then
|
2017-03-07 13:00:37 +00:00
|
|
|
AC_CHECK_LIB(beecrypt, mpfprintln, [
|
|
|
|
WITH_BEECRYPT_LIB="-lbeecrypt"
|
|
|
|
],[
|
|
|
|
- AC_MSG_ERROR([missing required library 'beecrypt'])
|
|
|
|
+ AC_MSG_ERROR([missing required library 'beecrypt'])
|
|
|
|
])
|
|
|
|
AC_CHECK_HEADER([beecrypt/api.h], [AC_DEFINE(HAVE_BEECRYPT_API_H, 1, [Define to 1 if you have the <beecrypt/api.h> header file.])
|
|
|
|
])
|
2017-03-16 15:37:08 +00:00
|
|
|
@@ -273,13 +285,100 @@ AC_SUBST(WITH_BEECRYPT_LIB)
|
2017-03-07 13:00:37 +00:00
|
|
|
AC_SUBST(WITH_BEECRYPT_INCLUDE)
|
|
|
|
|
|
|
|
#=================
|
|
|
|
+# Check for OpenSSL library.
|
|
|
|
+# We need evp.h from OpenSSL.
|
|
|
|
+
|
|
|
|
+WITH_OPENSSL_INCLUDE=
|
|
|
|
+WITH_OPENSSL_LIB=
|
|
|
|
+if test "$with_crypto" = openssl; then
|
|
|
|
+# If we have pkgconfig make sure CPPFLAGS are setup correctly for the OpenSSL
|
|
|
|
+# -I include path.
|
|
|
|
+AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no], [$PATH:/usr/bin:/usr/local/bin])
|
|
|
|
+if test "x$PKGCONFIG" != "xno"; then
|
|
|
|
+ CPPFLAGS="$CPPFLAGS $($PKGCONFIG --cflags libcrypto)"
|
|
|
|
+ WITH_OPENSSL_LIB=$($PKGCONFIG --libs libcrypto)
|
|
|
|
+else
|
|
|
|
+ WITH_OPENSSL_LIB=-lcrypto
|
|
|
|
+fi
|
|
|
|
+
|
|
|
|
+AC_CHECK_HEADERS([openssl/evp.h], [], [
|
|
|
|
+ AC_MSG_ERROR([missing required OpenSSL header])
|
|
|
|
+])
|
|
|
|
+AC_CHECK_HEADERS([openssl/rsa.h], [], [
|
|
|
|
+ AC_MSG_ERROR([missing required OpenSSL header])
|
|
|
|
+])
|
|
|
|
+AC_CHECK_HEADERS([openssl/dsa.h], [], [
|
|
|
|
+ AC_MSG_ERROR([missing required OpenSSL header])
|
|
|
|
+])
|
|
|
|
+
|
|
|
|
+AC_CHECK_LIB(crypto, EVP_DigestInit_ex, [], [
|
|
|
|
+ AC_MSG_ERROR([required OpenSSL library 'libcrypto' missing or too old])
|
|
|
|
+])
|
|
|
|
+
|
|
|
|
+AC_CHECK_LIB(crypto, EVP_MD_CTX_new, [
|
|
|
|
+ AC_DEFINE(HAVE_EVP_MD_CTX_NEW, 1, [Define to 1 if OpenSSL has EVP_MD_CTX_new])
|
|
|
|
+ AC_SUBST(HAVE_EVP_MD_CTX_NEW, [1])
|
|
|
|
+ ], [
|
|
|
|
+ AC_CHECK_LIB(crypt, EVP_MD_CTX_create, [], [
|
|
|
|
+ AC_MSG_ERROR([required OpenSSL library 'libcrypto' missing or too old])
|
|
|
|
+ ])
|
|
|
|
+])
|
|
|
|
+
|
|
|
|
+AC_CHECK_LIB(crypto, EVP_PKEY_CTX_new, [], [
|
|
|
|
+ AC_MSG_ERROR([required OpenSSL library 'libcrypto' missing or too old])
|
|
|
|
+])
|
|
|
|
+
|
|
|
|
+AC_CHECK_LIB(crypto, DSA_set0_key, [
|
|
|
|
+ AC_DEFINE(HAVE_DSA_SET0_KEY, 1, [Define to 1 if OpenSSL has DSA_set0_key])
|
|
|
|
+ AC_SUBST(HAVE_DSA_SET0_KEY, [1])
|
|
|
|
+ ], []
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+AC_CHECK_LIB(crypto, DSA_set0_pqg, [
|
|
|
|
+ AC_DEFINE(HAVE_DSA_SET0_PQG, 1, [Define to 1 if OpenSSL has DSA_set0_pqg])
|
|
|
|
+ AC_SUBST(HAVE_DSA_SET0_PQG, [1])
|
|
|
|
+ ], []
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+AC_CHECK_LIB(crypto, DSA_SIG_set0, [
|
|
|
|
+ AC_DEFINE(HAVE_DSA_SIG_SET0, 1, [Define to 1 if OpenSSL has DSA_SIG_set0])
|
|
|
|
+ AC_SUBST(HAVE_DSA_SIG_SET0, [1])
|
|
|
|
+ ], []
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+AC_CHECK_LIB(crypto, RSA_set0_key, [
|
|
|
|
+ AC_DEFINE(HAVE_RSA_SET0_KEY, 1, [Define to 1 if OpenSSL has RSA_set0_key])
|
|
|
|
+ AC_SUBST(HAVE_RSA_SET0_KEY, [1])
|
|
|
|
+ ], []
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+AC_CHECK_LIB(crypto, BN_bn2binpad, [
|
|
|
|
+ AC_DEFINE(HAVE_BN2BINPAD, 1, [Define to 1 if OpenSSL has BN_bn2binpad])
|
|
|
|
+ AC_SUBST(HAVE_BN2BINPAD, [1])
|
|
|
|
+ ], []
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+fi
|
|
|
|
+
|
|
|
|
+AM_CONDITIONAL([WITH_OPENSSL],[test "$with_crypto" = openssl])
|
|
|
|
+AC_SUBST(WITH_OPENSSL_INCLUDE)
|
|
|
|
+AC_SUBST(WITH_OPENSSL_LIB)
|
|
|
|
+
|
|
|
|
+#=================
|
|
|
|
# Check for NSS library.
|
|
|
|
-# We need nss.h from NSS which needs nspr.h. Unfortunately both glibc and NSS
|
|
|
|
-# have a header named nss.h... so make extra check for NSS's sechash.h
|
|
|
|
+# We need nss.h from NSS which needs nspr.h. Unfortunately both glibc and NSS
|
|
|
|
+# have a header named nss.h... so make extra check for NSS's sechash.h
|
|
|
|
# which we use too and hopefully is slightly more unique to NSS.
|
|
|
|
WITH_NSS_INCLUDE=
|
|
|
|
WITH_NSS_LIB=
|
|
|
|
-if test "$with_beecrypt" != yes ; then
|
|
|
|
+if test "$with_crypto" = nss; then
|
2017-03-16 15:37:08 +00:00
|
|
|
+# If we have pkgconfig make sure CPPFLAGS are setup correctly for the nss
|
|
|
|
+# -I include path. Otherwise the below checks will fail because nspr.h
|
|
|
|
+# cannot be found.
|
|
|
|
+AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no], [$PATH:/usr/bin:/usr/local/bin])
|
|
|
|
+if test "x$PKGCONFIG" != "xno"; then
|
|
|
|
+ CPPFLAGS="$CPPFLAGS $($PKGCONFIG --cflags nss)"
|
|
|
|
+fi
|
|
|
|
AC_CHECK_HEADERS([nspr.h nss.h sechash.h], [], [
|
|
|
|
AC_MSG_ERROR([missing required NSPR / NSS header])
|
|
|
|
])
|
2017-03-07 13:00:37 +00:00
|
|
|
diff --git a/rpmio/Makefile.am b/rpmio/Makefile.am
|
2017-03-16 15:37:08 +00:00
|
|
|
index 68a821934..9062f58a5 100644
|
2017-03-07 13:00:37 +00:00
|
|
|
--- a/rpmio/Makefile.am
|
|
|
|
+++ b/rpmio/Makefile.am
|
2017-03-16 15:37:08 +00:00
|
|
|
@@ -5,6 +5,7 @@ include $(top_srcdir)/rpm.am
|
2017-03-07 13:00:37 +00:00
|
|
|
AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) -I$(top_builddir)/include/
|
|
|
|
AM_CPPFLAGS += @WITH_NSS_INCLUDE@
|
|
|
|
AM_CPPFLAGS += @WITH_BEECRYPT_INCLUDE@
|
|
|
|
+AM_CPPFLAGS += @WITH_OPENSSL_INCLUDE@
|
|
|
|
AM_CPPFLAGS += @WITH_POPT_INCLUDE@
|
|
|
|
AM_CPPFLAGS += -I$(top_srcdir)/misc
|
|
|
|
AM_CPPFLAGS += -DRPMCONFIGDIR="\"@RPMCONFIGDIR@\""
|
2017-03-16 15:37:08 +00:00
|
|
|
@@ -23,8 +24,12 @@ librpmio_la_SOURCES = \
|
2017-03-07 13:00:37 +00:00
|
|
|
if WITH_BEECRYPT
|
|
|
|
librpmio_la_SOURCES += digest_beecrypt.c
|
|
|
|
else
|
|
|
|
+if WITH_OPENSSL
|
|
|
|
+librpmio_la_SOURCES += digest_openssl.c
|
|
|
|
+else
|
|
|
|
librpmio_la_SOURCES += digest_nss.c
|
|
|
|
endif
|
|
|
|
+endif
|
|
|
|
|
|
|
|
|
|
|
|
librpmio_la_LDFLAGS = -version-info $(rpm_version_info)
|
2017-03-16 15:37:08 +00:00
|
|
|
@@ -32,6 +37,7 @@ librpmio_la_LIBADD = \
|
2017-03-07 13:00:37 +00:00
|
|
|
../misc/libmisc.la \
|
|
|
|
@WITH_NSS_LIB@ \
|
|
|
|
@WITH_BEECRYPT_LIB@ \
|
|
|
|
+ @WITH_OPENSSL_LIB@ \
|
|
|
|
@WITH_BZ2_LIB@ \
|
|
|
|
@WITH_ZLIB_LIB@ \
|
|
|
|
@WITH_LIBELF_LIB@ \
|
|
|
|
diff --git a/rpmio/digest_openssl.c b/rpmio/digest_openssl.c
|
|
|
|
new file mode 100644
|
|
|
|
index 000000000..aea460e39
|
|
|
|
--- /dev/null
|
|
|
|
+++ b/rpmio/digest_openssl.c
|
|
|
|
@@ -0,0 +1,838 @@
|
|
|
|
+#include "system.h"
|
|
|
|
+
|
|
|
|
+#include <openssl/evp.h>
|
|
|
|
+#include <openssl/rsa.h>
|
|
|
|
+#include <openssl/dsa.h>
|
|
|
|
+#include <rpm/rpmpgp.h>
|
|
|
|
+
|
|
|
|
+#include "rpmio/digest.h"
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/* Compatibility functions for OpenSSL 1.0.2 */
|
|
|
|
+
|
|
|
|
+#ifndef HAVE_EVP_MD_CTX_NEW
|
|
|
|
+# define EVP_MD_CTX_new EVP_MD_CTX_create
|
|
|
|
+# define EVP_MD_CTX_free EVP_MD_CTX_destroy
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+#ifndef HAVE_RSA_SET0_KEY
|
|
|
|
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
|
|
|
|
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
|
|
|
|
+{
|
|
|
|
+ if (!r) return 0;
|
|
|
|
+
|
|
|
|
+ if (n) {
|
|
|
|
+ r->n = n;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (e) {
|
|
|
|
+ r->e = e;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (d) {
|
|
|
|
+ r->d = d;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+#endif /* HAVE_RSA_SET0_KEY */
|
|
|
|
+
|
|
|
|
+#ifndef HAVE_DSA_SET0_KEY
|
|
|
|
+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
|
|
|
|
+
|
|
|
|
+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
|
|
|
|
+{
|
|
|
|
+ if (!d) return 0;
|
|
|
|
+
|
|
|
|
+ if (pub_key) {
|
|
|
|
+ d->pub_key = pub_key;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (priv_key) {
|
|
|
|
+ d->priv_key = priv_key;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+#endif /* HAVE_DSA_SET0_KEY */
|
|
|
|
+
|
|
|
|
+#ifndef HAVE_DSA_SET0_PQG
|
|
|
|
+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
|
|
|
|
+
|
|
|
|
+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
|
|
|
+{
|
|
|
|
+ if (!d) return 0;
|
|
|
|
+
|
|
|
|
+ if (p) {
|
|
|
|
+ d->p = p;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (q) {
|
|
|
|
+ d->q = q;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (g) {
|
|
|
|
+ d->g = g;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+#endif /* HAVE_DSA_SET0_PQG */
|
|
|
|
+
|
|
|
|
+#ifndef HAVE_DSA_SIG_SET0
|
|
|
|
+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s);
|
|
|
|
+
|
|
|
|
+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
|
|
|
|
+{
|
|
|
|
+ if (!sig) return 0;
|
|
|
|
+
|
|
|
|
+ if (r) {
|
|
|
|
+ sig->r = r;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (s) {
|
|
|
|
+ sig->s = s;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+#endif /* HAVE_DSA_SIG_SET0 */
|
|
|
|
+
|
|
|
|
+#ifndef HAVE_BN2BINPAD
|
|
|
|
+static int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ i = BN_num_bytes(a);
|
|
|
|
+ if (tolen < i)
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ /* Add leading zeroes if necessary */
|
|
|
|
+ if (tolen > i) {
|
|
|
|
+ memset(to, 0, tolen - i);
|
|
|
|
+ to += tolen - i;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ BN_bn2bin(a, to);
|
|
|
|
+
|
|
|
|
+ return tolen;
|
|
|
|
+}
|
|
|
|
+#endif /* HAVE_BN2BINPAD */
|
|
|
|
+
|
|
|
|
+struct DIGEST_CTX_s {
|
|
|
|
+ rpmDigestFlags flags; /*!< Bit(s) to control digest operation. */
|
|
|
|
+ int algo; /*!< Used hash algorithm */
|
|
|
|
+
|
|
|
|
+ EVP_MD_CTX *md_ctx; /* Digest context (opaque) */
|
|
|
|
+
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/**************************** init ************************************/
|
|
|
|
+
|
|
|
|
+int rpmInitCrypto(void) {
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int rpmFreeCrypto(void) {
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**************************** digest ************************************/
|
|
|
|
+
|
|
|
|
+DIGEST_CTX rpmDigestDup(DIGEST_CTX octx)
|
|
|
|
+{
|
|
|
|
+ if (!octx) return NULL;
|
|
|
|
+
|
|
|
|
+ DIGEST_CTX nctx = NULL;
|
|
|
|
+ nctx = xcalloc(1, sizeof(*nctx));
|
|
|
|
+
|
|
|
|
+ nctx->flags = octx->flags;
|
|
|
|
+ nctx->algo = octx->algo;
|
|
|
|
+ nctx->md_ctx = EVP_MD_CTX_new();
|
|
|
|
+ if (!nctx->md_ctx) {
|
|
|
|
+ free(nctx);
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!EVP_MD_CTX_copy(nctx->md_ctx, octx->md_ctx)) {
|
|
|
|
+ free(nctx);
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return nctx;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static const EVP_MD *getEVPMD(int hashalgo)
|
|
|
|
+{
|
|
|
|
+ switch (hashalgo) {
|
|
|
|
+
|
|
|
|
+ case PGPHASHALGO_MD5:
|
|
|
|
+ return EVP_md5();
|
|
|
|
+
|
|
|
|
+ case PGPHASHALGO_SHA1:
|
|
|
|
+ return EVP_sha1();
|
|
|
|
+
|
|
|
|
+ case PGPHASHALGO_RIPEMD160:
|
|
|
|
+ return EVP_ripemd160();
|
|
|
|
+
|
|
|
|
+ case PGPHASHALGO_MD2:
|
|
|
|
+ return EVP_md2();
|
|
|
|
+
|
|
|
|
+ case PGPHASHALGO_SHA256:
|
|
|
|
+ return EVP_sha256();
|
|
|
|
+
|
|
|
|
+ case PGPHASHALGO_SHA384:
|
|
|
|
+ return EVP_sha384();
|
|
|
|
+
|
|
|
|
+ case PGPHASHALGO_SHA512:
|
|
|
|
+ return EVP_sha512();
|
|
|
|
+
|
|
|
|
+ case PGPHASHALGO_SHA224:
|
|
|
|
+ return EVP_sha224();
|
|
|
|
+
|
|
|
|
+ default:
|
|
|
|
+ return EVP_md_null();
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+size_t rpmDigestLength(int hashalgo)
|
|
|
|
+{
|
|
|
|
+ return EVP_MD_size(getEVPMD(hashalgo));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+DIGEST_CTX rpmDigestInit(int hashalgo, rpmDigestFlags flags)
|
|
|
|
+{
|
|
|
|
+ DIGEST_CTX ctx = xcalloc(1, sizeof(*ctx));
|
|
|
|
+
|
|
|
|
+ ctx->md_ctx = EVP_MD_CTX_new();
|
|
|
|
+ if (!ctx->md_ctx) {
|
|
|
|
+ free(ctx);
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const EVP_MD *md = getEVPMD(hashalgo);
|
|
|
|
+ if (md == EVP_md_null()) {
|
|
|
|
+ free(ctx->md_ctx);
|
|
|
|
+ free(ctx);
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ctx->algo = hashalgo;
|
|
|
|
+ ctx->flags = flags;
|
|
|
|
+ if (!EVP_DigestInit_ex(ctx->md_ctx, md, NULL)) {
|
|
|
|
+ free(ctx->md_ctx);
|
|
|
|
+ free(ctx);
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return ctx;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int rpmDigestUpdate(DIGEST_CTX ctx, const void *data, size_t len)
|
|
|
|
+{
|
|
|
|
+ if (ctx == NULL) return -1;
|
|
|
|
+
|
|
|
|
+ EVP_DigestUpdate(ctx->md_ctx, data, len);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int rpmDigestFinal(DIGEST_CTX ctx, void ** datap, size_t *lenp, int asAscii)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+ unsigned char *digest = NULL;
|
|
|
|
+ unsigned int digestlen;
|
|
|
|
+
|
|
|
|
+ if (ctx == NULL) return -1;
|
|
|
|
+
|
|
|
|
+ digestlen = EVP_MD_CTX_size(ctx->md_ctx);
|
|
|
|
+ digest = xcalloc(digestlen, sizeof(*digest));
|
|
|
|
+
|
|
|
|
+ ret = EVP_DigestFinal_ex(ctx->md_ctx, digest, &digestlen);
|
|
|
|
+ if (ret != 1) goto done;
|
|
|
|
+
|
|
|
|
+ if (!asAscii) {
|
|
|
|
+ /* Raw data requested */
|
|
|
|
+ if (lenp) *lenp = digestlen;
|
|
|
|
+ if (datap) {
|
|
|
|
+ *datap = digest;
|
|
|
|
+ digest = NULL;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ else {
|
|
|
|
+ /* ASCII requested */
|
|
|
|
+ if (lenp) *lenp = (2*digestlen) + 1;
|
|
|
|
+ if (datap) {
|
|
|
|
+ const uint8_t * s = (const uint8_t *) digest;
|
|
|
|
+ *datap = pgpHexStr(s, digestlen);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = 1;
|
|
|
|
+
|
|
|
|
+done:
|
|
|
|
+ if (digest) {
|
|
|
|
+ /* Zero the digest, just in case it's sensitive */
|
|
|
|
+ memset(digest, 0, digestlen);
|
|
|
|
+ free(digest);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ EVP_MD_CTX_free(ctx->md_ctx);
|
|
|
|
+ free(ctx);
|
|
|
|
+
|
|
|
|
+ if (ret != 1) {
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/****************************** RSA **************************************/
|
|
|
|
+
|
|
|
|
+/* Key */
|
|
|
|
+
|
|
|
|
+struct pgpDigKeyRSA_s {
|
|
|
|
+ size_t nbytes; /* Size of modulus */
|
|
|
|
+
|
|
|
|
+ BIGNUM *n; /* Common Modulus */
|
|
|
|
+ BIGNUM *e; /* Public Exponent */
|
|
|
|
+
|
|
|
|
+ EVP_PKEY *evp_pkey; /* Fully constructed key */
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int constructRSASigningKey(struct pgpDigKeyRSA_s *key)
|
|
|
|
+{
|
|
|
|
+ if (key->evp_pkey) {
|
|
|
|
+ /* We've already constructed it, so just reuse it */
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Create the RSA key */
|
|
|
|
+ RSA *rsa = RSA_new();
|
|
|
|
+ if (!rsa) return 0;
|
|
|
|
+
|
|
|
|
+ if (!RSA_set0_key(rsa, key->n, key->e, NULL)) {
|
|
|
|
+ RSA_free(rsa);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Create an EVP_PKEY container to abstract the key-type. */
|
|
|
|
+ key->evp_pkey = EVP_PKEY_new();
|
|
|
|
+ if (!key->evp_pkey) {
|
|
|
|
+ RSA_free(rsa);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Assign the RSA key to the EVP_PKEY structure.
|
|
|
|
+ This will take over memory management of the RSA key */
|
|
|
|
+ if (!EVP_PKEY_assign_RSA(key->evp_pkey, rsa)) {
|
|
|
|
+ EVP_PKEY_free(key->evp_pkey);
|
|
|
|
+ key->evp_pkey = NULL;
|
|
|
|
+ RSA_free(rsa);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
|
|
|
|
+{
|
|
|
|
+ size_t mlen = pgpMpiLen(p) - 2;
|
|
|
|
+ struct pgpDigKeyRSA_s *key = pgpkey->data;
|
|
|
|
+
|
|
|
|
+ if(!key) {
|
|
|
|
+ key = pgpkey->data = xcalloc(1, sizeof(*key));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ switch(num) {
|
|
|
|
+ case 0:
|
|
|
|
+ /* Modulus */
|
|
|
|
+ if (key->n) {
|
|
|
|
+ /* This should only ever happen once per key */
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ key->nbytes = mlen;
|
|
|
|
+ /* Create a BIGNUM from the pointer.
|
|
|
|
+ Note: this assumes big-endian data as required by PGP */
|
|
|
|
+ key->n = BN_bin2bn(p+2, mlen, NULL);
|
|
|
|
+ if (!key->n) return 1;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 1:
|
|
|
|
+ /* Exponent */
|
|
|
|
+ if (key->e) {
|
|
|
|
+ /* This should only ever happen once per key */
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Create a BIGNUM from the pointer.
|
|
|
|
+ Note: this assumes big-endian data as required by PGP */
|
|
|
|
+ key->e = BN_bin2bn(p+2, mlen, NULL);
|
|
|
|
+ if (!key->e) return 1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void pgpFreeKeyRSA(pgpDigAlg pgpkey)
|
|
|
|
+{
|
|
|
|
+ struct pgpDigKeyRSA_s *key = pgpkey->data;
|
|
|
|
+ if (key) {
|
|
|
|
+ if (key->evp_pkey) {
|
|
|
|
+ EVP_PKEY_free(key->evp_pkey);
|
|
|
|
+ } else {
|
|
|
|
+ /* If key->evp_pkey was constructed,
|
|
|
|
+ * the memory management of these BNs
|
|
|
|
+ * are freed with it. */
|
|
|
|
+ BN_clear_free(key->n);
|
|
|
|
+ BN_clear_free(key->e);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ free(key);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* Signature */
|
|
|
|
+
|
|
|
|
+struct pgpDigSigRSA_s {
|
|
|
|
+ BIGNUM *bn;
|
|
|
|
+ size_t len;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int pgpSetSigMpiRSA(pgpDigAlg pgpsig, int num, const uint8_t *p)
|
|
|
|
+{
|
|
|
|
+ BIGNUM *bn = NULL;
|
|
|
|
+
|
|
|
|
+ int mlen = pgpMpiLen(p) - 2;
|
|
|
|
+ int rc = 1;
|
|
|
|
+
|
|
|
|
+ struct pgpDigSigRSA_s *sig = pgpsig->data;
|
|
|
|
+ if (!sig) {
|
|
|
|
+ sig = xcalloc(1, sizeof(*sig));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ switch (num) {
|
|
|
|
+ case 0:
|
|
|
|
+ if (sig->bn) {
|
|
|
|
+ /* This should only ever happen once per signature */
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ bn = sig->bn = BN_new();
|
|
|
|
+ if (!bn) return 1;
|
|
|
|
+
|
|
|
|
+ /* Create a BIGNUM from the signature pointer.
|
|
|
|
+ Note: this assumes big-endian data as required
|
|
|
|
+ by the PGP multiprecision integer format
|
|
|
|
+ (RFC4880, Section 3.2)
|
|
|
|
+ This will be useful later, as we can
|
|
|
|
+ retrieve this value with appropriate
|
|
|
|
+ padding. */
|
|
|
|
+ bn = BN_bin2bn(p+2, mlen, bn);
|
|
|
|
+ if (!bn) return 1;
|
|
|
|
+
|
|
|
|
+ sig->bn = bn;
|
|
|
|
+ sig->len = mlen;
|
|
|
|
+
|
|
|
|
+ pgpsig->data = sig;
|
|
|
|
+ rc = 0;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void pgpFreeSigRSA(pgpDigAlg pgpsig)
|
|
|
|
+{
|
|
|
|
+ struct pgpDigSigRSA_s *sig = pgpsig->data;
|
|
|
|
+ if (sig) {
|
|
|
|
+ BN_clear_free(sig->bn);
|
|
|
|
+ free(pgpsig->data);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int pgpVerifySigRSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
|
|
|
|
+ uint8_t *hash, size_t hashlen, int hash_algo)
|
|
|
|
+{
|
|
|
|
+ int rc, ret;
|
|
|
|
+ EVP_PKEY_CTX *pkey_ctx = NULL;
|
|
|
|
+ struct pgpDigSigRSA_s *sig = pgpsig->data;
|
|
|
|
+
|
|
|
|
+ void *padded_sig = NULL;
|
|
|
|
+
|
|
|
|
+ struct pgpDigKeyRSA_s *key = pgpkey->data;
|
|
|
|
+
|
|
|
|
+ if(!constructRSASigningKey(key)) {
|
|
|
|
+ rc = 1;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pkey_ctx = EVP_PKEY_CTX_new(key->evp_pkey, NULL);
|
|
|
|
+ if (!pkey_ctx) {
|
|
|
|
+ rc = 1;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = EVP_PKEY_verify_init(pkey_ctx);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ rc = 1;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PADDING);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ rc = 1;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = EVP_PKEY_CTX_set_signature_md(pkey_ctx, getEVPMD(hash_algo));
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ rc = 1;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int pkey_len = EVP_PKEY_size(key->evp_pkey);
|
|
|
|
+ padded_sig = xcalloc(1, pkey_len);
|
|
|
|
+ if (!BN_bn2binpad(sig->bn, padded_sig, pkey_len)) {
|
|
|
|
+ rc = 1;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = EVP_PKEY_verify(pkey_ctx, padded_sig, pkey_len, hash, hashlen);
|
|
|
|
+ if (ret == 1)
|
|
|
|
+ {
|
|
|
|
+ /* Success */
|
|
|
|
+ rc = 0;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ /* Failure */
|
|
|
|
+ rc = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+done:
|
|
|
|
+ EVP_PKEY_CTX_free(pkey_ctx);
|
|
|
|
+ free(padded_sig);
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/****************************** DSA ***************************************/
|
|
|
|
+/* Key */
|
|
|
|
+
|
|
|
|
+struct pgpDigKeyDSA_s {
|
|
|
|
+ BIGNUM *p; /* Prime */
|
|
|
|
+ BIGNUM *q; /* Subprime */
|
|
|
|
+ BIGNUM *g; /* Base */
|
|
|
|
+ BIGNUM *y; /* Public Key */
|
|
|
|
+
|
|
|
|
+ DSA *dsa_key; /* Fully constructed key */
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int constructDSASigningKey(struct pgpDigKeyDSA_s *key)
|
|
|
|
+{
|
|
|
|
+ int rc;
|
|
|
|
+
|
|
|
|
+ if (key->dsa_key) {
|
|
|
|
+ /* We've already constructed it, so just reuse it */
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Create the DSA key */
|
|
|
|
+ DSA *dsa = DSA_new();
|
|
|
|
+ if (!dsa) return 0;
|
|
|
|
+
|
|
|
|
+ if (!DSA_set0_pqg(dsa, key->p, key->q, key->g)) {
|
|
|
|
+ rc = 0;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!DSA_set0_key(dsa, key->y, NULL)) {
|
|
|
|
+ rc = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ key->dsa_key = dsa;
|
|
|
|
+
|
|
|
|
+ rc = 1;
|
|
|
|
+done:
|
|
|
|
+ if (rc == 0) {
|
|
|
|
+ DSA_free(dsa);
|
|
|
|
+ }
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static int pgpSetKeyMpiDSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
|
|
|
|
+{
|
|
|
|
+ BIGNUM *bn;
|
|
|
|
+ size_t mlen = pgpMpiLen(p) - 2;
|
|
|
|
+ struct pgpDigKeyDSA_s *key = pgpkey->data;
|
|
|
|
+
|
|
|
|
+ if(!key) {
|
|
|
|
+ key = pgpkey->data = xcalloc(1, sizeof(*key));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Create a BIGNUM from the key pointer.
|
|
|
|
+ Note: this assumes big-endian data as required
|
|
|
|
+ by the PGP multiprecision integer format
|
|
|
|
+ (RFC4880, Section 3.2) */
|
|
|
|
+ bn = BN_bin2bn(p+2, mlen, NULL);
|
|
|
|
+ if (!bn) return 1;
|
|
|
|
+
|
|
|
|
+ switch(num) {
|
|
|
|
+ case 0:
|
|
|
|
+ /* Prime */
|
|
|
|
+ if (key->p) {
|
|
|
|
+ /* This should only ever happen once per key */
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ key->p = bn;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 1:
|
|
|
|
+ /* Subprime */
|
|
|
|
+ if (key->q) {
|
|
|
|
+ /* This should only ever happen once per key */
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ key->q = bn;
|
|
|
|
+ break;
|
|
|
|
+ case 2:
|
|
|
|
+ /* Base */
|
|
|
|
+ if (key->g) {
|
|
|
|
+ /* This should only ever happen once per key */
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ key->g = bn;
|
|
|
|
+ break;
|
|
|
|
+ case 3:
|
|
|
|
+ /* Public */
|
|
|
|
+ if (key->y) {
|
|
|
|
+ /* This should only ever happen once per key */
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ key->y = bn;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void pgpFreeKeyDSA(pgpDigAlg pgpkey)
|
|
|
|
+{
|
|
|
|
+ struct pgpDigKeyDSA_s *key = pgpkey->data;
|
|
|
|
+ if (key) {
|
|
|
|
+ if (key->dsa_key) {
|
|
|
|
+ DSA_free(key->dsa_key);
|
|
|
|
+ } else {
|
|
|
|
+ /* If sig->dsa_key was constructed,
|
|
|
|
+ * the memory management of these BNs
|
|
|
|
+ * are freed with it. */
|
|
|
|
+ BN_clear_free(key->p);
|
|
|
|
+ BN_clear_free(key->q);
|
|
|
|
+ BN_clear_free(key->g);
|
|
|
|
+ BN_clear_free(key->y);
|
|
|
|
+ }
|
|
|
|
+ free(key);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* Signature */
|
|
|
|
+
|
|
|
|
+struct pgpDigSigDSA_s {
|
|
|
|
+ BIGNUM *r;
|
|
|
|
+ BIGNUM *s;
|
|
|
|
+
|
|
|
|
+ DSA_SIG *dsa_sig;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int constructDSASignature(struct pgpDigSigDSA_s *sig)
|
|
|
|
+{
|
|
|
|
+ int rc;
|
|
|
|
+
|
|
|
|
+ if (sig->dsa_sig) {
|
|
|
|
+ /* We've already constructed it, so just reuse it */
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Create the DSA signature */
|
|
|
|
+ DSA_SIG *dsa_sig = DSA_SIG_new();
|
|
|
|
+ if (!dsa_sig) return 0;
|
|
|
|
+
|
|
|
|
+ if (!DSA_SIG_set0(dsa_sig, sig->r, sig->s)) {
|
|
|
|
+ rc = 0;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ sig->dsa_sig = dsa_sig;
|
|
|
|
+
|
|
|
|
+ rc = 1;
|
|
|
|
+done:
|
|
|
|
+ if (rc == 0) {
|
|
|
|
+ DSA_SIG_free(sig->dsa_sig);
|
|
|
|
+ }
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int pgpSetSigMpiDSA(pgpDigAlg pgpsig, int num, const uint8_t *p)
|
|
|
|
+{
|
|
|
|
+ BIGNUM *bn = NULL;
|
|
|
|
+
|
|
|
|
+ int mlen = pgpMpiLen(p) - 2;
|
|
|
|
+ int rc = 1;
|
|
|
|
+
|
|
|
|
+ struct pgpDigSigDSA_s *sig = pgpsig->data;
|
|
|
|
+ if (!sig) {
|
|
|
|
+ sig = xcalloc(1, sizeof(*sig));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Create a BIGNUM from the signature pointer.
|
|
|
|
+ Note: this assumes big-endian data as required
|
|
|
|
+ by the PGP multiprecision integer format
|
|
|
|
+ (RFC4880, Section 3.2) */
|
|
|
|
+ bn = BN_bin2bn(p+2, mlen, NULL);
|
|
|
|
+ if (!bn) return 1;
|
|
|
|
+
|
|
|
|
+ switch (num) {
|
|
|
|
+ case 0:
|
|
|
|
+ if (sig->r) {
|
|
|
|
+ /* This should only ever happen once per signature */
|
|
|
|
+ BN_free(bn);
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ sig->r = bn;
|
|
|
|
+ rc = 0;
|
|
|
|
+ break;
|
|
|
|
+ case 1:
|
|
|
|
+ if (sig->s) {
|
|
|
|
+ /* This should only ever happen once per signature */
|
|
|
|
+ BN_free(bn);
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ sig->s = bn;
|
|
|
|
+ rc = 0;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pgpsig->data = sig;
|
|
|
|
+
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void pgpFreeSigDSA(pgpDigAlg pgpsig)
|
|
|
|
+{
|
|
|
|
+ struct pgpDigSigDSA_s *sig = pgpsig->data;
|
|
|
|
+ if (sig) {
|
|
|
|
+ if (sig->dsa_sig) {
|
|
|
|
+ DSA_SIG_free(sig->dsa_sig);
|
|
|
|
+ } else {
|
|
|
|
+ /* If sig->dsa_sig was constructed,
|
|
|
|
+ * the memory management of these BNs
|
|
|
|
+ * are freed with it. */
|
|
|
|
+ BN_clear_free(sig->r);
|
|
|
|
+ BN_clear_free(sig->s);
|
|
|
|
+ }
|
|
|
|
+ free(pgpsig->data);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int pgpVerifySigDSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
|
|
|
|
+ uint8_t *hash, size_t hashlen, int hash_algo)
|
|
|
|
+{
|
|
|
|
+ int rc, ret;
|
|
|
|
+ struct pgpDigSigDSA_s *sig = pgpsig->data;
|
|
|
|
+
|
|
|
|
+ struct pgpDigKeyDSA_s *key = pgpkey->data;
|
|
|
|
+
|
|
|
|
+ if(!constructDSASigningKey(key)) {
|
|
|
|
+ rc = 1;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!constructDSASignature(sig)) {
|
|
|
|
+ rc = 1;
|
|
|
|
+ goto done;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = DSA_do_verify(hash, hashlen, sig->dsa_sig, key->dsa_key);
|
|
|
|
+ if (ret == 1)
|
|
|
|
+ {
|
|
|
|
+ /* Success */
|
|
|
|
+ rc = 0;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ /* Failure */
|
|
|
|
+ rc = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+done:
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/****************************** NULL **************************************/
|
|
|
|
+
|
|
|
|
+static int pgpSetMpiNULL(pgpDigAlg pgpkey, int num, const uint8_t *p)
|
|
|
|
+{
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int pgpVerifyNULL(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
|
|
|
|
+ uint8_t *hash, size_t hashlen, int hash_algo)
|
|
|
|
+{
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/****************************** PGP **************************************/
|
|
|
|
+pgpDigAlg pgpPubkeyNew(int algo)
|
|
|
|
+{
|
|
|
|
+ pgpDigAlg ka = xcalloc(1, sizeof(*ka));;
|
|
|
|
+
|
|
|
|
+ switch (algo) {
|
|
|
|
+ case PGPPUBKEYALGO_RSA:
|
|
|
|
+ ka->setmpi = pgpSetKeyMpiRSA;
|
|
|
|
+ ka->free = pgpFreeKeyRSA;
|
|
|
|
+ ka->mpis = 2;
|
|
|
|
+ break;
|
|
|
|
+ case PGPPUBKEYALGO_DSA:
|
|
|
|
+ ka->setmpi = pgpSetKeyMpiDSA;
|
|
|
|
+ ka->free = pgpFreeKeyDSA;
|
|
|
|
+ ka->mpis = 4;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ ka->setmpi = pgpSetMpiNULL;
|
|
|
|
+ ka->mpis = -1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ka->verify = pgpVerifyNULL; /* keys can't be verified */
|
|
|
|
+
|
|
|
|
+ return ka;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pgpDigAlg pgpSignatureNew(int algo)
|
|
|
|
+{
|
|
|
|
+ pgpDigAlg sa = xcalloc(1, sizeof(*sa));
|
|
|
|
+
|
|
|
|
+ switch (algo) {
|
|
|
|
+ case PGPPUBKEYALGO_RSA:
|
|
|
|
+ sa->setmpi = pgpSetSigMpiRSA;
|
|
|
|
+ sa->free = pgpFreeSigRSA;
|
|
|
|
+ sa->verify = pgpVerifySigRSA;
|
|
|
|
+ sa->mpis = 1;
|
|
|
|
+ break;
|
|
|
|
+ case PGPPUBKEYALGO_DSA:
|
|
|
|
+ sa->setmpi = pgpSetSigMpiDSA;
|
|
|
|
+ sa->free = pgpFreeSigDSA;
|
|
|
|
+ sa->verify = pgpVerifySigDSA;
|
|
|
|
+ sa->mpis = 2;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ sa->setmpi = pgpSetMpiNULL;
|
|
|
|
+ sa->verify = pgpVerifyNULL;
|
|
|
|
+ sa->mpis = -1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ return sa;
|
|
|
|
+}
|