diff options
-rw-r--r-- | configure.in | 4 | ||||
-rw-r--r-- | doc/tor-spec.txt | 174 | ||||
-rw-r--r-- | src/common/Makefile.am | 4 | ||||
-rw-r--r-- | src/common/crypto.c | 6 | ||||
-rw-r--r-- | src/common/crypto.h | 6 | ||||
-rw-r--r-- | src/common/tortls.c | 323 | ||||
-rw-r--r-- | src/common/tortls.h | 29 | ||||
-rw-r--r-- | src/or/buffers.c | 33 | ||||
-rw-r--r-- | src/or/or.h | 8 |
9 files changed, 425 insertions, 162 deletions
diff --git a/configure.in b/configure.in index 8adc9415d1..737a431d22 100644 --- a/configure.in +++ b/configure.in @@ -36,7 +36,7 @@ AC_CACHE_CHECK([for OpenSSL directory], ac_cv_openssldir, [ for ssldir in $tryssldir "" /usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /usr/pkg /opt /opt/openssl ; do CPPFLAGS="$saved_CPPFLAGS" LDFLAGS="$saved_LDFLAGS" - LIBS="$saved_LIBS -lcrypto" + LIBS="$saved_LIBS -lcrypto -lssl" # Skip directories if they don't exist if test ! -z "$ssldir" -a ! -d "$ssldir" ; then @@ -126,7 +126,7 @@ if (test ! -z "$ac_cv_openssldir" && test "x$ac_cv_openssldir" != "x(system)") ; fi fi fi -LIBS="$saved_LIBS -lcrypto" +LIBS="$saved_LIBS -lcrypto -lssl" dnl The warning message here is no longer strictly accurate. diff --git a/doc/tor-spec.txt b/doc/tor-spec.txt index 5ba4a468f9..e9e56b10d3 100644 --- a/doc/tor-spec.txt +++ b/doc/tor-spec.txt @@ -42,160 +42,32 @@ each node knows its predecessor and successor, but no others. Traffic flowing down the circuit is unwrapped by a symmetric key at each node, which reveals the downstream node. - 2. Connections -2.1. Establishing connections to onion routers (ORs) - There are two ways to connect to an OR. The first is as an onion - proxy (OP), which allows any node to connect without providing any - authentication or name. The second is as another OR, which allows - strong authentication. In both cases the initiating party (called - the 'client') sets up shared keys with the listening OR (called the - 'server'). - - Before the handshake begins, assume all parties know the {(1024-bit) - public key, IPV4 address, and port} triplet of each OR. - - 1. Client connects to server: - - The client generates a pair of 16-byte symmetric keys (one - [K_f] for the 'forward' stream from client to server, and one - [K_b] for the 'backward' stream from server to client) to be - used for link encryption. - - The client then generates a 'Client authentication' message [M] - containing: - - (If client is an OP) - The number 1 to signify OP handshake [2 bytes] - Forward link key [K_f] [16 bytes] - Backward link key [K_b] [16 bytes] - [Total: 34 bytes] - - (If client is an OR) - The number 2 to signify OR handshake [2 bytes] - The client's published IPV4 address [4 bytes] - The client's published port [2 bytes] - The server's published IPV4 address [4 bytes] - The server's published port [2 bytes] - The forward key [K_f] [16 bytes] - The backward key [K_b] [16 bytes] - [Total: 46 bytes] - - The client then RSA-encrypts [M] with the server's public key - and PKCS1 padding to give an encrypted message. - - The client then opens a TCP connection to the server, sends - the 128-byte RSA-encrypted data to the server, and waits for a - reply. - - 2. The server receives the first handshake: - - The OR waits for 128 bytes of data, and decrypts the resulting - data with its private key, checking the PKCS1 padding. If - the padding is invalid, it closes the connection. If the tag - indicates the client is an OP, and the message is 34 bytes long, - it performs step 2a. If the tag indicates the client is an OR, - and the message is 46 bytes long, it performs step 2b. Else, - it closes the connection. - - 2a. If client is an OP: - - The connection is established, and the OR is ready to receive - cells. The server sets its keys for this connection, setting K_f - to the client's K_b, and K_b to the client's K_f. The handshake - is complete. - - 2b. If the client is an OR: - - The server checks the list of known ORs for one with the address - and port given in the client's authentication. If no such OR - is known, or if the server is already connected to that OR, the - server closes the current TCP connection and stops handshaking. - - The server sets its keys for this connection, setting K_f to - the client's K_b, and K_b to the client's K_f. - - The server then creates a server authentication message [M2] as - follows: - Client's handshake [M] [44 bytes] - A random nonce [N] [8 bytes] - [Total: 52 bytes] - - The server encrypts M2 with the client's public key (found - from the list of known routers), using PKCS1 padding. - - The server sends the 128-byte encrypted message to the client, - and waits for a reply. - - 3. Client authenticates to server. - - Once the client has received 128 bytes, it decrypts them with - its public key, and checks the PKCS1 padding. If the padding - is invalid, or the decrypted message's length is other than 52 - bytes, the client closes the TCP connection. - - The client checks that the addresses and keys in the reply - message are the same as the ones it originally sent. If not, - it closes the TCP connection. - - The client generates the following authentication message [M3]: - The client's published IPV4 address [4 bytes] - The client's published port [2 bytes] - The server's published IPV4 address [4 bytes] - The server's published port [2 bytes] - The server-generated nonce [N] [8 bytes] - [Total: 20 bytes] - - Once again, the client encrypts this message using the - server's public key and PKCS1 padding, and sends the resulting - 128-byte message to the server. - - 4. Server checks client authentication - - The server once again waits to receive 128 bytes from the - client, decrypts the message with its private key, and checks - the PKCS1 padding. If the padding is incorrect, or if the - message's length is other than 20 bytes, the server closes the - TCP connection and stops handshaking. - - If the addresses in the decrypted message M3 match those in M - and M2, and if the nonce in M3 is the same as in M2, the - handshake is complete, and the client and server begin sending - cells to one another. Otherwise, the server closes the TCP - connection. - -2.2. Sending cells and link encryption - - Once the handshake is complete, the two sides send cells - (specified below) to one another. Cells are sent serially, - encrypted with the AES-CTR keystream specified by the handshake - protocol. Over a connection, communicants encrypt outgoing cells - with the connection's K_f, and decrypt incoming cells with the - connection's K_b. - - [Commentary: This means that OR/OP->OR connections are malleable; I - can flip bits in cells as they go across the wire, and see flipped - bits coming out the cells as they are decrypted at the next - server. I need to look more at the data format to see whether - this is exploitable, but if there's no integrity checking there - either, I suspect we may have an attack here. -NM] - [Yes, this protocol is open to tagging attacks. The payloads are - encrypted inside the network, so it's only at the edge node and beyond - that it's a worry. But adversaries can already count packets and - observe/modify timing. It's not worth putting in hashes; indeed, it - would be quite hard, because one of the sides of the circuit doesn't - know the keys that are used for de/encrypting at each hop, so couldn't - craft hashes anyway. See the Bandwidth Throttling (threat model) - thread on http://archives.seul.org/or/dev/Jul-2002/threads.html. -RD] - [Even if I don't control both sides of the connection, I can still - do evil stuff. For instance, if I can guess that a cell is a - TOPIC_COMMAND_BEGIN cell to www.slashdot.org:80 , I can change the - address and port to point to a machine I control. -NM] - [We're going to address this tagging issue with e2e-only hashes. - See TODO file. -RD] - + proxy (OP), which allows the OP to authenticate the OR without + authenticating itself. The second is as another OR, which allows + mutual authentication. + + Tor uses TLS for link encryption, using the cipher suite + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA". An OR always sends a + self-signed X.509 certificate whose commonName is the server's + nickname, and whose public key is in the server directory. + + All parties receiving certificates must confirm that the public + key is as it appears in the server directory, and close the + connection if it does not. + + Once a TLS connection is established, the two sides send cells + (specified below) to one another. Cells are sent serially. All + cells are 256 bytes long. Cells may be sent embedded in TLS + records of any size or divided across TLS records, but the framing + of TLS records should not leak information about the type or + contents of the cells. + + OR-to-OR connections are never deliberately closed. OP-to-OR + connections are closed when the OP has no more circuits running + over a connection, and an amount of time (????) has passed. 3. Cell Packet format diff --git a/src/common/Makefile.am b/src/common/Makefile.am index cdcc367d9b..7bd90b0bf4 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -3,7 +3,7 @@ noinst_LIBRARIES = libor.a #CFLAGS = -Wall -Wpointer-arith -O2 -libor_a_SOURCES = log.c crypto.c fakepoll.c util.c aes.c +libor_a_SOURCES = log.c crypto.c fakepoll.c util.c aes.c tortls.c -noinst_HEADERS = log.h crypto.h fakepoll.h test.h util.h aes.h torint.h +noinst_HEADERS = log.h crypto.h fakepoll.h test.h util.h aes.h torint.h tortls.h diff --git a/src/common/crypto.c b/src/common/crypto.c index da78d06ce3..06e66857e2 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -696,11 +696,6 @@ int crypto_SHA_digest(unsigned char *m, int len, unsigned char *digest) return (SHA1(m,len,digest) == NULL); } - -struct crypto_dh_env_st { - DH *dh; -}; - static BIGNUM *dh_param_p = NULL; static BIGNUM *dh_param_g = NULL; @@ -735,6 +730,7 @@ static void init_dh_param() { supposedly it equals: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }. */ + /* See also rfc 3536 */ r = BN_hex2bn(&p, "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" diff --git a/src/common/crypto.h b/src/common/crypto.h index 181101b592..051251329a 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -7,6 +7,7 @@ #include <stdio.h> #include <openssl/rsa.h> +#include <openssl/dh.h> /* available encryption primitives */ #define CRYPTO_CIPHER_IDENTITY 0 @@ -72,7 +73,10 @@ int base64_encode(char *dest, int destlen, char *src, int srclen); int base64_decode(char *dest, int destlen, char *src, int srclen); /* Key negotiation */ -typedef struct crypto_dh_env_st crypto_dh_env_t; +typedef struct crypto_dh_env_st { + DH *dh; +} crypto_dh_env_t; + /* #define CRYPTO_DH_SIZE (1536 / 8) */ #define CRYPTO_DH_SIZE (1024 / 8) crypto_dh_env_t *crypto_dh_new(); diff --git a/src/common/tortls.c b/src/common/tortls.c new file mode 100644 index 0000000000..9e964de6e6 --- /dev/null +++ b/src/common/tortls.c @@ -0,0 +1,323 @@ +/* Copyright 2003 Roger Dingledine. */ +/* See LICENSE for licensing information */ +/* $Id$ */ + +/* TLS wrappers for The Onion Router. (Unlike other tor functions, these + * are prefixed with tor_ in order to avoid conflicting with OpenSSL + * functions and variables.) + */ + +#include "./crypto.h" +#include "./tortls.h" +#include "./util.h" + +#include <assert.h> +#include <openssl/ssl.h> +#include <openssl/err.h> +#include <openssl/tls1.h> +#include <openssl/asn1.h> +#include <openssl/bio.h> + +struct tor_tls_context_st { + SSL_CTX *ctx; +}; + +struct tor_tls_st { + SSL *ssl; + int socket; + enum { + TOR_TLS_ST_HANDSHAKE, TOR_TLS_ST_OPEN, TOR_TLS_ST_GOTCLOSE, + TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED + } state; + int isServer; +}; + +#define _TOR_TLS_SYSCALL -6 +#define _TOR_TLS_ZERORETURN -5 + +static int +tor_tls_get_error(tor_tls *tls, int r, int extra) +{ + int err = SSL_get_error(tls->ssl, r); + switch (err) { + case SSL_ERROR_NONE: + return TOR_TLS_DONE; + case SSL_ERROR_WANT_READ: + return TOR_TLS_WANTREAD; + case SSL_ERROR_WANT_WRITE: + return TOR_TLS_WANTWRITE; + case SSL_ERROR_SYSCALL: + return extra ? _TOR_TLS_SYSCALL : TOR_TLS_ERROR; + case SSL_ERROR_ZERO_RETURN: + return extra ? _TOR_TLS_ZERORETURN : TOR_TLS_ERROR; + default: + return TOR_TLS_ERROR; + } +} + +static int always_accept_verify_cb(int preverify_ok, + X509_STORE_CTX *x509_ctx) +{ + /* XXXX Actually, this needs to get more complicated. But for now, + XXXX always accept peer certs. */ + return 1; +} + +/* Generate a self-signed certificate with the private key 'rsa' and + * commonName 'nickname', and write it, PEM-encoded, to the file named + * by 'certfile'. Return 0 on success, -1 for failure. + */ +int +tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname) +{ + RSA *_rsa = NULL; + time_t start_time, end_time; + EVP_PKEY *pkey = NULL; + X509 *x509 = NULL; + X509_NAME *name = NULL; + BIO *out = NULL; + int nid; + + start_time = time(NULL); + + assert(rsa && rsa->type == CRYPTO_PK_RSA); + if (!(_rsa = RSAPrivateKey_dup((RSA*)rsa->key))) + return -1; + if (!(pkey = EVP_PKEY_new())) + return -1; + if (!(EVP_PKEY_assign_RSA(pkey, _rsa))) + return -1; + if (!(x509 = X509_new())) + return -1; + if (!(X509_set_version(x509, 2))) + return -1; + if (!(ASN1_INTEGER_set(X509_get_serialNumber(x509), (long)start_time))) + return -1; + + if (!(name = X509_NAME_new())) + return -1; + if ((nid = OBJ_txt2nid("organizationName")) != NID_undef) return -1; + if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, + "TOR", -1, -1, 0))) return -1; + if ((nid = OBJ_txt2nid("commonName")) != NID_undef) return -1; + if (!(X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, + nickname, -1, -1, 0))) return -1; + + if (!(X509_set_issuer_name(x509, name))) + return -1; + if (!(X509_set_subject_name(x509, name))) + return -1; + if (!X509_time_adj(X509_get_notBefore(x509),0,&start_time)) + return -1; + end_time = start_time + 24*60*60*365; + if (!X509_time_adj(X509_get_notAfter(x509),0,&end_time)) + return -1; + if (!X509_set_pubkey(x509, pkey)) + return -1; + if (!X509_sign(x509, pkey, EVP_sha1())) + return -1; + if (!(out = BIO_new_file(certfile, "w"))) + return -1; + if (!(PEM_write_bio_X509(out, x509))) + return -1; + BIO_free(out); + X509_free(x509); + EVP_PKEY_free(pkey); + X509_NAME_free(name); + return 0; +} + +/* Create a new TLS context. If we are going to be using it as a + * server, it must have isServer set to true, certfile set to a + * filename for a certificate file, and RSA set to the private key + * used for that certificate. + */ +tor_tls_context * +tor_tls_context_new(char *certfile, crypto_pk_env_t *rsa, int isServer) +{ + assert(!rsa || rsa->type == CRYPTO_PK_RSA); + assert((certfile && rsa) || (!certfile && !rsa)); + crypto_dh_env_t *dh = NULL; + RSA *_rsa = NULL; + EVP_PKEY *pkey = NULL; + tor_tls_context *result; + + result = tor_malloc(sizeof(tor_tls_context)); + if (!(result->ctx = SSL_CTX_new(TLSv1_method()))) + return NULL; + /* XXXX This should use AES, but we'll need to require OpenSSL 0.9.7 first */ + if (!SSL_CTX_set_cipher_list(result->ctx, TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA)) + /* TLS1_TXT_DHE_RSA_WITH_AES_128_SHA)) */ + return NULL; + if (certfile && !SSL_CTX_use_certificate_file(result->ctx,certfile, + SSL_FILETYPE_PEM)) + return NULL; + SSL_CTX_set_session_cache_mode(result->ctx, SSL_SESS_CACHE_OFF); + if (rsa) { + if (!(_rsa = RSAPrivateKey_dup((RSA*)rsa->key))) + return NULL; + if (!(pkey = EVP_PKEY_new())) + return NULL; + if (!EVP_PKEY_assign_RSA(pkey, _rsa)) + return NULL; + if (!SSL_CTX_use_PrivateKey(result->ctx, pkey)) + return NULL; + EVP_PKEY_free(pkey); + if (certfile) { + if (!SSL_CTX_check_private_key(result->ctx)) + return NULL; + } + } + dh = crypto_dh_new(); + SSL_CTX_set_tmp_dh(result->ctx, dh->dh); + crypto_dh_free(dh); + SSL_CTX_set_verify(result->ctx, SSL_VERIFY_PEER, + always_accept_verify_cb); + + return result; +} + +/* Create a new TLS object from a TLS context, a filedescriptor, and + * a flag to determine whether it is functioning as a server. + */ +tor_tls * +tor_tls_new(tor_tls_context *ctx, int sock, int isServer) +{ + tor_tls *result = tor_malloc(sizeof(tor_tls)); + if (!(result->ssl = SSL_new(ctx->ctx))) + return NULL; + result->socket = sock; + SSL_set_fd(result->ssl, sock); + result->state = TOR_TLS_ST_HANDSHAKE; + result->isServer = isServer; + return result; +} + +/* Release resources associated with a TLS object. Does not close the + * underlying file descriptor. + */ +void +tor_tls_free(tor_tls *tls) +{ + SSL_free(tls->ssl); + free(tls); +} + +/* Underlying function for TLS reading. Reads up to 'len' characters + * from 'tls' into 'cp'. On success, returns the number of characters + * read. On failure, returns TOR_TLS_ERROR, TOR_TLS_CLOSE, + * TOR_TLS_WANTREAD, or TOR_TLS_WANTWRITE. + */ +int +tor_tls_read(tor_tls *tls, char *cp, int len) +{ + int r, err; + assert(tls && tls->ssl); + assert(tls->state == TOR_TLS_ST_OPEN); + r = SSL_read(tls->ssl, cp, len); + if (r > 0) + return r; + err = tor_tls_get_error(tls, r, 1); + if (err == _TOR_TLS_SYSCALL) + return TOR_TLS_ERROR; + else if (err == _TOR_TLS_ZERORETURN) { + tls->state = TOR_TLS_ST_CLOSED; + return TOR_TLS_CLOSE; + } else { + /* XXXX Make sure it's not TOR_TLS_DONE. */ + return err; + } +} + +/* Underlying function for TLS writing. Write up to 'n' characters + * from 'cp' onto 'tls'. On success, returns the number of characters + * written. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, + * or TOR_TLS_WANTWRITE. + */ +int +tor_tls_write(tor_tls *tls, char *cp, int n) +{ + int r, err; + assert(tls && tls->ssl); + assert(tls->state == TOR_TLS_ST_OPEN); + r = SSL_write(tls->ssl, cp, n); + err = tor_tls_get_error(tls, r, 1); + if (err == _TOR_TLS_ZERORETURN) { + /* should never happen XXXX */ + return 0; + } else if (err == TOR_TLS_DONE) { + return r; + } else { + return err; + } +} + +/* Perform initial handshake on 'tls'. When finished, returns + * TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, + * or TOR_TLS_WANNTWRITE. + */ +int +tor_tls_handshake(tor_tls *tls) +{ + int r; + assert(tls && tls->ssl); + assert(tls->state == TOR_TLS_ST_HANDSHAKE); + if (tls->isServer) { + r = SSL_accept(tls->ssl); + } else { + r = SSL_connect(tls->ssl); + } + r = tor_tls_get_error(tls,r,0); + if (r == TOR_TLS_DONE) { + tls->state = TOR_TLS_ST_OPEN; + } + return r; +} + +/* Shut down an open tls connection 'tls'. When finished, returns + * TOR_TLS_DONE. On failure, returns TOR_TLS_ERROR, TOR_TLS_WANTREAD, + * or TOR_TLS_WANTWRITE. + */ +int +tor_tls_shutdown(tor_tls *tls) +{ + int r, err; + char buf[128]; + assert(tls && tls->ssl); + + if (tls->state == TOR_TLS_ST_SENTCLOSE) { + do { + r = SSL_read(tls->ssl, buf, 128); + } while (r>0); + err = tor_tls_get_error(tls, r, 1); + if (err == _TOR_TLS_ZERORETURN) { + tls->state = TOR_TLS_ST_GOTCLOSE; + /* fall through */ + } else { + if (err == _TOR_TLS_SYSCALL) + err = TOR_TLS_ERROR; + return err; + } + } + + r = SSL_shutdown(tls->ssl); + if (r == 1) { + tls->state = TOR_TLS_ST_CLOSED; + return TOR_TLS_DONE; + } + err = tor_tls_get_error(tls, r, 1); + if (err == _TOR_TLS_SYSCALL) + return TOR_TLS_ST_CLOSED; /* XXXX is this right? */ + else if (err == _TOR_TLS_ZERORETURN) { + if (tls->state == TOR_TLS_ST_GOTCLOSE || + tls->state == TOR_TLS_ST_SENTCLOSE) { + /* XXXX log; unexpected. */ + return TOR_TLS_ERROR; + } + tls->state = TOR_TLS_ST_SENTCLOSE; + return tor_tls_shutdown(tls); + } else { + /* XXXX log if not error. */ + return err; + } +} diff --git a/src/common/tortls.h b/src/common/tortls.h new file mode 100644 index 0000000000..fa1b72f205 --- /dev/null +++ b/src/common/tortls.h @@ -0,0 +1,29 @@ +/* Copyright 2003 Roger Dingledine */ +/* See LICENSE for licensing information */ +/* $Id$ */ + +#ifndef _TORTLS_H +#define _TORTLS_H + +#include "../common/crypto.h" + +typedef struct tor_tls_context_st tor_tls_context; +typedef struct tor_tls_st tor_tls; + +#define TOR_TLS_ERROR -4 +#define TOR_TLS_CLOSE -3 +#define TOR_TLS_WANTREAD -2 +#define TOR_TLS_WANTWRITE -1 +#define TOR_TLS_DONE 0 + +int tor_tls_write_certificate(char *certfile, crypto_pk_env_t *rsa, char *nickname); +tor_tls_context *tor_tls_context_new(char *certfile, crypto_pk_env_t *rsa, int isServer); +tor_tls *tor_tls_new(tor_tls_context *ctx, int sock, int isServer); +void tor_tls_free(tor_tls *tls); +int tor_tls_read(tor_tls *tls, char *cp, int len); +int tor_tls_write(tor_tls *tls, char *cp, int n); +int tor_tls_handshake(tor_tls *tls); +/* XXXX we need a function to check for validated, verified peer certs. */ +int tor_tls_shutdown(tor_tls *tls); + +#endif diff --git a/src/or/buffers.c b/src/or/buffers.c index 3ea26dbabb..2cf313f10d 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -86,6 +86,23 @@ int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, i } } +int read_to_buf_tls(tor_tls *tls, int at_most, char **buf, int *buflen, int *buf_datalen) { + int r; + assert(tls && *buf && buflen && buf_datalen); + + if (at_most > *buflen - *buf_datalen) + at_most = *buflen - *buf_datalen; + + if (at_most == 0) + return 0; + + r = tor_tls_read(tls, *buf+*buf_datalen, at_most); + if (r<0) + return r; + *buf_datalen += r; + return r; +} + int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen) { /* push from buf onto s @@ -127,6 +144,22 @@ int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datale } } +int flush_buf_tls(tor_tls *tls, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen) +{ + int r; + assert(tls && *buf && buflen && buf_datalen); + if (*buf_flushlen == 0) + return 0; + r = tor_tls_write(tls, *buf, *buf_flushlen); + if (r < 0) { + return r; + } + *buf_datalen -= r; + *buf_flushlen -= r; + memmove(*buf, *buf+r, *buf_datalen); + return r; +} + int write_to_buf(char *string, int string_len, char **buf, int *buflen, int *buf_datalen) { diff --git a/src/or/or.h b/src/or/or.h index 9a8bb36276..7937a8333c 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -90,6 +90,7 @@ #endif #include "../common/crypto.h" +#include "../common/tortls.h" #include "../common/log.h" #include "../common/util.h" @@ -482,11 +483,17 @@ void buf_free(char *buf); int read_to_buf(int s, int at_most, char **buf, int *buflen, int *buf_datalen, int *reached_eof); /* grab from s, put onto buf, return how many bytes read */ +int read_to_buf_tls(tor_tls *tls, int at_most, char **buf, int *buflen, int *buf_datalen); + /* grab from s, put onto buf, return how many bytes read or a TLS + * status (same status codes as tor_tls_read) */ int flush_buf(int s, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen); /* push from buf onto s * then memmove to front of buf * return -1 or how many bytes remain on the buf */ +int flush_buf_tls(tor_tls *tls, char **buf, int *buflen, int *buf_flushlen, int *buf_datalen); + /* As flush_buf, but returns number of bytes written or TLS status + * (same status codes as tor_tls_write) */ int write_to_buf(char *string, int string_len, char **buf, int *buflen, int *buf_datalen); @@ -494,7 +501,6 @@ int write_to_buf(char *string, int string_len, * return total number of bytes on the buf */ - int fetch_from_buf(char *string, int string_len, char **buf, int *buflen, int *buf_datalen); /* if there is string_len bytes in buf, write them onto string, |