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

version» Context lines:

pike.git/lib/modules/SSL.pmod/Connection.pike:1:   #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), + //! 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 + //! 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. Incomiong packets are stored in queue objects and parsed + //! in priority order. + //!   //! @note - //! This class should never not be created directly, instead - //! one of the classes that inherits it should be used (ie either + //! 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 @[sslfile()->create()]. + //! this is to be a client-side or server-side connection. These in + //! turn are typically created by @[sslfile()->create()].   //!   //! @seealso - //! @[ClientConnection], @[ServerConnection], @[context], - //! @[session], @[sslfile], @[state] + //! @[ClientConnection], @[ServerConnection], @[Context], + //! @[Session], @[sslfile], @[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)
pike.git/lib/modules/SSL.pmod/Connection.pike:150:    }   }      Packet certificate_packet(array(string(8bit)) certificates)   {    ADT.struct struct = ADT.struct();    int len = 0;       if(certificates && sizeof(certificates))    len = `+( @ Array.map(certificates, sizeof)); -  // SSL3_DEBUG_MSG("SSL.handshake: certificate_message size %d\n", len); +  // SSL3_DEBUG_MSG("SSL.Connection: certificate_message size %d\n", len);    struct->put_uint(len + 3 * sizeof(certificates), 3);    foreach(certificates, string(8bit) cert)    struct->put_var_string(cert, 3);       return handshake_packet(HANDSHAKE_certificate, struct->pop_data());   }      Packet heartbeat_packet(string(8bit) s)   {    Packet packet = Packet();
pike.git/lib/modules/SSL.pmod/Connection.pike:304:       version = ctx->max_version;    context = ctx;   }         //   // --- Old connection.pike below   //    - //! SSL packet layer. - //! - //! @[SSL.connection] inherits @[SSL.handshake], and in addition to the state in - //! the handshake super class, it contains the current read and write - //! states, packet queues. This object is responsible for receiving and - //! sending packets, processing handshake packets, and providing clear - //! text packets for some application. +     - // SSL/TLS Protocol Specification documents: - // - // SSL 2 http://wp.netscape.com/eng/security/SSL_2.html - // SSL 3.0 http://wp.netscape.com/eng/ssl3/draft302.txt - // (aka draft-freier-ssl-version3-02.txt). - // TLS 1.0 (SSL 3.1) RFC 2246 "The TLS Protocol Version 1.0". - // TLS 1.1 (SSL 3.2) draft-ietf-tls-rfc2246-bis - // Renegotiation RFC 5746 "Renegotiation Indication Extension". -  +    State current_read_state;   State current_write_state;   string left_over;   Packet packet;      int sent;   int dying;   int closing; // Bitfield: 1 if a close is sent, 2 of one is received.      function(object,int|object,string:void) alert_callback;
pike.git/lib/modules/SSL.pmod/Connection.pike:355:   {    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 data)   {    string|Packet res;    -  // SSL3_DEBUG_MSG("SSL.connection->recv_packet(%O)\n", data); +  // SSL3_DEBUG_MSG("SSL.Connection->recv_packet(%O)\n", data);    if (left_over || !packet)    {    packet = Packet(2048);    res = packet->recv( (left_over || "") + data, version);    }    else    res = packet->recv(data, version);       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", +  SSL3_DEBUG_MSG("SSL.Connection->recv_packet(): version=0x%x\n",    version);    return current_read_state->decrypt_packet(packet, version);    } else { -  SSL3_DEBUG_MSG("SSL.connection->recv_packet(): current_read_state is zero!\n"); +  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 (closing & 1) { -  SSL3_DEBUG_MSG("SSL.connection->send_packet: ignoring packet after close\n"); +  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 (!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", +  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);
pike.git/lib/modules/SSL.pmod/Connection.pike:438:   {    if (dying)    return -1;       Packet packet = [object(Packet)](alert_q->get() || urgent_q->get() ||    application_q->get());    if (!packet) {    return closing ? 1 : "";    }    -  SSL3_DEBUG_MSG("SSL.connection: writing packet of type %d, %O\n", +  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;    // 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
pike.git/lib/modules/SSL.pmod/Connection.pike:515:    int level = s[0];    int description = s[1];    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 %d\n", description); +  SSL3_DEBUG_MSG("SSL.Connection: Fatal alert %d\n", description);    return -1;    }    if (description == ALERT_close_notify)    { -  SSL3_DEBUG_MSG("SSL.connection: Close notify alert %d\n", description); +  SSL3_DEBUG_MSG("SSL.Connection: Close notify alert %d\n", description);    closing |= 2;    return 1;    }    if (description == ALERT_no_certificate)    { -  SSL3_DEBUG_MSG("SSL.connection: No certificate alert %d\n", description); +  SSL3_DEBUG_MSG("SSL.Connection: No certificate alert %d\n", 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 %d\n", description); +  werror("SSL.Connection: Received warning alert %d\n", description);   #endif    return 0;   }      int handle_change_cipher(int c)   {    if (!expect_change_cipher || (c != 1))    { -  SSL3_DEBUG_MSG("SSL.connection: handle_change_cipher: Unexcepted message!"); +  SSL3_DEBUG_MSG("SSL.Connection: handle_change_cipher: Unexcepted message!");    send_packet(alert(ALERT_fatal, ALERT_unexpected_message,    "Unexpected change cipher!\n"));    return -1;    }    else    {    current_read_state = pending_read_state;    expect_change_cipher = 0;    return 0;    }
pike.git/lib/modules/SSL.pmod/Connection.pike:590:    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)", +  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
pike.git/lib/modules/SSL.pmod/Connection.pike:648:    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); +  SSL3_DEBUG_MSG("SSL.Connection: Heartbeat roundtrip: %dus\n", delta);   #endif    }    break;    default:    break;    }   }      string(8bit) alert_buffer = "";   string(8bit) handshake_buffer = "";
pike.git/lib/modules/SSL.pmod/Connection.pike:688:    string alert_context = (left_over || "") + s;       string res = "";    Packet packet;    while (packet = recv_packet([string]s))    {    s = "";       if (packet->is_alert)    { /* Reply alert */ -  SSL3_DEBUG_MSG("SSL.connection: Bad received packet\n"); +  SSL3_DEBUG_MSG("SSL.Connection: Bad received packet\n");    send_packet(packet);    if (alert_callback)    alert_callback(packet, current_read_state->seq_num, alert_context);    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", +  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"); +  SSL3_DEBUG_MSG("SSL.Connection: ALERT\n");       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..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"); +  SSL3_DEBUG_MSG("SSL.Connection: CHANGE_CIPHER_SPEC\n");       int i;    int err;    for (i = 0; (i < sizeof(packet->fragment)); i++)    {    err = handle_change_cipher(packet->fragment[i]);    SSL3_DEBUG_MSG("tried change_cipher: %d\n", err);    if (err)    return err;    }    break;    }    case PACKET_handshake:    { -  SSL3_DEBUG_MSG("SSL.connection: HANDSHAKE\n"); +  SSL3_DEBUG_MSG("SSL.Connection: HANDSHAKE\n");       if (handshake_finished && !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;    }
pike.git/lib/modules/SSL.pmod/Connection.pike:801:    handshake_buffer = handshake_buffer[len + 4..];    if (err < 0)    return err;    if (err > 0) {    handshake_finished = 1;    }    }    break;    }    case PACKET_application_data: -  SSL3_DEBUG_MSG("SSL.connection: APPLICATION_DATA\n"); +  SSL3_DEBUG_MSG("SSL.Connection: APPLICATION_DATA\n");       if (!handshake_finished)    {    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"); +  SSL3_DEBUG_MSG("SSL.Connection: Heartbeat.\n");    if (!handshake_finished) {    // 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
pike.git/lib/modules/SSL.pmod/Connection.pike:859:    default:    if (!handshake_finished)    {    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", +  SSL3_DEBUG_MSG("SSL.Connection: Ignoring packet of type %s\n",    fmt_constant(packet->content_type, "PACKET"));    break;    }    }    }    return closing & 2 ? 1 : res;   }