Daniel Holth avatar Daniel Holth committed 87168b3

first try at WheelFile.verify() (signatures)

Comments (0)

Files changed (1)

 import zipfile
 import hmac
 import hashlib
+import csv
 from email.parser import Parser
 
 from wheel.decorator import reify
-from wheel.util import urlsafe_b64encode, utf8, to_json
+from wheel.util import urlsafe_b64encode, utf8, to_json, from_json
+from wheel import signatures
 
 # The next major version after this version of the 'wheel' tool:
 VERSION_TOO_HIGH = (1, 0)
         sig = self.sign_hs256(key)
         self.zipfile.writestr('/'.join((self.distinfo_name, 'RECORD.jws')),
                               sig)
+        
+    def verify(self):
+        """Verify the wheel file by verifying the signature and every hash
+        in RECORD."""
+        record = self.zipfile.read('/'.join((self.distinfo_name, 'RECORD')))
+        reader = csv.reader(record.splitlines())
+        for row in reader:
+            filename = row[0]
+            hash = row[1]
+            if not hash:
+                sys.stderr.write("%s has no hash!\n" % filename)
+                continue
+            zf = self.zipfile.open(filename, 'r')
+            sha256 = hashlib.sha256()
+            chunk = zf.read(1<<20)
+            while chunk:
+                sha256.update(chunk)
+                chunk = zf.read(1<<20)
+            expected = "sha256=%s" % urlsafe_b64encode(sha256.digest())
+            if hash != expected:
+                raise ValueError("Bad hash in RECORD for %s" % (filename,))
+            sys.stdout.write("%s %s %s\n" % (filename, hash, expected))
+        record_digest = urlsafe_b64encode(hashlib.sha256(record).digest())
+        sig = from_json(self.zipfile.read('/'.join((self.distinfo_name, 'RECORD.jws'))))
+        headers, payload = signatures.verify(sig)
+        if payload['hash'] != "sha256=" + record_digest:
+            raise ValueError("Claimed RECORD hash != computed hash.")
 
     def sign_hs256(self, key):
         record = self.zipfile.read('/'.join((self.distinfo_name, 'RECORD')))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.