Skip to content

Commit

Permalink
Check driver updates signatures
Browse files Browse the repository at this point in the history
  • Loading branch information
imobachgs committed Mar 11, 2016
1 parent 914abcc commit 920957a
Show file tree
Hide file tree
Showing 21 changed files with 437 additions and 13 deletions.
49 changes: 45 additions & 4 deletions src/lib/installation/driver_update.rb
Expand Up @@ -31,17 +31,30 @@ class NotFound < StandardError; end

EXTRACT_CMD = "gzip -dc %<source>s | cpio --quiet --sparse -dimu --no-absolute-filenames"
APPLY_CMD = "/etc/adddir %<source>s/inst-sys /" # openSUSE/installation-images
EXTRACT_SIG_CMD = "gpg --homedir %<homedir>s --batch --no-default-keyring --keyring %<keyring>s " \
"--ignore-valid-from --ignore-time-conflict --output '%<unpacked>s' '%<source>s'"
VERIFY_SIG_CMD = "gpg --homedir %<homedir>s --batch --no-default-keyring --keyring %<keyring>s " \
"--ignore-valid-from --ignore-time-conflict --verify '%<path>s'"
TEMP_FILENAME = "remote.dud"
UNPACKED_EXT = ".unpacked"
SIG_EXT = ".asc"

attr_reader :uri, :local_path
attr_reader :uri, :local_path, :keyring, :gpg_homedir

# Constructor
#
# @param uri [URI] Driver Update URI
def initialize(uri)
def initialize(uri, keyring: keyring, gpg_homedir: nil)
Yast.import "Linuxrc"
@uri = uri
@local_path = nil
@keyring = keyring
@gpg_homedir = gpg_homedir || "/root/.gnupg"
@signed = nil
end

def signed?
@signed
end

# Fetch the DUD and store it in the given directory
Expand All @@ -53,11 +66,26 @@ def fetch(target)
Dir.chdir(dir) do
temp_file = Pathname.pwd.join(TEMP_FILENAME)
download_file_to(temp_file)
clear_signature(temp_file)
check_detached_signature(temp_file) unless signed?
extract(temp_file, local_path)
end
end
end

def check_detached_signature(temp_file)
asc_file = temp_file.sub_ext("#{temp_file.extname}#{SIG_EXT}")
get_remote_file(uri.merge("#{uri}#{SIG_EXT}"), asc_file)
cmd = format(VERIFY_SIG_CMD, path: asc_file, keyring: keyring, homedir: gpg_homedir)
out = Yast::SCR.Execute(Yast::Path.new(".target.bash_output"), cmd)
::FileUtils.rm(asc_file) if asc_file.exist?
@signed = check_gpg_output(out)
end

def check_gpg_output(out)
out["exit"].zero? && !out["stderr"].include?("WARNING")
end

# Apply the DUD to the running system
def apply
raise "Driver updated not fetched yet!" if local_path.nil?
Expand All @@ -80,6 +108,15 @@ def extract(source, target)
::FileUtils.mv(update_dir, target)
end

def clear_signature(path)
unpacked_path = path.sub_ext(UNPACKED_EXT)
cmd = format(EXTRACT_SIG_CMD, source: path, unpacked: unpacked_path,
keyring: keyring, homedir: gpg_homedir)
out = Yast::SCR.Execute(Yast::Path.new(".target.bash_output"), cmd)
@signed = check_gpg_output(out)
::FileUtils.mv(unpacked_path, path) if unpacked_path.exist?
end

# Set up the target directory
#
# Refresh the target directory (dir will be re-created).
Expand All @@ -96,8 +133,7 @@ def setup_target(dir)
#
# @return [True] true if download was successful
def download_file_to(path)
get_file_from_url(scheme: uri.scheme, host: uri.host, urlpath: uri.path,
localfile: path.to_s, urltok: {}, destdir: "")
get_remote_file(uri, path)
raise NotFound unless path.exist?
true
end
Expand Down Expand Up @@ -130,5 +166,10 @@ def run_update_pre
out = Yast::SCR.Execute(Yast::Path.new(".target.bash_output"), update_pre_path.to_s)
out["exit"].zero?
end

