1 /*
2  * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * 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: the server_name extension.
54  *  . SignatureAlgorithmsExtension: the signature_algorithms extension.
55  *  . SupportedEllipticCurvesExtension: the ECC supported curves extension.
56  *  . SupportedEllipticPointFormatsExtension: the ECC supported point formats
57  *      (compressed/uncompressed) extension.
58  *
59  * @since   1.6
60  * @author  Andreas Sterbenz
61  */
62 final class HelloExtensions {
63 
64     private List<HelloExtension> extensions;
65     private int encodedLength;
66 
HelloExtensions()67     HelloExtensions() {
68         extensions = Collections.emptyList();
69     }
70 
HelloExtensions(HandshakeInStream s)71     HelloExtensions(HandshakeInStream s) throws IOException {
72         int len = s.getInt16();
73         extensions = new ArrayList<HelloExtension>();
74         encodedLength = len + 2;
75         while (len > 0) {
76             int type = s.getInt16();
77             int extlen = s.getInt16();
78             ExtensionType extType = ExtensionType.get(type);
79             HelloExtension extension;
80             if (extType == ExtensionType.EXT_SERVER_NAME) {
81                 extension = new ServerNameExtension(s, extlen);
82             } else if (extType == ExtensionType.EXT_SIGNATURE_ALGORITHMS) {
83                 extension = new SignatureAlgorithmsExtension(s, extlen);
84             } else if (extType == ExtensionType.EXT_ELLIPTIC_CURVES) {
85                 extension = new SupportedEllipticCurvesExtension(s, extlen);
86             } else if (extType == ExtensionType.EXT_EC_POINT_FORMATS) {
87                 extension =
88                         new SupportedEllipticPointFormatsExtension(s, extlen);
89             } else if (extType == ExtensionType.EXT_RENEGOTIATION_INFO) {
90                 extension = new RenegotiationInfoExtension(s, extlen);
91             } else {
92                 extension = new UnknownExtension(s, extlen, extType);
93             }
94             extensions.add(extension);
95             len -= extlen + 4;
96         }
97         if (len != 0) {
98             throw new SSLProtocolException(
99                         "Error parsing extensions: extra data");
100         }
101     }
102 
103     // Return the List of extensions. Must not be modified by the caller.
list()104     List<HelloExtension> list() {
105         return extensions;
106     }
107 
add(HelloExtension ext)108     void add(HelloExtension ext) {
109         if (extensions.isEmpty()) {
110             extensions = new ArrayList<HelloExtension>();
111         }
112         extensions.add(ext);
113         encodedLength = -1;
114     }
115 
get(ExtensionType type)116     HelloExtension get(ExtensionType type) {
117         for (HelloExtension ext : extensions) {
118             if (ext.type == type) {
119                 return ext;
120             }
121         }
122         return null;
123     }
124 
length()125     int length() {
126         if (encodedLength >= 0) {
127             return encodedLength;
128         }
129         if (extensions.isEmpty()) {
130             encodedLength = 0;
131         } else {
132             encodedLength = 2;
133             for (HelloExtension ext : extensions) {
134                 encodedLength += ext.length();
135             }
136         }
137         return encodedLength;
138     }
139 
send(HandshakeOutStream s)140     void send(HandshakeOutStream s) throws IOException {
141         int length = length();
142         if (length == 0) {
143             return;
144         }
145         s.putInt16(length - 2);
146         for (HelloExtension ext : extensions) {
147             ext.send(s);
148         }
149     }
150 
print(PrintStream s)151     void print(PrintStream s) throws IOException {
152         for (HelloExtension ext : extensions) {
153             s.println(ext.toString());
154         }
155     }
156 }
157 
158 final class ExtensionType {
159 
160     final int id;
161     final String name;
162 
ExtensionType(int id, String name)163     private ExtensionType(int id, String name) {
164         this.id = id;
165         this.name = name;
166     }
167 
toString()168     public String toString() {
169         return name;
170     }
171 
172     static List<ExtensionType> knownExtensions = new ArrayList<>(9);
173 
get(int id)174     static ExtensionType get(int id) {
175         for (ExtensionType ext : knownExtensions) {
176             if (ext.id == id) {
177                 return ext;
178             }
179         }
180         return new ExtensionType(id, "type_" + id);
181     }
182 
e(int id, String name)183     private static ExtensionType e(int id, String name) {
184         ExtensionType ext = new ExtensionType(id, name);
185         knownExtensions.add(ext);
186         return ext;
187     }
188 
189     // extensions defined in RFC 3546
190     final static ExtensionType EXT_SERVER_NAME =
191             e(0x0000, "server_name");            // IANA registry value: 0
192     final static ExtensionType EXT_MAX_FRAGMENT_LENGTH =
193             e(0x0001, "max_fragment_length");    // IANA registry value: 1
194     final static ExtensionType EXT_CLIENT_CERTIFICATE_URL =
195             e(0x0002, "client_certificate_url"); // IANA registry value: 2
196     final static ExtensionType EXT_TRUSTED_CA_KEYS =
197             e(0x0003, "trusted_ca_keys");        // IANA registry value: 3
198     final static ExtensionType EXT_TRUNCATED_HMAC =
199             e(0x0004, "truncated_hmac");         // IANA registry value: 4
200     final static ExtensionType EXT_STATUS_REQUEST =
201             e(0x0005, "status_request");         // IANA registry value: 5
202 
203     // extensions defined in RFC 4681
204     final static ExtensionType EXT_USER_MAPPING =
205             e(0x0006, "user_mapping");           // IANA registry value: 6
206 
207     // extensions defined in RFC 5081
208     final static ExtensionType EXT_CERT_TYPE =
209             e(0x0009, "cert_type");              // IANA registry value: 9
210 
211     // extensions defined in RFC 4492 (ECC)
212     final static ExtensionType EXT_ELLIPTIC_CURVES =
213             e(0x000A, "elliptic_curves");        // IANA registry value: 10
214     final static ExtensionType EXT_EC_POINT_FORMATS =
215             e(0x000B, "ec_point_formats");       // IANA registry value: 11
216 
217     // extensions defined in RFC 5054
218     final static ExtensionType EXT_SRP =
219             e(0x000C, "srp");                    // IANA registry value: 12
220 
221     // extensions defined in RFC 5246
222     final static ExtensionType EXT_SIGNATURE_ALGORITHMS =
223             e(0x000D, "signature_algorithms");   // IANA registry value: 13
224 
225     // extensions defined in RFC 5746
226     final static ExtensionType EXT_RENEGOTIATION_INFO =
227             e(0xff01, "renegotiation_info");     // IANA registry value: 65281
228 }
229 
230 abstract class HelloExtension {
231 
232     final ExtensionType type;
233 
HelloExtension(ExtensionType type)234     HelloExtension(ExtensionType type) {
235         this.type = type;
236     }
237 
238     // Length of the encoded extension, including the type and length fields
length()239     abstract int length();
240 
send(HandshakeOutStream s)241     abstract void send(HandshakeOutStream s) throws IOException;
242 
toString()243     public abstract String toString();
244 
245 }
246 
247 final class UnknownExtension extends HelloExtension {
248 
249     private final byte[] data;
250 
UnknownExtension(HandshakeInStream s, int len, ExtensionType type)251     UnknownExtension(HandshakeInStream s, int len, ExtensionType type)
252             throws IOException {
253         super(type);
254         data = new byte[len];
255         // s.read() does not handle 0-length arrays.
256         if (len != 0) {
257             s.read(data);
258         }
259     }
260 
length()261     int length() {
262         return 4 + data.length;
263     }
264 
send(HandshakeOutStream s)265     void send(HandshakeOutStream s) throws IOException {
266         s.putInt16(type.id);
267         s.putBytes16(data);
268     }
269 
toString()270     public String toString() {
271         return "Unsupported extension " + type + ", data: " +
272             Debug.toString(data);
273     }
274 }
275 
276 /*
277  * [RFC4366] To facilitate secure connections to servers that host multiple
278  * 'virtual' servers at a single underlying network address, clients MAY
279  * include an extension of type "server_name" in the (extended) client hello.
280  * The "extension_data" field of this extension SHALL contain "ServerNameList"
281  * where:
282  *
283  *     struct {
284  *         NameType name_type;
285  *         select (name_type) {
286  *             case host_name: HostName;
287  *         } name;
288  *     } ServerName;
289  *
290  *     enum {
291  *         host_name(0), (255)
292  *     } NameType;
293  *
294  *     opaque HostName<1..2^16-1>;
295  *
296  *     struct {
297  *         ServerName server_name_list<1..2^16-1>
298  *     } ServerNameList;
299  */
300 final class ServerNameExtension extends HelloExtension {
301 
302     final static int NAME_HOST_NAME = 0;
303 
304     private List<ServerName> names;
305     private int listLength;     // ServerNameList length
306 
ServerNameExtension(List<String> hostnames)307     ServerNameExtension(List<String> hostnames) throws IOException {
308         super(ExtensionType.EXT_SERVER_NAME);
309 
310         listLength = 0;
311         names = new ArrayList<ServerName>(hostnames.size());
312         for (String hostname : hostnames) {
313             if (hostname != null && hostname.length() != 0) {
314                 // we only support DNS hostname now.
315                 ServerName serverName =
316                         new ServerName(NAME_HOST_NAME, hostname);
317                 names.add(serverName);
318                 listLength += serverName.length;
319             }
320         }
321 
322         // As we only support DNS hostname now, the hostname list must
323         // not contain more than one hostname
324         if (names.size() > 1) {
325             throw new SSLProtocolException(
326                     "The ServerNameList MUST NOT contain more than " +
327                     "one name of the same name_type");
328         }
329 
330         // We only need to add "server_name" extension in ClientHello unless
331         // we support SNI in server side in the future. It is possible that
332         // the SNI is empty in ServerHello. As we don't support SNI in
333         // ServerHello now, we will throw exception for empty list for now.
334         if (listLength == 0) {
335             throw new SSLProtocolException(
336                     "The ServerNameList cannot be empty");
337         }
338     }
339 
ServerNameExtension(HandshakeInStream s, int len)340     ServerNameExtension(HandshakeInStream s, int len)
341             throws IOException {
342         super(ExtensionType.EXT_SERVER_NAME);
343 
344         int remains = len;
345         if (len >= 2) {    // "server_name" extension in ClientHello
346             listLength = s.getInt16();     // ServerNameList length
347             if (listLength == 0 || listLength + 2 != len) {
348                 throw new SSLProtocolException(
349                         "Invalid " + type + " extension");
350             }
351 
352             remains -= 2;
353             names = new ArrayList<ServerName>();
354             while (remains > 0) {
355                 ServerName name = new ServerName(s);
356                 names.add(name);
357                 remains -= name.length;
358 
359                 // we may need to check the duplicated ServerName type
360             }
361         } else if (len == 0) {     // "server_name" extension in ServerHello
362             listLength = 0;
363             names = Collections.<ServerName>emptyList();
364         }
365 
366         if (remains != 0) {
367             throw new SSLProtocolException("Invalid server_name extension");
368         }
369     }
370 
371     static class ServerName {
372         final int length;
373         final int type;
374         final byte[] data;
375         final String hostname;
376 
ServerName(int type, String hostname)377         ServerName(int type, String hostname) throws IOException {
378             this.type = type;                       // NameType
379             this.hostname = hostname;
380             this.data = hostname.getBytes("UTF8");  // HostName
381             this.length = data.length + 3;          // NameType: 1 byte
382                                                     // HostName length: 2 bytes
383         }
384 
ServerName(HandshakeInStream s)385         ServerName(HandshakeInStream s) throws IOException {
386             type = s.getInt8();         // NameType
387             data = s.getBytes16();      // HostName (length read in getBytes16)
388             length = data.length + 3;   // NameType: 1 byte
389                                         // HostName length: 2 bytes
390             if (type == NAME_HOST_NAME) {
391                 hostname = new String(data, "UTF8");
392             } else {
393                 hostname = null;
394             }
395         }
396 
toString()397         public String toString() {
398             if (type == NAME_HOST_NAME) {
399                 return "host_name: " + hostname;
400             } else {
401                 return "unknown-" + type + ": " + Debug.toString(data);
402             }
403         }
404     }
405 
length()406     int length() {
407         return listLength == 0 ? 4 : 6 + listLength;
408     }
409 
send(HandshakeOutStream s)410     void send(HandshakeOutStream s) throws IOException {
411         s.putInt16(type.id);
412         s.putInt16(listLength + 2);
413         if (listLength != 0) {
414             s.putInt16(listLength);
415 
416             for (ServerName name : names) {
417                 s.putInt8(name.type);           // NameType
418                 s.putBytes16(name.data);        // HostName
419             }
420         }
421     }
422 
toString()423     public String toString() {
424         StringBuffer buffer = new StringBuffer();
425         for (ServerName name : names) {
426             buffer.append("[" + name + "]");
427         }
428 
429         return "Extension " + type + ", server_name: " + buffer;
430     }
431 }
432 
433 final class SupportedEllipticCurvesExtension extends HelloExtension {
434 
435     // the extension value to send in the ClientHello message
436     static final SupportedEllipticCurvesExtension DEFAULT;
437 
438     private static final boolean fips;
439 
440     static {
441         int[] ids;
442         fips = SunJSSE.isFIPS();
443         if (fips == false) {
444             ids = new int[] {
445                 // NIST curves first
446                 // prefer NIST P-256, rest in order of increasing key length
447                 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14,
448                 // non-NIST curves
449                 15, 16, 17, 2, 18, 4, 5, 20, 8, 22,
450             };
451         } else {
452             ids = new int[] {
453                 // same as above, but allow only NIST curves in FIPS mode
454                 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14,
455             };
456         }
457         DEFAULT = new SupportedEllipticCurvesExtension(ids);
458     }
459 
460     private final int[] curveIds;
461 
SupportedEllipticCurvesExtension(int[] curveIds)462     private SupportedEllipticCurvesExtension(int[] curveIds) {
463         super(ExtensionType.EXT_ELLIPTIC_CURVES);
464         this.curveIds = curveIds;
465     }
466 
SupportedEllipticCurvesExtension(HandshakeInStream s, int len)467     SupportedEllipticCurvesExtension(HandshakeInStream s, int len)
468             throws IOException {
469         super(ExtensionType.EXT_ELLIPTIC_CURVES);
470         int k = s.getInt16();
471         if (((len & 1) != 0) || (k + 2 != len)) {
472             throw new SSLProtocolException("Invalid " + type + " extension");
473         }
474         curveIds = new int[k >> 1];
475         for (int i = 0; i < curveIds.length; i++) {
476             curveIds[i] = s.getInt16();
477         }
478     }
479 
contains(int index)480     boolean contains(int index) {
481         for (int curveId : curveIds) {
482             if (index == curveId) {
483                 return true;
484             }
485         }
486         return false;
487     }
488 
489     // Return a reference to the internal curveIds array.
490     // The caller must NOT modify the contents.
curveIds()491     int[] curveIds() {
492         return curveIds;
493     }
494 
length()495     int length() {
496         return 6 + (curveIds.length << 1);
497     }
498 
send(HandshakeOutStream s)499     void send(HandshakeOutStream s) throws IOException {
500         s.putInt16(type.id);
501         int k = curveIds.length << 1;
502         s.putInt16(k + 2);
503         s.putInt16(k);
504         for (int curveId : curveIds) {
505             s.putInt16(curveId);
506         }
507     }
508 
toString()509     public String toString() {
510         StringBuilder sb = new StringBuilder();
511         sb.append("Extension " + type + ", curve names: {");
512         boolean first = true;
513         for (int curveId : curveIds) {
514             if (first) {
515                 first = false;
516             } else {
517                 sb.append(", ");
518             }
519             // first check if it is a known named curve, then try other cases.
520             String oid = getCurveOid(curveId);
521             if (oid != null) {
522                 ECParameterSpec spec = JsseJce.getECParameterSpec(oid);
523                 // this toString() output will look nice for the current
524                 // implementation of the ECParameterSpec class in the Sun
525                 // provider, but may not look good for other implementations.
526                 if (spec != null) {
527                     sb.append(spec.toString().split(" ")[0]);
528                 } else {
529                     sb.append(oid);
530                 }
531             } else if (curveId == ARBITRARY_PRIME) {
532                 sb.append("arbitrary_explicit_prime_curves");
533             } else if (curveId == ARBITRARY_CHAR2) {
534                 sb.append("arbitrary_explicit_char2_curves");
535             } else {
536                 sb.append("unknown curve " + curveId);
537             }
538         }
539         sb.append("}");
540         return sb.toString();
541     }
542 
543     // Test whether we support the curve with the given index.
isSupported(int index)544     static boolean isSupported(int index) {
545         if ((index <= 0) || (index >= NAMED_CURVE_OID_TABLE.length)) {
546             return false;
547         }
548         if (fips == false) {
549             // in non-FIPS mode, we support all valid indices
550             return true;
551         }
552         return DEFAULT.contains(index);
553     }
554 
getCurveIndex(ECParameterSpec params)555     static int getCurveIndex(ECParameterSpec params) {
556         String oid = JsseJce.getNamedCurveOid(params);
557         if (oid == null) {
558             return -1;
559         }
560         Integer n = curveIndices.get(oid);
561         return (n == null) ? -1 : n;
562     }
563 
getCurveOid(int index)564     static String getCurveOid(int index) {
565         if ((index > 0) && (index < NAMED_CURVE_OID_TABLE.length)) {
566             return NAMED_CURVE_OID_TABLE[index];
567         }
568         return null;
569     }
570 
571     private final static int ARBITRARY_PRIME = 0xff01;
572     private final static int ARBITRARY_CHAR2 = 0xff02;
573 
574     // See sun.security.ec.NamedCurve for the OIDs
575     private final static String[] NAMED_CURVE_OID_TABLE = new String[] {
576         null,                   //  (0) unused
577         "1.3.132.0.1",          //  (1) sect163k1, NIST K-163
578         "1.3.132.0.2",          //  (2) sect163r1
579         "1.3.132.0.15",         //  (3) sect163r2, NIST B-163
580         "1.3.132.0.24",         //  (4) sect193r1
581         "1.3.132.0.25",         //  (5) sect193r2
582         "1.3.132.0.26",         //  (6) sect233k1, NIST K-233
583         "1.3.132.0.27",         //  (7) sect233r1, NIST B-233
584         "1.3.132.0.3",          //  (8) sect239k1
585         "1.3.132.0.16",         //  (9) sect283k1, NIST K-283
586         "1.3.132.0.17",         // (10) sect283r1, NIST B-283
587         "1.3.132.0.36",         // (11) sect409k1, NIST K-409
588         "1.3.132.0.37",         // (12) sect409r1, NIST B-409
589         "1.3.132.0.38",         // (13) sect571k1, NIST K-571
590         "1.3.132.0.39",         // (14) sect571r1, NIST B-571
591         "1.3.132.0.9",          // (15) secp160k1
592         "1.3.132.0.8",          // (16) secp160r1
593         "1.3.132.0.30",         // (17) secp160r2
594         "1.3.132.0.31",         // (18) secp192k1
595         "1.2.840.10045.3.1.1",  // (19) secp192r1, NIST P-192
596         "1.3.132.0.32",         // (20) secp224k1
597         "1.3.132.0.33",         // (21) secp224r1, NIST P-224
598         "1.3.132.0.10",         // (22) secp256k1
599         "1.2.840.10045.3.1.7",  // (23) secp256r1, NIST P-256
600         "1.3.132.0.34",         // (24) secp384r1, NIST P-384
601         "1.3.132.0.35",         // (25) secp521r1, NIST P-521
602     };
603 
604     private final static Map<String,Integer> curveIndices;
605 
606     static {
607         curveIndices = new HashMap<String,Integer>();
608         for (int i = 1; i < NAMED_CURVE_OID_TABLE.length; i++) {
curveIndices.put(NAMED_CURVE_OID_TABLE[i], i)609             curveIndices.put(NAMED_CURVE_OID_TABLE[i], i);
610         }
611     }
612 
613 }
614 
615 final class SupportedEllipticPointFormatsExtension extends HelloExtension {
616 
617     final static int FMT_UNCOMPRESSED = 0;
618     final static int FMT_ANSIX962_COMPRESSED_PRIME = 1;
619     final static int FMT_ANSIX962_COMPRESSED_CHAR2 = 2;
620 
621     static final HelloExtension DEFAULT =
622         new SupportedEllipticPointFormatsExtension(
623             new byte[] {FMT_UNCOMPRESSED});
624 
625     private final byte[] formats;
626 
SupportedEllipticPointFormatsExtension(byte[] formats)627     private SupportedEllipticPointFormatsExtension(byte[] formats) {
628         super(ExtensionType.EXT_EC_POINT_FORMATS);
629         this.formats = formats;
630     }
631 
SupportedEllipticPointFormatsExtension(HandshakeInStream s, int len)632     SupportedEllipticPointFormatsExtension(HandshakeInStream s, int len)
633             throws IOException {
634         super(ExtensionType.EXT_EC_POINT_FORMATS);
635         formats = s.getBytes8();
636         // RFC 4492 says uncompressed points must always be supported.
637         // Check just to make sure.
638         boolean uncompressed = false;
639         for (int format : formats) {
640             if (format == FMT_UNCOMPRESSED) {
641                 uncompressed = true;
642                 break;
643             }
644         }
645         if (uncompressed == false) {
646             throw new SSLProtocolException
647                 ("Peer does not support uncompressed points");
648         }
649     }
650 
length()651     int length() {
652         return 5 + formats.length;
653     }
654 
send(HandshakeOutStream s)655     void send(HandshakeOutStream s) throws IOException {
656         s.putInt16(type.id);
657         s.putInt16(formats.length + 1);
658         s.putBytes8(formats);
659     }
660 
toString(byte format)661     private static String toString(byte format) {
662         int f = format & 0xff;
663         switch (f) {
664         case FMT_UNCOMPRESSED:
665             return "uncompressed";
666         case FMT_ANSIX962_COMPRESSED_PRIME:
667             return "ansiX962_compressed_prime";
668         case FMT_ANSIX962_COMPRESSED_CHAR2:
669             return "ansiX962_compressed_char2";
670         default:
671             return "unknown-" + f;
672         }
673     }
674 
toString()675     public String toString() {
676         List<String> list = new ArrayList<>();
677         for (byte format : formats) {
678             list.add(toString(format));
679         }
680         return "Extension " + type + ", formats: " + list;
681     }
682 }
683 
684 /*
685  * For secure renegotiation, RFC5746 defines a new TLS extension,
686  * "renegotiation_info" (with extension type 0xff01), which contains a
687  * cryptographic binding to the enclosing TLS connection (if any) for
688  * which the renegotiation is being performed.  The "extension data"
689  * field of this extension contains a "RenegotiationInfo" structure:
690  *
691  *      struct {
692  *          opaque renegotiated_connection<0..255>;
693  *      } RenegotiationInfo;
694  */
695 final class RenegotiationInfoExtension extends HelloExtension {
696     private final byte[] renegotiated_connection;
697 
RenegotiationInfoExtension(byte[] clientVerifyData, byte[] serverVerifyData)698     RenegotiationInfoExtension(byte[] clientVerifyData,
699                 byte[] serverVerifyData) {
700         super(ExtensionType.EXT_RENEGOTIATION_INFO);
701 
702         if (clientVerifyData.length != 0) {
703             renegotiated_connection =
704                     new byte[clientVerifyData.length + serverVerifyData.length];
705             System.arraycopy(clientVerifyData, 0, renegotiated_connection,
706                     0, clientVerifyData.length);
707 
708             if (serverVerifyData.length != 0) {
709                 System.arraycopy(serverVerifyData, 0, renegotiated_connection,
710                         clientVerifyData.length, serverVerifyData.length);
711             }
712         } else {
713             // ignore both the client and server verify data.
714             renegotiated_connection = new byte[0];
715         }
716     }
717 
RenegotiationInfoExtension(HandshakeInStream s, int len)718     RenegotiationInfoExtension(HandshakeInStream s, int len)
719                 throws IOException {
720         super(ExtensionType.EXT_RENEGOTIATION_INFO);
721 
722         // check the extension length
723         if (len < 1) {
724             throw new SSLProtocolException("Invalid " + type + " extension");
725         }
726 
727         int renegoInfoDataLen = s.getInt8();
728         if (renegoInfoDataLen + 1 != len) {  // + 1 = the byte we just read
729             throw new SSLProtocolException("Invalid " + type + " extension");
730         }
731 
732         renegotiated_connection = new byte[renegoInfoDataLen];
733         if (renegoInfoDataLen != 0) {
734             s.read(renegotiated_connection, 0, renegoInfoDataLen);
735         }
736     }
737 
738 
739     // Length of the encoded extension, including the type and length fields
length()740     int length() {
741         return 5 + renegotiated_connection.length;
742     }
743 
send(HandshakeOutStream s)744     void send(HandshakeOutStream s) throws IOException {
745         s.putInt16(type.id);
746         s.putInt16(renegotiated_connection.length + 1);
747         s.putBytes8(renegotiated_connection);
748     }
749 
isEmpty()750     boolean isEmpty() {
751         return renegotiated_connection.length == 0;
752     }
753 
getRenegotiatedConnection()754     byte[] getRenegotiatedConnection() {
755         return renegotiated_connection;
756     }
757 
toString()758     public String toString() {
759         return "Extension " + type + ", renegotiated_connection: " +
760                     (renegotiated_connection.length == 0 ? "<empty>" :
761                     Debug.toString(renegotiated_connection));
762     }
763 
764 }
765 
766 /*
767  * [RFC5246] The client uses the "signature_algorithms" extension to
768  * indicate to the server which signature/hash algorithm pairs may be
769  * used in digital signatures.  The "extension_data" field of this
770  * extension contains a "supported_signature_algorithms" value.
771  *
772  *     enum {
773  *         none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
774  *         sha512(6), (255)
775  *     } HashAlgorithm;
776  *
777  *     enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
778  *       SignatureAlgorithm;
779  *
780  *     struct {
781  *           HashAlgorithm hash;
782  *           SignatureAlgorithm signature;
783  *     } SignatureAndHashAlgorithm;
784  *
785  *     SignatureAndHashAlgorithm
786  *       supported_signature_algorithms<2..2^16-2>;
787  */
788 final class SignatureAlgorithmsExtension extends HelloExtension {
789 
790     private Collection<SignatureAndHashAlgorithm> algorithms;
791     private int algorithmsLen;  // length of supported_signature_algorithms
792 
SignatureAlgorithmsExtension( Collection<SignatureAndHashAlgorithm> signAlgs)793     SignatureAlgorithmsExtension(
794             Collection<SignatureAndHashAlgorithm> signAlgs) {
795 
796         super(ExtensionType.EXT_SIGNATURE_ALGORITHMS);
797 
798         algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs);
799         algorithmsLen =
800             SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size();
801     }
802 
SignatureAlgorithmsExtension(HandshakeInStream s, int len)803     SignatureAlgorithmsExtension(HandshakeInStream s, int len)
804                 throws IOException {
805         super(ExtensionType.EXT_SIGNATURE_ALGORITHMS);
806 
807         algorithmsLen = s.getInt16();
808         if (algorithmsLen == 0 || algorithmsLen + 2 != len) {
809             throw new SSLProtocolException("Invalid " + type + " extension");
810         }
811 
812         algorithms = new ArrayList<SignatureAndHashAlgorithm>();
813         int remains = algorithmsLen;
814         int sequence = 0;
815         while (remains > 1) {   // needs at least two bytes
816             int hash = s.getInt8();         // hash algorithm
817             int signature = s.getInt8();    // signature algorithm
818 
819             SignatureAndHashAlgorithm algorithm =
820                 SignatureAndHashAlgorithm.valueOf(hash, signature, ++sequence);
821             algorithms.add(algorithm);
822             remains -= 2;  // one byte for hash, one byte for signature
823         }
824 
825         if (remains != 0) {
826             throw new SSLProtocolException("Invalid server_name extension");
827         }
828     }
829 
getSignAlgorithms()830     Collection<SignatureAndHashAlgorithm> getSignAlgorithms() {
831         return algorithms;
832     }
833 
834     @Override
length()835     int length() {
836         return 6 + algorithmsLen;
837     }
838 
839     @Override
send(HandshakeOutStream s)840     void send(HandshakeOutStream s) throws IOException {
841         s.putInt16(type.id);
842         s.putInt16(algorithmsLen + 2);
843         s.putInt16(algorithmsLen);
844 
845         for (SignatureAndHashAlgorithm algorithm : algorithms) {
846             s.putInt8(algorithm.getHashValue());      // HashAlgorithm
847             s.putInt8(algorithm.getSignatureValue()); // SignatureAlgorithm
848         }
849     }
850 
851     @Override
toString()852     public String toString() {
853         StringBuffer buffer = new StringBuffer();
854         boolean opened = false;
855         for (SignatureAndHashAlgorithm signAlg : algorithms) {
856             if (opened) {
857                 buffer.append(", " + signAlg.getAlgorithmName());
858             } else {
859                 buffer.append(signAlg.getAlgorithmName());
860                 opened = true;
861             }
862         }
863 
864         return "Extension " + type + ", signature_algorithms: " + buffer;
865     }
866 }
867