[pacman-dev] [PATCH] makepkg: Verify git signatures

Allan McRae allan at archlinux.org
Tue Jan 3 05:22:48 UTC 2017


On 17/12/16 04:56, Eli Schwartz wrote:
> A git repository is marked as signed if it contains the query "signed"
> as defined by https://tools.ietf.org/html/rfc3986
> 
> Adds two utility functions in util/source.sh.in to extract fragments and
> queries, and modifies source/git.sh.in to use them.
> 

Needs documentation added.  e.g. can the query string occur anywhere
relative to the fragment?

> Signed-off-by: Eli Schwartz <eschwartz93 at gmail.com>
> ---
>  .../libmakepkg/integrity/verify_signature.sh.in    | 56 ++++++++++++++++++----
>  scripts/libmakepkg/source/git.sh.in                | 11 ++---
>  scripts/libmakepkg/util/source.sh.in               | 27 +++++++++++
>  3 files changed, 76 insertions(+), 18 deletions(-)
> 
> diff --git a/scripts/libmakepkg/integrity/verify_signature.sh.in b/scripts/libmakepkg/integrity/verify_signature.sh.in
> index 6df62727..634958f9 100644
> --- a/scripts/libmakepkg/integrity/verify_signature.sh.in
> +++ b/scripts/libmakepkg/integrity/verify_signature.sh.in
> @@ -32,11 +32,12 @@ check_pgpsigs() {
>  
>  	msg "$(gettext "Verifying source file signatures with %s...")" "gpg"
>  
> -	local file ext decompress found pubkey success status fingerprint trusted
> +	local netfile file ext decompress found pubkey success status fingerprint trusted
>  	local warning=0
>  	local errors=0
>  	local statusfile=$(mktemp)
>  	local all_sources
> +	local proto dir fragment query fragtype fragval
>  
>  	case $1 in
>  		all)
> @@ -46,15 +47,38 @@ check_pgpsigs() {
>  			get_all_sources_for_arch 'all_sources'
>  			;;
>  	esac
> -	for file in "${all_sources[@]}"; do
> -		file="$(get_filename "$file")"
> -		if [[ $file != *.@(sig?(n)|asc) ]]; then
> +	for netfile in "${all_sources[@]}"; do
> +		file="$(get_filename "$netfile")"
> +		proto="$(get_protocol "$netfile")"
> +		dir=$(get_filepath "$netfile")
> +		fragment=$(get_uri_fragment "$netfile")
> +		query=$(get_uri_query "$netfile")
> +
> +		if [[ $proto = git* && $query = signed ]]; then
> +			case ${fragment%%=*} in
> +				tag)
> +					fragtype=tag
> +					fragval=${fragment##*=}
> +					;;
> +				commit|branch)
> +					fragtype=commit
> +					fragval=${fragment##*=}
> +					;;
> +				'')
> +					fragtype=commit
> +					fragval=HEAD
> +			esac

I'm guessing other modern VCS tools can have signatures verified too?
This function will become a mess when they are included.  Please split
out git and standard file verification to their own functions called
within this one.

