RPM Package Manager, CVS Repository
  http://rpm5.org/cvs/
  ____________________________________________________________________________

  Server: rpm5.org                         Name:   Ralf S. Engelschall
  Root:   /v/rpm/cvs                       Email:  [EMAIL PROTECTED]
  Module: rpm lua                          Date:   02-Jan-2008 17:57:37
  Branch: HEAD                             Handle: 2008010216573601

  Added files:
    rpm/scripts             integrity.cfg integrity.fp integrity.lua
                            integrity.pgp integrity.sh integrity.txt
  Modified files:
    lua/local               llocal.lua
    rpm                     VENDOR devtool.conf rpmqv.c

  Log:
    On Jeff's request, still contribute my (currently fully OpenPKG-scoped)
    RPM Integrity Checking Framework to rpm5.org to make it available to a
    wider audience and to include it already in the RPM 5 code base.
    
    This commit provides both the framework for RPM itself (changes to
    files rpmqv.c and lua/local/llocal.lua) and example usage (new files
    scripts/integrity.*).
    
    In short, the RPM Integrity Checking Framework is based around the
    following four technological parts:
    
    1. Declarative   Integrity Configuration Specification  (.cfg)
    2. Programmatic  Integrity Validation    Processor      (.lua)
    3. Cryptographic Integrity Authority     Public-Key     (.pgp)
    4. Cryptographic Integrity Authority     Fingerprint    (.fp)
    
    More detailed documentation can be found in scripts/integrity.txt.

  Summary:
    Revision    Changes     Path
    1.10        +116 -0     lua/local/llocal.lua
    2.26        +5  -0      rpm/VENDOR
    2.163       +5  -0      rpm/devtool.conf
    1.137       +196 -0     rpm/rpmqv.c
    1.1         +25 -0      rpm/scripts/integrity.cfg
    1.1         +1  -0      rpm/scripts/integrity.fp
    1.1         +65 -0      rpm/scripts/integrity.lua
    1.1         +17 -0      rpm/scripts/integrity.pgp
    1.1         +59 -0      rpm/scripts/integrity.sh
    1.1         +150 -0     rpm/scripts/integrity.txt
  ____________________________________________________________________________

  patch -p0 <<'@@ .'
  Index: lua/local/llocal.lua
  ============================================================================
  $ cvs diff -u -r1.9 -r1.10 llocal.lua
  --- lua/local/llocal.lua      2 Jan 2008 15:54:32 -0000       1.9
  +++ lua/local/llocal.lua      2 Jan 2008 16:57:37 -0000       1.10
  @@ -213,3 +213,119 @@
       return data
   end
   
  +--  -----------------------------------------------------------------------  
--
  +--                   INTEGRITY PROCESSOR GLUE CODE
  +--  -----------------------------------------------------------------------  
--
  +
  +--  provide additional "integrity" namespace
  +integrity = {}
  +
  +--  extract plaintext from a PGP clearsigned text
  +function integrity.plaintext(text)
  +    local s, _, m = util.rmatch(
  +        text,
  +        "(?s)" ..
  +        "^\\s*" ..
  +        "-----BEGIN PGP SIGNED MESSAGE-----" ..
  +        ".*?" ..
  +        "\\r?\\n" ..
  +        "\\r?\\n" ..
  +        "(.+?\\r?\\n)" ..
  +        "-----BEGIN PGP SIGNATURE-----" ..
  +        "\\r?\\n" ..
  +        ".*" ..
  +        "$"
  +    )
  +    if s == nil then
  +        return nil
  +    else
  +        return m[1]
  +    end
  +end
  +
  +--  integrity processor
  +function integrity.processor(progname, progmode, spec_fn, spec_cfg, proc_fn, 
proc_lua, proc_minver)
  +    --  optionally read integrity configuration specification
  +    if spec_cfg == nil then
  +        local fp, error = io.open(spec_fn, "r")
  +        if fp == nil then
  +            return "ERROR: unable to read Integrity Configuration 
Specification file: " .. error
  +        end
  +        spec_cfg = fp:read("*all")
  +        io.close(fp)
  +    end
  +
  +    --  optionally read integrity validation processor
  +    if proc_lua == nil then
  +        local fp, error = io.open(proc_fn, "r")
  +        if fp == nil then
  +            return "ERROR: unable to read Integrity Validation Processor 
file: " .. error
  +        end
  +        proc_lua = fp:read("*all")
  +        io.close(fp)
  +    end
  +
  +    --  extract plaintext from "clearsigned" integrity configuration 
specification
  +    spec_cfg = integrity.plaintext(spec_cfg)
  +    if spec_cfg == nil then
  +        return "ERROR: failed to extract Integrity Configuration 
