tls: add the i/o loop - largish rework of i/o buffering
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 20 Jan 2017 02:15:09 +0000 (03:15 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 20 Jan 2017 02:15:09 +0000 (03:15 +0100)
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/tls.c

index 0927358843b3a6f13e3175532ff45ba37b5f6425..71be2def8a8307294e9aa27c3e2d6f11df477a59 100644 (file)
 //usage:#define tls_full_usage "\n\n"
 
 #include "tls.h"
+#include "common_bufsiz.h"
 
 #define TLS_DEBUG      1
-#define TLS_DEBUG_HASH 0
+#define TLS_DEBUG_HASH 1
 #define TLS_DEBUG_DER  0
 
 #if TLS_DEBUG
 // works against "openssl s_server -cipher NULL"
 // and against wolfssl-3.9.10-stable/examples/server/server.c:
 //#define CIPHER_ID TLS_RSA_WITH_NULL_SHA256 // for testing (does everything except encrypting)
-// "works", meaning
-// "can send encrypted FINISHED to  wolfssl-3.9.10-stable/examples/server/server.c",
-// don't yet read its encrypted answers:
+// works against wolfssl-3.9.10-stable/examples/server/server.c
+// (getting back and decrypt ok first application data message)
 #define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE
 
 enum {
@@ -162,6 +162,11 @@ enum {
        AES_BLOCKSIZE = 16,
        AES128_KEYSIZE = 16,
        AES256_KEYSIZE = 32,
+
+       MAX_TLS_RECORD = (1 << 14),
+       OUTBUF_PFX = 8 + AES_BLOCKSIZE, /* header + IV */
+       OUTBUF_SFX = SHA256_OUTSIZE + AES_BLOCKSIZE, /* MAC + padding */
+       MAX_OTBUF = MAX_TLS_RECORD - OUTBUF_PFX - OUTBUF_SFX,
 };
 
 struct record_hdr {
@@ -195,6 +200,9 @@ typedef struct tls_state {
 // exceed 2^64-1.
        uint64_t write_seq64_be;
 
+       int outbuf_size;
+       uint8_t *outbuf;
+
        // RFC 5246
        // |6.2.1. Fragmentation
        // |  The record layer fragments information blocks into TLSPlaintext
@@ -225,7 +233,6 @@ typedef struct tls_state {
 //needed?
        uint64_t align____;
        uint8_t inbuf[20*1024];
-       uint8_t outbuf[20*1024];
 } tls_state_t;
 
 
@@ -462,6 +469,17 @@ static void tls_error_die(tls_state_t *tls)
        xfunc_die();
 }
 
+static void *tls_get_outbuf(tls_state_t *tls, int len)
+{
+       if (len > MAX_OTBUF)
+               xfunc_die();
+       if (tls->outbuf_size < len + OUTBUF_PFX + OUTBUF_SFX) {
+               tls->outbuf_size = len + OUTBUF_PFX + OUTBUF_SFX;
+               tls->outbuf = xrealloc(tls->outbuf, tls->outbuf_size);
+       }
+       return tls->outbuf + OUTBUF_PFX;
+}
+
 // RFC 5246
 // 6.2.3.1.  Null or Standard Stream Cipher
 //
@@ -501,39 +519,41 @@ static void tls_error_die(tls_state_t *tls)
 // --------  -----------  ----------  --------------
 // SHA       HMAC-SHA1       20            20
 // SHA256    HMAC-SHA256     32            32
-static void xwrite_and_hash(tls_state_t *tls, /*const*/ void *buf, unsigned size)
+static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
 {
-       uint8_t mac_hash[SHA256_OUTSIZE];
-       struct record_hdr *xhdr = buf;
+       uint8_t *buf = tls->outbuf + OUTBUF_PFX;
+       struct record_hdr *xhdr;
 
-       if (!tls->encrypt_on_write) {
-               xwrite(tls->fd, buf, size);
-               dbg("wrote %u bytes\n", size);
-               /* Handshake hash does not include record headers */
-               if (size > 5 && xhdr->type == RECORD_TYPE_HANDSHAKE) {
-                       sha256_hash_dbg(">> sha256:%s", &tls->handshake_sha256_ctx, (uint8_t*)buf + 5, size - 5);
-               }
-               return;
-       }
+       xhdr = (void*)(buf - sizeof(*xhdr));
+       if (CIPHER_ID != TLS_RSA_WITH_NULL_SHA256)
+               xhdr = (void*)(buf - sizeof(*xhdr) - AES_BLOCKSIZE); /* place for IV */
+
+       xhdr->type = type;
+       xhdr->proto_maj = TLS_MAJ;
+       xhdr->proto_min = TLS_MIN;
+       /* fake unencrypted record header len for MAC calculation */
+       xhdr->len16_hi = size >> 8;
+       xhdr->len16_lo = size & 0xff;
 
+       /* Calculate MAC signature */
 //TODO: convert hmac_sha256 to precomputed
-       hmac_sha256(mac_hash,
+       hmac_sha256(buf + size,
                        tls->client_write_MAC_key, sizeof(tls->client_write_MAC_key),
                        &tls->write_seq64_be, sizeof(tls->write_seq64_be),
+                       xhdr, sizeof(*xhdr),
                        buf, size,
                        NULL);
        tls->write_seq64_be = SWAP_BE64(1 + SWAP_BE64(tls->write_seq64_be));
 
+       size += SHA256_OUTSIZE;
+
        if (CIPHER_ID == TLS_RSA_WITH_NULL_SHA256) {
                /* No encryption, only signing */
-               xhdr->len16_lo += SHA256_OUTSIZE;
-//FIXME: overflow into len16_hi?
-               xwrite(tls->fd, buf, size);
-               xhdr->len16_lo -= SHA256_OUTSIZE;
-               dbg("wrote %u bytes\n", size);
-
-               xwrite(tls->fd, mac_hash, sizeof(mac_hash));
-               dbg("wrote %u bytes of hash\n", (int)sizeof(mac_hash));
+               xhdr->len16_hi = size >> 8;
+               xhdr->len16_lo = size & 0xff;
+               dump_hex(">> %s\n", xhdr, sizeof(*xhdr) + size);
+               xwrite(tls->fd, xhdr, sizeof(*xhdr) + size);
+               dbg("wrote %u bytes (NULL crypt, SHA256 hash)\n", size);
                return;
        }
 
@@ -579,13 +599,8 @@ static void xwrite_and_hash(tls_state_t *tls, /*const*/ void *buf, unsigned size
        uint8_t padding_length;
 
        /* Build IV+content+MAC+padding in outbuf */
-       tls_get_random(tls->outbuf, AES_BLOCKSIZE); /* IV */
-       p = tls->outbuf + AES_BLOCKSIZE;
-       size -= sizeof(*xhdr);
-       dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", size, (int)sizeof(mac_hash));
-       p = mempcpy(p, buf + sizeof(*xhdr), size);  /* content */
-       p = mempcpy(p, mac_hash, sizeof(mac_hash)); /* MAC */
-       size += sizeof(mac_hash);
+       tls_get_random(buf - AES_BLOCKSIZE, AES_BLOCKSIZE); /* IV */
+       dbg("before crypt: 5 hdr + %u data + %u hash bytes\n", size, SHA256_OUTSIZE);
        // RFC is talking nonsense:
        //    Padding that is added to force the length of the plaintext to be
        //    an integral multiple of the block cipher's block length.
@@ -601,6 +616,7 @@ static void xwrite_and_hash(tls_state_t *tls, /*const*/ void *buf, unsigned size
        // If you need no bytes to reach BLOCKSIZE, you have to pad a full
        // BLOCKSIZE with bytes of value (BLOCKSIZE-1).
        // It's ok to have more than minimum padding, but we do minimum.
+       p = buf + size;
        padding_length = (~size) & (AES_BLOCKSIZE - 1);
        do {
                *p++ = padding_length;              /* padding */
@@ -608,12 +624,12 @@ static void xwrite_and_hash(tls_state_t *tls, /*const*/ void *buf, unsigned size
        } while ((size & (AES_BLOCKSIZE - 1)) != 0);
 
        /* Encrypt content+MAC+padding in place */
-       psAesInit(&ctx, tls->outbuf, /* IV */
+       psAesInit(&ctx, buf - AES_BLOCKSIZE, /* IV */
                        tls->client_write_key, sizeof(tls->client_write_key)
        );
        psAesEncrypt(&ctx,
-                       tls->outbuf + AES_BLOCKSIZE, /* plaintext */
-                       tls->outbuf + AES_BLOCKSIZE, /* ciphertext */
+                       buf, /* plaintext */
+                       buf, /* ciphertext */
                        size
        );
 
@@ -623,14 +639,33 @@ static void xwrite_and_hash(tls_state_t *tls, /*const*/ void *buf, unsigned size
        size += AES_BLOCKSIZE;     /* + IV */
        xhdr->len16_hi = size >> 8;
        xhdr->len16_lo = size & 0xff;
-       xwrite(tls->fd, xhdr, sizeof(*xhdr));
-       xwrite(tls->fd, tls->outbuf, size);
+       dump_hex(">> %s\n", xhdr, sizeof(*xhdr) + size);
+       xwrite(tls->fd, xhdr, sizeof(*xhdr) + size);
        dbg("wrote %u bytes\n", (int)sizeof(*xhdr) + size);
-//restore xhdr->len16_hi = ;
-//restore xhdr->len16_lo = ;
     }
 }
 
+static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size)
+{
+       if (!tls->encrypt_on_write) {
+               uint8_t *buf = tls->outbuf + OUTBUF_PFX;
+               struct record_hdr *xhdr = (void*)(buf - sizeof(*xhdr));
+
+               xhdr->type = RECORD_TYPE_HANDSHAKE;
+               xhdr->proto_maj = TLS_MAJ;
+               xhdr->proto_min = TLS_MIN;
+               xhdr->len16_hi = size >> 8;
+               xhdr->len16_lo = size & 0xff;
+               dump_hex(">> %s\n", xhdr, sizeof(*xhdr) + size);
+               xwrite(tls->fd, xhdr, sizeof(*xhdr) + size);
+               dbg("wrote %u bytes\n", (int)sizeof(*xhdr) + size);
+               /* Handshake hash does not include record headers */
+               sha256_hash_dbg(">> sha256:%s", &tls->handshake_sha256_ctx, buf, size);
+               return;
+       }
+       xwrite_encrypted(tls, size, RECORD_TYPE_HANDSHAKE);
+}
+
 static int xread_tls_block(tls_state_t *tls)
 {
        struct record_hdr *xhdr;
@@ -668,7 +703,7 @@ static int xread_tls_block(tls_state_t *tls)
        sz = target - sizeof(*xhdr);
 
        /* Needs to be decrypted? */
-       if (tls->min_encrypted_len_on_read) {
+       if (tls->min_encrypted_len_on_read > SHA256_OUTSIZE) {
                psCipherContext_t ctx;
                uint8_t *p = tls->inbuf + sizeof(*xhdr);
                int padding_len;
@@ -698,6 +733,10 @@ static int xread_tls_block(tls_state_t *tls)
                        /* Skip IV */
                        memmove(tls->inbuf + 5, tls->inbuf + 5 + AES_BLOCKSIZE, sz);
                }
+       } else {
+               /* if nonzero, then it's TLS_RSA_WITH_NULL_SHA256: drop MAC */
+               /* else: no encryption yet on input, subtract zero = NOP */
+               sz -= tls->min_encrypted_len_on_read;
        }
 
        /* RFC 5246 is not saying it explicitly, but sha256 hash
@@ -943,39 +982,24 @@ static int xread_tls_handshake_block(tls_state_t *tls, int min_len)
        return len;
 }
 
-static void fill_handshake_record_hdr(struct record_hdr *xhdr, unsigned len)
+static ALWAYS_INLINE void fill_handshake_record_hdr(void *buf, unsigned type, unsigned len)
 {
        struct handshake_hdr {
-               struct record_hdr xhdr;
                uint8_t type;
                uint8_t len24_hi, len24_mid, len24_lo;
-       } *h = (void*)xhdr;
-
-       h->xhdr.type = RECORD_TYPE_HANDSHAKE;
-       h->xhdr.proto_maj = TLS_MAJ;
-       h->xhdr.proto_min = TLS_MIN;
-       len -= 5;
-       h->xhdr.len16_hi = len >> 8;
-       // can be optimized to do one store instead of four:
-       // uint32_t v = htonl(0x100*(RECORD_TYPE_HANDSHAKE + 0x100*(TLS_MAJ + 0x100*(TLS_MIN))))
-       //            | ((len >> 8) << 24); // little-endian specific, don't use in this form
-       // *(uint32_t *)xhdr = v;
-
-       h->xhdr.len16_lo = len & 0xff;
+       } *h = buf;
 
        len -= 4;
+       h->type = type;
        h->len24_hi  = len >> 16;
        h->len24_mid = len >> 8;
        h->len24_lo  = len & 0xff;
-
-       memset(h + 1, 0, len);
 }
 
 //TODO: implement RFC 5746 (Renegotiation Indication Extension) - some servers will refuse to work with us otherwise
 static void send_client_hello(tls_state_t *tls)
 {
        struct client_hello {
-               struct record_hdr xhdr;
                uint8_t type;
                uint8_t len24_hi, len24_mid, len24_lo;
                uint8_t proto_maj, proto_min;
@@ -987,25 +1011,25 @@ static void send_client_hello(tls_state_t *tls)
                uint8_t comprtypes_len;
                uint8_t comprtypes[1]; /* actually variable */
        };
-       struct client_hello record;
-
-       fill_handshake_record_hdr(&record.xhdr, sizeof(record));
-       record.type = HANDSHAKE_CLIENT_HELLO;
-       record.proto_maj = TLS_MAJ;     /* the "requested" version of the protocol, */
-       record.proto_min = TLS_MIN;     /* can be higher than one in record headers */
-       tls_get_random(record.rand32, sizeof(record.rand32));
-       /* record.session_id_len = 0; - already is */
-       /* record.cipherid_len16_hi = 0; */
-       record.cipherid_len16_lo = 2 * 1;
-       record.cipherid[0] = CIPHER_ID >> 8;
-       record.cipherid[1] = CIPHER_ID & 0xff;
-       record.comprtypes_len = 1;
-       /* record.comprtypes[0] = 0; */
+       struct client_hello *record = tls_get_outbuf(tls, sizeof(*record));
+
+       fill_handshake_record_hdr(record, HANDSHAKE_CLIENT_HELLO, sizeof(*record));
+       record->proto_maj = TLS_MAJ;    /* the "requested" version of the protocol, */
+       record->proto_min = TLS_MIN;    /* can be higher than one in record headers */
+       tls_get_random(record->rand32, sizeof(record->rand32));
+memset(record->rand32, 0x11, sizeof(record->rand32));
+       memcpy(tls->client_and_server_rand32, record->rand32, sizeof(record->rand32));
+       record->session_id_len = 0;
+       record->cipherid_len16_hi = 0;
+       record->cipherid_len16_lo = 2 * 1;
+       record->cipherid[0] = CIPHER_ID >> 8;
+       record->cipherid[1] = CIPHER_ID & 0xff;
+       record->comprtypes_len = 1;
+       record->comprtypes[0] = 0;
 
        //dbg (make it repeatable): memset(record.rand32, 0x11, sizeof(record.rand32));
        dbg(">> CLIENT_HELLO\n");
-       xwrite_and_hash(tls, &record, sizeof(record));
-       memcpy(tls->client_and_server_rand32, record.rand32, sizeof(record.rand32));
+       xwrite_and_update_handshake_hash(tls, sizeof(*record));
 }
 
 static void get_server_hello(tls_state_t *tls)
@@ -1099,21 +1123,19 @@ static void get_server_cert(tls_state_t *tls)
 static void send_client_key_exchange(tls_state_t *tls)
 {
        struct client_key_exchange {
-               struct record_hdr xhdr;
                uint8_t type;
                uint8_t len24_hi, len24_mid, len24_lo;
                /* keylen16 exists for RSA (in TLS, not in SSL), but not for some other key types */
                uint8_t keylen16_hi, keylen16_lo;
                uint8_t key[4 * 1024]; // size??
        };
-       struct client_key_exchange record;
+//FIXME: better size estimate
+       struct client_key_exchange *record = tls_get_outbuf(tls, sizeof(*record));
        uint8_t rsa_premaster[SSL_HS_RSA_PREMASTER_SIZE];
        int len;
 
-       fill_handshake_record_hdr(&record.xhdr, sizeof(record) - sizeof(record.key));
-       record.type = HANDSHAKE_CLIENT_KEY_EXCHANGE;
-
        tls_get_random(rsa_premaster, sizeof(rsa_premaster));
+memset(rsa_premaster, 0x44, sizeof(rsa_premaster));
        // RFC 5246
        // "Note: The version number in the PreMasterSecret is the version
        // offered by the client in the ClientHello.client_version, not the
@@ -1123,22 +1145,20 @@ static void send_client_key_exchange(tls_state_t *tls)
        len = psRsaEncryptPub(/*pool:*/ NULL,
                /* psRsaKey_t* */ &tls->server_rsa_pub_key,
                rsa_premaster, /*inlen:*/ sizeof(rsa_premaster),
-               record.key, sizeof(record.key),
+               record->key, sizeof(record->key),
                data_param_ignored
        );
-       /* length fields need fixing */
-       record.keylen16_hi = len >> 8;
-       record.keylen16_lo = len & 0xff;
+       record->keylen16_hi = len >> 8;
+       record->keylen16_lo = len & 0xff;
        len += 2;
-       /* record.len24_hi  = 0; - already is */
-       record.len24_mid = len >> 8;
-       record.len24_lo  = len & 0xff;
+       record->type = HANDSHAKE_CLIENT_KEY_EXCHANGE;
+       record->len24_hi  = 0;
+       record->len24_mid = len >> 8;
+       record->len24_lo  = len & 0xff;
        len += 4;
-       record.xhdr.len16_hi = len >> 8;
-       record.xhdr.len16_lo = len & 0xff;
 
        dbg(">> CLIENT_KEY_EXCHANGE\n");
-       xwrite_and_hash(tls, &record, sizeof(record.xhdr) + len);
+       xwrite_and_update_handshake_hash(tls, len);
 
        // RFC 5246
        // For all key exchange methods, the same algorithm is used to convert
@@ -1224,7 +1244,6 @@ static const uint8_t rec_CHANGE_CIPHER_SPEC[] = {
 
 static void send_change_cipher_spec(tls_state_t *tls)
 {
-       /* Not "xwrite_and_hash": this is not a handshake message */
        dbg(">> CHANGE_CIPHER_SPEC\n");
        xwrite(tls->fd, rec_CHANGE_CIPHER_SPEC, sizeof(rec_CHANGE_CIPHER_SPEC));
 }
@@ -1269,19 +1288,17 @@ static void send_change_cipher_spec(tls_state_t *tls)
 static void send_client_finished(tls_state_t *tls)
 {
        struct finished {
-               struct record_hdr xhdr;
                uint8_t type;
                uint8_t len24_hi, len24_mid, len24_lo;
                uint8_t prf_result[12];
        };
-       struct finished record;
+       struct finished *record = tls_get_outbuf(tls, sizeof(*record));
        uint8_t handshake_hash[SHA256_OUTSIZE];
 
-       fill_handshake_record_hdr(&record.xhdr, sizeof(record));
-       record.type = HANDSHAKE_FINISHED;
+       fill_handshake_record_hdr(record, HANDSHAKE_FINISHED, sizeof(*record));
 
        sha256_peek(&tls->handshake_sha256_ctx, handshake_hash);
-       prf_hmac_sha256(record.prf_result, sizeof(record.prf_result),
+       prf_hmac_sha256(record->prf_result, sizeof(record->prf_result),
                        tls->master_secret, sizeof(tls->master_secret),
                        "client finished",
                        handshake_hash, sizeof(handshake_hash)
@@ -1289,13 +1306,10 @@ static void send_client_finished(tls_state_t *tls)
        dump_hex("from secret: %s\n", tls->master_secret, sizeof(tls->master_secret));
        dump_hex("from labelSeed: %s", "client finished", sizeof("client finished")-1);
        dump_hex("%s\n", handshake_hash, sizeof(handshake_hash));
-       dump_hex("=> digest: %s\n", record.prf_result, sizeof(record.prf_result));
-
-//(1) TODO: well, this should be encrypted on send, really.
-//(2) do we really need to also hash it?
+       dump_hex("=> digest: %s\n", record->prf_result, sizeof(record->prf_result));
 
        dbg(">> FINISHED\n");
-       xwrite_and_hash(tls, &record, sizeof(record));
+       xwrite_encrypted(tls, sizeof(*record), RECORD_TYPE_HANDSHAKE);
 }
 
 static void tls_handshake(tls_state_t *tls)
@@ -1376,8 +1390,11 @@ static void tls_handshake(tls_state_t *tls)
        if (len != 1 || memcmp(tls->inbuf, rec_CHANGE_CIPHER_SPEC, 6) != 0)
                tls_error_die(tls);
        dbg("<< CHANGE_CIPHER_SPEC\n");
-       /* all incoming packets now should be encrypted and have IV + MAC + padding */
-       tls->min_encrypted_len_on_read = AES_BLOCKSIZE + SHA256_OUTSIZE + AES_BLOCKSIZE;
+       if (CIPHER_ID == TLS_RSA_WITH_NULL_SHA256)
+               tls->min_encrypted_len_on_read = SHA256_OUTSIZE;
+       else
+               /* all incoming packets now should be encrypted and have IV + MAC + padding */
+               tls->min_encrypted_len_on_read = AES_BLOCKSIZE + SHA256_OUTSIZE + AES_BLOCKSIZE;
 
        /* Get (encrypted) FINISHED from the server */
        len = xread_tls_block(tls);
@@ -1387,6 +1404,12 @@ static void tls_handshake(tls_state_t *tls)
        /* application data can be sent/received */
 }
 
+static void tls_xwrite(tls_state_t *tls, int len)
+{
+       dbg(">> DATA\n");
+       xwrite_encrypted(tls, len, RECORD_TYPE_APPLICATION_DATA);
+}
+
 // To run a test server using openssl:
 // openssl req -x509 -newkey rsa:$((4096/4*3)) -keyout key.pem -out server.pem -nodes -days 99999 -subj '/CN=localhost'
 // openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1
@@ -1400,8 +1423,8 @@ int tls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int tls_main(int argc UNUSED_PARAM, char **argv)
 {
        tls_state_t *tls;
-       len_and_sockaddr *lsa;
-       int fd;
+       fd_set readfds, testfds;
+       int cfd;
 
        // INIT_G();
        // getopt32(argv, "myopts")
@@ -1409,13 +1432,48 @@ int tls_main(int argc UNUSED_PARAM, char **argv)
        if (!argv[1])
                bb_show_usage();
 
-       lsa = xhost2sockaddr(argv[1], 443);
-       fd = xconnect_stream(lsa);
+       cfd = create_and_connect_stream_or_die(argv[1], 443);
 
        tls = new_tls_state();
-       tls->fd = fd;
+       tls->fd = cfd;
        tls_handshake(tls);
 
+       /* Select loop copying stdin to cfd, and cfd to stdout */
+       FD_ZERO(&readfds);
+       FD_SET(cfd, &readfds);
+       FD_SET(STDIN_FILENO, &readfds);
+
+#define iobuf bb_common_bufsiz1
+       setup_common_bufsiz();
+       for (;;) {
+               int nread;
+
+               testfds = readfds;
+
+               if (select(cfd + 1, &testfds, NULL, NULL, NULL) < 0)
+                       bb_perror_msg_and_die("select");
+
+               if (FD_ISSET(STDIN_FILENO, &testfds)) {
+                       void *buf = tls_get_outbuf(tls, COMMON_BUFSIZE);
+                       nread = safe_read(STDIN_FILENO, buf, COMMON_BUFSIZE);
+                       if (nread < 1) {
+//&& errno != EAGAIN
+                               /* Close outgoing half-connection so they get EOF,
+                                * but leave incoming alone so we can see response */
+//                             shutdown(cfd, SHUT_WR);
+                               FD_CLR(STDIN_FILENO, &readfds);
+                       }
+                       tls_xwrite(tls, nread);
+               }
+               if (FD_ISSET(cfd, &testfds)) {
+                       nread = xread_tls_block(tls);
+                       if (nread < 1)
+//if eof, just close stdout, but not exit!
+                               return EXIT_SUCCESS;
+                       xwrite(STDOUT_FILENO, tls->inbuf + 5, nread);
+               }
+       }
+
        return EXIT_SUCCESS;
 }
 /* Unencryped SHA256 example: