Skip to content

Commit

Permalink
parse DIGESTS file and add signature checking for portage snapshots
Browse files Browse the repository at this point in the history
  • Loading branch information
specing committed Mar 28, 2015
1 parent bc12650 commit 8760b2c
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 25 deletions.
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,24 @@ to use your default ($HOME/.gnupg) directory.

mkdir -p /path/to/random/dir
chmod 0700 /path/to/random/dir
# import key (subkeys.pgp.net is flaky)

# import stage3 signing key (subkeys.pgp.net is flaky)
gpg --homedir /path/to/random/dir --keyserver pool.sks-keyservers.net --recv-keys 0xBB572E0E2D182910
# check fingerprint (current: 13EB BDBE DE7A 1277 5DFD B1BA BB57 2E0E 2D18 2910)
gpg --homedir /path/to/random/dir --fingerprint 0xBB572E0E2D182910
# trust it
gpg --homedir /path/to/random/dir --edit-key 0xBB572E0E2D182910 trust

# if you do not have the portage tree yet: import portage signing key
gpg --homedir /path/to/random/dir --keyserver pool.sks-keyservers.net --recv-keys 0xDB6B8C1F96D8BF6D
# check fingerprint (current: DCD0 5B71 EAB9 4199 527F 44AC DB6B 8C1F 96D8 BF6D)
gpg --homedir /path/to/random/dir --fingerprint 0xDB6B8C1F96D8BF6D
# trust it
gpg --homedir /path/to/random/dir --edit-key 0xDB6B8C1F96D8BF6D trust

make sure to verify that the key is actually the right one (check fingerprint with
friends, ask on IRC #gentoo-releng, #gentoo, #gentoo-containers, #lxccontainers, ...)
friends, ask on IRC #gentoo-releng, #gentoo, #gentoo-containers, #lxccontainers,
visit https://www.gentoo.org/proj/en/releng/index.xml , ...)

Network Configuration Notes
---------------------------
Expand Down
137 changes: 114 additions & 23 deletions lxc-gentoo
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ setup_portage()

# PORTAGE_SOURCE will be set by fetch_portage.
if [[ -f "$PORTAGE_SOURCE" ]]; then
verify_gpg "$PORTAGE_SOURCE.gpgsig" "$PORTAGE_SOURCE"

printf "Extracting the portage tree into %s/var/portage/tree...\n" "$ROOTFS"
tar -xp --strip-components 1 -C "$ROOTFS/var/portage/tree/" -f "$PORTAGE_SOURCE" \
|| die 2 "Error: unable to extract the portage tree.\n"
Expand Down Expand Up @@ -487,36 +489,113 @@ set_guest_root_password()
echo "done."
}

verify_image()
verify_gpg()
{
local digest_file="$1"
local image_file_absolute="$2"
local image_file="${image_file_absolute##*/}"
local image_dir="${image_file_absolute%/*}"
local signature="$1"
local file="$2"
local numargs=$#

if [[ -n "$PGP_DIR" && -d "$PGP_DIR" && -f "$PGP_DIR/pubring.gpg" ]]; then
# verify it
if [[ -d "$PGP_DIR" && -f "$PGP_DIR/pubring.gpg" ]]; then
command -v gpg > /dev/null \
|| die 2 "gpg program is not installed, unable to verify digest.\n"
|| die 2 "verify_gpg(): Error: GNU privacy guard (gpg) is not installed, unable to verify.\n"

gpg --homedir "$PGP_DIR" --verify "$digest_file" \
|| die 7 "Error: Unable to verify PGP signature! Please refer to README, section PGP setup\n"
if [[ $numargs -eq 1 ]]; then
# signed file, e.g. DIGESTS.asc
gpg --homedir "$PGP_DIR" --verify "$signature" \
|| die 7 "verify_gpg(): Error: Unable to verify attached PGP signature! Please refer to README, section PGP setup\n"
else
# detached signature, e.g. portage-latest.tar.bz2.gpgsig
gpg --homedir "$PGP_DIR" --verify "$signature" "$file" \
|| die 7 "verify_gpg(): Error: Unable to verify detached PGP signature! Please refer to README, section PGP setup\n"
fi
else
printf "Warning: \$PGP_DIR is empty or not a directory or $PGP_DIR/pubring.gpg\n%s\n" \
printf "verify_gpg(): Warning: \$PGP_DIR is empty or not a directory or $PGP_DIR/pubring.gpg\n%s\n" \
"doesen't exist, disabling signature checking!"
fi
}

# verify sha512 checksum
command -v sha512sum > /dev/null \
|| die 2 "sha512sum program is not installed, unable to verify checksum.\n"

