Merge lp:~twom/launchpad/per-series-signing-keys into lp:launchpad

Proposed by Tom Wardill
Status: Merged
Merged at revision: 19035
Proposed branch: lp:~twom/launchpad/per-series-signing-keys
Merge into: lp:launchpad
Diff against target: 192 lines (+135/-13)
2 files modified
lib/lp/archivepublisher/signing.py (+35/-10)
lib/lp/archivepublisher/tests/test_signing.py (+100/-3)
To merge this branch: bzr merge lp:~twom/launchpad/per-series-signing-keys
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+371675@code.launchpad.net

Commit message

Allow per series signing keys for UEFI

Description of the change

If the series has a uefi key created for it, use it. Otherwise walk back up the series list until we find one that exists and use that.
If nothing exists use the root key.
If we're going to create the key if it doesn't exist, just accept the given path for the series.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Needs Fixing
Revision history for this message
Colin Watson (cjwatson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/archivepublisher/signing.py'
2--- lib/lp/archivepublisher/signing.py 2019-06-06 10:55:17 +0000
3+++ lib/lp/archivepublisher/signing.py 2019-08-27 09:41:48 +0000
4@@ -82,6 +82,23 @@
5 self.package, self.version, self.arch = self.parsePath(
6 tarfile_path)
7
8+ def getSeriesPath(self, pubconf, key_name, archive):
9+ """Find the key path for a given series.
10+
11+ Will iterate the series list backwards until either one exists,
12+ or we reach the key at the filesystem root.
13+ """
14+ for series in archive.distribution.series:
15+ path = os.path.join(
16+ pubconf.signingroot,
17+ series.name,
18+ key_name
19+ )
20+ if os.path.exists(path):
21+ return path
22+ # If we have exhausted all available series, return the root
23+ return os.path.join(pubconf.signingroot, key_name)
24+
25 def setTargetDirectory(self, archive, tarfile_path, suite):
26 self.archive = archive
27 pubconf = getPubConfig(archive)
28@@ -101,19 +118,27 @@
29 self.fit_cert = None
30 self.autokey = False
31 else:
32- self.uefi_key = os.path.join(pubconf.signingroot, "uefi.key")
33- self.uefi_cert = os.path.join(pubconf.signingroot, "uefi.crt")
34- self.kmod_pem = os.path.join(pubconf.signingroot, "kmod.pem")
35- self.kmod_x509 = os.path.join(pubconf.signingroot, "kmod.x509")
36- self.opal_pem = os.path.join(pubconf.signingroot, "opal.pem")
37- self.opal_x509 = os.path.join(pubconf.signingroot, "opal.x509")
38- self.sipl_pem = os.path.join(pubconf.signingroot, "sipl.pem")
39- self.sipl_x509 = os.path.join(pubconf.signingroot, "sipl.x509")
40+ self.uefi_key = self.getSeriesPath(pubconf, "uefi.key", archive)
41+ self.uefi_cert = self.getSeriesPath(pubconf, "uefi.crt", archive)
42+ self.kmod_pem = self.getSeriesPath(pubconf, "kmod.pem", archive)
43+ self.kmod_x509 = self.getSeriesPath(pubconf, "kmod.x509", archive)
44+ self.opal_pem = self.getSeriesPath(pubconf, "opal.pem", archive)
45+ self.opal_x509 = self.getSeriesPath(pubconf, "opal.x509", archive)
46+ self.sipl_pem = self.getSeriesPath(pubconf, "sipl.pem", archive)
47+ self.sipl_x509 = self.getSeriesPath(pubconf, "sipl.x509", archive)
48 # Note: the signature tool allows a collection of keys and takes
49 # a directory name with all valid keys. Avoid mixing the
50 # other signing types' keys with the fit keys.
51- self.fit_key = os.path.join(pubconf.signingroot, "fit", "fit.key")
52- self.fit_cert = os.path.join(pubconf.signingroot, "fit", "fit.crt")
53+ self.fit_key = self.getSeriesPath(
54+ pubconf,
55+ os.path.join("fit", "fit.key"),
56+ archive
57+ )
58+ self.fit_cert = self.getSeriesPath(
59+ pubconf,
60+ os.path.join("fit", "fit.crt"),
61+ archive
62+ )
63 self.autokey = pubconf.signingautokey
64
65 self.setComponents(tarfile_path)
66
67=== modified file 'lib/lp/archivepublisher/tests/test_signing.py'
68--- lib/lp/archivepublisher/tests/test_signing.py 2019-06-06 10:55:17 +0000
69+++ lib/lp/archivepublisher/tests/test_signing.py 2019-08-27 09:41:48 +0000
70@@ -215,9 +215,13 @@
71 yield IArchiveSigningKey(self.archive).setSigningKey(
72 key_path, async_keyserver=True)
73
74- def setUpUefiKeys(self, create=True):
75- self.key = os.path.join(self.signing_dir, "uefi.key")
76- self.cert = os.path.join(self.signing_dir, "uefi.crt")
77+ def setUpUefiKeys(self, create=True, series=None):
78+ if not series:
79+ self.key = os.path.join(self.signing_dir, "uefi.key")
80+ self.cert = os.path.join(self.signing_dir, "uefi.crt")
81+ else:
82+ self.key = os.path.join(self.signing_dir, series.name, "uefi.key")
83+ self.cert = os.path.join(self.signing_dir, series.name, "uefi.crt")
84 if create:
85 write_file(self.key, b"")
86 write_file(self.cert, b"")
87@@ -970,6 +974,32 @@
88 upload = self.process()
89 self.assertEqual(1, upload.signUefi.call_count)
90
91+ def test_signs_uefi_image_per_series(self):
92+ """Check that signing can be per series.
93+ This should fall through to the first series,
94+ as the second does not have keys.
95+ """
96+ first_series = self.factory.makeDistroSeries(
97+ self.distro,
98+ name="existing-keys"
99+ )
100+ self.factory.makeDistroSeries(
101+ self.distro,
102+ name="no-keys"
103+ )
104+ # Each image in the tarball is signed.
105+ self.setUpUefiKeys()
106+ self.setUpUefiKeys(series=first_series)
107+ self.openArchive("test", "1.0", "amd64")
108+ self.tarfile.add_file("1.0/empty.efi", b"")
109+ upload = self.process_emulate()
110+ expected_callers = [('UEFI signing', 1),]
111+ self.assertContentEqual(expected_callers, upload.callLog.caller_list())
112+ # Check the correct series name appears in the call arguments
113+ self.assertIn(
114+ "existing-keys",
115+ upload.callLog.extract_args()[0][1][2])
116+
117 def test_signs_fit_image(self):
118 # Each image in the tarball is signed.
119 self.setUpFitKeys()
120@@ -1351,6 +1381,73 @@
121 "SUITE": Equals(self.suite),
122 }))
123
124+ def test_getSeriesKeyName_no_series(self):
125+ upload = SigningUpload()
126+ config = getPubConfig(self.archive)
127+ result = upload.getSeriesPath(
128+ config, 'key.key', self.archive)
129+ expected_path = os.path.join(config.signingroot, 'key.key')
130+ self.assertEqual(expected_path, result)
131+
132+ def test_getSeriesKeyName_autokey(self):
133+ self.setUpPPA()
134+ self.factory.makeDistroSeries(self.distro, name='newdistroseries')
135+ upload = SigningUpload()
136+ config = getPubConfig(self.archive)
137+ result = upload.getSeriesPath(
138+ config, "uefi.key", self.archive)
139+ expected_path = os.path.join(config.signingroot, "uefi.key")
140+ self.assertEqual(expected_path, result)
141+
142+ def test_getSeriesKeyName_one_distroseries(self):
143+ self.setUpUefiKeys(
144+ series=self.factory.makeDistroSeries(
145+ self.distro, name="newdistroseries"))
146+ upload = SigningUpload()
147+ config = getPubConfig(self.archive)
148+ result = upload.getSeriesPath(
149+ config, "uefi.key", self.archive)
150+ expected_path = os.path.join(
151+ config.signingroot,
152+ "newdistroseries",
153+ "uefi.key",
154+ )
155+ self.assertEqual(expected_path, result)
156+
157+ def test_getSeriesKeyName_two_distroseries(self):
158+ self.setUpUefiKeys(
159+ series=self.factory.makeDistroSeries(
160+ self.distro, name="newdistroseries"))
161+ self.setUpUefiKeys(
162+ series=self.factory.makeDistroSeries(
163+ self.distro, name="seconddistroseries"))
164+ upload = SigningUpload()
165+ config = getPubConfig(self.archive)
166+ result = upload.getSeriesPath(
167+ config, "uefi.key", self.archive)
168+ expected_path = os.path.join(
169+ config.signingroot,
170+ "seconddistroseries",
171+ "uefi.key",
172+ )
173+ self.assertEqual(expected_path, result)
174+
175+ def test_getSeriesKeyName_two_distroseries_fallthrough(self):
176+ self.setUpUefiKeys(
177+ series=self.factory.makeDistroSeries(
178+ self.distro, name="newdistroseries"))
179+ self.factory.makeDistroSeries(self.distro, name="seconddistroseries")
180+ upload = SigningUpload()
181+ config = getPubConfig(self.archive)
182+ result = upload.getSeriesPath(
183+ config, "uefi.key", self.archive)
184+ expected_path = os.path.join(
185+ config.signingroot,
186+ "newdistroseries",
187+ "uefi.key",
188+ )
189+ self.assertEqual(expected_path, result)
190+
191
192 class TestUefi(TestSigningHelpers):
193