Ticket URL: https://fedorahosted.org/koji/ticket/119


$ diff -u ./koji-1.6.0/hub/kojihub.py /usr/share/koji-hub/kojihub.py 
--- ./koji-1.6.0/hub/kojihub.py 2010-12-16 16:13:17.000000000 -0500
+++ /usr/share/koji-hub/kojihub.py 2011-12-04 20:17:40.460047608 -0500
@@ -51,6 +51,86 @@
 import zipfile
 from koji.context import context
 
+import hashlib
+import struct
+
+def sigsha2(fn, cm=None):
+ # http://www.iagora.com/~espel/rpm2cpio
+
+ nel = 0
+ f = open(fn, "r")
+
+ rpm = f.read(96)
+ if (len(rpm) != 96):
+ #print("error reading lead 96.0")
+ return cm
+ nel += len(rpm)
+
+ # http://perldoc.perl.org/functions/pack.html
+ # http://docs.python.org/library/struct.html
+
+ (magic, major, minor, rest) = struct.unpack(">LBB90s", rpm)
+
+ if (magic != 0xedabeedb):
+ #print("incorrect lead magic")
+ return cm
+
+ if ((major != 3) and (major != 4)):
+ #print("incorrect lead major")
+ return cm
+
+ # http://docs.python.org/library/stdtypes.html
+
+ while (1):
+ pos = nel
+ rpm = f.read(16)
+ if (len(rpm) != 16):
+ #print("error reading header 16.0")
+ return cm
+ nel += len(rpm)
+ (smagic, rest) = struct.unpack(">H14s", rpm)
+ if ((smagic == 0x1f8b) or (smagic == 0x425a) or (smagic == 0xfd37)):
+ break
+ if (pos & 0x7):
+ pos += 7
+ pos &= (~0x7)
+ f.seek(pos, 0)
+ nel = pos
+ rpm = f.read(16)
+ if (len(rpm) != 16):
+ #print("error reading header 16.1")
+ return cm
+ nel += len(rpm)
+ left = (len(rpm) - 16)
+ (magic, data, sections, bytes, rest) = struct.unpack(">4L" + str(left) + "s", rpm)
+ if (magic != 0x8eade801):
+ #print("incorrect header magic")
+ return cm
+ # beg custom
+ f.seek(pos + 16, 0)
+ tmp = f.read((16 * sections) + bytes)
+ head = (rpm + tmp)
+ # end custom
+ pos += 16
+ pos += (16 * sections)
+ pos += bytes
+ f.seek(pos, 0)
+ nel = pos
+
+ while (1):
+ tmp = f.read(16384)
+ if (not tmp):
+ break
+ rpm += tmp
+
+ f.close()
+ md5hex = hashlib.md5(head + rpm).hexdigest()
+
+ if ((cm != None) and (cm != md5hex)):
+ #print("sigmd5 mis-match")
+ return cm
+
+ return hashlib.sha256(head + rpm).hexdigest()
 
 logger = logging.getLogger('koji.hub')
 
@@ -4092,12 +4172,13 @@
             raise koji.GenericError, "srpm mismatch for %s: %s (expected %s)" \
                     % (fn,basename,srpmname)
 
+    hdr_md5 = hdr[rpm.RPMTAG_SIGMD5]
     #add rpminfo entry
     rpminfo['id'] = _singleValue("""SELECT nextval('rpminfo_id_seq')""")
     rpminfo['build'] = buildinfo
     rpminfo['build_id'] = buildinfo['id']
     rpminfo['size'] = os.path.getsize(fn)