def get_remote_file(location, path)
get_file_from_url(scheme: location.scheme, host: location.host, urlpath: location.path,
localfile: path.to_s, urltok: {}, destdir: "")
end
end
end
99 changes: 90 additions & 9 deletions test/driver_update_test.rb
Expand Up @@ -12,27 +12,27 @@
TEMP_DIR = TEST_DIR.join("test", "tmp", "update")
FIXTURES_DIR = TEST_DIR.join("fixtures")

let(:url) { URI("file://#{FIXTURES_DIR}/fake.dud") }
let(:url) { URI("file://#{FIXTURES_DIR}/fake.signed.dud") }
let(:keyring) { FIXTURES_DIR.join("pubring.gpg") }
let(:gpg_homedir) { FIXTURES_DIR.join("dot.gnupg") }
let(:target) { TEST_DIR.join("target") }

subject { Installation::DriverUpdate.new(url) }
subject { Installation::DriverUpdate.new(url, keyring: keyring, gpg_homedir: gpg_homedir) }

before do
allow(Yast::Linuxrc).to receive(:InstallInf).with("UpdateDir")
.and_return("/linux/suse/x86_64-sles12")
::FileUtils.chmod(0700, gpg_homedir)
end

after do
# Make sure those files are removed
::FileUtils.rm_r(TEMP_DIR) if TEMP_DIR.exist?
::FileUtils.rm_r(target) if target.exist?
end

describe "#fetch" do
let(:target) { TEST_DIR.join("target") }

after do
::FileUtils.rm_r(target) if target.exist? # Make sure the file is removed
end

let(:dud_io) { StringIO.new(File.binread(FIXTURES_DIR.join("fake.dud"))) }
let(:url) { URI("file://#{FIXTURES_DIR}/fake.signed.dud") }

it "downloads the file at #url and stores in the given directory" do
subject.fetch(target)
Expand All @@ -48,6 +48,87 @@
end
end

describe "#signed?" do
before do
#subject.fetch(target)
end

context "if the signature is attached" do
context "and signature is valid and trusted" do
let(:url) { URI("file://#{FIXTURES_DIR}/fake.signed.dud") }

it "returns true" do
subject.fetch(target)
expect(subject).to be_signed
end
end

context "and signature is valid but not trusted" do
let(:url) { URI("file://#{FIXTURES_DIR}/fake.signed+untrusted.dud") }

it "returns false" do
allow(subject).to receive(:get_remote_file).with(any_args).and_call_original
allow(subject).to receive(:get_remote_file)
.with(URI("file://#{FIXTURES_DIR}/fake.signed+untrusted.dud.asc"), any_args).once.and_return(false)
subject.fetch(target)
expect(subject).to_not be_signed
end
end

context "and signature is unknown" do
let(:url) { URI("file://#{FIXTURES_DIR}/fake.signed+unknown.dud") }

it "returns false" do
allow(subject).to receive(:get_remote_file).with(any_args).and_call_original
allow(subject).to receive(:get_remote_file)
.with(URI("file://#{FIXTURES_DIR}/fake.signed+unknown.dud.asc"), any_args).once.and_return(false)
subject.fetch(target)
expect(subject).to_not be_signed
end
end
end

context "signature is detached" do
context "and signature is valid and trusted" do
let(:url) { URI("file://#{FIXTURES_DIR}/fake.detached.dud") }

it "returns true" do
subject.fetch(target)
expect(subject).to be_signed
end
end

context "and signature is valid but not trusted" do
let(:url) { URI("file://#{FIXTURES_DIR}/fake.detached+untrusted.dud") }

it "returns false" do
subject.fetch(target)
expect(subject).to_not be_signed
end
end

context "and signature is unknown" do
let(:url) { URI("file://#{FIXTURES_DIR}/fake.detached+unknown.dud") }

it "returns false" do
expect(subject).to_not be_signed
end
end

context "and .asc file does not exist" do
before do
allow(subject).to receive(:get_remote_file)
.with(URI("file://#{FIXTURES_DIR}/fake.dud.asc"), any_args).once.and_return(false)
allow(subject).to receive(:get_remote_file).with(any_args).and_call_original
end

it "returns false" do
expect(subject).to_not be_signed
end
end
end
end

describe "#apply" do
let(:local_path) { TEMP_DIR.join("000") }