# eh eh
# if there is no OK line we fail. I don't know how else to make sha*sum -c
# behave properly. Maybe ditch it and compare checksums directly?
(
cd "$image_dir" \
&& sha512sum -c "$digest_file" 2>/dev/null | grep "$image_file" | grep OK
) || die 7 "Error: Checksum mismatch or other error!\n"
# sha512sum, etc. busybox seems to behave the same as coreutils
verify_with_stdutils()
{
local program="$1"
local known_hash="$2"
local file_to_verify="$3"

local stdout
local retval
stdout="$($program "$file_to_verify")"
retval=$?

if [[ $retval -ne 0 ]]; then
die 2 "verify_with_stdoutils(): Error: '%s' returned nonzero (%s)\n" \
"'$program' '$file_to_verify'" "$retval"
else
stdout="${stdout%% *}" # discard all but the hash

if [[ "$stdout" == "$known_hash" ]]; then
printf "verify_with_stdutils(): '%s': OK\n" "$file_to_verify"
else
die 2 "verify_with_stdutils(): Error: file '%s' differs on disk, checksum\n\t%s\nshould be\n\t%s\n" \
"$file_to_verify" "$stdout" "$known_hash"
fi
fi
}

# parses a .DIGESTS file and attempts to verify the given file
verify_digests()
{
local digest_file="$1"
local file_to_verify="$2"

[[ ! -f "$digest_file" ]] && die 18 "verify_digests(): digest_file '%s' is not a file\n" "$digest_file"
[[ ! -f "$file_to_verify" ]] && die 18 "verify_digests(): file_to_verify '%s' is not a file\n" "$file_to_verify"

mapfile -t < "$digest_file"

local state=""
local verified=0
local line_number=0

local verify_hash_type=""

for line in "${MAPFILE[@]}"; do
(( line_number += 1 ))
# default state: get next hash type
if [[ "$state" == "" ]]; then
if [[ "$line" = *HASH ]]; then
local hashtype="${line##\# }" # remove '# ' at start
hashtype="${hashtype%% HASH}" # remove ' HASH' at end

case "$hashtype" in
SHA512) if command -v sha512sum > /dev/null; then
state="verify_with_stdutils"
verify_hash_type="sha512sum"
continue
fi
;;
*) printf "verify_digests(): (this is normal): discarding unknown hash type in '%s':%s: '%s'\n" \
"$digest_file" "$line_number" "$line"
continue
;;
esac
fi
else
# these states are names of functions that will verify checksums
known_hash="${line%% *}" # remove everything but the hash
known_file="${line##* }" # remove everything but the filename
last_component="${file_to_verify##*/}"

if [[ "$last_component" == "$known_file" ]]; then
# will call die()
$state "$verify_hash_type" "$known_hash" "$file_to_verify"
verified=1
fi
state=""
fi
done

[[ $verified -eq 0 ]] && die 2 "Unable to verify checksums for '%s',\ngiven digests '%s'\n" \
"$file_to_verify" "$digest_file"
}

fetch_stage3()
Expand Down Expand Up @@ -580,7 +659,9 @@ fetch_stage3()
fetch_portage()
{
local url="$MIRROR/snapshots/portage-latest.tar.bz2"
local signature_url="$url.gpgsig"
local dest="$CACHE/portage-latest.tar.bz2"
local signature_dest="$dest.gpgsig"

mkdir -p "$CACHE"
if [[ ! -f "$dest" ]]; then
Expand All @@ -593,6 +674,15 @@ fetch_portage()
printf " => done.\n"
fi

if [[ ! -f "$signature_dest" ]]; then
printf "Downloading Gentoo portage (software build database) snapshot GPG signatures...\n"

${WGET} -O "$signature_dest" "$signature_url" \
|| die 6 "Error: unable to fetch\n"

printf " => done.\n"
fi

# used by calling function
PORTAGE_SOURCE="$dest"
}
Expand Down Expand Up @@ -760,7 +850,8 @@ create()
fi
fi

verify_image "$STAGE3_TARBALL.DIGESTS.asc" "$STAGE3_TARBALL"
verify_gpg "$STAGE3_TARBALL.DIGESTS.asc"
verify_digests "$STAGE3_TARBALL.DIGESTS.asc" "$STAGE3_TARBALL"

# variable is nonzero, try to unpack
printf "\nUnpacking filesystem from %s to %s ... " "$STAGE3_TARBALL" "$ROOTFS"
Expand Down

0 comments on commit 8760b2c

Please sign in to comment.