Permalink
Browse files

PR: 2658

Submitted by: Robin Seggelmann <seggelmann@fh-muenster.de>
Reviewed by: steve

Support for TLS/DTLS heartbeats.
  • Loading branch information...
snhenson committed Dec 31, 2011
1 parent 578519e commit bd6941cfaa31ee8a3f8661cb98227a5cbcc0f9f3
Showing with 561 additions and 4 deletions.
  1. +3 −0 CHANGES
  2. +20 −0 apps/s_cb.c
  3. +8 −0 apps/s_client.c
  4. +10 −0 apps/s_server.c
  5. +151 −1 ssl/d1_both.c
  6. +13 −0 ssl/d1_clnt.c
  7. +8 −0 ssl/d1_lib.c
  8. +13 −0 ssl/d1_pkt.c
  9. +13 −0 ssl/d1_srvr.c
  10. +1 −1 ssl/dtls1.h
  11. +12 −0 ssl/s3_clnt.c
  12. +21 −0 ssl/s3_lib.c
  13. +13 −0 ssl/s3_pkt.c
  14. +12 −0 ssl/s3_srvr.c
  15. +24 −2 ssl/ssl.h
  16. +4 −0 ssl/ssl3.h
  17. +4 −0 ssl/ssl_err.c
  18. +7 −0 ssl/ssl_locl.h
  19. +211 −0 ssl/t1_lib.c
  20. +13 −0 ssl/tls1.h