Expand Down
Empty file.
Empty file.
Binary file added test/fixtures/dot.gnupg/trustdb.gpg
Binary file not shown.
Binary file added test/fixtures/fake.detached+unknown.dud
Binary file not shown.
11 changes: 11 additions & 0 deletions test/fixtures/fake.detached+unknown.dud.asc
@@ -0,0 +1,11 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAABAgAGBQJW4aH0AAoJEEXOXBCAeBnGV3MH/2A2QLzKVfgOKjFzp9qah2q/
zPk8BAU+nyuVVIt6NVnc0Zub9edDZ8MnkBXDQdNoXfzMcDcSJb7smok61EEMtcpK
RJrEdI2MZyKA/wChjxjMRGTSoGe6anbVS0PeCqsJRrPpcX4mTWq3EoUdG/wi+rBg
2Dbj0ANKVlcpYbHRPAwmN/zOmGnekJZN/O9p/OEVwtOWEPAmiezQ6oVygyKdvgZ2
l9Q4Bvu5MUB/DBHR93JqsCoLYhgdPXVeYiwFgwrA2jmnruN4+6LxgYd9oNWm0F1W
3HhBDkVNA7EgDlqACc9ina07yrFj7+RGRTKrdb5kY2dKzlu8YmHrCXF15WL50rI=
=WcQI
-----END PGP SIGNATURE-----
Binary file added test/fixtures/fake.detached+untrusted.dud
Binary file not shown.
Binary file added test/fixtures/fake.detached+untrusted.dud.asc
Binary file not shown.
Binary file added test/fixtures/fake.detached.dud
Binary file not shown.
11 changes: 11 additions & 0 deletions test/fixtures/fake.detached.dud.asc
@@ -0,0 +1,11 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQEcBAABAgAGBQJW4XkSAAoJEDKUTdyYJZBjVXAH/ifZTBK8hMvD29RXcghp4sME
5yRnaGxICCUqZGyXU7ImdIAwGWx+C8Qn5bq+N6OumJiqd5skQlAJg3HCV2xcpj4D
SixcfmL0eux/P97uMN68g1bYFPagmmYE+LTYXnxSsLCGodULwNVjSCas7Xb8zBIc
PwflpnbFww/MN540S20989H6vblbdIY7vdtcxHVqiHyVYwmwNh15GbRAIQ6CKr+4
Lh/M17qloqA3arurXu960jeiubozZbOTXn38CIkchloFx0iNNa2vHIqdflRAIUE+
vuAhN3rc1tEqjhBuJXW5FFI6ro7V+vuhTmmS8kY9jlKO76x6rbNq+4U6WCeR6ew=
=zTw+
-----END PGP SIGNATURE-----
22 changes: 22 additions & 0 deletions test/fixtures/fake.signed+unknown.dud
@@ -0,0 +1,22 @@
-----BEGIN PGP MESSAGE-----
Version: GnuPG v2

