Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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.")
Beispiel #4
0
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
Beispiel #5
0
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
Beispiel #6
0
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