diff --git a/.fmf/version b/.fmf/version new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/.fmf/version @@ -0,0 +1 @@ +1 diff --git a/README.md b/README.md deleted file mode 100644 index d04ca61..0000000 --- a/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# gpgverify - -The gpgverify package diff --git a/gating.yaml b/gating.yaml new file mode 100644 index 0000000..0bd5927 --- /dev/null +++ b/gating.yaml @@ -0,0 +1,14 @@ +--- !Policy +product_versions: + - fedora-* +decision_context: bodhi_update_push_testing +subject_type: koji_build +rules: + - !PassingTestCaseRule {test_case_name: fedora-ci.koji-build.tier0.functional} +--- !Policy +product_versions: + - fedora-* +decision_context: bodhi_update_push_stable +subject_type: koji_build +rules: + - !PassingTestCaseRule {test_case_name: fedora-ci.koji-build.tier0.functional} diff --git a/gpgverify b/gpgverify new file mode 100755 index 0000000..def86ef --- /dev/null +++ b/gpgverify @@ -0,0 +1,193 @@ +#!/bin/bash + +# Copyright 2018 – 2024 B. Persson, Bjorn@Rombobeorn.se +# +# This material is provided as is, with absolutely no warranty expressed +# or implied. Any use is at your own risk. +# +# Permission is hereby granted to use or copy this program +# for any purpose, provided the above notices are retained on all copies. +# Permission to modify the code and to distribute modified code is granted, +# provided the above notices are retained, and a notice that the code was +# modified is included with the above copyright notice. + + +function print_help { + cat <<'EOF' +gpgverify is a wrapper around gpgv designed for easy and safe scripting. It +verifies a file against an OpenPGP signature and one or more keyrings. The +keyrings shall together contain all the keys that are trusted to certify the +authenticity of the file, and must not contain any untrusted keys. + +To verify a detached signature, where the signature and the signed data are two +separate files, both --signature and --data must be given: + gpgverify --keyring= --signature= --data= + gpgverify --keyrings ... --signature= --data= + +If the signature is embedded in the signed file, give --data and --output: + gpgverify --keyring= --data= --output= + gpgverify --keyrings ... --data= --output= + +The verified data will be written to the output file. An output file is required +even for a clearsigned text file, because a clearsigned block can be surrounded +by unsigned text. A program that trusts the contents of a clearsigned file after +verifying the signature is vulnerable to spoofing. Only the contents of the +output file can be trusted. + +The differences, compared to invoking gpgv directly, are that gpgverify accepts +keyrings in either ASCII-armored or unarmored form, that it won't accidentally +use a default keyring in addition to the specified ones, and that it insists on +writing an output file if the signature is not detached. + +Parameters: + --keyring= keyring with only trusted keys (can be repeated) + --keyrings Multiple keyrings with only trusted keys follow. + --signature= detached signature to verify + --data= signed file to verify, or data file to verify against + a detached signature + --output= file to write the verified data to when the signature + is embedded in the signed file +EOF +} + + +function fatal_error { + message="$1" # an error message + status=$2 # a number to use as the exit code + echo "gpgverify: $message" >&2 + exit $status +} + + +function parameter_error { + message="$1" # an error message + fatal_error "${message}" 2 +} + + +function require_parameter { + term="$1" # a term for a required parameter + value="$2" # Complain and terminate if this value is empty. + if test -z "${value}" ; then + parameter_error "No ${term} was provided." + fi +} + + +function check_status { + action="$1" # a string that describes the action that was attempted + status=$2 # the exit code of the command + if test $status -ne 0 ; then + fatal_error "$action failed." $status + fi +} + + +# Parse the command line. +keyring_parameters=false +keyrings=() # empty array +signature= +data= +output= +for parameter in "$@" ; do + if [[ "${parameter}" = -* ]] ; then + # This parameter begins with a dash, so it's not part of any list of + # keyrings. + keyring_parameters=false + fi + case "${parameter}" in + (--help) + print_help + exit + ;; + (--keyrings) + # The following parameters will be keyring pathnames until one + # begins with a dash. + keyring_parameters=true + ;; + (--keyring=*) + keyrings+=("${parameter#*=}") + ;; + (--signature=*) + if test -n "${signature}" ; then + # This is a second occurrence of --signature. + parameter_error 'Only one signature at a time can be verified.' + fi + signature="${parameter#*=}" + ;; + (--data=*) + if test -n "${data}" ; then + # This is a second occurrence of --data. + parameter_error 'Only one data file at a time can be verified.' + fi + data="${parameter#*=}" + ;; + (--output=*) + if test -n "${output}" ; then + # This is a second occurrence of --output. + parameter_error 'Only one output file can be written.' + fi + output="${parameter#*=}" + ;; + (*) + if ${keyring_parameters} ; then + keyrings+=("${parameter}") + else + parameter_error "Unknown parameter: \"${parameter}\"" + fi + ;; + esac +done +require_parameter 'keyring' "${keyrings}" +require_parameter 'data file' "${data}" + +# If no detached signature is provided, then the signature is embedded in the +# data file, and there must be an output file to write the verified data to – +# even if the data file is clearsigned. +if test -z "${signature}${output}" ; then + msg='Neither a signature nor an output file was provided. ' + msg+='Trusting a clearsigned file without stripping off unsigned text ' + msg+='makes you vulnerable to spoofing.' + parameter_error "${msg}" +fi + +# Make a temporary working directory. +workdir="$(mktemp --directory)" +check_status 'Making a temporary directory' $? + +# Decode any ASCII armor on the keyrings. +keyring_params=() # empty array +number=1 +for keyring in "${keyrings[@]}" ; do + if grep --quiet '^-----BEGIN PGP PUBLIC KEY BLOCK-----' "${keyring}" ; then + # This looks like an ASCII-armored keyring. + ring="${workdir}/keyring${number}.gpg" + gpg2 --homedir="${workdir}" --yes --output="${ring}" --dearmor \ + "${keyring}" + check_status "Decoding the keyring \"${keyring}\"" $? + ((++number)) + else + # This is not an ASCII-armored keyring. Don't dearmor it, but ensure + # that the pathname contains slashes to prevent GnuPG from looking for + # the file in the wrong place. + ring=`realpath "${keyring}" --canonicalize-existing` + check_status 'Accessing a keyring' $? + fi + keyring_params+=("--keyring=${ring}") +done + +# Verify the signature using the decoded keyrings. +# The signature pathname shall be a single parameter even if it contains +# whitespace, but shall be omitted entirely if it's an empty string. +gpgv2 --homedir="${workdir}" "${keyring_params[@]}" \ + ${output:+"--output=${output}"} ${signature:+"${signature}"} "${data}" +check_status 'Signature verification' $? + +# (--homedir isn't actually necessary. --dearmor processes only the input file, +# and if --keyring is used and contains a slash, then gpgv2 uses only that +# keyring. Thus neither command will look for a default keyring, but --homedir +# makes extra double sure that no default keyring will be touched in case +# another version of GPG works differently.) + +# Clean up. (This is not done in case of an error that may need inspection.) +rm --recursive --force ${workdir} diff --git a/gpgverify.spec b/gpgverify.spec new file mode 100644 index 0000000..9a567a4 --- /dev/null +++ b/gpgverify.spec @@ -0,0 +1,61 @@ +Name: gpgverify +Version: 2.2 +Release: 3%{?dist} +Summary: Signature verifier for easy and safe scripting + +License: Boehm-GC +URL: https://src.fedoraproject.org/rpms/gpgverify +Source: gpgverify +Source: macros.gpgverify.in +Source: license.txt +BuildArch: noarch + +Requires: grep gnupg2 gnupg2-verify + +%description +GPGverify is a wrapper around GnuPG's gpgv. It verifies a file against an +OpenPGP signature and one or more keyrings. Rather than assuming manual use by +a knowledgeable user, GPGverify is designed to be easy to use safely in a +script. It avoids various unsafe ways of using gpgv that could make a script +vulnerable. + +%prep +# Enable use of filenames instead of source numbers. +%setup -c -T +cp --preserve=timestamps %{sources} . + +%conf +# Convey the location of the shellscript to macros.gpgverify. To keep build +# dependencies minimal, do substitution in Bash instead of something like Sed. +macrofile=$(macros.gpgverify + +%install +mkdir --parents %{buildroot}%{rpmmacrodir} %{buildroot}%{_libexecdir} +cp --preserve=timestamps gpgverify %{buildroot}%{_libexecdir}/ +cp macros.gpgverify %{buildroot}%{rpmmacrodir}/ + +%files +%attr(0755,-,-) %{_libexecdir}/gpgverify +%attr(0644,-,-) %{rpmmacrodir}/macros.gpgverify +%license license.txt + +%changelog +* Thu Jul 24 2025 Fedora Release Engineering - 2.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + +* Tue Jul 15 2025 Björn Persson - 2.2-2 +- Adapted the dependencies because the gnupg2 package has been split. + +* Fri Jun 27 2025 Björn Persson - 2.2-1 +- Evaluate _libexecdir at build time, not at run time (reported by Yaakov + Selkowitz). + +* Fri May 09 2025 Björn Persson - 2.1-3 +- Rebuilt to retry the testsuite. + +* Wed May 07 2025 Björn Persson - 2.1-2 +- Added a separate license file. + +* Mon Apr 14 2025 Björn Persson - 2.1-1 +- GPGverify has been split out from redhat-rpm-config. diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..c461e69 --- /dev/null +++ b/license.txt @@ -0,0 +1,12 @@ +Copyright 2018 – 2024 B. Persson, Bjorn@Rombobeorn.se + +This material is provided as is, with absolutely no warranty expressed +or implied. Any use is at your own risk. + +Permission is hereby granted to use or copy this program +for any purpose, provided the above notices are retained on all copies. +Permission to modify the code and to distribute modified code is granted, +provided the above notices are retained, and a notice that the code was +modified is included with the above copyright notice. + +A few files have other copyright holders. diff --git a/macros.gpgverify.in b/macros.gpgverify.in new file mode 100644 index 0000000..20c78e0 --- /dev/null +++ b/macros.gpgverify.in @@ -0,0 +1,30 @@ +# Copyright 2019 Miro Hrončok +# Copyright 2025 Björn Persson, Bjorn@Rombobeorn.se +# +# This material is provided as is, with absolutely no warranty expressed +# or implied. Any use is at your own risk. +# +# Permission is hereby granted to use or copy this program +# for any purpose, provided the above notices are retained on all copies. +# Permission to modify the code and to distribute modified code is granted, +# provided the above notices are retained, and a notice that the code was +# modified is included with the above copyright notice. + + +# gpgverify verifies signed sources. There is documentation in the script. +%gpgverify(k:s:d:) %{lua: +local script = rpm.expand("@libexecdir@/gpgverify ") +local keyring = rpm.expand("%{-k*}") +local signature = rpm.expand("%{-s*}") +local data = rpm.expand("%{-d*}") +print(script) +if keyring ~= "" then + print(rpm.expand("--keyring='%{SOURCE" .. keyring .. "}' ")) +end +if signature ~= "" then + print(rpm.expand("--signature='%{SOURCE" .. signature .. "}' ")) +end +if data ~= "" then + print(rpm.expand("--data='%{SOURCE" .. data .. "}' ")) +end +} diff --git a/sources b/sources new file mode 100644 index 0000000..e69de29 diff --git a/tests/armored/dummy.tar.gz b/tests/armored/dummy.tar.gz new file mode 100644 index 0000000..b05ec65 Binary files /dev/null and b/tests/armored/dummy.tar.gz differ diff --git a/tests/armored/dummy.tar.gz.asc b/tests/armored/dummy.tar.gz.asc new file mode 100644 index 0000000..deb52a5 --- /dev/null +++ b/tests/armored/dummy.tar.gz.asc @@ -0,0 +1,7 @@ +-----BEGIN PGP SIGNATURE----- + +iHUEABYKAB0WIQR9GjJ6xDDwYQebheulmOS1Lv+uEQUCZ4D1CwAKCRClmOS1Lv+u +EWl2AQCrOjyhqoudwwZpec/01Mr71sLaY9ZTiLcMrpPgEAzMLAEA1X1mkbso14nh +gK98UWd+rNV2cKq2S2obVuElQ5KiqQw= +=88Ke +-----END PGP SIGNATURE----- diff --git a/tests/armored/gpgverify-test-armored.spec b/tests/armored/gpgverify-test-armored.spec new file mode 100644 index 0000000..73397c6 --- /dev/null +++ b/tests/armored/gpgverify-test-armored.spec @@ -0,0 +1,21 @@ +Name: gpgverify-test-armored +Version: 1 +Release: 1 +Summary: gpgverify testcase, ASCII-armored files +License: FSFAP +Source1: key.asc +Source2: dummy.tar.gz +Source3: dummy.tar.gz.asc +BuildRequires: gpgverify + +%description +This tests signature verification where the key and the signature are ASCII- +armored. + +%prep +%{gpgverify} --keyring='%{SOURCE1}' --data='%{SOURCE2}' --signature='%{SOURCE3}' +echo 'Execution of prep continues.' + +%changelog +* Fri Jan 10 2025 Björn Persson - 1-1 +- created diff --git a/tests/armored/key.asc b/tests/armored/key.asc new file mode 100644 index 0000000..8536cd1 --- /dev/null +++ b/tests/armored/key.asc @@ -0,0 +1,9 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mDMEZ4DMQxYJKwYBBAHaRw8BAQdAhKAEwrtQ/pllxlghuM7ay7OZgTkLz1aMxu2d +hEN/Tia0CnRlc3Qga2V5IDGIkwQTFgoAOxYhBH0aMnrEMPBhB5uF66WY5LUu/64R +BQJngMxDAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEKWY5LUu/64R +uvABAMqGHRsYw/Vs70axCgENNQ1jJuIKU6x6Sb5F4p5TETqIAP9edVC13EvH03zy +xjbJblfWaNwsA4Z5lTasp7NTKUg0Cw== +=LJAl +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/armored/main.fmf b/tests/armored/main.fmf new file mode 100644 index 0000000..fe5ecb3 --- /dev/null +++ b/tests/armored/main.fmf @@ -0,0 +1 @@ +summary: gpgverify testcase, ASCII-armored files diff --git a/tests/bad-signer/dummy.tar.gz b/tests/bad-signer/dummy.tar.gz new file mode 100644 index 0000000..cb6bde6 Binary files /dev/null and b/tests/bad-signer/dummy.tar.gz differ diff --git a/tests/bad-signer/dummy.tar.gz.sig b/tests/bad-signer/dummy.tar.gz.sig new file mode 100644 index 0000000..6459969 Binary files /dev/null and b/tests/bad-signer/dummy.tar.gz.sig differ diff --git a/tests/bad-signer/gpgverify-test-bad-signer.spec b/tests/bad-signer/gpgverify-test-bad-signer.spec new file mode 100644 index 0000000..75d337e --- /dev/null +++ b/tests/bad-signer/gpgverify-test-bad-signer.spec @@ -0,0 +1,20 @@ +Name: gpgverify-test-bad-signer +Version: 1 +Release: 1 +Summary: gpgverify testcase, bad signer +License: FSFAP +Source1: key.gpg +Source2: dummy.tar.gz +Source3: dummy.tar.gz.sig +BuildRequires: gpgverify + +%description +Building this package shall fail because the signature is made with another key. + +%prep +%{gpgverify} --keyring='%{SOURCE1}' --data='%{SOURCE2}' --signature='%{SOURCE3}' +echo 'Execution of prep continues.' + +%changelog +* Fri Jan 10 2025 Björn Persson - 1-1 +- created diff --git a/tests/bad-signer/key.gpg b/tests/bad-signer/key.gpg new file mode 100644 index 0000000..028ffc9 Binary files /dev/null and b/tests/bad-signer/key.gpg differ diff --git a/tests/bad-signer/main.fmf b/tests/bad-signer/main.fmf new file mode 100644 index 0000000..d74d5da --- /dev/null +++ b/tests/bad-signer/main.fmf @@ -0,0 +1,5 @@ +summary: gpgverify testcase, bad signer + +environment: + test_kind: "negative" + required_output: "gpgverify: Signature verification failed." diff --git a/tests/bad-tarball/dummy.tar.gz b/tests/bad-tarball/dummy.tar.gz new file mode 100644 index 0000000..cb6bde6 Binary files /dev/null and b/tests/bad-tarball/dummy.tar.gz differ diff --git a/tests/bad-tarball/dummy.tar.gz.sig b/tests/bad-tarball/dummy.tar.gz.sig new file mode 100644 index 0000000..3cef4c6 Binary files /dev/null and b/tests/bad-tarball/dummy.tar.gz.sig differ diff --git a/tests/bad-tarball/gpgverify-test-bad-tarball.spec b/tests/bad-tarball/gpgverify-test-bad-tarball.spec new file mode 100644 index 0000000..bf656ea --- /dev/null +++ b/tests/bad-tarball/gpgverify-test-bad-tarball.spec @@ -0,0 +1,21 @@ +Name: gpgverify-test-bad-tarball +Version: 1 +Release: 1 +Summary: gpgverify testcase, bad tarball +License: FSFAP +Source1: key.gpg +Source2: dummy.tar.gz +Source3: dummy.tar.gz.sig +BuildRequires: gpgverify + +%description +Building this package shall fail because the tarball doesn't match the +signature. + +%prep +%{gpgverify} --keyring='%{SOURCE1}' --data='%{SOURCE2}' --signature='%{SOURCE3}' +echo 'Execution of prep continues.' + +%changelog +* Fri Jan 10 2025 Björn Persson - 1-1 +- created diff --git a/tests/bad-tarball/key.gpg b/tests/bad-tarball/key.gpg new file mode 100644 index 0000000..028ffc9 Binary files /dev/null and b/tests/bad-tarball/key.gpg differ diff --git a/tests/bad-tarball/main.fmf b/tests/bad-tarball/main.fmf new file mode 100644 index 0000000..63c196f --- /dev/null +++ b/tests/bad-tarball/main.fmf @@ -0,0 +1,5 @@ +summary: gpgverify testcase, bad tarball + +environment: + test_kind: "negative" + required_output: "gpgverify: Signature verification failed." diff --git a/tests/bad-usage/dummy.txt.asc b/tests/bad-usage/dummy.txt.asc new file mode 100644 index 0000000..29e9344 --- /dev/null +++ b/tests/bad-usage/dummy.txt.asc @@ -0,0 +1,18 @@ +unsigned garbage +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +Copying and distribution of this file, with or without modification, are +permitted in any medium without royalty provided the copyright notice and +this notice are preserved. This file is offered as-is, without any warranty. + +This file represents a clearsigned text file. +-----BEGIN PGP SIGNATURE----- + +iHUEARYKAB0WIQR9GjJ6xDDwYQebheulmOS1Lv+uEQUCZ4D22wAKCRClmOS1Lv+u +Ef/pAP9JuYRLjob/bRWanpPMo7gW0KpE9qE2dbwGHeBfLKi/4QD+MGTlpEZOam1W +AAsUsGu586wv3q9TTGOmITmokrkl7Q4= +=lunw +unsigned garbage +-----END PGP SIGNATURE----- +unsigned garbage diff --git a/tests/bad-usage/gpgverify-test-bad-usage.spec b/tests/bad-usage/gpgverify-test-bad-usage.spec new file mode 100644 index 0000000..4e80fe2 --- /dev/null +++ b/tests/bad-usage/gpgverify-test-bad-usage.spec @@ -0,0 +1,22 @@ +Name: gpgverify-test-bad-usage +Version: 1 +Release: 1 +Summary: gpgverify testcase, insecure clearsigned usage +License: FSFAP +Source1: key.gpg +Source2: dummy.txt.asc +BuildRequires: gpgverify + +%description +Building this package shall fail because it tries to verify a clearsigned text +file in an insecure way. The --output parameter is missing. + +%prep +%{gpgverify} --keyring='%{SOURCE1}' --data='%{SOURCE2}' +echo 'Execution of prep continues.' +# A naive packager would now pass dummy.txt.asc directly to some other program, +# thinking it has been verified, unaware that it contains unsigned parts. + +%changelog +* Sat Jan 11 2025 Björn Persson - 1-1 +- created diff --git a/tests/bad-usage/key.gpg b/tests/bad-usage/key.gpg new file mode 100644 index 0000000..028ffc9 Binary files /dev/null and b/tests/bad-usage/key.gpg differ diff --git a/tests/bad-usage/main.fmf b/tests/bad-usage/main.fmf new file mode 100644 index 0000000..8e5dee5 --- /dev/null +++ b/tests/bad-usage/main.fmf @@ -0,0 +1,5 @@ +summary: gpgverify testcase, insecure clearsigned usage + +environment: + test_kind: "negative" + required_output: "gpgverify: Neither a signature nor an output file was provided." diff --git a/tests/clearsigned/dummy.txt.asc b/tests/clearsigned/dummy.txt.asc new file mode 100644 index 0000000..29e9344 --- /dev/null +++ b/tests/clearsigned/dummy.txt.asc @@ -0,0 +1,18 @@ +unsigned garbage +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +Copying and distribution of this file, with or without modification, are +permitted in any medium without royalty provided the copyright notice and +this notice are preserved. This file is offered as-is, without any warranty. + +This file represents a clearsigned text file. +-----BEGIN PGP SIGNATURE----- + +iHUEARYKAB0WIQR9GjJ6xDDwYQebheulmOS1Lv+uEQUCZ4D22wAKCRClmOS1Lv+u +Ef/pAP9JuYRLjob/bRWanpPMo7gW0KpE9qE2dbwGHeBfLKi/4QD+MGTlpEZOam1W +AAsUsGu586wv3q9TTGOmITmokrkl7Q4= +=lunw +unsigned garbage +-----END PGP SIGNATURE----- +unsigned garbage diff --git a/tests/clearsigned/gpgverify-test-clearsigned.spec b/tests/clearsigned/gpgverify-test-clearsigned.spec new file mode 100644 index 0000000..51768b8 --- /dev/null +++ b/tests/clearsigned/gpgverify-test-clearsigned.spec @@ -0,0 +1,23 @@ +Name: gpgverify-test-clearsigned +Version: 1 +Release: 1 +Summary: gpgverify testcase, clearsigned text file +License: FSFAP +Source1: key.gpg +Source2: dummy.txt.asc +BuildRequires: gpgverify + +%description +This tests verifying a clearsigned text file. The clearsigned file includes +unsigned parts, which must be excluded from the verified text. + +%prep +%{gpgverify} --keyring='%{SOURCE1}' --data='%{SOURCE2}' --output=verified.txt +echo 'Execution of prep continues.' +# The verified text would now be processed by some other program, such as +# sha512sum. Here it's instead output for inspection by test-rpmbuild. +cat verified.txt + +%changelog +* Sat Jan 11 2025 Björn Persson - 1-1 +- created diff --git a/tests/clearsigned/key.gpg b/tests/clearsigned/key.gpg new file mode 100644 index 0000000..028ffc9 Binary files /dev/null and b/tests/clearsigned/key.gpg differ diff --git a/tests/clearsigned/main.fmf b/tests/clearsigned/main.fmf new file mode 100644 index 0000000..1b0e858 --- /dev/null +++ b/tests/clearsigned/main.fmf @@ -0,0 +1,5 @@ +summary: gpgverify testcase, clearsigned text file + +environment: + required_output: "This file represents a clearsigned text file." + forbidden_output: "garbage" diff --git a/tests/expired/dummy.tar.gz b/tests/expired/dummy.tar.gz new file mode 100644 index 0000000..b05ec65 Binary files /dev/null and b/tests/expired/dummy.tar.gz differ diff --git a/tests/expired/dummy.tar.gz.sig b/tests/expired/dummy.tar.gz.sig new file mode 100644 index 0000000..06fc4e7 Binary files /dev/null and b/tests/expired/dummy.tar.gz.sig differ diff --git a/tests/expired/gpgverify-test-expired.spec b/tests/expired/gpgverify-test-expired.spec new file mode 100644 index 0000000..bc12a47 --- /dev/null +++ b/tests/expired/gpgverify-test-expired.spec @@ -0,0 +1,21 @@ +Name: gpgverify-test-expired +Version: 1 +Release: 1 +Summary: gpgverify testcase, expired key +License: FSFAP +Source1: key.gpg +Source2: dummy.tar.gz +Source3: dummy.tar.gz.sig +BuildRequires: gpgverify + +%description +This tests signature verification with an expired key. Rebuilds shall not fail +just because the clock has ticked past an arbitrary date. + +%prep +%{gpgverify} --keyring='%{SOURCE1}' --data='%{SOURCE2}' --signature='%{SOURCE3}' +echo 'Execution of prep continues.' + +%changelog +* Fri Jan 10 2025 Björn Persson - 1-1 +- created diff --git a/tests/expired/key.gpg b/tests/expired/key.gpg new file mode 100644 index 0000000..84cdcd6 Binary files /dev/null and b/tests/expired/key.gpg differ diff --git a/tests/expired/main.fmf b/tests/expired/main.fmf new file mode 100644 index 0000000..1891149 --- /dev/null +++ b/tests/expired/main.fmf @@ -0,0 +1 @@ +summary: gpgverify testcase, expired key diff --git a/tests/invalid-keyring/dummy.tar.gz b/tests/invalid-keyring/dummy.tar.gz new file mode 100644 index 0000000..b05ec65 Binary files /dev/null and b/tests/invalid-keyring/dummy.tar.gz differ diff --git a/tests/invalid-keyring/dummy.tar.gz.sig b/tests/invalid-keyring/dummy.tar.gz.sig new file mode 100644 index 0000000..3cef4c6 Binary files /dev/null and b/tests/invalid-keyring/dummy.tar.gz.sig differ diff --git a/tests/invalid-keyring/gpgverify-test-invalid-keyring.spec b/tests/invalid-keyring/gpgverify-test-invalid-keyring.spec new file mode 100644 index 0000000..fb8d653 --- /dev/null +++ b/tests/invalid-keyring/gpgverify-test-invalid-keyring.spec @@ -0,0 +1,20 @@ +Name: gpgverify-test-invalid-keyring +Version: 1 +Release: 1 +Summary: gpgverify testcase, invalid keyring +License: FSFAP +Source1: key.gpg +Source2: dummy.tar.gz +Source3: dummy.tar.gz.sig +BuildRequires: gpgverify + +%description +Building this package shall fail because the keyring is invalid. + +%prep +%{gpgverify} --keyring='%{SOURCE1}' --data='%{SOURCE2}' --signature='%{SOURCE3}' +echo 'Execution of prep continues.' + +%changelog +* Fri Jan 10 2025 Björn Persson - 1-1 +- created diff --git a/tests/invalid-keyring/key.gpg b/tests/invalid-keyring/key.gpg new file mode 100644 index 0000000..1cceb77 Binary files /dev/null and b/tests/invalid-keyring/key.gpg differ diff --git a/tests/invalid-keyring/main.fmf b/tests/invalid-keyring/main.fmf new file mode 100644 index 0000000..1cdb098 --- /dev/null +++ b/tests/invalid-keyring/main.fmf @@ -0,0 +1,5 @@ +summary: gpgverify testcase, invalid keyring + +environment: + test_kind: "negative" + required_output: "gpgverify: Signature verification failed." diff --git a/tests/invalid-parameter/dummy.tar.gz b/tests/invalid-parameter/dummy.tar.gz new file mode 100644 index 0000000..cb6bde6 Binary files /dev/null and b/tests/invalid-parameter/dummy.tar.gz differ diff --git a/tests/invalid-parameter/dummy.tar.gz.sig b/tests/invalid-parameter/dummy.tar.gz.sig new file mode 100644 index 0000000..3cef4c6 Binary files /dev/null and b/tests/invalid-parameter/dummy.tar.gz.sig differ diff --git a/tests/invalid-parameter/gpgverify-test-invalid-parameter.spec b/tests/invalid-parameter/gpgverify-test-invalid-parameter.spec new file mode 100644 index 0000000..5c343b5 --- /dev/null +++ b/tests/invalid-parameter/gpgverify-test-invalid-parameter.spec @@ -0,0 +1,23 @@ +Name: gpgverify-test-invalid-parameter +Version: 1 +Release: 1 +Summary: gpgverify testcase, invalid parameter +License: FSFAP +Source1: key.gpg +Source2: dummy.tar.gz +Source3: dummy.tar.gz.sig +BuildRequires: gpgverify + +%description +Building this package shall fail because "0" is invalid as a parameter to +gpgverify. This checks that gpgverify does not have the vulnerability that an +attacker tried to inject in this merge request: +https://src.fedoraproject.org/rpms/redhat-rpm-config/pull-request/84 + +%prep +%{gpgverify} --keyring='%{SOURCE1}' --data='%{SOURCE2}' --signature='%{SOURCE3}' 0 +echo 'Execution of prep continues.' + +%changelog +* Thu Jan 23 2025 Björn Persson - 1-1 +- created diff --git a/tests/invalid-parameter/key.gpg b/tests/invalid-parameter/key.gpg new file mode 100644 index 0000000..028ffc9 Binary files /dev/null and b/tests/invalid-parameter/key.gpg differ diff --git a/tests/invalid-parameter/main.fmf b/tests/invalid-parameter/main.fmf new file mode 100644 index 0000000..572d8fe --- /dev/null +++ b/tests/invalid-parameter/main.fmf @@ -0,0 +1,5 @@ +summary: gpgverify testcase, invalid parameter + +environment: + test_kind: "negative" + required_output: "gpgverify: Unknown parameter: \"0\"" diff --git a/tests/invalid-signature/dummy.tar.gz b/tests/invalid-signature/dummy.tar.gz new file mode 100644 index 0000000..b05ec65 Binary files /dev/null and b/tests/invalid-signature/dummy.tar.gz differ diff --git a/tests/invalid-signature/dummy.tar.gz.sig b/tests/invalid-signature/dummy.tar.gz.sig new file mode 100644 index 0000000..72dc39d Binary files /dev/null and b/tests/invalid-signature/dummy.tar.gz.sig differ diff --git a/tests/invalid-signature/gpgverify-test-invalid-signature.spec b/tests/invalid-signature/gpgverify-test-invalid-signature.spec new file mode 100644 index 0000000..21cb09a --- /dev/null +++ b/tests/invalid-signature/gpgverify-test-invalid-signature.spec @@ -0,0 +1,20 @@ +Name: gpgverify-test-invalid-signature +Version: 1 +Release: 1 +Summary: gpgverify testcase, invalid signature +License: FSFAP +Source1: key.gpg +Source2: dummy.tar.gz +Source3: dummy.tar.gz.sig +BuildRequires: gpgverify + +%description +Building this package shall fail because the signature is invalid. + +%prep +%{gpgverify} --keyring='%{SOURCE1}' --data='%{SOURCE2}' --signature='%{SOURCE3}' +echo 'Execution of prep continues.' + +%changelog +* Fri Jan 10 2025 Björn Persson - 1-1 +- created diff --git a/tests/invalid-signature/key.gpg b/tests/invalid-signature/key.gpg new file mode 100644 index 0000000..028ffc9 Binary files /dev/null and b/tests/invalid-signature/key.gpg differ diff --git a/tests/invalid-signature/main.fmf b/tests/invalid-signature/main.fmf new file mode 100644 index 0000000..a2cd4a8 --- /dev/null +++ b/tests/invalid-signature/main.fmf @@ -0,0 +1,5 @@ +summary: gpgverify testcase, invalid signature + +environment: + test_kind: "negative" + required_output: "gpgverify: Signature verification failed." diff --git a/tests/keybox/dummy.tar.gz b/tests/keybox/dummy.tar.gz new file mode 100644 index 0000000..b05ec65 Binary files /dev/null and b/tests/keybox/dummy.tar.gz differ diff --git a/tests/keybox/dummy.tar.gz.sig b/tests/keybox/dummy.tar.gz.sig new file mode 100644 index 0000000..3cef4c6 Binary files /dev/null and b/tests/keybox/dummy.tar.gz.sig differ diff --git a/tests/keybox/gpgverify-test-keybox.spec b/tests/keybox/gpgverify-test-keybox.spec new file mode 100644 index 0000000..2999c28 --- /dev/null +++ b/tests/keybox/gpgverify-test-keybox.spec @@ -0,0 +1,20 @@ +Name: gpgverify-test-keybox +Version: 1 +Release: 1 +Summary: gpgverify testcase, key in a keybox file +License: FSFAP +Source1: key.kbx +Source2: dummy.tar.gz +Source3: dummy.tar.gz.sig +BuildRequires: gpgverify + +%description +This tests signature verification with a key in the keybox format. + +%prep +%{gpgverify} --keyring='%{SOURCE1}' --data='%{SOURCE2}' --signature='%{SOURCE3}' +echo 'Execution of prep continues.' + +%changelog +* Sun Jan 12 2025 Björn Persson - 1-1 +- created diff --git a/tests/keybox/key.kbx b/tests/keybox/key.kbx new file mode 100644 index 0000000..6e36b12 Binary files /dev/null and b/tests/keybox/key.kbx differ diff --git a/tests/keybox/main.fmf b/tests/keybox/main.fmf new file mode 100644 index 0000000..ec06f69 --- /dev/null +++ b/tests/keybox/main.fmf @@ -0,0 +1 @@ +summary: gpgverify testcase, key in a keybox file diff --git a/tests/main.fmf b/tests/main.fmf new file mode 100644 index 0000000..36fe2ef --- /dev/null +++ b/tests/main.fmf @@ -0,0 +1,11 @@ +# The gpgverify testcases have these data in common. The details that differ +# are in the subdirectories. + +require: + - rpm-build + - gpgverify + - grep + +test: ../test-rpmbuild +# ".." because it's apparently relative to the subdirectory of each testcase, +# not relative to this file. diff --git a/tests/stdin/dummy.tar.gz b/tests/stdin/dummy.tar.gz new file mode 100644 index 0000000..b05ec65 Binary files /dev/null and b/tests/stdin/dummy.tar.gz differ diff --git a/tests/stdin/dummy.tar.gz.sig b/tests/stdin/dummy.tar.gz.sig new file mode 100644 index 0000000..3cef4c6 Binary files /dev/null and b/tests/stdin/dummy.tar.gz.sig differ diff --git a/tests/stdin/gpgverify-test-stdin.spec b/tests/stdin/gpgverify-test-stdin.spec new file mode 100644 index 0000000..42d1b72 --- /dev/null +++ b/tests/stdin/gpgverify-test-stdin.spec @@ -0,0 +1,21 @@ +Name: gpgverify-test-stdin +Version: 1 +Release: 1 +Summary: gpgverify testcase, standard input +License: FSFAP +Source1: key.gpg +Source2: dummy.tar.gz +Source3: dummy.tar.gz.sig +BuildRequires: gpgverify + +%description +This tests gpgverify in a pipeline where the signed data come through the +standard input stream. + +%prep +cat '%{SOURCE2}' | %{gpgverify} --keyring='%{SOURCE1}' --data=- --signature='%{SOURCE3}' +echo 'Execution of prep continues.' + +%changelog +* Fri Jan 10 2025 Björn Persson - 1-1 +- created diff --git a/tests/stdin/key.gpg b/tests/stdin/key.gpg new file mode 100644 index 0000000..028ffc9 Binary files /dev/null and b/tests/stdin/key.gpg differ diff --git a/tests/stdin/main.fmf b/tests/stdin/main.fmf new file mode 100644 index 0000000..3caad15 --- /dev/null +++ b/tests/stdin/main.fmf @@ -0,0 +1 @@ +summary: gpgverify testcase, standard input diff --git a/tests/test-rpmbuild b/tests/test-rpmbuild new file mode 100755 index 0000000..f9673ea --- /dev/null +++ b/tests/test-rpmbuild @@ -0,0 +1,102 @@ +#!/bin/bash + +# Distinguishing between failures and errors isn't possible in all cases, as +# RPMbuild uses exit code 1 for more than one kind of error, but this script +# still tries to make the distinction where possible. + +# Try to run the prep scriptlet of the spec found in the current directory. +# (There is one for each testcase, each in its own directory.) Save a copy of +# the output for inspection. +rpmbuild --define "_sourcedir ${PWD}" -bp *.spec 2>&1 | tee rpmbuild_output +result=${PIPESTATUS[0]} tee_result=${PIPESTATUS[1]} +if test "${test_kind}" = negative ; then + # This is a negative test. Swap the success and failure codes. Leave any + # other value as an error code. + case ${result} in + (0) + echo 'RPMbuild succeeded when it should have failed.' + exit 1 + ;; + (1) + echo 'RPMbuild failed as it should.' + result=0 + ;; + esac +fi +if test ${result} -ne 0 ; then + exit ${result} +fi + +# Any problem with tee is an error in the test. +case ${tee_result} in + (0) + # OK + ;; + (1) + exit 2 # Return error, not failure. + ;; + (*) + exit ${tee_result} + ;; +esac + +# Check whether commands after the signature verification were executed. +grep --quiet --fixed-strings 'Execution of prep continues.' rpmbuild_output +result=$? +case ${result} in + (0) + if test "${test_kind}" != negative ; then + echo 'Execution continued correctly.' + else + echo 'Execution continued when it should have stopped.' + exit 1 + fi + ;; + (1) + if test "${test_kind}" != negative ; then + echo 'Execution stopped when it should have continued.' + exit 1 + else + echo 'Execution stopped correctly.' + fi + ;; + (*) + exit ${result} # error in the test + ;; +esac + +if test -n "${required_output}" ; then + # Look for output that must be present. + grep --quiet --fixed-strings --regexp="${required_output}" rpmbuild_output + result=$? + case ${result} in + (0) + echo "The text \"${required_output}\" was correctly present." + ;; + (1) + echo "The text \"${required_output}\" didn't appear where it should." + exit 1 + ;; + (*) + exit ${result} # error in the test + ;; + esac +fi + +if test -n "${forbidden_output}" ; then + # Look for output that must be absent. + grep --quiet --fixed-strings --regexp="${forbidden_output}" rpmbuild_output + result=$? + case ${result} in + (0) + echo "The text \"${forbidden_output}\" appeared where it shouldn't." + exit 1 + ;; + (1) + echo "The text \"${forbidden_output}\" was correctly absent." + ;; + (*) + exit ${result} # error in the test + ;; + esac +fi diff --git a/tests/two-keys/dummy.tar.gz b/tests/two-keys/dummy.tar.gz new file mode 100644 index 0000000..b05ec65 Binary files /dev/null and b/tests/two-keys/dummy.tar.gz differ diff --git a/tests/two-keys/dummy.tar.gz.sig b/tests/two-keys/dummy.tar.gz.sig new file mode 100644 index 0000000..3cef4c6 Binary files /dev/null and b/tests/two-keys/dummy.tar.gz.sig differ diff --git a/tests/two-keys/gpgverify-test-two-keys.spec b/tests/two-keys/gpgverify-test-two-keys.spec new file mode 100644 index 0000000..06a9c64 --- /dev/null +++ b/tests/two-keys/gpgverify-test-two-keys.spec @@ -0,0 +1,21 @@ +Name: gpgverify-test-two-keys +Version: 1 +Release: 1 +Summary: gpgverify testcase, two separate keyrings +License: FSFAP +Source1: key-1.gpg +Source2: key-2.gpg +Source3: dummy.tar.gz +Source4: dummy.tar.gz.sig +BuildRequires: gpgverify + +%description +This tests passing --keyring to gpgverify more than once. + +%prep +%{gpgverify} --keyring='%{SOURCE1}' --keyring='%{SOURCE2}' --data='%{SOURCE3}' --signature='%{SOURCE4}' +echo 'Execution of prep continues.' + +%changelog +* Sat Jan 11 2025 Björn Persson - 1-1 +- created diff --git a/tests/two-keys/key-1.gpg b/tests/two-keys/key-1.gpg new file mode 100644 index 0000000..028ffc9 Binary files /dev/null and b/tests/two-keys/key-1.gpg differ diff --git a/tests/two-keys/key-2.gpg b/tests/two-keys/key-2.gpg new file mode 100644 index 0000000..a690910 Binary files /dev/null and b/tests/two-keys/key-2.gpg differ diff --git a/tests/two-keys/main.fmf b/tests/two-keys/main.fmf new file mode 100644 index 0000000..34fbe2b --- /dev/null +++ b/tests/two-keys/main.fmf @@ -0,0 +1 @@ +summary: gpgverify testcase, two separate keyrings diff --git a/tests/unarmored/dummy.tar.gz b/tests/unarmored/dummy.tar.gz new file mode 100644 index 0000000..b05ec65 Binary files /dev/null and b/tests/unarmored/dummy.tar.gz differ diff --git a/tests/unarmored/dummy.tar.gz.sig b/tests/unarmored/dummy.tar.gz.sig new file mode 100644 index 0000000..3cef4c6 Binary files /dev/null and b/tests/unarmored/dummy.tar.gz.sig differ diff --git a/tests/unarmored/gpgverify-test-unarmored.spec b/tests/unarmored/gpgverify-test-unarmored.spec new file mode 100644 index 0000000..71f401e --- /dev/null +++ b/tests/unarmored/gpgverify-test-unarmored.spec @@ -0,0 +1,21 @@ +Name: gpgverify-test-unarmored +Version: 1 +Release: 1 +Summary: gpgverify testcase, no ASCII armor +License: FSFAP +Source1: key.gpg +Source2: dummy.tar.gz +Source3: dummy.tar.gz.sig +BuildRequires: gpgverify + +%description +This tests the most basic signature verification. There is no ASCII armor or +other complications. + +%prep +%{gpgverify} --keyring='%{SOURCE1}' --data='%{SOURCE2}' --signature='%{SOURCE3}' +echo 'Execution of prep continues.' + +%changelog +* Fri Jan 10 2025 Björn Persson - 1-1 +- created diff --git a/tests/unarmored/key.gpg b/tests/unarmored/key.gpg new file mode 100644 index 0000000..028ffc9 Binary files /dev/null and b/tests/unarmored/key.gpg differ diff --git a/tests/unarmored/main.fmf b/tests/unarmored/main.fmf new file mode 100644 index 0000000..a805397 --- /dev/null +++ b/tests/unarmored/main.fmf @@ -0,0 +1 @@ +summary: gpgverify testcase, no ASCII armor diff --git a/tests/wildcard/dummy.tar.gz b/tests/wildcard/dummy.tar.gz new file mode 100644 index 0000000..b05ec65 Binary files /dev/null and b/tests/wildcard/dummy.tar.gz differ diff --git a/tests/wildcard/dummy.tar.gz.sig b/tests/wildcard/dummy.tar.gz.sig new file mode 100644 index 0000000..fdfd665 Binary files /dev/null and b/tests/wildcard/dummy.tar.gz.sig differ diff --git a/tests/wildcard/gpgverify-test-wildcard.spec b/tests/wildcard/gpgverify-test-wildcard.spec new file mode 100644 index 0000000..80c44d3 --- /dev/null +++ b/tests/wildcard/gpgverify-test-wildcard.spec @@ -0,0 +1,21 @@ +Name: gpgverify-test-wildcard +Version: 1 +Release: 1 +Summary: gpgverify testcase, listing multiple keyrings +License: FSFAP +Source1: key-1.gpg +Source2: key-2.gpg +Source3: dummy.tar.gz +Source4: dummy.tar.gz.sig +BuildRequires: gpgverify + +%description +This tests passing multiple keyrings to gpgverify through wildcard expansion. + +%prep +%{gpgverify} --keyrings '%{_sourcedir}'/key-* --data='%{SOURCE3}' --signature='%{SOURCE4}' +echo 'Execution of prep continues.' + +%changelog +* Sat Jan 11 2025 Björn Persson - 1-1 +- created diff --git a/tests/wildcard/key-1.gpg b/tests/wildcard/key-1.gpg new file mode 100644 index 0000000..028ffc9 Binary files /dev/null and b/tests/wildcard/key-1.gpg differ diff --git a/tests/wildcard/key-2.gpg b/tests/wildcard/key-2.gpg new file mode 100644 index 0000000..a690910 Binary files /dev/null and b/tests/wildcard/key-2.gpg differ diff --git a/tests/wildcard/main.fmf b/tests/wildcard/main.fmf new file mode 100644 index 0000000..178708c --- /dev/null +++ b/tests/wildcard/main.fmf @@ -0,0 +1 @@ +summary: gpgverify testcase, listing multiple keyrings diff --git a/testsuite.fmf b/testsuite.fmf new file mode 100644 index 0000000..462146d --- /dev/null +++ b/testsuite.fmf @@ -0,0 +1,8 @@ +# Something in the testing machinery demands a "plan", and it must be kept +# separate from the testcases, so here's a file that makes two defaults +# explicit. + +discover: + how: fmf +execute: + how: tmt