View
@@ -4,6 +4,9 @@
Changes between 1.0.0f and 1.0.1 [xx XXX xxxx]
+ *) Add support for TLS/DTLS heartbeats.
+ [Robin Seggelmann <seggelmann@fh-muenster.de>]
+
*) Improved PRNG seeding for VOS.
[Paul Green <Paul.Green@stratus.com>]
View
@@ -600,6 +600,26 @@ void MS_CALLBACK msg_cb(int write_p, int version, int content_type, const void *
}
}
}
+
+#ifndef OPENSSL_NO_HEARTBEATS
+ if (content_type == 24) /* Heartbeat */
+ {
+ str_details1 = ", Heartbeat";
+
+ if (len > 0)
+ {
+ switch (((const unsigned char*)buf)[0])
+ {
+ case 1:
+ str_details1 = ", HeartbeatRequest";
+ break;
+ case 2:
+ str_details1 = ", HeartbeatResponse";
+ break;
+ }
+ }
+ }
+#endif
}
BIO_printf(bio, "%s %s%s [length %04lx]%s%s\n", str_write_p, str_version, str_content_type, (unsigned long)len, str_details1, str_details2);
View
@@ -1862,6 +1862,14 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240
SSL_renegotiate(con);
cbuf_len=0;
}
+#ifndef OPENSSL_NO_HEARTBEATS
+ else if ((!c_ign_eof) && (cbuf[0] == 'B'))
+ {
+ BIO_printf(bio_err,"HEARTBEATING\n");
+ SSL_heartbeat(con);
+ cbuf_len=0;
+ }
+#endif
else
{
cbuf_len=i;
View
@@ -2192,6 +2192,16 @@ static int sv_body(char *hostname, int s, unsigned char *context)
goto err;
}
+#ifndef OPENSSL_NO_HEARTBEATS
+ if ((buf[0] == 'B') &&
+ ((buf[1] == '\n') || (buf[1] == '\r')))
+ {
+ BIO_printf(bio_err,"HEARTBEATING\n");
+ SSL_heartbeat(con);
+ i=0;
+ continue;
+ }
+#endif
if ((buf[0] == 'r') &&
((buf[1] == '\n') || (buf[1] == '\r')))
{
View
@@ -1084,7 +1084,11 @@ int dtls1_read_failed(SSL *s, int code)
return code;
}
- if ( ! SSL_in_init(s)) /* done, no need to send a retransmit */
+#ifndef OPENSSL_NO_HEARTBEATS
+ if (!SSL_in_init(s) && !s->tlsext_hb_pending) /* done, no need to send a retransmit */
+#else
+ if (!SSL_in_init(s)) /* done, no need to send a retransmit */
+#endif
{
BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ);
return code;
@@ -1438,3 +1442,149 @@ int dtls1_shutdown(SSL *s)
#endif
return ret;
}
+
+#ifndef OPENSSL_NO_HEARTBEATS
+int
+dtls1_process_heartbeat(SSL *s)
+ {
+ unsigned char *p = &s->s3->rrec.data[0], *pl;
+ unsigned short hbtype;
+ unsigned int payload;
+ unsigned int padding = 16; /* Use minimum padding */
+
+ /* Read type and payload length first */
+ hbtype = *p++;
+ n2s(p, payload);
+ pl = p;
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
+ &s->s3->rrec.data[0], s->s3->rrec.length,
+ s, s->msg_callback_arg);
+
+ if (hbtype == TLS1_HB_REQUEST)
+ {
+ unsigned char *buffer, *bp;
+ int r;
+
+ /* Allocate memory for the response, size is 1 byte
+ * message type, plus 2 bytes payload length, plus
+ * payload, plus padding
+ */
+ buffer = OPENSSL_malloc(1 + 2 + payload + padding);
+ bp = buffer;
+
+ /* Enter response type, length and copy payload */
+ *bp++ = TLS1_HB_RESPONSE;
+ s2n(payload, bp);
+ memcpy(bp, pl, payload);
+ /* Random padding */
+ RAND_pseudo_bytes(p, padding);
+
+ r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
+
+ if (r >= 0 && s->msg_callback)
+ s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+ buffer, 3 + payload + padding,
+ s, s->msg_callback_arg);
+
+ OPENSSL_free(buffer);
+
+ if (r < 0)
+ return r;
+ }
+ else if (hbtype == TLS1_HB_RESPONSE)
+ {
+ unsigned int seq;
+
+ /* We only send sequence numbers (2 bytes unsigned int),
+ * and 16 random bytes, so we just try to read the
+ * sequence number */
+ n2s(pl, seq);
+
+ if (payload == 18 && seq == s->tlsext_hb_seq)
+ {
+ dtls1_stop_timer(s);
+ s->tlsext_hb_seq++;
+ s->tlsext_hb_pending = 0;
+ }
+ }
+
+ return 0;
+ }
+
+int
+dtls1_heartbeat(SSL *s)
+ {
+ unsigned char *buf, *p;
+ int ret;
+ unsigned int payload = 18; /* Sequence number + random bytes */
+ unsigned int padding = 16; /* Use minimum padding */
+
+ /* Only send if peer supports and accepts HB requests... */
+ if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
+ s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS)
+ {
+ SSLerr(SSL_F_DTLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
+ return -1;
+ }
+
+ /* ...and there is none in flight yet... */
+ if (s->tlsext_hb_pending)
+ {
+ SSLerr(SSL_F_DTLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PENDING);
+ return -1;
+ }
+
+ /* ...and no handshake in progress. */
+ if (SSL_in_init(s) || s->in_handshake)
+ {
+ SSLerr(SSL_F_DTLS1_HEARTBEAT,SSL_R_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ /* Check if padding is too long, payload and padding
+ * must not exceed 2^14 - 3 = 16381 bytes in total.
+ */
+ OPENSSL_assert(payload + padding <= 16381);
+
+ /* Create HeartBeat message, we just use a sequence number
+ * as payload to distuingish different messages and add
+ * some random stuff.
+ * - Message Type, 1 byte
+ * - Payload Length, 2 bytes (unsigned int)
+ * - Payload, the sequence number (2 bytes uint)
+ * - Payload, random bytes (16 bytes uint)
+ * - Padding
+ */
+ buf = OPENSSL_malloc(1 + 2 + payload + padding);
+ p = buf;
+ /* Message Type */
+ *p++ = TLS1_HB_REQUEST;
+ /* Payload length (18 bytes here) */
+ s2n(payload, p);
+ /* Sequence number */
+ s2n(s->tlsext_hb_seq, p);
+ /* 16 random bytes */
+ RAND_pseudo_bytes(p, 16);
+ p += 16;
+ /* Random padding */
+ RAND_pseudo_bytes(p, padding);
+
+ ret = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
+ if (ret >= 0)
+ {
+ if (s->msg_callback)
+ s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+ buf, 3 + payload + padding,
+ s, s->msg_callback_arg);
+
+ dtls1_start_timer(s);
+ s->tlsext_hb_pending = 1;
+ }
+
+ OPENSSL_free(buf);
+
+ return ret;
+ }
+#endif
View
@@ -176,6 +176,19 @@ int dtls1_connect(SSL *s)
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, s->in_handshake, NULL);
#endif
+#ifndef OPENSSL_NO_HEARTBEATS
+ /* If we're awaiting a HeartbeatResponse, pretend we
+ * already got and don't await it anymore, because
+ * Heartbeats don't make sense during handshakes anyway.
+ */
+ if (s->tlsext_hb_pending)
+ {
+ dtls1_stop_timer(s);
+ s->tlsext_hb_pending = 0;
+ s->tlsext_hb_seq++;
+ }
+#endif
+
for (;;)
{
state=s->state;
View
@@ -424,6 +424,14 @@ int dtls1_handle_timeout(SSL *s)
state->timeout.read_timeouts = 1;
}
+#ifndef OPENSSL_NO_HEARTBEATS
+ if (s->tlsext_hb_pending)
+ {
+ s->tlsext_hb_pending = 0;
+ return dtls1_heartbeat(s);
+ }
+#endif
+
dtls1_start_timer(s);
return dtls1_retransmit_buffered_messages(s);
}
View
@@ -937,6 +937,19 @@ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
dest = s->d1->alert_fragment;
dest_len = &s->d1->alert_fragment_len;
}
+#ifndef OPENSSL_NO_HEARTBEATS
+ else if (rr->type == TLS1_RT_HEARTBEAT)
+ {
+ dtls1_process_heartbeat(s);
+
+ /* Exit and notify application to read again */
+ rr->length = 0;
+ s->rwstate=SSL_READING;
+ BIO_clear_retry_flags(SSL_get_rbio(s));
+ BIO_set_retry_read(SSL_get_rbio(s));
+ return(-1);
+ }
+#endif
/* else it's a CCS message, or application data or wrong */
else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC)
{
View
@@ -186,6 +186,19 @@ int dtls1_accept(SSL *s)
return(-1);
}
+#ifndef OPENSSL_NO_HEARTBEATS
+ /* If we're awaiting a HeartbeatResponse, pretend we
+ * already got and don't await it anymore, because
+ * Heartbeats don't make sense during handshakes anyway.
+ */
+ if (s->tlsext_hb_pending)
+ {
+ dtls1_stop_timer(s);
+ s->tlsext_hb_pending = 0;
+ s->tlsext_hb_seq++;
+ }
+#endif
+
for (;;)
{
state=s->state;
View
@@ -232,7 +232,7 @@ typedef struct dtls1_state_st
struct dtls1_timeout_st timeout;
- /* Indicates when the last handshake msg sent will timeout */
+ /* Indicates when the last handshake msg or heartbeat sent will timeout */
struct timeval next_timeout;
/* Timeout duration */
View
@@ -203,6 +203,18 @@ int ssl3_connect(SSL *s)
s->in_handshake++;
if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
+#ifndef OPENSSL_NO_HEARTBEATS
+ /* If we're awaiting a HeartbeatResponse, pretend we
+ * already got and don't await it anymore, because
+ * Heartbeats don't make sense during handshakes anyway.
+ */
+ if (s->tlsext_hb_pending)
+ {
+ s->tlsext_hb_pending = 0;
+ s->tlsext_hb_seq++;
+ }
+#endif
+
for (;;)
{
state=s->state;
View
@@ -3328,6 +3328,27 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
ret = 1;
break;
+#ifndef OPENSSL_NO_HEARTBEATS
+ case SSL_CTRL_TLS_EXT_SEND_HEARTBEAT:
+ if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+ ret = dtls1_heartbeat(s);
+ else
+ ret = tls1_heartbeat(s);
+ break;
+
+ case SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING:
+ ret = s->tlsext_hb_pending;
+ break;
+
+ case SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS:
+ if (larg)
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_RECV_REQUESTS;
+ else
+ s->tlsext_heartbeat &= ~SSL_TLSEXT_HB_DONT_RECV_REQUESTS;
+ ret = 1;
+ break;
+#endif
+
#endif /* !OPENSSL_NO_TLSEXT */
default:
break;
View
@@ -1070,6 +1070,19 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
dest = s->s3->alert_fragment;
dest_len = &s->s3->alert_fragment_len;
}
+#ifndef OPENSSL_NO_HEARTBEATS
+ else if (rr->type == TLS1_RT_HEARTBEAT)
+ {
+ tls1_process_heartbeat(s);
+
+ /* Exit and notify application to read again */
+ rr->length = 0;
+ s->rwstate=SSL_READING;
+ BIO_clear_retry_flags(SSL_get_rbio(s));
+ BIO_set_retry_read(SSL_get_rbio(s));
+ return(-1);
+ }
+#endif
if (dest_maxlen > 0)
{
Oops, something went wrong.

29 comments on commit bd6941c

@Atomfire

This comment has been minimized.

Show comment
Hide comment

Doh!

@scp

This comment has been minimized.

Show comment
Hide comment
@scp

scp Apr 8, 2014

The ramifications are of truly epic proportions.

scp replied Apr 8, 2014

The ramifications are of truly epic proportions.

@dijit

This comment has been minimized.

Show comment
Hide comment
@dijit

dijit Apr 8, 2014

I don't see you guys implementing this.

perhaps you should criticize less, and maybe peruse the code looking for other bugs.

dijit replied Apr 8, 2014

I don't see you guys implementing this.

perhaps you should criticize less, and maybe peruse the code looking for other bugs.

@mcmillan

This comment has been minimized.

Show comment
Hide comment
@mcmillan

mcmillan Apr 8, 2014

@dijit That's a little uncalled for. I don't think anyone here is directly criticising this commit or its authors (everybody writes bugs!) however the code here is currently causing massive ramifications for a large chunk of the internet and it's therefore worthy of note in at least some way.

@dijit That's a little uncalled for. I don't think anyone here is directly criticising this commit or its authors (everybody writes bugs!) however the code here is currently causing massive ramifications for a large chunk of the internet and it's therefore worthy of note in at least some way.

@AnthonyAkentiev

This comment has been minimized.

Show comment
Hide comment

Oh, shit!

@zeroasterisk

This comment has been minimized.

Show comment
Hide comment
@zeroasterisk

zeroasterisk Apr 8, 2014

I too have had some bad commits... or even good commits with horrible unforeseen ramifications.

I'll totally buy you a drink @snhenson -- I bet you could use one.

Best of luck all.

I too have had some bad commits... or even good commits with horrible unforeseen ramifications.

I'll totally buy you a drink @snhenson -- I bet you could use one.

Best of luck all.

@Amelek

This comment has been minimized.

Show comment
Hide comment
@Amelek

Amelek Apr 8, 2014

Sorry, but whoever wrote this rubbish shouldn't be allowed near C compiler, much less critical libraries like this one. Also, it is blatantly obvious that this code was either not reviewed, or reviewer was at least as incompetent as person who wrote this.

Take a look:
@tls1_heartbeat(SSL *s)

    buf = OPENSSL_malloc(1 + 2 + payload + padding);
    p = buf;
    /* Message Type */
    *p++ = TLS1_HB_REQUEST;

and
@tls1_process_heartbeat(SSL *s)

        buffer = OPENSSL_malloc(1 + 2 + payload + padding);
        bp = buffer;

        /* Enter response type, length and copy payload */
        *bp++ = TLS1_HB_RESPONSE;

one does not simply check if malloc failed? Mind you, that all other calls to OPENSSL_malloc in relevant file do check if null was returned, so it wasn't designed in infinite memory / abort on failure environment. How had such code even passed the review?

Also, I love how it's "1 + 2 + payload + padding" in one place and "3 + payload + padding" in other, in case someone was attempting to understand this.

Sorry, but whoever wrote this rubbish shouldn't be allowed near C compiler, much less critical libraries like this one. Also, it is blatantly obvious that this code was either not reviewed, or reviewer was at least as incompetent as person who wrote this.

Take a look:
@tls1_heartbeat(SSL *s)

    buf = OPENSSL_malloc(1 + 2 + payload + padding);
    p = buf;
    /* Message Type */
    *p++ = TLS1_HB_REQUEST;

and
@tls1_process_heartbeat(SSL *s)

        buffer = OPENSSL_malloc(1 + 2 + payload + padding);
        bp = buffer;

        /* Enter response type, length and copy payload */
        *bp++ = TLS1_HB_RESPONSE;

one does not simply check if malloc failed? Mind you, that all other calls to OPENSSL_malloc in relevant file do check if null was returned, so it wasn't designed in infinite memory / abort on failure environment. How had such code even passed the review?

Also, I love how it's "1 + 2 + payload + padding" in one place and "3 + payload + padding" in other, in case someone was attempting to understand this.

@AdditionalPylons

This comment has been minimized.

Show comment
Hide comment
@AdditionalPylons

AdditionalPylons Apr 8, 2014

@Amelek I agree, but it's not only this guy. The OpenSSL source is plagued with antiquated and terrible programming practices - more specifically the terrible naming conventions (or lack thereof) that are completely non-descriptive, ambiguous, and quite frankly just plain stupid. Look at char * buffer, char * p, int r, n2s and s2n.

It's impossible to know what these are without reading the code around it for context. Why not just put the extra effort and name it response_buffer and response_buffer_ptr and save time for everyone else who has to inspect that code.

These bugs happen because the people who write them can neither read nor review it themselves, and obviously neither can anybody else without spending a disproportionate amount of time figuring out what the hell you were trying to do.

Also if you use _bp++ =, shave your unix beard and remember you live in 2014. Writing code for a large scale project doesn't need any of your 1337 bullsh_t.

@Amelek I agree, but it's not only this guy. The OpenSSL source is plagued with antiquated and terrible programming practices - more specifically the terrible naming conventions (or lack thereof) that are completely non-descriptive, ambiguous, and quite frankly just plain stupid. Look at char * buffer, char * p, int r, n2s and s2n.

It's impossible to know what these are without reading the code around it for context. Why not just put the extra effort and name it response_buffer and response_buffer_ptr and save time for everyone else who has to inspect that code.

These bugs happen because the people who write them can neither read nor review it themselves, and obviously neither can anybody else without spending a disproportionate amount of time figuring out what the hell you were trying to do.

Also if you use _bp++ =, shave your unix beard and remember you live in 2014. Writing code for a large scale project doesn't need any of your 1337 bullsh_t.

@brbeaird

This comment has been minimized.

Show comment
Hide comment
@brbeaird

brbeaird Apr 9, 2014

Classic Robin and steve.

Classic Robin and steve.

@mculp

This comment has been minimized.

Show comment
Hide comment
@mculp

mculp Apr 9, 2014

Fucking steve.

mculp replied Apr 9, 2014

Fucking steve.

@kivikakk

This comment has been minimized.

Show comment
Hide comment
@kivikakk

kivikakk Apr 10, 2014

@AdditionalPylons

Also if you use *bp++ =, shave your unix beard and remember you live in 2014.

Are you serious? Who doesn't use this?

@AdditionalPylons

Also if you use *bp++ =, shave your unix beard and remember you live in 2014.

Are you serious? Who doesn't use this?

@Mackaber

This comment has been minimized.

Show comment
Hide comment
@Mackaber

Mackaber Apr 10, 2014

People should write and review the code (preferably while still in dev) instead of ranting about it...

People should write and review the code (preferably while still in dev) instead of ranting about it...

@Amelek

This comment has been minimized.

Show comment
Hide comment
@Amelek

Amelek Apr 10, 2014

@kivikakk

Are you serious? Who doesn't use this?

Probably everybody uses this. There is however major difference between everybody and person writing user-facing code of one of the most critical libraries used in Linux environment. There is no place for 1337 code in OpenSSL nor any user exposed code. And even if we stomach single letter local variables, look at this:

&s->s3->rrec.data[0]

"s" is SSL* context, then "s3" is ssl3_state_st*, "rrec" is actually decrypted user content. How is this 21 century coding practice? And &x[0] seem to be an idiom for people who never attempted to understand C.

Tbh, I think this whole patch should be reverted and this feature removed. There is no need to have keepalive protocol on the encryption layer, and even if there exists some bizarre environment where this is required, keepalive protocol should not allow user defined payload. 64kb of user payload is criminal.

@kivikakk

Are you serious? Who doesn't use this?

Probably everybody uses this. There is however major difference between everybody and person writing user-facing code of one of the most critical libraries used in Linux environment. There is no place for 1337 code in OpenSSL nor any user exposed code. And even if we stomach single letter local variables, look at this:

&s->s3->rrec.data[0]

"s" is SSL* context, then "s3" is ssl3_state_st*, "rrec" is actually decrypted user content. How is this 21 century coding practice? And &x[0] seem to be an idiom for people who never attempted to understand C.

Tbh, I think this whole patch should be reverted and this feature removed. There is no need to have keepalive protocol on the encryption layer, and even if there exists some bizarre environment where this is required, keepalive protocol should not allow user defined payload. 64kb of user payload is criminal.

@tylerl

This comment has been minimized.

Show comment
Hide comment
@tylerl

tylerl Apr 10, 2014

@Amelek The thread needed a "this programmer shouldn't be allowed near a computer" Dunning-Kruger representative. So thanks for stepping up.

The effective problem with this code, as I'm sure you can figure out by reading your nearest tech journal, has nothing to do with anything you've pointed out. Yes, the style of OpenSSL is arcane, but it's consistently so throughout the library. That's not the problem. This particular change set is neither worse nor better than the core of the library.

If you want to understand what's wrong with the OpenSSL code, compare it against the Linux kernel code. The kernel is the largest collaborative software project in the world and is easily one of the most readable, but by your standards, none of the developers should be allowed near a compiler. Just look at those variable names! And the pointer arithmetic!

No, If you want to understand what's really wrong with OpenSSL, look through the code to see how a function like EVP_CIPHER_CTX_new() is implemented. Along the way you'll discover a very key difference between the two codebases. That is the real reason why you shouldn't trust OpenSSL. Not this code here. This was just a logic failure which would have been just as easy to make if your own coding standards had been followed.

@Amelek The thread needed a "this programmer shouldn't be allowed near a computer" Dunning-Kruger representative. So thanks for stepping up.

The effective problem with this code, as I'm sure you can figure out by reading your nearest tech journal, has nothing to do with anything you've pointed out. Yes, the style of OpenSSL is arcane, but it's consistently so throughout the library. That's not the problem. This particular change set is neither worse nor better than the core of the library.

If you want to understand what's wrong with the OpenSSL code, compare it against the Linux kernel code. The kernel is the largest collaborative software project in the world and is easily one of the most readable, but by your standards, none of the developers should be allowed near a compiler. Just look at those variable names! And the pointer arithmetic!

No, If you want to understand what's really wrong with OpenSSL, look through the code to see how a function like EVP_CIPHER_CTX_new() is implemented. Along the way you'll discover a very key difference between the two codebases. That is the real reason why you shouldn't trust OpenSSL. Not this code here. This was just a logic failure which would have been just as easy to make if your own coding standards had been followed.

@jpgohlke

This comment has been minimized.

Show comment
Hide comment
@jpgohlke

jpgohlke Apr 10, 2014

@tylerl Damn it. You had to give just enough tantalizing hints without any explanation, so that now I have to spend the next day or two crawling through code bases to satisfy my curiosity. Haha

@tylerl Damn it. You had to give just enough tantalizing hints without any explanation, so that now I have to spend the next day or two crawling through code bases to satisfy my curiosity. Haha

@okorz001

This comment has been minimized.

Show comment
Hide comment
@okorz001

okorz001 Apr 10, 2014

@Amelek

FWIW, I've worked with a compiler where &x[0] was necessary because char[] would not implicitly decay to char*. I believe even the C89 standard requires this decay, but you've got to work with the toolchain you're given.

@Amelek

FWIW, I've worked with a compiler where &x[0] was necessary because char[] would not implicitly decay to char*. I believe even the C89 standard requires this decay, but you've got to work with the toolchain you're given.

@nolim1t

This comment has been minimized.

Show comment
Hide comment

Epic

@sensahin

This comment has been minimized.

Show comment
Hide comment

Dope!

@thirdknife

This comment has been minimized.

Show comment
Hide comment

Nightmare!

@O1O1O1O

This comment has been minimized.

Show comment
Hide comment
@O1O1O1O

O1O1O1O Apr 13, 2014

So it is generally the case for OpenSSL that major additions of features have no tests for them whatsoever? That makes me sad. Shouldn't I be able to have my browser/client/server refuse SSL connections with implementations that I don't trust or are know to have flaws? Sure an endpoint could lie about what code it was running, but it would at least be effective against non-malicious flaws.

So it is generally the case for OpenSSL that major additions of features have no tests for them whatsoever? That makes me sad. Shouldn't I be able to have my browser/client/server refuse SSL connections with implementations that I don't trust or are know to have flaws? Sure an endpoint could lie about what code it was running, but it would at least be effective against non-malicious flaws.

@onetom

This comment has been minimized.

Show comment
Hide comment
@onetom

onetom Apr 13, 2014

I just wanted to ask the same as @O1O1O1O. Even small projects doesn't accept contributions without the corresponding test suite... But hey, it's written in C, what do you expect... Not that I know of any seriously practical OS or core library which was written in a test driven way, using some other language than C, BUT maybe it's time to raise the bar and start leaving this computing dark medieval age behind us...

We saw better security architecture before (centralized into the OS, seamlessly exposed to applications):
http://plan9.bell-labs.com/sys/doc/auth.html

Integrated systems has been written in a different language from C before (not suffering obvious plagues like, null pointer dereference or buffer overflow):
http://en.wikipedia.org/wiki/Lisp_machine

Multi-core friendly, high performance code can be generated from a domain friendly custom language:
http://nv.github.io/nile/demo_shape.html

And let's not forget the newly budding, full-stack language, which can bring these concepts under one, common hood:
http://www.red-lang.org/
(which is kind of following the principles of low fat computing: http://www.ultratechnology.com/lowfat.htm)

I'm aware of http://www.jwz.org/doc/worse-is-better.html but does it really have to be that way?

I just wanted to ask the same as @O1O1O1O. Even small projects doesn't accept contributions without the corresponding test suite... But hey, it's written in C, what do you expect... Not that I know of any seriously practical OS or core library which was written in a test driven way, using some other language than C, BUT maybe it's time to raise the bar and start leaving this computing dark medieval age behind us...

We saw better security architecture before (centralized into the OS, seamlessly exposed to applications):
http://plan9.bell-labs.com/sys/doc/auth.html

Integrated systems has been written in a different language from C before (not suffering obvious plagues like, null pointer dereference or buffer overflow):
http://en.wikipedia.org/wiki/Lisp_machine

Multi-core friendly, high performance code can be generated from a domain friendly custom language:
http://nv.github.io/nile/demo_shape.html

And let's not forget the newly budding, full-stack language, which can bring these concepts under one, common hood:
http://www.red-lang.org/
(which is kind of following the principles of low fat computing: http://www.ultratechnology.com/lowfat.htm)

I'm aware of http://www.jwz.org/doc/worse-is-better.html but does it really have to be that way?

@andrewchambers

This comment has been minimized.

Show comment
Hide comment
@andrewchambers

andrewchambers Apr 13, 2014

@Amelek
I would just like to point at that you have no public repositories so I cant review your code at all. Perhaps you could submit a pull request renaming some variables so its more to your liking.

@Amelek
I would just like to point at that you have no public repositories so I cant review your code at all. Perhaps you could submit a pull request renaming some variables so its more to your liking.

@Amelek

This comment has been minimized.

Show comment
Hide comment
@Amelek

Amelek Apr 14, 2014

@andrewchambers
Doing full pull request seem like a waste of time to me and I don't really feel like contributing to that project now.

Regardless, there is refactored version of tls1_process_heartbeat
https://github.com/Amelek/RandomUploads/blob/master/openSSL/openssl_refactored.patch

Is it better? No - it's not reviewed and thus can't be used anywhere. There may be new bugs introduced in it.

Observation while doing that patch: OpenSSL's fixed code:

  • does not adhere to RFC - you can send requests up to 0xFFFF in length while 2^14 is max length
  • does not check if malloc failed - server will crash under load. Seem unlikely
  • does not check if random actually filled the buffer - server will leak 16 bytes of uninitialized memory if it hadn't. I doubt that it can be the case though.
  • I have no idea what msg_callback does and if it can change rrec or not. It does take entire SSL* as argument, so it has to be taken into consideration

@andrewchambers
Doing full pull request seem like a waste of time to me and I don't really feel like contributing to that project now.

Regardless, there is refactored version of tls1_process_heartbeat
https://github.com/Amelek/RandomUploads/blob/master/openSSL/openssl_refactored.patch

Is it better? No - it's not reviewed and thus can't be used anywhere. There may be new bugs introduced in it.

Observation while doing that patch: OpenSSL's fixed code:

  • does not adhere to RFC - you can send requests up to 0xFFFF in length while 2^14 is max length
  • does not check if malloc failed - server will crash under load. Seem unlikely
  • does not check if random actually filled the buffer - server will leak 16 bytes of uninitialized memory if it hadn't. I doubt that it can be the case though.
  • I have no idea what msg_callback does and if it can change rrec or not. It does take entire SSL* as argument, so it has to be taken into consideration
@dennis-fedco

This comment has been minimized.

Show comment
Hide comment
@dennis-fedco

dennis-fedco Apr 15, 2014

@Amelek I like the renamed variables. Truly while "hbtype" makes sense to you while you are writing the code, "heartbeat_type" is just so much more user friendly, and makes it for a much easier time when you or someone looks at the code later. And so I approve this message.

@Amelek I like the renamed variables. Truly while "hbtype" makes sense to you while you are writing the code, "heartbeat_type" is just so much more user friendly, and makes it for a much easier time when you or someone looks at the code later. And so I approve this message.

@4of92000

This comment has been minimized.

Show comment
Hide comment
@4of92000

4of92000 Apr 15, 2014

First person to find another critical bug with OpenSSL wins!

First person to find another critical bug with OpenSSL wins!

@Niteshvgupta

This comment has been minimized.

Show comment
Hide comment
@Niteshvgupta

Niteshvgupta Apr 16, 2014

Can someone point out exactly where the actual bug is? I'm curious.

Can someone point out exactly where the actual bug is? I'm curious.

@TugTales

This comment has been minimized.

Show comment
Hide comment
@TugTales

TugTales Apr 16, 2014

It was simultaneously discovered after 2 long years by two independent groups? Really? That's so improbable. Anyone that's been in US government has heard the phrase, "Cover your ass". Sounds like one group knew for a while and only admitted it after an independent group reported it. Or were they using the same test suite? Seems like with that much money and safety at stake it shouldn't be criminals that discover and exploit these things first as has been confirmed in at least two places. They need to cut back on the coffee & cigarettes.

I'm not going to pretend I know whether or not this code is good or not - I just know that I avoided pointers when possible; something it seems would be near impossible to do in kernel code but very desirable when writing something like openSSL.

It was simultaneously discovered after 2 long years by two independent groups? Really? That's so improbable. Anyone that's been in US government has heard the phrase, "Cover your ass". Sounds like one group knew for a while and only admitted it after an independent group reported it. Or were they using the same test suite? Seems like with that much money and safety at stake it shouldn't be criminals that discover and exploit these things first as has been confirmed in at least two places. They need to cut back on the coffee & cigarettes.

I'm not going to pretend I know whether or not this code is good or not - I just know that I avoided pointers when possible; something it seems would be near impossible to do in kernel code but very desirable when writing something like openSSL.

@O1O1O1O

This comment has been minimized.

Show comment
Hide comment
@O1O1O1O

O1O1O1O Apr 17, 2014

@barneysbombers I believe it was far more likely that someone, somewhere was either suspicious or actually new there was an issue with OpenSSL can somehow various teams were pointed in the right direction looking for holes. My guess is that there were investigations around the various Bitcoin exchanges getting plundered even when people said they had extremely secure passwords (but no 2FA). This is separate from any other Bitcoin related issues that resulted in losses although one can never rule out exchanges that had admin accounts publicly accessible and compromised due to the SSL issue. Of course some other high value targets like government or banking entities could also have gathered evidence that SSL was being compromised in a way they could not identify. If you had gathered enough reports you could correlate OpenSSL version to those reports and narrow you focus...

@barneysbombers I believe it was far more likely that someone, somewhere was either suspicious or actually new there was an issue with OpenSSL can somehow various teams were pointed in the right direction looking for holes. My guess is that there were investigations around the various Bitcoin exchanges getting plundered even when people said they had extremely secure passwords (but no 2FA). This is separate from any other Bitcoin related issues that resulted in losses although one can never rule out exchanges that had admin accounts publicly accessible and compromised due to the SSL issue. Of course some other high value targets like government or banking entities could also have gathered evidence that SSL was being compromised in a way they could not identify. If you had gathered enough reports you could correlate OpenSSL version to those reports and narrow you focus...

@TugTales

This comment has been minimized.

Show comment
Hide comment
@TugTales

TugTales Apr 17, 2014

Well, security isn't something that should be strictly outsourced. There needs to be competitive and competent security teams investigating these things internal to the government and big businesses as well. It's not like these organizations can't afford it. And it's not like if they couldn't afford it the government wouldn't print the money so that they could if they so desired, a bit like they all do with their defense budgets.

I find it a bit unreasonable to believe that the Russian, Chinese, Ukrainian, American, and various other security agencies didn't know about this flaw, almost from the get go. Indeed with the news about the NSA and the behavior of these governments it wouldn't be unreasonable to think this at all.

We do not need a situation in security such as what caused financial markets to collapse all over the world a few years back; where the 'independent regulatory and ratings outsiders, the experts' were almost as irresponsible as the financial firms and traders. Well, it's already been exposed it wasn't so much irresponsibility as corruption, regardless that I spend more time in jail as a 19 year old forgetting I had a traffic ticket than any of the perpetrators of those abuses.

Well, security isn't something that should be strictly outsourced. There needs to be competitive and competent security teams investigating these things internal to the government and big businesses as well. It's not like these organizations can't afford it. And it's not like if they couldn't afford it the government wouldn't print the money so that they could if they so desired, a bit like they all do with their defense budgets.

I find it a bit unreasonable to believe that the Russian, Chinese, Ukrainian, American, and various other security agencies didn't know about this flaw, almost from the get go. Indeed with the news about the NSA and the behavior of these governments it wouldn't be unreasonable to think this at all.

We do not need a situation in security such as what caused financial markets to collapse all over the world a few years back; where the 'independent regulatory and ratings outsiders, the experts' were almost as irresponsible as the financial firms and traders. Well, it's already been exposed it wasn't so much irresponsibility as corruption, regardless that I spend more time in jail as a 19 year old forgetting I had a traffic ticket than any of the perpetrators of those abuses.

Please sign in to comment.