From 7f278032625d561405cd89632a129d0ee1d581e0 Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Tue, 7 Mar 2017 14:00:37 +0100 Subject: [PATCH] Switch to OpenSSL (RHBZ #1390624) Signed-off-by: Igor Gnatenko --- ...SL-support-for-digest-and-signatures.patch | 1160 +++++++++++++++++ rpm.spec | 16 +- 2 files changed, 1171 insertions(+), 5 deletions(-) create mode 100644 0001-Add-OpenSSL-support-for-digest-and-signatures.patch diff --git a/0001-Add-OpenSSL-support-for-digest-and-signatures.patch b/0001-Add-OpenSSL-support-for-digest-and-signatures.patch new file mode 100644 index 0000000..070e555 --- /dev/null +++ b/0001-Add-OpenSSL-support-for-digest-and-signatures.patch @@ -0,0 +1,1160 @@ +From 64028f9a1c25ada8ffc7a48775f526600edcbf85 Mon Sep 17 00:00:00 2001 +From: Stephen Gallagher +Date: Mon, 16 Jan 2017 09:19:43 -0500 +Subject: [PATCH] Add OpenSSL support for digest and signatures + +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 +--- + INSTALL | 27 +- + Makefile.am | 17 +- + configure.ac | 108 ++++++- + rpmio/Makefile.am | 6 + + rpmio/digest_openssl.c | 838 +++++++++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 975 insertions(+), 21 deletions(-) + 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 +index b99da12ec..56aa485f7 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -43,6 +43,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/lib + AM_CPPFLAGS += -I$(top_srcdir)/rpmio + AM_CPPFLAGS += @WITH_BEECRYPT_INCLUDE@ + 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)\"" +@@ -111,45 +112,45 @@ rpm_SOURCES = rpmqv.c debug.h system.h + rpm_CPPFLAGS = $(AM_CPPFLAGS) -DIAM_RPMEIU -DIAM_RPMQ -DIAM_RPMV + rpm_LDADD = libcliutils.la + rpm_LDADD += lib/librpm.la rpmio/librpmio.la +-rpm_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ ++rpm_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ + + rpmdb_SOURCES = rpmdb.c debug.h system.h + rpmdb_CPPFLAGS = $(AM_CPPFLAGS) + rpmdb_LDADD = libcliutils.la + rpmdb_LDADD += lib/librpm.la rpmio/librpmio.la +-rpmdb_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ ++rpmdb_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ + + rpmkeys_SOURCES = rpmkeys.c debug.h system.h + rpmkeys_CPPFLAGS = $(AM_CPPFLAGS) + rpmkeys_LDADD = libcliutils.la + rpmkeys_LDADD += lib/librpm.la rpmio/librpmio.la +-rpmkeys_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ ++rpmkeys_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ + + 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 +-rpmsign_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ ++rpmsign_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ + + 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 +-rpmbuild_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ ++rpmbuild_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ + + 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 +-rpmspec_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ ++rpmspec_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ + + rpm2cpio_SOURCES = rpm2cpio.c debug.h system.h + rpm2cpio_LDADD = lib/librpm.la rpmio/librpmio.la +-rpm2cpio_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ ++rpm2cpio_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ + + rpm2archive_SOURCES = rpm2archive.c debug.h system.h + rpm2archive_LDADD = lib/librpm.la rpmio/librpmio.la +-rpm2archive_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ @WITH_ARCHIVE_LIB@ ++rpm2archive_LDADD += @WITH_BEECRYPT_LIB@ @WITH_NSS_LIB@ @WITH_OPENSSL_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@ @WITH_ARCHIVE_LIB@ + + + if LIBELF +diff --git a/configure.ac b/configure.ac +index 4f3be8770..9ecef95d1 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -245,18 +245,30 @@ AC_CHECK_HEADERS([dwarf.h], [ + 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" +@@ -265,7 +277,7 @@ if test "$with_beecrypt" = yes ; then + 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 header file.]) + ]) +@@ -275,13 +287,93 @@ AC_SUBST(WITH_BEECRYPT_LIB) + 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 + # 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. +diff --git a/rpmio/Makefile.am b/rpmio/Makefile.am +index 5ad4d6818..3ac1c715d 100644 +--- a/rpmio/Makefile.am ++++ b/rpmio/Makefile.am +@@ -6,6 +6,7 @@ AM_CFLAGS = @RPMCFLAGS@ + 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@\"" +@@ -24,8 +25,12 @@ librpmio_la_SOURCES = \ + 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) +@@ -33,6 +38,7 @@ librpmio_la_LIBADD = \ + ../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 ++#include ++#include ++#include ++ ++#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; ++} +-- +2.12.0 + diff --git a/rpm.spec b/rpm.spec index bc8aad5..f346a70 100644 --- a/rpm.spec +++ b/rpm.spec @@ -29,7 +29,7 @@ Summary: The RPM package management system Name: rpm Version: %{rpmver} -Release: %{?snapver:0.%{snapver}.}8%{?dist} +Release: %{?snapver:0.%{snapver}.}9%{?dist} Group: System Environment/Base Url: http://www.rpm.org/ Source0: http://rpm.org/releases/%{srcdir}/%{name}-%{srcver}.tar.bz2 @@ -88,6 +88,9 @@ Patch262: 0013-missing_build_ids_terminate_build.patch Patch263: 0014-generateBuildIDs-Fix-error-handling.patch Patch264: 0015-reset-buildid-file-attrs.patch +# OpenSSL backend +Patch300: 0001-Add-OpenSSL-support-for-digest-and-signatures.patch + # These are not yet upstream Patch302: rpm-4.7.1-geode-i686.patch # Probably to be upstreamed in slightly different form @@ -120,8 +123,7 @@ BuildRequires: gawk BuildRequires: elfutils-devel >= 0.112 BuildRequires: elfutils-libelf-devel BuildRequires: readline-devel zlib-devel -BuildRequires: nss-devel -BuildRequires: nss-softokn-freebl-devel +BuildRequires: openssl-devel # The popt version here just documents an older known-good version BuildRequires: popt-devel >= 1.10.2 BuildRequires: file-devel @@ -348,7 +350,7 @@ ln -s db-%{bdbver} db #CPPFLAGS=-I%{_includedir}/db%{bdbver} #LDFLAGS=-L%{_libdir}/db%{bdbver} %endif -CPPFLAGS="$CPPFLAGS `pkg-config --cflags nss` -DLUA_COMPAT_APIINTCASTS" +CPPFLAGS="$CPPFLAGS -DLUA_COMPAT_APIINTCASTS" CFLAGS="$RPM_OPT_FLAGS %{?sanitizer_flags} -DLUA_COMPAT_APIINTCASTS" LDFLAGS="$LDFLAGS %{?__global_ldflags}" export CPPFLAGS CFLAGS LDFLAGS @@ -378,7 +380,8 @@ done; --with-cap \ --with-acl \ %{?with_ndb: --with-ndb} \ - --enable-python + --enable-python \ + --with-crypto=openssl make %{?_smp_mflags} @@ -588,6 +591,9 @@ exit 0 %doc doc/librpm/html/* %changelog +* Thu Mar 16 2017 Igor Gnatenko - 4.13.0.1-9 +- Switch to OpenSSL (RHBZ #1390624) + * Wed Mar 15 2017 Mark Wielaard - 4.13.0.1-8 - Add fix to reset buildid file attributes (#1432372)