owEBEwPs/JANAwACAUXOXBCAeBnGAa0B4mIXZmFrZS5zaWduZWQrdW5rbm93bi5k
dWRW4atiH4sIAAQY11YCA+2WXW+CMBSGudVfUbNrpF8U8A4HJCbLLoy7XirUyURn
KBr990OnzjrULhlc7YSE5rTN+/T0vAToQAciCCEjNiXlG1IUBrA6iM0CB7mQquko
PAzwlX2nfNeA53p+TXrsOMjSxWqjavZr0uwrmpZcSWGUoWg/1qONvJ/a1sZlr4ya
MhMS4QuOvb6LfHqFA6kcTqTHgek9DitZJd34YzFJ38raPIA4F7wQCRhvwXxWzgHU
xbT9skzK7CDotbhnjz0CxyYiODYpTiYmd1xmIiEQcmM6JtA+LH/mc9FrfY2B1j61
JmE9d4Px3ZqkC1mYcitVnugOD97zsMv5uzxMm8cSRaww2VCrb1hw8AJ2NZmiXzFZ
Ez4TZtktO3+NpqkE5fO+kgXgYDcFgjxdixwceiFI5azbVs6x5/dRFOn1Pww0fehU
nCPlZy40jAtbqvVlNXG5FVzLZXzOcZOLNFkvUvpUs164Jq6q7ynP52snO4Hc5PIa
vEdJPLjRvEenJi7/Wn9l4khykws1yMV5Hk+/SW5y2TVxsep6aTG5DXpx11s6XtQJ
3XVX/6tGQ3/wFA47nY7xH38Wn6HvoZgADAAAiQEcBAABAgAGBQJW4atiAAoJEEXO
XBCAeBnGz/AH/RfWPwGa4K8VedL0ucgO6+IeVZQzB0MBZ2BvfY5my1OfsSfVOVE2
t2FRrhbsRk+MGvOA3wJlE+PxvueslHZ8v18VbZiFuY11c7QEucminQN+m7xnQdpe
JXPpobbvR1GCk5WaMvyBWTHCEI4jZA44ONZQNZu2J/FVTqVAX9l9DFH5eCMEpy2k
6L1xxLVwtKqMGjn+403z09dpC4HgUjoiw1MZBbV28CRianNY67RYbASBC9iKersi
EF+YcK693cpRPpKaLLbsf0dnZMUCI8FA04ZFTdCTFz/V26n/6QPT5EltNUCEYCBZ
sWBMMkzSnBYALI9sHrS5/vIh0Jv1bmAZGYs=
=rDy0
-----END PGP MESSAGE-----
22 changes: 22 additions & 0 deletions test/fixtures/fake.signed+untrusted.dud
@@ -0,0 +1,22 @@
-----BEGIN PGP MESSAGE-----
Version: GnuPG v2

owEBFQPq/JANAwACAamOUJNq83goAa0B5GIZZmFrZS5zaWduZWQrdW50cnVzdGVk
LmR1ZFbhq0sfiwgABBjXVgID7ZZdb4IwFIa51V9Rs2ukXxTwDgckJssujLteKtTJ
RGcoGv33Q6fOOtQuGVzthITmtM379PS8BOhAByIIISM2JeUbUhQGsDqIzQIHuZCq
6Sg8DPCVfad814Dnen5Neuw4yNLFaqNq9mvS7CuallxJYZShaD/Wo428n9rWxmWv
jJoyExLhC469vot8eoUDqRxOpMeB6T0OK1kl3fhjMUnfyto8gDgXvBAJGG/BfFbO
AdTFtP2yTMrsIOi1uGePPQLHJiI4NilOJiZ3XGYiIRByYzom0D4sf+Zz0Wt9jYHW
PrUmYT13g/HdmqQLWZhyK1We6A4P3vOwy/m7PEybxxJFrDDZUKtvWHDwAnY1maJf
MVkTPhNm2S07f42mqQTl876SBeBgNwWCPF2LHBx6IUjlrNtWzrHn91EU6fU/DDR9
6FScI+VnLjSMC1uq9WU1cbkVXMtlfM5xk4s0WS9S+lSzXrgmrqrvKc/nayc7gdzk
8hq8R0k8uNG8R6cmLv9af2XiSHKTCzXIxXkeT79JbnLZNXGx6nppMbkNenHXWzpe
1AnddVf/q0ZDf/AUDjudjvEffxafoe+hmAAMAACJARwEAAECAAYFAlbhq0sACgkQ
qY5Qk2rzeCj64QgAiUPRf0RxDVG+DZjIU/rXhFfPyZ7eyXr1Gf+Zd7UAL85FYiyE
N/tvIOMv+n79yKilGts3Y6MAycqe9djZad/zakSMGWIvc31r9rWL/FnKto0fjols
hNXGMpYtrqf3oPe2jSEXvAbdgGt/Bx2MI1CvbzA2fSDtJBSnh87+6ZH5JgG9Mjj4
t5fWaqfi/Gq4oduW8zNQSN1Jb/u7OZ0JabcU1Yzoplbseya6BfmCbYMv2pEp+A11
3Z1lPTOlsEYkMRC2dwYBT48JYT9U0XugyaLHym626zlbDXuy+GuGFzPGVjEuaVFa
IUA1saOZuSE9+j/aV9VWQwvQ2ZSWDge22AMzmg==
=INkW
-----END PGP MESSAGE-----
Binary file added test/fixtures/fake.signed.dud
Binary file not shown.
Empty file.
58 changes: 58 additions & 0 deletions test/fixtures/keys/bogus+unknown.sec
@@ -0,0 +1,58 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: GnuPG v2

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
8ufeNzdjpmwn
=kmTS
-----END PGP PRIVATE KEY BLOCK-----
31 changes: 31 additions & 0 deletions test/fixtures/keys/bogus+untrusted.pub
@@ -0,0 +1,31 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2

