History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/tools/TimestampedSigner.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/tools/TimestampedSigner.java+387−0
@@ -0,0 +1,387 @@
1/*
2 * Copyright (c) 2007, 2011, 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.security.tools;
27
28import java.io.ByteArrayOutputStream;
29import java.io.IOException;
30import java.math.BigInteger;
31import java.net.URI;
32import java.security.MessageDigest;
33import java.security.NoSuchAlgorithmException;
34import java.security.Principal;
35import java.security.SecureRandom;
36import java.security.cert.CertificateException;
37import java.security.cert.X509Certificate;
38import java.util.List;
39
40import com.sun.jarsigner.*;
41import java.util.Arrays;
42import sun.security.pkcs.*;
43import sun.security.timestamp.*;
44import sun.security.util.*;
45import sun.security.x509.*;
46
47/**
48 * This class implements a content signing service.
49 * It generates a timestamped signature for a given content according to
50 * <a href="http://www.ietf.org/rfc/rfc3161.txt">RFC 3161</a>.
51 * The signature along with a trusted timestamp and the signer's certificate
52 * are all packaged into a standard PKCS #7 Signed Data message.
53 *
54 * @author Vincent Ryan
55 */
56
57public final class TimestampedSigner extends ContentSigner {
58
59 /*
60 * Random number generator for creating nonce values
61 */
62 private static final SecureRandom RANDOM;
63 static {
64 SecureRandom tmp = null;
65 try {
66 tmp = SecureRandom.getInstance("SHA1PRNG");
67 } catch (NoSuchAlgorithmException e) {
68 // should not happen
69 }
70 RANDOM = tmp;
71 }
72
73 /*
74 * Object identifier for the subject information access X.509 certificate
75 * extension.
76 */
77 private static final String SUBJECT_INFO_ACCESS_OID = "1.3.6.1.5.5.7.1.11";
78
79 /*
80 * Object identifier for the timestamping key purpose.
81 */
82 private static final String KP_TIMESTAMPING_OID = "1.3.6.1.5.5.7.3.8";
83
84 /*
85 * Object identifier for extendedKeyUsage extension
86 */
87 private static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37";
88
89 /*
90 * Object identifier for the timestamping access descriptors.
91 */
92 private static final ObjectIdentifier AD_TIMESTAMPING_Id;
93 static {
94 ObjectIdentifier tmp = null;
95 try {
96 tmp = new ObjectIdentifier("1.3.6.1.5.5.7.48.3");
97 } catch (IOException e) {
98 // ignore
99 }
100 AD_TIMESTAMPING_Id = tmp;
101 }
102
103 /*
104 * Location of the TSA.
105 */
106 private String tsaUrl = null;
107
108 /*
109 * TSA's X.509 certificate.
110 */
111 private X509Certificate tsaCertificate = null;
112
113 /*
114 * Generates an SHA-1 hash value for the data to be timestamped.
115 */
116 private MessageDigest messageDigest = null;
117
118 /*
119 * Parameters for the timestamping protocol.
120 */
121 private boolean tsRequestCertificate = true;
122
123 /**
124 * Instantiates a content signer that supports timestamped signatures.
125 */
126 public TimestampedSigner() {
127 }
128
129 /**
130 * Generates a PKCS #7 signed data message that includes a signature
131 * timestamp.
132 * This method is used when a signature has already been generated.
133 * The signature, a signature timestamp, the signer's certificate chain,
134 * and optionally the content that was signed, are packaged into a PKCS #7
135 * signed data message.
136 *
137 * @param parameters The non-null input parameters.
138 * @param omitContent true if the content should be omitted from the
139 * signed data message. Otherwise the content is included.
140 * @param applyTimestamp true if the signature should be timestamped.
141 * Otherwise timestamping is not performed.
142 * @return A PKCS #7 signed data message including a signature timestamp.
143 * @throws NoSuchAlgorithmException The exception is thrown if the signature
144 * algorithm is unrecognised.
145 * @throws CertificateException The exception is thrown if an error occurs
146 * while processing the signer's certificate or the TSA's
147 * certificate.
148 * @throws IOException The exception is thrown if an error occurs while
149 * generating the signature timestamp or while generating the signed
150 * data message.
151 * @throws NullPointerException The exception is thrown if parameters is
152 * null.
153 */
154 public byte[] generateSignedData(ContentSignerParameters parameters,
155 boolean omitContent, boolean applyTimestamp)
156 throws NoSuchAlgorithmException, CertificateException, IOException {
157
158 if (parameters == null) {
159 throw new NullPointerException();
160 }
161
162 // Parse the signature algorithm to extract the digest and key
163 // algorithms. The expected format is:
164 // "<digest>with<encryption>"
165 // or "<digest>with<encryption>and<mgf>"
166 String signatureAlgorithm = parameters.getSignatureAlgorithm();
167 String keyAlgorithm =
168 AlgorithmId.getEncAlgFromSigAlg(signatureAlgorithm);
169 String digestAlgorithm =
170 AlgorithmId.getDigAlgFromSigAlg(signatureAlgorithm);
171 AlgorithmId digestAlgorithmId = AlgorithmId.get(digestAlgorithm);
172
173 // Examine signer's certificate
174 X509Certificate[] signerCertificateChain =
175 parameters.getSignerCertificateChain();
176 Principal issuerName = signerCertificateChain[0].getIssuerDN();
177 if (!(issuerName instanceof X500Name)) {
178 // must extract the original encoded form of DN for subsequent
179 // name comparison checks (converting to a String and back to
180 // an encoded DN could cause the types of String attribute
181 // values to be changed)
182 X509CertInfo tbsCert = new
183 X509CertInfo(signerCertificateChain[0].getTBSCertificate());
184 issuerName = (Principal)
185 tbsCert.get(CertificateIssuerName.NAME + "." +
186 CertificateIssuerName.DN_NAME);
187 }
188 BigInteger serialNumber = signerCertificateChain[0].getSerialNumber();
189
190 // Include or exclude content
191 byte[] content = parameters.getContent();
192 ContentInfo contentInfo;
193 if (omitContent) {
194 contentInfo = new ContentInfo(ContentInfo.DATA_OID, null);
195 } else {
196 contentInfo = new ContentInfo(content);
197 }
198
199 // Generate the timestamp token
200 byte[] signature = parameters.getSignature();
201 SignerInfo signerInfo = null;
202 if (applyTimestamp) {
203
204 tsaCertificate = parameters.getTimestampingAuthorityCertificate();
205 URI tsaUri = parameters.getTimestampingAuthority();
206 if (tsaUri != null) {
207 tsaUrl = tsaUri.toString();
208 } else {
209 // Examine TSA cert
210 String certUrl = getTimestampingUrl(tsaCertificate);
211 if (certUrl == null) {
212 throw new CertificateException(
213 "Subject Information Access extension not found");
214 }
215 tsaUrl = certUrl;
216 }
217
218 // Timestamp the signature
219 byte[] tsToken = generateTimestampToken(signature);
220
221 // Insert the timestamp token into the PKCS #7 signer info element
222 // (as an unsigned attribute)
223 PKCS9Attributes unsignedAttrs =
224 new PKCS9Attributes(new PKCS9Attribute[]{
225 new PKCS9Attribute(
226 PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_STR,
227 tsToken)});
228 signerInfo = new SignerInfo((X500Name)issuerName, serialNumber,
229 digestAlgorithmId, null, AlgorithmId.get(keyAlgorithm),
230 signature, unsignedAttrs);
231 } else {
232 signerInfo = new SignerInfo((X500Name)issuerName, serialNumber,
233 digestAlgorithmId, AlgorithmId.get(keyAlgorithm), signature);
234 }
235
236 SignerInfo[] signerInfos = {signerInfo};
237 AlgorithmId[] algorithms = {digestAlgorithmId};
238
239 // Create the PKCS #7 signed data message
240 PKCS7 p7 = new PKCS7(algorithms, contentInfo, signerCertificateChain,
241 null, signerInfos);
242 ByteArrayOutputStream p7out = new ByteArrayOutputStream();
243 p7.encodeSignedData(p7out);
244
245 return p7out.toByteArray();
246 }
247
248 /**
249 * Examine the certificate for a Subject Information Access extension
250 * (<a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280</a>).
251 * The extension's <tt>accessMethod</tt> field should contain the object
252 * identifier defined for timestamping: 1.3.6.1.5.5.7.48.3 and its
253 * <tt>accessLocation</tt> field should contain an HTTP or HTTPS URL.
254 *
255 * @param tsaCertificate An X.509 certificate for the TSA.
256 * @return An HTTP or HTTPS URL or null if none was found.
257 */
258 public static String getTimestampingUrl(X509Certificate tsaCertificate) {
259
260 if (tsaCertificate == null) {
261 return null;
262 }
263 // Parse the extensions
264 try {
265 byte[] extensionValue =
266 tsaCertificate.getExtensionValue(SUBJECT_INFO_ACCESS_OID);
267 if (extensionValue == null) {
268 return null;
269 }
270 DerInputStream der = new DerInputStream(extensionValue);
271 der = new DerInputStream(der.getOctetString());
272 DerValue[] derValue = der.getSequence(5);
273 AccessDescription description;
274 GeneralName location;
275 URIName uri;
276 for (int i = 0; i < derValue.length; i++) {
277 description = new AccessDescription(derValue[i]);
278 if (description.getAccessMethod().equals(AD_TIMESTAMPING_Id)) {
279 location = description.getAccessLocation();
280 if (location.getType() == GeneralNameInterface.NAME_URI) {
281 uri = (URIName) location.getName();
282 if (uri.getScheme().equalsIgnoreCase("http") ||
283 uri.getScheme().equalsIgnoreCase("https")) {
284 return uri.getName();
285 }
286 }
287 }
288 }
289 } catch (IOException ioe) {
290 // ignore
291 }
292 return null;
293 }
294
295 /*
296 * Returns a timestamp token from a TSA for the given content.
297 * Performs a basic check on the token to confirm that it has been signed
298 * by a certificate that is permitted to sign timestamps.
299 *
300 * @param toBeTimestamped The data to be timestamped.
301 * @throws IOException The exception is throw if an error occurs while
302 * communicating with the TSA.
303 * @throws CertificateException The exception is throw if the TSA's
304 * certificate is not permitted for timestamping.
305 */
306 private byte[] generateTimestampToken(byte[] toBeTimestamped)
307 throws CertificateException, IOException {
308
309 // Generate hash value for the data to be timestamped
310 // SHA-1 is always used.
311 if (messageDigest == null) {
312 try {
313 messageDigest = MessageDigest.getInstance("SHA-1");
314 } catch (NoSuchAlgorithmException e) {
315 // ignore
316 }
317 }
318 byte[] digest = messageDigest.digest(toBeTimestamped);
319
320 // Generate a timestamp
321 TSRequest tsQuery = new TSRequest(digest, "SHA-1");
322 // Generate a nonce
323 BigInteger nonce = null;
324 if (RANDOM != null) {
325 nonce = new BigInteger(64, RANDOM);
326 tsQuery.setNonce(nonce);
327 }
328 tsQuery.requestCertificate(tsRequestCertificate);
329
330 Timestamper tsa = new HttpTimestamper(tsaUrl); // use supplied TSA
331 TSResponse tsReply = tsa.generateTimestamp(tsQuery);
332 int status = tsReply.getStatusCode();
333 // Handle TSP error
334 if (status != 0 && status != 1) {
335 int failureCode = tsReply.getFailureCode();
336 if (failureCode == -1) {
337 throw new IOException("Error generating timestamp: " +
338 tsReply.getStatusCodeAsText());
339 } else {
340 throw new IOException("Error generating timestamp: " +
341 tsReply.getStatusCodeAsText() + " " +
342 tsReply.getFailureCodeAsText());
343 }
344 }
345 PKCS7 tsToken = tsReply.getToken();
346
347 TimestampToken tst = new TimestampToken(tsToken.getContentInfo().getData());
348 if (!tst.getHashAlgorithm().equals(
349 new AlgorithmId(new ObjectIdentifier("1.3.14.3.2.26")))) {
350 throw new IOException("Digest algorithm not SHA-1 in timestamp token");
351 }
352 if (!Arrays.equals(tst.getHashedMessage(), digest)) {
353 throw new IOException("Digest octets changed in timestamp token");
354 };
355
356 BigInteger replyNonce = tst.getNonce();
357 if (replyNonce == null && nonce != null) {
358 throw new IOException("Nonce missing in timestamp token");
359 }
360 if (replyNonce != null && !replyNonce.equals(nonce)) {
361 throw new IOException("Nonce changed in timestamp token");
362 }
363
364 // Examine the TSA's certificate (if present)
365 for (SignerInfo si: tsToken.getSignerInfos()) {
366 X509Certificate cert = si.getCertificate(tsToken);
367 if (cert == null) {
368 // Error, we've already set tsRequestCertificate = true
369 throw new CertificateException(
370 "Certificate not included in timestamp token");
371 } else {
372 if (!cert.getCriticalExtensionOIDs().contains(
373 EXTENDED_KEY_USAGE_OID)) {
374 throw new CertificateException(
375 "Certificate is not valid for timestamping");
376 }
377 List keyPurposes = cert.getExtendedKeyUsage();
378 if (keyPurposes == null ||
379 ! keyPurposes.contains(KP_TIMESTAMPING_OID)) {
380 throw new CertificateException(
381 "Certificate is not valid for timestamping");
382 }
383 }
384 }
385 return tsReply.getEncodedToken();
386 }
387}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t