1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
|
#pike __REAL_VERSION__
#pragma strict_types
#require constant(SSL.Cipher)
//! SSL.Connection keeps the state relevant for a single SSL connection.
//! This includes the @[Context] object (which doesn't change), various
//! buffers, the @[Session] object (reused or created as appropriate),
//! and pending read and write states being negotiated.
//!
//! Each connection will have two sets of read and write @[State]s: The
//! current read and write states used for encryption, and pending read
//! and write states to be taken into use when the current keyexchange
//! handshake is finished.
//!
//! This object is also responsible for managing incoming and outgoing
//! packets. Outgoing packets are stored in queue objects and sent in
//! priority order.
//!
//! @note
//! This class should never be created directly, instead one of the
//! classes that inherits it should be used (ie either
//! @[ClientConnection] or @[ServerConnection]) depending on whether
//! this is to be a client-side or server-side connection. These in
//! turn are typically created by @[File()->create()].
//!
//! @seealso
//! @[ClientConnection], @[ServerConnection], @[Context],
//! @[Session], @[File], @[State]
//#define SSL3_PROFILING
import .Constants;
#define State .State
#define Session .Session
#define Context .Context
#ifdef SSL3_DEBUG
#define SSL3_DEBUG_MSG(X ...) werror(X)
#else /*! SSL3_DEBUG */
#define SSL3_DEBUG_MSG(X ...)
#endif /* SSL3_DEBUG */
Session session;
Context context;
State pending_read_state;
State pending_write_state;
/* State variables */
int handshake_state; // Constant.STATE_*
int reuse;
constant CERT_none = 0;
constant CERT_requested = 1;
constant CERT_received = 2;
constant CERT_no_certificate = 3;
int certificate_state;
int expect_change_cipher; /* Reset to 0 if a change_cipher message is
* received */
// RFC 5746-related fields
int secure_renegotiation;
string(8bit) client_verify_data = "";
string(8bit) server_verify_data = "";
// 3.2: Initially of zero length for both the
// ClientHello and the ServerHello.
//! The active @[Cipher.KeyExchange] (if any).
.Cipher.KeyExchange ke;
ProtocolVersion version;
ProtocolVersion client_version; /* Used to check for version roll-back attacks. */
//! Random cookies, sent and received with the hello-messages.
string(8bit) client_random;
string(8bit) server_random;
#define Packet .Packet
#define Alert .Alert
int(0..1) tickets_enabled = 0;
// RFC 7301 (ALPN) 3.1:
// Unlike many other TLS extensions, this extension does not establish
// properties of the session, only of the connection. When session
// resumption or session tickets [RFC5077] are used, the previous
// contents of this extension are irrelevant, and only the values in the
// new handshake messages are considered.
//! Selected ALPN (RFC 7301) protocol (if any).
//!
//! @note
//! Note that this is a connection property, and needs to be renegotiated
//! on session resumption.
string(8bit) application_protocol;
Alert alert(int(1..2) level, int(8bit) description,
string|void message)
{
return context->alert_factory(this, level, description, version,
message);
}
string(8bit) get_signature_algorithms()
{
ADT.struct sign_algs = ADT.struct();
foreach(context->get_signature_algorithms(), [int hash, int sign])
{
sign_algs->put_uint(hash, 1);
sign_algs->put_uint(sign, 1);
}
return sign_algs->pop_data();
}
#ifdef SSL3_PROFILING
System.Timer timer = System.Timer();
void addRecord(int t,int s) {
Stdio.stdout.write("time: %.6f sender: %d type: %s\n", timer->get(), s,
fmt_constant(t, "HANDSHAKE"));
}
#endif
string(8bit) handshake_messages;
Packet handshake_packet(int(8bit) type, string data)
{
#ifdef SSL3_PROFILING
addRecord(type,1);
#endif
/* Perhaps one need to split large packages? */
Packet packet = Packet(version);
packet->content_type = PACKET_handshake;
packet->fragment = sprintf("%1c%3H", type, [string(8bit)]data);
handshake_messages += packet->fragment;
return packet;
}
Packet change_cipher_packet()
{
Packet packet = Packet(version);
packet->content_type = PACKET_change_cipher_spec;
packet->fragment = "\001";
expect_change_cipher++;
return packet;
}
string(8bit) hash_messages(string(8bit) sender)
{
if(version == PROTOCOL_SSL_3_0) {
return .Cipher.MACmd5(session->master_secret)->hash(handshake_messages + sender) +
.Cipher.MACsha(session->master_secret)->hash(handshake_messages + sender);
}
else if(version <= PROTOCOL_TLS_1_1) {
return session->cipher_spec->prf(session->master_secret, sender,
Crypto.MD5.hash(handshake_messages)+
Crypto.SHA1.hash(handshake_messages), 12);
} else if(version >= PROTOCOL_TLS_1_2) {
return session->cipher_spec->prf(session->master_secret, sender,
session->cipher_spec->hash->hash(handshake_messages), 12);
}
}
Packet certificate_packet(array(string(8bit)) certificates)
{
ADT.struct struct = ADT.struct();
struct->put_var_string_array(certificates, 3, 3);
return handshake_packet(HANDSHAKE_certificate, struct->pop_data());
}
Packet heartbeat_packet(string(8bit) s)
{
Packet packet = Packet(version);
packet->content_type = PACKET_heartbeat;
packet->fragment = s;
return packet;
}
protected Crypto.AES heartbeat_encode;
protected Crypto.AES heartbeat_decode;
Packet heartbleed_packet()
{
if (!heartbeat_encode) {
// NB: We encrypt the payload with a random AES key
// to reduce the amount of known plaintext in
// the heartbeat masseages. This is needed now
// that many cipher suites (such as GCM and CCM)
// use xor with a cipher stream, to reduce risk
// of revealing larger segments of the stream.
heartbeat_encode = Crypto.AES();
heartbeat_decode = Crypto.AES();
string(8bit) heartbeat_key = random_string(16);
heartbeat_encode->set_encrypt_key(heartbeat_key);
heartbeat_decode->set_decrypt_key(heartbeat_key);
}
// This packet probes for the Heartbleed vulnerability (CVE-2014-0160)
// by crafting a heartbeat packet with insufficient (0) padding.
//
// If we get a response, the peer doesn't validate the message sizes
// properly, and probably suffers from the Heartbleed vulnerability.
//
// Note that we don't use negative padding (as per the actual attack),
// to avoid actually stealing information from the peer.
//
// Note that we detect the packet on return by it having all zeros
// in the second field.
ADT.struct hb_msg = ADT.struct();
hb_msg->put_uint(HEARTBEAT_MESSAGE_request, 1);
hb_msg->put_uint(16, 2);
int now = gethrtime();
hb_msg->put_fix_string(heartbeat_encode->crypt(sprintf("%8c%8c", now, 0)));
// No padding.
return heartbeat_packet(hb_msg->pop_data());
}
// verify that a certificate chain is acceptable
//
int verify_certificate_chain(array(string) certs)
{
// do we need to verify the certificate chain?
if(!context->verify_certificates)
return 1;
// if we're not requiring the certificate, and we don't provide one,
// that should be okay.
if((context->auth_level < AUTHLEVEL_require) && !sizeof(certs))
return 1;
// a lack of certificates when we reqiure and must verify the
// certificates is probably a failure.
if(!certs || !sizeof(certs))
return 0;
// See if the issuer of the certificate is acceptable. This means
// the issuer of the certificate must be one of the authorities.
if(sizeof(context->authorities_cache))
{
string r=Standards.X509.decode_certificate(certs[-1])->issuer
->get_der();
int issuer_known = 0;
foreach(context->authorities_cache, string c)
{
if(r == c) // we have a trusted issuer
{
issuer_known = 1;
break;
}
}
if(issuer_known==0)
{
return 0;
}
}
// ok, so we have a certificate chain whose client certificate is
// issued by an authority known to us.
// next we must verify the chain to see if the chain is unbroken
mapping result =
Standards.X509.verify_certificate_chain(certs,
context->trusted_issuers_cache,
context->require_trust,
([ "verifier_algorithms"
: context->verifier_algorithms]));
// This data isn't actually used internally.
session->cert_data = result;
if(result->verified && session->server_name &&
sizeof([array](result->certificates || ({})))) {
array(Standards.X509.TBSCertificate) certs =
[array(Standards.X509.TBSCertificate)](result->certificates);
Standards.X509.TBSCertificate cert = certs[-1];
array(string) globs = Standards.PKCS.Certificate.
decode_distinguished_name(cert->subject)->commonName - ({ 0 });
if (cert->ext_subjectAltName_dNSName) {
globs += cert->ext_subjectAltName_dNSName;
}
array(string) split_server_name = lower_case(session->server_name) / ".";
result->verified = 0;
OUTER: foreach (map(globs, lower_case);; string the_glob) {
array(string) split_glob = the_glob / ".";
if (sizeof(split_glob) != sizeof(split_server_name))
continue;
foreach (split_glob; int i; string the_glob) {
if (!glob(the_glob, split_server_name[i]))
continue OUTER;
}
result->verified = 1;
break;
}
}
return [int(0..1)](result->verified);
}
//! Do handshake processing. Type is one of HANDSHAKE_*, data is the
//! contents of the packet, and raw is the raw packet received (needed
//! for supporting SSLv2 hello messages).
//!
//! This function returns 0 if handshake is in progress, 1 if handshake
//! is finished, and -1 if a fatal error occurred. It uses the
//! send_packet() function to transmit packets.
int(-1..1) handle_handshake(int type, string(8bit) data, string(8bit) raw);
//! Initialize the connection state.
//!
//! @param ctx
//! The context for the connection.
protected void create(Context ctx)
{
current_read_state = State(this);
current_write_state = State(this);
if ((ctx->max_version < PROTOCOL_SSL_3_0) ||
(ctx->max_version > PROTOCOL_TLS_MAX)) {
ctx->max_version = PROTOCOL_TLS_MAX;
}
if (ctx->min_version < PROTOCOL_SSL_3_0) {
ctx->min_version = PROTOCOL_SSL_3_0;
} else if (ctx->min_version > ctx->max_version) {
ctx->min_version = ctx->max_version;
}
version = ctx->max_version;
context = ctx;
}
//
// --- Old connection.pike below
//
State current_read_state;
State current_write_state;
string(8bit) left_over;
Packet packet;
//! Number of application data bytes sent by us.
int sent;
//! Bitfield with the current connection state.
ConnectionState state = CONNECTION_handshaking;
function(object,int|object,string:void) alert_callback;
constant PRI_alert = 1;
constant PRI_urgent = 2;
constant PRI_application = 3;
protected ADT.Queue alert_q = ADT.Queue();
protected ADT.Queue urgent_q = ADT.Queue();
protected ADT.Queue application_q = ADT.Queue();
//! Returns a string describing the current connection state.
string describe_state()
{
if (!state) return "ready";
array(string) res = ({});
if (state & CONNECTION_handshaking) {
res += ({ "handshaking(" + fmt_constant(handshake_state, "STATE") + ")" });
}
if (state & CONNECTION_local_failing) {
if (state & CONNECTION_local_fatal) {
res += ({ "local_fatal" });
} else {
res += ({ "local_failing" });
}
}
if (state & CONNECTION_local_closing) {
if (state & CONNECTION_local_closed) {
res += ({ "local_closed" });
} else {
res += ({ "local_closing" });
}
}
if (state & CONNECTION_peer_fatal) res += ({ "peer_fatal" });
if (state & CONNECTION_peer_closed) res += ({ "peer_closed" });
return res * "|";
}
protected string _sprintf(int t)
{
if (t == 'O') return sprintf("SSL.Connection(%s)", describe_state());
}
//! Called with alert object, sequence number of bad packet,
//! and raw data as arguments, if a bad packet is received.
//!
//! Can be used to support a fallback redirect https->http.
void set_alert_callback(function(object,int|object,string:void) callback)
{
alert_callback = callback;
}
//! Low-level receive handler. Returns a packet, an alert, or zero if
//! more data is needed to get a complete packet.
protected Packet recv_packet(string(8bit) data)
{
string(8bit)|Packet res;
// SSL3_DEBUG_MSG("SSL.Connection->recv_packet(%O)\n", data);
if (left_over || !packet)
{
packet = Packet(version, 2048);
res = packet->recv( (left_over || "") + data);
}
else
res = packet->recv(data);
if (stringp(res))
{ /* Finished a packet */
left_over = [string]res;
if (current_read_state) {
SSL3_DEBUG_MSG("SSL.Connection->recv_packet(): version=0x%x\n",
version);
return current_read_state->decrypt_packet(packet);
} else {
SSL3_DEBUG_MSG("SSL.Connection->recv_packet(): current_read_state is zero!\n");
return 0;
}
}
else /* Partial packet read, or error */
left_over = 0;
return [object]res;
}
//! Queues a packet for write. Handshake and and change cipher
//! must use the same priority, so must application data and
//! close_notifies.
void send_packet(Packet packet, int|void priority)
{
if (state & CONNECTION_local_closing) {
SSL3_DEBUG_MSG("SSL.Connection->send_packet: ignoring packet after close\n");
return;
}
if (packet->content_type == PACKET_alert) {
if (packet->level == ALERT_fatal) {
state = [int(0..0)|ConnectionState](state | CONNECTION_local_failing);
} else if (packet->description == ALERT_close_notify) {
state = [int(0..0)|ConnectionState](state | CONNECTION_local_closing);
}
}
if (!priority)
priority = ([ PACKET_alert : PRI_alert,
PACKET_change_cipher_spec : PRI_urgent,
PACKET_handshake : PRI_urgent,
PACKET_heartbeat : PRI_urgent,
PACKET_application_data : PRI_application ])[packet->content_type];
if ((packet->content_type == PACKET_handshake) &&
(priority == PRI_application)) {
// Assume the packet is either hello_request or client_hello,
// and that we want to renegotiate.
expect_change_cipher = 0;
certificate_state = 0;
state = [int(0..0)|ConnectionState](state | CONNECTION_handshaking);
handshake_state = STATE_wait_for_hello;
}
SSL3_DEBUG_MSG("SSL.Connection->send_packet: type %d, pri %d, %O\n",
packet->content_type, priority, packet->fragment[..5]);
switch (priority)
{
default:
error( "Internal error\n" );
case PRI_alert:
alert_q->put(packet);
break;
case PRI_urgent:
urgent_q->put(packet);
break;
case PRI_application:
application_q->put(packet);
break;
}
}
//! Returns the number of packets queued for writing.
//!
//! @returns
//! Returns the number of times @[to_write()] can be called before
//! it stops returning non-empty strings.
int query_write_queue_size()
{
return sizeof(alert_q) + sizeof(urgent_q) + sizeof(application_q);
}
//! Extracts data from the packet queues. Returns a string of data
//! to be written, "" if there are no pending packets, 1 of the
//! connection is being closed politely, and -1 if the connection
//! died unexpectedly.
//!
//! This function is intended to be called from an i/o write callback.
//!
//! @seealso
//! @[query_write_queue_size()], @[send_streaming_data()].
string|int to_write()
{
if (state & CONNECTION_local_fatal)
return -1;
Packet packet = [object(Packet)](alert_q->get() || urgent_q->get() ||
application_q->get());
if (!packet) {
return (state & CONNECTION_local_closing) ? 1 : "";
}
SSL3_DEBUG_MSG("SSL.Connection: writing packet of type %d, %O\n",
packet->content_type, packet->fragment[..6]);
if (packet->content_type == PACKET_alert)
{
if (packet->level == ALERT_fatal) {
state = [int(0..0)|ConnectionState](state | CONNECTION_local_fatal);
// SSL3 5.4:
// Alert messages with a level of fatal result in the immediate
// termination of the connection. In this case, other
// connections corresponding to the session may continue, but
// the session identifier must be invalidated, preventing the
// failed session from being used to establish new connections.
if (session) {
context->purge_session(session);
}
} else if (packet->description == ALERT_close_notify) {
state = [int(0..0)|ConnectionState](state | CONNECTION_local_closed);
}
}
string res = current_write_state->encrypt_packet(packet)->send();
if (packet->content_type == PACKET_change_cipher_spec)
current_write_state = pending_write_state;
return res;
}
//! Initiate close.
void send_close()
{
send_packet(alert(ALERT_warning, ALERT_close_notify,
"Closing connection.\n"), PRI_application);
}
//! Renegotiate the connection.
void send_renegotiate();
//! Send an application data packet. If the data block is too large
//! then as much as possible of the beginning of it is sent. The size
//! of the sent data is returned.
int send_streaming_data (string(8bit) data)
{
if (!sizeof(data)) return 0;
Packet packet = Packet(version);
packet->content_type = PACKET_application_data;
int max_packet_size = session->max_packet_size;
int size;
if ((!sent) && (version < PROTOCOL_TLS_1_1) &&
(session->cipher_spec->cipher_type ==
CIPHER_block)) {
// Workaround for the BEAST attack.
// This method is known as the 1/(n-1) split:
// Send just one byte of payload in the first packet
// to improve the initialization vectors in TLS 1.0.
size = sizeof((packet->fragment = data[..0]));
if (sizeof(data) > 1) {
// If we have more data, take the opportunity to queue some of it too.
send_packet(packet);
packet = Packet(version);
packet->content_type = PACKET_application_data;
size += sizeof((packet->fragment = data[1..max_packet_size-1]));
}
} else {
size = sizeof ((packet->fragment = data[..max_packet_size-1]));
}
send_packet (packet);
sent += size;
return size;
}
//! Handle an alert received from the peer.
//!
//! @param level
//! Alert level; either @[ALERT_warning] or @[ALERT_fatal].
//!
//! @param description
//! Alert description code; one of
//! @expr{indices(SSL.Constants.ALERT_descriptions)@}.
//!
//! @returns
//! @mixed
//! @type int(-1..-1)
//! Returns @expr{-1@} if a fatal error occurred and processing should stop.
//! @type int(0..0)
//! Returns @expr{0@} if processing can continue.
//! @type int(1..1)
//! Returns @expr{1@} if connection should close.
//! @endmixed
int(-1..1) handle_alert(int level, int description)
{
if (! (ALERT_levels[level] && ALERT_descriptions[description]))
{
send_packet(alert(ALERT_fatal, ALERT_unexpected_message,
"invalid alert\n"));
return -1;
}
if (level == ALERT_fatal)
{
SSL3_DEBUG_MSG("SSL.Connection: Fatal alert %O\n",
ALERT_descriptions[description]);
state = [int(0..0)|ConnectionState](state | CONNECTION_peer_fatal |
CONNECTION_peer_closed);
// SSL3 5.4:
// Alert messages with a level of fatal result in the immediate
// termination of the connection. In this case, other
// connections corresponding to the session may continue, but
// the session identifier must be invalidated, preventing the
// failed session from being used to establish new connections.
if (session) {
context->purge_session(session);
}
return -1;
}
if (description == ALERT_close_notify)
{
SSL3_DEBUG_MSG("SSL.Connection: %O\n", ALERT_descriptions[description]);
state = [int(0..0)|ConnectionState](state | CONNECTION_peer_closed);
return 1;
}
if (description == ALERT_no_certificate)
{
SSL3_DEBUG_MSG("SSL.Connection: %O\n", ALERT_descriptions[description]);
if ((certificate_state == CERT_requested) && (context->auth_level == AUTHLEVEL_ask))
{
certificate_state = CERT_no_certificate;
return 0;
} else {
send_packet(alert(ALERT_fatal,
((certificate_state == CERT_requested)
? ALERT_handshake_failure
: ALERT_unexpected_message),
"Certificate required.\n"));
return -1;
}
}
#ifdef SSL3_DEBUG
else
werror("SSL.Connection: Received warning alert %O\n",
ALERT_descriptions[description]);
#endif
return 0;
}
int handle_change_cipher(int c)
{
if (!expect_change_cipher || (c != 1))
{
send_packet(alert(ALERT_fatal, ALERT_unexpected_message,
"Unexpected change cipher!\n"));
return -1;
}
else
{
current_read_state = pending_read_state;
expect_change_cipher--;
return 0;
}
}
void send_heartbeat()
{
if ((state != CONNECTION_ready) ||
(session->heartbeat_mode != HEARTBEAT_MODE_peer_allowed_to_send)) {
// We're not allowed to send heartbeats.
return;
}
ADT.struct hb_msg = ADT.struct();
hb_msg->put_uint(HEARTBEAT_MESSAGE_request, 1);
hb_msg->put_uint(16, 2);
int now = gethrtime();
hb_msg->put_fix_string(heartbeat_encode->crypt(sprintf("%8c%8c", now, now)));
// We pad to an even 64 bytes.
hb_msg->put_fix_string(random_string(64 - sizeof(hb_msg)));
send_packet(heartbeat_packet(hb_msg->pop_data()));
}
void handle_heartbeat(string(8bit) s)
{
if (sizeof(s) < 19) return; // Minimum size for valid heartbeats.
ADT.struct hb_msg = ADT.struct(s);
int hb_type = hb_msg->get_uint(1);
int hb_len = hb_msg->get_uint(2);
SSL3_DEBUG_MSG("SSL.Connection: Heartbeat %s (%d bytes)",
fmt_constant(hb_type, "HEARTBEAT_MESSAGE"), hb_len);
string(8bit) payload;
int pad_len = 16;
// RFC 6520 4:
// If the payload_length of a received HeartbeatMessage is too
// large, the received HeartbeatMessage MUST be discarded silently.
if ((hb_len < 0) || ((hb_len + 16) > sizeof(hb_msg))) {
#ifdef SSL3_SIMULATE_HEARTBLEED
payload = hb_msg->get_rest();
if (sizeof(payload) < hb_len) {
payload = payload + random_string(hb_len - sizeof(payload));
} else {
payload = payload[..hb_len-1];
}
#else
return;
#endif
} else {
payload = hb_msg->get_fix_string(hb_len);
pad_len = sizeof(hb_msg);
}
switch(hb_type) {
case HEARTBEAT_MESSAGE_request:
// RFC 6520 4:
// When a HeartbeatRequest message is received and sending a
// HeartbeatResponse is not prohibited as described elsewhere in
// this document, the receiver MUST send a corresponding
// HeartbeatResponse message carrying an exact copy of the payload
// of the received HeartbeatRequest.
hb_msg = ADT.struct();
hb_msg->put_uint(HEARTBEAT_MESSAGE_response, 1);
hb_msg->put_uint(hb_len, 2);
hb_msg->put_fix_string(payload);
hb_msg->put_fix_string(random_string(pad_len));
send_packet(heartbeat_packet(hb_msg->pop_data()));
break;
case HEARTBEAT_MESSAGE_response:
// RFC 6520 4:
// If a received HeartbeatResponse message does not contain the
// expected payload, the message MUST be discarded silently.
if ((sizeof(payload) == 16) && heartbeat_decode) {
hb_msg = ADT.struct(heartbeat_decode->crypt(payload));
int a = hb_msg->get_uint(8);
int b = hb_msg->get_uint(8);
if (a != b) {
if (!b) {
// Heartbleed probe response.
send_packet(alert(ALERT_fatal, ALERT_insufficient_security,
"Peer suffers from a bleeding heart.\n"));
}
break;
}
#ifdef SSL3_DEBUG
int delta = gethrtime() - a;
SSL3_DEBUG_MSG("SSL.Connection: Heartbeat roundtrip: %dus\n", delta);
#endif
}
break;
default:
break;
}
}
string(8bit) alert_buffer = "";
string(8bit) handshake_buffer = "";
//! Main receive handler.
//!
//! @param data
//! String of data received from the peer.
//!
//! @returns
//! Returns one of:
//! @mixed
//! @type string(zero)
//! Returns an empty string if there's neither application data
//! nor errors (eg during the initial handshake).
//! @type string(8bit)
//! Returns a string of received application data.
//! @type int(1..1)
//! Returns @expr{1@} if the peer has closed the connection.
//! @type int(-1..-1)
//! Returns @expr{-1@} if an error has occurred.
//!
//! These are the main cases of errors:
//! @ul
//! @item
//! There was a low-level protocol communications failure
//! (the data didn't look like an SSL packet), in which case
//! the alert_callback will be called with the raw packet data.
//! This can eg be used to detect HTTP clients connecting to
//! an HTTPS server and similar.
//! @item
//! The peer has sent an @[Alert] packet, and @[handle_alert()]
//! for it has returned -1.
//! @item
//! The peer has sent an unsupported/illegal sequence of
//! packets, in which case a suitable @[Alert] will have been
//! generated and queued for sending to the peer.
//! @endul
//! @endmixed
//!
//! This function is intended to be called from an i/o read callback.
string(8bit)|int got_data(string(8bit) data)
{
if (state & (CONNECTION_peer_closed|CONNECTION_local_fatal)) {
// The peer has closed the connection, or we sent a fatal.
return 1;
}
// If closing we continue to try to read a remote close message.
// That enables the caller to check for a clean close, and
// to get the leftovers after the SSL connection.
/* If alert_callback is called, this data is passed as an argument */
string(8bit) alert_context = (left_over || "") + data;
string(8bit) res = "";
Packet packet;
while (packet = recv_packet(data))
{
data = "";
if (packet->is_alert)
{ /* Reply alert */
SSL3_DEBUG_MSG("SSL.Connection: Bad received packet\n");
if (alert_callback)
alert_callback(packet, current_read_state->seq_num, alert_context);
if (this && packet)
send_packet(packet);
if ((!packet) || (!this) || (packet->level == ALERT_fatal))
return -1;
if (alert_callback)
break;
}
else
{
SSL3_DEBUG_MSG("SSL.Connection: received packet of type %d\n",
packet->content_type);
switch (packet->content_type)
{
case PACKET_alert:
{
SSL3_DEBUG_MSG("SSL.Connection: ALERT\n");
if( !sizeof(packet->fragment) )
{
send_packet(alert(ALERT_fatal, ALERT_unexpected_message,
"Zero length Alert fragments not allowed.\n"));
return -1;
}
int i;
int err = 0;
alert_buffer += packet->fragment;
for (i = 0;
!err && ((sizeof(alert_buffer) - i) >= 2);
i+= 2)
err = handle_alert(alert_buffer[i], alert_buffer[i+1]);
alert_buffer = alert_buffer[i..];
if (err)
if (err > 0 && sizeof (res))
// If we get a close then we return the data we got so far.
return res;
else
return err;
break;
}
case PACKET_change_cipher_spec:
{
SSL3_DEBUG_MSG("SSL.Connection: CHANGE_CIPHER_SPEC\n");
if( !sizeof(packet->fragment) )
{
send_packet(alert(ALERT_fatal, ALERT_unexpected_message,
"Zero length ChangeCipherSpec fragments not allowed.\n"));
return -1;
}
foreach(packet->fragment;; int c)
{
int err = handle_change_cipher(c);
SSL3_DEBUG_MSG("tried change_cipher: %d\n", err);
if (err)
return err;
}
break;
}
case PACKET_handshake:
{
SSL3_DEBUG_MSG("SSL.Connection: HANDSHAKE\n");
if( !sizeof(packet->fragment) )
{
send_packet(alert(ALERT_fatal, ALERT_unexpected_message,
"Zero length Handshake fragments not allowed.\n"));
return -1;
}
if (!(state & CONNECTION_handshaking) &&
!secure_renegotiation) {
// Don't allow renegotiation in unsecure mode, to address
// http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2009-3555.
// For details see: http://www.g-sec.lu/practicaltls.pdf and
// RFC 5746.
send_packet(alert(ALERT_warning, ALERT_no_renegotiation,
"Renegotiation not supported in unsecure mode.\n"));
return -1;
}
if (expect_change_cipher)
{
/* No change_cipher message was received */
// FIXME: There's a bug somewhere since expect_change_cipher often
// remains set after the handshake is completed. The effect is that
// renegotiation doesn't work all the time.
//
// A side effect is that we are partly invulnerable to the
// renegotiation vulnerability mentioned above. It is however not
// safe to assume that, since there might be routes past this,
// maybe through the use of a version 2 hello message below.
send_packet(alert(ALERT_fatal, ALERT_unexpected_message,
"Expected change cipher.\n"));
return -1;
}
int err, len;
handshake_buffer += packet->fragment;
while (sizeof(handshake_buffer) >= 4)
{
sscanf(handshake_buffer, "%*c%3c", len);
if (sizeof(handshake_buffer) < (len + 4))
break;
mixed exception = catch {
err = handle_handshake(handshake_buffer[0],
handshake_buffer[4..len + 3],
handshake_buffer[.. len + 3]);
};
if( exception )
{
if( objectp(exception) && ([object]exception)->ADT_struct )
{
Error.Generic e = [object(Error.Generic)]exception;
send_packet(alert(ALERT_fatal, ALERT_decode_error,
e->message()));
return -1;
}
throw(exception);
}
handshake_buffer = handshake_buffer[len + 4..];
if (err < 0)
return err;
if (err > 0) {
state &= ~CONNECTION_handshaking;
if( expect_change_cipher && sizeof(handshake_buffer) )
{
send_packet(alert(ALERT_fatal, ALERT_unexpected_message,
"Extraneous handshake packets.\n"));
return -1;
}
if( !secure_renegotiation && sizeof(handshake_buffer) )
{
send_packet(alert(ALERT_fatal, ALERT_no_renegotiation,
"Renegotiation not supported in unsecure "
"mode.\n"));
return -1;
}
}
}
break;
}
case PACKET_application_data:
SSL3_DEBUG_MSG("SSL.Connection: APPLICATION_DATA\n");
if (state & CONNECTION_handshaking)
{
send_packet(alert(ALERT_fatal, ALERT_unexpected_message,
"Handshake not finished yet!\n"));
return -1;
}
res += packet->fragment;
break;
case PACKET_heartbeat:
{
// RFC 6520.
SSL3_DEBUG_MSG("SSL.Connection: Heartbeat.\n");
if (state != CONNECTION_ready) {
// RFC 6520 3:
// The receiving peer SHOULD discard the message silently,
// if it arrives during the handshake.
break;
}
if (!session->heartbeat_mode) {
// RFC 6520 2:
// If an endpoint that has indicated peer_not_allowed_to_send
// receives a HeartbeatRequest message, the endpoint SHOULD
// drop the message silently and MAY send an unexpected_message
// Alert message.
send_packet(alert(ALERT_warning, ALERT_unexpected_message,
"Heart beat mode not enabled.\n"));
break;
}
mixed exception = catch {
handle_heartbeat(packet->fragment);
};
if( exception )
{
if( objectp(exception) && ([object]exception)->ADT_struct )
{
Error.Generic e = [object(Error.Generic)]exception;
send_packet(alert(ALERT_fatal, ALERT_decode_error,
e->message()));
return -1;
}
throw(exception);
}
}
break;
default:
if (state & CONNECTION_handshaking)
{
send_packet(alert(ALERT_fatal, ALERT_unexpected_message,
"Unexpected message during handshake!\n"));
return -1;
}
// RFC 4346 6:
// If a TLS implementation receives a record type it does not
// understand, it SHOULD just ignore it.
SSL3_DEBUG_MSG("SSL.Connection: Ignoring packet of type %s\n",
fmt_constant(packet->content_type, "PACKET"));
break;
}
}
}
if (sizeof(res)) return res;
if (state & CONNECTION_peer_closed) return 1;
return "";
}
|