Merge lp:~apw/launchpad/signing-sipl into lp:launchpad
- signing-sipl
- Merge into devel
Proposed by
Andy Whitcroft
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 18979 | ||||
Proposed branch: | lp:~apw/launchpad/signing-sipl | ||||
Merge into: | lp:launchpad | ||||
Diff against target: |
575 lines (+237/-23) 2 files modified
lib/lp/archivepublisher/signing.py (+39/-17) lib/lp/archivepublisher/tests/test_signing.py (+198/-6) |
||||
To merge this branch: | bzr merge lp:~apw/launchpad/signing-sipl | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Colin Watson (community) | Approve | ||
Review via email: mp+368275@code.launchpad.net |
Commit message
Add s390x Secure Initial Program Load signing support.
Description of the change
On newer s390x mainframes zipl implements signature verification for zipl stage 3 and for the loaded kernel binaries. These signatures are essentially kernel module signing signatures. Add support for performing SIPL signing against *.sipl files in the signing custom uploads.
To post a comment you must log in.
Revision history for this message
Andy Whitcroft (apw) wrote : | # |
Hopefully that is all of the nits addressed.
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 2018-08-03 16:10:41 +0000 |
3 | +++ lib/lp/archivepublisher/signing.py 2019-06-06 09:45:01 +0000 |
4 | @@ -95,6 +95,8 @@ |
5 | self.kmod_x509 = None |
6 | self.opal_pem = None |
7 | self.opal_x509 = None |
8 | + self.sipl_pem = None |
9 | + self.sipl_x509 = None |
10 | self.autokey = False |
11 | else: |
12 | self.uefi_key = os.path.join(pubconf.signingroot, "uefi.key") |
13 | @@ -103,6 +105,8 @@ |
14 | self.kmod_x509 = os.path.join(pubconf.signingroot, "kmod.x509") |
15 | self.opal_pem = os.path.join(pubconf.signingroot, "opal.pem") |
16 | self.opal_x509 = os.path.join(pubconf.signingroot, "opal.x509") |
17 | + self.sipl_pem = os.path.join(pubconf.signingroot, "sipl.pem") |
18 | + self.sipl_x509 = os.path.join(pubconf.signingroot, "sipl.x509") |
19 | self.autokey = pubconf.signingautokey |
20 | |
21 | self.setComponents(tarfile_path) |
22 | @@ -176,6 +180,8 @@ |
23 | yield (os.path.join(dirpath, filename), self.signKmod) |
24 | elif filename.endswith(".opal"): |
25 | yield (os.path.join(dirpath, filename), self.signOpal) |
26 | + elif filename.endswith(".sipl"): |
27 | + yield (os.path.join(dirpath, filename), self.signSipl) |
28 | |
29 | def getKeys(self, which, generate, *keynames): |
30 | """Validate and return the uefi key and cert for encryption.""" |
31 | @@ -242,7 +248,7 @@ |
32 | cmdl = ["sbsign", "--key", key, "--cert", cert, image] |
33 | return self.callLog("UEFI signing", cmdl) |
34 | |
35 | - openssl_config_opal = textwrap.dedent(""" |
36 | + openssl_config_base = textwrap.dedent("""\ |
37 | [ req ] |
38 | default_bits = 4096 |
39 | distinguished_name = req_distinguished_name |
40 | @@ -260,37 +266,35 @@ |
41 | authorityKeyIdentifier=keyid |
42 | """) |
43 | |
44 | - openssl_config_kmod = openssl_config_opal + textwrap.dedent(""" |
45 | + openssl_config_opal = "# OPAL OpenSSL config\n" + openssl_config_base |
46 | + |
47 | + openssl_config_kmod = "# KMOD OpenSSL config\n" + openssl_config_base + \ |
48 | + textwrap.dedent(""" |
49 | # codeSigning: specifies that this key is used to sign code. |
50 | # 1.3.6.1.4.1.2312.16.1.2: defines this key as used for |
51 | # module signing only. See https://lkml.org/lkml/2015/8/26/741. |
52 | extendedKeyUsage = codeSigning,1.3.6.1.4.1.2312.16.1.2 |
53 | """) |
54 | |
55 | - def generateOpensslConfig(self, key_type, common_name): |
56 | - if key_type == 'Kmod': |
57 | - genkey_tmpl = self.openssl_config_kmod |
58 | - elif key_type == 'Opal': |
59 | - genkey_tmpl = self.openssl_config_opal |
60 | - else: |
61 | - raise ValueError("unknown key_type " + key_type) |
62 | + openssl_config_sipl = "# SIPL OpenSSL config\n" + openssl_config_base |
63 | + |
64 | + def generateOpensslConfig(self, key_type, genkey_tmpl): |
65 | + # Truncate name to 64 character maximum. |
66 | + common_name = self.generateKeyCommonName( |
67 | + self.archive.owner.name, self.archive.name, key_type) |
68 | |
69 | return genkey_tmpl.format(common_name=common_name) |
70 | |
71 | - def generatePemX509Pair(self, key_type, pem_filename, x509_filename): |
72 | + def generatePemX509Pair(self, key_type, genkey_text, pem_filename, |
73 | + x509_filename): |
74 | """Generate new pem/x509 key pairs.""" |
75 | directory = os.path.dirname(pem_filename) |
76 | if not os.path.exists(directory): |
77 | os.makedirs(directory) |
78 | |
79 | - # Truncate name to 64 character maximum. |
80 | - common_name = self.generateKeyCommonName( |
81 | - self.archive.owner.name, self.archive.name, key_type) |
82 | - |
83 | old_mask = os.umask(0o077) |
84 | try: |
85 | with tempfile.NamedTemporaryFile(suffix='.keygen') as tf: |
86 | - genkey_text = self.generateOpensslConfig(key_type, common_name) |
87 | print(genkey_text, file=tf) |
88 | |
89 | # Close out the underlying file so we know it is complete. |
90 | @@ -318,7 +322,8 @@ |
91 | |
92 | def generateKmodKeys(self): |
93 | """Generate new Kernel Signing Keys for this archive.""" |
94 | - self.generatePemX509Pair("Kmod", self.kmod_pem, self.kmod_x509) |
95 | + config = self.generateOpensslConfig("Kmod", self.openssl_config_kmod) |
96 | + self.generatePemX509Pair("Kmod", config, self.kmod_pem, self.kmod_x509) |
97 | |
98 | def signKmod(self, image): |
99 | """Attempt to sign a kernel module.""" |
100 | @@ -333,7 +338,8 @@ |
101 | |
102 | def generateOpalKeys(self): |
103 | """Generate new Opal Signing Keys for this archive.""" |
104 | - self.generatePemX509Pair("Opal", self.opal_pem, self.opal_x509) |
105 | + config = self.generateOpensslConfig("Opal", self.openssl_config_opal) |
106 | + self.generatePemX509Pair("Opal", config, self.opal_pem, self.opal_x509) |
107 | |
108 | def signOpal(self, image): |
109 | """Attempt to sign a kernel image for Opal.""" |
110 | @@ -346,6 +352,22 @@ |
111 | cmdl = ["kmodsign", "-D", "sha512", pem, cert, image, image + ".sig"] |
112 | return self.callLog("Opal signing", cmdl) |
113 | |
114 | + def generateSiplKeys(self): |
115 | + """Generate new Sipl Signing Keys for this archive.""" |
116 | + config = self.generateOpensslConfig("SIPL", self.openssl_config_sipl) |
117 | + self.generatePemX509Pair("SIPL", config, self.sipl_pem, self.sipl_x509) |
118 | + |
119 | + def signSipl(self, image): |
120 | + """Attempt to sign a kernel image for Sipl.""" |
121 | + remove_if_exists("%s.sig" % image) |
122 | + (pem, cert) = self.getKeys('SIPL Kernel', self.generateSiplKeys, |
123 | + self.sipl_pem, self.sipl_x509) |
124 | + if not pem or not cert: |
125 | + return |
126 | + self.publishPublicKey(cert) |
127 | + cmdl = ["kmodsign", "-D", "sha512", pem, cert, image, image + ".sig"] |
128 | + return self.callLog("SIPL signing", cmdl) |
129 | + |
130 | def convertToTarball(self): |
131 | """Convert unpacked output to signing tarball.""" |
132 | tarfilename = os.path.join(self.tmpdir, "signed.tar.gz") |
133 | |
134 | === modified file 'lib/lp/archivepublisher/tests/test_signing.py' |
135 | --- lib/lp/archivepublisher/tests/test_signing.py 2019-05-24 11:10:38 +0000 |
136 | +++ lib/lp/archivepublisher/tests/test_signing.py 2019-06-06 09:45:01 +0000 |
137 | @@ -91,6 +91,9 @@ |
138 | "Opal signing": 0, |
139 | "Opal keygen key": 0, |
140 | "Opal keygen cert": 0, |
141 | + "SIPL signing": 0, |
142 | + "SIPL keygen key": 0, |
143 | + "SIPL keygen cert": 0, |
144 | } |
145 | |
146 | def __call__(self, *args, **kwargs): |
147 | @@ -130,9 +133,20 @@ |
148 | elif description == "Opal keygen key": |
149 | write_file(self.upload.opal_pem, b"") |
150 | |
151 | + elif description == "SIPL signing": |
152 | + filename = cmdl[-1] |
153 | + if filename.endswith(".sipl.sig"): |
154 | + write_file(filename, b"") |
155 | + |
156 | + elif description == "SIPL keygen cert": |
157 | + write_file(self.upload.sipl_x509, b"") |
158 | + |
159 | + elif description == "SIPL keygen key": |
160 | + write_file(self.upload.sipl_pem, b"") |
161 | + |
162 | else: |
163 | - raise AssertionError("unknown command executed cmd=(%s)" % |
164 | - " ".join(cmdl)) |
165 | + raise AssertionError("unknown command executed description=(%s) " |
166 | + "cmd=(%s)" % (description, " ".join(cmdl))) |
167 | |
168 | return 0 |
169 | |
170 | @@ -211,6 +225,13 @@ |
171 | write_file(self.opal_pem, b"") |
172 | write_file(self.opal_x509, b"") |
173 | |
174 | + def setUpSiplKeys(self, create=True): |
175 | + self.sipl_pem = os.path.join(self.signing_dir, "sipl.pem") |
176 | + self.sipl_x509 = os.path.join(self.signing_dir, "sipl.x509") |
177 | + if create: |
178 | + write_file(self.sipl_pem, b"") |
179 | + write_file(self.sipl_x509, b"") |
180 | + |
181 | def openArchive(self, loader_type, version, arch): |
182 | self.path = os.path.join( |
183 | self.temp_dir, "%s_%s_%s.tar.gz" % (loader_type, version, arch)) |
184 | @@ -247,6 +268,7 @@ |
185 | upload.signUefi = FakeMethod() |
186 | upload.signKmod = FakeMethod() |
187 | upload.signOpal = FakeMethod() |
188 | + upload.signSipl = FakeMethod() |
189 | # Under no circumstances is it safe to execute actual commands. |
190 | fake_call = FakeMethod(result=0) |
191 | self.useFixture(MonkeyPatch("subprocess.call", fake_call)) |
192 | @@ -267,6 +289,7 @@ |
193 | self.tarfile.add_file("1.0/empty.efi", b"") |
194 | self.tarfile.add_file("1.0/empty.ko", b"") |
195 | self.tarfile.add_file("1.0/empty.opal", b"") |
196 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
197 | upload = self.process_emulate() |
198 | self.assertContentEqual([], upload.callLog.caller_list()) |
199 | |
200 | @@ -277,6 +300,7 @@ |
201 | self.tarfile.add_file("1.0/empty.efi", b"") |
202 | self.tarfile.add_file("1.0/empty.ko", b"") |
203 | self.tarfile.add_file("1.0/empty.opal", b"") |
204 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
205 | upload = self.process_emulate() |
206 | self.assertContentEqual([], upload.callLog.caller_list()) |
207 | |
208 | @@ -289,6 +313,7 @@ |
209 | self.tarfile.add_file("1.0/empty.efi", b"") |
210 | self.tarfile.add_file("1.0/empty.ko", b"") |
211 | self.tarfile.add_file("1.0/empty.opal", b"") |
212 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
213 | upload = self.process_emulate() |
214 | expected_callers = [ |
215 | ('UEFI signing', 1), |
216 | @@ -304,6 +329,7 @@ |
217 | self.tarfile.add_file("1.0/empty.efi", b"") |
218 | self.tarfile.add_file("1.0/empty.ko", b"") |
219 | self.tarfile.add_file("1.0/empty.opal", b"") |
220 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
221 | upload = self.process_emulate() |
222 | expected_callers = [ |
223 | ('UEFI keygen', 1), |
224 | @@ -311,9 +337,12 @@ |
225 | ('Kmod keygen cert', 1), |
226 | ('Opal keygen key', 1), |
227 | ('Opal keygen cert', 1), |
228 | + ('SIPL keygen key', 1), |
229 | + ('SIPL keygen cert', 1), |
230 | ('UEFI signing', 1), |
231 | ('Kmod signing', 1), |
232 | ('Opal signing', 1), |
233 | + ('SIPL signing', 1), |
234 | ] |
235 | self.assertContentEqual(expected_callers, upload.callLog.caller_list()) |
236 | |
237 | @@ -387,16 +416,19 @@ |
238 | self.setUpUefiKeys() |
239 | self.setUpKmodKeys() |
240 | self.setUpOpalKeys() |
241 | + self.setUpSiplKeys() |
242 | self.openArchive("test", "1.0", "amd64") |
243 | self.tarfile.add_file("1.0/empty.efi", b"") |
244 | self.tarfile.add_file("1.0/empty.ko", b"") |
245 | self.tarfile.add_file("1.0/empty.opal", b"") |
246 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
247 | self.process_emulate() |
248 | self.assertThat(self.getSignedPath("test", "amd64"), SignedMatches([ |
249 | "1.0/SHA256SUMS", |
250 | "1.0/empty.efi", "1.0/empty.efi.signed", "1.0/control/uefi.crt", |
251 | "1.0/empty.ko", "1.0/empty.ko.sig", "1.0/control/kmod.x509", |
252 | "1.0/empty.opal", "1.0/empty.opal.sig", "1.0/control/opal.x509", |
253 | + "1.0/empty.sipl", "1.0/empty.sipl.sig", "1.0/control/sipl.x509", |
254 | ])) |
255 | |
256 | def test_options_tarball(self): |
257 | @@ -405,11 +437,13 @@ |
258 | self.setUpUefiKeys() |
259 | self.setUpKmodKeys() |
260 | self.setUpOpalKeys() |
261 | + self.setUpSiplKeys() |
262 | self.openArchive("test", "1.0", "amd64") |
263 | self.tarfile.add_file("1.0/control/options", b"tarball") |
264 | self.tarfile.add_file("1.0/empty.efi", b"") |
265 | self.tarfile.add_file("1.0/empty.ko", b"") |
266 | self.tarfile.add_file("1.0/empty.opal", b"") |
267 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
268 | self.process_emulate() |
269 | self.assertThat(self.getSignedPath("test", "amd64"), SignedMatches([ |
270 | "1.0/SHA256SUMS", |
271 | @@ -425,6 +459,8 @@ |
272 | '1.0/empty.ko', '1.0/empty.ko.sig', '1.0/control/kmod.x509', |
273 | '1.0/empty.opal', '1.0/empty.opal.sig', |
274 | '1.0/control/opal.x509', |
275 | + '1.0/empty.sipl', '1.0/empty.sipl.sig', |
276 | + '1.0/control/sipl.x509', |
277 | ], tarball.getnames()) |
278 | |
279 | def test_options_signed_only(self): |
280 | @@ -433,17 +469,20 @@ |
281 | self.setUpUefiKeys() |
282 | self.setUpKmodKeys() |
283 | self.setUpOpalKeys() |
284 | + self.setUpSiplKeys() |
285 | self.openArchive("test", "1.0", "amd64") |
286 | self.tarfile.add_file("1.0/control/options", b"signed-only") |
287 | self.tarfile.add_file("1.0/empty.efi", b"") |
288 | self.tarfile.add_file("1.0/empty.ko", b"") |
289 | self.tarfile.add_file("1.0/empty.opal", b"") |
290 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
291 | self.process_emulate() |
292 | self.assertThat(self.getSignedPath("test", "amd64"), SignedMatches([ |
293 | "1.0/SHA256SUMS", "1.0/control/options", |
294 | "1.0/empty.efi.signed", "1.0/control/uefi.crt", |
295 | "1.0/empty.ko.sig", "1.0/control/kmod.x509", |
296 | "1.0/empty.opal.sig", "1.0/control/opal.x509", |
297 | + "1.0/empty.sipl.sig", "1.0/control/sipl.x509", |
298 | ])) |
299 | |
300 | def test_options_tarball_signed_only(self): |
301 | @@ -453,11 +492,13 @@ |
302 | self.setUpUefiKeys() |
303 | self.setUpKmodKeys() |
304 | self.setUpOpalKeys() |
305 | + self.setUpSiplKeys() |
306 | self.openArchive("test", "1.0", "amd64") |
307 | self.tarfile.add_file("1.0/control/options", b"tarball\nsigned-only") |
308 | self.tarfile.add_file("1.0/empty.efi", b"") |
309 | self.tarfile.add_file("1.0/empty.ko", b"") |
310 | self.tarfile.add_file("1.0/empty.opal", b"") |
311 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
312 | self.process_emulate() |
313 | self.assertThat(self.getSignedPath("test", "amd64"), SignedMatches([ |
314 | "1.0/SHA256SUMS", |
315 | @@ -471,6 +512,7 @@ |
316 | '1.0/empty.efi.signed', '1.0/control/uefi.crt', |
317 | '1.0/empty.ko.sig', '1.0/control/kmod.x509', |
318 | '1.0/empty.opal.sig', '1.0/control/opal.x509', |
319 | + '1.0/empty.sipl.sig', '1.0/control/sipl.x509', |
320 | ], tarball.getnames()) |
321 | |
322 | def test_no_signed_files(self): |
323 | @@ -484,6 +526,8 @@ |
324 | self.getSignedPath("empty", "amd64"), "1.0", "hello"))) |
325 | self.assertEqual(0, upload.signUefi.call_count) |
326 | self.assertEqual(0, upload.signKmod.call_count) |
327 | + self.assertEqual(0, upload.signOpal.call_count) |
328 | + self.assertEqual(0, upload.signSipl.call_count) |
329 | |
330 | def test_already_exists(self): |
331 | # If the target directory already exists, processing fails. |
332 | @@ -559,15 +603,20 @@ |
333 | def test_correct_kmod_openssl_config(self): |
334 | # Check that calling generateOpensslConfig() will return an appropriate |
335 | # openssl configuration. |
336 | + self.setUpPPA() |
337 | upload = SigningUpload() |
338 | - text = upload.generateOpensslConfig('Kmod', 'something-unique') |
339 | + upload.setTargetDirectory( |
340 | + self.archive, "test_1.0_amd64.tar.gz", "distroseries") |
341 | + text = upload.generateOpensslConfig('Kmod', upload.openssl_config_kmod) |
342 | |
343 | - cn_re = re.compile(r'\bCN\s*=\s*something-unique\b') |
344 | + id_re = re.compile(r'^# KMOD OpenSSL config\n') |
345 | + cn_re = re.compile(r'\bCN\s*=\s*' + self.testcase_cn[4:-1] + '\s+Kmod') |
346 | eku_re = re.compile( |
347 | r'\bextendedKeyUsage\s*=\s*' |
348 | r'codeSigning,1.3.6.1.4.1.2312.16.1.2\s*\b') |
349 | |
350 | self.assertIn('[ req ]', text) |
351 | + self.assertIsNotNone(id_re.search(text)) |
352 | self.assertIsNotNone(cn_re.search(text)) |
353 | self.assertIsNotNone(eku_re.search(text)) |
354 | |
355 | @@ -640,12 +689,17 @@ |
356 | def test_correct_opal_openssl_config(self): |
357 | # Check that calling generateOpensslConfig() will return an appropriate |
358 | # openssl configuration. |
359 | + self.setUpPPA() |
360 | upload = SigningUpload() |
361 | - text = upload.generateOpensslConfig('Opal', 'something-unique') |
362 | + upload.setTargetDirectory( |
363 | + self.archive, "test_1.0_amd64.tar.gz", "distroseries") |
364 | + text = upload.generateOpensslConfig('Opal', upload.openssl_config_opal) |
365 | |
366 | - cn_re = re.compile(r'\bCN\s*=\s*something-unique\b') |
367 | + id_re = re.compile(r'^# OPAL OpenSSL config\n') |
368 | + cn_re = re.compile(r'\bCN\s*=\s*' + self.testcase_cn[4:-1] + '\s+Opal') |
369 | |
370 | self.assertIn('[ req ]', text) |
371 | + self.assertIsNotNone(id_re.search(text)) |
372 | self.assertIsNotNone(cn_re.search(text)) |
373 | self.assertNotIn('extendedKeyUsage', text) |
374 | |
375 | @@ -715,6 +769,89 @@ |
376 | ] |
377 | self.assertEqual(expected_cmd, args) |
378 | |
379 | + def test_correct_sipl_openssl_config(self): |
380 | + # Check that calling generateOpensslConfig() will return an appropriate |
381 | + # openssl configuration. |
382 | + self.setUpPPA() |
383 | + upload = SigningUpload() |
384 | + upload.setTargetDirectory( |
385 | + self.archive, "test_1.0_amd64.tar.gz", "distroseries") |
386 | + text = upload.generateOpensslConfig('SIPL', upload.openssl_config_sipl) |
387 | + |
388 | + id_re = re.compile(r'^# SIPL OpenSSL config\n') |
389 | + cn_re = re.compile(r'\bCN\s*=\s*' + self.testcase_cn[4:-1] + '\s+SIPL') |
390 | + |
391 | + self.assertIn('[ req ]', text) |
392 | + self.assertIsNotNone(id_re.search(text)) |
393 | + self.assertIsNotNone(cn_re.search(text)) |
394 | + self.assertNotIn('extendedKeyUsage', text) |
395 | + |
396 | + def test_correct_sipl_signing_command_executed(self): |
397 | + # Check that calling signSipl() will generate the expected command |
398 | + # when appropriate keys are present. |
399 | + self.setUpSiplKeys() |
400 | + fake_call = FakeMethod(result=0) |
401 | + self.useFixture(MonkeyPatch("subprocess.call", fake_call)) |
402 | + upload = SigningUpload() |
403 | + upload.generateSiplKeys = FakeMethod() |
404 | + upload.setTargetDirectory( |
405 | + self.archive, "test_1.0_amd64.tar.gz", "distroseries") |
406 | + upload.signSipl('t.sipl') |
407 | + self.assertEqual(1, fake_call.call_count) |
408 | + # Assert command form. |
409 | + args = fake_call.calls[0][0][0] |
410 | + expected_cmd = [ |
411 | + 'kmodsign', '-D', 'sha512', self.sipl_pem, self.sipl_x509, |
412 | + 't.sipl', 't.sipl.sig' |
413 | + ] |
414 | + self.assertEqual(expected_cmd, args) |
415 | + self.assertEqual(0, upload.generateSiplKeys.call_count) |
416 | + |
417 | + def test_correct_sipl_signing_command_executed_no_keys(self): |
418 | + # Check that calling signSipl() will generate no commands when |
419 | + # no keys are present. |
420 | + self.setUpSiplKeys(create=False) |
421 | + fake_call = FakeMethod(result=0) |
422 | + self.useFixture(MonkeyPatch("subprocess.call", fake_call)) |
423 | + upload = SigningUpload() |
424 | + upload.generateSiplKeys = FakeMethod() |
425 | + upload.setTargetDirectory( |
426 | + self.archive, "test_1.0_amd64.tar.gz", "distroseries") |
427 | + upload.signOpal('t.sipl') |
428 | + self.assertEqual(0, fake_call.call_count) |
429 | + self.assertEqual(0, upload.generateSiplKeys.call_count) |
430 | + |
431 | + def test_correct_sipl_keygen_command_executed(self): |
432 | + # Check that calling generateSiplKeys() will generate the |
433 | + # expected command. |
434 | + self.setUpPPA() |
435 | + self.setUpSiplKeys(create=False) |
436 | + fake_call = FakeMethod(result=0) |
437 | + self.useFixture(MonkeyPatch("subprocess.call", fake_call)) |
438 | + upload = SigningUpload() |
439 | + upload.setTargetDirectory( |
440 | + self.archive, "test_1.0_amd64.tar.gz", "distroseries") |
441 | + upload.generateSiplKeys() |
442 | + self.assertEqual(2, fake_call.call_count) |
443 | + # Assert the actual command matches. |
444 | + args = fake_call.calls[0][0][0] |
445 | + # Sanitise the keygen tmp file. |
446 | + if args[11].endswith('.keygen'): |
447 | + args[11] = 'XXX.keygen' |
448 | + expected_cmd = [ |
449 | + 'openssl', 'req', '-new', '-nodes', '-utf8', '-sha512', |
450 | + '-days', '3650', '-batch', '-x509', |
451 | + '-config', 'XXX.keygen', '-outform', 'PEM', |
452 | + '-out', self.sipl_pem, '-keyout', self.sipl_pem |
453 | + ] |
454 | + self.assertEqual(expected_cmd, args) |
455 | + args = fake_call.calls[1][0][0] |
456 | + expected_cmd = [ |
457 | + 'openssl', 'x509', '-in', self.sipl_pem, '-outform', 'DER', |
458 | + '-out', self.sipl_x509 |
459 | + ] |
460 | + self.assertEqual(expected_cmd, args) |
461 | + |
462 | def test_signs_uefi_image(self): |
463 | # Each image in the tarball is signed. |
464 | self.setUpUefiKeys() |
465 | @@ -739,6 +876,14 @@ |
466 | upload = self.process() |
467 | self.assertEqual(1, upload.signOpal.call_count) |
468 | |
469 | + def test_signs_sipl_image(self): |
470 | + # Each image in the tarball is signed. |
471 | + self.setUpSiplKeys() |
472 | + self.openArchive("test", "1.0", "amd64") |
473 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
474 | + upload = self.process() |
475 | + self.assertEqual(1, upload.signSipl.call_count) |
476 | + |
477 | def test_signs_combo_image(self): |
478 | # Each image in the tarball is signed. |
479 | self.setUpKmodKeys() |
480 | @@ -749,10 +894,15 @@ |
481 | self.tarfile.add_file("1.0/empty.opal", b"") |
482 | self.tarfile.add_file("1.0/empty2.opal", b"") |
483 | self.tarfile.add_file("1.0/empty3.opal", b"") |
484 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
485 | + self.tarfile.add_file("1.0/empty2.sipl", b"") |
486 | + self.tarfile.add_file("1.0/empty3.sipl", b"") |
487 | + self.tarfile.add_file("1.0/empty4.sipl", b"") |
488 | upload = self.process() |
489 | self.assertEqual(1, upload.signUefi.call_count) |
490 | self.assertEqual(2, upload.signKmod.call_count) |
491 | self.assertEqual(3, upload.signOpal.call_count) |
492 | + self.assertEqual(4, upload.signSipl.call_count) |
493 | |
494 | def test_installed(self): |
495 | # Files in the tarball are installed correctly. |
496 | @@ -898,16 +1048,55 @@ |
497 | self.assertEqual(stat.S_IMODE(os.stat(self.opal_pem).st_mode), 0o600) |
498 | self.assertEqual(stat.S_IMODE(os.stat(self.opal_x509).st_mode), 0o644) |
499 | |
500 | + def test_create_sipl_keys_autokey_off(self): |
501 | + # Keys are not created. |
502 | + self.setUpSiplKeys(create=False) |
503 | + self.assertFalse(os.path.exists(self.sipl_pem)) |
504 | + self.assertFalse(os.path.exists(self.sipl_x509)) |
505 | + fake_call = FakeMethod(result=0) |
506 | + self.useFixture(MonkeyPatch("subprocess.call", fake_call)) |
507 | + upload = SigningUpload() |
508 | + upload.callLog = FakeMethodCallLog(upload=upload) |
509 | + upload.setTargetDirectory( |
510 | + self.archive, "test_1.0_amd64.tar.gz", "distroseries") |
511 | + upload.signOpal(os.path.join(self.makeTemporaryDirectory(), 't.sipl')) |
512 | + self.assertEqual(0, upload.callLog.caller_count('SIPL keygen key')) |
513 | + self.assertEqual(0, upload.callLog.caller_count('SIPL keygen cert')) |
514 | + self.assertFalse(os.path.exists(self.sipl_pem)) |
515 | + self.assertFalse(os.path.exists(self.sipl_x509)) |
516 | + |
517 | + def test_create_sipl_keys_autokey_on(self): |
518 | + # Keys are created on demand. |
519 | + self.setUpPPA() |
520 | + self.setUpSiplKeys(create=False) |
521 | + self.assertFalse(os.path.exists(self.sipl_pem)) |
522 | + self.assertFalse(os.path.exists(self.sipl_x509)) |
523 | + fake_call = FakeMethod(result=0) |
524 | + self.useFixture(MonkeyPatch("subprocess.call", fake_call)) |
525 | + upload = SigningUpload() |
526 | + upload.callLog = FakeMethodCallLog(upload=upload) |
527 | + upload.setTargetDirectory( |
528 | + self.archive, "test_1.0_amd64.tar.gz", "distroseries") |
529 | + upload.signSipl(os.path.join(self.makeTemporaryDirectory(), 't.sipl')) |
530 | + self.assertEqual(1, upload.callLog.caller_count('SIPL keygen key')) |
531 | + self.assertEqual(1, upload.callLog.caller_count('SIPL keygen cert')) |
532 | + self.assertTrue(os.path.exists(self.sipl_pem)) |
533 | + self.assertTrue(os.path.exists(self.sipl_x509)) |
534 | + self.assertEqual(stat.S_IMODE(os.stat(self.sipl_pem).st_mode), 0o600) |
535 | + self.assertEqual(stat.S_IMODE(os.stat(self.sipl_x509).st_mode), 0o644) |
536 | + |
537 | def test_checksumming_tree(self): |
538 | # Specifying no options should leave us with an open tree, |
539 | # confirm it is checksummed. |
540 | self.setUpUefiKeys() |
541 | self.setUpKmodKeys() |
542 | self.setUpOpalKeys() |
543 | + self.setUpSiplKeys() |
544 | self.openArchive("test", "1.0", "amd64") |
545 | self.tarfile.add_file("1.0/empty.efi", b"") |
546 | self.tarfile.add_file("1.0/empty.ko", b"") |
547 | self.tarfile.add_file("1.0/empty.opal", b"") |
548 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
549 | self.process_emulate() |
550 | sha256file = os.path.join(self.getSignedPath("test", "amd64"), |
551 | "1.0", "SHA256SUMS") |
552 | @@ -926,6 +1115,7 @@ |
553 | self.tarfile.add_file("1.0/empty.efi", b"") |
554 | self.tarfile.add_file("1.0/empty.ko", b"") |
555 | self.tarfile.add_file("1.0/empty.opal", b"") |
556 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
557 | self.process_emulate() |
558 | sha256file = os.path.join(self.getSignedPath("test", "amd64"), |
559 | "1.0", "SHA256SUMS") |
560 | @@ -949,6 +1139,7 @@ |
561 | self.tarfile.add_file("1.0/empty.efi", b"") |
562 | self.tarfile.add_file("1.0/empty.ko", b"") |
563 | self.tarfile.add_file("1.0/empty.opal", b"") |
564 | + self.tarfile.add_file("1.0/empty.sipl", b"") |
565 | self.process_emulate() |
566 | sha256file = os.path.join(self.getSignedPath("test", "amd64"), |
567 | "1.0", "SHA256SUMS") |
568 | @@ -982,6 +1173,7 @@ |
569 | self.tarfile.add_file("1.0/empty.efi", "") |
570 | self.tarfile.add_file("1.0/empty.ko", "") |
571 | self.tarfile.add_file("1.0/empty.opal", "") |
572 | + self.tarfile.add_file("1.0/empty.sipl", "") |
573 | self.process_emulate() |
574 | sha256file = os.path.join(self.getSignedPath("test", "amd64"), |
575 | "1.0", "SHA256SUMS") |
Looks pretty much OK; just a few nits.