Specification plaintext from clearsigned text"
  +    end
  +
  +    --  extract plaintext from "clearsigned" integrity validation processor
  +    proc_lua = integrity.plaintext(proc_lua)
  +    if proc_lua == nil then
  +        return "ERROR: failed to extract Integrity Validation Processor 
plaintext from clearsigned text"
  +    end
  +
  +    --  parse integrity configuration specification
  +    local cfg = {}
  +    util.rsubst(spec_cfg,
  +        "(?s)" ..
  +        "([A-Za-z0-9][A-Za-z0-9-]*):[ \\t]*" ..
  +        "([^\\r\\n]*" ..
  +        "(?:\\r?\\n[ \\t]+[^\\r\\n]+)*" ..
  +        ")\\r?\\n",
  +        function (m)
  +            local key = m[1]
  +            local value = util.rsubst(m[2], "^[ \\t]*(?:\\r?\\n)?(.*?)[ 
\\t]*$", "$1")
  +            cfg[key] = value
  +        end
  +    )
  +
  +    --  create validation context object
  +    local ctx = {}
  +    ctx.rpm = {}
  +    ctx.rpm.name = progname;
  +    ctx.rpm.mode = progmode;
  +
  +    --  load integrity validation processor
  +    integrity.version = nil
  +    integrity.validate = nil
  +    local f, e = loadstring(proc_lua)
  +    if f == nil then
  +        return "ERROR: failed to load Integrity Validation Processor (syntax 
problem):\n" ..
  +               "rpm: Lua: " .. e
  +    end
  +    f();
  +    if type(integrity.validate) ~= "function" then
  +        return "ERROR: failed to load Integrity Validation Processor 
(semantic problem)"
  +    end
  +
  +    --  ensure that integrity validation processor is at least of the 
minimum required version
  +    if type(integrity.version) ~= "string" then
  +        return "ERROR: invalid Integrity Validation Processor version 
(syntax problem)"
  +    end
  +    if rpm.vercmp(integrity.version, proc_minver) < 0 then
  +        return "ERROR: too old Integrity Validation Processor version 
(semantic problem)"
  +    end
  +
  +    --  call integrity validation processor
  +    local result = integrity.validate(ctx, cfg)
  +
  +    --  return validation result
  +    if type(result) ~= "string" then
  +        result = "ERROR: invalid result from Integrity Validation Processor"
  +    end
  +    return result
  +end
  +
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/VENDOR
  ============================================================================
  $ cvs diff -u -r2.25 -r2.26 VENDOR
  --- rpm/VENDOR        2 Jan 2008 11:29:51 -0000       2.25
  +++ rpm/VENDOR        2 Jan 2008 16:57:36 -0000       2.26
  @@ -370,6 +370,11 @@
                        plus "rpm -bb" operations.
        ________________________________________________________________________
   
  +     Change:         integrity-checking
  +     Purpose:        RPM integrity checking framework
  +     Reason:         [see scripts/integrity.txt for detailed documentation]
  +     ________________________________________________________________________
  +
     o  Name:           RPM4DARWIN
        Vendor:         RPM for Darwin (Mac OS X) 
<http://rpm4darwin.sourceforge.net/>
        Representative: Anders F. Bjorklund <[EMAIL PROTECTED]> <[EMAIL 
PROTECTED]>
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/devtool.conf
  ============================================================================
  $ cvs diff -u -r2.162 -r2.163 devtool.conf
  --- rpm/devtool.conf  31 Dec 2007 20:22:38 -0000      2.162
  +++ rpm/devtool.conf  2 Jan 2008 16:57:36 -0000       2.163
  @@ -857,6 +857,11 @@
           LIBS=""
           if [ ".$RPM_VENDOR_OPENPKG" != . ]; then
               CPPFLAGS="$CPPFLAGS -DRPM_VENDOR_OPENPKG"
  +            RPM_INTEGRITY_FP=`cat scripts/integrity.fp`
  +            RPM_INTEGRITY_MV=`grep 'integrity\.version' 
scripts/integrity.lua |\
  +                sed -e 's;^.*"\([0-9][0-9.]*\)".*$;\1;'`
  +            CPPFLAGS="$CPPFLAGS -DRPM_INTEGRITY_FP=\\\"$RPM_INTEGRITY_FP\\\""
  +            CPPFLAGS="$CPPFLAGS -DRPM_INTEGRITY_MV=\\\"$RPM_INTEGRITY_MV\\\""
           fi
           LDFLAGS="$LDFLAGS -L$base3rd/bin/$platform/openssl-${v_openssl}"     
  # shameless workaround for Neon/XAR
           LDFLAGS="$LDFLAGS 
