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