8155973: Tighten jar checks

Reviewed-by: mullan, igerasim, ahgross
This commit is contained in:
Anthony Scarpino 2016-07-21 10:33:56 -07:00
parent dd92b2d236
commit 941822bf15
8 changed files with 174 additions and 28 deletions

View File

@ -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 @@ package sun.security.pkcs;
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 @@ import sun.security.util.HexDumpEncoder;
*/
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 @@ public class SignerInfo implements DerEncoder {
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 @@ public class SignerInfo implements DerEncoder {
String algname = AlgorithmId.makeSigAlg(
digestAlgname, encryptionAlgname);
Signature sig = Signature.getInstance(algname);
X509Certificate cert = getCertificate(block);
// 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 @@ public class SignerInfo implements DerEncoder {
}
}
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 @@ public class SignerInfo implements DerEncoder {
*/
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))) {

View File

@ -60,6 +60,10 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
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 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
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);

View File

@ -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 @@ public class SignatureFileVerifier {
/** 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 @@ public class SignatureFileVerifier {
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 @@ public class SignatureFileVerifier {
private boolean verifyManifestMainAttrs(Manifest sf,
ManifestDigester md)
throws IOException
throws IOException, SignatureException
{
Attributes mattr = sf.getMainAttributes();
boolean attrsVerified = true;
@ -430,14 +460,14 @@ public class SignatureFileVerifier {
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) {

View File

@ -935,3 +935,42 @@ jdk.xml.dsig.secureValidationPolicy=\
# 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

View File

@ -88,6 +88,7 @@ fi
${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=$?

View File

@ -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=

View File

@ -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.io.FileInputStream;
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 @@ public class PKCS7VerifyTest {
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

View File

@ -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 @@ public class JarSigningNonAscii {
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", ".");