mQENBFbhnMYBCADJdjj1UExJAVyXI9krLW8LgdKFZ8V4GOniJj0TdznWQ+52FNjd
v2KMRo8q4ZWdbNx3s+30/psVYIArE6qrQFulgop2wUBTHtaQVHtEPizhkDIz29Wr
5xZ6G6etHV05Vjm7bLRDA24LR4lFW/BjKtYT08WtIAyd69M1Tvbj/L6p+1PhvNlM
9hkKlE4QZTwcXsY1/5x/Q+ozOePRuh1snfRoSExhkdpujEFc3zGdMRfJCXf7+M7K
lsag2rAwmS/g+duozuYhFKUfcsDzrS0FfOZiRmnjwrsWu+hRRK8Jah3km/sJZeei
Iob1WXwz2jNdzwwxMIGC4IIUjGuUav7pYfZ3ABEBAAG0N1lhU1QgYm9ndXMgYW5k
IHVudHJ1c3RlZCBHUEcga2V5IDx5YXN0K3VudHJ1c3RlZEBib2d1cz6JATkEEwEC
ACMFAlbhnMYCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRCpjlCTavN4
KDucCACGEYrojAvEeTm3AUrlgXRHrN/YfkkBbnkEISki1Ii8IURz0mtqA3uLn9VW
fZJ4H8i9hd/vgcjUkpspRXhjIcKHuCuJQNbNIdZyqDN2FgNedU8SPDSdLAByKPu1
lWacBo1hUDhZGTl7QXQUs+0P24Tx9bV8PElrg9ObiiVLeL7r3eCNPJbvcYhl/R/v
ssd8pJpvzhf6sZAw1PnApwhiHk0qCyQBSCe6Swpl7BVrwFwXeKAr34FwFmPR9seP
p/3s9Iesr7yeRy+sKLfPcXZF5u0PgVDIP7ygGPsWDqYWTa8FST9gsLF7QwJTrRz1
EKG3x05Jsz8m1tWu9jUbC7SEKCFkuQENBFbhnMYBCADXYOz78YhCo/xExWWzjDiA
4j46mVmvIOezDs2YlwCPW4k5UYE/jl0NUU/2Msys/d0aFdwuvrhC2dR6wlgsxLyK
NvmMZSb23uT0khYzmO0H9v4fsPq9qymX3qWdcVbc6W+pnfNuSjDLeixBhQlFync6
pp2YYlTIoGWHUtE+AndkILWO6LbcbDds0Fs7zMp6ye1C10kYYUogiL5hYRZykxBy
LWLdkpc+5zQMyBGA5qcIxAiGv0Vlof50EjcCi4i9y6WZzincnb7qsjVhcfe1y5N0
vzyej21rJuP8LmckvoZf5DmqymD1b5fVquoxdCC+v8RgbeAUwGScotZAsMvsIcTl
ABEBAAGJAR8EGAECAAkFAlbhnMYCGwwACgkQqY5Qk2rzeChXTgf+MbRyymWu2tab
AfZBUOhL7yPAQdGKSYn5fJN2vRQWp7f4tR5dAOITZXW8Ut7DlcsOtrlX3Nywv508
17YVfBY0Sh+NnZpnxetbOdCPf45d7sZkRhZxahUuUwpWIzr0AWABRgKefBwy3tta
9uttZEAPZvUpsWfdYCTy0xynG+SUXI8n74XYtt7Z/6GrbA//eBc65jU4afvbaoTm
pHzng0bK+aW0Vc7FMUc3s3FeUBxX9BK39UXHs1Vg/IMuF+UPznRW2ZccMEe7+pjp
MhabX664dR9bS5sF9zmWCXX2A1yxpDSkiXOOsmU2pQkyJxR2Qwu862xCKaZ7hzex
6ItIOUiDQw==
=o0to
-----END PGP PUBLIC KEY BLOCK-----

0 comments on commit 920957a

Please sign in to comment.