1 /**
2 * TLS Extensions
3 * 
4 * Copyright:
5 * (C) 2011-2012,2015 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.tls.extensions;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_TLS):
15 package:
16 
17 import memutils.vector;
18 import botan.tls.magic;
19 import botan.utils.types;
20 import memutils.hashmap;
21 import botan.tls.reader;
22 import botan.tls.exceptn;
23 import botan.tls.alert;
24 import botan.utils.types : Unique;
25 import botan.utils.get_byte;
26 import std.conv : to;
27 import std.array : Appender;
28 
29 alias ushort HandshakeExtensionType;
30 enum : HandshakeExtensionType {
31     TLSEXT_SERVER_NAME_INDICATION    = 0,
32     TLSEXT_MAX_FRAGMENT_LENGTH       = 1,
33     TLSEXT_CLIENT_CERT_URL           = 2,
34     TLSEXT_TRUSTED_CA_KEYS           = 3,
35     TLSEXT_TRUNCATED_HMAC            = 4,
36 
37     TLSEXT_CERTIFICATE_TYPES         = 9,
38     TLSEXT_USABLE_ELLIPTIC_CURVES    = 10,
39     TLSEXT_EC_POINT_FORMATS          = 11,
40     TLSEXT_SRP_IDENTIFIER            = 12,
41     TLSEXT_SIGNATURE_ALGORITHMS      = 13,
42     TLSEXT_HEARTBEAT_SUPPORT         = 15,
43     TLSEXT_ALPN                      = 16,
44 
45     TLSEXT_SESSION_TICKET            = 35,
46 
47     TLSEXT_SAFE_RENEGOTIATION        = 65281,
48 }
49 
50 /**
51 * Base class representing a TLS extension of some kind
52 */
53 interface Extension
54 {
55 public:
56     /**
57     * Returns: code number of the extension
58     */
59     abstract HandshakeExtensionType type() const;
60 
61     /**
62     * Returns: serialized binary for the extension
63     */
64     abstract Vector!ubyte serialize() const;
65 
66     /**
67     * Returns: if we should encode this extension or not
68     */
69     abstract @property bool empty() const;
70 }
71 
72 /**
73 * TLS Server Name Indicator extension (RFC 3546)
74 */
75 class ServerNameIndicator : Extension
76 {
77 public:
78     static HandshakeExtensionType staticType() { return TLSEXT_SERVER_NAME_INDICATION; }
79 
80     override HandshakeExtensionType type() const { return staticType(); }
81 
82     this(in string host_name) 
83     {
84 		//logDebug("SNI loaded with host name: ", host_name);
85         m_sni_host_name = host_name;
86     }
87 
88     this(ref TLSDataReader reader, ushort extension_size)
89     {
90         /*
91         * This is used by the server to confirm that it knew the name
92         */
93         if (extension_size == 0)
94             return;
95         
96         ushort name_bytes = reader.get_ushort();
97         
98         if (name_bytes + 2 != extension_size)
99             throw new DecodingError("Bad encoding of SNI extension");
100         
101         while (name_bytes)
102         {
103             ubyte name_type = reader.get_byte();
104             name_bytes--;
105             
106             if (name_type == 0) // DNS
107             {
108                 m_sni_host_name = reader.getString(2, 1, 65535);
109                 name_bytes -= (2 + m_sni_host_name.length);
110             }
111             else // some other unknown name type
112             {
113                 reader.discardNext(name_bytes);
114                 name_bytes = 0;
115             }
116         }
117     }
118 
119 	string hostName() const { return m_sni_host_name; }
120 
121     override Vector!ubyte serialize() const
122     {
123         Vector!ubyte buf;
124         
125         size_t name_len = m_sni_host_name.length;
126         
127         buf.pushBack(get_byte(0, cast(ushort) (name_len+3)));
128         buf.pushBack(get_byte(1, cast(ushort) (name_len+3)));
129         buf.pushBack(0); // DNS
130         
131         buf.pushBack(get_byte(0, cast(ushort) name_len));
132         buf.pushBack(get_byte(1, cast(ushort) name_len));
133         
134         buf ~= (cast(const(ubyte)*)m_sni_host_name.ptr)[0 .. m_sni_host_name.length];
135         
136         return buf.move();
137     }
138 
139     override @property bool empty() const { return m_sni_host_name == ""; }
140 private:
141     string m_sni_host_name;
142 }
143 
144 /**
145 * SRP identifier extension (RFC 5054)
146 */
147 class SRPIdentifier : Extension
148 {
149 public:
150     static HandshakeExtensionType staticType() { return TLSEXT_SRP_IDENTIFIER; }
151 
152     override HandshakeExtensionType type() const { return staticType(); }
153 
154     this(in string identifier) 
155     {
156         m_srp_identifier = identifier;
157     }
158 
159     this(ref TLSDataReader reader, ushort extension_size)
160     {
161         m_srp_identifier = reader.getString(1, 1, 255);
162         
163         if (m_srp_identifier.length + 1 != extension_size)
164             throw new DecodingError("Bad encoding for SRP identifier extension");
165     }
166 
167     this(ref TLSDataReader reader, ushort extension_size);
168 
169     string identifier() const { return m_srp_identifier; }
170 
171 
172     override Vector!ubyte serialize() const
173     {
174         Vector!ubyte buf;
175 
176         const(ubyte)* srp_bytes = cast(const(ubyte)*) m_srp_identifier.ptr;
177         
178         appendTlsLengthValue(buf, srp_bytes, m_srp_identifier.length, 1);
179         
180         return buf.move();
181     }
182 
183     override @property bool empty() const { return m_srp_identifier == ""; }
184 private:
185     string m_srp_identifier;
186 }
187 
188 /**
189 * Renegotiation Indication Extension (RFC 5746)
190 */
191 class RenegotiationExtension : Extension
192 {
193 public:
194     static HandshakeExtensionType staticType() { return TLSEXT_SAFE_RENEGOTIATION; }
195 
196     override HandshakeExtensionType type() const { return staticType(); }
197 
198     this() {}
199 
200     this(Vector!ubyte bits)
201     {
202         m_reneg_data = bits.move();
203     }
204 
205     this(ref TLSDataReader reader, ushort extension_size)
206     {
207         m_reneg_data = reader.getRange!ubyte(1, 0, 255);
208         
209         if (m_reneg_data.length + 1 != extension_size)
210             throw new DecodingError("Bad encoding for secure renegotiation extn");
211     }
212 
213     ref const(Vector!ubyte) renegotiationInfo() const { return m_reneg_data; }
214 
215     override Vector!ubyte serialize() const
216     {
217         Vector!ubyte buf;
218         appendTlsLengthValue(buf, m_reneg_data, 1);
219         return buf.move();
220     }
221 
222     override @property bool empty() const { return false; } // always send this
223 
224 private:
225     Vector!ubyte m_reneg_data;
226 }
227 
228 /**
229 * Maximum Fragment Length Negotiation Extension (RFC 4366 sec 3.2)
230 */
231 class MaximumFragmentLength : Extension
232 {
233 public:
234     static HandshakeExtensionType staticType() { return TLSEXT_MAX_FRAGMENT_LENGTH; }
235 
236     override HandshakeExtensionType type() const { return staticType(); }
237 
238     override @property bool empty() const { return false; }
239 
240     size_t fragmentSize() const { return m_max_fragment; }
241 
242     override Vector!ubyte serialize() const
243     {
244         static ubyte[size_t] fragment_to_code;
245         if (fragment_to_code.length == 0)
246             fragment_to_code = [ 512: 1, 1024: 2, 2048: 3, 4096: 4 ];
247         
248         auto i = fragment_to_code.get(m_max_fragment, 0);
249         
250         if (i == 0)
251             throw new InvalidArgument("Bad setting " ~ to!string(m_max_fragment) ~ " for maximum fragment size");
252         
253         return Vector!ubyte([i]);
254     }
255 
256     /**
257     * Params:
258     *  max_fragment = specifies what maximum fragment size to
259     *          advertise. Currently must be one of 512, 1024, 2048, or
260     *          4096.
261     */
262     this(size_t max_fragment) 
263     {
264         m_max_fragment = max_fragment;
265     }
266 
267     this(ref TLSDataReader reader, ushort extension_size)
268     {
269         __gshared immutable size_t[] code_to_fragment = [ 0, 512, 1024, 2048, 4096 ];
270         if (extension_size != 1)
271             throw new DecodingError("Bad size for maximum fragment extension");
272         ubyte val = reader.get_byte();
273 
274         if (val < code_to_fragment.length) {
275 
276             auto i = code_to_fragment[val];
277             
278             m_max_fragment = i;
279         }
280         else
281             throw new TLSException(TLSAlert.ILLEGAL_PARAMETER, "Bad value in maximum fragment extension");
282 
283     }
284 
285 private:
286     size_t m_max_fragment;
287 }
288 
289 /**
290 * ALPN (RFC 7301)
291 */
292 class ApplicationLayerProtocolNotification : Extension
293 {
294 public:
295     static HandshakeExtensionType staticType() { return TLSEXT_ALPN; }
296 
297     override HandshakeExtensionType type() const { return staticType(); }
298 
299     ref const(Vector!string) protocols() const { return m_protocols; }
300 
301     /**
302     * Single protocol, used by server
303     */
304     this() {}
305 
306     /**
307     * List of protocols, used by client
308     */
309     this(Vector!string protocols) 
310     {
311         m_protocols = protocols.move(); 
312     }
313 
314     this(string protocol) {
315         m_protocols.length = 1;
316         m_protocols[0] = protocol;
317     }
318 
319     this(ref TLSDataReader reader, ushort extension_size)
320     {
321         if (extension_size == 0)
322             return; // empty extension
323         
324         const ushort name_bytes = reader.get_ushort();
325         
326         size_t bytes_remaining = extension_size - 2;
327 
328         if (name_bytes != bytes_remaining)
329             throw new DecodingError("Bad encoding of ALPN extension, bad length field");
330 
331         while (bytes_remaining)
332         {
333             const string p = reader.getString(1, 0, 255);
334             
335             if (bytes_remaining < p.length + 1)
336                 throw new DecodingError("Bad encoding of ALPN, length field too long");
337             
338             bytes_remaining -= (p.length + 1);
339 			//logDebug("Got protocol: ", p); 
340             m_protocols.pushBack(p);
341         }
342     }
343 
344     ref string singleProtocol() const
345     {
346         if (m_protocols.length != 1)
347             throw new TLSException(TLSAlert.HANDSHAKE_FAILURE, "Server sent " ~ m_protocols.length.to!string ~ " protocols in ALPN extension response");
348         
349         return m_protocols[0];
350     }
351 
352     override Vector!ubyte serialize() const
353     {
354         Vector!ubyte buf = Vector!ubyte(2);
355 
356         foreach (ref p; m_protocols)
357         {
358             if (p.length >= 256)
359                 throw new TLSException(TLSAlert.INTERNAL_ERROR, "ALPN name too long");
360             if (p != "")
361                 appendTlsLengthValue(buf, cast(const(ubyte)*) p.ptr, p.length, 1);
362         }
363         ushort len = cast(ushort)( buf.length - 2 );
364         buf[0] = get_byte!ushort(0, len);
365         buf[1] = get_byte!ushort(1, len);
366 
367         return buf.move();
368     }
369 
370     override @property bool empty() const { return m_protocols.empty; }
371 private:
372     Vector!string m_protocols;
373 }
374 
375 /**
376 * TLSSession Ticket Extension (RFC 5077)
377 */
378 class SessionTicket : Extension
379 {
380 public:
381     static HandshakeExtensionType staticType() { return TLSEXT_SESSION_TICKET; }
382 
383     override HandshakeExtensionType type() const { return staticType(); }
384 
385     /**
386     * Returns: contents of the session ticket
387     */
388     ref const(Vector!ubyte) contents() const { return m_ticket; }
389 
390     /**
391     * Create empty extension, used by both client and server
392     */
393     this() {}
394 
395     /**
396     * Extension with ticket, used by client
397     */
398     this(Vector!ubyte session_ticket)
399     {
400         m_ticket = session_ticket.move();
401     }
402 
403     /**
404     * Deserialize a session ticket
405     */
406     this(ref TLSDataReader reader, ushort extension_size)
407     {
408         m_ticket = reader.getElem!(ubyte, Vector!ubyte)(extension_size);
409     }
410 
411     override Vector!ubyte serialize() const { return m_ticket.dup; }
412 
413     override @property bool empty() const { return false; }
414 private:
415     Vector!ubyte m_ticket;
416 }
417 
418 /**
419 * Supported Elliptic Curves Extension (RFC 4492)
420 */
421 class SupportedEllipticCurves : Extension
422 {
423 public:
424     static HandshakeExtensionType staticType() { return TLSEXT_USABLE_ELLIPTIC_CURVES; }
425 
426     override HandshakeExtensionType type() const { return staticType(); }
427 
428     static string curveIdToName(ushort id)
429     {
430         switch(id)
431         {
432             case 15:
433                 return "secp160k1";
434             case 16:
435                 return "secp160r1";
436             case 17:
437                 return "secp160r2";
438             case 18:
439                 return "secp192k1";
440             case 19:
441                 return "secp192r1";
442             case 20:
443                 return "secp224k1";
444             case 21:
445                 return "secp224r1";
446             case 22:
447                 return "secp256k1";
448             case 23:
449                 return "secp256r1";
450             case 24:
451                 return "secp384r1";
452             case 25:
453                 return "secp521r1";
454             case 26:
455                 return "brainpool256r1";
456             case 27:
457                 return "brainpool384r1";
458             case 28:
459                 return "brainpool512r1";
460             default:
461                 return id.to!string; // something we don't know or support
462         }
463     }
464 
465     static ushort nameToCurveId(in string name)
466     {
467         if (name == "secp160k1")
468             return 15;
469         if (name == "secp160r1")
470             return 16;
471         if (name == "secp160r2")
472             return 17;
473         if (name == "secp192k1")
474             return 18;
475         if (name == "secp192r1")
476             return 19;
477         if (name == "secp224k1")
478             return 20;
479         if (name == "secp224r1")
480             return 21;
481         if (name == "secp256k1")
482             return 22;
483         if (name == "secp256r1")
484             return 23;
485         if (name == "secp384r1")
486             return 24;
487         if (name == "secp521r1")
488             return 25;
489         if (name == "brainpool256r1")
490             return 26;
491         if (name == "brainpool384r1")
492             return 27;
493         if (name == "brainpool512r1")
494             return 28;
495         
496         throw new InvalidArgument("name_to_curve_id unknown name " ~ name);
497     }
498 
499     ref const(Vector!string) curves() const { return m_curves; }
500 
501     override Vector!ubyte serialize() const
502     {
503         Vector!ubyte buf = Vector!ubyte(2);
504         
505         for (size_t i = 0; i != m_curves.length; ++i)
506         {
507             const ushort id = nameToCurveId(m_curves[i]);
508             buf.pushBack(get_byte(0, id));
509             buf.pushBack(get_byte(1, id));
510         }
511         
512         buf[0] = get_byte(0, cast(ushort) (buf.length-2));
513         buf[1] = get_byte(1, cast(ushort) (buf.length-2));
514         
515         return buf.move();
516     }
517 
518     this(Vector!string curves) 
519     {
520         m_curves = curves.move();
521     }
522 
523     this(ref TLSDataReader reader, ushort extension_size)
524     {
525         ushort len = reader.get_ushort();
526 		//logDebug("Got elliptic curves len: ", len, " ext size: ", extension_size);
527         if (len + 2 != extension_size)
528             throw new DecodingError("Inconsistent length field in elliptic curve list");
529         
530         if (len % 2 == 1)
531             throw new DecodingError("Elliptic curve list of strange size");
532         
533         len /= 2;
534         
535         foreach (size_t i; 0 .. len)
536         {
537             const ushort id = reader.get_ushort();
538             const string name = curveIdToName(id);
539 			//logDebug("Got curve name: ", name);
540             
541             if (name != "")
542                 m_curves.pushBack(name);
543         }
544     }
545 
546     override @property bool empty() const { return m_curves.empty; }
547 private:
548     Vector!string m_curves;
549 }
550 
551 /**
552 * Signature Algorithms Extension for TLS 1.2 (RFC 5246)
553 */
554 class SignatureAlgorithms : Extension
555 {
556 public:
557     static HandshakeExtensionType staticType() { return TLSEXT_SIGNATURE_ALGORITHMS; }
558 
559     override HandshakeExtensionType type() const { return staticType(); }
560 
561     static string hashAlgoName(ubyte code)
562     {
563         switch(code)
564         {
565             case 1:
566                 return "MD5";
567                 // code 1 is MD5 - ignore it
568                 
569             case 2:
570                 return "SHA-1";
571             case 3:
572                 return "SHA-224";
573             case 4:
574                 return "SHA-256";
575             case 5:
576                 return "SHA-384";
577             case 6:
578                 return "SHA-512";
579             default:
580                 return "";
581         }
582     }
583 
584     static ubyte hashAlgoCode(in string name)
585     {
586         if (name == "MD5")
587             return 1;
588         
589         if (name == "SHA-1")
590             return 2;
591         
592         if (name == "SHA-224")
593             return 3;
594         
595         if (name == "SHA-256")
596             return 4;
597         
598         if (name == "SHA-384")
599             return 5;
600         
601         if (name == "SHA-512")
602             return 6;
603         
604         throw new InternalError("Unknown hash ID " ~ name ~ " for signature_algorithms");
605     }
606 
607     static string sigAlgoName(ubyte code)
608     {
609         switch(code)
610         {
611             case 1:
612                 return "RSA";
613             case 2:
614                 return "DSA";
615             case 3:
616                 return "ECDSA";
617             default:
618                 return "";
619         }
620     }
621 
622     static ubyte sigAlgoCode(in string name)
623     {
624         if (name == "RSA")
625             return 1;
626         
627         if (name == "DSA")
628             return 2;
629         
630         if (name == "ECDSA")
631             return 3;
632         
633         throw new InternalError("Unknown sig ID " ~ name ~ " for signature_algorithms");
634     }
635 
636     ref const(Vector!( Pair!(string, string)  )) supportedSignatureAlgorthms() const
637     {
638         return m_supported_algos;
639     }
640 
641     override Vector!ubyte serialize() const
642     {
643         Vector!ubyte buf = Vector!ubyte(2);
644         
645         for (size_t i = 0; i != m_supported_algos.length; ++i)
646         {
647             try
648             {
649                 const ubyte hash_code = hashAlgoCode(m_supported_algos[i].first);
650                 const ubyte sig_code = sigAlgoCode(m_supported_algos[i].second);
651                 
652                 buf.pushBack(hash_code);
653                 buf.pushBack(sig_code);
654             }
655             catch (Exception)
656             {}
657         }
658         
659         buf[0] = get_byte(0, cast(ushort) (buf.length-2));
660         buf[1] = get_byte(1, cast(ushort) (buf.length-2));
661         
662         return buf.move();
663     }
664 
665     override @property bool empty() const { return false; }
666 
667     this()(auto const ref Vector!string hashes, auto const ref Vector!string sigs)
668     {
669         for (size_t i = 0; i != hashes.length; ++i)
670             for (size_t j = 0; j != sigs.length; ++j)
671                 m_supported_algos.pushBack(makePair(hashes[i], sigs[j]));
672     }
673     
674     this(ref TLSDataReader reader,
675          ushort extension_size)
676     {
677         ushort len = reader.get_ushort();
678         
679         if (len + 2 != extension_size)
680             throw new DecodingError("Bad encoding on signature algorithms extension");
681         
682         while (len)
683         {
684             const string hash_code = hashAlgoName(reader.get_byte());
685             const string sig_code = sigAlgoName(reader.get_byte());
686             
687             len -= 2;
688             
689             // If not something we know, ignore it completely
690             if (hash_code == "" || sig_code == "")
691                 continue;
692 			//logDebug("Got signature: ", hash_code, " => ",sig_code);
693             m_supported_algos.pushBack(makePair(hash_code, sig_code));
694         }
695     }
696 
697     this(Vector!( Pair!(string, string)  ) algos) 
698     {
699         m_supported_algos = algos.move();
700     }
701 
702 private:
703     Vector!( Pair!(string, string) ) m_supported_algos;
704 }
705 
706 /**
707 * Heartbeat Extension (RFC 6520)
708 */
709 class HeartbeatSupportIndicator : Extension
710 {
711 public:
712     static HandshakeExtensionType staticType() { return TLSEXT_HEARTBEAT_SUPPORT; }
713 
714     override HandshakeExtensionType type() const { return staticType(); }
715 
716     bool peerAllowedToSend() const { return m_peer_allowed_to_send; }
717 
718     override Vector!ubyte serialize() const
719     {
720         Vector!ubyte heartbeat = Vector!ubyte(1);
721         heartbeat[0] = (m_peer_allowed_to_send ? 1 : 2);
722         return heartbeat.move();
723     }
724 
725     override @property bool empty() const { return false; }
726 
727     this(bool peer_allowed_to_send) 
728     {
729         m_peer_allowed_to_send = peer_allowed_to_send; 
730     }
731 
732     this(ref TLSDataReader reader, ushort extension_size)
733     {
734         if (extension_size != 1)
735             throw new DecodingError("Strange size for heartbeat extension");
736         
737         const ubyte code = reader.get_byte();
738         
739         if (code != 1 && code != 2)
740             throw new TLSException(TLSAlert.ILLEGAL_PARAMETER, "Unknown heartbeat code " ~ to!string(code));
741         
742         m_peer_allowed_to_send = (code == 1);
743     }
744 
745 private:
746     bool m_peer_allowed_to_send;
747 }
748 
749 /**
750 * Represents a block of extensions in a hello message
751 */
752 struct TLSExtensions
753 {
754 public:
755     Vector!HandshakeExtensionType extensionTypes() const
756     {
757 		return m_extensions.types.dup;
758     }
759 
760 
761     T get(T)() const
762     {
763         HandshakeExtensionType type = T.staticType();
764 
765         return cast(T)m_extensions.get(type, T.init);
766     }
767 
768     void add(Extension extn)
769     {
770         assert(extn);
771 
772         auto val = m_extensions.get(extn.type(), null);
773         if (val) {
774 			m_extensions.remove(extn.type());
775 		}
776         m_extensions.add(extn.type(), extn);
777     }
778 
779     Vector!ubyte serialize() const
780     {
781         Vector!ubyte buf = Vector!ubyte(2); // 2 bytes for length field
782         
783         foreach (const ref Extension extn; m_extensions.extensions[])
784         {
785             if (extn.empty)
786                 continue;
787             
788             const ushort extn_code = extn.type();
789             const Vector!ubyte extn_val = extn.serialize();
790             
791             buf.pushBack(get_byte(0, extn_code));
792             buf.pushBack(get_byte(1, extn_code));
793             
794             buf.pushBack(get_byte(0, cast(ushort) extn_val.length));
795             buf.pushBack(get_byte(1, cast(ushort) extn_val.length));
796             
797             buf ~= extn_val[];
798         }
799         
800         const ushort extn_size = cast(ushort) (buf.length - 2);
801         
802         buf[0] = get_byte(0, extn_size);
803         buf[1] = get_byte(1, extn_size);
804         
805         // avoid sending a completely empty extensions block
806         if (buf.length == 2)
807             return Vector!ubyte();
808         
809         return buf.move();
810     }
811 
812     void deserialize(ref TLSDataReader reader)
813     {
814         if (reader.hasRemaining())
815         {
816             const ushort all_extn_size = reader.get_ushort();
817             
818             if (reader.remainingBytes() != all_extn_size)
819                 throw new DecodingError("Bad extension size");
820             
821             while (reader.hasRemaining())
822             {
823                 const ushort extension_code = reader.get_ushort();
824                 const ushort extension_size = reader.get_ushort();
825 				//logDebug("Got extension: ", extension_code); 
826                 Extension extn = makeExtension(reader, extension_code, extension_size);
827                 
828                 if (extn)
829                     this.add(extn);
830                 else // unknown/unhandled extension
831                     reader.discardNext(extension_size);
832             }
833         }
834     }
835 
836     this(ref TLSDataReader reader) { deserialize(reader); }
837 
838 private:
839 	HandshakeExtensions m_extensions;
840 }
841 
842 private struct HandshakeExtensions {
843 private:
844 	Vector!HandshakeExtensionType types;
845 	Vector!Extension extensions;
846 
847 	Extension get(HandshakeExtensionType type, Extension dflt) const {
848 		size_t i;
849 		foreach (HandshakeExtensionType t; types[]) {
850 			if (t == type)
851 				return cast() extensions[i];
852 			i++;
853 		}
854 		return dflt;
855 	}
856 
857 	void add(HandshakeExtensionType type, Extension ext)
858 	{
859 		types ~= type;
860 		extensions ~= ext;
861 	}
862 
863 	void remove(HandshakeExtensionType type) {
864 		size_t i;
865 		foreach (HandshakeExtensionType t; types[]) {
866 			if (t == type) {
867 				Vector!HandshakeExtensionType tmp_types;
868 				tmp_types.reserve(types.length - 1);
869 				tmp_types ~= types[0 .. i];
870 				Vector!Extension tmp_extensions;
871 				tmp_extensions.reserve(extensions.length - 1);
872 				tmp_extensions ~= extensions[0 .. i];
873 				if (i != types.length - 1) {
874 					tmp_types ~= types[i+1 .. types.length];
875 					tmp_extensions ~= extensions[i+1 .. extensions.length];
876 				}
877 				types[] = tmp_types[];
878 				extensions[] = tmp_extensions[];
879 				return;
880 			}
881 			i++;
882 		}
883 		logError("Could not find a TLS extension we wanted to remove...");
884 	}
885 
886 }
887 
888 private:
889 
890 Extension makeExtension(ref TLSDataReader reader, ushort code, ushort size)
891 {
892     switch(code)
893     {
894         case TLSEXT_SERVER_NAME_INDICATION:
895             return new ServerNameIndicator(reader, size);
896             
897         case TLSEXT_MAX_FRAGMENT_LENGTH:
898             return new MaximumFragmentLength(reader, size);
899             
900         case TLSEXT_SRP_IDENTIFIER:
901             return new SRPIdentifier(reader, size);
902             
903         case TLSEXT_USABLE_ELLIPTIC_CURVES:
904             return new SupportedEllipticCurves(reader, size);
905             
906         case TLSEXT_SAFE_RENEGOTIATION:
907             return new RenegotiationExtension(reader, size);
908             
909         case TLSEXT_SIGNATURE_ALGORITHMS:
910             return new SignatureAlgorithms(reader, size);
911             
912         case TLSEXT_ALPN:
913             return new ApplicationLayerProtocolNotification(reader, size);
914             
915         case TLSEXT_HEARTBEAT_SUPPORT:
916             return new HeartbeatSupportIndicator(reader, size);
917             
918         case TLSEXT_SESSION_TICKET:
919             return new SessionTicket(reader, size);
920             
921         default:
922             return null; // not known
923     }
924 }