1 /*
2  * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /**
25  * @test
26  * @bug 8056174 8242068 8255536
27  * @summary Make sure JarSigner impl conforms to spec
28  * @library /test/lib
29  * @modules java.base/sun.security.tools.keytool
30  *          java.base/sun.security.provider.certpath
31  *          jdk.jartool
32  *          jdk.crypto.ec
33  * @build jdk.test.lib.util.JarUtils
34  * @run main/othervm Spec
35  */
36 
37 import com.sun.jarsigner.ContentSigner;
38 import com.sun.jarsigner.ContentSignerParameters;
39 import jdk.security.jarsigner.JarSigner;
40 import jdk.test.lib.util.JarUtils;
41 import sun.security.provider.certpath.X509CertPath;
42 
43 import java.io.File;
44 import java.io.IOException;
45 import java.net.URI;
46 import java.nio.file.Files;
47 import java.nio.file.Paths;
48 import java.security.*;
49 import java.security.cert.CertPath;
50 import java.security.cert.CertificateException;
51 import java.security.cert.CertificateFactory;
52 import java.util.Arrays;
53 import java.util.Collections;
54 import java.util.function.BiConsumer;
55 
56 public class Spec {
57 
main(String[] args)58     public static void main(String[] args) throws Exception {
59 
60         // Prepares raw file
61         Files.write(Paths.get("a"), "a".getBytes());
62 
63         // Pack
64         JarUtils.createJar("a.jar", "a");
65 
66         // Prepare a keystore
67         sun.security.tools.keytool.Main.main(
68                 ("-keystore ks -storepass changeit -keypass changeit -dname" +
69                         " CN=RSA -alias r -genkeypair -keyalg rsa").split(" "));
70         sun.security.tools.keytool.Main.main(
71                 ("-keystore ks -storepass changeit -keypass changeit -dname" +
72                         " CN=DSA -alias d -genkeypair -keyalg dsa").split(" "));
73         sun.security.tools.keytool.Main.main(
74                 ("-keystore ks -storepass changeit -keypass changeit -dname" +
75                         " CN=Ed25519 -alias e -genkeypair -keyalg Ed25519").split(" "));
76 
77         char[] pass = "changeit".toCharArray();
78 
79         KeyStore ks = KeyStore.getInstance(
80                 new File("ks"), pass);
81         PrivateKey pkr = (PrivateKey)ks.getKey("r", pass);
82         PrivateKey pkd = (PrivateKey)ks.getKey("d", pass);
83         CertPath cp = CertificateFactory.getInstance("X.509")
84                 .generateCertPath(Arrays.asList(ks.getCertificateChain("r")));
85 
86         Provider sun = Security.getProvider("SUN");
87 
88         // throws
89         npe(()->new JarSigner.Builder(null));
90         npe(()->new JarSigner.Builder(null, cp));
91         iae(()->new JarSigner.Builder(
92                 pkr, new X509CertPath(Collections.emptyList())));
93         iae(()->new JarSigner.Builder(pkd, cp));    // unmatched certs alg
94 
95         JarSigner.Builder b1 = new JarSigner.Builder(pkr, cp);
96 
97         npe(()->b1.digestAlgorithm(null));
98         nsae(()->b1.digestAlgorithm("HAHA"));
99         b1.digestAlgorithm("SHA-256");
100 
101         npe(()->b1.digestAlgorithm("SHA-256", null));
102         npe(()->b1.digestAlgorithm(null, sun));
103         nsae(()->b1.digestAlgorithm("HAHA", sun));
104         b1.digestAlgorithm("SHA-256", sun);
105 
106         npe(()->b1.signatureAlgorithm(null));
107         nsae(()->b1.signatureAlgorithm("HAHAwithHEHE"));
108         iae(()->b1.signatureAlgorithm("SHA256withECDSA"));
109 
110         npe(()->b1.signatureAlgorithm(null, sun));
111         npe(()->b1.signatureAlgorithm("SHA256withRSA", null));
112         nsae(()->b1.signatureAlgorithm("HAHAwithHEHE", sun));
113         iae(()->b1.signatureAlgorithm("SHA256withDSA", sun));
114 
115         npe(()->b1.tsa(null));
116 
117         npe(()->b1.signerName(null));
118         iae(()->b1.signerName(""));
119         iae(()->b1.signerName("123456789"));
120         iae(()->b1.signerName("a+b"));
121 
122         npe(()->b1.setProperty(null, ""));
123         uoe(()->b1.setProperty("what", ""));
124         npe(()->b1.setProperty("tsadigestalg", null));
125         iae(()->b1.setProperty("tsadigestalg", "HAHA"));
126         npe(()->b1.setProperty("tsapolicyid", null));
127         npe(()->b1.setProperty("internalsf", null));
128         iae(()->b1.setProperty("internalsf", "Hello"));
129         npe(()->b1.setProperty("sectionsonly", null));
130         iae(()->b1.setProperty("sectionsonly", "OK"));
131         npe(()->b1.setProperty("sectionsonly", null));
132         npe(()->b1.setProperty("altsigner", null));
133         npe(()->b1.eventHandler(null));
134 
135         // default values
136         JarSigner.Builder b2 = new JarSigner.Builder(pkr, cp);
137         JarSigner js2 = b2.build();
138 
139         assertTrue(js2.getDigestAlgorithm().equals(
140                 JarSigner.Builder.getDefaultDigestAlgorithm()));
141         assertTrue(js2.getSignatureAlgorithm().equals(
142                 JarSigner.Builder.getDefaultSignatureAlgorithm(pkr)));
143         assertTrue(js2.getTsa() == null);
144         assertTrue(js2.getSignerName().equals("SIGNER"));
145         assertTrue(js2.getProperty("tsadigestalg").equals(
146                 JarSigner.Builder.getDefaultDigestAlgorithm()));
147         assertTrue(js2.getProperty("tsapolicyid") == null);
148         assertTrue(js2.getProperty("internalsf").equals("false"));
149         assertTrue(js2.getProperty("sectionsonly").equals("false"));
150         assertTrue(js2.getProperty("altsigner") == null);
151         uoe(()->js2.getProperty("invalid"));
152 
153         // default values
154         BiConsumer<String,String> myeh = (a,s)->{};
155         URI tsa = new URI("https://tsa.com");
156 
157         JarSigner.Builder b3 = new JarSigner.Builder(pkr, cp)
158                 .digestAlgorithm("SHA-1")
159                 .signatureAlgorithm("SHA1withRSA")
160                 .signerName("Duke")
161                 .tsa(tsa)
162                 .setProperty("tsadigestalg", "SHA-512")
163                 .setProperty("tsapolicyid", "1.2.3.4")
164                 .setProperty("internalsf", "true")
165                 .setProperty("sectionsonly", "true")
166                 .setProperty("altsigner", "MyContentSigner")
167                 .eventHandler(myeh);
168         JarSigner js3 = b3.build();
169 
170         assertTrue(js3.getDigestAlgorithm().equals("SHA-1"));
171         assertTrue(js3.getSignatureAlgorithm().equals("SHA1withRSA"));
172         assertTrue(js3.getTsa().equals(tsa));
173         assertTrue(js3.getSignerName().equals("DUKE"));
174         assertTrue(js3.getProperty("tsadigestalg").equals("SHA-512"));
175         assertTrue(js3.getProperty("tsapolicyid").equals("1.2.3.4"));
176         assertTrue(js3.getProperty("internalsf").equals("true"));
177         assertTrue(js3.getProperty("sectionsonly").equals("true"));
178         assertTrue(js3.getProperty("altsigner").equals("MyContentSigner"));
179         assertTrue(js3.getProperty("altsignerpath") == null);
180 
181         assertTrue(JarSigner.Builder.getDefaultDigestAlgorithm().equals("SHA-256"));
182 
183         // Calculating large DSA and RSA keys are too slow.
184         KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
185         kpg.initialize(1024);
186         assertTrue(JarSigner.Builder
187                 .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate())
188                     .equals("SHA256withRSA"));
189 
190         kpg = KeyPairGenerator.getInstance("DSA");
191         kpg.initialize(1024);
192         assertTrue(JarSigner.Builder
193                 .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate())
194                 .equals("SHA256withDSA"));
195 
196         kpg = KeyPairGenerator.getInstance("EC");
197         kpg.initialize(256);
198         assertTrue(JarSigner.Builder
199                 .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate())
200                 .equals("SHA256withECDSA"));
201         kpg.initialize(384);
202         assertTrue(JarSigner.Builder
203                 .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate())
204                 .equals("SHA384withECDSA"));
205         kpg.initialize(521);
206         assertTrue(JarSigner.Builder
207                 .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate())
208                 .equals("SHA512withECDSA"));
209 
210         // altsigner does not support modern algorithms
211         JarSigner.Builder b4 = new JarSigner.Builder(
212                 (PrivateKey)ks.getKey("e", pass),
213                 CertificateFactory.getInstance("X.509")
214                         .generateCertPath(Arrays.asList(ks.getCertificateChain("e"))));
215         b4.setProperty("altsigner", "MyContentSigner");
216         iae(() -> b4.build());
217     }
218 
219     interface RunnableWithException {
run()220         void run() throws Exception;
221     }
222 
uoe(RunnableWithException r)223     static void uoe(RunnableWithException r) throws Exception {
224         checkException(r, UnsupportedOperationException.class);
225     }
226 
nsae(RunnableWithException r)227     static void nsae(RunnableWithException r) throws Exception {
228         checkException(r, NoSuchAlgorithmException.class);
229     }
230 
npe(RunnableWithException r)231     static void npe(RunnableWithException r) throws Exception {
232         checkException(r, NullPointerException.class);
233     }
234 
iae(RunnableWithException r)235     static void iae(RunnableWithException r) throws Exception {
236         checkException(r, IllegalArgumentException.class);
237     }
238 
checkException(RunnableWithException r, Class ex)239     static void checkException(RunnableWithException r, Class ex)
240             throws Exception {
241         try {
242             r.run();
243         } catch (Exception e) {
244             if (ex.isAssignableFrom(e.getClass())) {
245                 return;
246             }
247             throw e;
248         }
249         throw new Exception("No exception thrown");
250     }
251 
assertTrue(boolean x)252     static void assertTrue(boolean x) throws Exception {
253         if (!x) throw new Exception("Not true");
254     }
255 
256     static class MyContentSigner extends ContentSigner {
257         @Override
generateSignedData( ContentSignerParameters parameters, boolean omitContent, boolean applyTimestamp)258         public byte[] generateSignedData(
259                 ContentSignerParameters parameters,
260                 boolean omitContent,
261                 boolean applyTimestamp) throws NoSuchAlgorithmException,
262                 CertificateException, IOException {
263             return new byte[0];
264         }
265     }
266 }
267