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 }