-L$base3rd/bin/$platform/libxml2-${v_libxml2}/.libs" # shameless workaround for 
XAR
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmqv.c
  ============================================================================
  $ cvs diff -u -r1.136 -r1.137 rpmqv.c
  --- rpm/rpmqv.c       28 Dec 2007 11:46:58 -0000      1.136
  +++ rpm/rpmqv.c       2 Jan 2008 16:57:36 -0000       1.137
  @@ -13,10 +13,21 @@
   #define      IAM_RPMK
   #endif
   
  +#if defined(RPM_VENDOR_OPENPKG) /* integrity-checking */
  +#include "rpmio_internal.h"
  +#endif
  +
   #include <rpmio.h>
   #include <rpmcli.h>
   #include <rpmbuild.h>
   
  +#if defined(RPM_VENDOR_OPENPKG) /* integrity-checking */
  +#include "rpmns.h"
  +#define _RPMLUA_INTERNAL
  +#include "rpmlua.h"
  +#include "rpmluaext.h"
  +#endif
  +
   #include "rpmdb.h"
   #include "rpmps.h"
   #include "rpmts.h"
  @@ -168,6 +179,187 @@
        poptPrintUsage(con, fp, flags);
   }
   
  +#if defined(RPM_VENDOR_OPENPKG) /* integrity-checking */
  +
  +#if !defined(RPM_INTEGRITY_FP)
  +#error required RPM_INTEGRITY_FP (fingerprint of public key of integrity 
