Commits

Daniel Holth committed 1793191

add basic sign/verify of signatures only (doesn't check file contents yet)

  • Participants
  • Parent commits 3aea7d8

Comments (0)

Files changed (3)

wheel/__main__.py

 import ed25519ll
 import sys
 import keyring
+import wheel.install
+import wheel.signatures
+import json
 from .util import urlsafe_b64decode, urlsafe_b64encode
 
 wb = baker.Baker()
         raise Exception("Keyring is broken. Could not retrieve secret key.")
 
 @wb.command()
-def sign():
+def sign(wheelfile):
     """Sign a wheel"""
-    pass
+    import hashlib    
+    wf = wheel.install.WheelFile(wheelfile, append=True)
+    record_name = wf.distinfo_name + '/RECORD'
+    sig_name = wf.distinfo_name + '/RECORD.JWS'
+    if sig_name in wf.zipfile.namelist():
+        raise NotImplementedError("Wheel is already signed")
+    record_data = wf.zipfile.read(record_name)
+    payload = {"hash":"sha256=%s" % urlsafe_b64encode(hashlib.sha256(record_data).digest())}
+    sig = wheel.signatures.sign(payload, ed25519ll.crypto_sign_keypair())
+    wf.zipfile.writestr(sig_name, json.dumps(sig, sort_keys=True))
+    wf.zipfile.close()
+
+@wb.command()
+def verify(wheelfile):
+    """Verify a wheel."""    
+    wf = wheel.install.WheelFile(wheelfile)
+    sig_name = wf.distinfo_name + '/RECORD.JWS'
+    sig = json.loads(wf.zipfile.open(sig_name).read())
+    sys.stdout.write("Signatures are %r" % (wheel.signatures.verify(sig),))
 
 def main():
     wb.run()
     """Parse wheel-specific attributes from a wheel (.whl) file"""
     WHEEL_INFO = "WHEEL"
 
-    def __init__(self, filename):
+    def __init__(self, filename, append=False):
+        """
+        :param append: Open archive in append mode.
+        """
         self.filename = filename
+        self.append = append
         basename = os.path.basename(filename)
         self.parsed_filename = WHEEL_INFO_RE(basename)
         if not basename.endswith('.whl') or self.parsed_filename is None:
 
     @reify
     def zipfile(self):
-        return VerifyingZipFile(self.filename)
+        mode = "r"
+        if self.append:
+            mode = "a"
+        return VerifyingZipFile(self.filename, mode)
 
     def get_metadata(self):
         pass

wheel/signatures.py

     Caller must decide whether the keys are actually trusted."""
     # XXX forbid duplicate keys in JSON input
     encoded_headers = jwsjs["headers"]
-    encoded_payload = jwsjs["payload"]
+    encoded_payload = jwsjs["payload"].encode('latin1')
     encoded_signatures = jwsjs["signatures"]
     headers = []
     for h, s in zip(encoded_headers, encoded_signatures):
+        h = h.encode('latin1')
+        s = s.encode('latin1')
         header = json.loads(urlsafe_b64decode(h))
         assert header["alg"] == "Ed25519"
         assert header["key"]["alg"] == "Ed25519"