buffers_tls.c (5154B)
1 /* Copyright (c) 2001 Matej Pfajfar. 2 * Copyright (c) 2001-2004, Roger Dingledine. 3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 4 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 5 /* See LICENSE for licensing information */ 6 7 /** 8 * \file buffers_tls.c 9 * \brief Read and write data on a tor_tls_t connection from a buf_t object. 10 **/ 11 12 #define BUFFERS_PRIVATE 13 #include "orconfig.h" 14 #include <stddef.h> 15 #include "lib/buf/buffers.h" 16 #include "lib/tls/buffers_tls.h" 17 #include "lib/cc/torint.h" 18 #include "lib/log/log.h" 19 #include "lib/log/util_bug.h" 20 #include "lib/tls/tortls.h" 21 22 #ifdef HAVE_UNISTD_H 23 #include <unistd.h> 24 #endif 25 26 /** As read_to_chunk(), but return (negative) error code on error, blocking, 27 * or TLS, and the number of bytes read otherwise. */ 28 static inline int 29 read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls, 30 size_t at_most) 31 { 32 int read_result; 33 34 tor_assert(CHUNK_REMAINING_CAPACITY(chunk) >= at_most); 35 read_result = tor_tls_read(tls, CHUNK_WRITE_PTR(chunk), at_most); 36 if (read_result < 0) 37 return read_result; 38 buf->datalen += read_result; 39 chunk->datalen += read_result; 40 return read_result; 41 } 42 43 /** As read_to_buf, but reads from a TLS connection, and returns a TLS 44 * status value rather than the number of bytes read. 45 * 46 * Using TLS on OR connections complicates matters in two ways. 47 * 48 * First, a TLS stream has its own read buffer independent of the 49 * connection's read buffer. (TLS needs to read an entire frame from 50 * the network before it can decrypt any data. Thus, trying to read 1 51 * byte from TLS can require that several KB be read from the network 52 * and decrypted. The extra data is stored in TLS's decrypt buffer.) 53 * Because the data hasn't been read by Tor (it's still inside the TLS), 54 * this means that sometimes a connection "has stuff to read" even when 55 * poll() didn't return POLLIN. The tor_tls_get_pending_bytes function is 56 * used in connection.c to detect TLS objects with non-empty internal 57 * buffers and read from them again. 58 * 59 * Second, the TLS stream's events do not correspond directly to network 60 * events: sometimes, before a TLS stream can read, the network must be 61 * ready to write -- or vice versa. 62 * 63 * On success, return the number of bytes read. On error, a TOR_TLS_* negative 64 * code is returned (expect any of them except TOR_TLS_DONE). 65 */ 66 int 67 buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most) 68 { 69 int r = 0; 70 size_t total_read = 0; 71 72 check_no_tls_errors(); 73 74 IF_BUG_ONCE(buf->datalen > BUF_MAX_LEN) 75 return TOR_TLS_ERROR_MISC; 76 IF_BUG_ONCE(buf->datalen > BUF_MAX_LEN - at_most) 77 return TOR_TLS_ERROR_MISC; 78 79 while (at_most > total_read) { 80 size_t readlen = at_most - total_read; 81 chunk_t *chunk; 82 if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) { 83 chunk = buf_add_chunk_with_capacity(buf, at_most, 1); 84 if (readlen > chunk->memlen) 85 readlen = chunk->memlen; 86 } else { 87 size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail); 88 chunk = buf->tail; 89 if (cap < readlen) 90 readlen = cap; 91 } 92 93 r = read_to_chunk_tls(buf, chunk, tls, readlen); 94 if (r < 0) 95 return r; /* Error */ 96 tor_assert(total_read+r <= BUF_MAX_LEN); 97 total_read += r; 98 } 99 return (int)total_read; 100 } 101 102 /** Helper for buf_flush_to_tls(): try to write <b>sz</b> bytes from chunk 103 * <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. (Tries to write 104 * more if there is a forced pending write size.) On success, deduct the 105 * bytes written from *<b>buf_flushlen</b>. Return the number of bytes 106 * written on success, and a TOR_TLS error code on failure or blocking. 107 */ 108 static inline int 109 flush_chunk_tls(tor_tls_t *tls, buf_t *buf, chunk_t *chunk, size_t sz) 110 { 111 int r; 112 size_t forced; 113 char *data; 114 115 forced = tor_tls_get_forced_write_size(tls); 116 if (forced > sz) 117 sz = forced; 118 if (chunk) { 119 data = chunk->data; 120 tor_assert(sz <= chunk->datalen); 121 } else { 122 data = NULL; 123 tor_assert(sz == 0); 124 } 125 r = tor_tls_write(tls, data, sz); 126 if (r < 0) 127 return r; 128 buf_drain(buf, r); 129 log_debug(LD_NET,"flushed %d bytes, %d remain.", 130 r,(int)buf->datalen); 131 return r; 132 } 133 134 /** As buf_flush_to_socket(), but writes data to a TLS connection. Can write 135 * more than <b>flushlen</b> bytes. 136 */ 137 int 138 buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen) 139 { 140 int r; 141 size_t flushed = 0; 142 ssize_t sz; 143 IF_BUG_ONCE(flushlen > buf->datalen) { 144 flushlen = buf->datalen; 145 } 146 sz = (ssize_t) flushlen; 147 148 /* we want to let tls write even if flushlen is zero, because it might 149 * have a partial record pending */ 150 check_no_tls_errors(); 151 152 do { 153 size_t flushlen0; 154 if (buf->head) { 155 if ((ssize_t)buf->head->datalen >= sz) 156 flushlen0 = sz; 157 else 158 flushlen0 = buf->head->datalen; 159 } else { 160 flushlen0 = 0; 161 } 162 163 r = flush_chunk_tls(tls, buf, buf->head, flushlen0); 164 if (r < 0) 165 return r; 166 flushed += r; 167 sz -= r; 168 if (r == 0) /* Can't flush any more now. */ 169 break; 170 } while (sz > 0); 171 tor_assert(flushed <= BUF_MAX_LEN); 172 return (int)flushed; 173 }