< prev index next >
src/share/classes/sun/security/pkcs/SignerInfo.java
Print this page
rev 1455 : 6870812: enhance security tools to use ECC algorithms
Reviewed-by: vinnie, mullan
rev 1462 : 7180907: Jarsigner -verify fails if rsa file used sha-256 with authenticated attributes
Reviewed-by: xuelei, vinnie
rev 1514 : 8049480: Current versions of Java can't verify jars signed and timestamped with Java 9
Reviewed-by: xuelei, mullan
rev 1518 : 7102686: Restructure timestamp code so that jars and modules can more easily share the same code
Reviewed-by: mchung
rev 1547 : 8155973: Tighten jar checks
Reviewed-by: mullan, igerasim, ahgross
rev 1590 : 8165816: jarsigner -verify shows jar unsigned if it was signed with a weak algorithm
Reviewed-by: mullan
*** 1,7 ****
/*
! * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 26,58 ****
package sun.security.pkcs;
import java.io.OutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.cert.X509Certificate;
- import java.security.*;
import java.util.ArrayList;
! import sun.security.util.*;
import sun.security.x509.AlgorithmId;
import sun.security.x509.X500Name;
import sun.security.x509.KeyUsageExtension;
- import sun.misc.HexDumpEncoder;
/**
* A SignerInfo, as defined in PKCS#7's signedData type.
*
* @author Benjamin Renaud
*/
public class SignerInfo implements DerEncoder {
BigInteger version;
X500Name issuerName;
BigInteger certificateSerialNumber;
AlgorithmId digestAlgorithmId;
AlgorithmId digestEncryptionAlgorithmId;
byte[] encryptedDigest;
PKCS9Attributes authenticatedAttributes;
PKCS9Attributes unauthenticatedAttributes;
public SignerInfo(X500Name issuerName,
--- 26,95 ----
package sun.security.pkcs;
import java.io.OutputStream;
import java.io.IOException;
import java.math.BigInteger;
+ import java.security.InvalidKeyException;
+ import java.security.MessageDigest;
+ import java.security.NoSuchAlgorithmException;
+ import java.security.Principal;
+ import java.security.PublicKey;
+ import java.security.Signature;
+ import java.security.SignatureException;
+ import java.security.Timestamp;
+ import java.security.cert.CertificateException;
+ import java.security.cert.CertificateFactory;
+ import java.security.cert.CertPath;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
+ import java.util.Arrays;
+ import java.util.Collections;
+ import java.util.EnumSet;
+ import java.util.Set;
! import sun.misc.HexDumpEncoder;
! import sun.security.timestamp.TimestampToken;
! import sun.security.util.CryptoPrimitive;
! import sun.security.util.Debug;
! import sun.security.util.DerEncoder;
! import sun.security.util.DerInputStream;
! import sun.security.util.DerOutputStream;
! import sun.security.util.DerValue;
! import sun.security.util.DisabledAlgorithmConstraints;
! import sun.security.util.KeyUtil;
! import sun.security.util.ObjectIdentifier;
import sun.security.x509.AlgorithmId;
import sun.security.x509.X500Name;
import sun.security.x509.KeyUsageExtension;
/**
* A SignerInfo, as defined in PKCS#7's signedData type.
*
* @author Benjamin Renaud
*/
public class SignerInfo implements DerEncoder {
+ // Digest and Signature restrictions
+ private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET =
+ Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
+
+ private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET =
+ Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
+
+ private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK =
+ new DisabledAlgorithmConstraints(
+ DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
+
BigInteger version;
X500Name issuerName;
BigInteger certificateSerialNumber;
AlgorithmId digestAlgorithmId;
AlgorithmId digestEncryptionAlgorithmId;
byte[] encryptedDigest;
+ Timestamp timestamp;
+ private boolean hasTimestamp = true;
+ private static final Debug debug = Debug.getInstance("jar");
PKCS9Attributes authenticatedAttributes;
PKCS9Attributes unauthenticatedAttributes;
public SignerInfo(X500Name issuerName,
*** 283,294 ****
if (data == null) {
data = content.getContentBytes();
}
String digestAlgname = getDigestAlgorithmId().getName();
- if (digestAlgname.equalsIgnoreCase("SHA"))
- digestAlgname = "SHA1";
byte[] dataSigned;
// if there are authenticate attributes, get the message
// digest and compare it with the digest of data
--- 320,329 ----
*** 310,320 ****
PKCS9Attribute.MESSAGE_DIGEST_OID);
if (messageDigest == null) // fail if there is no message digest
return null;
! MessageDigest md = MessageDigest.getInstance(digestAlgname);
byte[] computedMessageDigest = md.digest(data);
if (messageDigest.length != computedMessageDigest.length)
return null;
for (int i = 0; i < messageDigest.length; i++) {
--- 345,363 ----
PKCS9Attribute.MESSAGE_DIGEST_OID);
if (messageDigest == null) // fail if there is no message digest
return null;
! // check that algorithm is not restricted
! if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET,
! digestAlgname, null)) {
! throw new SignatureException("Digest check failed. " +
! "Disabled algorithm used: " + digestAlgname);
! }
!
! MessageDigest md = MessageDigest.getInstance(
! AlgorithmId.getStandardDigestName(digestAlgname));
byte[] computedMessageDigest = md.digest(data);
if (messageDigest.length != computedMessageDigest.length)
return null;
for (int i = 0; i < messageDigest.length; i++) {
*** 334,353 ****
// put together digest algorithm and encryption algorithm
// to form signing algorithm
String encryptionAlgname =
getDigestEncryptionAlgorithmId().getName();
! if (encryptionAlgname.equalsIgnoreCase("SHA1withDSA"))
! encryptionAlgname = "DSA";
! String algname = digestAlgname + "with" + encryptionAlgname;
- Signature sig = Signature.getInstance(algname);
X509Certificate cert = getCertificate(block);
!
if (cert == null) {
return null;
}
if (cert.hasUnsupportedCriticalExtension()) {
throw new SignatureException("Certificate has unsupported "
+ "critical extension(s)");
}
--- 377,413 ----
// put together digest algorithm and encryption algorithm
// to form signing algorithm
String encryptionAlgname =
getDigestEncryptionAlgorithmId().getName();
! // Workaround: sometimes the encryptionAlgname is actually
! // a signature name
! String tmp = AlgorithmId.getEncAlgFromSigAlg(encryptionAlgname);
! if (tmp != null) encryptionAlgname = tmp;
! String algname = AlgorithmId.makeSigAlg(
! digestAlgname, encryptionAlgname);
!
! // check that algorithm is not restricted
! if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, algname, null)) {
! throw new SignatureException("Signature check failed. " +
! "Disabled algorithm used: " + algname);
! }
X509Certificate cert = getCertificate(block);
! PublicKey key = cert.getPublicKey();
if (cert == null) {
return null;
}
+
+ // check if the public key is restricted
+ if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
+ throw new SignatureException("Public key check failed. " +
+ "Disabled key used: " +
+ KeyUtil.getKeySize(key) + " bit " +
+ key.getAlgorithm());
+ }
+
if (cert.hasUnsupportedCriticalExtension()) {
throw new SignatureException("Certificate has unsupported "
+ "critical extension(s)");
}
*** 380,394 ****
+ "cannot be used for "
+ "digital signatures");
}
}
! PublicKey key = cert.getPublicKey();
sig.initVerify(key);
-
sig.update(dataSigned);
-
if (sig.verify(encryptedDigest)) {
return this;
}
} catch (IOException e) {
--- 440,452 ----
+ "cannot be used for "
+ "digital signatures");
}
}
! Signature sig = Signature.getInstance(algname);
sig.initVerify(key);
sig.update(dataSigned);
if (sig.verify(encryptedDigest)) {
return this;
}
} catch (IOException e) {
*** 439,448 ****
--- 497,599 ----
public PKCS9Attributes getUnauthenticatedAttributes() {
return unauthenticatedAttributes;
}
+ /*
+ * Extracts a timestamp from a PKCS7 SignerInfo.
+ *
+ * Examines the signer's unsigned attributes for a
+ * <tt>signatureTimestampToken</tt> attribute. If present,
+ * then it is parsed to extract the date and time at which the
+ * timestamp was generated.
+ *
+ * @param info A signer information element of a PKCS 7 block.
+ *
+ * @return A timestamp token or null if none is present.
+ * @throws IOException if an error is encountered while parsing the
+ * PKCS7 data.
+ * @throws NoSuchAlgorithmException if an error is encountered while
+ * verifying the PKCS7 object.
+ * @throws SignatureException if an error is encountered while
+ * verifying the PKCS7 object.
+ * @throws CertificateException if an error is encountered while generating
+ * the TSA's certpath.
+ */
+ public Timestamp getTimestamp()
+ throws IOException, NoSuchAlgorithmException, SignatureException,
+ CertificateException
+ {
+ if (timestamp != null || !hasTimestamp)
+ return timestamp;
+
+ if (unauthenticatedAttributes == null) {
+ hasTimestamp = false;
+ return null;
+ }
+ PKCS9Attribute tsTokenAttr =
+ unauthenticatedAttributes.getAttribute(
+ PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID);
+ if (tsTokenAttr == null) {
+ hasTimestamp = false;
+ return null;
+ }
+
+ PKCS7 tsToken = new PKCS7((byte[])tsTokenAttr.getValue());
+ // Extract the content (an encoded timestamp token info)
+ byte[] encTsTokenInfo = tsToken.getContentInfo().getData();
+ // Extract the signer (the Timestamping Authority)
+ // while verifying the content
+ SignerInfo[] tsa = tsToken.verify(encTsTokenInfo);
+ // Expect only one signer
+ ArrayList<X509Certificate> chain = tsa[0].getCertificateChain(tsToken);
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ CertPath tsaChain = cf.generateCertPath(chain);
+ // Create a timestamp token info object
+ TimestampToken tsTokenInfo = new TimestampToken(encTsTokenInfo);
+ // Check that the signature timestamp applies to this signature
+ verifyTimestamp(tsTokenInfo);
+ // Create a timestamp object
+ timestamp = new Timestamp(tsTokenInfo.getDate(), tsaChain);
+ return timestamp;
+ }
+
+ /*
+ * Check that the signature timestamp applies to this signature.
+ * Match the hash present in the signature timestamp token against the hash
+ * of this signature.
+ */
+ private void verifyTimestamp(TimestampToken token)
+ throws NoSuchAlgorithmException, SignatureException {
+ String digestAlgname =
+ AlgorithmId.getStandardDigestName(token.getHashAlgorithm().getName());
+ // check that algorithm is not restricted
+ if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, digestAlgname,
+ null)) {
+ throw new SignatureException("Timestamp token digest check failed. " +
+ "Disabled algorithm used: " + digestAlgname);
+ }
+
+ MessageDigest md =
+ MessageDigest.getInstance(digestAlgname);
+
+ if (!Arrays.equals(token.getHashedMessage(),
+ md.digest(encryptedDigest))) {
+
+ throw new SignatureException("Signature timestamp (#" +
+ token.getSerialNumber() + ") generated on " + token.getDate() +
+ " is inapplicable");
+ }
+
+ if (debug != null) {
+ debug.println();
+ debug.println("Detected signature timestamp (#" +
+ token.getSerialNumber() + ") generated on " + token.getDate());
+ debug.println();
+ }
+ }
+
public String toString() {
HexDumpEncoder hexDump = new HexDumpEncoder();
String out = "";
*** 464,470 ****
out += "\tunauthenticatedAttributes: " +
unauthenticatedAttributes + "\n";
}
return out;
}
-
}
--- 615,620 ----
< prev index next >