src/share/classes/sun/security/ssl/HelloExtensions.java

Print this page
rev 928 : Summary: Added support for Server Name Indication (SNI) hello
extension to SSL client.
Contributed-by: Michael Tandy <michaeltandy at googlemail dot com>


  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.IOException;
  29 import java.io.PrintStream;
  30 import java.util.*;
  31 
  32 import java.security.spec.ECParameterSpec;
  33 
  34 import javax.net.ssl.SSLProtocolException;
  35 

  36 /**
  37  * This file contains all the classes relevant to TLS Extensions for the
  38  * ClientHello and ServerHello messages. The extension mechanism and
  39  * several extensions are defined in RFC 3546. Additional extensions are
  40  * defined in the ECC RFC 4492.
  41  *
  42  * Currently, only the two ECC extensions are fully supported.
  43  *
  44  * The classes contained in this file are:
  45  *  . HelloExtensions: a List of extensions as used in the client hello
  46  *      and server hello messages.
  47  *  . ExtensionType: an enum style class for the extension type
  48  *  . HelloExtension: abstract base class for all extensions. All subclasses
  49  *      must be immutable.
  50  *
  51  *  . UnknownExtension: used to represent all parsed extensions that we do not
  52  *      explicitly support.
  53  *  . ServerNameExtension: partially implemented server_name extension.
  54  *  . SupportedEllipticCurvesExtension: the ECC supported curves extension.
  55  *  . SupportedEllipticPointFormatsExtension: the ECC supported point formats


 130         return encodedLength;
 131     }
 132 
 133     void send(HandshakeOutStream s) throws IOException {
 134         int length = length();
 135         if (length == 0) {
 136             return;
 137         }
 138         s.putInt16(length - 2);
 139         for (HelloExtension ext : extensions) {
 140             ext.send(s);
 141         }
 142     }
 143 
 144     void print(PrintStream s) throws IOException {
 145         for (HelloExtension ext : extensions) {
 146             s.println(ext.toString());
 147         }
 148     }
 149 }
 150 
 151 final class ExtensionType {
 152 
 153     final int id;
 154     final String name;
 155 
 156     private ExtensionType(int id, String name) {
 157         this.id = id;
 158         this.name = name;
 159     }
 160 
 161     public String toString() {
 162         return name;
 163     }
 164 
 165     static List<ExtensionType> knownExtensions = new ArrayList<ExtensionType>(8);
 166 
 167     static ExtensionType get(int id) {
 168         for (ExtensionType ext : knownExtensions) {
 169             if (ext.id == id) {
 170                 return ext;


 244 final class ServerNameExtension extends HelloExtension {
 245 
 246     final static int NAME_HOST_NAME = 0;
 247 
 248     private List<ServerName> names;
 249 
 250     ServerNameExtension(HandshakeInStream s, int len)
 251             throws IOException {
 252         super(ExtensionType.EXT_SERVER_NAME);
 253         names = new ArrayList<ServerName>();
 254         while (len > 0) {
 255             ServerName name = new ServerName(s);
 256             names.add(name);
 257             len -= name.length + 2;
 258         }
 259         if (len != 0) {
 260             throw new SSLProtocolException("Invalid server_name extension");
 261         }
 262     }
 263 








 264     static class ServerName {
 265         final int length;
 266         final int type;
 267         final byte[] data;
 268         final String hostname;
 269 
 270         ServerName(HandshakeInStream s) throws IOException {
 271             length = s.getInt16();
 272             type = s.getInt8();
 273             data = s.getBytes16();
 274             if (type == NAME_HOST_NAME) {
 275                 hostname = new String(data, "UTF8");
 276             } else {
 277                 hostname = null;
 278             }
 279         }
 280 














 281         public String toString() {
 282             if (type == NAME_HOST_NAME) {
 283                 return "host_name: " + hostname;
 284             } else {
 285                 return "unknown-" + type + ": " + Debug.toString(data);
 286             }
 287         }
 288     }
 289 
 290     int length() {
 291         throw new RuntimeException("not yet supported");






 292     }
 293 
 294     void send(HandshakeOutStream s) throws IOException {
 295         throw new RuntimeException("not yet supported");












 296     }
 297 
 298     public String toString() {
 299         return "Unsupported extension " + type + ", " + names.toString();





 300     }
 301 }
 302 
 303 final class SupportedEllipticCurvesExtension extends HelloExtension {
 304 
 305     // the extension value to send in the ClientHello message
 306     static final SupportedEllipticCurvesExtension DEFAULT;
 307 
 308     private static final boolean fips;
 309 
 310     static {
 311         int[] ids;
 312         fips = SunJSSE.isFIPS();
 313         if (fips == false) {
 314             ids = new int[] {
 315                 // NIST curves first
 316                 // prefer NIST P-256, rest in order of increasing key length
 317                 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14,
 318                 // non-NIST curves
 319                 15, 16, 17, 2, 18, 4, 5, 20, 8, 22,




  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.IOException;
  29 import java.io.PrintStream;
  30 import java.util.*;
  31 
  32 import java.security.spec.ECParameterSpec;
  33 
  34 import javax.net.ssl.SSLProtocolException;
  35 
  36 
  37 /**
  38  * This file contains all the classes relevant to TLS Extensions for the
  39  * ClientHello and ServerHello messages. The extension mechanism and
  40  * several extensions are defined in RFC 3546. Additional extensions are
  41  * defined in the ECC RFC 4492.
  42  *
  43  * Currently, only the two ECC extensions are fully supported.
  44  *
  45  * The classes contained in this file are:
  46  *  . HelloExtensions: a List of extensions as used in the client hello
  47  *      and server hello messages.
  48  *  . ExtensionType: an enum style class for the extension type
  49  *  . HelloExtension: abstract base class for all extensions. All subclasses
  50  *      must be immutable.
  51  *
  52  *  . UnknownExtension: used to represent all parsed extensions that we do not
  53  *      explicitly support.
  54  *  . ServerNameExtension: partially implemented server_name extension.
  55  *  . SupportedEllipticCurvesExtension: the ECC supported curves extension.
  56  *  . SupportedEllipticPointFormatsExtension: the ECC supported point formats


 131         return encodedLength;
 132     }
 133 
 134     void send(HandshakeOutStream s) throws IOException {
 135         int length = length();
 136         if (length == 0) {
 137             return;
 138         }
 139         s.putInt16(length - 2);
 140         for (HelloExtension ext : extensions) {
 141             ext.send(s);
 142         }
 143     }
 144 
 145     void print(PrintStream s) throws IOException {
 146         for (HelloExtension ext : extensions) {
 147             s.println(ext.toString());
 148         }
 149     }
 150 }

 151 final class ExtensionType {
 152 
 153     final int id;
 154     final String name;
 155 
 156     private ExtensionType(int id, String name) {
 157         this.id = id;
 158         this.name = name;
 159     }
 160 
 161     public String toString() {
 162         return name;
 163     }
 164 
 165     static List<ExtensionType> knownExtensions = new ArrayList<ExtensionType>(8);
 166 
 167     static ExtensionType get(int id) {
 168         for (ExtensionType ext : knownExtensions) {
 169             if (ext.id == id) {
 170                 return ext;


 244 final class ServerNameExtension extends HelloExtension {
 245 
 246     final static int NAME_HOST_NAME = 0;
 247 
 248     private List<ServerName> names;
 249 
 250     ServerNameExtension(HandshakeInStream s, int len)
 251             throws IOException {
 252         super(ExtensionType.EXT_SERVER_NAME);
 253         names = new ArrayList<ServerName>();
 254         while (len > 0) {
 255             ServerName name = new ServerName(s);
 256             names.add(name);
 257             len -= name.length + 2;
 258         }
 259         if (len != 0) {
 260             throw new SSLProtocolException("Invalid server_name extension");
 261         }
 262     }
 263     
 264     ServerNameExtension(String serverName) {
 265         super(ExtensionType.EXT_SERVER_NAME);
 266         names = new ArrayList<ServerName>(1);
 267         if ((serverName != null)&&(serverName.length()>0)) {
 268             names.add(new ServerName(serverName));
 269         }
 270     }
 271 
 272     static class ServerName {
 273         final int length;
 274         final int type;
 275         final byte[] data;
 276         final String hostname;
 277 
 278         ServerName(HandshakeInStream s) throws IOException {
 279             length = s.getInt16();
 280             type = s.getInt8();
 281             data = s.getBytes16();
 282             if (type == NAME_HOST_NAME) {
 283                 hostname = new String(data, "UTF8");
 284             } else {
 285                 hostname = null;
 286             }
 287         }
 288         
 289         ServerName(String hostname) {
 290             this.hostname = hostname;
 291             byte[] hostnameAsUTF8 = null;
 292             try {
 293                 hostnameAsUTF8 = hostname.getBytes("UTF-8");
 294             } catch (java.io.UnsupportedEncodingException ex) {
 295                 // UTF-8 encoding should reliably be present.
 296                 throw new RuntimeException(ex);
 297             }
 298             this.data = hostnameAsUTF8;
 299             this.type = NAME_HOST_NAME;
 300             this.length = this.data.length + 3;
 301         }
 302 
 303         public String toString() {
 304             if (type == NAME_HOST_NAME) {
 305                 return "host_name: " + hostname;
 306             } else {
 307                 return "unknown-" + type + ": " + Debug.toString(data);
 308             }
 309         }
 310     }
 311     
 312     int length() {
 313         if (names.size() == 0)
 314             return 0;
 315         int serverNameListLength = 0;
 316         for (ServerName sn : names) {
 317             serverNameListLength += sn.length + 2;
 318         }
 319         return serverNameListLength + 4;
 320     }
 321 
 322     void send(HandshakeOutStream s) throws IOException {
 323         if (names.size() == 0)
 324             return;
 325         s.putInt16(type.id);
 326         int serverNameListLength = 0;
 327         for (ServerName sn : names) {
 328             serverNameListLength += sn.length + 2;
 329         }
 330         s.putInt16(serverNameListLength);
 331         for (ServerName sn : names) {
 332             s.putInt16(sn.length);
 333             s.putInt8(sn.type);
 334             s.putBytes16(sn.data);
 335         }
 336     }
 337 
 338     public String toString() {
 339         StringBuilder sb = new StringBuilder();
 340         sb.append("Extension " + type + ", host names:\n");
 341         for (ServerName sn : names) {
 342             sb.append("  " + sn + "\n");
 343         }
 344         return sb.toString();
 345     }
 346 }
 347 
 348 final class SupportedEllipticCurvesExtension extends HelloExtension {
 349 
 350     // the extension value to send in the ClientHello message
 351     static final SupportedEllipticCurvesExtension DEFAULT;
 352 
 353     private static final boolean fips;
 354 
 355     static {
 356         int[] ids;
 357         fips = SunJSSE.isFIPS();
 358         if (fips == false) {
 359             ids = new int[] {
 360                 // NIST curves first
 361                 // prefer NIST P-256, rest in order of increasing key length
 362                 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14,
 363                 // non-NIST curves
 364                 15, 16, 17, 2, 18, 4, 5, 20, 8, 22,