#pike __REAL_VERSION__ |
#pragma strict_types |
#require constant(SSL.Cipher) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|
int handshake_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; |
|
|
|
int secure_renegotiation; |
string(8bit) client_verify_data = ""; |
string(8bit) server_verify_data = ""; |
|
|
|
|
.Cipher.KeyExchange ke; |
|
ProtocolVersion version; |
ProtocolVersion client_version; |
|
|
string(8bit) client_random; |
string(8bit) server_random; |
|
#define Packet .Packet |
#define Alert .Alert |
|
int(0..1) tickets_enabled = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
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) { |
|
|
|
|
|
|
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); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
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))); |
|
return heartbeat_packet(hb_msg->pop_data()); |
} |
|
|
|
int verify_certificate_chain(array(string) certs) |
{ |
|
if(!context->verify_certificates) |
return 1; |
|
|
|
if((context->auth_level < AUTHLEVEL_require) && !sizeof(certs)) |
return 1; |
|
|
|
if(!certs || !sizeof(certs)) |
return 0; |
|
|
|
|
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) |
{ |
issuer_known = 1; |
break; |
} |
} |
|
if(issuer_known==0) |
{ |
return 0; |
} |
} |
|
|
|
|
|
|
mapping result = |
Standards.X509.verify_certificate_chain(certs, |
context->trusted_issuers_cache, |
context->require_trust, |
([ "verifier_algorithms" |
: context->verifier_algorithms])); |
|
|
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); |
} |
|
|
|
|
|
|
|
|
int(-1..1) handle_handshake(int type, string(8bit) data, string(8bit) raw); |
|
|
|
|
|
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; |
} |
|
|
|
|
|
|
|
State current_read_state; |
State current_write_state; |
string(8bit) left_over; |
Packet packet; |
|
|
int sent; |
|
|
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(); |
|
|
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()); |
} |
|
|
|
|
|
void set_alert_callback(function(object,int|object,string:void) callback) |
{ |
alert_callback = callback; |
} |
|
|
|
protected Packet recv_packet(string(8bit) data) |
{ |
string(8bit)|Packet res; |
|
|
if (left_over || !packet) |
{ |
packet = Packet(version, 2048); |
res = packet->recv( (left_over || "") + data); |
} |
else |
res = packet->recv(data); |
|
if (stringp(res)) |
{ |
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 |
left_over = 0; |
|
return [object]res; |
} |
|
|
|
|
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)) { |
|
|
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; |
} |
|
} |
|
|
|
|
|
|
int query_write_queue_size() |
{ |
return sizeof(alert_q) + sizeof(urgent_q) + sizeof(application_q); |
} |
|
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
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; |
} |
|
|
void send_close() |
{ |
send_packet(alert(ALERT_warning, ALERT_close_notify, |
"Closing connection.\n"), PRI_application); |
} |
|
|
void send_renegotiate(); |
|
|
|
|
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)) { |
|
|
|
|
size = sizeof((packet->fragment = data[..0])); |
if (sizeof(data) > 1) { |
|
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; |
} |
|
protected int handle_alert(string s) |
{ |
|
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 %O\n", |
ALERT_descriptions[description]); |
state = [int(0..0)|ConnectionState](state | CONNECTION_peer_fatal | |
CONNECTION_peer_closed); |
|
|
|
|
|
|
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)) { |
|
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))); |
|
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; |
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; |
|
|
|
|
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: |
|
|
|
|
|
|
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: |
|
|
|
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) { |
|
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 = ""; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string(8bit)|int got_data(string(8bit) data) |
{ |
if (state & (CONNECTION_peer_closed|CONNECTION_local_fatal)) { |
|
return 1; |
} |
|
|
|
|
|
string(8bit) alert_context = (left_over || "") + data; |
|
string(8bit) res = ""; |
Packet packet; |
while (packet = recv_packet(data)) |
{ |
data = ""; |
|
if (packet->is_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..i+1]); |
|
alert_buffer = alert_buffer[i..]; |
if (err) |
if (err > 0 && sizeof (res)) |
|
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) { |
|
|
|
|
send_packet(alert(ALERT_warning, ALERT_no_renegotiation, |
"Renegotiation not supported in unsecure mode.\n")); |
return -1; |
} |
if (expect_change_cipher) |
{ |
|
|
|
|
|
|
|
|
|
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: |
{ |
|
SSL3_DEBUG_MSG("SSL.Connection: Heartbeat.\n"); |
if (state != CONNECTION_ready) { |
|
|
|
break; |
} |
if (!session->heartbeat_mode) { |
|
|
|
|
|
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; |
} |
|
|
|
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 ""; |
} |
|
|