--- a/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java Mon Jul 18 08:28:48 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java Thu Jul 21 10:33:56 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -28,20 +28,37 @@
import java.io.OutputStream;
import java.io.IOException;
import java.math.BigInteger;
+import java.security.CryptoPrimitive;
+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.security.*;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
import sun.security.timestamp.TimestampToken;
-import sun.security.util.*;
+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.HexDumpEncoder;
+import sun.security.util.ObjectIdentifier;
import sun.security.x509.AlgorithmId;
import sun.security.x509.X500Name;
import sun.security.x509.KeyUsageExtension;
-import sun.security.util.HexDumpEncoder;
/**
* A SignerInfo, as defined in PKCS#7's signedData type.
@@ -50,6 +67,17 @@
*/
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;
@@ -318,6 +346,13 @@
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(digestAlgname);
byte[] computedMessageDigest = md.digest(data);
@@ -349,12 +384,24 @@
String algname = AlgorithmId.makeSigAlg(
digestAlgname, encryptionAlgname);
- Signature sig = Signature.getInstance(algname);
+ // 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 algorithm used: " + key.getAlgorithm());
+ }
+
if (cert.hasUnsupportedCriticalExtension()) {
throw new SignatureException("Certificate has unsupported "
+ "critical extension(s)");
@@ -391,11 +438,9 @@
}
}
- PublicKey key = cert.getPublicKey();
+ Signature sig = Signature.getInstance(algname);
sig.initVerify(key);
-
sig.update(dataSigned);
-
if (sig.verify(encryptedDigest)) {
return this;
}
@@ -515,9 +560,16 @@
*/
private void verifyTimestamp(TimestampToken token)
throws NoSuchAlgorithmException, SignatureException {
+ String digestAlgname = 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(token.getHashAlgorithm().getName());
+ MessageDigest.getInstance(digestAlgname);
if (!Arrays.equals(token.getHashedMessage(),
md.digest(encryptedDigest))) {
--- a/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java Mon Jul 18 08:28:48 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java Thu Jul 21 10:33:56 2016 -0700
@@ -60,6 +60,10 @@
public static final String PROPERTY_TLS_DISABLED_ALGS =
"jdk.tls.disabledAlgorithms";
+ // the known security property, jdk.jar.disabledAlgorithms
+ public static final String PROPERTY_JAR_DISABLED_ALGS =
+ "jdk.jar.disabledAlgorithms";
+
private final String[] disabledAlgorithms;
private final Constraints algorithmConstraints;
@@ -73,6 +77,14 @@
this(propertyName, new AlgorithmDecomposer());
}
+ /**
+ * Initialize algorithm constraints with the specified security property
+ * for a specific usage type.
+ *
+ * @param propertyName the security property name that define the disabled
+ * algorithm constraints
+ * @param decomposer an alternate AlgorithmDecomposer.
+ */
public DisabledAlgorithmConstraints(String propertyName,
AlgorithmDecomposer decomposer) {
super(decomposer);
--- a/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java Mon Jul 18 08:28:48 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java Thu Jul 21 10:33:56 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -25,26 +25,49 @@
package sun.security.util;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.CodeSigner;
+import java.security.CryptoPrimitive;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
import java.security.cert.CertPath;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
-import java.security.*;
-import java.io.*;
-import java.util.*;
-import java.util.jar.*;
-
-import sun.security.pkcs.*;
+import java.util.ArrayList;
import java.util.Base64;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarException;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
import sun.security.jca.Providers;
+import sun.security.pkcs.PKCS7;
+import sun.security.pkcs.SignerInfo;
public class SignatureFileVerifier {
/* Are we debugging ? */
private static final Debug debug = Debug.getInstance("jar");
- /* cache of CodeSigner objects */
+ private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET =
+ Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
+
+ private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK =
+ new DisabledAlgorithmConstraints(
+ DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
+
private ArrayList<CodeSigner[]> signerCache;
private static final String ATTR_DIGEST =
@@ -199,8 +222,15 @@
/** get digest from cache */
- private MessageDigest getDigest(String algorithm)
- {
+ private MessageDigest getDigest(String algorithm) throws SignatureException {
+ // check that algorithm is not restricted
+ if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, algorithm, null)) {
+ SignatureException e =
+ new SignatureException("SignatureFile check failed. " +
+ "Disabled algorithm used: " + algorithm);
+ throw e;
+ }
+
if (createdDigests == null)
createdDigests = new HashMap<>();
@@ -320,7 +350,7 @@
private boolean verifyManifestHash(Manifest sf,
ManifestDigester md,
List<Object> manifestDigests)
- throws IOException
+ throws IOException, SignatureException
{
Attributes mattr = sf.getMainAttributes();
boolean manifestSigned = false;
@@ -364,7 +394,7 @@
private boolean verifyManifestMainAttrs(Manifest sf,
ManifestDigester md)
- throws IOException
+ throws IOException, SignatureException
{
Attributes mattr = sf.getMainAttributes();
boolean attrsVerified = true;
@@ -430,14 +460,14 @@
private boolean verifySection(Attributes sfAttr,
String name,
ManifestDigester md)
- throws IOException
+ throws IOException, SignatureException
{
boolean oneDigestVerified = false;
ManifestDigester.Entry mde = md.get(name,block.isOldStyle());
if (mde == null) {
throw new SecurityException(
- "no manifiest section for signature file entry "+name);
+ "no manifest section for signature file entry "+name);
}
if (sfAttr != null) {
--- a/jdk/src/java.base/share/conf/security/java.security Mon Jul 18 08:28:48 2016 +0100
+++ b/jdk/src/java.base/share/conf/security/java.security Thu Jul 21 10:33:56 2016 -0700
@@ -935,3 +935,42 @@
# Otherwise, the status is UNDECIDED.
#
#jdk.serialFilter=pattern;pattern
+
+# Algorithm restrictions for signed JAR files
+#
+# In some environments, certain algorithms or key lengths may be undesirable
+# for signed JAR validation. For example, "MD2" is generally no longer
+# considered to be a secure hash algorithm. This section describes the
+# mechanism for disabling algorithms based on algorithm name and/or key length.
+# JARs signed with any of the disabled algorithms or key sizes will be treated
+# as unsigned.
+#
+# The syntax of the disabled algorithm string is described as follows:
+# DisabledAlgorithms:
+# " DisabledAlgorithm { , DisabledAlgorithm } "
+#
+# DisabledAlgorithm:
+# AlgorithmName [Constraint]
+#
+# AlgorithmName:
+# (see below)
+#
+# Constraint:
+# KeySizeConstraint
+#
+# KeySizeConstraint:
+# keySize Operator KeyLength
+#
+# Operator:
+# <= | < | == | != | >= | >
+#
+# KeyLength:
+# Integer value of the algorithm's key length in bits
+#
+# Note: This property is currently used by the JDK Reference
+# implementation. It is not guaranteed to be examined and used by other
+# implementations.
+#
+jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
+ DSA keySize < 1024
+
--- a/jdk/test/javax/crypto/SecretKeyFactory/FailOverTest.sh Mon Jul 18 08:28:48 2016 +0100
+++ b/jdk/test/javax/crypto/SecretKeyFactory/FailOverTest.sh Thu Jul 21 10:33:56 2016 -0700
@@ -88,6 +88,7 @@
${TESTJAVA}${FS}bin${FS}java \
${TESTVMOPTS} \
+ -Djava.security.properties=${TESTSRC}${FS}security.properties \
-classpath "${TESTSRC}${FS}P1.jar${PS}${TESTSRC}${FS}P2.jar${PS}." \
FailOverTest
result=$?
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/crypto/SecretKeyFactory/security.properties Thu Jul 21 10:33:56 2016 -0700
@@ -0,0 +1,6 @@
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+
+jdk.security.provider.preferred=
+jdk.jar.disabledAlgorithms=
+
--- a/jdk/test/sun/security/pkcs/pkcs7/PKCS7VerifyTest.java Mon Jul 18 08:28:48 2016 +0100
+++ b/jdk/test/sun/security/pkcs/pkcs7/PKCS7VerifyTest.java Thu Jul 21 10:33:56 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -27,8 +27,8 @@
* @summary Read signed data in one or more PKCS7 objects from individual files,
* verify SignerInfos and certificate chain.
* @modules java.base/sun.security.pkcs
- * @run main PKCS7VerifyTest PKCS7TEST.DSA.base64
- * @run main PKCS7VerifyTest PKCS7TEST.DSA.base64 PKCS7TEST.SF
+ * @run main/othervm PKCS7VerifyTest PKCS7TEST.DSA.base64
+ * @run main/othervm PKCS7VerifyTest PKCS7TEST.DSA.base64 PKCS7TEST.SF
*/
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -36,6 +36,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.HashMap;
@@ -55,6 +56,8 @@
throw new RuntimeException("usage: java JarVerify <file1> <file2>");
}
+ Security.setProperty("jdk.jar.disabledAlgorithms", "");
+
// The command " java PKCS7VerifyTest file1 [file2] "
// treats file1 as containing the DER encoding of a PKCS7 signed data
// object. If file2 is absent, the program verifies that some signature
--- a/jdk/test/sun/security/tools/jarsigner/JarSigningNonAscii.java Mon Jul 18 08:28:48 2016 +0100
+++ b/jdk/test/sun/security/tools/jarsigner/JarSigningNonAscii.java Thu Jul 21 10:33:56 2016 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -26,10 +26,12 @@
* @bug 4924188
* @summary sign a JAR file that has entry names with non-ASCII characters.
* @modules jdk.jartool/sun.security.tools.jarsigner
+ * @run main/othervm JarSigningNonAscii
*/
import sun.security.tools.*;
import java.io.*;
+import java.security.Security;
import java.util.*;
import java.util.jar.*;
import java.security.cert.Certificate;
@@ -40,6 +42,7 @@
private static String keystore;
public static void main(String[] args) throws Exception {
+ Security.setProperty("jdk.jar.disabledAlgorithms", "");
String srcDir = System.getProperty("test.src", ".");
String destDir = System.getProperty("test.classes", ".");