diff --git a/src/share/classes/com/sun/jndi/dns/DnsContextFactory.java b/src/share/classes/com/sun/jndi/dns/DnsContextFactory.java index c006ebdb5b95743510edd86d6556ae1109c3b26d..2ce289e7d4dee431d938244bc3f67d66db573bcb 100644 --- a/src/share/classes/com/sun/jndi/dns/DnsContextFactory.java +++ b/src/share/classes/com/sun/jndi/dns/DnsContextFactory.java @@ -54,6 +54,7 @@ import sun.net.dns.ResolverConfiguration; // available since 1.4.1 public class DnsContextFactory implements InitialContextFactory { private static final String DEFAULT_URL = "dns:"; + private static final int DEFAULT_PORT = 53; public Context getInitialContext(Hashtable env) throws NamingException { @@ -89,7 +90,9 @@ public class DnsContextFactory implements InitialContextFactory { * Public for use by product test suite. */ public static boolean platformServersAvailable() { - return !ResolverConfiguration.open().nameservers().isEmpty(); + return !filterNameServers( + ResolverConfiguration.open().nameservers(), true + ).isEmpty(); } private static Context urlToContext(String url, Hashtable env) @@ -142,8 +145,8 @@ public class DnsContextFactory implements InitialContextFactory { // No server or port given, so look to underlying platform. // ResolverConfiguration does some limited caching, so the // following is reasonably efficient even if called rapid-fire. - List platformServers = - ResolverConfiguration.open().nameservers(); + List platformServers = filterNameServers( + ResolverConfiguration.open().nameservers(), false); if (!platformServers.isEmpty()) { servers.addAll(platformServers); continue; // on to next URL (if any, which is unlikely) @@ -213,4 +216,44 @@ public class DnsContextFactory implements InitialContextFactory { String url = (String) env.get(Context.PROVIDER_URL); return ((url != null) ? url : DEFAULT_URL); } + + /** + * Removes any DNS server that's not permitted to access + * @param input the input server[:port] list, must not be null + * @param oneIsEnough return output once there exists one ok + * @return the filtered list, all non-permitted input removed + */ + private static List filterNameServers(List input, boolean oneIsEnough) { + SecurityManager security = System.getSecurityManager(); + if (security == null || input == null || input.isEmpty()) { + return input; + } else { + List output = new ArrayList(); + for (Object o: input) { + if (o instanceof String) { + String platformServer = (String)o; + int colon = platformServer.indexOf(':', + platformServer.indexOf(']') + 1); + + int p = (colon < 0) + ? DEFAULT_PORT + : Integer.parseInt( + platformServer.substring(colon + 1)); + String s = (colon < 0) + ? platformServer + : platformServer.substring(0, colon); + try { + security.checkConnect(s, p); + output.add(platformServer); + if (oneIsEnough) { + return output; + } + } catch (SecurityException se) { + continue; + } + } + } + return output; + } + } } diff --git a/src/share/classes/java/awt/image/IndexColorModel.java b/src/share/classes/java/awt/image/IndexColorModel.java index c5afce8218ceaebda06eb332cd2661dbbf993ae5..969d524f9abaf0d1030838d6fe959913efbafdde 100644 --- a/src/share/classes/java/awt/image/IndexColorModel.java +++ b/src/share/classes/java/awt/image/IndexColorModel.java @@ -129,6 +129,8 @@ public class IndexColorModel extends ColorModel { private boolean allgrayopaque; private BigInteger validBits; + private sun.awt.image.BufImgSurfaceData.ICMColorData colorData = null; + private static int[] opaqueBits = {8, 8, 8}; private static int[] alphaBits = {8, 8, 8, 8}; @@ -1511,7 +1513,6 @@ public class IndexColorModel extends ColorModel { * longer referenced. */ public void finalize() { - sun.awt.image.BufImgSurfaceData.freeNativeICMData(this); } /** diff --git a/src/share/classes/java/net/HttpURLConnection.java b/src/share/classes/java/net/HttpURLConnection.java index c6b1ffab6c9414c97214905d9c010e8ab80061f2..0b3e578022c5eba2cdeba11641fe1e83b593577b 100644 --- a/src/share/classes/java/net/HttpURLConnection.java +++ b/src/share/classes/java/net/HttpURLConnection.java @@ -399,6 +399,8 @@ abstract public class HttpURLConnection extends URLConnection { * @param method the HTTP method * @exception ProtocolException if the method cannot be reset or if * the requested method isn't valid for HTTP. + * @exception SecurityException if a security manager is set and the + * "allowHttpTrace" NetPermission is not granted. * @see #getRequestMethod() */ public void setRequestMethod(String method) throws ProtocolException { @@ -412,6 +414,12 @@ abstract public class HttpURLConnection extends URLConnection { for (int i = 0; i < methods.length; i++) { if (methods[i].equals(method)) { + if (method.equals("TRACE")) { + SecurityManager s = System.getSecurityManager(); + if (s != null) { + s.checkPermission(new NetPermission("allowHttpTrace")); + } + } this.method = method; return; } diff --git a/src/share/classes/java/net/NetPermission.java b/src/share/classes/java/net/NetPermission.java index 5083a40fb3467b02c35db375b05213f9f8f7789b..1cff4a8767677583b3be728a19991a7fe1113346 100644 --- a/src/share/classes/java/net/NetPermission.java +++ b/src/share/classes/java/net/NetPermission.java @@ -54,44 +54,23 @@ import java.util.StringTokenizer; * What the Permission Allows * Risks of Allowing this Permission * - * - * - * setDefaultAuthenticator - * The ability to set the - * way authentication information is retrieved when - * a proxy or HTTP server asks for authentication - * Malicious - * code can set an authenticator that monitors and steals user - * authentication input as it retrieves the input from the user. - * - * - * - * requestPasswordAuthentication - * The ability - * to ask the authenticator registered with the system for - * a password - * Malicious code may steal this password. - * - * * - * specifyStreamHandler - * The ability - * to specify a stream handler when constructing a URL - * Malicious code may create a URL with resources that it would -normally not have access to (like file:/foo/fum/), specifying a -stream handler that gets the actual bytes from someplace it does -have access to. Thus it might be able to trick the system into -creating a ProtectionDomain/CodeSource for a class even though -that class really didn't come from that location. - * + * allowHttpTrace + * The ability to use the HTTP TRACE method in HttpURLConnection. + * Malicious code using HTTP TRACE could get access to security sensitive + * information in the HTTP headers (such as cookies) that it might not + * otherwise have access to. + * * * - * setProxySelector - * The ability to set the proxy selector used to make decisions - * on which proxies to use when making network connections. - * Malicious code can set a ProxySelector that directs network - * traffic to an arbitrary network host. - * + * getCookieHandler + * The ability to get the cookie handler that processes highly + * security sensitive cookie information for an Http session. + * Malicious code can get a cookie handler to obtain access to + * highly security sensitive cookie information. Some web servers + * use cookies to save user private information such as access + * control information, or to track user browsing habit. + * * * * getProxySelector @@ -103,6 +82,22 @@ that class really didn't come from that location. * * * + * getResponseCache + * The ability to get the response cache that provides + * access to a local response cache. + * Malicious code getting access to the local response cache + * could access security sensitive information. + * + * + * + * requestPasswordAuthentication + * The ability + * to ask the authenticator registered with the system for + * a password + * Malicious code may steal this password. + * + * + * * setCookieHandler * The ability to set the cookie handler that processes highly * security sensitive cookie information for an Http session. @@ -113,14 +108,22 @@ that class really didn't come from that location. * * * - * getCookieHandler - * The ability to get the cookie handler that processes highly - * security sensitive cookie information for an Http session. - * Malicious code can get a cookie handler to obtain access to - * highly security sensitive cookie information. Some web servers - * use cookies to save user private information such as access - * control information, or to track user browsing habit. - * + * setDefaultAuthenticator + * The ability to set the + * way authentication information is retrieved when + * a proxy or HTTP server asks for authentication + * Malicious + * code can set an authenticator that monitors and steals user + * authentication input as it retrieves the input from the user. + * + * + * + * setProxySelector + * The ability to set the proxy selector used to make decisions + * on which proxies to use when making network connections. + * Malicious code can set a ProxySelector that directs network + * traffic to an arbitrary network host. + * * * * setResponseCache @@ -132,13 +135,16 @@ that class really didn't come from that location. * * * - * getResponseCache - * The ability to get the response cache that provides - * access to a local response cache. - * Malicious code getting access to the local response cache - * could access security sensitive information. - * - * + * specifyStreamHandler + * The ability + * to specify a stream handler when constructing a URL + * Malicious code may create a URL with resources that it would +normally not have access to (like file:/foo/fum/), specifying a +stream handler that gets the actual bytes from someplace it does +have access to. Thus it might be able to trick the system into +creating a ProtectionDomain/CodeSource for a class even though +that class really didn't come from that location. + * * * * @see java.security.BasicPermission diff --git a/src/share/classes/java/net/NetworkInterface.java b/src/share/classes/java/net/NetworkInterface.java index 51ebf23917bb6afdf863e05232371b67e3e2ac23..2dd0e96a390c6e7e20392bba8a4816408d5bf957 100644 --- a/src/share/classes/java/net/NetworkInterface.java +++ b/src/share/classes/java/net/NetworkInterface.java @@ -86,7 +86,9 @@ public final class NetworkInterface { * If there is a security manager, its checkConnect * method is called for each InetAddress. Only InetAddresses where * the checkConnect doesn't throw a SecurityException - * will be returned in the Enumeration. + * will be returned in the Enumeration. However, if the caller has the + * {@link NetPermission}("getNetworkInformation") permission, then all + * InetAddresses are returned. * @return an Enumeration object with all or a subset of the InetAddresses * bound to this network interface */ @@ -99,11 +101,19 @@ public final class NetworkInterface { checkedAddresses() { local_addrs = new InetAddress[addrs.length]; + boolean trusted = true; SecurityManager sec = System.getSecurityManager(); + if (sec != null) { + try { + sec.checkPermission(new NetPermission("getNetworkInformation")); + } catch (SecurityException e) { + trusted = false; + } + } for (int j=0; jnull if + * the address doesn't exist, is not accessible or a security + * manager is set and the caller does not have the permission + * NetPermission("getNetworkInformation") * - * @return a byte array containing the address or null if - * the address doesn't exist or is not accessible. * @exception SocketException if an I/O error occurs. * @since 1.6 */ public byte[] getHardwareAddress() throws SocketException { + SecurityManager sec = System.getSecurityManager(); + if (sec != null) { + try { + sec.checkPermission(new NetPermission("getNetworkInformation")); + } catch (SecurityException e) { + if (!getInetAddresses().hasMoreElements()) { + // don't have connect permission to any local address + return null; + } + } + } for (InetAddress addr : addrs) { if (addr instanceof Inet4Address) { return getMacAddr0(((Inet4Address)addr).getAddress(), name, index); @@ -523,11 +549,10 @@ public final class NetworkInterface { } public int hashCode() { - int count = 0; - if (addrs != null) { - for (int i = 0; i < addrs.length; i++) { - count += addrs[i].hashCode(); - } + int count = name == null? 0: name.hashCode(); + Enumeration addrs = getInetAddresses(); + while (addrs.hasMoreElements()) { + count += addrs.nextElement().hashCode(); } return count; } diff --git a/src/share/classes/javax/swing/UIDefaults.java b/src/share/classes/javax/swing/UIDefaults.java index 2c9f2c34e1dfb6a7de1097cdad2786ac9628f6aa..2a9056f539bad32d70c7d93d21b7ea292f1f69f9 100644 --- a/src/share/classes/javax/swing/UIDefaults.java +++ b/src/share/classes/javax/swing/UIDefaults.java @@ -52,6 +52,7 @@ import java.security.AccessControlContext; import java.security.PrivilegedAction; import sun.reflect.misc.MethodUtil; +import sun.reflect.misc.ReflectUtil; import sun.util.CoreResourceBundleControl; /** @@ -1078,6 +1079,9 @@ public class UIDefaults extends Hashtable // In order to pick up the security policy in effect at the // time of creation we use a doPrivileged with the // AccessControlContext that was in place when this was created. + if (acc == null && System.getSecurityManager() != null) { + throw new SecurityException("null AccessControlContext"); + } return AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { @@ -1093,7 +1097,9 @@ public class UIDefaults extends Hashtable cl = ClassLoader.getSystemClassLoader(); } } + ReflectUtil.checkPackageAccess(className); c = Class.forName(className, true, (ClassLoader)cl); + checkAccess(c.getModifiers()); if (methodName != null) { Class[] types = getClassArray(args); Method m = c.getMethod(methodName, types); @@ -1101,6 +1107,7 @@ public class UIDefaults extends Hashtable } else { Class[] types = getClassArray(args); Constructor constructor = c.getConstructor(types); + checkAccess(constructor.getModifiers()); return constructor.newInstance(args); } } catch(Exception e) { @@ -1115,6 +1122,13 @@ public class UIDefaults extends Hashtable }, acc); } + private void checkAccess(int modifiers) { + if(System.getSecurityManager() != null && + !Modifier.isPublic(modifiers)) { + throw new SecurityException("Resource is not accessible"); + } + } + /* * Coerce the array of class types provided into one which * looks the way the Reflection APIs expect. This is done diff --git a/src/share/classes/javax/swing/text/html/HTMLEditorKit.java b/src/share/classes/javax/swing/text/html/HTMLEditorKit.java index 88a3661b0bafb88efeed55f80adb192dcc734b0b..f9642c7bdd75488221443683b66305e8edf2b94c 100644 --- a/src/share/classes/javax/swing/text/html/HTMLEditorKit.java +++ b/src/share/classes/javax/swing/text/html/HTMLEditorKit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, 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 @@ -24,6 +24,8 @@ */ package javax.swing.text.html; +import sun.awt.AppContext; + import java.lang.reflect.Method; import java.awt.*; import java.awt.event.*; @@ -369,7 +371,11 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { * if desired. */ public void setStyleSheet(StyleSheet s) { - defaultStyles = s; + if (s == null) { + AppContext.getAppContext().remove(DEFAULT_STYLES_KEY); + } else { + AppContext.getAppContext().put(DEFAULT_STYLES_KEY, s); + } } /** @@ -379,8 +385,12 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { * instances. */ public StyleSheet getStyleSheet() { + AppContext appContext = AppContext.getAppContext(); + StyleSheet defaultStyles = (StyleSheet) appContext.get(DEFAULT_STYLES_KEY); + if (defaultStyles == null) { defaultStyles = new StyleSheet(); + appContext.put(DEFAULT_STYLES_KEY, defaultStyles); try { InputStream is = HTMLEditorKit.getResourceAsStream(DEFAULT_CSS); Reader r = new BufferedReader( @@ -620,7 +630,7 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { private static final ViewFactory defaultFactory = new HTMLFactory(); MutableAttributeSet input; - private static StyleSheet defaultStyles = null; + private static final Object DEFAULT_STYLES_KEY = new Object(); private LinkController linkHandler = new LinkController(); private static Parser defaultParser = null; private Cursor defaultCursor = DefaultCursor; diff --git a/src/share/classes/javax/swing/text/html/parser/DTD.java b/src/share/classes/javax/swing/text/html/parser/DTD.java index 4639b8379ba7ed679e9aad673ef5096ab0560719..b0787eabbb07f886b1e201b9c72456118b7a8ea7 100644 --- a/src/share/classes/javax/swing/text/html/parser/DTD.java +++ b/src/share/classes/javax/swing/text/html/parser/DTD.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2010, 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,6 +25,8 @@ package javax.swing.text.html.parser; +import sun.awt.AppContext; + import java.io.PrintStream; import java.io.File; import java.io.FileInputStream; @@ -314,13 +316,14 @@ class DTD implements DTDConstants { } /** - * The hashtable of DTDs. + * The hashtable key of DTDs in AppContext. */ - static Hashtable dtdHash = new Hashtable(); + private static final Object DTD_HASH_KEY = new Object(); + + public static void putDTDHash(String name, DTD dtd) { + getDtdHash().put(name, dtd); + } - public static void putDTDHash(String name, DTD dtd) { - dtdHash.put(name, dtd); - } /** * Returns a DTD with the specified name. If * a DTD with that name doesn't exist, one is created @@ -332,13 +335,27 @@ class DTD implements DTDConstants { */ public static DTD getDTD(String name) throws IOException { name = name.toLowerCase(); - DTD dtd = dtdHash.get(name); + DTD dtd = getDtdHash().get(name); if (dtd == null) dtd = new DTD(name); return dtd; } + private static Hashtable getDtdHash() { + AppContext appContext = AppContext.getAppContext(); + + Hashtable result = (Hashtable) appContext.get(DTD_HASH_KEY); + + if (result == null) { + result = new Hashtable(); + + appContext.put(DTD_HASH_KEY, result); + } + + return result; + } + /** * Recreates a DTD from an archived format. * @param in the DataInputStream to read from diff --git a/src/share/classes/javax/swing/text/html/parser/ParserDelegator.java b/src/share/classes/javax/swing/text/html/parser/ParserDelegator.java index 89289e080970a4bc46641ce81102b374892bbc9f..06b53483dc082b91319b9502eeba04a6c3d0c645 100644 --- a/src/share/classes/javax/swing/text/html/parser/ParserDelegator.java +++ b/src/share/classes/javax/swing/text/html/parser/ParserDelegator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2010, 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,6 +25,8 @@ package javax.swing.text.html.parser; +import sun.awt.AppContext; + import javax.swing.text.html.HTMLEditorKit; import java.io.BufferedInputStream; import java.io.IOException; @@ -33,7 +35,6 @@ import java.io.DataInputStream; import java.io.ObjectInputStream; import java.io.Reader; import java.io.Serializable; -import java.lang.reflect.Method; /** * Responsible for starting up a new DocumentParser @@ -45,9 +46,13 @@ import java.lang.reflect.Method; public class ParserDelegator extends HTMLEditorKit.Parser implements Serializable { - private static DTD dtd = null; + private static final Object DTD_KEY = new Object(); protected static synchronized void setDefaultDTD() { + AppContext appContext = AppContext.getAppContext(); + + DTD dtd = (DTD) appContext.get(DTD_KEY); + if (dtd == null) { DTD _dtd = null; // (PENDING) Hate having to hard code! @@ -59,6 +64,8 @@ public class ParserDelegator extends HTMLEditorKit.Parser implements Serializabl System.out.println("Throw an exception: could not get default dtd: " + nm); } dtd = createDTD(_dtd, nm); + + appContext.put(DTD_KEY, dtd); } } @@ -81,13 +88,11 @@ public class ParserDelegator extends HTMLEditorKit.Parser implements Serializabl public ParserDelegator() { - if (dtd == null) { - setDefaultDTD(); - } + setDefaultDTD(); } public void parse(Reader r, HTMLEditorKit.ParserCallback cb, boolean ignoreCharSet) throws IOException { - new DocumentParser(dtd).parse(r, cb, ignoreCharSet); + new DocumentParser((DTD) AppContext.getAppContext().get(DTD_KEY)).parse(r, cb, ignoreCharSet); } /** @@ -113,8 +118,6 @@ public class ParserDelegator extends HTMLEditorKit.Parser implements Serializabl private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { s.defaultReadObject(); - if (dtd == null) { - setDefaultDTD(); - } + setDefaultDTD(); } } diff --git a/src/share/classes/sun/awt/image/BufImgSurfaceData.java b/src/share/classes/sun/awt/image/BufImgSurfaceData.java index 082c1f581ff3a8291fa05840f48c6c81d474b882..43ec7286620f9d5e347454a61b21cbff78c3de9c 100644 --- a/src/share/classes/sun/awt/image/BufImgSurfaceData.java +++ b/src/share/classes/sun/awt/image/BufImgSurfaceData.java @@ -49,7 +49,7 @@ public class BufImgSurfaceData extends SurfaceData { private BufferedImageGraphicsConfig graphicsConfig; RenderLoops solidloops; - private static native void initIDs(Class ICM); + private static native void initIDs(Class ICM, Class ICMColorData); private static final int DCM_RGBX_RED_MASK = 0xff000000; private static final int DCM_RGBX_GREEN_MASK = 0x00ff0000; @@ -67,7 +67,7 @@ public class BufImgSurfaceData extends SurfaceData { private static final int DCM_ARGBBM_BLUE_MASK = 0x000000ff; static { - initIDs(IndexColorModel.class); + initIDs(IndexColorModel.class, ICMColorData.class); } public static SurfaceData createData(BufferedImage bufImg) { @@ -403,7 +403,7 @@ public class BufImgSurfaceData extends SurfaceData { // their pixels are immediately retrievable anyway. } - public static native void freeNativeICMData(IndexColorModel icm); + private static native void freeNativeICMData(long pData); /** * Returns destination Image associated with this SurfaceData. @@ -411,4 +411,19 @@ public class BufImgSurfaceData extends SurfaceData { public Object getDestination() { return bufImg; } + + public static final class ICMColorData { + private long pData = 0L; + + private ICMColorData(long pData) { + this.pData = pData; + } + + public void finalize() { + if (pData != 0L) { + BufImgSurfaceData.freeNativeICMData(pData); + pData = 0L; + } + } + } } diff --git a/src/share/classes/sun/net/www/MessageHeader.java b/src/share/classes/sun/net/www/MessageHeader.java index a9f9f9dc1ff51a0ce0cc9bcccc5804bf2fc7eb51..2493290d8241fe1750fd20b1deb34b66963f213d 100644 --- a/src/share/classes/sun/net/www/MessageHeader.java +++ b/src/share/classes/sun/net/www/MessageHeader.java @@ -196,6 +196,10 @@ class MessageHeader { } public synchronized Map> getHeaders(String[] excludeList) { + return filterAndAddHeaders(excludeList, null); + } + + public synchronized Map> filterAndAddHeaders(String[] excludeList, Map> include) { boolean skipIt = false; Map> m = new HashMap>(); for (int i = nkeys; --i >= 0;) { @@ -223,6 +227,19 @@ class MessageHeader { } } + if (include != null) { + Iterator entries = include.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry entry = (Map.Entry)entries.next(); + List l = (List)m.get(entry.getKey()); + if (l == null) { + l = new ArrayList(); + m.put((String)entry.getKey(), l); + } + l.add(entry.getValue()); + } + } + for (String key : m.keySet()) { m.put(key, Collections.unmodifiableList(m.get(key))); } diff --git a/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index ad45c983f29a1adcf5ad702faac021476a9b5b1c..56ed6a40fa34fd03b04ac0fa938fd9537851dee8 100644 --- a/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -51,6 +51,9 @@ import java.util.List; import java.util.Locale; import java.util.StringTokenizer; import java.util.Iterator; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Set; import sun.net.*; import sun.net.www.*; import sun.net.www.http.HttpClient; @@ -140,6 +143,54 @@ public class HttpURLConnection extends java.net.HttpURLConnection { */ private static int bufSize4ES = 0; + /* + * Restrict setting of request headers through the public api + * consistent with JavaScript XMLHttpRequest2 with a few + * exceptions. Disallowed headers are silently ignored for + * backwards compatibility reasons rather than throwing a + * SecurityException. For example, some applets set the + * Host header since old JREs did not implement HTTP 1.1. + * Additionally, any header starting with Sec- is + * disallowed. + * + * The following headers are allowed for historical reasons: + * + * Accept-Charset, Accept-Encoding, Cookie, Cookie2, Date, + * Referer, TE, User-Agent, headers beginning with Proxy-. + * + * The following headers are allowed in a limited form: + * + * Connection: close + * + * See http://www.w3.org/TR/XMLHttpRequest2. + */ + private static final boolean allowRestrictedHeaders; + private static final Set restrictedHeaderSet; + private static final String[] restrictedHeaders = { + /* Restricted by XMLHttpRequest2 */ + //"Accept-Charset", + //"Accept-Encoding", + "Access-Control-Request-Headers", + "Access-Control-Request-Method", + "Connection", /* close is allowed */ + "Content-Length", + //"Cookie", + //"Cookie2", + "Content-Transfer-Encoding", + //"Date", + //"Expect", + "Host", + "Keep-Alive", + "Origin", + // "Referer", + // "TE", + "Trailer", + "Transfer-Encoding", + "Upgrade", + //"User-Agent", + "Via" + }; + static { maxRedirects = java.security.AccessController.doPrivileged( new sun.security.action.GetIntegerAction( @@ -178,7 +229,17 @@ public class HttpURLConnection extends java.net.HttpURLConnection { bufSize4ES = 4096; // use the default } - + allowRestrictedHeaders = ((Boolean)java.security.AccessController.doPrivileged( + new sun.security.action.GetBooleanAction( + "sun.net.http.allowRestrictedHeaders"))).booleanValue(); + if (!allowRestrictedHeaders) { + restrictedHeaderSet = new HashSet(restrictedHeaders.length); + for (int i=0; i < restrictedHeaders.length; i++) { + restrictedHeaderSet.add(restrictedHeaders[i].toLowerCase()); + } + } else { + restrictedHeaderSet = null; + } } static final String httpVersion = "HTTP/1.1"; @@ -191,6 +252,15 @@ public class HttpURLConnection extends java.net.HttpURLConnection { "Proxy-Authorization", "Authorization" }; + + // also exclude system cookies when any might be set + private static final String[] EXCLUDE_HEADERS2= { + "Proxy-Authorization", + "Authorization", + "Cookie", + "Cookie2" + }; + protected HttpClient http; protected Handler handler; protected Proxy instProxy; @@ -213,6 +283,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection { /* User set Cookies */ private boolean setUserCookies = true; private String userCookies = null; + private String userCookies2 = null; /* We only have a single static authenticator for now. * REMIND: backwards compatibility with JDK 1.1. Should be @@ -329,6 +400,41 @@ public class HttpURLConnection extends java.net.HttpURLConnection { }); } + private boolean isRestrictedHeader(String key, String value) { + if (allowRestrictedHeaders) { + return false; + } + + key = key.toLowerCase(); + if (restrictedHeaderSet.contains(key)) { + /* + * Exceptions to restricted headers: + * + * Allow "Connection: close". + */ + if (key.equals("connection") && value.equalsIgnoreCase("close")) { + return false; + } + return true; + } else if (key.startsWith("sec-")) { + return true; + } + return false; + } + + /* + * Checks the validity of http message header and whether the header + * is restricted and throws IllegalArgumentException if invalid or + * restricted. + */ + private boolean isExternalMessageHeaderAllowed(String key, String value) { + checkMessageHeader(key, value); + if (!isRestrictedHeader(key, value)) { + return true; + } + return false; + } + /* Logging support */ public static PlatformLogger getHttpLogger() { return logger; @@ -463,9 +569,12 @@ public class HttpURLConnection extends java.net.HttpURLConnection { "application/x-www-form-urlencoded"); } + boolean chunked = false; + if (streaming()) { if (chunkLength != -1) { requests.set ("Transfer-Encoding", "chunked"); + chunked = true; } else { /* fixed content length */ if (fixedContentLengthLong != -1) { requests.set ("Content-Length", @@ -485,6 +594,16 @@ public class HttpURLConnection extends java.net.HttpURLConnection { } } + if (!chunked) { + if (requests.findValue("Transfer-Encoding") != null) { + requests.remove("Transfer-Encoding"); + if (logger.isLoggable(PlatformLogger.WARNING)) { + logger.warning( + "use streaming mode for chunked encoding"); + } + } + } + // get applicable cookies based on the uri and request headers // add them to the existing request headers setCookieHeader(); @@ -1034,15 +1153,21 @@ public class HttpURLConnection extends java.net.HttpURLConnection { // we only want to capture the user defined Cookies once, as // they cannot be changed by user code after we are connected, // only internally. - if (setUserCookies) { - int k = requests.getKey("Cookie"); - if ( k != -1) - userCookies = requests.getValue(k); - setUserCookies = false; + synchronized (this) { + if (setUserCookies) { + int k = requests.getKey("Cookie"); + if (k != -1) + userCookies = requests.getValue(k); + k = requests.getKey("Cookie2"); + if (k != -1) + userCookies2 = requests.getValue(k); + setUserCookies = false; + } } // remove old Cookie header before setting new one. requests.remove("Cookie"); + requests.remove("Cookie2"); URI uri = ParseUtil.toURI(url); if (uri != null) { @@ -1088,6 +1213,13 @@ public class HttpURLConnection extends java.net.HttpURLConnection { else requests.set("Cookie", userCookies); } + if (userCookies2 != null) { + int k; + if ((k = requests.getKey("Cookie2")) != -1) + requests.set("Cookie2", requests.getValue(k) + ";" + userCookies2); + else + requests.set("Cookie2", userCookies2); + } } // end of getting cookies } @@ -2530,8 +2662,9 @@ public class HttpURLConnection extends java.net.HttpURLConnection { if (key == null) throw new NullPointerException ("key is null"); - checkMessageHeader(key, value); - requests.set(key, value); + if (isExternalMessageHeaderAllowed(key, value)) { + requests.set(key, value); + } } /** @@ -2552,8 +2685,9 @@ public class HttpURLConnection extends java.net.HttpURLConnection { if (key == null) throw new NullPointerException ("key is null"); - checkMessageHeader(key, value); - requests.add(key, value); + if (isExternalMessageHeaderAllowed(key, value)) { + requests.add(key, value); + } } // @@ -2566,13 +2700,23 @@ public class HttpURLConnection extends java.net.HttpURLConnection { } @Override - public String getRequestProperty (String key) { + public synchronized String getRequestProperty (String key) { + if (key == null) { + return null; + } + // don't return headers containing security sensitive information - if (key != null) { - for (int i=0; i < EXCLUDE_HEADERS.length; i++) { - if (key.equalsIgnoreCase(EXCLUDE_HEADERS[i])) { - return null; - } + for (int i=0; i < EXCLUDE_HEADERS.length; i++) { + if (key.equalsIgnoreCase(EXCLUDE_HEADERS[i])) { + return null; + } + } + if (!setUserCookies) { + if (key.equalsIgnoreCase("Cookie")) { + return userCookies; + } + if (key.equalsIgnoreCase("Cookie2")) { + return userCookies2; } } return requests.findValue(key); @@ -2591,12 +2735,29 @@ public class HttpURLConnection extends java.net.HttpURLConnection { * @since 1.4 */ @Override - public Map> getRequestProperties() { + public synchronized Map> getRequestProperties() { if (connected) throw new IllegalStateException("Already connected"); // exclude headers containing security-sensitive info - return requests.getHeaders(EXCLUDE_HEADERS); + if (setUserCookies) { + return requests.getHeaders(EXCLUDE_HEADERS); + } + /* + * The cookies in the requests message headers may have + * been modified. Use the saved user cookies instead. + */ + Map userCookiesMap = null; + if (userCookies != null || userCookies2 != null) { + userCookiesMap = new HashMap(); + if (userCookies != null) { + userCookiesMap.put("Cookie", userCookies); + } + if (userCookies2 != null) { + userCookiesMap.put("Cookie2", userCookies2); + } + } + return requests.filterAndAddHeaders(EXCLUDE_HEADERS2, userCookiesMap); } @Override diff --git a/src/share/classes/sun/security/jgss/krb5/InitialToken.java b/src/share/classes/sun/security/jgss/krb5/InitialToken.java index 36e0d517b3c4943935c52389dac6610c4b770ebe..e889fcc42a86025968f252f18115bd0c583c12a1 100644 --- a/src/share/classes/sun/security/jgss/krb5/InitialToken.java +++ b/src/share/classes/sun/security/jgss/krb5/InitialToken.java @@ -35,7 +35,6 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import sun.security.krb5.*; -import sun.security.jgss.HttpCaller; import sun.security.krb5.internal.Krb5; abstract class InitialToken extends Krb5Token { @@ -217,6 +216,12 @@ abstract class InitialToken extends Krb5Token { int pos = 0; + if (checksum == null) { + GSSException ge = new GSSException(GSSException.FAILURE, -1, + "No cksum in AP_REQ's authenticator"); + ge.initCause(new KrbException(Krb5.KRB_AP_ERR_INAPP_CKSUM)); + throw ge; + } checksumBytes = checksum.getBytes(); if ((checksumBytes[0] != CHECKSUM_FIRST_BYTES[0]) || diff --git a/src/share/classes/sun/security/ssl/Alerts.java b/src/share/classes/sun/security/ssl/Alerts.java index 2704628dd003bcc3a30a5298d95a8a2ef52e919e..672d9b719d77b7d29793c7d65097099aa671390b 100644 --- a/src/share/classes/sun/security/ssl/Alerts.java +++ b/src/share/classes/sun/security/ssl/Alerts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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 @@ -74,7 +74,7 @@ final class Alerts { static final byte alert_insufficient_security = 71; static final byte alert_internal_error = 80; static final byte alert_user_canceled = 90; - static final byte alert_no_negotiation = 100; + static final byte alert_no_renegotiation = 100; // from RFC 3546 (TLS Extensions) static final byte alert_unsupported_extension = 110; @@ -132,8 +132,8 @@ final class Alerts { return "internal_error"; case alert_user_canceled: return "user_canceled"; - case alert_no_negotiation: - return "no_negotiation"; + case alert_no_renegotiation: + return "no_renegotiation"; case alert_unsupported_extension: return "unsupported_extension"; case alert_certificate_unobtainable: @@ -203,7 +203,7 @@ final class Alerts { case alert_protocol_version: case alert_internal_error: case alert_user_canceled: - case alert_no_negotiation: + case alert_no_renegotiation: default: e = new SSLException(reason); break; diff --git a/src/share/classes/sun/security/ssl/CipherSuite.java b/src/share/classes/sun/security/ssl/CipherSuite.java index 6844e9defa9188081158afcf9f4db94eb1679018..b6619a952a8d6a2091000d5454247968c254206d 100644 --- a/src/share/classes/sun/security/ssl/CipherSuite.java +++ b/src/share/classes/sun/security/ssl/CipherSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, 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 @@ -126,6 +126,8 @@ final class CipherSuite implements Comparable { macAlg = M_SHA; } else if (name.endsWith("_NULL")) { macAlg = M_NULL; + } else if (name.endsWith("_SCSV")) { + macAlg = M_NULL; } else { throw new IllegalArgumentException ("Unknown MAC algorithm for ciphersuite " + name); @@ -160,6 +162,10 @@ final class CipherSuite implements Comparable { return allowed && keyExchange.isAvailable() && cipher.isAvailable(); } + boolean isNegotiable() { + return this != C_SCSV && isAvailable(); + } + /** * Compares CipherSuites based on their priority. Has the effect of * sorting CipherSuites when put in a sorted collection, which is @@ -268,7 +274,10 @@ final class CipherSuite implements Comparable { // Kerberos cipher suites K_KRB5 ("KRB5", true), - K_KRB5_EXPORT("KRB5_EXPORT", true); + K_KRB5_EXPORT("KRB5_EXPORT", true), + + // renegotiation protection request signaling cipher suite + K_SCSV ("SCSV", true); // name of the key exchange algorithm, e.g. DHE_DSS final String name; @@ -352,7 +361,8 @@ final class CipherSuite implements Comparable { this.exportable = true; } - BulkCipher(String transformation, int keySize, int ivSize, boolean allowed) { + BulkCipher(String transformation, int keySize, + int ivSize, boolean allowed) { this.transformation = transformation; this.algorithm = transformation.split("/")[0]; this.description = this.algorithm + "/" + (keySize << 3); @@ -370,7 +380,8 @@ final class CipherSuite implements Comparable { * * @exception NoSuchAlgorithmException if anything goes wrong */ - CipherBox newCipher(ProtocolVersion version, SecretKey key, IvParameterSpec iv, + CipherBox newCipher(ProtocolVersion version, + SecretKey key, IvParameterSpec iv, boolean encrypt) throws NoSuchAlgorithmException { return CipherBox.newCipherBox(version, this, key, iv, encrypt); } @@ -407,8 +418,9 @@ final class CipherSuite implements Comparable { if (b == null) { try { SecretKey key = new SecretKeySpec - (new byte[cipher.expandedKeySize], cipher.algorithm); - IvParameterSpec iv = new IvParameterSpec(new byte[cipher.ivSize]); + (new byte[cipher.expandedKeySize], cipher.algorithm); + IvParameterSpec iv = + new IvParameterSpec(new byte[cipher.ivSize]); cipher.newCipher(ProtocolVersion.DEFAULT, key, iv, true); b = Boolean.TRUE; } catch (NoSuchAlgorithmException e) { @@ -460,18 +472,28 @@ final class CipherSuite implements Comparable { } // export strength ciphers - final static BulkCipher B_NULL = new BulkCipher("NULL", 0, 0, 0, true); - final static BulkCipher B_RC4_40 = new BulkCipher(CIPHER_RC4, 5, 16, 0, true); - final static BulkCipher B_RC2_40 = new BulkCipher("RC2", 5, 16, 8, false); - final static BulkCipher B_DES_40 = new BulkCipher(CIPHER_DES, 5, 8, 8, true); + final static BulkCipher B_NULL = + new BulkCipher("NULL", 0, 0, 0, true); + final static BulkCipher B_RC4_40 = + new BulkCipher(CIPHER_RC4, 5, 16, 0, true); + final static BulkCipher B_RC2_40 = + new BulkCipher("RC2", 5, 16, 8, false); + final static BulkCipher B_DES_40 = + new BulkCipher(CIPHER_DES, 5, 8, 8, true); // domestic strength ciphers - final static BulkCipher B_RC4_128 = new BulkCipher(CIPHER_RC4, 16, 0, true); - final static BulkCipher B_DES = new BulkCipher(CIPHER_DES, 8, 8, true); - final static BulkCipher B_3DES = new BulkCipher(CIPHER_3DES, 24, 8, true); - final static BulkCipher B_IDEA = new BulkCipher("IDEA", 16, 8, false); - final static BulkCipher B_AES_128 = new BulkCipher(CIPHER_AES, 16, 16, true); - final static BulkCipher B_AES_256 = new BulkCipher(CIPHER_AES, 32, 16, true); + final static BulkCipher B_RC4_128 = + new BulkCipher(CIPHER_RC4, 16, 0, true); + final static BulkCipher B_DES = + new BulkCipher(CIPHER_DES, 8, 8, true); + final static BulkCipher B_3DES = + new BulkCipher(CIPHER_3DES, 24, 8, true); + final static BulkCipher B_IDEA = + new BulkCipher("IDEA", 16, 8, false); + final static BulkCipher B_AES_128 = + new BulkCipher(CIPHER_AES, 16, 16, true); + final static BulkCipher B_AES_256 = + new BulkCipher(CIPHER_AES, 32, 16, true); // MACs final static MacAlg M_NULL = new MacAlg("NULL", 0); @@ -487,93 +509,159 @@ final class CipherSuite implements Comparable { // N: ciphersuites only allowed if we are not in FIPS mode final boolean N = (SunJSSE.isFIPS() == false); -add("SSL_NULL_WITH_NULL_NULL", 0x0000, 1, K_NULL, B_NULL, F); + add("SSL_NULL_WITH_NULL_NULL", + 0x0000, 1, K_NULL, B_NULL, F); // Definition of the CipherSuites that are enabled by default. // They are listed in preference order, most preferred first. int p = DEFAULT_SUITES_PRIORITY * 2; -add("SSL_RSA_WITH_RC4_128_MD5", 0x0004, --p, K_RSA, B_RC4_128, N); -add("SSL_RSA_WITH_RC4_128_SHA", 0x0005, --p, K_RSA, B_RC4_128, N); -add("TLS_RSA_WITH_AES_128_CBC_SHA", 0x002f, --p, K_RSA, B_AES_128, T); -add("TLS_RSA_WITH_AES_256_CBC_SHA", 0x0035, --p, K_RSA, B_AES_256, T); - -add("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", 0xC002, --p, K_ECDH_ECDSA, B_RC4_128, N); -add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", 0xC004, --p, K_ECDH_ECDSA, B_AES_128, T); -add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", 0xC005, --p, K_ECDH_ECDSA, B_AES_256, T); -add("TLS_ECDH_RSA_WITH_RC4_128_SHA", 0xC00C, --p, K_ECDH_RSA, B_RC4_128, N); -add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", 0xC00E, --p, K_ECDH_RSA, B_AES_128, T); -add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", 0xC00F, --p, K_ECDH_RSA, B_AES_256, T); - -add("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 0xC007, --p, K_ECDHE_ECDSA,B_RC4_128, N); -add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", 0xC009, --p, K_ECDHE_ECDSA,B_AES_128, T); -add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", 0xC00A, --p, K_ECDHE_ECDSA,B_AES_256, T); -add("TLS_ECDHE_RSA_WITH_RC4_128_SHA", 0xC011, --p, K_ECDHE_RSA, B_RC4_128, N); -add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 0xC013, --p, K_ECDHE_RSA, B_AES_128, T); -add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 0xC014, --p, K_ECDHE_RSA, B_AES_256, T); - -add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 0x0033, --p, K_DHE_RSA, B_AES_128, T); -add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", 0x0039, --p, K_DHE_RSA, B_AES_256, T); -add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 0x0032, --p, K_DHE_DSS, B_AES_128, T); -add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", 0x0038, --p, K_DHE_DSS, B_AES_256, T); - -add("SSL_RSA_WITH_3DES_EDE_CBC_SHA", 0x000a, --p, K_RSA, B_3DES, T); -add("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xC003, --p, K_ECDH_ECDSA, B_3DES, T); -add("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", 0xC00D, --p, K_ECDH_RSA, B_3DES, T); -add("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xC008, --p, K_ECDHE_ECDSA,B_3DES, T); -add("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", 0xC012, --p, K_ECDHE_RSA, B_3DES, T); -add("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", 0x0016, --p, K_DHE_RSA, B_3DES, T); -add("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", 0x0013, --p, K_DHE_DSS, B_3DES, N); - -add("SSL_RSA_WITH_DES_CBC_SHA", 0x0009, --p, K_RSA, B_DES, N); -add("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0015, --p, K_DHE_RSA, B_DES, N); -add("SSL_DHE_DSS_WITH_DES_CBC_SHA", 0x0012, --p, K_DHE_DSS, B_DES, N); -add("SSL_RSA_EXPORT_WITH_RC4_40_MD5", 0x0003, --p, K_RSA_EXPORT, B_RC4_40, N); -add("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0008, --p, K_RSA_EXPORT, B_DES_40, N); -add("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0014, --p, K_DHE_RSA, B_DES_40, N); -add("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x0011, --p, K_DHE_DSS, B_DES_40, N); + add("SSL_RSA_WITH_RC4_128_MD5", + 0x0004, --p, K_RSA, B_RC4_128, N); + add("SSL_RSA_WITH_RC4_128_SHA", + 0x0005, --p, K_RSA, B_RC4_128, N); + add("TLS_RSA_WITH_AES_128_CBC_SHA", + 0x002f, --p, K_RSA, B_AES_128, T); + add("TLS_RSA_WITH_AES_256_CBC_SHA", + 0x0035, --p, K_RSA, B_AES_256, T); + + add("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", + 0xC002, --p, K_ECDH_ECDSA, B_RC4_128, N); + add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", + 0xC004, --p, K_ECDH_ECDSA, B_AES_128, T); + add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", + 0xC005, --p, K_ECDH_ECDSA, B_AES_256, T); + add("TLS_ECDH_RSA_WITH_RC4_128_SHA", + 0xC00C, --p, K_ECDH_RSA, B_RC4_128, N); + add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", + 0xC00E, --p, K_ECDH_RSA, B_AES_128, T); + add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", + 0xC00F, --p, K_ECDH_RSA, B_AES_256, T); + + add("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", + 0xC007, --p, K_ECDHE_ECDSA,B_RC4_128, N); + add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + 0xC009, --p, K_ECDHE_ECDSA,B_AES_128, T); + add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + 0xC00A, --p, K_ECDHE_ECDSA,B_AES_256, T); + add("TLS_ECDHE_RSA_WITH_RC4_128_SHA", + 0xC011, --p, K_ECDHE_RSA, B_RC4_128, N); + add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + 0xC013, --p, K_ECDHE_RSA, B_AES_128, T); + add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + 0xC014, --p, K_ECDHE_RSA, B_AES_256, T); + + add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", + 0x0033, --p, K_DHE_RSA, B_AES_128, T); + add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", + 0x0039, --p, K_DHE_RSA, B_AES_256, T); + add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + 0x0032, --p, K_DHE_DSS, B_AES_128, T); + add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", + 0x0038, --p, K_DHE_DSS, B_AES_256, T); + + add("SSL_RSA_WITH_3DES_EDE_CBC_SHA", + 0x000a, --p, K_RSA, B_3DES, T); + add("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", + 0xC003, --p, K_ECDH_ECDSA, B_3DES, T); + add("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", + 0xC00D, --p, K_ECDH_RSA, B_3DES, T); + add("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", + 0xC008, --p, K_ECDHE_ECDSA,B_3DES, T); + add("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", + 0xC012, --p, K_ECDHE_RSA, B_3DES, T); + add("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + 0x0016, --p, K_DHE_RSA, B_3DES, T); + add("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + 0x0013, --p, K_DHE_DSS, B_3DES, N); + + add("SSL_RSA_WITH_DES_CBC_SHA", + 0x0009, --p, K_RSA, B_DES, N); + add("SSL_DHE_RSA_WITH_DES_CBC_SHA", + 0x0015, --p, K_DHE_RSA, B_DES, N); + add("SSL_DHE_DSS_WITH_DES_CBC_SHA", + 0x0012, --p, K_DHE_DSS, B_DES, N); + add("SSL_RSA_EXPORT_WITH_RC4_40_MD5", + 0x0003, --p, K_RSA_EXPORT, B_RC4_40, N); + add("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + 0x0008, --p, K_RSA_EXPORT, B_DES_40, N); + add("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + 0x0014, --p, K_DHE_RSA, B_DES_40, N); + add("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", + 0x0011, --p, K_DHE_DSS, B_DES_40, N); + + // Renegotiation protection request Signalling Cipher Suite Value (SCSV) + add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", + 0x00ff, --p, K_SCSV, B_NULL, T); // Definition of the CipherSuites that are supported but not enabled // by default. // They are listed in preference order, preferred first. p = DEFAULT_SUITES_PRIORITY; -// Anonymous key exchange and the NULL ciphers -add("SSL_RSA_WITH_NULL_MD5", 0x0001, --p, K_RSA, B_NULL, N); -add("SSL_RSA_WITH_NULL_SHA", 0x0002, --p, K_RSA, B_NULL, N); -add("TLS_ECDH_ECDSA_WITH_NULL_SHA", 0xC001, --p, K_ECDH_ECDSA, B_NULL, N); -add("TLS_ECDH_RSA_WITH_NULL_SHA", 0xC00B, --p, K_ECDH_RSA, B_NULL, N); -add("TLS_ECDHE_ECDSA_WITH_NULL_SHA", 0xC006, --p, K_ECDHE_ECDSA,B_NULL, N); -add("TLS_ECDHE_RSA_WITH_NULL_SHA", 0xC010, --p, K_ECDHE_RSA, B_NULL, N); - -add("SSL_DH_anon_WITH_RC4_128_MD5", 0x0018, --p, K_DH_ANON, B_RC4_128, N); -add("TLS_DH_anon_WITH_AES_128_CBC_SHA", 0x0034, --p, K_DH_ANON, B_AES_128, N); -add("TLS_DH_anon_WITH_AES_256_CBC_SHA", 0x003a, --p, K_DH_ANON, B_AES_256, N); -add("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", 0x001b, --p, K_DH_ANON, B_3DES, N); -add("SSL_DH_anon_WITH_DES_CBC_SHA", 0x001a, --p, K_DH_ANON, B_DES, N); - -add("TLS_ECDH_anon_WITH_RC4_128_SHA", 0xC016, --p, K_ECDH_ANON, B_RC4_128, N); -add("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", 0xC018, --p, K_ECDH_ANON, B_AES_128, T); -add("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", 0xC019, --p, K_ECDH_ANON, B_AES_256, T); -add("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", 0xC017, --p, K_ECDH_ANON, B_3DES, T); - -add("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", 0x0017, --p, K_DH_ANON, B_RC4_40, N); -add("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", 0x0019, --p, K_DH_ANON, B_DES_40, N); - -add("TLS_ECDH_anon_WITH_NULL_SHA", 0xC015, --p, K_ECDH_ANON, B_NULL, N); - -// Supported Kerberos ciphersuites from RFC2712 -add("TLS_KRB5_WITH_RC4_128_SHA", 0x0020, --p, K_KRB5, B_RC4_128, N); -add("TLS_KRB5_WITH_RC4_128_MD5", 0x0024, --p, K_KRB5, B_RC4_128, N); -add("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", 0x001f, --p, K_KRB5, B_3DES, N); -add("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", 0x0023, --p, K_KRB5, B_3DES, N); -add("TLS_KRB5_WITH_DES_CBC_SHA", 0x001e, --p, K_KRB5, B_DES, N); -add("TLS_KRB5_WITH_DES_CBC_MD5", 0x0022, --p, K_KRB5, B_DES, N); -add("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", 0x0028, --p, K_KRB5_EXPORT, B_RC4_40, N); -add("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", 0x002b, --p, K_KRB5_EXPORT, B_RC4_40, N); -add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", 0x0026, --p, K_KRB5_EXPORT, B_DES_40, N); -add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", 0x0029, --p, K_KRB5_EXPORT, B_DES_40, N); - + // Anonymous key exchange and the NULL ciphers + add("SSL_RSA_WITH_NULL_MD5", + 0x0001, --p, K_RSA, B_NULL, N); + add("SSL_RSA_WITH_NULL_SHA", + 0x0002, --p, K_RSA, B_NULL, N); + add("TLS_ECDH_ECDSA_WITH_NULL_SHA", + 0xC001, --p, K_ECDH_ECDSA, B_NULL, N); + add("TLS_ECDH_RSA_WITH_NULL_SHA", + 0xC00B, --p, K_ECDH_RSA, B_NULL, N); + add("TLS_ECDHE_ECDSA_WITH_NULL_SHA", + 0xC006, --p, K_ECDHE_ECDSA,B_NULL, N); + add("TLS_ECDHE_RSA_WITH_NULL_SHA", + 0xC010, --p, K_ECDHE_RSA, B_NULL, N); + + add("SSL_DH_anon_WITH_RC4_128_MD5", + 0x0018, --p, K_DH_ANON, B_RC4_128, N); + add("TLS_DH_anon_WITH_AES_128_CBC_SHA", + 0x0034, --p, K_DH_ANON, B_AES_128, N); + add("TLS_DH_anon_WITH_AES_256_CBC_SHA", + 0x003a, --p, K_DH_ANON, B_AES_256, N); + add("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", + 0x001b, --p, K_DH_ANON, B_3DES, N); + add("SSL_DH_anon_WITH_DES_CBC_SHA", + 0x001a, --p, K_DH_ANON, B_DES, N); + + add("TLS_ECDH_anon_WITH_RC4_128_SHA", + 0xC016, --p, K_ECDH_ANON, B_RC4_128, N); + add("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", + 0xC018, --p, K_ECDH_ANON, B_AES_128, T); + add("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", + 0xC019, --p, K_ECDH_ANON, B_AES_256, T); + add("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", + 0xC017, --p, K_ECDH_ANON, B_3DES, T); + + add("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", + 0x0017, --p, K_DH_ANON, B_RC4_40, N); + add("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", + 0x0019, --p, K_DH_ANON, B_DES_40, N); + + add("TLS_ECDH_anon_WITH_NULL_SHA", + 0xC015, --p, K_ECDH_ANON, B_NULL, N); + + // Supported Kerberos ciphersuites from RFC2712 + add("TLS_KRB5_WITH_RC4_128_SHA", + 0x0020, --p, K_KRB5, B_RC4_128, N); + add("TLS_KRB5_WITH_RC4_128_MD5", + 0x0024, --p, K_KRB5, B_RC4_128, N); + add("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", + 0x001f, --p, K_KRB5, B_3DES, N); + add("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", + 0x0023, --p, K_KRB5, B_3DES, N); + add("TLS_KRB5_WITH_DES_CBC_SHA", + 0x001e, --p, K_KRB5, B_DES, N); + add("TLS_KRB5_WITH_DES_CBC_MD5", + 0x0022, --p, K_KRB5, B_DES, N); + add("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", + 0x0028, --p, K_KRB5_EXPORT, B_RC4_40, N); + add("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", + 0x002b, --p, K_KRB5_EXPORT, B_RC4_40, N); + add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", + 0x0026, --p, K_KRB5_EXPORT, B_DES_40, N); + add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", + 0x0029, --p, K_KRB5_EXPORT, B_DES_40, N); // Register the names of a few additional CipherSuites. // Makes them show up as names instead of numbers in @@ -618,4 +706,6 @@ add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", 0x0029, --p, K_KRB5_EXPORT, B_DES_4 // ciphersuite SSL_NULL_WITH_NULL_NULL final static CipherSuite C_NULL = CipherSuite.valueOf(0, 0); + // ciphersuite TLS_EMPTY_RENEGOTIATION_INFO_SCSV + final static CipherSuite C_SCSV = CipherSuite.valueOf(0x00, 0xff); } diff --git a/src/share/classes/sun/security/ssl/CipherSuiteList.java b/src/share/classes/sun/security/ssl/CipherSuiteList.java index fb3ff162e7e09d33289240622a1158e5b7ddb863..93bfb15a02feede4d0da166e95cdd1ab430eb8ad 100644 --- a/src/share/classes/sun/security/ssl/CipherSuiteList.java +++ b/src/share/classes/sun/security/ssl/CipherSuiteList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, 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 @@ -51,8 +51,9 @@ final class CipherSuiteList { // null if not yet checked. private volatile Boolean containsEC; - // for use by buildAvailableCache() only - private CipherSuiteList(Collection cipherSuites) { + // for use by buildAvailableCache() and + // Handshaker.getKickstartMessage() only + CipherSuiteList(Collection cipherSuites) { this.cipherSuites = cipherSuites; } @@ -221,15 +222,18 @@ final class CipherSuiteList { // SortedSet automatically arranges ciphersuites in default // preference order Set cipherSuites = new TreeSet(); - Collection allowedCipherSuites = CipherSuite.allowedCipherSuites(); + Collection allowedCipherSuites = + CipherSuite.allowedCipherSuites(); for (CipherSuite c : allowedCipherSuites) { if ((c.allowed == false) || (c.priority < minPriority)) { continue; } + if (c.isAvailable()) { cipherSuites.add(c); } } + return new CipherSuiteList(cipherSuites); } diff --git a/src/share/classes/sun/security/ssl/ClientHandshaker.java b/src/share/classes/sun/security/ssl/ClientHandshaker.java index 32013610d9b32e2471116f8f0cac31b500cc5ef0..0e9960e11fc635083831705e751182ce3b9b945c 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, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, 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,16 +94,24 @@ final class ClientHandshaker extends Handshaker { */ ClientHandshaker(SSLSocketImpl socket, SSLContextImpl context, ProtocolList enabledProtocols, - ProtocolVersion activeProtocolVersion) { - super(socket, context, enabledProtocols, true, true); - this.activeProtocolVersion = activeProtocolVersion; + ProtocolVersion activeProtocolVersion, + boolean isInitialHandshake, boolean secureRenegotiation, + byte[] clientVerifyData, byte[] serverVerifyData) { + + super(socket, context, enabledProtocols, true, true, + activeProtocolVersion, isInitialHandshake, secureRenegotiation, + clientVerifyData, serverVerifyData); } ClientHandshaker(SSLEngineImpl engine, SSLContextImpl context, ProtocolList enabledProtocols, - ProtocolVersion activeProtocolVersion) { - super(engine, context, enabledProtocols, true, true); - this.activeProtocolVersion = activeProtocolVersion; + ProtocolVersion activeProtocolVersion, + boolean isInitialHandshake, boolean secureRenegotiation, + byte[] clientVerifyData, byte[] serverVerifyData) { + + super(engine, context, enabledProtocols, true, true, + activeProtocolVersion, isInitialHandshake, secureRenegotiation, + clientVerifyData, serverVerifyData); } /* @@ -279,10 +287,11 @@ final class ClientHandshaker extends Handshaker { // sent the "client hello" but the server's not seen it. // if (state < HandshakeMessage.ht_client_hello) { - if (!renegotiable) { // renegotiation is not allowed. + if (!secureRenegotiation && !allowUnsafeRenegotiation) { + // renegotiation is not allowed. if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) { - // response with a no_negotiation warning, - warningSE(Alerts.alert_no_negotiation); + // response with a no_renegotiation warning, + warningSE(Alerts.alert_no_renegotiation); // invalidate the handshake so that the caller can // dispose this object. @@ -293,26 +302,24 @@ final class ClientHandshaker extends Handshaker { // and the next handshake message will become incomplete. // // However, according to SSL/TLS specifications, no more - // handshake message could immediately follow ClientHello - // or HelloRequest. But in case of any improper messages, - // we'd better check to ensure there is no remaining bytes - // in the handshake input stream. - if (input.available() > 0) { - fatalSE(Alerts.alert_unexpected_message, - "HelloRequest followed by an unexpected " + - "handshake message"); - } - + // handshake message should immediately follow ClientHello + // or HelloRequest. So just let it be. } else { // For SSLv3, send the handshake_failure fatal error. - // Note that SSLv3 does not define a no_negotiation alert - // like TLSv1. However we cannot ignore the message + // Note that SSLv3 does not define a no_renegotiation + // alert like TLSv1. However we cannot ignore the message // simply, otherwise the other side was waiting for a // response that would never come. fatalSE(Alerts.alert_handshake_failure, - "renegotiation is not allowed"); + "Renegotiation is not allowed"); } } else { + if (!secureRenegotiation) { + if (debug != null && Debug.isOn("handshake")) { + System.out.println( + "Warning: continue with insecure renegotiation"); + } + } kickstart(); } } @@ -347,6 +354,68 @@ final class ClientHandshaker extends Handshaker { // Handshake streams setVersion(mesgVersion); + // check the "renegotiation_info" extension + RenegotiationInfoExtension serverHelloRI = (RenegotiationInfoExtension) + mesg.extensions.get(ExtensionType.EXT_RENEGOTIATION_INFO); + if (serverHelloRI != null) { + if (isInitialHandshake) { + // verify the length of the "renegotiated_connection" field + if (!serverHelloRI.isEmpty()) { + // abort the handshake with a fatal handshake_failure alert + fatalSE(Alerts.alert_handshake_failure, + "The renegotiation_info field is not empty"); + } + + secureRenegotiation = true; + } else { + // For a legacy renegotiation, the client MUST verify that + // it does not contain the "renegotiation_info" extension. + if (!secureRenegotiation) { + fatalSE(Alerts.alert_handshake_failure, + "Unexpected renegotiation indication extension"); + } + + // verify the client_verify_data and server_verify_data values + byte[] verifyData = + new byte[clientVerifyData.length + serverVerifyData.length]; + System.arraycopy(clientVerifyData, 0, verifyData, + 0, clientVerifyData.length); + System.arraycopy(serverVerifyData, 0, verifyData, + clientVerifyData.length, serverVerifyData.length); + if (!Arrays.equals(verifyData, + serverHelloRI.getRenegotiatedConnection())) { + fatalSE(Alerts.alert_handshake_failure, + "Incorrect verify data in ServerHello " + + "renegotiation_info message"); + } + } + } else { + // no renegotiation indication extension + if (isInitialHandshake) { + if (!allowLegacyHelloMessages) { + // abort the handshake with a fatal handshake_failure alert + fatalSE(Alerts.alert_handshake_failure, + "Failed to negotiate the use of secure renegotiation"); + } + + secureRenegotiation = false; + if (debug != null && Debug.isOn("handshake")) { + System.out.println("Warning: No renegotiation " + + "indication extension in ServerHello"); + } + } else { + // For a secure renegotiation, the client must abort the + // handshake if no "renegotiation_info" extension is present. + if (secureRenegotiation) { + fatalSE(Alerts.alert_handshake_failure, + "No renegotiation indication extension"); + } + + // we have already allowed unsafe renegotation before request + // the renegotiation. + } + } + // // Save server nonce, we always use it to compute connection // keys and it's also used to create the master secret if we're @@ -354,10 +423,11 @@ final class ClientHandshaker extends Handshaker { // svr_random = mesg.svr_random; - if (isEnabled(mesg.cipherSuite) == false) { + if (isNegotiable(mesg.cipherSuite) == false) { fatalSE(Alerts.alert_illegal_parameter, - "Server selected disabled ciphersuite " + cipherSuite); + "Server selected improper ciphersuite " + cipherSuite); } + setCipherSuite(mesg.cipherSuite); if (mesg.compression_method != 0) { @@ -452,7 +522,8 @@ final class ClientHandshaker extends Handshaker { for (HelloExtension ext : mesg.extensions.list()) { ExtensionType type = ext.type; if ((type != ExtensionType.EXT_ELLIPTIC_CURVES) - && (type != ExtensionType.EXT_EC_POINT_FORMATS)) { + && (type != ExtensionType.EXT_EC_POINT_FORMATS) + && (type != ExtensionType.EXT_RENEGOTIATION_INFO)) { fatalSE(Alerts.alert_unsupported_extension, "Server sent an unsupported extension: " + type); } @@ -868,6 +939,13 @@ final class ClientHandshaker extends Handshaker { // NOTREACHED } + /* + * save server verify data for secure renegotiation + */ + if (secureRenegotiation) { + serverVerifyData = mesg.getVerifyData(); + } + /* * OK, it verified. If we're doing the fast handshake, add that * "Finished" message to the hash of handshake messages, then send @@ -920,6 +998,13 @@ final class ClientHandshaker extends Handshaker { */ sendChangeCipherSpec(mesg, finishedTag); + /* + * save client verify data for secure renegotiation + */ + if (secureRenegotiation) { + clientVerifyData = mesg.getVerifyData(); + } + /* * Update state machine so server MUST send 'finished' next. * (In "long" handshake case; in short case, we're responding @@ -933,11 +1018,14 @@ final class ClientHandshaker extends Handshaker { * Returns a ClientHello message to kickstart renegotiations */ HandshakeMessage getKickstartMessage() throws SSLException { - ClientHello mesg = new ClientHello(sslContext.getSecureRandom(), - protocolVersion); - maxProtocolVersion = protocolVersion; + // session ID of the ClientHello message + SessionId sessionId = SSLSessionImpl.nullSession.getSessionId(); + + // a list of cipher suites sent by the client + CipherSuiteList cipherSuites = enabledCipherSuites; - clnt_random = mesg.clnt_random; + // set the max protocol version this client is supporting. + maxProtocolVersion = protocolVersion; // // Try to resume an existing session. This might be mandatory, @@ -962,9 +1050,9 @@ final class ClientHandshaker extends Handshaker { if (session != null) { CipherSuite sessionSuite = session.getSuite(); ProtocolVersion sessionVersion = session.getProtocolVersion(); - if (isEnabled(sessionSuite) == false) { + if (isNegotiable(sessionSuite) == false) { if (debug != null && Debug.isOn("session")) { - System.out.println("%% can't resume, cipher disabled"); + System.out.println("%% can't resume, unavailable cipher"); } session = null; } @@ -984,9 +1072,8 @@ final class ClientHandshaker extends Handshaker { + " from port " + getLocalPortSE()); } } - mesg.sessionId = session.getSessionId(); - mesg.protocolVersion = sessionVersion; + sessionId = session.getSessionId(); maxProtocolVersion = sessionVersion; // Update SSL version number in underlying SSL socket and @@ -995,33 +1082,78 @@ final class ClientHandshaker extends Handshaker { setVersion(sessionVersion); } - // - // don't say much beyond the obvious if we _must_ resume. - // + /* + * Force use of the previous session ciphersuite, and + * add the SCSV if enabled. + */ if (!enableNewSession) { if (session == null) { throw new SSLException( "Can't reuse existing SSL client session"); } - mesg.setCipherSuites(new CipherSuiteList(sessionSuite)); - return mesg; + + Collection cipherList = + new ArrayList(2); + cipherList.add(sessionSuite); + if (!secureRenegotiation && + cipherSuites.contains(CipherSuite.C_SCSV)) { + cipherList.add(CipherSuite.C_SCSV); + } // otherwise, renegotiation_info extension will be used + + cipherSuites = new CipherSuiteList(cipherList); } } - if (session == null) { - if (enableNewSession) { - mesg.sessionId = SSLSessionImpl.nullSession.getSessionId(); - } else { - throw new SSLException("No existing session to resume."); + + if (session == null && !enableNewSession) { + throw new SSLException("No existing session to resume"); + } + + // exclude SCSV for secure renegotiation + if (secureRenegotiation && cipherSuites.contains(CipherSuite.C_SCSV)) { + Collection cipherList = + new ArrayList(cipherSuites.size() - 1); + for (CipherSuite suite : cipherSuites.collection()) { + if (suite != CipherSuite.C_SCSV) { + cipherList.add(suite); + } } + + cipherSuites = new CipherSuiteList(cipherList); } - // - // All we have left to do is fill out the cipher suites. - // (If this changes, change the 'return' above!) - // - mesg.setCipherSuites(enabledCipherSuites); + // make sure there is a negotiable cipher suite. + boolean negotiable = false; + for (CipherSuite suite : cipherSuites.collection()) { + if (isNegotiable(suite)) { + negotiable = true; + break; + } + } + + if (!negotiable) { + throw new SSLException("No negotiable cipher suite"); + } + + // create the ClientHello message + ClientHello clientHelloMessage = new ClientHello( + sslContext.getSecureRandom(), maxProtocolVersion, + sessionId, cipherSuites); + + // reset the client random cookie + clnt_random = clientHelloMessage.clnt_random; + + /* + * need to set the renegotiation_info extension for: + * 1: secure renegotiation + * 2: initial handshake and no SCSV in the ClientHello + * 3: insecure renegotiation and no SCSV in the ClientHello + */ + if (secureRenegotiation || + !cipherSuites.contains(CipherSuite.C_SCSV)) { + clientHelloMessage.addRenegotiationInfoExtension(clientVerifyData); + } - return mesg; + return clientHelloMessage; } /* diff --git a/src/share/classes/sun/security/ssl/HandshakeMessage.java b/src/share/classes/sun/security/ssl/HandshakeMessage.java index 3bb60877034fa2f4fd42230ac89a84847177ef4e..126ad310345dedab5d36b9fe482e578947ffd725 100644 --- a/src/share/classes/sun/security/ssl/HandshakeMessage.java +++ b/src/share/classes/sun/security/ssl/HandshakeMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, 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 @@ -172,9 +172,7 @@ public abstract class HandshakeMessage { * Server can ask the client to initiate a new handshake, e.g. to change * session parameters after a connection has been (re)established. */ -static final -class HelloRequest extends HandshakeMessage -{ +static final class HelloRequest extends HandshakeMessage { int messageType() { return ht_hello_request; } HelloRequest() { } @@ -210,10 +208,7 @@ class HelloRequest extends HandshakeMessage * Until we know how to parse it, we will just read what we know * about, and let our caller handle the jumps over unknown data. */ -static final -class ClientHello extends HandshakeMessage -{ - int messageType() { return ht_client_hello; } +static final class ClientHello extends HandshakeMessage { ProtocolVersion protocolVersion; RandomCookie clnt_random; @@ -225,27 +220,48 @@ class ClientHello extends HandshakeMessage private final static byte[] NULL_COMPRESSION = new byte[] {0}; - ClientHello(SecureRandom generator, ProtocolVersion protocolVersion) { + ClientHello(SecureRandom generator, ProtocolVersion protocolVersion, + SessionId sessionId, CipherSuiteList cipherSuites) { + this.protocolVersion = protocolVersion; + this.sessionId = sessionId; + this.cipherSuites = cipherSuites; + + if (cipherSuites.containsEC()) { + extensions.add(SupportedEllipticCurvesExtension.DEFAULT); + extensions.add(SupportedEllipticPointFormatsExtension.DEFAULT); + } + clnt_random = new RandomCookie(generator); compression_methods = NULL_COMPRESSION; - // sessionId, cipher_suites TBS later + } + + ClientHello(HandshakeInStream s, int messageLength) throws IOException { + protocolVersion = ProtocolVersion.valueOf(s.getInt8(), s.getInt8()); + clnt_random = new RandomCookie(s); + sessionId = new SessionId(s.getBytes8()); + cipherSuites = new CipherSuiteList(s); + compression_methods = s.getBytes8(); + if (messageLength() != messageLength) { + extensions = new HelloExtensions(s); + } } CipherSuiteList getCipherSuites() { return cipherSuites; } - // Set the ciphersuites. - // This method may only be called once. - void setCipherSuites(CipherSuiteList cipherSuites) { - this.cipherSuites = cipherSuites; - if (cipherSuites.containsEC()) { - extensions.add(SupportedEllipticCurvesExtension.DEFAULT); - extensions.add(SupportedEllipticPointFormatsExtension.DEFAULT); - } + // add renegotiation_info extension + void addRenegotiationInfoExtension(byte[] clientVerifyData) { + HelloExtension renegotiationInfo = new RenegotiationInfoExtension( + clientVerifyData, new byte[0]); + extensions.add(renegotiationInfo); } + @Override + int messageType() { return ht_client_hello; } + + @Override int messageLength() { /* * Add fixed size parts of each field... @@ -258,17 +274,7 @@ class ClientHello extends HandshakeMessage + extensions.length(); } - ClientHello(HandshakeInStream s, int messageLength) throws IOException { - protocolVersion = ProtocolVersion.valueOf(s.getInt8(), s.getInt8()); - clnt_random = new RandomCookie(s); - sessionId = new SessionId(s.getBytes8()); - cipherSuites = new CipherSuiteList(s); - compression_methods = s.getBytes8(); - if (messageLength() != messageLength) { - extensions = new HelloExtensions(s); - } - } - + @Override void send(HandshakeOutStream s) throws IOException { s.putInt8(protocolVersion.major); s.putInt8(protocolVersion.minor); @@ -279,6 +285,7 @@ class ClientHello extends HandshakeMessage extensions.send(s); } + @Override void print(PrintStream s) throws IOException { s.println("*** ClientHello, " + protocolVersion); @@ -315,7 +322,6 @@ class ServerHello extends HandshakeMessage CipherSuite cipherSuite; byte compression_method; HelloExtensions extensions = new HelloExtensions(); - int extensionLength; ServerHello() { // empty @@ -1425,8 +1431,6 @@ static final class CertificateVerify extends HandshakeMessage { */ static final class Finished extends HandshakeMessage { - int messageType() { return ht_finished; } - // constant for a Finished message sent by the client final static int CLIENT = 1; @@ -1468,7 +1472,7 @@ static final class Finished extends HandshakeMessage { * both client and server are fully in sync, and that the handshake * computations have been successful. */ - boolean verify(ProtocolVersion protocolVersion, + boolean verify(ProtocolVersion protocolVersion, HandshakeHash handshakeHash, int sender, SecretKey master) { byte[] myFinished = getFinished(protocolVersion, handshakeHash, sender, master); @@ -1542,14 +1546,25 @@ static final class Finished extends HandshakeMessage { CertificateVerify.updateDigest(md, pad1, pad2, masterSecret); } + // get the verify_data of the finished message + byte[] getVerifyData() { + return verifyData; + } + + @Override + int messageType() { return ht_finished; } + + @Override int messageLength() { return verifyData.length; } + @Override void send(HandshakeOutStream out) throws IOException { out.write(verifyData); } + @Override void print(PrintStream s) throws IOException { s.println("*** Finished"); if (debug != null && Debug.isOn("verbose")) { @@ -1557,7 +1572,6 @@ static final class Finished extends HandshakeMessage { s.println("***"); } } - } // diff --git a/src/share/classes/sun/security/ssl/Handshaker.java b/src/share/classes/sun/security/ssl/Handshaker.java index 2f55fbdfa359943e298752bf0586a27475936db0..ddef8fc221a31d899f87ff55a5c0af914c3ec6a1 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, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, 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 @@ -66,6 +66,14 @@ abstract class Handshaker { // the currently active protocol version during a renegotiation ProtocolVersion activeProtocolVersion; + // security parameters for secure renegotiation. + boolean secureRenegotiation; + byte[] clientVerifyData; + byte[] serverVerifyData; + + // is it an initial negotiation or a renegotiation? + boolean isInitialHandshake; + // list of enabled protocols ProtocolList enabledProtocols; @@ -128,31 +136,66 @@ abstract class Handshaker { static final Debug debug = Debug.getInstance("ssl"); // By default, disable the unsafe legacy session renegotiation - static final boolean renegotiable = Debug.getBooleanProperty( + static final boolean allowUnsafeRenegotiation = Debug.getBooleanProperty( "sun.security.ssl.allowUnsafeRenegotiation", false); + // For maximum interoperability and backward compatibility, RFC 5746 + // allows server (or client) to accept ClientHello (or ServerHello) + // message without the secure renegotiation_info extension or SCSV. + // + // For maximum security, RFC 5746 also allows server (or client) to + // reject such message with a fatal "handshake_failure" alert. + // + // By default, allow such legacy hello messages. + static final boolean allowLegacyHelloMessages = Debug.getBooleanProperty( + "sun.security.ssl.allowLegacyHelloMessages", true); + // need to dispose the object when it is invalidated boolean invalidated; Handshaker(SSLSocketImpl c, SSLContextImpl context, ProtocolList enabledProtocols, boolean needCertVerify, - boolean isClient) { + boolean isClient, ProtocolVersion activeProtocolVersion, + boolean isInitialHandshake, boolean secureRenegotiation, + byte[] clientVerifyData, byte[] serverVerifyData) { this.conn = c; - init(context, enabledProtocols, needCertVerify, isClient); + init(context, enabledProtocols, needCertVerify, isClient, + activeProtocolVersion, isInitialHandshake, secureRenegotiation, + clientVerifyData, serverVerifyData); } Handshaker(SSLEngineImpl engine, SSLContextImpl context, ProtocolList enabledProtocols, boolean needCertVerify, - boolean isClient) { + boolean isClient, ProtocolVersion activeProtocolVersion, + boolean isInitialHandshake, boolean secureRenegotiation, + byte[] clientVerifyData, byte[] serverVerifyData) { this.engine = engine; - init(context, enabledProtocols, needCertVerify, isClient); + init(context, enabledProtocols, needCertVerify, isClient, + activeProtocolVersion, isInitialHandshake, secureRenegotiation, + clientVerifyData, serverVerifyData); } private void init(SSLContextImpl context, ProtocolList enabledProtocols, - boolean needCertVerify, boolean isClient) { + boolean needCertVerify, boolean isClient, + ProtocolVersion activeProtocolVersion, + boolean isInitialHandshake, boolean secureRenegotiation, + byte[] clientVerifyData, byte[] serverVerifyData) { + + if (debug != null && Debug.isOn("handshake")) { + System.out.println( + "Allow unsafe renegotiation: " + allowUnsafeRenegotiation + + "\nAllow legacy hello messages: " + allowLegacyHelloMessages + + "\nIs initial handshake: " + isInitialHandshake + + "\nIs secure renegotiation: " + secureRenegotiation); + } this.sslContext = context; this.isClient = isClient; + this.activeProtocolVersion = activeProtocolVersion; + this.isInitialHandshake = isInitialHandshake; + this.secureRenegotiation = secureRenegotiation; + this.clientVerifyData = clientVerifyData; + this.serverVerifyData = serverVerifyData; enableNewSession = true; invalidated = false; @@ -353,8 +396,8 @@ abstract class Handshaker { * changed due to change in JCE providers since it was enabled). * Does not check if the required server certificates are available. */ - boolean isEnabled(CipherSuite s) { - return enabledCipherSuites.contains(s) && s.isAvailable(); + boolean isNegotiable(CipherSuite s) { + return enabledCipherSuites.contains(s) && s.isNegotiable(); } /** @@ -458,6 +501,27 @@ abstract class Handshaker { return session; } + /* + * Returns true if renegotiation is in use for this connection. + */ + boolean isSecureRenegotiation() { + return secureRenegotiation; + } + + /* + * Returns the verify_data from the Finished message sent by the client. + */ + byte[] getClientVerifyData() { + return clientVerifyData; + } + + /* + * Returns the verify_data from the Finished message sent by the server. + */ + byte[] getServerVerifyData() { + return serverVerifyData; + } + /* * This routine is fed SSL handshake records when they become available, * and processes messages found therein. diff --git a/src/share/classes/sun/security/ssl/HelloExtensions.java b/src/share/classes/sun/security/ssl/HelloExtensions.java index a59037fe35df8ef5e4452381e214dc2377a627c6..8b2764494ea82bc2d92b84a0393fe549cc1f7006 100644 --- a/src/share/classes/sun/security/ssl/HelloExtensions.java +++ b/src/share/classes/sun/security/ssl/HelloExtensions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2010, 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 @@ -81,7 +81,10 @@ final class HelloExtensions { } else if (extType == ExtensionType.EXT_ELLIPTIC_CURVES) { extension = new SupportedEllipticCurvesExtension(s, extlen); } else if (extType == ExtensionType.EXT_EC_POINT_FORMATS) { - extension = new SupportedEllipticPointFormatsExtension(s, extlen); + extension = + new SupportedEllipticPointFormatsExtension(s, extlen); + } else if (extType == ExtensionType.EXT_RENEGOTIATION_INFO) { + extension = new RenegotiationInfoExtension(s, extlen); } else { extension = new UnknownExtension(s, extlen, extType); } @@ -89,7 +92,8 @@ final class HelloExtensions { len -= extlen + 4; } if (len != 0) { - throw new SSLProtocolException("Error parsing extensions: extra data"); + throw new SSLProtocolException( + "Error parsing extensions: extra data"); } } @@ -162,7 +166,8 @@ final class ExtensionType { return name; } - static List knownExtensions = new ArrayList(8); + static List knownExtensions = + new ArrayList(9); static ExtensionType get(int id) { for (ExtensionType ext : knownExtensions) { @@ -180,17 +185,44 @@ final class ExtensionType { } // extensions defined in RFC 3546 - final static ExtensionType EXT_SERVER_NAME = e( 0, "server_name"); - final static ExtensionType EXT_MAX_FRAGMENT_LENGTH = e( 1, "max_fragment_length"); - final static ExtensionType EXT_CLIENT_CERTIFICATE_URL = e( 2, "client_certificate_url"); - final static ExtensionType EXT_TRUSTED_CA_KEYS = e( 3, "trusted_ca_keys"); - final static ExtensionType EXT_TRUNCATED_HMAC = e( 4, "truncated_hmac"); - final static ExtensionType EXT_STATUS_REQUEST = e( 5, "status_request"); + final static ExtensionType EXT_SERVER_NAME = + e(0x0000, "server_name"); // IANA registry value: 0 + final static ExtensionType EXT_MAX_FRAGMENT_LENGTH = + e(0x0001, "max_fragment_length"); // IANA registry value: 1 + final static ExtensionType EXT_CLIENT_CERTIFICATE_URL = + e(0x0002, "client_certificate_url"); // IANA registry value: 2 + final static ExtensionType EXT_TRUSTED_CA_KEYS = + e(0x0003, "trusted_ca_keys"); // IANA registry value: 3 + final static ExtensionType EXT_TRUNCATED_HMAC = + e(0x0004, "truncated_hmac"); // IANA registry value: 4 + final static ExtensionType EXT_STATUS_REQUEST = + e(0x0005, "status_request"); // IANA registry value: 5 + + // extensions defined in RFC 4681 + final static ExtensionType EXT_USER_MAPPING = + e(0x0006, "user_mapping"); // IANA registry value: 6 + + // extensions defined in RFC 5081 + final static ExtensionType EXT_CERT_TYPE = + e(0x0009, "cert_type"); // IANA registry value: 9 // extensions defined in RFC 4492 (ECC) - final static ExtensionType EXT_ELLIPTIC_CURVES = e(10, "elliptic_curves"); - final static ExtensionType EXT_EC_POINT_FORMATS = e(11, "ec_point_formats"); - + final static ExtensionType EXT_ELLIPTIC_CURVES = + e(0x000A, "elliptic_curves"); // IANA registry value: 10 + final static ExtensionType EXT_EC_POINT_FORMATS = + e(0x000B, "ec_point_formats"); // IANA registry value: 11 + + // extensions defined in RFC 5054 + final static ExtensionType EXT_SRP = + e(0x000C, "srp"); // IANA registry value: 12 + + // extensions defined in RFC 5246 + final static ExtensionType EXT_SIGNATURE_ALGORITHMS = + e(0x000D, "signature_algorithms"); // IANA registry value: 13 + + // extensions defined in RFC 5746 + final static ExtensionType EXT_RENEGOTIATION_INFO = + e(0xff01, "renegotiation_info"); // IANA registry value: 65281 } abstract class HelloExtension { @@ -238,9 +270,11 @@ final class UnknownExtension extends HelloExtension { } } -// Support for the server_name extension is incomplete. Parsing is implemented -// so that we get nicer debug output, but we neither send it nor do we do -// act on it if we receive it. +/* + * Support for the server_name extension is incomplete. Parsing is implemented + * so that we get nicer debug output, but we neither send it nor do we do + * act on it if we receive it. + */ final class ServerNameExtension extends HelloExtension { final static int NAME_HOST_NAME = 0; @@ -268,9 +302,9 @@ final class ServerNameExtension extends HelloExtension { final String hostname; ServerName(HandshakeInStream s) throws IOException { - length = s.getInt16(); - type = s.getInt8(); - data = s.getBytes16(); + length = s.getInt16(); // ServerNameList length + type = s.getInt8(); // NameType + data = s.getBytes16(); // HostName (length read in getBytes16) if (type == NAME_HOST_NAME) { hostname = new String(data, "UTF8"); } else { @@ -549,3 +583,85 @@ final class SupportedEllipticPointFormatsExtension extends HelloExtension { return "Extension " + type + ", formats: " + list; } } + +/* + * For secure renegotiation, RFC5746 defines a new TLS extension, + * "renegotiation_info" (with extension type 0xff01), which contains a + * cryptographic binding to the enclosing TLS connection (if any) for + * which the renegotiation is being performed. The "extension data" + * field of this extension contains a "RenegotiationInfo" structure: + * + * struct { + * opaque renegotiated_connection<0..255>; + * } RenegotiationInfo; + */ +final class RenegotiationInfoExtension extends HelloExtension { + private final byte[] renegotiated_connection; + + RenegotiationInfoExtension(byte[] clientVerifyData, + byte[] serverVerifyData) { + super(ExtensionType.EXT_RENEGOTIATION_INFO); + + if (clientVerifyData.length != 0) { + renegotiated_connection = + new byte[clientVerifyData.length + serverVerifyData.length]; + System.arraycopy(clientVerifyData, 0, renegotiated_connection, + 0, clientVerifyData.length); + + if (serverVerifyData.length != 0) { + System.arraycopy(serverVerifyData, 0, renegotiated_connection, + clientVerifyData.length, serverVerifyData.length); + } + } else { + // ignore both the client and server verify data. + renegotiated_connection = new byte[0]; + } + } + + RenegotiationInfoExtension(HandshakeInStream s, int len) + throws IOException { + super(ExtensionType.EXT_RENEGOTIATION_INFO); + + // check the extension length + if (len < 1) { + throw new SSLProtocolException("Invalid " + type + " extension"); + } + + int renegoInfoDataLen = s.getInt8(); + if (renegoInfoDataLen + 1 != len) { // + 1 = the byte we just read + throw new SSLProtocolException("Invalid " + type + " extension"); + } + + renegotiated_connection = new byte[renegoInfoDataLen]; + if (renegoInfoDataLen != 0) { + s.read(renegotiated_connection, 0, renegoInfoDataLen); + } + } + + + // Length of the encoded extension, including the type and length fields + int length() { + return 5 + renegotiated_connection.length; + } + + void send(HandshakeOutStream s) throws IOException { + s.putInt16(type.id); + s.putInt16(renegotiated_connection.length + 1); + s.putBytes8(renegotiated_connection); + } + + boolean isEmpty() { + return renegotiated_connection.length == 0; + } + + byte[] getRenegotiatedConnection() { + return renegotiated_connection; + } + + public String toString() { + return "Extension " + type + ", renegotiated_connection: " + + (renegotiated_connection.length == 0 ? "" : + Debug.toString(renegotiated_connection)); + } + +} diff --git a/src/share/classes/sun/security/ssl/OutputRecord.java b/src/share/classes/sun/security/ssl/OutputRecord.java index 67fb344a939d9a9244b9cd5ee7d1118fb082e447..e5c7a6def78b6e3c494f4e751ce05b08c58a7261 100644 --- a/src/share/classes/sun/security/ssl/OutputRecord.java +++ b/src/share/classes/sun/security/ssl/OutputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, 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 @@ -343,6 +343,9 @@ class OutputRecord extends ByteArrayOutputStream implements Record { * example, Netscape Commerce 1.0 servers. The V3 message is in the * header and the bytes passed as parameter. This routine translates * the V3 message into an equivalent V2 one. + * + * Note that the translation will strip off all hello extensions as + * SSL V2.0 does not support hello extension. */ private void V3toV2ClientHello(byte v3Msg []) throws SSLException { int v3SessionIdLenOffset = 2 + 32; // version + nonce @@ -361,12 +364,21 @@ class OutputRecord extends ByteArrayOutputStream implements Record { int v3CipherSpecOffset = v3CipherSpecLenOffset + 2; // skip length int v2CipherSpecLen = 0; count = 11; + boolean containsRenegoInfoSCSV = false; for (int i = 0; i < cipherSpecs; i++) { byte byte1, byte2; byte1 = v3Msg[v3CipherSpecOffset++]; byte2 = v3Msg[v3CipherSpecOffset++]; v2CipherSpecLen += V3toV2CipherSuite(byte1, byte2); + if (!containsRenegoInfoSCSV && + byte1 == (byte)0x00 && byte2 == (byte)0xFF) { + containsRenegoInfoSCSV = true; + } + } + + if (!containsRenegoInfoSCSV) { + v2CipherSpecLen += V3toV2CipherSuite((byte)0x00, (byte)0xFF); } /* diff --git a/src/share/classes/sun/security/ssl/SSLEngineImpl.java b/src/share/classes/sun/security/ssl/SSLEngineImpl.java index 654bd248ff5cd18da711ccbcde198976df615040..cd7122aec19ada99f241d83f8ad1b8d657fa1f48 100644 --- a/src/share/classes/sun/security/ssl/SSLEngineImpl.java +++ b/src/share/classes/sun/security/ssl/SSLEngineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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 @@ -275,6 +275,12 @@ final public class SSLEngineImpl extends SSLEngine { private CipherBox readCipher, writeCipher; // NOTE: compression state would be saved here + /* + * security parameters for secure renegotiation. + */ + private boolean secureRenegotiation; + private byte[] clientVerifyData; + private byte[] serverVerifyData; /* * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME * @@ -356,6 +362,11 @@ final public class SSLEngineImpl extends SSLEngine { writeCipher = CipherBox.NULL; writeMAC = MAC.NULL; + // default security parameters for secure renegotiation + secureRenegotiation = false; + clientVerifyData = new byte[0]; + serverVerifyData = new byte[0]; + enabledCipherSuites = CipherSuiteList.getDefault(); enabledProtocols = ProtocolList.getDefault(); @@ -434,11 +445,14 @@ final public class SSLEngineImpl extends SSLEngine { } if (roleIsServer) { handshaker = new ServerHandshaker(this, sslContext, - enabledProtocols, doClientAuth, - connectionState == cs_RENEGOTIATE, protocolVersion); + enabledProtocols, doClientAuth, + protocolVersion, connectionState == cs_HANDSHAKE, + secureRenegotiation, clientVerifyData, serverVerifyData); } else { handshaker = new ClientHandshaker(this, sslContext, - enabledProtocols, protocolVersion); + enabledProtocols, + protocolVersion, connectionState == cs_HANDSHAKE, + secureRenegotiation, clientVerifyData, serverVerifyData); } handshaker.enabledCipherSuites = enabledCipherSuites; handshaker.setEnableSessionCreation(enableSessionCreation); @@ -640,8 +654,16 @@ final public class SSLEngineImpl extends SSLEngine { break; case cs_DATA: - if (!Handshaker.renegotiable) { - throw new SSLHandshakeException("renegotiation is not allowed"); + if (!secureRenegotiation && !Handshaker.allowUnsafeRenegotiation) { + throw new SSLHandshakeException( + "Insecure renegotiation is not allowed"); + } + + if (!secureRenegotiation) { + if (debug != null && Debug.isOn("handshake")) { + System.out.println( + "Warning: Using insecure renegotiation"); + } } // initialize the handshaker, move to cs_RENEGOTIATE @@ -978,6 +1000,12 @@ final public class SSLEngineImpl extends SSLEngine { connectionState = cs_DATA; } } else if (handshaker.isDone()) { + // reset the parameters for secure renegotiation. + secureRenegotiation = + handshaker.isSecureRenegotiation(); + clientVerifyData = handshaker.getClientVerifyData(); + serverVerifyData = handshaker.getServerVerifyData(); + sess = handshaker.getSession(); if (!writer.hasOutboundData()) { hsStatus = HandshakeStatus.FINISHED; diff --git a/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java b/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java index a2870ddaa0be37bfe922e7a4a665467fe429981e..914406b2e4281d1672c8ca8a663801b8e74b4297 100644 --- a/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java +++ b/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, 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 @@ -307,8 +307,9 @@ class SSLServerSocketImpl extends SSLServerSocket try { ServerHandshaker handshaker = tmp.getServerHandshaker(); - for (Iterator t = enabledCipherSuites.iterator(); t.hasNext(); ) { - CipherSuite suite = (CipherSuite)t.next(); + for (Iterator t = enabledCipherSuites.iterator(); + t.hasNext();) { + CipherSuite suite = t.next(); if (handshaker.trySetCipherSuite(suite)) { checkedEnabled = true; return; diff --git a/src/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/share/classes/sun/security/ssl/SSLSocketImpl.java index d9bfecfb31978d8fd86cebd8286fc6eedd28410f..a360fe7a2aaae4a1f0afde1200e664c57850d4ec 100644 --- a/src/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/src/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, 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 @@ -275,9 +275,9 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { * This is necessary so that processing of close_notify alerts * from the peer are handled properly. */ - private Object handshakeLock; - ReentrantLock writeLock; - private Object readLock; + final private Object handshakeLock = new Object(); + final ReentrantLock writeLock = new ReentrantLock(); + final private Object readLock = new Object(); private InputRecord inrec; @@ -288,6 +288,13 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { private CipherBox readCipher, writeCipher; // NOTE: compression state would be saved here + /* + * security parameters for secure renegotiation. + */ + private boolean secureRenegotiation; + private byte[] clientVerifyData; + private byte[] serverVerifyData; + /* * The authentication context holds all information used to establish * who this end of the connection is (certificate chains, private keys, @@ -528,11 +535,13 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { writeCipher = CipherBox.NULL; writeMAC = MAC.NULL; + // initial security parameters for secure renegotiation + secureRenegotiation = false; + clientVerifyData = new byte[0]; + serverVerifyData = new byte[0]; + enabledCipherSuites = CipherSuiteList.getDefault(); enabledProtocols = ProtocolList.getDefault(); - handshakeLock = new Object(); - writeLock = new ReentrantLock(); - readLock = new Object(); inrec = null; // save the acc @@ -914,6 +923,12 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { connectionState = cs_DATA; } } else if (handshaker.isDone()) { + // reset the parameters for secure renegotiation. + secureRenegotiation = + handshaker.isSecureRenegotiation(); + clientVerifyData = handshaker.getClientVerifyData(); + serverVerifyData = handshaker.getServerVerifyData(); + sess = handshaker.getSession(); handshaker = null; connectionState = cs_DATA; @@ -1091,11 +1106,14 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { } if (roleIsServer) { handshaker = new ServerHandshaker(this, sslContext, - enabledProtocols, doClientAuth, - connectionState == cs_RENEGOTIATE, protocolVersion); + enabledProtocols, doClientAuth, + protocolVersion, connectionState == cs_HANDSHAKE, + secureRenegotiation, clientVerifyData, serverVerifyData); } else { handshaker = new ClientHandshaker(this, sslContext, - enabledProtocols, protocolVersion); + enabledProtocols, + protocolVersion, connectionState == cs_HANDSHAKE, + secureRenegotiation, clientVerifyData, serverVerifyData); } handshaker.enabledCipherSuites = enabledCipherSuites; handshaker.setEnableSessionCreation(enableSessionCreation); @@ -1200,8 +1218,16 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { break; case cs_DATA: - if (!Handshaker.renegotiable) { - throw new SSLHandshakeException("renegotiation is not allowed"); + if (!secureRenegotiation && !Handshaker.allowUnsafeRenegotiation) { + throw new SSLHandshakeException( + "Insecure renegotiation is not allowed"); + } + + if (!secureRenegotiation) { + if (debug != null && Debug.isOn("handshake")) { + System.out.println( + "Warning: Using insecure renegotiation"); + } } // initialize the handshaker, move to cs_RENEGOTIATE diff --git a/src/share/classes/sun/security/ssl/ServerHandshaker.java b/src/share/classes/sun/security/ssl/ServerHandshaker.java index 84f0b8888b971b9c35c4288e91e5d3f64503cbc5..5d70c7492273f19a3d6aab84bb2020c1ca485ddb 100644 --- a/src/share/classes/sun/security/ssl/ServerHandshaker.java +++ b/src/share/classes/sun/security/ssl/ServerHandshaker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, 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 @@ -69,9 +69,6 @@ final class ServerHandshaker extends Handshaker { // flag to check for clientCertificateVerify message private boolean needClientVerify = false; - // indicate a renegotiation handshaking - private boolean isRenegotiation = false; - /* * For exportable ciphersuites using non-exportable key sizes, we use * ephemeral RSA keys. We could also do anonymous RSA in the same way @@ -100,13 +97,15 @@ final class ServerHandshaker extends Handshaker { */ ServerHandshaker(SSLSocketImpl socket, SSLContextImpl context, ProtocolList enabledProtocols, byte clientAuth, - boolean isRenegotiation, ProtocolVersion activeProtocolVersion) { + ProtocolVersion activeProtocolVersion, boolean isInitialHandshake, + boolean secureRenegotiation, + byte[] clientVerifyData, byte[] serverVerifyData) { super(socket, context, enabledProtocols, - (clientAuth != SSLEngineImpl.clauth_none), false); + (clientAuth != SSLEngineImpl.clauth_none), false, + activeProtocolVersion, isInitialHandshake, secureRenegotiation, + clientVerifyData, serverVerifyData); doClientAuth = clientAuth; - this.isRenegotiation = isRenegotiation; - this.activeProtocolVersion = activeProtocolVersion; } /* @@ -114,13 +113,15 @@ final class ServerHandshaker extends Handshaker { */ ServerHandshaker(SSLEngineImpl engine, SSLContextImpl context, ProtocolList enabledProtocols, byte clientAuth, - boolean isRenegotiation, ProtocolVersion activeProtocolVersion) { + ProtocolVersion activeProtocolVersion, + boolean isInitialHandshake, boolean secureRenegotiation, + byte[] clientVerifyData, byte[] serverVerifyData) { super(engine, context, enabledProtocols, - (clientAuth != SSLEngineImpl.clauth_none), false); + (clientAuth != SSLEngineImpl.clauth_none), false, + activeProtocolVersion, isInitialHandshake, secureRenegotiation, + clientVerifyData, serverVerifyData); doClientAuth = clientAuth; - this.isRenegotiation = isRenegotiation; - this.activeProtocolVersion = activeProtocolVersion; } /* @@ -269,41 +270,122 @@ final class ServerHandshaker extends Handshaker { mesg.print(System.out); } - // if it is a renegotiation request and renegotiation is not allowed - if (isRenegotiation && !renegotiable) { - if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) { - // response with a no_negotiation warning, - warningSE(Alerts.alert_no_negotiation); - - // invalidate the handshake so that the caller can - // dispose this object. - invalidated = true; + // Does the message include security renegotiation indication? + boolean renegotiationIndicated = false; - // If there is still unread block in the handshake - // input stream, it would be truncated with the disposal - // and the next handshake message will become incomplete. - // - // However, according to SSL/TLS specifications, no more - // handshake message could immediately follow ClientHello - // or HelloRequest. But in case of any improper messages, - // we'd better check to ensure there is no remaining bytes - // in the handshake input stream. - if (input.available() > 0) { - fatalSE(Alerts.alert_unexpected_message, - "ClientHello followed by an unexpected " + - "handshake message"); + // check the TLS_EMPTY_RENEGOTIATION_INFO_SCSV + CipherSuiteList cipherSuites = mesg.getCipherSuites(); + if (cipherSuites.contains(CipherSuite.C_SCSV)) { + renegotiationIndicated = true; + if (isInitialHandshake) { + secureRenegotiation = true; + } else { + // abort the handshake with a fatal handshake_failure alert + if (secureRenegotiation) { + fatalSE(Alerts.alert_handshake_failure, + "The SCSV is present in a secure renegotiation"); + } else { + fatalSE(Alerts.alert_handshake_failure, + "The SCSV is present in a insecure renegotiation"); + } + } + } + // check the "renegotiation_info" extension + RenegotiationInfoExtension clientHelloRI = (RenegotiationInfoExtension) + mesg.extensions.get(ExtensionType.EXT_RENEGOTIATION_INFO); + if (clientHelloRI != null) { + renegotiationIndicated = true; + if (isInitialHandshake) { + // verify the length of the "renegotiated_connection" field + if (!clientHelloRI.isEmpty()) { + // abort the handshake with a fatal handshake_failure alert + fatalSE(Alerts.alert_handshake_failure, + "The renegotiation_info field is not empty"); } - return; + secureRenegotiation = true; } else { - // For SSLv3, send the handshake_failure fatal error. - // Note that SSLv3 does not define a no_negotiation alert - // like TLSv1. However we cannot ignore the message - // simply, otherwise the other side was waiting for a - // response that would never come. - fatalSE(Alerts.alert_handshake_failure, - "renegotiation is not allowed"); + if (!secureRenegotiation) { + // unexpected RI extension for insecure renegotiation, + // abort the handshake with a fatal handshake_failure alert + fatalSE(Alerts.alert_handshake_failure, + "The renegotiation_info is present in a insecure " + + "renegotiation"); + } + + // verify the client_verify_data value + if (!Arrays.equals(clientVerifyData, + clientHelloRI.getRenegotiatedConnection())) { + fatalSE(Alerts.alert_handshake_failure, + "Incorrect verify data in ClientHello " + + "renegotiation_info message"); + } + } + } else if (!isInitialHandshake && secureRenegotiation) { + // if the connection's "secure_renegotiation" flag is set to TRUE + // and the "renegotiation_info" extension is not present, abort + // the handshake. + fatalSE(Alerts.alert_handshake_failure, + "Inconsistent secure renegotiation indication"); + } + + // if there is no security renegotiation indication or the previous + // handshake is insecure. + if (!renegotiationIndicated || !secureRenegotiation) { + if (isInitialHandshake) { + if (!allowLegacyHelloMessages) { + // abort the handshake with a fatal handshake_failure alert + fatalSE(Alerts.alert_handshake_failure, + "Failed to negotiate the use of secure renegotiation"); + } + + // continue with legacy ClientHello + if (debug != null && Debug.isOn("handshake")) { + System.out.println("Warning: No renegotiation " + + "indication in ClientHello, allow legacy ClientHello"); + } + } else if (!allowUnsafeRenegotiation) { + // abort the handshake + if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) { + // response with a no_renegotiation warning, + warningSE(Alerts.alert_no_renegotiation); + + // invalidate the handshake so that the caller can + // dispose this object. + invalidated = true; + + // If there is still unread block in the handshake + // input stream, it would be truncated with the disposal + // and the next handshake message will become incomplete. + // + // However, according to SSL/TLS specifications, no more + // handshake message could immediately follow ClientHello + // or HelloRequest. But in case of any improper messages, + // we'd better check to ensure there is no remaining bytes + // in the handshake input stream. + if (input.available() > 0) { + fatalSE(Alerts.alert_unexpected_message, + "ClientHello followed by an unexpected " + + "handshake message"); + } + + return; + } else { + // For SSLv3, send the handshake_failure fatal error. + // Note that SSLv3 does not define a no_renegotiation + // alert like TLSv1. However we cannot ignore the message + // simply, otherwise the other side was waiting for a + // response that would never come. + fatalSE(Alerts.alert_handshake_failure, + "Renegotiation is not allowed"); + } + } else { // !isInitialHandshake && allowUnsafeRenegotiation + // continue with unsafe renegotiation. + if (debug != null && Debug.isOn("handshake")) { + System.out.println( + "Warning: continue with insecure renegotiation"); + } } } @@ -454,7 +536,7 @@ final class ServerHandshaker extends Handshaker { // verify that the ciphersuite from the cached session // is in the list of client requested ciphersuites and // we have it enabled - if ((isEnabled(suite) == false) || + if ((isNegotiable(suite) == false) || (mesg.getCipherSuites().contains(suite) == false)) { resumingSession = false; } else { @@ -484,8 +566,8 @@ final class ServerHandshaker extends Handshaker { if (!enableNewSession) { throw new SSLException("Client did not resume a session"); } - supportedCurves = (SupportedEllipticCurvesExtension)mesg.extensions.get - (ExtensionType.EXT_ELLIPTIC_CURVES); + supportedCurves = (SupportedEllipticCurvesExtension) + mesg.extensions.get(ExtensionType.EXT_ELLIPTIC_CURVES); chooseCipherSuite(mesg); session = new SSLSessionImpl(protocolVersion, cipherSuite, sslContext.getSecureRandom(), @@ -498,6 +580,21 @@ final class ServerHandshaker extends Handshaker { m1.sessionId = session.getSessionId(); m1.compression_method = session.getCompression(); + if (secureRenegotiation) { + // For ServerHellos that are initial handshakes, then the + // "renegotiated_connection" field in "renegotiation_info" + // extension is of zero length. + // + // For ServerHellos that are renegotiating, this field contains + // the concatenation of client_verify_data and server_verify_data. + // + // Note that for initial handshakes, both the clientVerifyData + // variable and serverVerifyData variable are of zero length. + HelloExtension serverHelloRI = new RenegotiationInfoExtension( + clientVerifyData, serverVerifyData); + m1.extensions.add(serverHelloRI); + } + if (debug != null && Debug.isOn("handshake")) { m1.print(System.out); System.out.println("Cipher suite: " + session.getSuite()); @@ -686,11 +783,13 @@ final class ServerHandshaker extends Handshaker { */ private void chooseCipherSuite(ClientHello mesg) throws IOException { for (CipherSuite suite : mesg.getCipherSuites().collection()) { - if (isEnabled(suite) == false) { + if (isNegotiable(suite) == false) { continue; } + if (doClientAuth == SSLEngineImpl.clauth_required) { - if ((suite.keyExchange == K_DH_ANON) || (suite.keyExchange == K_ECDH_ANON)) { + if ((suite.keyExchange == K_DH_ANON) || + (suite.keyExchange == K_ECDH_ANON)) { continue; } } @@ -728,7 +827,7 @@ final class ServerHandshaker extends Handshaker { return true; } - if (suite.isAvailable() == false) { + if (suite.isNegotiable() == false) { return false; } @@ -1135,6 +1234,13 @@ final class ServerHandshaker extends Handshaker { // NOTREACHED } + /* + * save client verify data for secure renegotiation + */ + if (secureRenegotiation) { + clientVerifyData = mesg.getVerifyData(); + } + /* * OK, it verified. If we're doing the full handshake, add that * "Finished" message to the hash of handshake messages, then send @@ -1184,6 +1290,13 @@ final class ServerHandshaker extends Handshaker { */ sendChangeCipherSpec(mesg, finishedTag); + /* + * save server verify data for secure renegotiation + */ + if (secureRenegotiation) { + serverVerifyData = mesg.getVerifyData(); + } + /* * Update state machine so client MUST send 'finished' next * The update should only take place if it is not in the fast diff --git a/src/share/native/sun/awt/image/BufImgSurfaceData.c b/src/share/native/sun/awt/image/BufImgSurfaceData.c index d2b3b33a02f34ca36caa3e7a17e81ae940bba910..f8ebd3ad4b703198ab1eefa479d8a8f55f31132f 100644 --- a/src/share/native/sun/awt/image/BufImgSurfaceData.c +++ b/src/share/native/sun/awt/image/BufImgSurfaceData.c @@ -48,9 +48,12 @@ static ColorData *BufImg_SetupICM(JNIEnv *env, BufImgSDOps *bisdo); static jfieldID rgbID; static jfieldID mapSizeID; -static jfieldID CMpDataID; +static jfieldID colorDataID; +static jfieldID pDataID; static jfieldID allGrayID; +static jclass clsICMCD; +static jmethodID initICMCDmID; /* * Class: sun_awt_image_BufImgSurfaceData * Method: initIDs @@ -58,18 +61,23 @@ static jfieldID allGrayID; */ JNIEXPORT void JNICALL Java_sun_awt_image_BufImgSurfaceData_initIDs - (JNIEnv *env, jclass bisd, jclass icm) +(JNIEnv *env, jclass bisd, jclass icm, jclass cd) { if (sizeof(BufImgRIPrivate) > SD_RASINFO_PRIVATE_SIZE) { JNU_ThrowInternalError(env, "Private RasInfo structure too large!"); return; } + clsICMCD = (*env)->NewWeakGlobalRef(env, cd); + initICMCDmID = (*env)->GetMethodID(env, cd, "", "(J)V"); + pDataID = (*env)->GetFieldID(env, cd, "pData", "J"); + rgbID = (*env)->GetFieldID(env, icm, "rgb", "[I"); allGrayID = (*env)->GetFieldID(env, icm, "allgrayopaque", "Z"); mapSizeID = (*env)->GetFieldID(env, icm, "map_size", "I"); - CMpDataID = (*env)->GetFieldID(env, icm, "pData", "J"); - if (allGrayID == 0 || rgbID == 0 || mapSizeID == 0 || CMpDataID == 0) { + colorDataID = (*env)->GetFieldID(env, icm, "colorData", + "Lsun/awt/image/BufImgSurfaceData$ICMColorData;"); + if (allGrayID == 0 || rgbID == 0 || mapSizeID == 0 || pDataID == 0|| colorDataID == 0 || initICMCDmID == 0) { JNU_ThrowInternalError(env, "Could not get field IDs"); } } @@ -81,18 +89,9 @@ Java_sun_awt_image_BufImgSurfaceData_initIDs */ JNIEXPORT void JNICALL Java_sun_awt_image_BufImgSurfaceData_freeNativeICMData - (JNIEnv *env, jclass sd, jobject icm) + (JNIEnv *env, jclass sd, jlong pData) { - jlong pData; - ColorData *cdata; - - if (JNU_IsNull(env, icm)) { - JNU_ThrowNullPointerException(env, "IndexColorModel cannot be null"); - return; - } - - pData = (*env)->GetLongField (env, icm, CMpDataID); - cdata = (ColorData *)pData; + ColorData *cdata = (ColorData*)jlong_to_ptr(pData); freeICMColorData(cdata); } @@ -263,32 +262,48 @@ static void BufImg_Release(JNIEnv *env, static ColorData *BufImg_SetupICM(JNIEnv *env, BufImgSDOps *bisdo) { - ColorData *cData; + ColorData *cData = NULL; + jobject colorData; if (JNU_IsNull(env, bisdo->icm)) { return (ColorData *) NULL; } - cData = (ColorData *) JNU_GetLongFieldAsPtr(env, bisdo->icm, CMpDataID); + colorData = (*env)->GetObjectField(env, bisdo->icm, colorDataID); - if (cData == NULL) { - cData = (ColorData*)calloc(1, sizeof(ColorData)); + if (JNU_IsNull(env, colorData)) { + if (JNU_IsNull(env, clsICMCD)) { + // we are unable to create a wrapper object + return (ColorData*)NULL; + } + } else { + cData = (ColorData*)JNU_GetLongFieldAsPtr(env, colorData, pDataID); + } + + if (cData != NULL) { + return cData; + } + + cData = (ColorData*)calloc(1, sizeof(ColorData)); - if (cData != NULL) { - jboolean allGray - = (*env)->GetBooleanField(env, bisdo->icm, allGrayID); - int *pRgb = (int *) - ((*env)->GetPrimitiveArrayCritical(env, bisdo->lutarray, NULL)); - cData->img_clr_tbl = initCubemap(pRgb, bisdo->lutsize, 32); - if (allGray == JNI_TRUE) { - initInverseGrayLut(pRgb, bisdo->lutsize, cData); - } - (*env)->ReleasePrimitiveArrayCritical(env, bisdo->lutarray, pRgb, - JNI_ABORT); + if (cData != NULL) { + jboolean allGray + = (*env)->GetBooleanField(env, bisdo->icm, allGrayID); + int *pRgb = (int *) + ((*env)->GetPrimitiveArrayCritical(env, bisdo->lutarray, NULL)); + cData->img_clr_tbl = initCubemap(pRgb, bisdo->lutsize, 32); + if (allGray == JNI_TRUE) { + initInverseGrayLut(pRgb, bisdo->lutsize, cData); + } + (*env)->ReleasePrimitiveArrayCritical(env, bisdo->lutarray, pRgb, + JNI_ABORT); - initDitherTables(cData); + initDitherTables(cData); - JNU_SetLongFieldFromPtr(env, bisdo->icm, CMpDataID, cData); + if (JNU_IsNull(env, colorData)) { + jlong pData = ptr_to_jlong(cData); + colorData = (*env)->NewObjectA(env, clsICMCD, initICMCDmID, (jvalue *)&pData); + (*env)->SetObjectField(env, bisdo->icm, colorDataID, colorData); } } diff --git a/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/src/share/native/sun/awt/image/jpeg/imageioJPEG.c index 2475166fc0d6bbd0590037ff070006159f7bc74b..6495db28fc58c445302696280ad85d845235f23a 100644 --- a/src/share/native/sun/awt/image/jpeg/imageioJPEG.c +++ b/src/share/native/sun/awt/image/jpeg/imageioJPEG.c @@ -2614,7 +2614,8 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage JSAMPROW scanLinePtr; int i, j; int pixelStride; - unsigned char *in, *out, *pixelLimit; + unsigned char *in, *out, *pixelLimit, *scanLineLimit; + unsigned int scanLineSize, pixelBufferSize; int targetLine; pixelBufferPtr pb; sun_jpeg_error_ptr jerr; @@ -2650,19 +2651,25 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage } + scanLineSize = destWidth * numBands; if ((inCs < 0) || (inCs > JCS_YCCK) || (outCs < 0) || (outCs > JCS_YCCK) || (numBands < 1) || (numBands > MAX_BANDS) || (srcWidth < 0) || (destWidth < 0) || (destWidth > srcWidth) || (destHeight < 0) || - (stepX < 0) || (stepY < 0)) + (stepX < 0) || (stepY < 0) || + ((scanLineSize / numBands) < destWidth)) /* destWidth causes an integer overflow */ { JNU_ThrowByName(env, "javax/imageio/IIOException", "Invalid argument to native writeImage"); return JNI_FALSE; } + if (stepX > srcWidth) { + stepX = srcWidth; + } + bandSize = (*env)->GetIntArrayElements(env, bandSizes, NULL); for (i = 0; i < numBands; i++) { @@ -2710,7 +2717,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage } // Allocate a 1-scanline buffer - scanLinePtr = (JSAMPROW)malloc(destWidth*numBands); + scanLinePtr = (JSAMPROW)malloc(scanLineSize); if (scanLinePtr == NULL) { RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); JNU_ThrowByName( env, @@ -2718,6 +2725,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage "Writing JPEG Stream"); return data->abortFlag; } + scanLineLimit = scanLinePtr + scanLineSize; /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ jerr = (sun_jpeg_error_ptr) cinfo->err; @@ -2866,6 +2874,8 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage } targetLine = 0; + pixelBufferSize = srcWidth * numBands; + pixelStride = numBands * stepX; // for each line in destHeight while ((data->abortFlag == JNI_FALSE) @@ -2886,9 +2896,9 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage in = data->pixelBuf.buf.bp; out = scanLinePtr; - pixelLimit = in + srcWidth*numBands; - pixelStride = numBands*stepX; - for (; in < pixelLimit; in += pixelStride) { + pixelLimit = in + ((pixelBufferSize > data->pixelBuf.byteBufferLength) ? + data->pixelBuf.byteBufferLength : pixelBufferSize); + for (; (in < pixelLimit) && (out < scanLineLimit); in += pixelStride) { for (i = 0; i < numBands; i++) { if (scale !=NULL && scale[i] != NULL) { *out++ = scale[i][*(in+i)]; diff --git a/test/javax/swing/Security/6938813/bug6938813.java b/test/javax/swing/Security/6938813/bug6938813.java new file mode 100644 index 0000000000000000000000000000000000000000..5bedf95e1403036d2040d4c20d342bdefa892e67 --- /dev/null +++ b/test/javax/swing/Security/6938813/bug6938813.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2010, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6938813 + * @summary Swing mutable statics + * @author Pavel Porvatov + */ + +import sun.awt.AppContext; +import sun.awt.SunToolkit; + +import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.StyleSheet; +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.ParserDelegator; +import java.lang.reflect.Field; + +public class bug6938813 { + public static final String DTD_KEY = "dtd_key"; + + private static volatile StyleSheet styleSheet; + + public static void main(String[] args) throws Exception { + // Run validation and init values for this AppContext + validate(); + + Thread thread = new ThreadInAnotherAppContext(); + + thread.start(); + thread.join(); + } + + private static void validate() throws Exception { + AppContext appContext = AppContext.getAppContext(); + + assertTrue(DTD.getDTD(DTD_KEY).getName().equals(DTD_KEY), "DTD.getDTD() mixed AppContexts"); + + // Spoil hash value + DTD invalidDtd = DTD.getDTD("invalid DTD"); + + DTD.putDTDHash(DTD_KEY, invalidDtd); + + assertTrue(DTD.getDTD(DTD_KEY) == invalidDtd, "Something wrong with DTD.getDTD()"); + + Object dtdKey = getParserDelegator_DTD_KEY(); + + assertTrue(appContext.get(dtdKey) == null, "ParserDelegator mixed AppContexts"); + + // Init default DTD + new ParserDelegator(); + + Object dtdValue = appContext.get(dtdKey); + + assertTrue(dtdValue != null, "ParserDelegator.defaultDTD isn't initialized"); + + // Try reinit default DTD + new ParserDelegator(); + + assertTrue(dtdValue == appContext.get(dtdKey), "ParserDelegator.defaultDTD created a duplicate"); + + HTMLEditorKit htmlEditorKit = new HTMLEditorKit(); + + if (styleSheet == null) { + // First AppContext + styleSheet = htmlEditorKit.getStyleSheet(); + + assertTrue(styleSheet != null, "htmlEditorKit.getStyleSheet() returns null"); + assertTrue(htmlEditorKit.getStyleSheet() == styleSheet, "Something wrong with htmlEditorKit.getStyleSheet()"); + } else { + assertTrue(htmlEditorKit.getStyleSheet() != styleSheet, "HtmlEditorKit.getStyleSheet() mixed AppContexts"); + } + } + + private static void assertTrue(boolean b, String msg) { + if (!b) { + throw new RuntimeException("Test failed: " + msg); + } + } + + private static Object getParserDelegator_DTD_KEY() throws Exception { + Field field = ParserDelegator.class.getDeclaredField("DTD_KEY"); + + field.setAccessible(true); + + return field.get(null); + } + + private static class ThreadInAnotherAppContext extends Thread { + public ThreadInAnotherAppContext() { + super(new ThreadGroup("6938813"), "ThreadInAnotherAppContext"); + } + + public void run() { + SunToolkit.createNewAppContext(); + + try { + validate(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/test/javax/swing/UIDefaults/6622002/bug6622002.java b/test/javax/swing/UIDefaults/6622002/bug6622002.java new file mode 100644 index 0000000000000000000000000000000000000000..afd883b1e6566123452887d9e1ff36d447ff6735 --- /dev/null +++ b/test/javax/swing/UIDefaults/6622002/bug6622002.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 6622002 + * @author Alexander Potochkin + * @summary UIDefault.ProxyLazyValue has unsafe reflection usage + */ + +import javax.swing.*; + +public class bug6622002 { + public static void main(String[] args) { + + if (createPrivateValue() == null) { + throw new RuntimeException("The private value unexpectedly wasn't created"); + } + + if (createPublicValue() == null) { + throw new RuntimeException("The public value unexpectedly wasn't created"); + } + + System.setSecurityManager(new SecurityManager()); + + if (createPrivateValue() != null) { + throw new RuntimeException("The private value was unexpectedly created"); + } + + if (createPublicValue() == null) { + throw new RuntimeException("The public value unexpectedly wasn't created"); + } + } + + private static Object createPrivateValue() { + return new UIDefaults.ProxyLazyValue( + "javax.swing.MultiUIDefaults").createValue(null); + } + + private static Object createPublicValue() { + return new UIDefaults.ProxyLazyValue( + "javax.swing.UIDefaults").createValue(null); + } +} diff --git a/test/sun/security/pkcs11/fips/CipherTest.java b/test/sun/security/pkcs11/fips/CipherTest.java index e0558958210cbcafca4e9b90b2719172be0525f4..ea99884a4c7fec2ea68980900130187501a2c369 100644 --- a/test/sun/security/pkcs11/fips/CipherTest.java +++ b/test/sun/security/pkcs11/fips/CipherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, 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 @@ -114,10 +114,11 @@ public class CipherTest { } boolean isEnabled() { -// return cipherSuite.equals("SSL_RSA_WITH_RC4_128_MD5") && -// (clientAuth != null); -// return cipherSuite.indexOf("_RSA_") != -1; -// return cipherSuite.indexOf("DH_anon") != -1; + // ignore SCSV + if (cipherSuite.equals("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) { + return false; + } + return true; } diff --git a/test/sun/security/pkcs11/sslecc/CipherTest.java b/test/sun/security/pkcs11/sslecc/CipherTest.java index 9d29e56c7995a8e14b04625045ac0a395db37964..34ed0eeb9d74403da16b4968b1484200aa2ef359 100644 --- a/test/sun/security/pkcs11/sslecc/CipherTest.java +++ b/test/sun/security/pkcs11/sslecc/CipherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, 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 @@ -114,12 +114,11 @@ public class CipherTest { } boolean isEnabled() { -// if (true) return cipherSuite.contains("_ECDH_"); -// return cipherSuite.equals("SSL_RSA_WITH_RC4_128_MD5") && -// (clientAuth != null); -// return cipherSuite.indexOf("_RSA_") != -1; -// return cipherSuite.indexOf("DH_anon") != -1; -// return cipherSuite.contains("ECDSA") == false; + // ignore SCSV + if (cipherSuite.equals("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) { + return false; + } + return true; } diff --git a/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/InvalidateServerSessionRenegotiate.java b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/InvalidateServerSessionRenegotiate.java index 5410ec46d40322d9ce1d01ae1c1b1e828dc94ce4..6954f84bc7d662a6b02c6e34fe963ddaee38897f 100644 --- a/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/InvalidateServerSessionRenegotiate.java +++ b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLSocketImpl/InvalidateServerSessionRenegotiate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, 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,8 +25,6 @@ * @test * @bug 4403428 * @summary Invalidating JSSE session on server causes SSLProtocolException - * @ignore incompatible with disabled unsafe renegotiation (6898739), please - * reenable when safe renegotiation is implemented. * @author Brad Wetmore */ diff --git a/test/sun/security/ssl/javax/net/ssl/NewAPIs/JSSERenegotiate.java b/test/sun/security/ssl/javax/net/ssl/NewAPIs/JSSERenegotiate.java index e2809cb9370fb248c7b1c5f676c7641aba95ce77..8bf2f027053e4cd18091cbd33e216b06ad0f2ee9 100644 --- a/test/sun/security/ssl/javax/net/ssl/NewAPIs/JSSERenegotiate.java +++ b/test/sun/security/ssl/javax/net/ssl/NewAPIs/JSSERenegotiate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, 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,8 +26,6 @@ * @bug 4280338 * @summary "Unsupported SSL message version" SSLProtocolException * w/SSL_RSA_WITH_NULL_MD5 - * @ignore incompatible with disabled unsafe renegotiation (6898739), please - * reenable when safe renegotiation is implemented. * * @author Ram Marti * @author Brad Wetmore diff --git a/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/CheckStatus.java b/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/CheckStatus.java index a8bb12129d04db27d0ba8148f1565c6457545dae..c29f55a04b9f80dd22097f5e8c4c9f7e38b757d2 100644 --- a/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/CheckStatus.java +++ b/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/CheckStatus.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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,8 +25,6 @@ * @test * @bug 4948079 * @summary SSLEngineResult needs updating [none yet] - * @ignore incompatible with disabled unsafe renegotiation (6898739), please - * reenable when safe renegotiation is implemented. * * This is a simple hack to test a bunch of conditions and check * their return codes. diff --git a/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/ConnectionTest.java b/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/ConnectionTest.java index 2befa4a0eec560d7edbba05b8097ac16ca3ede45..546a7865668018040236da857146bc4692bbe364 100644 --- a/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/ConnectionTest.java +++ b/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/ConnectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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,8 +26,6 @@ * @bug 4495742 * @summary Add non-blocking SSL/TLS functionality, usable with any * I/O abstraction - * @ignore incompatible with disabled unsafe renegotiation (6898739), please - * reenable when safe renegotiation is implemented. * * This is a bit hacky, meant to test various conditions. The main * thing I wanted to do with this was to do buffer reads/writes diff --git a/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/NoAuthClientAuth.java b/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/NoAuthClientAuth.java index 972c7ea51d3aaa5425fb9fb186d9b62844fdeece..44a34372b3cbc028decd2d09005991e630a40c81 100644 --- a/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/NoAuthClientAuth.java +++ b/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/NoAuthClientAuth.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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,8 +25,6 @@ * @test * @bug 4495742 * @summary Demonstrate SSLEngine switch from no client auth to client auth. - * @ignore incompatible with disabled unsafe renegotiation (6898739), please - * reenable when safe renegotiation is implemented. * * @author Brad R. Wetmore */ diff --git a/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/TestAllSuites.java b/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/TestAllSuites.java index b7a0dd56b0941bff3ee0416cc8b96b1382e9d3a0..6b477a2bf2003eac16ad82d5ce20ae966ed5598e 100644 --- a/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/TestAllSuites.java +++ b/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/TestAllSuites.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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 @@ -119,6 +119,15 @@ public class TestAllSuites { return; } + /* + * Don't run the SCSV suite + */ + if (suite.equals("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) { + System.out.println("Ignoring SCSV suite"); + return; + } + + if (!suite.contains("DH_anon")) { ssle2.setNeedClientAuth(true); } diff --git a/test/sun/security/ssl/sanity/ciphersuites/CheckCipherSuites.java b/test/sun/security/ssl/sanity/ciphersuites/CheckCipherSuites.java index 8f58e3d2b8ab23971432276b5b6d5f328b7f1acb..e1ff7e6464eee590623e05ccf05d0b51d996adde 100644 --- a/test/sun/security/ssl/sanity/ciphersuites/CheckCipherSuites.java +++ b/test/sun/security/ssl/sanity/ciphersuites/CheckCipherSuites.java @@ -64,6 +64,8 @@ public class CheckCipherSuites { "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", + "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", + }; private final static String[] ENABLED_UNLIMITED = { @@ -101,6 +103,8 @@ public class CheckCipherSuites { "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", + "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", + }; // supported ciphersuites using default JCE policy jurisdiction files @@ -133,6 +137,7 @@ public class CheckCipherSuites { "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", + "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", "SSL_RSA_WITH_NULL_MD5", "SSL_RSA_WITH_NULL_SHA", @@ -160,6 +165,7 @@ public class CheckCipherSuites { "TLS_KRB5_EXPORT_WITH_RC4_40_MD5", "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", + }; // supported ciphersuites using unlimited JCE policy jurisdiction files @@ -199,6 +205,7 @@ public class CheckCipherSuites { "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", + "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", "SSL_RSA_WITH_NULL_MD5", "SSL_RSA_WITH_NULL_SHA", @@ -228,6 +235,7 @@ public class CheckCipherSuites { "TLS_KRB5_EXPORT_WITH_RC4_40_MD5", "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", + }; private static void showSuites(String[] suites) { diff --git a/test/sun/security/ssl/sanity/interop/CipherTest.java b/test/sun/security/ssl/sanity/interop/CipherTest.java index b1b3de61ce79c30f73605a7575ed353455885470..975bbe833e71fa20cedbc8003d3a5c7a1dfa8e31 100644 --- a/test/sun/security/ssl/sanity/interop/CipherTest.java +++ b/test/sun/security/ssl/sanity/interop/CipherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, 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,10 +115,11 @@ public class CipherTest { } boolean isEnabled() { -// return cipherSuite.equals("SSL_RSA_WITH_RC4_128_MD5") && -// (clientAuth != null); -// return cipherSuite.indexOf("_RSA_") != -1; -// return cipherSuite.indexOf("DH_anon") != -1; + // ignore SCSV + if (cipherSuite.equals("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) { + return false; + } + return true; }