diff options
Diffstat (limited to 'src')
17 files changed, 528 insertions, 103 deletions
diff --git a/src/share/classes/java/lang/Class.java b/src/share/classes/java/lang/Class.java index ea47cca2f..d400a6ac5 100644 --- a/src/share/classes/java/lang/Class.java +++ b/src/share/classes/java/lang/Class.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2014, 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 @@ -256,8 +256,8 @@ public final class Class<T> implements java.io.Serializable, @CallerSensitive public static Class<?> forName(String className) throws ClassNotFoundException { - return forName0(className, true, - ClassLoader.getClassLoader(Reflection.getCallerClass())); + Class<?> caller = Reflection.getCallerClass(); + return forName0(className, true, ClassLoader.getClassLoader(caller), caller); } @@ -327,22 +327,27 @@ public final class Class<T> implements java.io.Serializable, ClassLoader loader) throws ClassNotFoundException { - if (sun.misc.VM.isSystemDomainLoader(loader)) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - ClassLoader ccl = ClassLoader.getClassLoader(Reflection.getCallerClass()); + Class<?> caller = null; + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + // Reflective call to get caller class is only needed if a security manager + // is present. Avoid the overhead of making this call otherwise. + caller = Reflection.getCallerClass(); + if (sun.misc.VM.isSystemDomainLoader(loader)) { + ClassLoader ccl = ClassLoader.getClassLoader(caller); if (!sun.misc.VM.isSystemDomainLoader(ccl)) { sm.checkPermission( SecurityConstants.GET_CLASSLOADER_PERMISSION); } } } - return forName0(name, initialize, loader); + return forName0(name, initialize, loader, caller); } - /** Called after security checks have been made. */ + /** Called after security check for system loader access checks have been made. */ private static native Class<?> forName0(String name, boolean initialize, - ClassLoader loader) + ClassLoader loader, + Class<?> caller) throws ClassNotFoundException; /** diff --git a/src/share/classes/java/lang/invoke/MethodType.java b/src/share/classes/java/lang/invoke/MethodType.java index c26460048..08c17d789 100644 --- a/src/share/classes/java/lang/invoke/MethodType.java +++ b/src/share/classes/java/lang/invoke/MethodType.java @@ -653,7 +653,7 @@ class MethodType implements java.io.Serializable { * @return the parameter types (as an immutable list) */ public List<Class<?>> parameterList() { - return Collections.unmodifiableList(Arrays.asList(ptypes)); + return Collections.unmodifiableList(Arrays.asList(ptypes.clone())); } /*non-public*/ Class<?> lastParameterType() { diff --git a/src/share/classes/java/security/Signature.java b/src/share/classes/java/security/Signature.java index 7c5bd96eb..939428412 100644 --- a/src/share/classes/java/security/Signature.java +++ b/src/share/classes/java/security/Signature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2014, 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 @@ -590,6 +590,9 @@ public abstract class Signature extends SignatureSpi { if (outbuf == null) { throw new IllegalArgumentException("No output buffer given"); } + if (offset < 0 || len < 0) { + throw new IllegalArgumentException("offset or len is less than 0"); + } if (outbuf.length - offset < len) { throw new IllegalArgumentException ("Output buffer too small for specified offset and length"); @@ -658,9 +661,16 @@ public abstract class Signature extends SignatureSpi { public final boolean verify(byte[] signature, int offset, int length) throws SignatureException { if (state == VERIFY) { - if ((signature == null) || (offset < 0) || (length < 0) || - (length > signature.length - offset)) { - throw new IllegalArgumentException("Bad arguments"); + if (signature == null) { + throw new IllegalArgumentException("signature is null"); + } + if (offset < 0 || length < 0) { + throw new IllegalArgumentException + ("offset or length is less than 0"); + } + if (signature.length - offset < length) { + throw new IllegalArgumentException + ("signature too small for specified offset and length"); } return engineVerify(signature, offset, length); @@ -713,6 +723,16 @@ public abstract class Signature extends SignatureSpi { public final void update(byte[] data, int off, int len) throws SignatureException { if (state == SIGN || state == VERIFY) { + if (data == null) { + throw new IllegalArgumentException("data is null"); + } + if (off < 0 || len < 0) { + throw new IllegalArgumentException("off or len is less than 0"); + } + if (data.length - off < len) { + throw new IllegalArgumentException + ("data too small for specified offset and length"); + } engineUpdate(data, off, len); } else { throw new SignatureException("object not initialized for " diff --git a/src/share/classes/java/security/cert/CertificateRevokedException.java b/src/share/classes/java/security/cert/CertificateRevokedException.java index a54562706..505a007f5 100644 --- a/src/share/classes/java/security/cert/CertificateRevokedException.java +++ b/src/share/classes/java/security/cert/CertificateRevokedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2014, 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 @@ -94,7 +94,10 @@ public class CertificateRevokedException extends CertificateException { this.revocationDate = new Date(revocationDate.getTime()); this.reason = reason; this.authority = authority; - this.extensions = new HashMap<String, Extension>(extensions); + // make sure Map only contains correct types + this.extensions = Collections.checkedMap(new HashMap<>(), + String.class, Extension.class); + this.extensions.putAll(extensions); } /** @@ -172,7 +175,8 @@ public class CertificateRevokedException extends CertificateException { public String getMessage() { return "Certificate has been revoked, reason: " + reason + ", revocation date: " + revocationDate - + ", authority: " + authority + ", extensions: " + extensions; + + ", authority: " + authority + ", extension OIDs: " + + extensions.keySet(); } /** diff --git a/src/share/classes/java/util/logging/Logger.java b/src/share/classes/java/util/logging/Logger.java index 90cbb87e1..4629320c1 100644 --- a/src/share/classes/java/util/logging/Logger.java +++ b/src/share/classes/java/util/logging/Logger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2014, 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 @@ -1934,6 +1934,9 @@ public class Logger { } setCallersClassLoaderRef(callersClass); + if (isSystemLogger && getCallersClassLoader() != null) { + checkPermission(); + } if (findResourceBundle(name, true) == null) { // We've failed to find an expected ResourceBundle. // unset the caller's ClassLoader since we were unable to find the @@ -2168,11 +2171,13 @@ public class Logger { return trb; } final String rbName = isSystemLogger - ? trb.resourceBundleName + // ancestor of a system logger is expected to be a system logger. + // ignore resource bundle name if it's not. + ? (target.isSystemLogger ? trb.resourceBundleName : null) : target.getResourceBundleName(); if (rbName != null) { return LoggerBundle.get(rbName, - findResourceBundle(rbName, true)); + findResourceBundle(rbName, true)); } target = isSystemLogger ? target.parent : target.getParent(); } diff --git a/src/share/classes/javax/crypto/CipherInputStream.java b/src/share/classes/javax/crypto/CipherInputStream.java index 0e80a6013..d777ca003 100644 --- a/src/share/classes/javax/crypto/CipherInputStream.java +++ b/src/share/classes/javax/crypto/CipherInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -88,6 +88,8 @@ public class CipherInputStream extends FilterInputStream { private int ofinish = 0; // stream status private boolean closed = false; + // The stream has been read from. False if the stream has never been read. + private boolean read = false; /** * private convenience function. @@ -103,13 +105,15 @@ public class CipherInputStream extends FilterInputStream { private int getMoreData() throws IOException { if (done) return -1; int readin = input.read(ibuffer); + read = true; if (readin == -1) { done = true; try { obuffer = cipher.doFinal(); + } catch (IllegalBlockSizeException | BadPaddingException e) { + obuffer = null; + throw new IOException(e); } - catch (IllegalBlockSizeException e) {obuffer = null;} - catch (BadPaddingException e) {obuffer = null;} if (obuffer == null) return -1; else { @@ -120,7 +124,10 @@ public class CipherInputStream extends FilterInputStream { } try { obuffer = cipher.update(ibuffer, 0, readin); - } catch (IllegalStateException e) {obuffer = null;}; + } catch (IllegalStateException e) { + obuffer = null; + throw e; + } ostart = 0; if (obuffer == null) ofinish = 0; @@ -308,6 +315,11 @@ public class CipherInputStream extends FilterInputStream { } } catch (BadPaddingException | IllegalBlockSizeException ex) { + /* If no data has been read from the stream to be en/decrypted, + we supress any exceptions, and close quietly. */ + if (read) { + throw new IOException(ex); + } } ostart = 0; ofinish = 0; diff --git a/src/share/classes/sun/awt/image/BytePackedRaster.java b/src/share/classes/sun/awt/image/BytePackedRaster.java index bd3835d51..3e60f193a 100644 --- a/src/share/classes/sun/awt/image/BytePackedRaster.java +++ b/src/share/classes/sun/awt/image/BytePackedRaster.java @@ -1408,10 +1408,10 @@ public class BytePackedRaster extends SunWritableRaster { } } - int lastbit = (dataBitOffset - + (height-1) * scanlineStride * 8 - + (width-1) * pixelBitStride - + pixelBitStride - 1); + long lastbit = (long) dataBitOffset + + (long) (height - 1) * (long) scanlineStride * 8 + + (long) (width - 1) * (long) pixelBitStride + + (long) pixelBitStride - 1; if (lastbit < 0 || lastbit / 8 >= data.length) { throw new RasterFormatException("raster dimensions overflow " + "array bounds"); diff --git a/src/share/classes/sun/invoke/util/VerifyAccess.java b/src/share/classes/sun/invoke/util/VerifyAccess.java index a95aefbaf..fc870fc94 100644 --- a/src/share/classes/sun/invoke/util/VerifyAccess.java +++ b/src/share/classes/sun/invoke/util/VerifyAccess.java @@ -102,19 +102,24 @@ public class VerifyAccess { case PUBLIC: return true; // already checked above case PROTECTED: + assert !defc.isInterface(); // protected members aren't allowed in interfaces if ((allowedModes & PROTECTED_OR_PACKAGE_ALLOWED) != 0 && isSamePackage(defc, lookupClass)) return true; if ((allowedModes & PROTECTED) == 0) return false; + // Protected members are accessible by subclasses, which does not include interfaces. + // Interfaces are types, not classes. They should not have access to + // protected members in j.l.Object, even though it is their superclass. if ((mods & STATIC) != 0 && !isRelatedClass(refc, lookupClass)) return false; if ((allowedModes & PROTECTED) != 0 && - isSuperClass(defc, lookupClass)) + isSubClass(lookupClass, defc)) return true; return false; case PACKAGE_ONLY: // That is, zero. Unmarked member is package-only access. + assert !defc.isInterface(); // package-private members aren't allowed in interfaces return ((allowedModes & PACKAGE_ALLOWED) != 0 && isSamePackage(defc, lookupClass)); case PRIVATE: @@ -129,12 +134,13 @@ public class VerifyAccess { static boolean isRelatedClass(Class<?> refc, Class<?> lookupClass) { return (refc == lookupClass || - refc.isAssignableFrom(lookupClass) || - lookupClass.isAssignableFrom(refc)); + isSubClass(refc, lookupClass) || + isSubClass(lookupClass, refc)); } - static boolean isSuperClass(Class<?> defc, Class<?> lookupClass) { - return defc.isAssignableFrom(lookupClass); + static boolean isSubClass(Class<?> lookupClass, Class<?> defc) { + return defc.isAssignableFrom(lookupClass) && + !lookupClass.isInterface(); // interfaces are types, not classes. } static int getClassModifiers(Class<?> c) { diff --git a/src/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java b/src/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java index 6e73de70d..120fe7aac 100644 --- a/src/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java +++ b/src/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -29,7 +29,6 @@ import java.lang.annotation.*; import java.lang.reflect.*; import java.io.Serializable; import java.util.*; -import java.lang.annotation.*; import java.security.AccessController; import java.security.PrivilegedAction; @@ -45,6 +44,11 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { private final Map<String, Object> memberValues; AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) { + Class<?>[] superInterfaces = type.getInterfaces(); + if (!type.isAnnotation() || + superInterfaces.length != 1 || + superInterfaces[0] != java.lang.annotation.Annotation.class) + throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type."); this.type = type; this.memberValues = memberValues; } @@ -57,13 +61,17 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { if (member.equals("equals") && paramTypes.length == 1 && paramTypes[0] == Object.class) return equalsImpl(args[0]); - assert paramTypes.length == 0; - if (member.equals("toString")) + if (paramTypes.length != 0) + throw new AssertionError("Too many parameters for an annotation method"); + + switch(member) { + case "toString": return toStringImpl(); - if (member.equals("hashCode")) + case "hashCode": return hashCodeImpl(); - if (member.equals("annotationType")) + case "annotationType": return type; + } // Handle annotation member accessors Object result = memberValues.get(member); @@ -129,7 +137,7 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { * Implementation of dynamicProxy.toString() */ private String toStringImpl() { - StringBuffer result = new StringBuffer(128); + StringBuilder result = new StringBuilder(128); result.append('@'); result.append(type.getName()); result.append('('); @@ -277,6 +285,7 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { new PrivilegedAction<Method[]>() { public Method[] run() { final Method[] mm = type.getDeclaredMethods(); + validateAnnotationMethods(mm); AccessibleObject.setAccessible(mm, true); return mm; } @@ -287,6 +296,94 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { private transient volatile Method[] memberMethods = null; /** + * Validates that a method is structurally appropriate for an + * annotation type. As of Java SE 8, annotation types cannot + * contain static methods and the declared methods of an + * annotation type must take zero arguments and there are + * restrictions on the return type. + */ + private void validateAnnotationMethods(Method[] memberMethods) { + /* + * Specification citations below are from JLS + * 9.6.1. Annotation Type Elements + */ + boolean valid = true; + for(Method method : memberMethods) { + /* + * "By virtue of the AnnotationTypeElementDeclaration + * production, a method declaration in an annotation type + * declaration cannot have formal parameters, type + * parameters, or a throws clause. + * + * "By virtue of the AnnotationTypeElementModifier + * production, a method declaration in an annotation type + * declaration cannot be default or static." + */ + if (method.getModifiers() != (Modifier.PUBLIC | Modifier.ABSTRACT) || + method.isDefault() || + method.getParameterCount() != 0 || + method.getExceptionTypes().length != 0) { + valid = false; + break; + } + + /* + * "It is a compile-time error if the return type of a + * method declared in an annotation type is not one of the + * following: a primitive type, String, Class, any + * parameterized invocation of Class, an enum type + * (section 8.9), an annotation type, or an array type + * (chapter 10) whose element type is one of the preceding + * types." + */ + Class<?> returnType = method.getReturnType(); + if (returnType.isArray()) { + returnType = returnType.getComponentType(); + if (returnType.isArray()) { // Only single dimensional arrays + valid = false; + break; + } + } + + if (!((returnType.isPrimitive() && returnType != void.class) || + returnType == java.lang.String.class || + returnType == java.lang.Class.class || + returnType.isEnum() || + returnType.isAnnotation())) { + valid = false; + break; + } + + /* + * "It is a compile-time error if any method declared in an + * annotation type has a signature that is + * override-equivalent to that of any public or protected + * method declared in class Object or in the interface + * java.lang.annotation.Annotation." + * + * The methods in Object or Annotation meeting the other + * criteria (no arguments, contrained return type, etc.) + * above are: + * + * String toString() + * int hashCode() + * Class<? extends Annotation> annotationType() + */ + String methodName = method.getName(); + if ((methodName.equals("toString") && returnType == java.lang.String.class) || + (methodName.equals("hashCode") && returnType == int.class) || + (methodName.equals("annotationType") && returnType == java.lang.Class.class)) { + valid = false; + break; + } + } + if (valid) + return; + else + throw new AnnotationFormatError("Malformed method on an annotation type"); + } + + /** * Implementation of dynamicProxy.hashCode() */ private int hashCodeImpl() { @@ -330,7 +427,6 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); - // Check to make sure that types have not evolved incompatibly AnnotationType annotationType = null; @@ -343,7 +439,6 @@ class AnnotationInvocationHandler implements InvocationHandler, Serializable { Map<String, Class<?>> memberTypes = annotationType.memberTypes(); - // If there are annotation members without values, that // situation is handled by the invoke method. for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) { diff --git a/src/share/classes/sun/security/ssl/ClientHandshaker.java b/src/share/classes/sun/security/ssl/ClientHandshaker.java index 5c3abbcda..5108528f2 100644 --- a/src/share/classes/sun/security/ssl/ClientHandshaker.java +++ b/src/share/classes/sun/security/ssl/ClientHandshaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2014, 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 @@ -36,6 +36,8 @@ import java.security.spec.ECParameterSpec; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; +import java.security.cert.CertificateParsingException; +import javax.security.auth.x500.X500Principal; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @@ -89,12 +91,66 @@ final class ClientHandshaker extends Handshaker { private final static boolean enableSNIExtension = Debug.getBooleanProperty("jsse.enableSNIExtension", true); + /* + * Allow unsafe server certificate change? + * + * Server certificate change during SSL/TLS renegotiation may be considered + * unsafe, as described in the Triple Handshake attacks: + * + * https://secure-resumption.com/tlsauth.pdf + * + * Endpoint identification (See + * SSLParameters.getEndpointIdentificationAlgorithm()) is a pretty nice + * guarantee that the server certificate change in renegotiation is legal. + * However, endpoing identification is only enabled for HTTPS and LDAP + * over SSL/TLS by default. It is not enough to protect SSL/TLS + * connections other than HTTPS and LDAP. + * + * The renegotiation indication extension (See RFC 5764) is a pretty + * strong guarantee that the endpoints on both client and server sides + * are identical on the same connection. However, the Triple Handshake + * attacks can bypass this guarantee if there is a session-resumption + * handshake between the initial full handshake and the renegotiation + * full handshake. + * + * Server certificate change may be unsafe and should be restricted if + * endpoint identification is not enabled and the previous handshake is + * a session-resumption abbreviated initial handshake, unless the + * identities represented by both certificates can be regraded as the + * same (See isIdentityEquivalent()). + * + * Considering the compatibility impact and the actual requirements to + * support server certificate change in practice, the system property, + * jdk.tls.allowUnsafeServerCertChange, is used to define whether unsafe + * server certificate change in renegotiation is allowed or not. The + * default value of the system property is "false". To mitigate the + * compactibility impact, applications may want to set the system + * property to "true" at their own risk. + * + * If the value of the system property is "false", server certificate + * change in renegotiation after a session-resumption abbreviated initial + * handshake is restricted (See isIdentityEquivalent()). + * + * If the system property is set to "true" explicitly, the restriction on + * server certificate change in renegotiation is disabled. + */ + private final static boolean allowUnsafeServerCertChange = + Debug.getBooleanProperty("jdk.tls.allowUnsafeServerCertChange", false); + private List<SNIServerName> requestedServerNames = Collections.<SNIServerName>emptyList(); private boolean serverNamesAccepted = false; /* + * the reserved server certificate chain in previous handshaking + * + * The server certificate chain is only reserved if the previous + * handshake is a session-resumption abbreviated initial handshake. + */ + private X509Certificate[] reservedServerCerts = null; + + /* * Constructors */ ClientHandshaker(SSLSocketImpl socket, SSLContextImpl context, @@ -555,14 +611,19 @@ final class ClientHandshaker extends Handshaker { // we wanted to resume, but the server refused session = null; if (!enableNewSession) { - throw new SSLException - ("New session creation is disabled"); + throw new SSLException("New session creation is disabled"); } } } if (resumingSession && session != null) { setHandshakeSessionSE(session); + // Reserve the handshake state if this is a session-resumption + // abbreviated initial handshake. + if (isInitialHandshake) { + session.setAsSessionResumption(true); + } + return; } @@ -1064,6 +1125,13 @@ final class ClientHandshaker extends Handshaker { } /* + * Reset the handshake state if this is not an initial handshake. + */ + if (!isInitialHandshake) { + session.setAsSessionResumption(false); + } + + /* * OK, it verified. If we're doing the fast handshake, add that * "Finished" message to the hash of handshake messages, then send * our own change_cipher_spec and Finished message for the server @@ -1161,8 +1229,23 @@ final class ClientHandshaker extends Handshaker { System.out.println("%% No cached client session"); } } - if ((session != null) && (session.isRejoinable() == false)) { - session = null; + if (session != null) { + // If unsafe server certificate change is not allowed, reserve + // current server certificates if the previous handshake is a + // session-resumption abbreviated initial handshake. + if (!allowUnsafeServerCertChange && session.isSessionResumption()) { + try { + // If existing, peer certificate chain cannot be null. + reservedServerCerts = + (X509Certificate[])session.getPeerCertificates(); + } catch (SSLPeerUnverifiedException puve) { + // Maybe not certificate-based, ignore the exception. + } + } + + if (!session.isRejoinable()) { + session = null; + } } if (session != null) { @@ -1331,9 +1414,28 @@ final class ClientHandshaker extends Handshaker { } X509Certificate[] peerCerts = mesg.getCertificateChain(); if (peerCerts.length == 0) { - fatalSE(Alerts.alert_bad_certificate, - "empty certificate chain"); + fatalSE(Alerts.alert_bad_certificate, "empty certificate chain"); + } + + // Allow server certificate change in client side during renegotiation + // after a session-resumption abbreviated initial handshake? + // + // DO NOT need to check allowUnsafeServerCertChange here. We only + // reserve server certificates when allowUnsafeServerCertChange is + // flase. + if (reservedServerCerts != null) { + // It is not necessary to check the certificate update if endpoint + // identification is enabled. + String identityAlg = getEndpointIdentificationAlgorithmSE(); + if ((identityAlg == null || identityAlg.length() == 0) && + !isIdentityEquivalent(peerCerts[0], reservedServerCerts[0])) { + + fatalSE(Alerts.alert_bad_certificate, + "server certificate change is restricted " + + "during renegotiation"); + } } + // ask the trust manager to verify the chain X509TrustManager tm = sslContext.getX509TrustManager(); try { @@ -1370,4 +1472,81 @@ final class ClientHandshaker extends Handshaker { } session.setPeerCertificates(peerCerts); } + + /* + * Whether the certificates can represent the same identity? + * + * The certificates can be used to represent the same identity: + * 1. If the subject alternative names of IP address are present in + * both certificates, they should be identical; otherwise, + * 2. if the subject alternative names of DNS name are present in + * both certificates, they should be identical; otherwise, + * 3. if the subject fields are present in both certificates, the + * certificate subjects and issuers should be identical. + */ + private static boolean isIdentityEquivalent(X509Certificate thisCert, + X509Certificate prevCert) { + if (thisCert.equals(prevCert)) { + return true; + } + + // check the iPAddress field in subjectAltName extension + Object thisIPAddress = getSubjectAltName(thisCert, 7); // 7: iPAddress + Object prevIPAddress = getSubjectAltName(prevCert, 7); + if (thisIPAddress != null && prevIPAddress!= null) { + // only allow the exactly match + return Objects.equals(thisIPAddress, prevIPAddress); + } + + // check the dNSName field in subjectAltName extension + Object thisDNSName = getSubjectAltName(thisCert, 2); // 2: dNSName + Object prevDNSName = getSubjectAltName(prevCert, 2); + if (thisDNSName != null && prevDNSName!= null) { + // only allow the exactly match + return Objects.equals(thisDNSName, prevDNSName); + } + + // check the certificate subject and issuer + X500Principal thisSubject = thisCert.getSubjectX500Principal(); + X500Principal prevSubject = prevCert.getSubjectX500Principal(); + X500Principal thisIssuer = thisCert.getIssuerX500Principal(); + X500Principal prevIssuer = prevCert.getIssuerX500Principal(); + if (!thisSubject.getName().isEmpty() && + !prevSubject.getName().isEmpty() && + thisSubject.equals(prevSubject) && + thisIssuer.equals(prevIssuer)) { + return true; + } + + return false; + } + + /* + * Returns the subject alternative name of the specified type in the + * subjectAltNames extension of a certificate. + */ + private static Object getSubjectAltName(X509Certificate cert, int type) { + Collection<List<?>> subjectAltNames; + + try { + subjectAltNames = cert.getSubjectAlternativeNames(); + } catch (CertificateParsingException cpe) { + if (debug != null && Debug.isOn("handshake")) { + System.out.println( + "Attempt to obtain subjectAltNames extension failed!"); + } + return null; + } + + if (subjectAltNames != null) { + for (List<?> subjectAltName : subjectAltNames) { + int subjectAltNameType = (Integer)subjectAltName.get(0); + if (subjectAltNameType == type) { + return subjectAltName.get(1); + } + } + } + + return null; + } } diff --git a/src/share/classes/sun/security/ssl/Handshaker.java b/src/share/classes/sun/security/ssl/Handshaker.java index 9fea3fada..ba65d966a 100644 --- a/src/share/classes/sun/security/ssl/Handshaker.java +++ b/src/share/classes/sun/security/ssl/Handshaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2014, 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 @@ -359,6 +359,17 @@ abstract class Handshaker { } } + String getEndpointIdentificationAlgorithmSE() { + SSLParameters paras; + if (conn != null) { + paras = conn.getSSLParameters(); + } else { + paras = engine.getSSLParameters(); + } + + return paras.getEndpointIdentificationAlgorithm(); + } + private void setVersionSE(ProtocolVersion protocolVersion) { if (conn != null) { conn.setVersion(protocolVersion); diff --git a/src/share/classes/sun/security/ssl/SSLSessionImpl.java b/src/share/classes/sun/security/ssl/SSLSessionImpl.java index 6cb4170d3..b5f304b6b 100644 --- a/src/share/classes/sun/security/ssl/SSLSessionImpl.java +++ b/src/share/classes/sun/security/ssl/SSLSessionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2014, 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 @@ -115,6 +115,14 @@ final class SSLSessionImpl extends ExtendedSSLSession { private Principal localPrincipal; /* + * Is the session currently re-established with a session-resumption + * abbreviated initial handshake? + * + * Note that currently we only set this variable in client side. + */ + private boolean isSessionResumption = false; + + /* * We count session creations, eventually for statistical data but * also since counters make shorter debugging IDs than the big ones * we use in the protocol for uniqueness-over-time. @@ -325,6 +333,22 @@ final class SSLSessionImpl extends ExtendedSSLSession { } /** + * Return true if the session is currently re-established with a + * session-resumption abbreviated initial handshake. + */ + boolean isSessionResumption() { + return isSessionResumption; + } + + /** + * Resets whether the session is re-established with a session-resumption + * abbreviated initial handshake. + */ + void setAsSessionResumption(boolean flag) { + isSessionResumption = flag; + } + + /** * Returns the name of the cipher suite in use on this session */ @Override diff --git a/src/share/classes/sun/util/locale/BaseLocale.java b/src/share/classes/sun/util/locale/BaseLocale.java index 6eee58290..e0e9ed060 100644 --- a/src/share/classes/sun/util/locale/BaseLocale.java +++ b/src/share/classes/sun/util/locale/BaseLocale.java @@ -31,6 +31,7 @@ */ package sun.util.locale; +import java.lang.ref.SoftReference; public final class BaseLocale { @@ -163,11 +164,11 @@ public final class BaseLocale { return h; } - private static final class Key implements Comparable<Key> { - private final String lang; - private final String scrt; - private final String regn; - private final String vart; + private static final class Key { + private final SoftReference<String> lang; + private final SoftReference<String> scrt; + private final SoftReference<String> regn; + private final SoftReference<String> vart; private final boolean normalized; private final int hash; @@ -179,10 +180,10 @@ public final class BaseLocale { assert language.intern() == language && region.intern() == region; - lang = language; - scrt = ""; - regn = region; - vart = ""; + lang = new SoftReference(language); + scrt = new SoftReference(""); + regn = new SoftReference(region); + vart = new SoftReference(""); this.normalized = true; int h = language.hashCode(); @@ -203,40 +204,40 @@ public final class BaseLocale { String variant, boolean normalized) { int h = 0; if (language != null) { - lang = language; + lang = new SoftReference(language); int len = language.length(); for (int i = 0; i < len; i++) { h = 31*h + LocaleUtils.toLower(language.charAt(i)); } } else { - lang = ""; + lang = new SoftReference(""); } if (script != null) { - scrt = script; + scrt = new SoftReference(script); int len = script.length(); for (int i = 0; i < len; i++) { h = 31*h + LocaleUtils.toLower(script.charAt(i)); } } else { - scrt = ""; + scrt = new SoftReference(""); } if (region != null) { - regn = region; + regn = new SoftReference(region); int len = region.length(); for (int i = 0; i < len; i++) { h = 31*h + LocaleUtils.toLower(region.charAt(i)); } } else { - regn = ""; + regn = new SoftReference(""); } if (variant != null) { - vart = variant; + vart = new SoftReference(variant); int len = variant.length(); for (int i = 0; i < len; i++) { h = 31*h + variant.charAt(i); } } else { - vart = ""; + vart = new SoftReference(""); } hash = h; this.normalized = normalized; @@ -244,28 +245,31 @@ public final class BaseLocale { @Override public boolean equals(Object obj) { - return (this == obj) || - (obj instanceof Key) - && this.hash == ((Key)obj).hash - && LocaleUtils.caseIgnoreMatch(((Key)obj).lang, this.lang) - && LocaleUtils.caseIgnoreMatch(((Key)obj).scrt, this.scrt) - && LocaleUtils.caseIgnoreMatch(((Key)obj).regn, this.regn) - && ((Key)obj).vart.equals(vart); // variant is case sensitive in JDK! + if (this == obj) { + return true; } - @Override - public int compareTo(Key other) { - int res = LocaleUtils.caseIgnoreCompare(this.lang, other.lang); - if (res == 0) { - res = LocaleUtils.caseIgnoreCompare(this.scrt, other.scrt); - if (res == 0) { - res = LocaleUtils.caseIgnoreCompare(this.regn, other.regn); - if (res == 0) { - res = this.vart.compareTo(other.vart); + if (obj instanceof Key && this.hash == ((Key)obj).hash) { + String tl = this.lang.get(); + String ol = ((Key)obj).lang.get(); + if (tl != null && ol != null && + LocaleUtils.caseIgnoreMatch(ol, tl)) { + String ts = this.scrt.get(); + String os = ((Key)obj).scrt.get(); + if (ts != null && os != null && + LocaleUtils.caseIgnoreMatch(os, ts)) { + String tr = this.regn.get(); + String or = ((Key)obj).regn.get(); + if (tr != null && or != null && + LocaleUtils.caseIgnoreMatch(or, tr)) { + String tv = this.vart.get(); + String ov = ((Key)obj).vart.get(); + return (ov != null && ov.equals(tv)); } } } - return res; + } + return false; } @Override @@ -278,10 +282,10 @@ public final class BaseLocale { return key; } - String lang = LocaleUtils.toLowerString(key.lang).intern(); - String scrt = LocaleUtils.toTitleString(key.scrt).intern(); - String regn = LocaleUtils.toUpperString(key.regn).intern(); - String vart = key.vart.intern(); // preserve upper/lower cases + String lang = LocaleUtils.toLowerString(key.lang.get()).intern(); + String scrt = LocaleUtils.toTitleString(key.scrt.get()).intern(); + String regn = LocaleUtils.toUpperString(key.regn.get()).intern(); + String vart = key.vart.get().intern(); // preserve upper/lower cases return new Key(lang, scrt, regn, vart, true); } @@ -294,12 +298,18 @@ public final class BaseLocale { @Override protected Key normalizeKey(Key key) { + assert key.lang.get() != null && + key.scrt.get() != null && + key.regn.get() != null && + key.vart.get() != null; + return Key.normalize(key); } @Override protected BaseLocale createObject(Key key) { - return new BaseLocale(key.lang, key.scrt, key.regn, key.vart); + return new BaseLocale(key.lang.get(), key.scrt.get(), + key.regn.get(), key.vart.get()); } } } diff --git a/src/share/classes/sun/util/locale/LocaleObjectCache.java b/src/share/classes/sun/util/locale/LocaleObjectCache.java index 88920aaf5..eae148088 100644 --- a/src/share/classes/sun/util/locale/LocaleObjectCache.java +++ b/src/share/classes/sun/util/locale/LocaleObjectCache.java @@ -57,8 +57,10 @@ public abstract class LocaleObjectCache<K, V> { value = entry.get(); } if (value == null) { - key = normalizeKey(key); V newVal = createObject(key); + // make sure key is normalized *after* the object creation + // so that newVal is assured to be created from a valid key. + key = normalizeKey(key); if (key == null || newVal == null) { // subclass must return non-null key/value object return null; diff --git a/src/share/javavm/export/jvm.h b/src/share/javavm/export/jvm.h index ff5f823d8..9426a16d4 100644 --- a/src/share/javavm/export/jvm.h +++ b/src/share/javavm/export/jvm.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -386,6 +386,19 @@ JNIEXPORT jclass JNICALL JVM_FindClassFromBootLoader(JNIEnv *env, const char *name); /* + * Find a class from a given class loader. Throws ClassNotFoundException. + * name: name of class + * init: whether initialization is done + * loader: class loader to look up the class. This may not be the same as the caller's + * class loader. + * caller: initiating class. The initiating class may be null when a security + * manager is not installed. + */ +JNIEXPORT jclass JNICALL +JVM_FindClassFromCaller(JNIEnv *env, const char *name, jboolean init, + jobject loader, jclass caller); + +/* * Find a class from a given class loader. Throw ClassNotFoundException * or NoClassDefFoundError depending on the value of the last * argument. diff --git a/src/share/native/java/lang/Class.c b/src/share/native/java/lang/Class.c index b0ba34349..2f5e6b5c8 100644 --- a/src/share/native/java/lang/Class.c +++ b/src/share/native/java/lang/Class.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2014, 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 @@ -97,7 +97,7 @@ Java_java_lang_Class_registerNatives(JNIEnv *env, jclass cls) JNIEXPORT jclass JNICALL Java_java_lang_Class_forName0(JNIEnv *env, jclass this, jstring classname, - jboolean initialize, jobject loader) + jboolean initialize, jobject loader, jclass caller) { char *clname; jclass cls = 0; @@ -135,8 +135,7 @@ Java_java_lang_Class_forName0(JNIEnv *env, jclass this, jstring classname, goto done; } - cls = JVM_FindClassFromClassLoader(env, clname, initialize, - loader, JNI_FALSE); + cls = JVM_FindClassFromCaller(env, clname, initialize, loader, caller); done: if (clname != buf) { diff --git a/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp b/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp index 3707efdfb..e985b81cb 100644 --- a/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp +++ b/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp @@ -243,12 +243,22 @@ le_uint32 ContextualSubstitutionFormat1Subtable::process(const LETableReference le_uint16 srSetCount = SWAPW(subRuleSetCount); if (coverageIndex < srSetCount) { + LEReferenceToArrayOf<Offset> subRuleSetTableOffsetArrayRef(base, success, + &subRuleSetTableOffsetArray[coverageIndex], 1); + if (LE_FAILURE(success)) { + return 0; + } Offset subRuleSetTableOffset = SWAPW(subRuleSetTableOffsetArray[coverageIndex]); LEReferenceTo<SubRuleSetTable> subRuleSetTable(base, success, (const SubRuleSetTable *) ((char *) this + subRuleSetTableOffset)); le_uint16 subRuleCount = SWAPW(subRuleSetTable->subRuleCount); le_int32 position = glyphIterator->getCurrStreamPosition(); + LEReferenceToArrayOf<Offset> subRuleTableOffsetArrayRef(base, success, + subRuleSetTable->subRuleTableOffsetArray, subRuleCount); + if (LE_FAILURE(success)) { + return 0; + } for (le_uint16 subRule = 0; subRule < subRuleCount; subRule += 1) { Offset subRuleTableOffset = SWAPW(subRuleSetTable->subRuleTableOffsetArray[subRule]); @@ -301,13 +311,22 @@ le_uint32 ContextualSubstitutionFormat2Subtable::process(const LETableReference glyphIterator->getCurrGlyphID(), success); - if (setClass < scSetCount && subClassSetTableOffsetArray[setClass] != 0) { + if (setClass < scSetCount) { + LEReferenceToArrayOf<Offset> + subClassSetTableOffsetArrayRef(base, success, subClassSetTableOffsetArray, setClass); + if (LE_FAILURE(success)) { return 0; } + if (subClassSetTableOffsetArray[setClass] != 0) { + Offset subClassSetTableOffset = SWAPW(subClassSetTableOffsetArray[setClass]); LEReferenceTo<SubClassSetTable> subClassSetTable(base, success, (const SubClassSetTable *) ((char *) this + subClassSetTableOffset)); le_uint16 subClassRuleCount = SWAPW(subClassSetTable->subClassRuleCount); le_int32 position = glyphIterator->getCurrStreamPosition(); - + LEReferenceToArrayOf<Offset> + subClassRuleTableOffsetArrayRef(base, success, subClassSetTable->subClassRuleTableOffsetArray, subClassRuleCount); + if (LE_FAILURE(success)) { + return 0; + } for (le_uint16 scRule = 0; scRule < subClassRuleCount; scRule += 1) { Offset subClassRuleTableOffset = SWAPW(subClassSetTable->subClassRuleTableOffsetArray[scRule]); @@ -331,6 +350,7 @@ le_uint32 ContextualSubstitutionFormat2Subtable::process(const LETableReference glyphIterator->setCurrStreamPosition(position); } } + } // XXX If we get here, the table is mal-formed... } @@ -442,13 +462,22 @@ le_uint32 ChainingContextualSubstitutionFormat1Subtable::process(const LETableRe le_uint16 srSetCount = SWAPW(chainSubRuleSetCount); if (coverageIndex < srSetCount) { + LEReferenceToArrayOf<Offset> + chainSubRuleSetTableOffsetArrayRef(base, success, chainSubRuleSetTableOffsetArray, coverageIndex); + if (LE_FAILURE(success)) { + return 0; + } Offset chainSubRuleSetTableOffset = SWAPW(chainSubRuleSetTableOffsetArray[coverageIndex]); LEReferenceTo<ChainSubRuleSetTable> chainSubRuleSetTable(base, success, (const ChainSubRuleSetTable *) ((char *) this + chainSubRuleSetTableOffset)); le_uint16 chainSubRuleCount = SWAPW(chainSubRuleSetTable->chainSubRuleCount); le_int32 position = glyphIterator->getCurrStreamPosition(); GlyphIterator tempIterator(*glyphIterator, emptyFeatureList); - + LEReferenceToArrayOf<Offset> + chainSubRuleTableOffsetArrayRef(base, success, chainSubRuleSetTable->chainSubRuleTableOffsetArray, chainSubRuleCount); + if (LE_FAILURE(success)) { + return 0; + } for (le_uint16 subRule = 0; subRule < chainSubRuleCount; subRule += 1) { Offset chainSubRuleTableOffset = SWAPW(chainSubRuleSetTable->chainSubRuleTableOffsetArray[subRule]); @@ -530,6 +559,11 @@ le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LETableRe le_int32 setClass = inputClassDefinitionTable->getGlyphClass(inputClassDefinitionTable, glyphIterator->getCurrGlyphID(), success); + LEReferenceToArrayOf<Offset> + chainSubClassSetTableOffsetArrayRef(base, success, chainSubClassSetTableOffsetArray, setClass); + if (LE_FAILURE(success)) { + return 0; + } if (setClass < scSetCount && chainSubClassSetTableOffsetArray[setClass] != 0) { Offset chainSubClassSetTableOffset = SWAPW(chainSubClassSetTableOffsetArray[setClass]); @@ -538,7 +572,11 @@ le_uint32 ChainingContextualSubstitutionFormat2Subtable::process(const LETableRe le_uint16 chainSubClassRuleCount = SWAPW(chainSubClassSetTable->chainSubClassRuleCount); le_int32 position = glyphIterator->getCurrStreamPosition(); GlyphIterator tempIterator(*glyphIterator, emptyFeatureList); - + LEReferenceToArrayOf<Offset> + chainSubClassRuleTableOffsetArrayRef(base, success, chainSubClassSetTable->chainSubClassRuleTableOffsetArray, chainSubClassRuleCount); + if (LE_FAILURE(success)) { + return 0; + } for (le_uint16 scRule = 0; scRule < chainSubClassRuleCount; scRule += 1) { Offset chainSubClassRuleTableOffset = SWAPW(chainSubClassSetTable->chainSubClassRuleTableOffsetArray[scRule]); @@ -603,12 +641,14 @@ le_uint32 ChainingContextualSubstitutionFormat3Subtable::process(const LETableRe } le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount); + LEReferenceToArrayOf<Offset> backtrackGlyphArrayRef(base, success, backtrackCoverageTableOffsetArray, backtrkGlyphCount); + if (LE_FAILURE(success)) { + return 0; + } le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]); LEReferenceToArrayOf<Offset> inputCoverageTableOffsetArray(base, success, &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1], inputGlyphCount+2); // offset if (LE_FAILURE(success)) { return 0; } const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]); - - if( LE_FAILURE(success)) { return 0; } LEReferenceToArrayOf<Offset> lookaheadCoverageTableOffsetArray(base, success, inputCoverageTableOffsetArray.getAlias(inputGlyphCount + 1, success), lookaheadGlyphCount+2); if( LE_FAILURE(success) ) { return 0; } |