Almost all yours Ralf ;-)
I've renamed the routine (and changed the name space) to be more
generic.
I'm way tired of branding signification issues, PGP and GPG too ...
I'll wire up (and test) the signature(...) probe next.
Then I'll set about wiring up rpmRC returns, and add sufficient
debugging to diagnose rpm's bizarrely inscrutable behavior patterns.
There's way
too many error conditions (and the args are a bit twisty) to rely on the
overly simplified 0/1 verify return. You lose! is not what lusers
want to hear ...
Enjoy!
73 de Jeff
On Dec 29, 2007, at 3:18 PM, Jeff Johnson wrote:
> RPM Package Manager, CVS Repository
> http://rpm5.org/cvs/
>
> ______________________________________________________________________
> ______
>
> Server: rpm5.org Name: Jeff Johnson
> Root: /v/rpm/cvs Email: jbj@rpm5.org
> Module: rpm Date: 29-Dec-2007
> 21:18:47
> Branch: HEAD Handle: 2007122920184601
>
> Modified files:
> rpm CHANGES
> rpm/lib librpm.vers rpmns.c rpmns.h
>
> Log:
> - add rpmnsProbeSignature() & "signature(/text:/sig) = /pub:id"
> name
> space.
>
> Summary:
> Revision Changes Path
> 1.2037 +1 -0 rpm/CHANGES
> 1.30 +1 -0 rpm/lib/librpm.vers
> 1.8 +230 -1 rpm/lib/rpmns.c
> 1.11 +16 -0 rpm/lib/rpmns.h
>
> ______________________________________________________________________
> ______
>
> patch -p0 <<'@@ .'
> Index: rpm/CHANGES
>
> ======================================================================
> ======
> $ cvs diff -u -r1.2036 -r1.2037 CHANGES
> --- rpm/CHANGES 29 Dec 2007 16:00:07 -0000 1.2036
> +++ rpm/CHANGES 29 Dec 2007 20:18:46 -0000 1.2037
> @@ -1,4 +1,5 @@
> 5.0b3 -> 5.0b4:
> + - jbj: add rpmnsProbeSignature() & "signature(/text:/sig) = /
> pub:id" probe.
> - jbj: pgpReadPkts: truncate binary encoded pgp pktlen to
> actual length.
> - jbj: pgpReadPkts: identify binary encoded pgp pkts correctly.
> - jbj: fix: remove unused assertion.
> @@ .
> patch -p0 <<'@@ .'
> Index: rpm/lib/librpm.vers
>
> ======================================================================
> ======
> $ cvs diff -u -r1.29 -r1.30 librpm.vers
> --- rpm/lib/librpm.vers 18 Dec 2007 19:40:53 -0000 1.29
> +++ rpm/lib/librpm.vers 29 Dec 2007 20:18:47 -0000 1.30
> @@ -221,6 +221,7 @@
> _rpmns_debug;
> rpmnsClassify;
> rpmnsParse;
> + rpmnsProbeSignature;
> rpmPermsString;
> rpmPlatformScore;
> rpmProblemString;
> @@ .
> patch -p0 <<'@@ .'
> Index: rpm/lib/rpmns.c
>
> ======================================================================
> ======
> $ cvs diff -u -r1.7 -r1.8 rpmns.c
> --- rpm/lib/rpmns.c 7 Dec 2007 19:54:18 -0000 1.7
> +++ rpm/lib/rpmns.c 29 Dec 2007 20:18:47 -0000 1.8
> @@ -3,14 +3,23 @@
> */
> #include "system.h"
>
> -#include <rpmio.h>
> +#include <rpmio_internal.h> /* XXX rpmioSlurp */
> #include <rpmmacro.h>
>
> +#define _RPMPGP_INTERNAL
> +#include <rpmpgp.h>
> +
> #define _RPMEVR_INTERNAL
> #include <rpmevr.h>
> #define _RPMNS_INTERNAL
> #include <rpmns.h>
>
> +#include <rpmcb.h>
> +#include <rpmdb.h>
> +#include <rpmps.h>
> +#define _RPMTS_INTERNAL /* XXX ts->pkpkt */
> +#include <rpmts.h>
> +
> #include "debug.h"
>
> /*@unchecked@*/
> @@ -79,6 +88,7 @@
> { "running", RPMNS_TYPE_RUNNING },
> { "sanitycheck", RPMNS_TYPE_SANITY },
> { "vcheck", RPMNS_TYPE_VCHECK },
> + { "signature", RPMNS_TYPE_SIGNATURE },
> { "exists", RPMNS_TYPE_ACCESS },
> { "executable", RPMNS_TYPE_ACCESS },
> { "readable", RPMNS_TYPE_ACCESS },
> @@ -196,6 +206,7 @@
> case RPMNS_TYPE_RUNNING:
> case RPMNS_TYPE_SANITY:
> case RPMNS_TYPE_VCHECK:
> + case RPMNS_TYPE_SIGNATURE:
> ns->NS = ns->str;
> if (ns->NS[0] == '!')
> ns->NS++;
> @@ -226,3 +237,221 @@
> }
> return 0;
> }
> +
> +/**
> + * Convert hex to binary nibble.
> + * @param c hex character
> + * @return binary nibble
> + */
> +static inline unsigned char nibble(char c)
> + /*@*/
> +{
> + if (c >= '0' && c <= '9')
> + return (c - '0');
> + if (c >= 'A' && c <= 'F')
> + return (c - 'A') + 10;
> + if (c >= 'a' && c <= 'f')
> + return (c - 'a') + 10;
> + return 0;
> +}
> +
> +int rpmnsProbeSignature(void * _ts, const char * fn, const char
> * sigfn,
> + const char * pubfn, const char * pubid)
> +{
> + rpmts ts = _ts;
> + pgpDig dig = rpmtsDig(ts);
> + pgpDigParams sigp;
> + pgpDigParams pubp;
> + const unsigned char * sigpkt = NULL;
> + size_t sigpktlen = 0;
> + DIGEST_CTX ctx = NULL;
> + int printing = 0;
> + int rc = 0;
> + int xx;
> +
> + /* Load the signature. Use sigfn if specified, otherwise
> clearsign. */
> + if (sigfn != NULL) {
> + const char * _sigfn = rpmExpand(sigfn, NULL);
> + xx = pgpReadPkts(_sigfn, &sigpkt, &sigpktlen);
> + if (xx != PGPARMOR_SIGNATURE) {
> + _sigfn = _free(_sigfn);
> + goto exit;
> + }
> + _sigfn = _free(_sigfn);
> + } else {
> + const char * _sigfn = rpmExpand(fn, NULL);
> + xx = pgpReadPkts(_sigfn, &sigpkt, &sigpktlen);
> + if (xx != PGPARMOR_SIGNATURE) {
> + _sigfn = _free(_sigfn);
> + goto exit;
> + }
> + _sigfn = _free(_sigfn);
> + }
> + xx = pgpPrtPkts((uint8_t *)sigpkt, sigpktlen, dig, printing);
> + if (xx)
> + goto exit;
> +
> + sigp = pgpGetSignature(dig);
> +
> + if (sigp->version != 3 && sigp->version != 4)
> + goto exit;
> +
> + /* Load the pubkey. Use pubfn if specified, otherwise rpmdb
> keyring. */
> + if (pubfn != NULL) {
> + const char * _pubfn = rpmExpand(pubfn, NULL);
> + xx = pgpReadPkts(_pubfn, &ts->pkpkt, &ts->pkpktlen);
> + if (xx != PGPARMOR_PUBKEY) {
> + _pubfn = _free(_pubfn);
> + goto exit;
> + }
> + _pubfn = _free(_pubfn);
> + xx = pgpPrtPkts((uint8_t *)ts->pkpkt, ts->pkpktlen, dig,
> printing);
> + if (xx)
> + goto exit;
> + } else {
> + if (pgpFindPubkey(dig) != RPMRC_OK)
> + goto exit;
> + }
> +
> + pubp = pgpGetPubkey(dig);
> +
> + /* Is this the requested pubkey? */
> + if (pubid != NULL) {
> + size_t ns = strlen(pubid);
> + const char * s;
> + char * t;
> + int i;
> +
> + /* At least 8 hex digits please. */
> + for (i = 0, s = pubid; *s && isxdigit(*s); s++, i++)
> + ;
> + if (!(*s == '\0' && i > 8 && (i%2) == 0))
> + goto exit;
> +
> + /* Truncate to key id size. */
> + s = pubid;
> + if (ns > 16) {
> + s += (ns - 16);
> + ns = 16;
> + }
> + ns >>= 1;
> + t = memset(alloca(ns), 0, ns);
> + for (i = 0; i < ns; i++)
> + t[i] = (nibble(s[2*i]) << 4) | nibble(s[2*i+1]);
> +
> + /* Compare the pubkey id. */
> + s = (const char *)pubp->signid;
> + xx = memcmp(t, s + (8 - ns), ns);
> +
> + /* XXX HACK: V4 RSA key id's are wonky atm. */
> + if (pubp->pubkey_algo == PGPPUBKEYALGO_RSA)
> + xx = 0;
> +
> + if (xx)
> + goto exit;
> + }
> +
> + /* Do the parameters match the signature? */
> + if (!(sigp->pubkey_algo == pubp->pubkey_algo
> +#ifdef NOTYET
> + && sigp->hash_algo == pubp->hash_algo
> +#endif
> + /* XXX HACK: V4 RSA key id's are wonky atm. */
> + && (pubp->pubkey_algo == PGPPUBKEYALGO_RSA || !memcmp(sigp-
> >signid, pubp->signid, sizeof(sigp->signid))) ) )
> + goto exit;
> +
> + /* Compute the message digest. */
> + ctx = rpmDigestInit(sigp->hash_algo, RPMDIGEST_NONE);
> +
> + {
> + static const char clrtxt[] = "-----BEGIN PGP SIGNED MESSAGE-----";
> + static const char sigtxt[] = "-----BEGIN PGP SIGNATURE-----";
> + const char * _fn = rpmExpand(fn, NULL);
> + uint8_t * b = NULL;
> + ssize_t blen = 0;
> + int _rc = rpmioSlurp(_fn, &b, &blen);
> +
> + if (!(_rc == 0 && b != NULL && blen > 0)) {
> + b = _free(b);
> + _fn = _free(_fn);
> + goto exit;
> + }
> + _fn = _free(_fn);
> +
> + /* XXX clearsign sig is PGPSIGTYPE_TEXT not PGPSIGTYPE_BINARY. */
> + if (!strncmp((char *)b, clrtxt, strlen(clrtxt))) {
> + const char * be = (char *) (b + blen);
> + const char * t;
> + const char * te;
> +
> + /* Skip to '\n\n' start-of-plaintext */
> + t = (char *) b;
> + while (t && t < be && *t != '\n')
> + t = strchr(t, '\n') + 1;
> + if (!(t && t < be))
> + goto exit;
> + t++;
> +
> + /* Skip to start-of-signature */
> + te = t;
> + while (te && te < be && strncmp(te, sigtxt, strlen(sigtxt)))
> + te = strchr(te, '\n') + 1;
> + if (!(te && te < be))
> + goto exit;
> + te--; /* hmmm, one too far? does clearsign snip last \n? */
> +
> + xx = rpmDigestUpdate(ctx, t, (te - t));
> + } else
> + xx = rpmDigestUpdate(ctx, b, blen);
> +
> + b = _free(b);
> + }
> +
> + if (sigp->hash != NULL)
> + xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
> + if (sigp->version == 4) {
> + uint32_t nb = sigp->hashlen;
> + uint8_t trailer[6];
> + nb = htonl(nb);
> + trailer[0] = sigp->version;
> + trailer[1] = 0xff;
> + memcpy(trailer+2, &nb, sizeof(nb));
> + xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
> + }
> +
> + /* Load the message digest. */
> + switch(sigp->pubkey_algo) {
> + default:
> + xx = 1;
> + break;
> + case PGPPUBKEYALGO_DSA:
> + xx = pgpImplSetDSA(ctx, dig, sigp);
> + break;
> + case PGPPUBKEYALGO_RSA:
> + xx = pgpImplSetRSA(ctx, dig, sigp);
> + break;
> + }
> + if (xx)
> + goto exit;
> +
> + /* Verify the signature. */
> + switch(sigp->pubkey_algo) {
> + default:
> + rc = 0;
> + break;
> + case PGPPUBKEYALGO_DSA:
> + rc = pgpImplVerifyDSA(dig);
> + break;
> + case PGPPUBKEYALGO_RSA:
> + rc = pgpImplVerifyRSA(dig);
> + break;
> + }
> +
> +exit:
> + sigpkt = _free(sigpkt);
> + ts->pkpkt = _free(ts->pkpkt);
> + ts->pkpktlen = 0;
> + rpmtsCleanDig(ts);
> +
> + return rc;
> +}
> @@ .
> patch -p0 <<'@@ .'
> Index: rpm/lib/rpmns.h
>
> ======================================================================
> ======
> $ cvs diff -u -r1.10 -r1.11 rpmns.h
> --- rpm/lib/rpmns.h 26 Dec 2007 09:55:59 -0000 1.10
> +++ rpm/lib/rpmns.h 29 Dec 2007 20:18:47 -0000 1.11
> @@ -50,6 +50,7 @@
> RPMNS_TYPE_RUNNING = (1 << 24), /*!< running(foo) */
> RPMNS_TYPE_SANITY = (1 << 25), /*!< sanitycheck(foo) */
> RPMNS_TYPE_VCHECK = (1 << 26), /*!< vcheck(foo) */
> + RPMNS_TYPE_SIGNATURE= (1 << 27), /*!< signature(/text:/sig)
> = /pub:id */
> } nsType;
>
> #if defined(_RPMNS_INTERNAL)
> @@ -115,6 +116,21 @@
> /*@globals internalState @*/
> /*@modifies internalState @*/;
>
> +/** \ingroup rpmns
> + * Verify OpenPGP signature on a file.
> + * @param _ts transaction set
> + * @param fn plaintext (or clearsign) file
> + * @param sigfn binary/pem encoded signature file (NULL iff
> clearsign)
> + * @param pubfn binary/pem encoded pubkey file (NULL uses rpmdb
> keyring)
> + * @param pubid pubkey fingerprint hex string (NULL disables
> check)
> + * @return 1 if verified, 0 if not verified
> + */
> +int rpmnsProbeSignature(void * _ts, const char * fn,
> + /*@null@*/ const char * sigfn,
> + /*@null@*/ const char * pubfn,
> + /*@null@*/ const char * pubid)
> + /*@*/;
> +
> #ifdef __cplusplus
> }
> #endif
> @@ .
> ______________________________________________________________________
> RPM Package Manager http://rpm5.org
> CVS Sources Repository rpm-cvs@rpm5.org
Received on Sat Dec 29 21:29:33 2007