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 public alias ushort HandshakeExtensionType;
16 public enum : HandshakeExtensionType {
17     TLSEXT_SERVER_NAME_INDICATION    = 0,
18     TLSEXT_MAX_FRAGMENT_LENGTH       = 1,
19     TLSEXT_CLIENT_CERT_URL           = 2,
20     TLSEXT_TRUSTED_CA_KEYS           = 3,
21     TLSEXT_TRUNCATED_HMAC            = 4,
22 	TLSEXT_STATUS_REQUEST            = 5,
23 
24     TLSEXT_CERTIFICATE_TYPES         = 9,
25     TLSEXT_USABLE_ELLIPTIC_CURVES    = 10,
26     TLSEXT_EC_POINT_FORMATS          = 11,
27     TLSEXT_SRP_IDENTIFIER            = 12,
28     TLSEXT_SIGNATURE_ALGORITHMS      = 13,
29     TLSEXT_HEARTBEAT_SUPPORT         = 15,
30     TLSEXT_ALPN                      = 16,
31 	TLSEXT_SIGNED_CERT_TIMESTAMP     = 18,
32 	TLSEXT_PADDING                   = 21,
33 	TLSEXT_EXTENDED_MASTER_SECRET    = 23,
34 
35     TLSEXT_SESSION_TICKET            = 35,
36 
37 	TLSEXT_NPN                       = 13172,
38 
39 	TLSEXT_CHANNEL_ID                = 30032,
40 
41     TLSEXT_SAFE_RENEGOTIATION        = 65281,
42 }
43 
44 package:
45 
46 import memutils.vector;
47 import botan.tls.magic;
48 import botan.utils.types;
49 import memutils.hashmap;
50 import botan.tls.reader;
51 import botan.tls.exceptn;
52 import botan.tls.alert;
53 import botan.utils.types : Unique;
54 import botan.utils.get_byte;
55 import std.conv : to;
56 import std.array : Appender;
57 
58 /**
59 * Base class representing a TLS extension of some kind
60 */
61 interface Extension
62 {
63 public:
64     /**
65     * Returns: code number of the extension
66     */
67     abstract HandshakeExtensionType type() const;
68 
69     /**
70     * Returns: serialized binary for the extension
71     */
72     abstract Vector!ubyte serialize() const;
73 
74     /**
75     * Returns: if we should encode this extension or not
76     */
77     abstract @property bool empty() const;
78 }
79 
80 class NPN : Extension
81 {
82 	static HandshakeExtensionType staticType() { return TLSEXT_NPN; }
83 	
84 	override HandshakeExtensionType type() const { return staticType(); }
85 	
86 	override Vector!ubyte serialize() const
87 	{
88 		return Vector!ubyte();
89 	}
90 	
91 	override @property bool empty() const { return false; }
92 }
93 
94 /**
95  * OCSP Stapling
96 */
97 class StatusRequest : Extension
98 {
99 	static HandshakeExtensionType staticType() { return TLSEXT_STATUS_REQUEST; }
100 	
101 	override HandshakeExtensionType type() const { return staticType(); }
102 	
103 	override Vector!ubyte serialize() const
104 	{
105 		Vector!ubyte buf;
106 		buf.reserve(5);
107 		buf.pushBack(0x01); // OCSP
108 
109 		// Responders
110 		buf.pushBack(0x00);
111 		buf.pushBack(0x00);
112 
113 		// Request Extensions
114 		buf.pushBack(0x00);
115 		buf.pushBack(0x00);
116 		
117 		return buf.move();
118 	}
119 	
120 	override @property bool empty() const { return false; }
121 }
122 
123 /**
124  * Extended master secret
125  */
126 class ExtendedMasterSecret : Extension
127 {
128 	static HandshakeExtensionType staticType() { return TLSEXT_EXTENDED_MASTER_SECRET; }
129 	
130 	override HandshakeExtensionType type() const { return staticType(); }
131 	
132 	override Vector!ubyte serialize() const
133 	{
134 		return Vector!ubyte();
135 	}
136 	
137 	override @property bool empty() const { return false; }
138 
139 	this(){}
140 
141 	this(ref TLSDataReader reader, ushort extension_size)
142 	{
143 		if (extension_size != 0)
144 			throw new DecodingError("Invalid extended_master_secret extension");
145 	}
146 }
147 
148 /**
149 * Signed Certificate Timestamp
150 */
151 class SignedCertificateTimestamp : Extension
152 {
153 public:
154 	static HandshakeExtensionType staticType() { return TLSEXT_SIGNED_CERT_TIMESTAMP; }
155 	
156 	override HandshakeExtensionType type() const { return staticType(); }
157 	
158 	override Vector!ubyte serialize() const
159 	{
160 		return Vector!ubyte();
161 	}
162 	
163 	override @property bool empty() const { return false; }
164 }
165 
166 /**
167 * Channel ID
168 */
169 class ChannelIDSupport : Extension
170 {
171 public:
172     static HandshakeExtensionType staticType() { return TLSEXT_CHANNEL_ID; }
173     
174     override HandshakeExtensionType type() const { return staticType(); }
175     
176     override Vector!ubyte serialize() const
177     {
178         return Vector!ubyte();
179     }
180 
181     this() {}
182 
183     this(ref TLSDataReader reader, ushort extension_size)
184     {
185         /*
186         * This is used by the server to confirm that it supports Channel ID
187         */
188     }
189         
190     override @property bool empty() const { return false; }
191     
192 }
193 /**
194 * Channel ID
195 */
196 class EncryptedChannelID : Extension
197 {
198     import botan.pubkey.pk_keys;
199     import botan.pubkey.algo.ecdsa;
200     import botan.math.bigint.bigint;
201 public:
202     static HandshakeExtensionType staticType() { return TLSEXT_CHANNEL_ID; }
203     
204     override HandshakeExtensionType type() const { return staticType(); }
205   
206 
207     this(PrivateKey pkey, SecureVector!ubyte hs_hash, SecureVector!ubyte orig_hs_hash) {
208         m_priv = pkey;
209         m_hs_hash = hs_hash.move();
210         m_orig_hs_hash = orig_hs_hash.move();
211     }
212     
213     this(ref TLSDataReader reader, ushort extension_size)
214     {
215         /*
216         * The (x,y) pubkey verifies the info and its hash will be saved and used as a machine identifier
217         */
218     }
219 
220     override Vector!ubyte serialize() const
221     {
222         Vector!ubyte buf;
223         static string magic = "TLS Channel ID signature\x00";
224         static string resume_magic = "Resumption\x00";
225         buf.reserve(32*4);
226         SecureVector!ubyte concat = cast(ubyte[])magic;
227 
228         if (m_orig_hs_hash.length > 0) {
229             concat.reserve(128);
230             concat ~= resume_magic;
231             concat ~= m_orig_hs_hash[];
232         }
233 
234         concat ~= m_hs_hash[];
235         import botan.libstate.lookup;
236         Unique!HashFunction sha256 = retrieveHash("SHA-256").clone();
237         sha256.update(concat[]);
238         SecureVector!ubyte channel_id_hash = sha256.finished();
239         ECDSAPrivateKey ecdsa_priv = ECDSAPrivateKey(m_priv);
240         const BigInt x = ecdsa_priv.publicPoint().getAffineX();
241         const BigInt y = ecdsa_priv.publicPoint().getAffineY();
242         import std.algorithm : max;
243         size_t part_size = max(x.bytes(), y.bytes());
244         enforce(part_size <= 32);
245         Vector!ubyte bits = Vector!ubyte(64);
246         
247         x.binaryEncode(bits.ptr);
248         y.binaryEncode(bits.ptr + 32);
249 
250         buf ~= bits[];
251         auto signer = scoped!ECDSASignatureOperation(ecdsa_priv);
252         import botan.rng.auto_rng : AutoSeededRNG;
253         auto rng = scoped!AutoSeededRNG();
254         auto sig = signer.sign(channel_id_hash.ptr, channel_id_hash.length, rng).unlock();
255         buf ~= sig;
256         return buf.move();
257     }
258 
259     override @property bool empty() const { return false; }
260 
261 private:
262     PrivateKey m_priv;
263     SecureVector!ubyte m_orig_hs_hash;
264     SecureVector!ubyte m_hs_hash;
265 }
266 
267 /**
268 * EC Point formats (RFC 4492) only uncompressed supported.
269 */
270 class SupportedPointFormats : Extension
271 {
272 public:
273 	static HandshakeExtensionType staticType() { return TLSEXT_EC_POINT_FORMATS; }
274 	
275 	override HandshakeExtensionType type() const { return staticType(); }
276 		
277 	override Vector!ubyte serialize() const
278 	{
279 		Vector!ubyte buf;
280 		buf.reserve(4);
281 		buf.pushBack(0x01); // 1 point format
282 
283 		//uncompressed
284 		buf.pushBack(0x00);
285 		
286 		return buf.move();
287 	}
288 	
289 	override @property bool empty() const { return false; }
290 }
291 
292 /**
293 * TLS Server Name Indicator extension (RFC 3546)
294 */
295 class ServerNameIndicator : Extension
296 {
297 public:
298     static HandshakeExtensionType staticType() { return TLSEXT_SERVER_NAME_INDICATION; }
299 
300     override HandshakeExtensionType type() const { return staticType(); }
301 
302     this(in string host_name) 
303     {
304 		//logDebug("SNI loaded with host name: ", host_name);
305         m_sni_host_name = host_name;
306     }
307 
308     this(ref TLSDataReader reader, ushort extension_size)
309     {
310         /*
311         * This is used by the server to confirm that it knew the name
312         */
313         if (extension_size == 0)
314             return;
315         
316         ushort name_bytes = reader.get_ushort();
317         
318         if (name_bytes + 2 != extension_size)
319             throw new DecodingError("Bad encoding of SNI extension");
320         
321         while (name_bytes)
322         {
323             ubyte name_type = reader.get_byte();
324             name_bytes--;
325             
326             if (name_type == 0) // DNS
327             {
328                 m_sni_host_name = reader.getString(2, 1, 65535);
329                 name_bytes -= (2 + m_sni_host_name.length);
330             }
331             else // some other unknown name type
332             {
333                 reader.discardNext(name_bytes);
334                 name_bytes = 0;
335             }
336         }
337     }
338 
339 	string hostName() const { return m_sni_host_name; }
340 
341     override Vector!ubyte serialize() const
342     {
343         Vector!ubyte buf;
344         
345         size_t name_len = m_sni_host_name.length;
346         
347         buf.pushBack(get_byte(0, cast(ushort) (name_len+3)));
348         buf.pushBack(get_byte(1, cast(ushort) (name_len+3)));
349         buf.pushBack(0); // DNS
350         
351         buf.pushBack(get_byte(0, cast(ushort) name_len));
352         buf.pushBack(get_byte(1, cast(ushort) name_len));
353         
354         buf ~= (cast(const(ubyte)*)m_sni_host_name.ptr)[0 .. m_sni_host_name.length];
355         
356         return buf.move();
357     }
358 
359     override @property bool empty() const { return m_sni_host_name == ""; }
360 private:
361     string m_sni_host_name;
362 }
363 
364 /**
365 * SRP identifier extension (RFC 5054)
366 */
367 class SRPIdentifier : Extension
368 {
369 public:
370     static HandshakeExtensionType staticType() { return TLSEXT_SRP_IDENTIFIER; }
371 
372     override HandshakeExtensionType type() const { return staticType(); }
373 
374     this(in string identifier) 
375     {
376         m_srp_identifier = identifier;
377     }
378 
379     this(ref TLSDataReader reader, ushort extension_size)
380     {
381         m_srp_identifier = reader.getString(1, 1, 255);
382         
383         if (m_srp_identifier.length + 1 != extension_size)
384             throw new DecodingError("Bad encoding for SRP identifier extension");
385     }
386 
387     this(ref TLSDataReader reader, ushort extension_size);
388 
389     string identifier() const { return m_srp_identifier; }
390 
391 
392     override Vector!ubyte serialize() const
393     {
394         Vector!ubyte buf;
395 
396         const(ubyte)* srp_bytes = cast(const(ubyte)*) m_srp_identifier.ptr;
397         
398         appendTlsLengthValue(buf, srp_bytes, m_srp_identifier.length, 1);
399         
400         return buf.move();
401     }
402 
403     override @property bool empty() const { return m_srp_identifier == ""; }
404 private:
405     string m_srp_identifier;
406 }
407 
408 /**
409 * Renegotiation Indication Extension (RFC 5746)
410 */
411 class RenegotiationExtension : Extension
412 {
413 public:
414     static HandshakeExtensionType staticType() { return TLSEXT_SAFE_RENEGOTIATION; }
415 
416     override HandshakeExtensionType type() const { return staticType(); }
417 
418     this() {}
419 
420     this(Vector!ubyte bits)
421     {
422         m_reneg_data = bits.move();
423     }
424 
425     this(ref TLSDataReader reader, ushort extension_size)
426     {
427         m_reneg_data = reader.getRange!ubyte(1, 0, 255);
428         
429         if (m_reneg_data.length + 1 != extension_size)
430             throw new DecodingError("Bad encoding for secure renegotiation extn");
431     }
432 
433     ref const(Vector!ubyte) renegotiationInfo() const { return m_reneg_data; }
434 
435     override Vector!ubyte serialize() const
436     {
437         Vector!ubyte buf;
438         appendTlsLengthValue(buf, m_reneg_data, 1);
439         return buf.move();
440     }
441 
442     override @property bool empty() const { return m_reneg_data.empty; }
443 
444 private:
445     Vector!ubyte m_reneg_data;
446 }
447 
448 /**
449 * Maximum Fragment Length Negotiation Extension (RFC 4366 sec 3.2)
450 */
451 class MaximumFragmentLength : Extension
452 {
453 public:
454     static HandshakeExtensionType staticType() { return TLSEXT_MAX_FRAGMENT_LENGTH; }
455 
456     override HandshakeExtensionType type() const { return staticType(); }
457 
458     override @property bool empty() const { return false; }
459 
460     size_t fragmentSize() const { return m_max_fragment; }
461 
462     override Vector!ubyte serialize() const
463     {
464         static ubyte[size_t] fragment_to_code;
465         if (fragment_to_code.length == 0)
466             fragment_to_code = [ 512: 1, 1024: 2, 2048: 3, 4096: 4 ];
467         
468         auto i = fragment_to_code.get(m_max_fragment, 0);
469         
470         if (i == 0)
471             throw new InvalidArgument("Bad setting " ~ to!string(m_max_fragment) ~ " for maximum fragment size");
472         
473         return Vector!ubyte([i]);
474     }
475 
476     /**
477     * Params:
478     *  max_fragment = specifies what maximum fragment size to
479     *          advertise. Currently must be one of 512, 1024, 2048, or
480     *          4096.
481     */
482     this(size_t max_fragment) 
483     {
484         m_max_fragment = max_fragment;
485     }
486 
487     this(ref TLSDataReader reader, ushort extension_size)
488     {
489         __gshared immutable size_t[] code_to_fragment = [ 0, 512, 1024, 2048, 4096 ];
490         if (extension_size != 1)
491             throw new DecodingError("Bad size for maximum fragment extension");
492         ubyte val = reader.get_byte();
493 
494         if (val < code_to_fragment.length) {
495 
496             auto i = code_to_fragment[val];
497             
498             m_max_fragment = i;
499         }
500         else
501             throw new TLSException(TLSAlert.ILLEGAL_PARAMETER, "Bad value in maximum fragment extension");
502 
503     }
504 
505 private:
506     size_t m_max_fragment;
507 }
508 
509 /**
510 * ALPN (RFC 7301)
511 */
512 class ApplicationLayerProtocolNotification : Extension
513 {
514 public:
515     static HandshakeExtensionType staticType() { return TLSEXT_ALPN; }
516 
517     override HandshakeExtensionType type() const { return staticType(); }
518 
519     ref const(Vector!string) protocols() const { return m_protocols; }
520 
521     /**
522     * Single protocol, used by server
523     */
524     this() {}
525 
526     /**
527     * List of protocols, used by client
528     */
529     this(Vector!string protocols) 
530     {
531         m_protocols = protocols.move(); 
532     }
533 
534     this(string protocol) {
535         m_protocols.length = 1;
536         m_protocols[0] = protocol;
537     }
538 
539     this(ref TLSDataReader reader, ushort extension_size)
540     {
541         if (extension_size == 0)
542             return; // empty extension
543         
544         const ushort name_bytes = reader.get_ushort();
545         
546         size_t bytes_remaining = extension_size - 2;
547 
548         if (name_bytes != bytes_remaining)
549             throw new DecodingError("Bad encoding of ALPN extension, bad length field");
550 
551         while (bytes_remaining)
552         {
553             const string p = reader.getString(1, 0, 255);
554             
555             if (bytes_remaining < p.length + 1)
556                 throw new DecodingError("Bad encoding of ALPN, length field too long");
557             
558             bytes_remaining -= (p.length + 1);
559 			//logDebug("Got protocol: ", p); 
560             m_protocols.pushBack(p);
561         }
562     }
563 
564     ref string singleProtocol() const
565     {
566         if (m_protocols.length != 1)
567             throw new TLSException(TLSAlert.HANDSHAKE_FAILURE, "Server sent " ~ m_protocols.length.to!string ~ " protocols in ALPN extension response");
568         
569         return m_protocols[0];
570     }
571 
572     override Vector!ubyte serialize() const
573     {
574         Vector!ubyte buf = Vector!ubyte(2);
575 
576         foreach (ref p; m_protocols)
577         {
578             if (p.length >= 256)
579                 throw new TLSException(TLSAlert.INTERNAL_ERROR, "ALPN name too long");
580             if (p != "")
581                 appendTlsLengthValue(buf, cast(const(ubyte)*) p.ptr, p.length, 1);
582         }
583         ushort len = cast(ushort)( buf.length - 2 );
584         buf[0] = get_byte!ushort(0, len);
585         buf[1] = get_byte!ushort(1, len);
586 
587         return buf.move();
588     }
589 
590     override @property bool empty() const { return m_protocols.empty; }
591 private:
592     Vector!string m_protocols;
593 }
594 
595 /**
596 * TLSSession Ticket Extension (RFC 5077)
597 */
598 class SessionTicket : Extension
599 {
600 public:
601     static HandshakeExtensionType staticType() { return TLSEXT_SESSION_TICKET; }
602 
603     override HandshakeExtensionType type() const { return staticType(); }
604 
605     /**
606     * Returns: contents of the session ticket
607     */
608     ref const(Vector!ubyte) contents() const { return m_ticket; }
609 
610     /**
611     * Create empty extension, used by both client and server
612     */
613     this() {}
614 
615     /**
616     * Extension with ticket, used by client
617     */
618     this(Vector!ubyte session_ticket)
619     {
620         m_ticket = session_ticket.move();
621     }
622 
623     /**
624     * Deserialize a session ticket
625     */
626     this(ref TLSDataReader reader, ushort extension_size)
627     {
628         m_ticket = reader.getElem!(ubyte, Vector!ubyte)(extension_size);
629     }
630 
631     override Vector!ubyte serialize() const { return m_ticket.dup; }
632 
633     override @property bool empty() const { return false; }
634 private:
635     Vector!ubyte m_ticket;
636 }
637 
638 /**
639 * Supported Elliptic Curves Extension (RFC 4492)
640 */
641 class SupportedEllipticCurves : Extension
642 {
643 public:
644     static HandshakeExtensionType staticType() { return TLSEXT_USABLE_ELLIPTIC_CURVES; }
645 
646     override HandshakeExtensionType type() const { return staticType(); }
647 
648     static string curveIdToName(ushort id)
649     {
650         switch(id)
651         {
652 			/*
653 			 * unsupported 
654 			 */
655 			case 1:
656 				return "sect163k1";
657 			case 2:
658 				return "sect163r1";
659 			case 3:
660 				return "sect163r2";
661 			case 4:
662 				return "sect193r1";
663 			case 5:
664 				return "sect193r2";
665 			case 6:
666 				return "sect233k1";
667 			case 7:
668 				return "sect233r1";
669 			case 8:
670 				return "sect239k1";
671 			case 9:
672 				return "sect283k1";
673 			case 10:
674 				return "sect283r1";
675 			case 11:
676 				return "sect409k1";
677 			case 12:
678 				return "sect409r1";
679 			case 13:
680 				return "sect571k1";
681 			case 14:
682 				return "sect571r1";
683 			/*
684 			 * supported
685 			 */
686             case 15:
687                 return "secp160k1";
688             case 16:
689                 return "secp160r1";
690             case 17:
691                 return "secp160r2";
692             case 18:
693                 return "secp192k1";
694             case 19:
695                 return "secp192r1";
696             case 20:
697                 return "secp224k1";
698             case 21:
699                 return "secp224r1";
700             case 22:
701                 return "secp256k1";
702             case 23:
703                 return "secp256r1";
704             case 24:
705                 return "secp384r1";
706             case 25:
707                 return "secp521r1";
708             case 26:
709                 return "brainpool256r1";
710             case 27:
711                 return "brainpool384r1";
712             case 28:
713                 return "brainpool512r1";
714 			case 29:
715 				return "x25519";
716 			
717             default:
718                 return id.to!string; // something we don't know or support
719         }
720     }
721 
722     static ushort nameToCurveId(in string name)
723     {
724 		/*
725 		 * unsupported 
726 		 */
727 		if (name == "sect163k1")
728 			return 1;
729 		if (name == "sect163r1")
730 			return 2;
731 		if (name == "sect163r2")
732 			return 3;
733 		if (name == "sect193r1")
734 			return 4;
735 		if (name == "sect193r2")
736 			return 5;
737 		if (name == "sect233k1")
738 			return 6;
739 		if (name == "sect233r1")
740 			return 7;
741 		if (name == "sect239k1")
742 			return 8;
743 		if (name == "sect283k1")
744 			return 9;
745 		if (name == "sect283r1")
746 			return 10;
747 		if (name == "sect409k1")
748 			return 11;
749 		if (name == "sect409r1")
750 			return 12;
751 		if (name == "sect571k1")
752 			return 13;
753 		if (name == "sect571r1")
754 			return 14;
755 
756 		/*
757 		 * supported
758 		 */
759         if (name == "secp160k1")
760             return 15;
761         if (name == "secp160r1")
762             return 16;
763         if (name == "secp160r2")
764             return 17;
765         if (name == "secp192k1")
766             return 18;
767         if (name == "secp192r1")
768             return 19;
769         if (name == "secp224k1")
770             return 20;
771         if (name == "secp224r1")
772             return 21;
773         if (name == "secp256k1")
774             return 22;
775         if (name == "secp256r1")
776             return 23;
777         if (name == "secp384r1")
778             return 24;
779         if (name == "secp521r1")
780             return 25;
781         if (name == "brainpool256r1")
782             return 26;
783         if (name == "brainpool384r1")
784             return 27;
785         if (name == "brainpool512r1")
786             return 28;
787 		if (name == "x25519")
788 			return 29;
789         
790         throw new InvalidArgument("name_to_curve_id unknown name " ~ name);
791     }
792 
793     ref const(Vector!string) curves() const { return m_curves; }
794 
795     override Vector!ubyte serialize() const
796     {
797 		Vector!ubyte buf;
798 		buf.reserve(m_curves.length * 2 + 2);
799 		buf.length = 2;
800         
801         for (size_t i = 0; i != m_curves.length; ++i)
802         {
803             const ushort id = nameToCurveId(m_curves[i]);
804             buf.pushBack(get_byte(0, id));
805             buf.pushBack(get_byte(1, id));
806         }
807         
808         buf[0] = get_byte(0, cast(ushort) (buf.length-2));
809         buf[1] = get_byte(1, cast(ushort) (buf.length-2));
810         
811         return buf.move();
812     }
813 
814     this(Vector!string curves) 
815     {
816         m_curves = curves.move();
817     }
818 
819     this(ref TLSDataReader reader, ushort extension_size)
820     {
821         ushort len = reader.get_ushort();
822 		m_curves.reserve(cast(size_t)len);
823 		//logDebug("Got elliptic curves len: ", len, " ext size: ", extension_size);
824         if (len + 2 != extension_size)
825             throw new DecodingError("Inconsistent length field in elliptic curve list");
826         
827         if (len % 2 == 1)
828             throw new DecodingError("Elliptic curve list of strange size");
829         
830         len /= 2;
831         
832         foreach (size_t i; 0 .. len)
833         {
834             const ushort id = reader.get_ushort();
835             const string name = curveIdToName(id);
836 			//logDebug("Got curve name: ", name);
837             
838             if (name != "")
839                 m_curves.pushBack(name);
840         }
841     }
842 
843     override @property bool empty() const { return m_curves.empty; }
844 private:
845     Vector!string m_curves;
846 }
847 
848 /**
849 * Signature Algorithms Extension for TLS 1.2 (RFC 5246)
850 */
851 class SignatureAlgorithms : Extension
852 {
853 public:
854     static HandshakeExtensionType staticType() { return TLSEXT_SIGNATURE_ALGORITHMS; }
855 
856     override HandshakeExtensionType type() const { return staticType(); }
857 
858     static string hashAlgoName(ubyte code)
859     {
860         switch(code)
861         {
862             case 1:
863                 return "MD5";
864                 // code 1 is MD5 - ignore it
865                 
866             case 2:
867                 return "SHA-1";
868             case 3:
869                 return "SHA-224";
870             case 4:
871                 return "SHA-256";
872             case 5:
873                 return "SHA-384";
874             case 6:
875                 return "SHA-512";
876             default:
877                 return "";
878         }
879     }
880 
881     static ubyte hashAlgoCode(in string name)
882     {
883         if (name == "MD5")
884             return 1;
885         
886         if (name == "SHA-1")
887             return 2;
888         
889         if (name == "SHA-224")
890             return 3;
891         
892         if (name == "SHA-256")
893             return 4;
894         
895         if (name == "SHA-384")
896             return 5;
897         
898         if (name == "SHA-512")
899             return 6;
900         
901         throw new InternalError("Unknown hash ID " ~ name ~ " for signature_algorithms");
902     }
903 
904     static string sigAlgoName(ubyte code)
905     {
906         switch(code)
907         {
908             case 1:
909                 return "RSA";
910             case 2:
911                 return "DSA";
912             case 3:
913                 return "ECDSA";
914             default:
915                 return "";
916         }
917     }
918 
919     static ubyte sigAlgoCode(in string name)
920     {
921         if (name == "RSA")
922             return 1;
923         
924         if (name == "DSA")
925             return 2;
926         
927         if (name == "ECDSA")
928             return 3;
929         
930         throw new InternalError("Unknown sig ID " ~ name ~ " for signature_algorithms");
931     }
932 
933     ref const(Vector!( Pair!(string, string)  )) supportedSignatureAlgorthms() const
934     {
935         return m_supported_algos;
936     }
937 
938     override Vector!ubyte serialize() const
939     {
940         Vector!ubyte buf = Vector!ubyte(2);
941         
942         for (size_t i = 0; i != m_supported_algos.length; ++i)
943         {
944             try
945             {
946                 const ubyte hash_code = hashAlgoCode(m_supported_algos[i].first);
947                 const ubyte sig_code = sigAlgoCode(m_supported_algos[i].second);
948                 
949                 buf.pushBack(hash_code);
950                 buf.pushBack(sig_code);
951             }
952             catch (Exception)
953             {}
954         }
955         
956         buf[0] = get_byte(0, cast(ushort) (buf.length-2));
957         buf[1] = get_byte(1, cast(ushort) (buf.length-2));
958         
959         return buf.move();
960     }
961 
962     override @property bool empty() const { return false; }
963 
964     this()(auto const ref Vector!string hashes, auto const ref Vector!string sigs)
965     {
966         for (size_t i = 0; i != hashes.length; ++i)
967             for (size_t j = 0; j != sigs.length; ++j)
968                 m_supported_algos.pushBack(makePair(hashes[i], sigs[j]));
969     }
970     
971     this(ref TLSDataReader reader,
972          ushort extension_size)
973     {
974         ushort len = reader.get_ushort();
975         
976         if (len + 2 != extension_size)
977             throw new DecodingError("Bad encoding on signature algorithms extension");
978         
979         while (len)
980         {
981             const string hash_code = hashAlgoName(reader.get_byte());
982             const string sig_code = sigAlgoName(reader.get_byte());
983             
984             len -= 2;
985             
986             // If not something we know, ignore it completely
987             if (hash_code == "" || sig_code == "")
988                 continue;
989 			//logDebug("Got signature: ", hash_code, " => ",sig_code);
990             m_supported_algos.pushBack(makePair(hash_code, sig_code));
991         }
992     }
993 
994     this(Vector!( Pair!(string, string)  ) algos) 
995     {
996         m_supported_algos = algos.move();
997     }
998 
999 private:
1000     Vector!( Pair!(string, string) ) m_supported_algos;
1001 }
1002 
1003 /**
1004 * Heartbeat Extension (RFC 6520)
1005 */
1006 class HeartbeatSupportIndicator : Extension
1007 {
1008 public:
1009     static HandshakeExtensionType staticType() { return TLSEXT_HEARTBEAT_SUPPORT; }
1010 
1011     override HandshakeExtensionType type() const { return staticType(); }
1012 
1013     bool peerAllowedToSend() const { return m_peer_allowed_to_send; }
1014 
1015     override Vector!ubyte serialize() const
1016     {
1017         Vector!ubyte heartbeat = Vector!ubyte(1);
1018         heartbeat[0] = (m_peer_allowed_to_send ? 1 : 2);
1019         return heartbeat.move();
1020     }
1021 
1022     override @property bool empty() const { return false; }
1023 
1024     this(bool peer_allowed_to_send) 
1025     {
1026         m_peer_allowed_to_send = peer_allowed_to_send; 
1027     }
1028 
1029     this(ref TLSDataReader reader, ushort extension_size)
1030     {
1031         if (extension_size != 1)
1032             throw new DecodingError("Strange size for heartbeat extension");
1033         
1034         const ubyte code = reader.get_byte();
1035         
1036         if (code != 1 && code != 2)
1037             throw new TLSException(TLSAlert.ILLEGAL_PARAMETER, "Unknown heartbeat code " ~ to!string(code));
1038         
1039         m_peer_allowed_to_send = (code == 1);
1040     }
1041 
1042 private:
1043     bool m_peer_allowed_to_send;
1044 }
1045 
1046 /**
1047 * Represents a block of extensions in a hello message
1048 */
1049 struct TLSExtensions
1050 {
1051 public:
1052     Vector!HandshakeExtensionType extensionTypes() const
1053     {
1054 		return m_extensions.types.dup;
1055     }
1056 
1057 
1058     T get(T)() const
1059     {
1060         HandshakeExtensionType type = T.staticType();
1061 
1062         return cast(T)m_extensions.get(type, T.init);
1063     }
1064 
1065     void add(Extension extn)
1066     {
1067         assert(extn);
1068 
1069         auto val = m_extensions.get(extn.type(), null);
1070         if (val) {
1071 			m_extensions.remove(extn.type());
1072 		}
1073         m_extensions.add(extn.type(), extn);
1074     }
1075 
1076     Vector!ubyte serialize() const
1077     {
1078         Vector!ubyte buf = Vector!ubyte(2); // 2 bytes for length field
1079         
1080         foreach (const ref Extension extn; m_extensions.extensions[])
1081         {
1082             if (extn.empty)
1083                 continue;
1084             
1085             const ushort extn_code = extn.type();
1086             const Vector!ubyte extn_val = extn.serialize();
1087             
1088             buf.pushBack(get_byte(0, extn_code));
1089             buf.pushBack(get_byte(1, extn_code));
1090             
1091             buf.pushBack(get_byte(0, cast(ushort) extn_val.length));
1092             buf.pushBack(get_byte(1, cast(ushort) extn_val.length));
1093             
1094             buf ~= extn_val[];
1095         }
1096         
1097         const ushort extn_size = cast(ushort) (buf.length - 2);
1098         
1099         buf[0] = get_byte(0, extn_size);
1100         buf[1] = get_byte(1, extn_size);
1101         
1102         // avoid sending a completely empty extensions block
1103         if (buf.length == 2)
1104             return Vector!ubyte();
1105         
1106         return buf.move();
1107     }
1108 
1109     void deserialize(ref TLSDataReader reader)
1110     {
1111         if (reader.hasRemaining())
1112         {
1113             const ushort all_extn_size = reader.get_ushort();
1114             
1115             if (reader.remainingBytes() != all_extn_size)
1116                 throw new DecodingError("Bad extension size");
1117             
1118             while (reader.hasRemaining())
1119             {
1120                 const ushort extension_code = reader.get_ushort();
1121                 const ushort extension_size = reader.get_ushort();
1122 				//logDebug("Got extension: ", extension_code); 
1123                 Extension extn = makeExtension(reader, extension_code, extension_size);
1124                 
1125                 if (extn)
1126                     this.add(extn);
1127                 else // unknown/unhandled extension
1128                     reader.discardNext(extension_size);
1129             }
1130         }
1131     }
1132 
1133 	void reserve(size_t n) { m_extensions.extensions.reserve(n); }
1134 
1135     this(ref TLSDataReader reader) { deserialize(reader); }
1136 
1137 private:
1138 	HandshakeExtensions m_extensions;
1139 }
1140 
1141 private struct HandshakeExtensions {
1142 private:
1143 	Vector!HandshakeExtensionType types;
1144 	Vector!Extension extensions;
1145 
1146 	Extension get(HandshakeExtensionType type, Extension dflt) const {
1147 		size_t i;
1148 		foreach (HandshakeExtensionType t; types[]) {
1149 			if (t == type)
1150 				return cast() extensions[i];
1151 			i++;
1152 		}
1153 		return dflt;
1154 	}
1155 
1156 	void add(HandshakeExtensionType type, Extension ext)
1157 	{
1158 		types ~= type;
1159 		extensions ~= ext;
1160 	}
1161 
1162 	void remove(HandshakeExtensionType type) {
1163 		size_t i;
1164 		foreach (HandshakeExtensionType t; types[]) {
1165 			if (t == type) {
1166 				Vector!HandshakeExtensionType tmp_types;
1167 				tmp_types.reserve(types.length - 1);
1168 				tmp_types ~= types[0 .. i];
1169 				Vector!Extension tmp_extensions;
1170 				tmp_extensions.reserve(extensions.length - 1);
1171 				tmp_extensions ~= extensions[0 .. i];
1172 				if (i != types.length - 1) {
1173 					tmp_types ~= types[i+1 .. types.length];
1174 					tmp_extensions ~= extensions[i+1 .. extensions.length];
1175 				}
1176 				types[] = tmp_types[];
1177 				extensions[] = tmp_extensions[];
1178 				return;
1179 			}
1180 			i++;
1181 		}
1182 		logError("Could not find a TLS extension we wanted to remove...");
1183 	}
1184 
1185 }
1186 
1187 private:
1188 
1189 Extension makeExtension(ref TLSDataReader reader, ushort code, ushort size)
1190 {
1191     switch(code)
1192     {
1193         case TLSEXT_SERVER_NAME_INDICATION:
1194             return new ServerNameIndicator(reader, size);
1195             
1196 		case TLSEXT_EXTENDED_MASTER_SECRET:
1197 			return new ExtendedMasterSecret(reader, size);
1198 
1199         case TLSEXT_MAX_FRAGMENT_LENGTH:
1200             return new MaximumFragmentLength(reader, size);
1201             
1202         case TLSEXT_SRP_IDENTIFIER:
1203             return new SRPIdentifier(reader, size);
1204             
1205         case TLSEXT_USABLE_ELLIPTIC_CURVES:
1206             return new SupportedEllipticCurves(reader, size);
1207             
1208         case TLSEXT_SAFE_RENEGOTIATION:
1209             return new RenegotiationExtension(reader, size);
1210             
1211         case TLSEXT_SIGNATURE_ALGORITHMS:
1212             return new SignatureAlgorithms(reader, size);
1213             
1214         case TLSEXT_ALPN:
1215             return new ApplicationLayerProtocolNotification(reader, size);
1216             
1217         case TLSEXT_HEARTBEAT_SUPPORT:
1218             return new HeartbeatSupportIndicator(reader, size);
1219             
1220         case TLSEXT_SESSION_TICKET:
1221             return new SessionTicket(reader, size);
1222            
1223 		case TLSEXT_CHANNEL_ID:
1224 			return new ChannelIDSupport(reader, size);
1225 
1226         default:
1227             return null; // not known
1228     }
1229 }