RPM Community Forums

Mailing List Message of <rpm-cvs>

[CVS] RPM: rpm/ CHANGES rpm/lib/ librpm.vers rpmns.c rpmns.h

From: Jeff Johnson <jbj@rpm5.org>
Date: Sat 29 Dec 2007 - 21:18:47 CET
Message-Id: <20071229201847.7F53134845C@rpm5.org>
  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
  @@ .
Received on Sat Dec 29 21:18:47 2007
Driven by Jeff Johnson and the RPM project team.
Hosted by OpenPKG and Ralf S. Engelschall.
Powered by FreeBSD and OpenPKG.