From 0e783efc9b095b8686fcfbfcf84b3d6184a5a2b5 Mon Sep 17 00:00:00 2001 From: BJ Hargrave Date: Fri, 27 May 2022 15:13:31 -0400 Subject: [PATCH] jarsigner: Fix 2 bugs in the jarsigner support First, the support did not consult the JAVA_HOME env var to locate the jarsigner tool. So this could be a different version than the desired one. Second, the support did not handle EC key signing as the *.EC files were not copied in the result jar which breaks the signing. Signed-off-by: BJ Hargrave --- .../test/test/JarSignerTest.java | 49 +++++++----------- .../testresources/certificate/gencert.sh | 2 + biz.aQute.bndlib.tests/testresources/keystore | Bin 1375 -> 2560 bytes .../src/aQute/bnd/signing/JartoolSigner.java | 25 +++++++-- 4 files changed, 43 insertions(+), 33 deletions(-) create mode 100755 biz.aQute.bndlib.tests/testresources/certificate/gencert.sh diff --git a/biz.aQute.bndlib.tests/test/test/JarSignerTest.java b/biz.aQute.bndlib.tests/test/test/JarSignerTest.java index 18e6e36b68..8ea1fa0d95 100644 --- a/biz.aQute.bndlib.tests/test/test/JarSignerTest.java +++ b/biz.aQute.bndlib.tests/test/test/JarSignerTest.java @@ -1,13 +1,12 @@ package test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; import java.io.File; import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.jar.Attributes; +import java.util.jar.Attributes.Name; import java.util.jar.Manifest; import org.junit.jupiter.api.Test; @@ -15,7 +14,6 @@ import aQute.bnd.osgi.Builder; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Jar; -import aQute.bnd.osgi.Processor; import aQute.bnd.signing.JartoolSigner; import aQute.bnd.test.jupiter.InjectTemporaryDirectory; import aQute.lib.io.IO; @@ -30,6 +28,7 @@ public class JarSignerTest { public void testNoManifest(@InjectTemporaryDirectory File tmpdir) throws Exception { Builder b = new Builder(); + b.setProperty("jarsigner", "jarsigner"); b.setProperty("-sign", "test"); b.setProperty(Constants.PLUGIN, JartoolSigner.class.getName() + ";keystore=testresources/keystore;keypass=testtest;storepass=testtest;sigfile=test"); @@ -44,9 +43,10 @@ public void testNoManifest(@InjectTemporaryDirectory Jar jar2 = new Jar(tmp); Manifest manifest = jar2.getManifest(); - assertEquals("1.0", manifest.getMainAttributes() - .getValue("Manifest-Version")); - assertNotNull(manifest.getAttributes("WEB-INF/classes/org/osgi/framework/BundleContext.class")); + assertThat(manifest.getMainAttributes()).containsEntry(Name.MANIFEST_VERSION, "1.0"); + assertThat(jar2.getResources()).containsKeys("META-INF/TEST.SF", "META-INF/TEST.EC"); + + assertThat(manifest.getAttributes("WEB-INF/classes/org/osgi/framework/BundleContext.class")).isNotNull(); } @Test @@ -63,11 +63,8 @@ public void testError() throws Exception { Jar jar = new Jar(IO.getFile("testresources/test.jar")); b.setJar(jar); signer.sign(b, "test"); - System.err.println(Processor.join(b.getErrors(), "\n")); - assertEquals(1, b.getErrors() - .size()); - assertEquals(0, b.getWarnings() - .size()); + assertThat(b.getErrors()).hasSize(1); + assertThat(b.getWarnings()).isEmpty(); } } @@ -79,7 +76,7 @@ public void testSimple() throws Exception { properties.put("keypass", "testtest"); properties.put("storepass", "testtest"); properties.put("sigFile", "test"); - properties.put("digestalg", "SHA-1"); + properties.put("digestalg", "SHA-256"); signer.setProperties(properties); Jar jar = new Jar(IO.getFile("testresources/test.jar")); @@ -89,28 +86,22 @@ public void testSimple() throws Exception { try (Builder b = new Builder()) { b.setJar(jar); signer.sign(b, "test"); - System.err.println(Processor.join(b.getErrors(), "\n")); - System.err.println(Processor.join(b.getWarnings(), "\n")); - assertEquals(0, b.getErrors() - .size()); - assertEquals(0, b.getWarnings() - .size()); - assertNotNull(jar.getResource("META-INF/TEST.SF")); + assertThat(b.getErrors()).isEmpty(); + assertThat(b.getWarnings()).isEmpty(); + assertThat(jar.getResources()).containsKeys("META-INF/TEST.SF", "META-INF/TEST.EC"); Manifest m = jar.getManifest(); - // Should have added 2 new resources: TEST.SF and TEST.DSA/RSA - assertEquals(names.size(), b.getJar() - .getResources() - .size() - 3); + // Should have added 2 new resources: TEST.SF and TEST.DSA/RSA/EC + assertThat(b.getJar() + .getResources()).hasSize(names.size() + 3); - Attributes a = m.getAttributes("aQute/rendezvous/DNS.class"); - assertNotNull(a); - assertEquals("G0/1CIZlB4eIVyY8tU/ZfMCqZm4=", a.getValue("SHA-1-Digest")); + Name digestKey = new Name(properties.get("digestalg") + "-Digest"); + assertThat(m.getAttributes("aQute/rendezvous/DNS.class")).containsEntry(digestKey, + "BMyZnHUVh1dDzBZSzaEyjRAZU+3pygawaasUDYLGEJ0="); // Check if all resources are named for (String name : names) { - System.err.println("name: " + name); - assertNotNull(m.getAttributes(name)); + assertThat(m.getAttributes(name)).containsKey(digestKey); } } } diff --git a/biz.aQute.bndlib.tests/testresources/certificate/gencert.sh b/biz.aQute.bndlib.tests/testresources/certificate/gencert.sh new file mode 100755 index 0000000000..3e62334598 --- /dev/null +++ b/biz.aQute.bndlib.tests/testresources/certificate/gencert.sh @@ -0,0 +1,2 @@ +keytool -genkeypair -alias test -keyalg EC -sigalg SHA384withECDSA -validity 30000 -keystore ../keystore -keypass testtest -storepass testtest -dname "CN=John Smith,O=ACME Inc,OU=ACME Cert Authority,L=Austin,ST=Texas,C=US" +# keytool -exportcert -alias test -file cert.crt -storepass testtest -keystore ../keystore diff --git a/biz.aQute.bndlib.tests/testresources/keystore b/biz.aQute.bndlib.tests/testresources/keystore index c05617f076f8aac7a04d2602a3323375b5612834..4ac3320e28ced00704249fc67eab407024f3b4f4 100644 GIT binary patch literal 2560 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 literal 1375 zcmezO_TO6u1_mY|W&~rFlGNf7AcyT#+i?Y;#2$ktrX2=+Y+TxGj4X^=OoEJztPCto zOiN~M)AjZ?_{9G8XV=3GfxQV@-S)pC?T)$~w-V-5WW1qZA@Qip$8(I|hs{Zy z^?Hw$?bGR(%@zx@S4_yd^sH(HPf}8a)BGsj*3wt)f7Q>vTDaXzIQiG^8Ee_5C4A6I zo+`7-bazl9n|Rp#4vYKKj%}T_LP%fS@I0FW`@Q?z{>8OLjY8Arxh*)duv&AHwElkK z2+zFbGHISx9w)v>uby`G%Y)j}Jq)xB=vJ3Ck#2b>_{2wRYSREZ!J?ZX* z7m+4yHCG?UScloBdc-VUGv$o*1C4?WdmP?9-Syj9YM1}HEBs<%H4|^V{*l#J@GX7u zo6mQ`=WVfap6tZuyxZn@dpD!tUAHo`EppRh3R&{c^#>a)-drYp(M#&*?X=bgIep{* zo)M3IgcNfo-eKH(YGcirCpnfWamL|BGZSY8lrJ#L4S#Vx?CH5Her&I~H~Y2yxH`W` zwKICVnZC)(r8_cT9a^C~@82x1uIY0YZjioo#bNH7Vwtv=ZMgFDK98tY6jQ=-zBP-L9*U^l7QXW1=(%O}VLYcx zpXeRuKUchFi9l-ByJxX0mH$OA_`4@=qrHIs)hqqi)1SUnsGM@Ec&R81Fn-w=%@sYSk-<3O#!P?g@CfpZPY%9;)yiH5=*E7k}2R!-TCN>Cc zVVr)x(LSi`LBDasi8!`9H^Qg224uh5G&O6f-2PW;FFF73DSH4;(X0`ArUsV4q#OrK z%25VQjE9+6oZZ}G4S3l&wc0$|zVk9Nvam83lo)awaI!Invaks=g$5h)8SsEO9Kx(2 zsTGOEhWtSFKt8)Ln`3ElNoJm*jDZwLfLmDD(b?Bk!8x_4M8UDNBqP5lv!v2c(10H# z%O%VKmi5d_HWW4x1PL(L=wm;g1IXwRPHf7iKmCGVHd^8Vcy+|s{yRP9Y|E**9 SqlJyEMR86Wxjy_~%? map) { if (map.containsKey("keystore")) @@ -91,7 +96,12 @@ public void setProperties(Map map) { @Override public void setReporter(Reporter processor) {} - private static Pattern EXTENSIONS_P = Pattern.compile(".*\\.(DSA|RSA|SF|MF)$"); + @Override + public void setRegistry(Registry registry) { + processor = registry.getPlugin(Processor.class); + } + + private static Pattern SIGNING_P = Pattern.compile("META-INF/([^/]*\\.(DSA|RSA|EC|SF|MF)|SIG-[^/]*)"); @Override public void sign(Builder builder, String alias) throws Exception { @@ -102,12 +112,19 @@ public void sign(Builder builder, String alias) throws Exception { } Jar jar = builder.getJar(); - File tmp = File.createTempFile("signdjar", ".jar"); + File tmp = File.createTempFile("signedjar", ".jar"); tmp.deleteOnExit(); jar.write(tmp); Command command = new Command(); + if ((path == null) || path.equals("jarsigner")) { + if (processor != null) { + path = processor.getJavaExecutable("jarsigner"); + } else { + path = IO.getJavaExecutablePath("jarsigner"); + } + } command.add(path); if (keystore != null) { command.add("-keystore"); @@ -171,7 +188,7 @@ public void sign(Builder builder, String alias) throws Exception { builder.addClose(signed); MapStream.of(signed.getDirectory("META-INF")) - .filterKey(path -> EXTENSIONS_P.matcher(path) + .filterKey(path -> SIGNING_P.matcher(path) .matches()) .forEachOrdered(jar::putResource); jar.setDoNotTouchManifest();