Merge lp:~apw/launchpad/signing-sipl into lp:launchpad

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
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
Colin Watson (cjwatson) wrote :

Looks pretty much OK; just a few nits.

review: Approve
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")