-    rpminfo['payloadhash'] = koji.hex_string(hdr[rpm.RPMTAG_SIGMD5])
+    rpminfo['payloadhash'] = sigsha2(fn, koji.hex_string(hdr_md5))
     rpminfo['brootid'] = brootid
 
     koji.plugin.run_callbacks('preImport', type='rpm', rpm=rpminfo, build=buildinfo,
@@ -4539,7 +4620,9 @@
     if not os.path.isdir(builddir):
         raise koji.GenericError, "No such directory: %s" % builddir
     rawhdr = koji.RawHeader(sighdr)
-    sigmd5 = koji.hex_string(rawhdr.get(koji.RPM_SIGTAG_MD5))
+    rpm_path = "%s/%s" % (builddir, koji.pathinfo.rpm(rinfo))
+    hdr_md5 = rawhdr.get(koji.RPM_SIGTAG_MD5)
+    sigmd5 = sigsha2(rpm_path, koji.hex_string(hdr_md5))
     if sigmd5 == rinfo['payloadhash']:
         # note: payloadhash is a misnomer, that field is populated with sigmd5.
         sigkey = rawhdr.get(koji.RPM_SIGTAG_GPG)
@@ -4554,7 +4637,7 @@
         # we need to pull that differently as well
         rpm_path = "%s/%s" % (builddir, koji.pathinfo.rpm(rinfo))
         sigmd5, sigkey = _scan_sighdr(sighdr, rpm_path)
-        sigmd5 = koji.hex_string(sigmd5)
+        sigmd5 = sigsha2(rpm_path, koji.hex_string(sigmd5))
         if sigmd5 != rinfo['payloadhash']:
             nvra = "%(name)s-%(version)s-%(release)s.%(arch)s" % rinfo
             raise koji.GenericError, "wrong md5 for %s: %s" % (nvra, sigmd5)


$ koji list-tagged main-builds nledd
Build                                     Tag                   Built by
----------------------------------------  --------------------  ----------------
nledd-2.52-7.fc15                         main-builds           admin


$ su - koji -c "psql -c \"select name,payloadhash from rpminfo where name LIKE 'nledd%';\""
      name       |                           payloadhash                            
-----------------+------------------------------------------------------------------
 nledd           | a6f6f123dde44e0967e30b016c8a60ad6c32575a4dd4c83ef779b3bdcebf0279
 nledd           | 988e2594303acc3c7a1e15bbf1ca621cd626f21faff24c24365c68551f48af3a
 nledd-debuginfo | d9b6bf6a7d76f4f6cb966f3353f5d48075bd89184fe74e8a32c155dfd9abd402
(3 rows)


# Main Source Code Addition


import hashlib
import struct


def sigsha2(fn, cm=None):
# http://www.iagora.com/~espel/rpm2cpio

nel = 0
f = open(fn, "r")

rpm = f.read(96)
if (len(rpm) != 96):
#print("error reading lead 96.0")
return cm
nel += len(rpm)

# http://perldoc.perl.org/functions/pack.html
# http://docs.python.org/library/struct.html

(magic, major, minor, rest) = struct.unpack(">LBB90s", rpm)

if (magic != 0xedabeedb):
#print("incorrect lead magic")
return cm

if ((major != 3) and (major != 4)):
#print("incorrect lead major")
return cm

# http://docs.python.org/library/stdtypes.html

while (1):
pos = nel
rpm = f.read(16)
if (len(rpm) != 16):
#print("error reading header 16.0")
return cm
nel += len(rpm)
(smagic, rest) = struct.unpack(">H14s", rpm)
if ((smagic == 0x1f8b) or (smagic == 0x425a) or (smagic == 0xfd37)):
break
if (pos & 0x7):
pos += 7
pos &= (~0x7)
f.seek(pos, 0)
nel = pos
rpm = f.read(16)
if (len(rpm) != 16):
#print("error reading header 16.1")
return cm
nel += len(rpm)
left = (len(rpm) - 16)
(magic, data, sections, bytes, rest) = struct.unpack(">4L" + str(left) + "s", rpm)
if (magic != 0x8eade801):
#print("incorrect header magic")
return cm
# beg custom
f.seek(pos + 16, 0)
tmp = f.read((16 * sections) + bytes)
head = (rpm + tmp)
# end custom
pos += 16
pos += (16 * sections)
pos += bytes
f.seek(pos, 0)
nel = pos

while (1):
tmp = f.read(16384)
if (not tmp):
break
rpm += tmp

f.close()
md5hex = hashlib.md5(head + rpm).hexdigest()

if ((cm != None) and (cm != md5hex)):
#print("sigmd5 mis-match")
return cm

return hashlib.sha256(head + rpm).hexdigest()