1 /*
2 * Copyright (c) 1996, 2016, 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
26 package sun.security.pkcs;
27
28 import java.io.OutputStream;
29 import java.io.IOException;
30 import java.math.BigInteger;
31 import java.security.CryptoPrimitive;
32 import java.security.InvalidKeyException;
33 import java.security.MessageDigest;
34 import java.security.NoSuchAlgorithmException;
35 import java.security.Principal;
36 import java.security.PublicKey;
37 import java.security.Signature;
38 import java.security.SignatureException;
39 import java.security.Timestamp;
40 import java.security.cert.CertificateException;
41 import java.security.cert.CertificateFactory;
42 import java.security.cert.CertPath;
43 import java.security.cert.X509Certificate;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.Collections;
47 import java.util.EnumSet;
48 import java.util.Set;
49
50 import sun.misc.HexDumpEncoder;
51 import sun.security.timestamp.TimestampToken;
52 import sun.security.util.Debug;
53 import sun.security.util.DerEncoder;
54 import sun.security.util.DerInputStream;
55 import sun.security.util.DerOutputStream;
56 import sun.security.util.DerValue;
57 import sun.security.util.DisabledAlgorithmConstraints;
58 import sun.security.util.KeyUtil;
59 import sun.security.util.ObjectIdentifier;
60 import sun.security.x509.AlgorithmId;
61 import sun.security.x509.X500Name;
62 import sun.security.x509.KeyUsageExtension;
63
64 /**
65 * A SignerInfo, as defined in PKCS#7's signedData type.
66 *
67 * @author Benjamin Renaud
68 */
69 public class SignerInfo implements DerEncoder {
70
71 // Digest and Signature restrictions
192 if (derin.available() != 0
193 && (byte)(derin.peekByte()) == (byte)0xA1) {
194 unauthenticatedAttributes =
195 new PKCS9Attributes(derin, true);// ignore unsupported attrs
196 }
197 }
198
199 // all done
200 if (derin.available() != 0) {
201 throw new ParsingException("extra data at the end");
202 }
203 }
204
205 public void encode(DerOutputStream out) throws IOException {
206
207 derEncode(out);
208 }
209
210 /**
211 * DER encode this object onto an output stream.
212 * Implements the <code>DerEncoder</code> interface.
213 *
214 * @param out
215 * the output stream on which to write the DER encoding.
216 *
217 * @exception IOException on encoding error.
218 */
219 public void derEncode(OutputStream out) throws IOException {
220 DerOutputStream seq = new DerOutputStream();
221 seq.putInteger(version);
222 DerOutputStream issuerAndSerialNumber = new DerOutputStream();
223 issuerName.encode(issuerAndSerialNumber);
224 issuerAndSerialNumber.putInteger(certificateSerialNumber);
225 seq.write(DerValue.tag_Sequence, issuerAndSerialNumber);
226
227 digestAlgorithmId.encode(seq);
228
229 // encode authenticated attributes if there are any
230 if (authenticatedAttributes != null)
231 authenticatedAttributes.encode((byte)0xA0, seq);
232
249 /*
250 * Returns the (user) certificate pertaining to this SignerInfo.
251 */
252 public X509Certificate getCertificate(PKCS7 block)
253 throws IOException
254 {
255 return block.getCertificate(certificateSerialNumber, issuerName);
256 }
257
258 /*
259 * Returns the certificate chain pertaining to this SignerInfo.
260 */
261 public ArrayList<X509Certificate> getCertificateChain(PKCS7 block)
262 throws IOException
263 {
264 X509Certificate userCert;
265 userCert = block.getCertificate(certificateSerialNumber, issuerName);
266 if (userCert == null)
267 return null;
268
269 ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
270 certList.add(userCert);
271
272 X509Certificate[] pkcsCerts = block.getCertificates();
273 if (pkcsCerts == null
274 || userCert.getSubjectDN().equals(userCert.getIssuerDN())) {
275 return certList;
276 }
277
278 Principal issuer = userCert.getIssuerDN();
279 int start = 0;
280 while (true) {
281 boolean match = false;
282 int i = start;
283 while (i < pkcsCerts.length) {
284 if (issuer.equals(pkcsCerts[i].getSubjectDN())) {
285 // next cert in chain found
286 certList.add(pkcsCerts[i]);
287 // if selected cert is self-signed, we're done
288 // constructing the chain
289 if (pkcsCerts[i].getSubjectDN().equals(
304 }
305 if (!match)
306 break;
307 }
308
309 return certList;
310 }
311
312 /* Returns null if verify fails, this signerInfo if
313 verify succeeds. */
314 SignerInfo verify(PKCS7 block, byte[] data)
315 throws NoSuchAlgorithmException, SignatureException {
316
317 try {
318
319 ContentInfo content = block.getContentInfo();
320 if (data == null) {
321 data = content.getContentBytes();
322 }
323
324 String digestAlgname = getDigestAlgorithmId().getName();
325
326 byte[] dataSigned;
327
328 // if there are authenticate attributes, get the message
329 // digest and compare it with the digest of data
330 if (authenticatedAttributes == null) {
331 dataSigned = data;
332 } else {
333
334 // first, check content type
335 ObjectIdentifier contentType = (ObjectIdentifier)
336 authenticatedAttributes.getAttributeValue(
337 PKCS9Attribute.CONTENT_TYPE_OID);
338 if (contentType == null ||
339 !contentType.equals((Object)content.contentType))
340 return null; // contentType does not match, bad SignerInfo
341
342 // now, check message digest
343 byte[] messageDigest = (byte[])
344 authenticatedAttributes.getAttributeValue(
345 PKCS9Attribute.MESSAGE_DIGEST_OID);
346
347 if (messageDigest == null) // fail if there is no message digest
348 return null;
349
350 // check that algorithm is not restricted
351 if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET,
352 digestAlgname, null)) {
353 throw new SignatureException("Digest check failed. " +
354 "Disabled algorithm used: " + digestAlgname);
355 }
356
357 MessageDigest md = MessageDigest.getInstance(digestAlgname);
358 byte[] computedMessageDigest = md.digest(data);
359
360 if (messageDigest.length != computedMessageDigest.length)
361 return null;
362 for (int i = 0; i < messageDigest.length; i++) {
363 if (messageDigest[i] != computedMessageDigest[i])
364 return null;
365 }
366
367 // message digest attribute matched
368 // digest of original data
369
370 // the data actually signed is the DER encoding of
371 // the authenticated attributes (tagged with
372 // the "SET OF" tag, not 0xA0).
373 dataSigned = authenticatedAttributes.getDerEncoding();
374 }
375
376 // put together digest algorithm and encryption algorithm
377 // to form signing algorithm
378 String encryptionAlgname =
379 getDigestEncryptionAlgorithmId().getName();
380
381 // Workaround: sometimes the encryptionAlgname is actually
382 // a signature name
383 String tmp = AlgorithmId.getEncAlgFromSigAlg(encryptionAlgname);
384 if (tmp != null) encryptionAlgname = tmp;
385 String algname = AlgorithmId.makeSigAlg(
386 digestAlgname, encryptionAlgname);
387
388 // check that algorithm is not restricted
389 if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, algname, null)) {
390 throw new SignatureException("Signature check failed. " +
391 "Disabled algorithm used: " + algname);
392 }
393
394 X509Certificate cert = getCertificate(block);
395 PublicKey key = cert.getPublicKey();
396 if (cert == null) {
397 return null;
398 }
399
400 // check if the public key is restricted
401 if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
402 throw new SignatureException("Public key check failed. " +
403 "Disabled key used: " +
404 KeyUtil.getKeySize(key) + " bit " +
405 key.getAlgorithm());
406 }
407
408 if (cert.hasUnsupportedCriticalExtension()) {
409 throw new SignatureException("Certificate has unsupported "
410 + "critical extension(s)");
411 }
412
413 // Make sure that if the usage of the key in the certificate is
414 // restricted, it can be used for digital signatures.
415 // XXX We may want to check for additional extensions in the
416 // future.
417 boolean[] keyUsageBits = cert.getKeyUsage();
418 if (keyUsageBits != null) {
502 * Returns the timestamp PKCS7 data unverified.
503 * @return a PKCS7 object
504 */
505 public PKCS7 getTsToken() throws IOException {
506 if (unauthenticatedAttributes == null) {
507 return null;
508 }
509 PKCS9Attribute tsTokenAttr =
510 unauthenticatedAttributes.getAttribute(
511 PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID);
512 if (tsTokenAttr == null) {
513 return null;
514 }
515 return new PKCS7((byte[])tsTokenAttr.getValue());
516 }
517
518 /*
519 * Extracts a timestamp from a PKCS7 SignerInfo.
520 *
521 * Examines the signer's unsigned attributes for a
522 * <tt>signatureTimestampToken</tt> attribute. If present,
523 * then it is parsed to extract the date and time at which the
524 * timestamp was generated.
525 *
526 * @param info A signer information element of a PKCS 7 block.
527 *
528 * @return A timestamp token or null if none is present.
529 * @throws IOException if an error is encountered while parsing the
530 * PKCS7 data.
531 * @throws NoSuchAlgorithmException if an error is encountered while
532 * verifying the PKCS7 object.
533 * @throws SignatureException if an error is encountered while
534 * verifying the PKCS7 object.
535 * @throws CertificateException if an error is encountered while generating
536 * the TSA's certpath.
537 */
538 public Timestamp getTimestamp()
539 throws IOException, NoSuchAlgorithmException, SignatureException,
540 CertificateException
541 {
542 if (timestamp != null || !hasTimestamp)
|
1 /*
2 * Copyright (c) 1996, 2017, 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
26 package sun.security.pkcs;
27
28 import java.io.OutputStream;
29 import java.io.IOException;
30 import java.math.BigInteger;
31 import java.security.CryptoPrimitive;
32 import java.security.InvalidKeyException;
33 import java.security.MessageDigest;
34 import java.security.NoSuchAlgorithmException;
35 import java.security.Principal;
36 import java.security.PublicKey;
37 import java.security.Signature;
38 import java.security.SignatureException;
39 import java.security.Timestamp;
40 import java.security.cert.CertPathValidatorException;
41 import java.security.cert.CertificateException;
42 import java.security.cert.CertificateFactory;
43 import java.security.cert.CertPath;
44 import java.security.cert.X509Certificate;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.EnumSet;
49 import java.util.Set;
50
51 import sun.misc.HexDumpEncoder;
52 import sun.security.timestamp.TimestampToken;
53 import sun.security.util.ConstraintsParameters;
54 import sun.security.util.Debug;
55 import sun.security.util.DerEncoder;
56 import sun.security.util.DerInputStream;
57 import sun.security.util.DerOutputStream;
58 import sun.security.util.DerValue;
59 import sun.security.util.DisabledAlgorithmConstraints;
60 import sun.security.util.KeyUtil;
61 import sun.security.util.ObjectIdentifier;
62 import sun.security.x509.AlgorithmId;
63 import sun.security.x509.X500Name;
64 import sun.security.x509.KeyUsageExtension;
65
66 /**
67 * A SignerInfo, as defined in PKCS#7's signedData type.
68 *
69 * @author Benjamin Renaud
70 */
71 public class SignerInfo implements DerEncoder {
72
73 // Digest and Signature restrictions
194 if (derin.available() != 0
195 && (byte)(derin.peekByte()) == (byte)0xA1) {
196 unauthenticatedAttributes =
197 new PKCS9Attributes(derin, true);// ignore unsupported attrs
198 }
199 }
200
201 // all done
202 if (derin.available() != 0) {
203 throw new ParsingException("extra data at the end");
204 }
205 }
206
207 public void encode(DerOutputStream out) throws IOException {
208
209 derEncode(out);
210 }
211
212 /**
213 * DER encode this object onto an output stream.
214 * Implements the {@code DerEncoder} interface.
215 *
216 * @param out
217 * the output stream on which to write the DER encoding.
218 *
219 * @exception IOException on encoding error.
220 */
221 public void derEncode(OutputStream out) throws IOException {
222 DerOutputStream seq = new DerOutputStream();
223 seq.putInteger(version);
224 DerOutputStream issuerAndSerialNumber = new DerOutputStream();
225 issuerName.encode(issuerAndSerialNumber);
226 issuerAndSerialNumber.putInteger(certificateSerialNumber);
227 seq.write(DerValue.tag_Sequence, issuerAndSerialNumber);
228
229 digestAlgorithmId.encode(seq);
230
231 // encode authenticated attributes if there are any
232 if (authenticatedAttributes != null)
233 authenticatedAttributes.encode((byte)0xA0, seq);
234
251 /*
252 * Returns the (user) certificate pertaining to this SignerInfo.
253 */
254 public X509Certificate getCertificate(PKCS7 block)
255 throws IOException
256 {
257 return block.getCertificate(certificateSerialNumber, issuerName);
258 }
259
260 /*
261 * Returns the certificate chain pertaining to this SignerInfo.
262 */
263 public ArrayList<X509Certificate> getCertificateChain(PKCS7 block)
264 throws IOException
265 {
266 X509Certificate userCert;
267 userCert = block.getCertificate(certificateSerialNumber, issuerName);
268 if (userCert == null)
269 return null;
270
271 ArrayList<X509Certificate> certList = new ArrayList<>();
272 certList.add(userCert);
273
274 X509Certificate[] pkcsCerts = block.getCertificates();
275 if (pkcsCerts == null
276 || userCert.getSubjectDN().equals(userCert.getIssuerDN())) {
277 return certList;
278 }
279
280 Principal issuer = userCert.getIssuerDN();
281 int start = 0;
282 while (true) {
283 boolean match = false;
284 int i = start;
285 while (i < pkcsCerts.length) {
286 if (issuer.equals(pkcsCerts[i].getSubjectDN())) {
287 // next cert in chain found
288 certList.add(pkcsCerts[i]);
289 // if selected cert is self-signed, we're done
290 // constructing the chain
291 if (pkcsCerts[i].getSubjectDN().equals(
306 }
307 if (!match)
308 break;
309 }
310
311 return certList;
312 }
313
314 /* Returns null if verify fails, this signerInfo if
315 verify succeeds. */
316 SignerInfo verify(PKCS7 block, byte[] data)
317 throws NoSuchAlgorithmException, SignatureException {
318
319 try {
320
321 ContentInfo content = block.getContentInfo();
322 if (data == null) {
323 data = content.getContentBytes();
324 }
325
326 ConstraintsParameters cparams =
327 new ConstraintsParameters(timestamp);
328 String digestAlgname = getDigestAlgorithmId().getName();
329
330 byte[] dataSigned;
331
332 // if there are authenticate attributes, get the message
333 // digest and compare it with the digest of data
334 if (authenticatedAttributes == null) {
335 dataSigned = data;
336 } else {
337
338 // first, check content type
339 ObjectIdentifier contentType = (ObjectIdentifier)
340 authenticatedAttributes.getAttributeValue(
341 PKCS9Attribute.CONTENT_TYPE_OID);
342 if (contentType == null ||
343 !contentType.equals((Object)content.contentType))
344 return null; // contentType does not match, bad SignerInfo
345
346 // now, check message digest
347 byte[] messageDigest = (byte[])
348 authenticatedAttributes.getAttributeValue(
349 PKCS9Attribute.MESSAGE_DIGEST_OID);
350
351 if (messageDigest == null) // fail if there is no message digest
352 return null;
353
354 // check that digest algorithm is not restricted
355 try {
356 JAR_DISABLED_CHECK.permits(digestAlgname, cparams);
357 } catch (CertPathValidatorException e) {
358 throw new SignatureException(e.getMessage(), e);
359 }
360
361 MessageDigest md = MessageDigest.getInstance(digestAlgname);
362 byte[] computedMessageDigest = md.digest(data);
363
364 if (messageDigest.length != computedMessageDigest.length)
365 return null;
366 for (int i = 0; i < messageDigest.length; i++) {
367 if (messageDigest[i] != computedMessageDigest[i])
368 return null;
369 }
370
371 // message digest attribute matched
372 // digest of original data
373
374 // the data actually signed is the DER encoding of
375 // the authenticated attributes (tagged with
376 // the "SET OF" tag, not 0xA0).
377 dataSigned = authenticatedAttributes.getDerEncoding();
378 }
379
380 // put together digest algorithm and encryption algorithm
381 // to form signing algorithm
382 String encryptionAlgname =
383 getDigestEncryptionAlgorithmId().getName();
384
385 // Workaround: sometimes the encryptionAlgname is actually
386 // a signature name
387 String tmp = AlgorithmId.getEncAlgFromSigAlg(encryptionAlgname);
388 if (tmp != null) encryptionAlgname = tmp;
389 String algname = AlgorithmId.makeSigAlg(
390 digestAlgname, encryptionAlgname);
391
392 // check that jar signature algorithm is not restricted
393 try {
394 JAR_DISABLED_CHECK.permits(algname, cparams);
395 } catch (CertPathValidatorException e) {
396 throw new SignatureException(e.getMessage(), e);
397 }
398
399 X509Certificate cert = getCertificate(block);
400 if (cert == null) {
401 return null;
402 }
403 PublicKey key = cert.getPublicKey();
404
405 // check if the public key is restricted
406 if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
407 throw new SignatureException("Public key check failed. " +
408 "Disabled key used: " +
409 KeyUtil.getKeySize(key) + " bit " +
410 key.getAlgorithm());
411 }
412
413 if (cert.hasUnsupportedCriticalExtension()) {
414 throw new SignatureException("Certificate has unsupported "
415 + "critical extension(s)");
416 }
417
418 // Make sure that if the usage of the key in the certificate is
419 // restricted, it can be used for digital signatures.
420 // XXX We may want to check for additional extensions in the
421 // future.
422 boolean[] keyUsageBits = cert.getKeyUsage();
423 if (keyUsageBits != null) {
507 * Returns the timestamp PKCS7 data unverified.
508 * @return a PKCS7 object
509 */
510 public PKCS7 getTsToken() throws IOException {
511 if (unauthenticatedAttributes == null) {
512 return null;
513 }
514 PKCS9Attribute tsTokenAttr =
515 unauthenticatedAttributes.getAttribute(
516 PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID);
517 if (tsTokenAttr == null) {
518 return null;
519 }
520 return new PKCS7((byte[])tsTokenAttr.getValue());
521 }
522
523 /*
524 * Extracts a timestamp from a PKCS7 SignerInfo.
525 *
526 * Examines the signer's unsigned attributes for a
527 * {@code signatureTimestampToken} attribute. If present,
528 * then it is parsed to extract the date and time at which the
529 * timestamp was generated.
530 *
531 * @param info A signer information element of a PKCS 7 block.
532 *
533 * @return A timestamp token or null if none is present.
534 * @throws IOException if an error is encountered while parsing the
535 * PKCS7 data.
536 * @throws NoSuchAlgorithmException if an error is encountered while
537 * verifying the PKCS7 object.
538 * @throws SignatureException if an error is encountered while
539 * verifying the PKCS7 object.
540 * @throws CertificateException if an error is encountered while generating
541 * the TSA's certpath.
542 */
543 public Timestamp getTimestamp()
544 throws IOException, NoSuchAlgorithmException, SignatureException,
545 CertificateException
546 {
547 if (timestamp != null || !hasTimestamp)
|