def get_public_key_from_jar(jar): """ Get the public key and its fingerprint from a JAR file. :raises: VerificationException() if the JAR was not signed exactly once :param jar: a zipfile.ZipFile object :return: the public key from the jar and its fingerprint """ # extract certificate from jar certs = [ n for n in jar.namelist() if common.SIGNATURE_BLOCK_FILE_REGEX.match(n) ] if len(certs) < 1: raise VerificationException( _("Found no signing certificates for repository.")) if len(certs) > 1: raise VerificationException( _("Found multiple signing certificates for repository.")) # extract public key from certificate public_key = common.get_certificate(jar.read(certs[0])) public_key_fingerprint = common.get_cert_fingerprint(public_key).replace( ' ', '') return public_key, public_key_fingerprint
def download_repo_index(url_str, etag=None, verify_fingerprint=True): """ Downloads the repository index from the given :param url_str and verifies the repository's fingerprint if :param verify_fingerprint is not False. :raises: VerificationException() if the repository could not be verified :return: A tuple consisting of: - The index in JSON format or None if the index did not change - The new eTag as returned by the HTTP request """ url = urllib.parse.urlsplit(url_str) fingerprint = None if verify_fingerprint: query = urllib.parse.parse_qs(url.query) if 'fingerprint' not in query: raise VerificationException(_("No fingerprint in URL.")) fingerprint = query['fingerprint'][0] url = urllib.parse.SplitResult(url.scheme, url.netloc, url.path + '/index-v1.jar', '', '') download, new_etag = net.http_get(url.geturl(), etag) if download is None: return None, new_etag with tempfile.NamedTemporaryFile() as fp: # write and open JAR file fp.write(download) jar = zipfile.ZipFile(fp) # verify that the JAR signature is valid logging.debug(_('Verifying index signature:')) common.verify_jar_signature(fp.name) # get public key and its fingerprint from JAR public_key, public_key_fingerprint = get_public_key_from_jar(jar) # compare the fingerprint if verify_fingerprint is True if verify_fingerprint and fingerprint.upper( ) != public_key_fingerprint: raise VerificationException( _("The repository's fingerprint does not match.")) # load repository index from JSON index = json.loads(jar.read('index-v1.json').decode("utf-8")) index["repo"]["pubkey"] = hexlify(public_key).decode("utf-8") index["repo"]["fingerprint"] = public_key_fingerprint # turn the apps into App objects index["apps"] = [metadata.App(app) for app in index["apps"]] return index, new_etag
def verify_jar_signature(file): """ Verifies the signature of a given JAR file. :raises: VerificationException() if the JAR's signature could not be verified """ if not common.verify_apk_signature(file, jar=True): raise VerificationException("The repository's index could not be verified.")
def download_repo_index(url_str, etag=None, verify_fingerprint=True, timeout=600): """Download and verifies index file, then returns its data. Downloads the repository index from the given :param url_str and verifies the repository's fingerprint if :param verify_fingerprint is not False. Raises ------ VerificationException() if the repository could not be verified Returns ------- A tuple consisting of: - The index in JSON format or None if the index did not change - The new eTag as returned by the HTTP request """ url = urllib.parse.urlsplit(url_str) fingerprint = None if verify_fingerprint: query = urllib.parse.parse_qs(url.query) if 'fingerprint' not in query: raise VerificationException(_("No fingerprint in URL.")) fingerprint = query['fingerprint'][0] if url.path.endswith('/index-v1.jar'): path = url.path[:-13].rstrip('/') else: path = url.path.rstrip('/') url = urllib.parse.SplitResult(url.scheme, url.netloc, path + '/index-v1.jar', '', '') download, new_etag = net.http_get(url.geturl(), etag, timeout) if download is None: return None, new_etag with tempfile.NamedTemporaryFile() as fp: fp.write(download) fp.flush() index, public_key, public_key_fingerprint = get_index_from_jar( fp.name, fingerprint) index["repo"]["pubkey"] = hexlify(public_key).decode() index["repo"]["fingerprint"] = public_key_fingerprint index["apps"] = [metadata.App(app) for app in index["apps"]] return index, new_etag
def get_index_from_jar(jarfile, fingerprint=None): """Returns the data, public key, and fingerprint from index-v1.jar :raises: VerificationException() if the repository could not be verified """ logging.debug(_('Verifying index signature:')) common.verify_jar_signature(jarfile) with zipfile.ZipFile(jarfile) as jar: public_key, public_key_fingerprint = get_public_key_from_jar(jar) if fingerprint is not None: if fingerprint.upper() != public_key_fingerprint: raise VerificationException(_("The repository's fingerprint does not match.")) data = json.loads(jar.read('index-v1.json').decode()) return data, public_key, public_key_fingerprint
def get_index_from_jar(jarfile, fingerprint=None): """Returns the data, public key, and fingerprint from index-v1.jar :param fingerprint is the SHA-256 fingerprint of signing key. Only hex digits count, all other chars will can be discarded. :raises: VerificationException() if the repository could not be verified """ logging.debug(_('Verifying index signature:')) common.verify_jar_signature(jarfile) with zipfile.ZipFile(jarfile) as jar: public_key, public_key_fingerprint = get_public_key_from_jar(jar) if fingerprint is not None: fingerprint = re.sub(r'[^0-9A-F]', r'', fingerprint.upper()) if fingerprint != public_key_fingerprint: raise VerificationException( _("The repository's fingerprint does not match.")) data = json.loads(jar.read('index-v1.json').decode()) return data, public_key, public_key_fingerprint