8155973: Tighten jar checks
Reviewed-by: mullan, igerasim, ahgross
This commit is contained in:
parent
dd92b2d236
commit
941822bf15
@ -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))) {
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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=$?
|
||||
|
@ -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=
|
||||
|
@ -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
|
||||
|
@ -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", ".");
|
||||
|
Loading…
Reference in New Issue
Block a user