Rewrite SignatureCheck and add tests
Separate SignatureCheck to functions and add tests. Also, rewrite the logic as SignatureCheck was obsolete and didn't work properly (e.g. it searched for "MISSING KEYS" and "pgp|gpg" strings that are no longer used in 'rpm -K' output). Now it checks the output of 'rpm -Kv' which provides more detailed output. Thanks to that we could add another check ('E: invalid-signature' that checks if the signature is corrupted or not). The test_signature.py file was added so now all 3 signature checks are tested properly.
This commit is contained in:
parent
aa433df1ce
commit
297f09e745
|
@ -1,11 +1,3 @@
|
|||
#############################################################################
|
||||
# File : SignatureCheck.py
|
||||
# Package : rpmlint
|
||||
# Author : Frederic Lepied
|
||||
# Created on : Thu Oct 7 17:06:14 1999
|
||||
# Purpose : check the presence of a PGP signature.
|
||||
#############################################################################
|
||||
|
||||
import re
|
||||
|
||||
from rpmlint.checks.AbstractCheck import AbstractCheck
|
||||
|
@ -13,21 +5,56 @@ from rpmlint.helpers import print_warning
|
|||
|
||||
|
||||
class SignatureCheck(AbstractCheck):
|
||||
pgp_regex = re.compile(r'pgp|gpg', re.IGNORECASE)
|
||||
unknown_key_regex = re.compile(r'\(MISSING KEYS:(?:\([^)]+\))?\s+([^\)]+)\)')
|
||||
"""
|
||||
Checks for PGP signature in the package.
|
||||
|
||||
It checks if the signature is present, known (imported in RPM DB) and
|
||||
valid. It uses 'rpm -Kv' command than returns detailed information about
|
||||
the package digests and signature.
|
||||
"""
|
||||
any_sig_regex = re.compile(r'[Ss]ignature, key ID')
|
||||
nokey_sig_regex = re.compile(r'[Ss]ignature, key ID ([\w\d]*): NOKEY')
|
||||
invalid_sig_regex = re.compile(r'invalid OpenPGP signature')
|
||||
|
||||
def check(self, pkg):
|
||||
res = pkg.checkSignature()
|
||||
if not res or res[0] != 0:
|
||||
if res and res[1]:
|
||||
kres = SignatureCheck.unknown_key_regex.search(res[1])
|
||||
else:
|
||||
kres = None
|
||||
if kres:
|
||||
self.output.add_info('E', pkg, 'unknown-key', kres.group(1))
|
||||
else:
|
||||
print_warning('Error checking signature of %s: %s' %
|
||||
(pkg.filename, res[1]))
|
||||
else:
|
||||
if not SignatureCheck.pgp_regex.search(res[1]):
|
||||
self.output.add_info('E', pkg, 'no-signature')
|
||||
retcode, output = pkg.checkSignature()
|
||||
|
||||
# Skip all signature checks if checkSignature output is empty
|
||||
if output is None:
|
||||
print_warning(f'No output from checkSignature() for '
|
||||
f'{pkg.filename}. Skipping signature checks.')
|
||||
return
|
||||
|
||||
self._check_no_signature(pkg, retcode, output)
|
||||
self._check_unknown_key(pkg, retcode, output)
|
||||
self._check_invalid_signature(pkg, retcode, output)
|
||||
|
||||
def _check_no_signature(self, pkg, retcode, output):
|
||||
"""
|
||||
Check if the package contains a signature.
|
||||
|
||||
Print an error if there is no signature present. That means that
|
||||
there is no mention about any signature in the 'rpm -Kv' output.
|
||||
"""
|
||||
if retcode == 0 and not SignatureCheck.any_sig_regex.search(output):
|
||||
self.output.add_info('E', pkg, 'no-signature')
|
||||
|
||||
def _check_unknown_key(self, pkg, retcode, output):
|
||||
"""
|
||||
Check if the public key is imported in the RPM database.
|
||||
|
||||
Print an error if it's not imported and signature is therefore unknown.
|
||||
"""
|
||||
if retcode == 1:
|
||||
nokey = SignatureCheck.nokey_sig_regex.search(output)
|
||||
if nokey and not SignatureCheck.invalid_sig_regex.search(output):
|
||||
self.output.add_info('E', pkg, 'unknown-key', nokey.group(1))
|
||||
|
||||
def _check_invalid_signature(self, pkg, retcode, output):
|
||||
"""
|
||||
Check if the signature is valid.
|
||||
|
||||
Print an error if the signature is corrupted.
|
||||
"""
|
||||
if retcode == 1 and SignatureCheck.invalid_sig_regex.search(output):
|
||||
self.output.add_info('E', pkg, 'invalid-signature')
|
||||
|
|
|
@ -5,3 +5,6 @@ unknown-key="""
|
|||
The package was signed, but with an unknown key. See the rpm --import option
|
||||
for more information.
|
||||
"""
|
||||
invalid-signature="""
|
||||
The package was signed, but the signature is corrupted.
|
||||
"""
|
||||
|
|
|
@ -476,7 +476,9 @@ class Pkg(AbstractPkg):
|
|||
return dirname
|
||||
|
||||
def checkSignature(self):
|
||||
ret = subprocess.run(('rpm', '-K', self.filename), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=ENGLISH_ENVIROMENT)
|
||||
ret = subprocess.run(('rpm', '-Kv', self.filename),
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
env=ENGLISH_ENVIROMENT)
|
||||
text = ret.stdout.decode()
|
||||
if text.endswith('\n'):
|
||||
text = text[:-1]
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,51 @@
|
|||
import pytest
|
||||
from rpmlint.checks.SignatureCheck import SignatureCheck
|
||||
from rpmlint.filter import Filter
|
||||
|
||||
from Testing import CONFIG, get_tested_package
|
||||
|
||||
|
||||
@pytest.fixture(scope='function', autouse=True)
|
||||
def signaturecheck():
|
||||
CONFIG.info = True
|
||||
output = Filter(CONFIG)
|
||||
test = SignatureCheck(CONFIG, output)
|
||||
return output, test
|
||||
|
||||
|
||||
# The signature was stripped via "rpmsign --delsign <package>"
|
||||
@pytest.mark.parametrize('package', ['binary/no-signature'])
|
||||
def test_no_signature(tmpdir, package, signaturecheck):
|
||||
output, test = signaturecheck
|
||||
test.check(get_tested_package(package, tmpdir))
|
||||
out = output.print_results(output.results)
|
||||
assert 'E: no-signature' in out
|
||||
assert 'E: unknown-key' not in out
|
||||
assert 'E: invalid-signature' not in out
|
||||
|
||||
|
||||
# The test rpm was signed with gpg key created for this purpose that is not
|
||||
# imported in rpm db and therefore unknown-key error should be thrown
|
||||
@pytest.mark.parametrize('package', ['binary/unknown-key'])
|
||||
def test_unknown_key(tmpdir, package, signaturecheck):
|
||||
output, test = signaturecheck
|
||||
test.check(get_tested_package(package, tmpdir))
|
||||
out = output.print_results(output.results)
|
||||
assert 'E: unknown-key 31fdc502' in out
|
||||
assert 'E: no-signature' not in out
|
||||
assert 'E: invalid-signature' not in out
|
||||
|
||||
|
||||
# The test rpm hello-2.0-1.x86_64-signed.rpm was taken from
|
||||
# https://github.com/rpm-software-management/rpm/blob/master/tests/data/RPMS/
|
||||
# and then the signature was corrupted by running "dd if=/dev/zero
|
||||
# of=hello-2.0-1.x86_64-signed.rpm conv=notrunc bs=1 seek=264 count=6
|
||||
# 2> /dev/null"
|
||||
@pytest.mark.parametrize('package', ['binary/hello'])
|
||||
def test_invalid_signature(tmpdir, package, signaturecheck):
|
||||
output, test = signaturecheck
|
||||
test.check(get_tested_package(package, tmpdir))
|
||||
out = output.print_results(output.results)
|
||||
assert 'E: invalid-signature' in out
|
||||
assert 'E: no-signature' not in out
|
||||
assert 'E: unknown-key' not in out
|
Loading…
Reference in New Issue