# HG changeset patch # User ascarpino # Date 1469122436 25200 # Node ID cc479488428c16aabbdbe87e6ac89f9979d8c9f2 # Parent c0fe2e6364d9b0af74a7004684c43c9227ec5efe 8155973: Tighten jar checks Reviewed-by: mullan, igerasim, ahgross diff -r c0fe2e6364d9 -r cc479488428c jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java --- 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 DIGEST_PRIMITIVE_SET = + Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST)); + + private static final Set 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))) { diff -r c0fe2e6364d9 -r cc479488428c jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java --- 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); diff -r c0fe2e6364d9 -r cc479488428c jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java --- 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 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 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 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) { diff -r c0fe2e6364d9 -r cc479488428c jdk/src/java.base/share/conf/security/java.security --- 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 + diff -r c0fe2e6364d9 -r cc479488428c jdk/test/javax/crypto/SecretKeyFactory/FailOverTest.sh --- 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=$? diff -r c0fe2e6364d9 -r cc479488428c jdk/test/javax/crypto/SecretKeyFactory/security.properties --- /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= + diff -r c0fe2e6364d9 -r cc479488428c jdk/test/sun/security/pkcs/pkcs7/PKCS7VerifyTest.java --- 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 "); } + 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 diff -r c0fe2e6364d9 -r cc479488428c jdk/test/sun/security/tools/jarsigner/JarSigningNonAscii.java --- 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", ".");