pike.git / lib / modules / SSL.pmod / Connection.pike

version» Context lines:

pike.git/lib/modules/SSL.pmod/Connection.pike:43:   Session session;   Context context;      State pending_read_state;   State pending_write_state;      /* State variables */      int handshake_state; // Constant.STATE_*    - int handshake_finished = 0; -  +    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
pike.git/lib/modules/SSL.pmod/Connection.pike:306:   //   // --- 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; - int dying; - int closing; // Bitfield: 1 if a close is sent, 2 of one is received. +     -  + //! 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" }); +  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 * "|"; + } +    //! 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
pike.git/lib/modules/SSL.pmod/Connection.pike:367:    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 (closing & 1) { +  if (state & CONNECTION_local_closing) {    SSL3_DEBUG_MSG("SSL.Connection->send_packet: ignoring packet after close\n");    return;    }    -  if (packet->content_type == PACKET_alert && -  packet->description == ALERT_close_notify) -  closing |= 1; +  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];    SSL3_DEBUG_MSG("SSL.Connection->send_packet: type %d, pri %d, %O\n",    packet->content_type, priority, packet->fragment[..5]);    switch (priority)
pike.git/lib/modules/SSL.pmod/Connection.pike:409:   }      //! 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.   string|int to_write()   { -  if (dying) +  if (state & CONNECTION_local_fatal)    return -1;       Packet packet = [object(Packet)](alert_q->get() || urgent_q->get() ||    application_q->get());    if (!packet) { -  return closing ? 1 : ""; +  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) { -  dying = 1; +  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, version)->send();    if (packet->content_type == PACKET_change_cipher_spec)    current_write_state = pending_write_state;    return res;   }      //! Initiate close.   void send_close()
pike.git/lib/modules/SSL.pmod/Connection.pike:497:    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);    return -1;    }    if (description == ALERT_close_notify)    {    SSL3_DEBUG_MSG("SSL.Connection: %O\n", ALERT_descriptions[description]); -  closing |= 2; +  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;
pike.git/lib/modules/SSL.pmod/Connection.pike:549:    else    {    current_read_state = pending_read_state;    expect_change_cipher = 0;    return 0;    }   }      void send_heartbeat()   { -  if (!handshake_finished || +  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)));
pike.git/lib/modules/SSL.pmod/Connection.pike:681:   //! @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 (closing & 2) { +  if (state & CONNECTION_peer_closed) {    // The peer has closed the connection.    return 1;    } -  // If closing == 1 we continue to try to read a remote close -  // message. That enables the caller to check for a clean close, and +  // 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 = "";
pike.git/lib/modules/SSL.pmod/Connection.pike:755:    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 (handshake_finished && !secure_renegotiation) { +  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)    {
pike.git/lib/modules/SSL.pmod/Connection.pike:807:    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) { -  handshake_finished = 1; +  state &= ~CONNECTION_handshaking;    }    }    break;    }    case PACKET_application_data:    SSL3_DEBUG_MSG("SSL.Connection: APPLICATION_DATA\n");    -  if (!handshake_finished) +  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 (!handshake_finished) { +  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
pike.git/lib/modules/SSL.pmod/Connection.pike:862:    send_packet(alert(ALERT_fatal, ALERT_decode_error,    e->message()));    return -1;    }    throw(exception);    }       }    break;    default: -  if (!handshake_finished) +  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 (closing & 2) return 1; +  if (state & CONNECTION_peer_closed) return 1;    return "";   }