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 }