> +		elif [[ $file != *.@(sig?(n)|asc) ]]; then
>  			continue
>  		fi
>  
> -		printf "    %s ... " "${file%.*}" >&2
> +		if [[ $proto = git* ]]; then
> +			printf "    %s git repo ... " "${file%.*}" >&2
> +		else
> +			printf "    %s ... " "${file%.*}" >&2
> +		fi
>  
> -		if ! file="$(get_filepath "$file")"; then
> +		if ! file="$(get_filepath "$netfile")"; then
>  			printf '%s\n' "$(gettext "SIGNATURE NOT FOUND")" >&2
>  			errors=1
>  			continue
> @@ -67,7 +91,7 @@ check_pgpsigs() {
>  				break;
>  			fi
>  		done
> -		if (( ! found )); then
> +		if [[ $proto != git* ]] && (( ! found )); then
>  			printf '%s\n' "$(gettext "SOURCE FILE NOT FOUND")" >&2
>  			errors=1
>  			continue
> @@ -83,7 +107,16 @@ check_pgpsigs() {
>  			"")  decompress="cat" ;;
>  		esac
>  
> -		$decompress < "$sourcefile" | gpg --quiet --batch --status-file "$statusfile" --verify "$file" - 2> /dev/null
> +		if [[ $proto = git* ]]; then
> +			git -C "$dir" verify-$fragtype --raw "$fragval" > "$statusfile" 2>&1
> +			if ! grep -qs NEWSIG "$statusfile"; then
> +				printf '%s\n' "$(gettext "SIGNATURE NOT FOUND")" >&2
> +				errors=1
> +				continue
> +			fi
> +		else
> +			$decompress < "$sourcefile" | gpg --quiet --batch --status-file "$statusfile" --verify "$file" - 2> /dev/null
> +		fi
>  		# these variables are assigned values in parse_gpg_statusfile
>  		success=0
>  		status=
> @@ -204,11 +237,14 @@ parse_gpg_statusfile() {
>  }
>  
>  source_has_signatures() {
> -	local file all_sources
> +	local file all_sources proto
>  
>  	get_all_sources_for_arch 'all_sources'
>  	for file in "${all_sources[@]}"; do
> -		if [[ ${file%%::*} = *.@(sig?(n)|asc) ]]; then
> +		proto="$(get_protocol "$file")"
> +		query=$(get_uri_query "$netfile")
> +
> +		if [[ ${file%%::*} = *.@(sig?(n)|asc) || ( $proto = git* && $query = signed ) ]]; then
>  			return 0
>  		fi
>  	done
> diff --git a/scripts/libmakepkg/source/git.sh.in b/scripts/libmakepkg/source/git.sh.in
> index cc27663d..3d370dbd 100644
> --- a/scripts/libmakepkg/source/git.sh.in
> +++ b/scripts/libmakepkg/source/git.sh.in
> @@ -39,6 +39,7 @@ download_git() {
>  	local url=$(get_url "$netfile")
>  	url=${url#git+}
>  	url=${url%%#*}
> +	url=${url%%\?*}
>  
>  	if [[ ! -d "$dir" ]] || dir_is_empty "$dir" ; then
>  		msg2 "$(gettext "Cloning %s %s repo...")" "${repo}" "git"
> @@ -66,14 +67,8 @@ download_git() {
>  extract_git() {
>  	local netfile=$1
>  
> -	local fragment=${netfile#*#}
> -	if [[ $fragment = "$netfile" ]]; then
> -		unset fragment
> -	fi
> -
> -	local repo=${netfile##*/}
> -	repo=${repo%%#*}
> -	repo=${repo%%.git*}
> +	local fragment=$(get_uri_fragment "$netfile")
> +	local repo=$(get_filename "$netfile")
>  
>  	local dir=$(get_filepath "$netfile")
>  	[[ -z "$dir" ]] && dir="$SRCDEST/$(get_filename "$netfile")"
> diff --git a/scripts/libmakepkg/util/source.sh.in b/scripts/libmakepkg/util/source.sh.in
> index 9d4ba4a6..890e92ba 100644
> --- a/scripts/libmakepkg/util/source.sh.in
> +++ b/scripts/libmakepkg/util/source.sh.in
> @@ -65,6 +65,7 @@ get_filename() {
>  	case $proto in
>  		bzr*|git*|hg*|svn*)
>  			filename=${netfile%%#*}
> +			filename=${netfile%%\?*}
>  			filename=${filename%/}
>  			filename=${filename##*/}
>  			if [[ $proto = bzr* ]]; then
> @@ -111,6 +112,32 @@ get_filepath() {
>  	printf "%s\n" "$file"
>  }
>  
> +# extract the VCS revision/branch specifier from a source entry
> +get_uri_fragment() {
> +	local netfile=$1
> +
> +	local fragment=${netfile#*#}
> +	if [[ $fragment = "$netfile" ]]; then
> +		unset fragment
> +	fi
> +	fragment=${fragment%\?*}
> +
> +	printf "%s\n" "$fragment"
> +}
> +
> +# extract the "signed" status of a source entry - defined as a trailing URI data component
> +get_uri_query() {
> +	local netfile=$1
> +
> +	local query=${netfile#*\?}
> +	if [[ $query = "$netfile" ]]; then
> +		unset query
> +	fi
> +	query=${query%#*}
> +
> +	printf "%s\n" "$query"
> +}
> +
>  get_downloadclient() {
>  	local proto=$1
>  
> 


More information about the pacman-dev mailing list