1 /*
2 * Copyright (c) 2003, 2013, 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 */
41 import java.util.jar.JarFile;
42
43 import sun.misc.IOUtils;
44 import sun.security.pkcs.ContentInfo;
45 import sun.security.pkcs.PKCS7;
46 import sun.security.pkcs.PKCS9Attribute;
47 import sun.security.pkcs.SignerInfo;
48 import sun.security.timestamp.TimestampToken;
49 import sun.security.util.DerOutputStream;
50 import sun.security.util.DerValue;
51 import sun.security.util.ObjectIdentifier;
52 import sun.security.x509.AlgorithmId;
53 import sun.security.x509.X500Name;
54
55 public class TimestampCheck {
56 static final String TSKS = "tsks";
57 static final String JAR = "old.jar";
58
59 static final String defaultPolicyId = "2.3.4.5";
60
61 static class Handler implements HttpHandler {
62 public void handle(HttpExchange t) throws IOException {
63 int len = 0;
64 for (String h: t.getRequestHeaders().keySet()) {
65 if (h.equalsIgnoreCase("Content-length")) {
66 len = Integer.valueOf(t.getRequestHeaders().get(h).get(0));
67 }
68 }
69 byte[] input = new byte[len];
70 t.getRequestBody().read(input);
71
72 try {
73 int path = 0;
74 if (t.getRequestURI().getPath().length() > 1) {
75 path = Integer.parseInt(
76 t.getRequestURI().getPath().substring(1));
77 }
78 byte[] output = sign(input, path);
79 Headers out = t.getResponseHeaders();
80 out.set("Content-Type", "application/timestamp-reply");
81
119 System.err.println("AlgorithmId: " + aid);
120
121 ObjectIdentifier policyId = new ObjectIdentifier(defaultPolicyId);
122 BigInteger nonce = null;
123 while (value.data.available() > 0) {
124 DerValue v = value.data.getDerValue();
125 if (v.tag == DerValue.tag_Integer) {
126 nonce = v.getBigInteger();
127 System.err.println("nonce: " + nonce);
128 } else if (v.tag == DerValue.tag_Boolean) {
129 System.err.println("certReq: " + v.getBoolean());
130 } else if (v.tag == DerValue.tag_ObjectId) {
131 policyId = v.getOID();
132 System.err.println("PolicyID: " + policyId);
133 }
134 }
135
136 // Write TSResponse
137 System.err.println("\nResponse\n===================");
138 KeyStore ks = KeyStore.getInstance("JKS");
139 ks.load(new FileInputStream(TSKS), "changeit".toCharArray());
140
141 String alias = "ts";
142 if (path == 6) alias = "tsbad1";
143 if (path == 7) alias = "tsbad2";
144 if (path == 8) alias = "tsbad3";
145
146 if (path == 11) {
147 policyId = new ObjectIdentifier(defaultPolicyId);
148 }
149
150 DerOutputStream statusInfo = new DerOutputStream();
151 statusInfo.putInteger(0);
152
153 DerOutputStream token = new DerOutputStream();
154 AlgorithmId[] algorithms = {aid};
155 Certificate[] chain = ks.getCertificateChain(alias);
156 X509Certificate[] signerCertificateChain = null;
157 X509Certificate signer = (X509Certificate)chain[0];
158 if (path == 5) { // Only case 5 uses full chain
159 signerCertificateChain = new X509Certificate[chain.length];
223 new X500Name(signer.getIssuerX500Principal().getName()),
224 signer.getSerialNumber(),
225 aid, AlgorithmId.get("RSA"), sig.sign());
226
227 SignerInfo[] signerInfos = {signerInfo};
228 PKCS7 p7 =
229 new PKCS7(algorithms, contentInfo, signerCertificateChain,
230 signerInfos);
231 ByteArrayOutputStream p7out = new ByteArrayOutputStream();
232 p7.encodeSignedData(p7out);
233
234 DerOutputStream response = new DerOutputStream();
235 response.write(DerValue.tag_Sequence, statusInfo);
236 response.putDerValue(new DerValue(p7out.toByteArray()));
237
238 DerOutputStream out = new DerOutputStream();
239 out.write(DerValue.tag_Sequence, response);
240
241 return out.toByteArray();
242 }
243 }
244
245 public static void main(String[] args) throws Exception {
246
247 Handler h = new Handler();
248 HttpServer server = HttpServer.create(new InetSocketAddress(0), 0);
249 int port = server.getAddress().getPort();
250 HttpContext ctx = server.createContext("/", h);
251 server.start();
252
253 String cmd = null;
254 // Use -J-Djava.security.egd=file:/dev/./urandom to speed up
255 // nonce generation in timestamping request. Not avaibale on
256 // Windows and defaults to thread seed generator, not too bad.
257 if (System.getProperty("java.home").endsWith("jre")) {
258 cmd = System.getProperty("java.home") + "/../bin/jarsigner";
259 } else {
260 cmd = System.getProperty("java.home") + "/bin/jarsigner";
261 }
262
263 cmd += " " + System.getProperty("test.tool.vm.opts") +
264 " -J-Djava.security.egd=file:/dev/./urandom" +
265 " -debug -keystore " + TSKS + " -storepass changeit" +
266 " -tsa http://localhost:" + port + "/%d" +
267 " -signedjar new_%d.jar " + JAR + " old";
268
269 try {
270 if (args.length == 0) { // Run this test
271 jarsigner(cmd, 0, true); // Success, normal call
272 jarsigner(cmd, 1, false); // These 4 should fail
273 jarsigner(cmd, 2, false);
274 jarsigner(cmd, 3, false);
275 jarsigner(cmd, 4, false);
276 jarsigner(cmd, 5, true); // Success, 6543440 solved.
277 jarsigner(cmd, 6, false); // tsbad1
278 jarsigner(cmd, 7, false); // tsbad2
279 jarsigner(cmd, 8, false); // tsbad3
280 jarsigner(cmd, 9, false); // no cert in timestamp
281 jarsigner(cmd + " -tsapolicyid 1.2.3.4", 10, true);
282 checkTimestamp("new_10.jar", "1.2.3.4", "SHA-256");
283 jarsigner(cmd + " -tsapolicyid 1.2.3.5", 11, false);
284 jarsigner(cmd + " -tsadigestalg SHA", 12, true);
285 checkTimestamp("new_12.jar", defaultPolicyId, "SHA-1");
286 } else { // Run as a standalone server
287 System.err.println("Press Enter to quit server");
288 System.in.read();
289 }
290 } finally {
291 server.stop(0);
292 }
293 }
294
295 static void checkTimestamp(String file, String policyId, String digestAlg)
296 throws Exception {
297 try (JarFile jf = new JarFile(file)) {
298 JarEntry je = jf.getJarEntry("META-INF/OLD.RSA");
299 try (InputStream is = jf.getInputStream(je)) {
300 byte[] content = IOUtils.readFully(is, -1, true);
301 PKCS7 p7 = new PKCS7(content);
302 SignerInfo[] si = p7.getSignerInfos();
303 if (si == null || si.length == 0) {
304 throw new Exception("Not signed");
305 }
306 PKCS9Attribute p9 = si[0].getUnauthenticatedAttributes()
307 .getAttribute(PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID);
308 PKCS7 tsToken = new PKCS7((byte[]) p9.getValue());
309 TimestampToken tt =
310 new TimestampToken(tsToken.getContentInfo().getData());
311 if (!tt.getHashAlgorithm().toString().equals(digestAlg)) {
|
1 /*
2 * Copyright (c) 2003, 2015, 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 */
41 import java.util.jar.JarFile;
42
43 import sun.misc.IOUtils;
44 import sun.security.pkcs.ContentInfo;
45 import sun.security.pkcs.PKCS7;
46 import sun.security.pkcs.PKCS9Attribute;
47 import sun.security.pkcs.SignerInfo;
48 import sun.security.timestamp.TimestampToken;
49 import sun.security.util.DerOutputStream;
50 import sun.security.util.DerValue;
51 import sun.security.util.ObjectIdentifier;
52 import sun.security.x509.AlgorithmId;
53 import sun.security.x509.X500Name;
54
55 public class TimestampCheck {
56 static final String TSKS = "tsks";
57 static final String JAR = "old.jar";
58
59 static final String defaultPolicyId = "2.3.4.5";
60
61 static class Handler implements HttpHandler, AutoCloseable {
62
63 private final HttpServer httpServer;
64 private final String keystore;
65
66 @Override
67 public void handle(HttpExchange t) throws IOException {
68 int len = 0;
69 for (String h: t.getRequestHeaders().keySet()) {
70 if (h.equalsIgnoreCase("Content-length")) {
71 len = Integer.valueOf(t.getRequestHeaders().get(h).get(0));
72 }
73 }
74 byte[] input = new byte[len];
75 t.getRequestBody().read(input);
76
77 try {
78 int path = 0;
79 if (t.getRequestURI().getPath().length() > 1) {
80 path = Integer.parseInt(
81 t.getRequestURI().getPath().substring(1));
82 }
83 byte[] output = sign(input, path);
84 Headers out = t.getResponseHeaders();
85 out.set("Content-Type", "application/timestamp-reply");
86
124 System.err.println("AlgorithmId: " + aid);
125
126 ObjectIdentifier policyId = new ObjectIdentifier(defaultPolicyId);
127 BigInteger nonce = null;
128 while (value.data.available() > 0) {
129 DerValue v = value.data.getDerValue();
130 if (v.tag == DerValue.tag_Integer) {
131 nonce = v.getBigInteger();
132 System.err.println("nonce: " + nonce);
133 } else if (v.tag == DerValue.tag_Boolean) {
134 System.err.println("certReq: " + v.getBoolean());
135 } else if (v.tag == DerValue.tag_ObjectId) {
136 policyId = v.getOID();
137 System.err.println("PolicyID: " + policyId);
138 }
139 }
140
141 // Write TSResponse
142 System.err.println("\nResponse\n===================");
143 KeyStore ks = KeyStore.getInstance("JKS");
144 try (FileInputStream fis = new FileInputStream(keystore)) {
145 ks.load(fis, "changeit".toCharArray());
146 }
147
148 String alias = "ts";
149 if (path == 6) alias = "tsbad1";
150 if (path == 7) alias = "tsbad2";
151 if (path == 8) alias = "tsbad3";
152
153 if (path == 11) {
154 policyId = new ObjectIdentifier(defaultPolicyId);
155 }
156
157 DerOutputStream statusInfo = new DerOutputStream();
158 statusInfo.putInteger(0);
159
160 DerOutputStream token = new DerOutputStream();
161 AlgorithmId[] algorithms = {aid};
162 Certificate[] chain = ks.getCertificateChain(alias);
163 X509Certificate[] signerCertificateChain = null;
164 X509Certificate signer = (X509Certificate)chain[0];
165 if (path == 5) { // Only case 5 uses full chain
166 signerCertificateChain = new X509Certificate[chain.length];
230 new X500Name(signer.getIssuerX500Principal().getName()),
231 signer.getSerialNumber(),
232 aid, AlgorithmId.get("RSA"), sig.sign());
233
234 SignerInfo[] signerInfos = {signerInfo};
235 PKCS7 p7 =
236 new PKCS7(algorithms, contentInfo, signerCertificateChain,
237 signerInfos);
238 ByteArrayOutputStream p7out = new ByteArrayOutputStream();
239 p7.encodeSignedData(p7out);
240
241 DerOutputStream response = new DerOutputStream();
242 response.write(DerValue.tag_Sequence, statusInfo);
243 response.putDerValue(new DerValue(p7out.toByteArray()));
244
245 DerOutputStream out = new DerOutputStream();
246 out.write(DerValue.tag_Sequence, response);
247
248 return out.toByteArray();
249 }
250
251 private Handler(HttpServer httpServer, String keystore) {
252 this.httpServer = httpServer;
253 this.keystore = keystore;
254 }
255
256 /**
257 * Initialize TSA instance.
258 *
259 * Extended Key Info extension of certificate that is used for
260 * signing TSA responses should contain timeStamping value.
261 */
262 static Handler init(int port, String keystore) throws IOException {
263 HttpServer httpServer = HttpServer.create(
264 new InetSocketAddress(port), 0);
265 Handler tsa = new Handler(httpServer, keystore);
266 httpServer.createContext("/", tsa);
267 return tsa;
268 }
269
270 /**
271 * Start TSA service.
272 */
273 void start() {
274 httpServer.start();
275 }
276
277 /**
278 * Stop TSA service.
279 */
280 void stop() {
281 httpServer.stop(0);
282 }
283
284 /**
285 * Return server port number.
286 */
287 int getPort() {
288 return httpServer.getAddress().getPort();
289 }
290
291 @Override
292 public void close() throws Exception {
293 stop();
294 }
295 }
296
297 public static void main(String[] args) throws Exception {
298 try (Handler tsa = Handler.init(0, TSKS);) {
299 tsa.start();
300 int port = tsa.getPort();
301
302 String cmd;
303 // Use -J-Djava.security.egd=file:/dev/./urandom to speed up
304 // nonce generation in timestamping request. Not avaibale on
305 // Windows and defaults to thread seed generator, not too bad.
306 if (System.getProperty("java.home").endsWith("jre")) {
307 cmd = System.getProperty("java.home") + "/../bin/jarsigner";
308 } else {
309 cmd = System.getProperty("java.home") + "/bin/jarsigner";
310 }
311
312 cmd += System.getProperty("test.tool.vm.opts")
313 + " -J-Djava.security.egd=file:/dev/./urandom"
314 + " -debug -keystore " + TSKS + " -storepass changeit"
315 + " -tsa http://localhost:" + port + "/%d"
316 + " -signedjar new_%d.jar " + JAR + " old";
317
318 if (args.length == 0) { // Run this test
319 jarsigner(cmd, 0, true); // Success, normal call
320 jarsigner(cmd, 1, false); // These 4 should fail
321 jarsigner(cmd, 2, false);
322 jarsigner(cmd, 3, false);
323 jarsigner(cmd, 4, false);
324 jarsigner(cmd, 5, true); // Success, 6543440 solved.
325 jarsigner(cmd, 6, false); // tsbad1
326 jarsigner(cmd, 7, false); // tsbad2
327 jarsigner(cmd, 8, false); // tsbad3
328 jarsigner(cmd, 9, false); // no cert in timestamp
329 jarsigner(cmd + " -tsapolicyid 1.2.3.4", 10, true);
330 checkTimestamp("new_10.jar", "1.2.3.4", "SHA-256");
331 jarsigner(cmd + " -tsapolicyid 1.2.3.5", 11, false);
332 jarsigner(cmd + " -tsadigestalg SHA", 12, true);
333 checkTimestamp("new_12.jar", defaultPolicyId, "SHA-1");
334 } else { // Run as a standalone server
335 System.err.println("Press Enter to quit server");
336 System.in.read();
337 }
338 }
339 }
340
341 static void checkTimestamp(String file, String policyId, String digestAlg)
342 throws Exception {
343 try (JarFile jf = new JarFile(file)) {
344 JarEntry je = jf.getJarEntry("META-INF/OLD.RSA");
345 try (InputStream is = jf.getInputStream(je)) {
346 byte[] content = IOUtils.readFully(is, -1, true);
347 PKCS7 p7 = new PKCS7(content);
348 SignerInfo[] si = p7.getSignerInfos();
349 if (si == null || si.length == 0) {
350 throw new Exception("Not signed");
351 }
352 PKCS9Attribute p9 = si[0].getUnauthenticatedAttributes()
353 .getAttribute(PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID);
354 PKCS7 tsToken = new PKCS7((byte[]) p9.getValue());
355 TimestampToken tt =
356 new TimestampToken(tsToken.getContentInfo().getData());
357 if (!tt.getHashAlgorithm().toString().equals(digestAlg)) {
|