authority) not defined!
  +#endif
  +
  +enum {
  +    INTEGRITY_OK      = 0,
  +    INTEGRITY_WARNING = 1,
  +    INTEGRITY_ERROR   = 2
  +};
  +
  +static void integrity_check_message(const char *fmt, ...)
  +{
  +    va_list ap;
  +
  +    va_start(ap, fmt);
  +    fprintf(stderr, "rpm: ATTENTION: INTEGRITY CHECKING DETECTED AN 
ENVIRONMENT ANOMALY!\nrpm: ");
  +    vfprintf(stderr, fmt, ap);
  +    va_end(ap);
  +    return;
  +}
  +
  +static void integrity_check(const char *progname, enum modes progmode_num)
  +{
  +    rpmts ts = NULL;
  +    rpmlua lua = NULL;
  +    char *spec_fn = NULL;
  +    char *proc_fn = NULL;
  +    char *pkey_fn = NULL;
  +    char *spec = NULL;
  +    char *proc = NULL;
  +    const char *result = NULL;
  +    const char *error = NULL;
  +    int xx;
  +    const char *progmode;
  +    int rc = INTEGRITY_ERROR;
  +
  +    /* determine paths of integrity checking related files */
  +    spec_fn = 
rpmExpand("%{?_integrity_spec_cfg}%{!?_integrity_spec_cfg:scripts/integrity.cfg}",
 NULL);
  +    if (spec_fn == NULL || spec_fn[0] == '\0') {
  +        integrity_check_message("ERROR: Integrity Configuration 
Specification file not configured.\n"
  +            "rpm: HINT: macro %%{_integrity_spec_cfg} not configured 
correctly.\n");
  +        goto failure;
  +    }
  +    proc_fn = 
rpmExpand("%{?_integrity_proc_lua}%{!?_integrity_proc_lua:scripts/integrity.lua}",
 NULL);
  +    if (proc_fn == NULL || proc_fn[0] == '\0') {
  +        integrity_check_message("ERROR: Integrity Validation Processor file 
not configured.\n"
  +            "rpm: HINT: macro %%{_integrity_proc_lua} not configured 
correctly.\n");
  +        goto failure;
  +    }
  +    pkey_fn = 
rpmExpand("%{?_integrity_pkey_pgp}%{!?_integrity_pkey_pgp:scripts/integrity.pgp}",
 NULL);
  +    if (pkey_fn == NULL || pkey_fn[0] == '\0') {
  +        integrity_check_message("ERROR: Integrity Autority Public-Key file 
not configured.\n"
  +            "rpm: HINT: macro %%{_integrity_pkey_pgp} not configured 
correctly.\n");
  +        goto failure;
  +    }
  +
  +    /* create RPM transaction environment and open RPM database */
  +    ts = rpmtsCreate();
  +    (void)rpmtsOpenDB(ts, O_RDONLY);
  +
  +    /* check signature on integrity configuration specification file */
  +    if (rpmnsProbeSignature(ts, spec_fn, NULL, pkey_fn, RPM_INTEGRITY_FP, 0) 
!= RPMRC_OK) {
  +        integrity_check_message("ERROR: Integrity Configuration 
Specification file contains invalid signature.\n"
  +            "rpm: HINT: Check file \"%s\".\n", spec_fn);
  +        goto failure;
  +    }
  +
  +    /* check signature on integrity validation processor file */
  +    if (rpmnsProbeSignature(ts, proc_fn, NULL, pkey_fn, RPM_INTEGRITY_FP, 0) 
!= RPMRC_OK) {
  +        integrity_check_message("ERROR: Integrity Validation Processor file 
contains invalid signature.\n"
  +            "rpm: HINT: Check file \"%s\".\n", proc_fn);
  +        goto failure;
  +    }
  +
  +    /* load integrity configuration specification file */
  +    spec = NULL;
  +     xx = rpmioSlurp(spec_fn, (uint8_t **)&spec, NULL);
  +     if (!(xx == 0 && spec != NULL)) {
  +        integrity_check_message("ERROR: Unable to load Integrity 
Configuration Specification file.\n"
  +            "rpm: HINT: Check file \"%s\".\n", spec_fn);
  +        goto failure;
  +    }
  +
  +    /* load integrity validation processor file */
  +    proc = NULL;
  +     xx = rpmioSlurp(proc_fn, (uint8_t **)&proc, NULL);
  +     if (!(xx == 0 && proc != NULL)) {
  +        integrity_check_message("ERROR: Unable to load Integrity Validation 
Processor file.\n"
  +            "rpm: HINT: Check file \"%s\".\n", proc_fn);
  +        goto failure;
  +    }
  +
  +    /* provision program name and mode */
  +    if (progname == NULL || progname[0] == '\0')
  +        progname = "rpm";
  +    switch (progmode_num) {
  +        case MODE_QUERY:     progmode = "query";     break;
  +        case MODE_VERIFY:    progmode = "verify";    break;
  +        case MODE_CHECKSIG:  progmode = "checksig";  break;
  +        case MODE_RESIGN:    progmode = "resign";    break;
  +        case MODE_INSTALL:   progmode = "install";   break;
  +        case MODE_ERASE:     progmode = "erase";     break;
  +        case MODE_BUILD:     progmode = "build";     break;
  +        case MODE_REBUILD:   progmode = "rebuild";   break;
  +        case MODE_RECOMPILE: progmode = "recompile"; break;
  +        case MODE_TARBUILD:  progmode = "tarbuild";  break;
  +        case MODE_INITDB:    progmode = "initdb";    break;
  +        case MODE_REBUILDDB: progmode = "rebuilddb"; break;
  +        case MODE_VERIFYDB:  progmode = "verifydb";  break;
  +        case MODE_UNKNOWN:   progmode = "unknown";   break;
  +        default:             progmode = "unknown";   break;
  +    }
  +
  +    /* execute Integrity Validation Processor via Lua glue code */
  +    lua = rpmluaNew();
  +    rpmluaSetPrintBuffer(lua, 1);
  +    rpmluaextActivate(lua);
  +    lua_getfield(lua->L, LUA_GLOBALSINDEX, "integrity");
  +    lua_getfield(lua->L, -1, "processor");
  +    lua_remove(lua->L, -2);
  +    lua_pushstring(lua->L, progname);
  +    lua_pushstring(lua->L, progmode);
  +    lua_pushstring(lua->L, spec_fn);
  +    lua_pushstring(lua->L, spec);
  +    lua_pushstring(lua->L, proc_fn);
  +    lua_pushstring(lua->L, proc);
  +#ifdef RPM_INTEGRITY_MV
  +    lua_pushstring(lua->L, RPM_INTEGRITY_MV);
  +#else
  +    lua_pushstring(lua->L, "0");
  +#endif
  +    if (lua_pcall(lua->L, 7, 1, 0) != 0) {
  +        error = lua_isstring(lua->L, -1) ? lua_tostring(lua->L, -1) : 
"unknown error";
  +        lua_pop(lua->L, 1);
  +        integrity_check_message("ERROR: Failed to execute Integrity 
Validation Processor.\n"
  +            "rpm: ERROR: Lua: %s.\n"
  +            "rpm: HINT: Check file \"%s\".\n", error, proc_fn);
  +        goto failure;
  +    }
  +
  +    /* check Integrity Validation Processor results */
  +    if (!lua_isstring(lua->L, -1)) {
  +        integrity_check_message("ERROR: Failed to fetch Integrity Validation 
Processor results.\n"
  +            "rpm: HINT: Check file \"%s\".\n", proc_fn);
  +        goto failure;
  +    }
  +    result = lua_tostring(lua->L, -1);
  +    if (strcmp(result, "OK") == 0)
  +        rc = INTEGRITY_OK;
  +    else if (strncmp(result, "WARNING:", 8) == 0) {
  +        rc = INTEGRITY_WARNING;
  +        integrity_check_message("%s\n", result);
  +    }
  +    else {
  +        rc = INTEGRITY_ERROR;
  +        integrity_check_message("%s\n", result);
  +    }
  +
  +    /* cleanup processing */
  +    failure:
  +    if (lua != NULL)
  +        rpmluaFree(lua);
  +    if (ts != NULL)
  +        ts = rpmtsFree(ts);
  +    if (spec != NULL)
  +        spec = _free(spec);
  +    if (proc != NULL)
  +        proc = _free(proc);
  +
  +    /* final result handling */
  +    if (rc != INTEGRITY_OK) {
  +        sleep(4);
  +        if (rc == INTEGRITY_ERROR)
  +            exit(42);
  +    }
  +    return;
  +}
  +#endif
  +
   /[EMAIL PROTECTED]@*/ /* LCL: segfault */
   /[EMAIL PROTECTED]@*/ /* FIX: shrug */
   #if !defined(__GLIBC__) && !defined(__LCLINT__)
  @@ -472,6 +664,10 @@
        }
       }
   
  +#if defined(RPM_VENDOR_OPENPKG) /* integrity-checking */
  +    integrity_check(__progname, bigMode);
  +#endif
  +
   #if defined(IAM_RPMBT) || defined(IAM_RPMK)
       if (0
   #if defined(IAM_RPMBT)
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/scripts/integrity.cfg
  ============================================================================
  $ cvs diff -u -r0 -r1.1 integrity.cfg
  --- /dev/null 2008-01-02 17:55:00 +0100
  +++ integrity.cfg     2008-01-02 17:57:37 +0100
  @@ -0,0 +1,25 @@
  +-----BEGIN PGP SIGNED MESSAGE-----
  +Hash: SHA1
  +
  +Id:       TRIVIAL
  +Name:     Trivial Integrity Configuration Specification
  +Version:  0.0.0
  +Issued:   2008-01-01
  +Issuer:   [EMAIL PROTECTED]
  +
  +Description:
  +    This is a trivial Integrity Configuration Specification which does
  +    nothing but to show the basic syntax of the the key/value pairs and
  +    contain a single environment constraint based on package names.
  +
  +Package:
  +    install:^(rpm|gpg-pubkey)$
  +    (build|rebuild|recompile|tarbuild):!^(foo|bar|quux)$
  +
  +-----BEGIN PGP SIGNATURE-----
  +Version: GnuPG v2.0.8 (OpenPKG-CURRENT)
  +
  +iEYEARECAAYFAkd7wjQACgkQ0mcr4lELuksBDQCg8LuAQXmvxy9HgI5B1FmAuw23
  +HkcAnj8m04N2AAGEwijWtXaUchq/bJOd
  +=WKYF
  +-----END PGP SIGNATURE-----
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/scripts/integrity.fp
  ============================================================================
  $ cvs diff -u -r0 -r1.1 integrity.fp
  --- /dev/null 2008-01-02 17:55:00 +0100
  +++ integrity.fp      2008-01-02 17:57:37 +0100
  @@ -0,0 +1 @@
  +A53B9DDD6C1446636CCC9E3BD2672BE2510BBA4B
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/scripts/integrity.lua
  ============================================================================
  $ cvs diff -u -r0 -r1.1 integrity.lua
  --- /dev/null 2008-01-02 17:55:00 +0100
  +++ integrity.lua     2008-01-02 17:57:37 +0100
  @@ -0,0 +1,65 @@
  +-----BEGIN PGP SIGNED MESSAGE-----
  +Hash: SHA1
  +
  +integrity.version = "0.9.0"
  +
  +function integrity.validate(ctx, cfg)
  +    --  display configuration specification information
  +    if rpm.verbose() then
  +        io.stderr:write("rpm: integrity.validate: ctx.rpm.name = \""    .. 
ctx.rpm.name    .. "\"\n")
  +        io.stderr:write("rpm: integrity.validate: ctx.rpm.mode = \""    .. 
ctx.rpm.mode    .. "\"\n")
  +        io.stderr:write("rpm: integrity.validate: cfg.Id = \""          .. 
cfg.Id          .. "\"\n")
  +        io.stderr:write("rpm: integrity.validate: cfg.Name = \""        .. 
cfg.Name        .. "\"\n")
  +        io.stderr:write("rpm: integrity.validate: cfg.Version = \""     .. 
cfg.Version     .. "\"\n")
  +        io.stderr:write("rpm: integrity.validate: cfg.Issued = \""      .. 
cfg.Issued      .. "\"\n")
  +        io.stderr:write("rpm: integrity.validate: cfg.Issuer = \""      .. 
cfg.Issuer      .. "\"\n")
  +        io.stderr:write("rpm: integrity.validate: cfg.Description = \"" .. 
cfg.Description .. "\"\n")
  +        io.stderr:write("rpm: integrity.validate: cfg.Package = \""     .. 
cfg.Package     .. "\"\n")
  +    end
  +
  +    --  process "Package" constraints
  +    if cfg.Package ~= nil then
  +        --  query RPMDB for names of all installed packages
  +        local packages = rpm.query("%{NAME}", true, "*")
  +        --  iterate over all constraints
  +        for _, constraint in ipairs(util.rsplit(util.rsubst(cfg.Package, 
"(?s)^\\s*(.+?)\\s*$", "$1"), "(?s)\\s+")) do
  +            --  parse constraint
  +            local s, _, m = util.rmatch(constraint, 
"(?s)^(!?)([^:]+):(!?)(.+)$")
  +            if s == nil then
  +                return "ERROR: Invalid syntax in \"Package\" constraint: \"" 
.. constraint .. "\"."
  +            end
  +            local mode_negate    = m[1] ~= ""
  +            local mode_regex     = m[2]
  +            local package_negate = m[3] ~= ""
  +            local package_regex  = m[4]
  +            --  apply the mode filter
  +            local mode_matches, _, _ = util.rmatch(ctx.rpm.mode, mode_regex);
  +            if     (not mode_negate and mode_matches ~= nil)
  +                or (    mode_negate and mode_matches == nil) then
  +                --  apply the package filter to names of all installed 
packages
  +                for _, package in ipairs(packages) do
  +                    local package_matches, _, _ = util.rmatch(package, 
package_regex)
  +                    if  not (   (not package_negate and package_matches ~= 
nil)
  +                             or (    package_negate and package_matches == 
nil)) then
  +                        --  indicate integrity validation error
  +                        return
  +                            "ERROR: Installed package \"" .. package .. "\" 
" ..
  +                            "not covered by \"Package\" constraint \"" .. 
package_regex .. "\" " ..
  +                            "under RPM mode \"" .. ctx.rpm.mode .. "\""
  +                    end
  +                end
  +            end
  +        end
  +    end
  +
  +    --  indicate integrity validation success
  +    return "OK"
  +end
  +
  +-----BEGIN PGP SIGNATURE-----
  +Version: GnuPG v2.0.8 (OpenPKG-CURRENT)
  +
  +iEYEARECAAYFAkd7wjQACgkQ0mcr4lELukvhbQCfZjAV4Ut2fUr+TjQaxorJWgzi
  +mDgAnjwALDwR5rFVf07HJXGkg1Q+mxQE
  +=bwnz
  +-----END PGP SIGNATURE-----
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/scripts/integrity.pgp
  ============================================================================
  $ cvs diff -u -r0 -r1.1 integrity.pgp
  --- /dev/null 2008-01-02 17:55:00 +0100
  +++ integrity.pgp     2008-01-02 17:57:37 +0100
  @@ -0,0 +1,17 @@
  +-----BEGIN PGP PUBLIC KEY BLOCK-----
  +Version: GnuPG v2.0.8 (OpenPKG-CURRENT)
  +
  +mQGiBEd7wjQRBACcZkFtmSEDdnI/sTqQ7r0d5/kAKIT7HkJQ3FaD04C3RBfL7xfW
  +ULTmszDO1UWU3ApaVPtFH6PedZ9OPh3saP7Yl6UZ50p63SIP945fVvtkw8gr8uQ8
  +7GSc2CjlJ+WisGn4y/Lxv9x/vo9mReyAVN9o0qer6nHOxHZ027lgWB5mnwCg/AOe
  +8V6Xk/iC7qfsNS0vsV234ysD/0G/P3e+jKKVPAokILt7HETK/TGToMC0v18pa0OJ
  +9XGF4kf0PDoSdbemPHVStSM2KBBMCp5I1Hh5FTcbEvt++U1m1wG+G9gy1yu0uxKw
  +AsQMH98ljVc0jybjjC2nKJu+Jz2DhX/QqdL1RYStUjZKFvGFoucFu4Nh1TKZ20Gr
  +3fUeA/0ezN89QlvUzxFWMjTTYlqlUdqnzS1Ao1kDhFaVRz6/5pjwfgbesZv4oAe/
  +BVL6TP1stP74DSyifQb+266dnMXENStoRLgBlq1dkdnjYgB8RX0jijxjHKm0Ii46
  +Mm+8dyyHqIbQ3yOPHS0fCYGCHX0xeHbiriyaNtx+2wY586V2c7Q1SW50ZWdyaXR5
  +LUF1dGhvcml0eSA8aW50ZWdyaXR5LWF1dGhvcml0eUBleGFtcGxlLmNvbT6IYAQT
  +EQIAIAUCR3vCNAIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJENJnK+JRC7pL
  +TWcAoN3mM5tlb7LV9gWFMEbywaNSh8jvAKDEzrxZYvEQIDIpF3K2dueeZ+SkRQ==
  +=qLx+
  +-----END PGP PUBLIC KEY BLOCK-----
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/scripts/integrity.sh
  ============================================================================
  $ cvs diff -u -r0 -r1.1 integrity.sh
  --- /dev/null 2008-01-02 17:55:00 +0100
  +++ integrity.sh      2008-01-02 17:57:37 +0100
  @@ -0,0 +1,59 @@
  +#!/bin/sh -x
  +
  +#   preparation
  +GNUPGHOME="`pwd`/.integrity"
  +export GNUPGHOME
  +if [ ! -d $GNUPGHOME ]; then
  +    mkdir $GNUPGHOME
  +    chmod 700 $GNUPGHOME
  +fi
  +
  +#   set name of signer
  +integrity_signer_name="Integrity-Authority"
  +integrity_signer_mail="[EMAIL PROTECTED]"
  +
  +#   generate signing key pair
  +gpg --quiet --gen-key --batch <<EOT
  +Key-Type:     DSA
  +Key-Length:   1024
  +Key-Usage:    sign
  +Name-Real:    $integrity_signer_name
  +Name-Email:   $integrity_signer_mail
  +%commit
  +EOT
  +
  +#   (re-)clearsign the integrity specification and processor   
  +clearsign () {
  +    perl -e '
  +        my $txt; { local $/; $txt = <STDIN>; }
  +        $txt =~ s/
  +            ^
  +            \s*
  +            -----BEGIN\s+PGP\s+SIGNED\s+MESSAGE-----
  +            .*?
  +            \r?\n
  +            \r?\n
  +            (.+?\r?\n)
  +            -----BEGIN\s+PGP\s+SIGNATURE-----\r?\n
  +            .*
  +            $
  +        /$1/xs;
  +        print $txt;
  +    ' <$1 >$1.tmp && \
  +    gpg --quiet --batch --clearsign --output - $1.tmp >$1
  +    rm -f $1.tmp
  +}
  +clearsign integrity.cfg
  +clearsign integrity.lua
  +
  +#   export signing public key
  +gpg --quiet --export --armor "$integrity_signer_name" >integrity.pgp
  +
  +#   determine signing key fingerprint
  +gpg --quiet --fingerprint "Integrity-Authority" 2>&1 |\
  +    grep "Key fingerprint" | sed -e 's;.*Key fingerprint = ;;' -e 
's;[^A-Z0-9];;g' \
  +    >integrity.fp
  +
  +#   cleanup
  +rm -rf $GNUPGHOME
  +
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/scripts/integrity.txt
  ============================================================================
  $ cvs diff -u -r0 -r1.1 integrity.txt
  --- /dev/null 2008-01-02 17:55:00 +0100
  +++ integrity.txt     2008-01-02 17:57:37 +0100
  @@ -0,0 +1,150 @@
  +
  +  RPM Integrity Checking Framework
  +  ================================
  +
  +  Author:   Ralf S. Engelschall <[EMAIL PROTECTED]>
  +  Created:  2007-12-30
  +  Modified: 2008-01-02
  +
  +  Background
  +  ----------
  +
  +  If a software installation is RPM based, RPM plays the role of the
  +  central management tool. Hence installation integrity checking should
  +  be wired directly into RPM.
  +
  +  The valid "integrity" of a software installation can be defined
  +  arbitrarily. It can mean that all installation files are untouched
  +  (still match a particular checksum or message digest), it can mean
  +  that a valid run-time license is installed (which was signed by the
  +  trusted license issuer), it can mean that the underlying system is
  +  operating in a particular mode or in a particular network environment,
  +  etc.
  +
  +  Approach
  +  --------
  +
  +  As it is not possible for a generic tool like RPM to cover all
  +  possibilities, RPM provides just the "framework" for hooking arbitrary
  +  integrity checks into its operation. For flexibility the integrity
  +  checking is split into the following four technological parts:
  +
  +  1. Declarative   Integrity Configuration Specification  (.cfg)
  +  2. Programmatic  Integrity Validation    Processor      (.lua)
  +  3. Cryptographic Integrity Authority     Public-Key     (.pgp)
  +  4. Cryptographic Integrity Authority     Fingerprint    (.fp)
  +
  +  In detail these are:
  +
  +  1. Declarative Integrity Configuration Specification (.cfg)
  +     --------------------------------------------------------
  +
  +     This is a static and declarative specification of the integrity
  +     configuration. It is a text file consisting of key/value pairs
  +     matching the following regular expression:
  +
  +     ([A-Za-z0-9][A-Za-z0-9-]*):[ \t]*([^\r\n]*(?:\r?\n
  +     [ \t]+[^\r\n]+)*)\r?\n
  +
  +     Examples are key/value pairs are "Foo: Bar\n" or "Foo: Bar\n Baz\n
  +     Quux\n". The integrity configuration usually is individually issued
  +     for a particular software installation or a class of similar
  +     software installations. The supported and required key/value pairs
  +     depend entirely on the particular Integrity Validation Processor.
  +
  +     The file has to be PGP "clear-signed" by the Integrity Authority.
  +
  +  2. Programmatic Integrity Validation Processor (.lua)
  +     --------------------------------------------------
  +
  +     This is a dynamic and programmatic integrity validation processor.
  +     It is a Lua script file consisting of at least a definition of
  +     the Lua string variable "integrity.version" and the Lua function
  +     "integrity.validate(ctx, spec)". The minimum valid Lua script is:
  +
  +         integrity.version = "0"
  +         function integrity.validate(ctx, spec)
  +             return "OK"
  +         end
  +
  +     The integrity validation processor usually is generic and reusable
  +     across a larger set of integrity configuration specifications. It
  +     is also implemented outside the RPM scope as its implementation
  +     can be arbitrary and RPM independent. It is dynamically loaded and
  +     executed under RPM run-time.
  +
  +     The file has to be PGP "clear-signed" by the Integrity Authority.
  +
  +  3. Cryptographic Integrity Authority Public-Key (.pgp)
  +     ---------------------------------------------------
  +
  +     This is the OpenPGP public key of the integrity authority, a
  +     party which is trusted by RPM to issue Integrity Configuraton
  +     Specifications and Integrity Validation Processors. RPM uses this
  +     file to cryptographically check the integrity of the Integrity
  +     Configuraton Specification and Integrity Validation Processor. For
  +     flexibility reasons it is also kept outside of RPM.
  +
  +  4. Cryptographic Integrity Authority Fingerprint (.fp)
  +     ---------------------------------------------------
  +
  +     This is the fingerprint (usually MD5 or SHA-1 message digest) of
  +     the OpenPGP public key of the Integrity Authority Public-Key. It is
  +     hard-coded into RPM during the build-time of RPM. It is the root of
  +     the integrity trust chain.
  +
  +  Implementation
  +  --------------
  +
  +  The current implementation for RPM 5 is as following:
  +
  +  -  RPM is built with the fixed/hard-coded Integrity Authority
  +     Fingerprint in the C preprocessor variable RPM_INTEGRITY_FP.
  +     Additionally, it is built with the fixed/hard-coded minimum version
  +     of the Integrity Validation Processor in the C preprocessor
  +     variable RPM_INTEGRITY_MV.
  +
  +  -  The paths to the external files are configured via RPM macros:
  +     %{_integrity_spec_cfg}: Declarative Integrity Configuration 
Specification
  +     %{_integrity_proc_lua}: Programmatic Integrity Validation Processor
  +     %{_integrity_pkey_pgp}: Cryptographic Integrity Authority Public-Key
  +
  +  -  RPM during run-time always runs the integrity checking via:
  +
  +     1. ensuring that %{_integrity_spec_cfg} is valid by checking
  +        that it was signed by the %{_integrity_pkey_pgp}
  +        and that %{_integrity_pkey_pgp} has the fingerprint
  +        RPM_INTEGRITY_FP.
  +
  +     2. ensuring that %{_integrity_proc_lua} is valid by checking
  +        that it was signed by the %{_integrity_pkey_pgp}
  +        and that %{_integrity_pkey_pgp} has the fingerprint
  +        RPM_INTEGRITY_FP.
  +
  +     3. extracting the declarative key/value pairs from
  +        the file %{_integrity_spec_cfg} as a Lua table "spec"
  +
  +     4. extracting the Lua function integrity.validate(ctx, spec)
  +        from the file %{_integrity_proc_lua}
  +
  +     5. assembling at least the RPM program name and run-time mode
  +        into the Lua table "ctx" as "ctx.rpm.name" and "ctx.rpm.mode".
  +
  +     6. executing the Lua function integrity.validate(ctx, spec)
  +
  +  -  The purpose of the integrity.validate(ctx, spec) function
  +     is to validate the current run-time environment against the
  +     integrity configuration specification. It can return:
  +
  +     - "OK" to indicate that RPM should silently continue
  +       with its regular processing.
  +
  +     - "WARNING[: ...]" to indicate a detected non-fatal anomaly in the
  +       environment. RPM will print the warning, wait a few seconds and
  +       then still contunue with its regular processing.
  +
  +     - "ERROR[: ...]" to indicate a detected fatal anomaly in the
  +       environment. RPM will print the error, wait a few seconds and
  +       then stop the regular processing immediately and exit with the
  +       special process return code 42.
  +
  @@ .
______________________________________________________________________
RPM Package Manager                                    http://rpm5.org
CVS Sources Repository                                rpm-cvs@rpm5.org

Reply via email to