mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-30 15:43:32 +01:00
Use trunnel for crypto_pwbox encoding/decoding.
This reduces the likelihood that I have made any exploitable errors in the encoding/decoding. This commit also imports the trunnel runtime source into Tor.
This commit is contained in:
parent
3011149401
commit
3b7d0ed08e
4
.gitignore
vendored
4
.gitignore
vendored
@ -170,6 +170,10 @@
|
|||||||
/src/tools/Makefile
|
/src/tools/Makefile
|
||||||
/src/tools/Makefile.in
|
/src/tools/Makefile.in
|
||||||
|
|
||||||
|
# /src/trunnel/
|
||||||
|
/src/trunnel/libor-trunnel-testing.a
|
||||||
|
/src/trunnel/libor-trunnel.a
|
||||||
|
|
||||||
# /src/tools/tor-fw-helper/
|
# /src/tools/tor-fw-helper/
|
||||||
/src/tools/tor-fw-helper/tor-fw-helper
|
/src/tools/tor-fw-helper/tor-fw-helper
|
||||||
/src/tools/tor-fw-helper/tor-fw-helper.exe
|
/src/tools/tor-fw-helper/tor-fw-helper.exe
|
||||||
|
@ -23,7 +23,6 @@ include src/include.am
|
|||||||
include doc/include.am
|
include doc/include.am
|
||||||
include contrib/include.am
|
include contrib/include.am
|
||||||
|
|
||||||
|
|
||||||
EXTRA_DIST+= \
|
EXTRA_DIST+= \
|
||||||
ChangeLog \
|
ChangeLog \
|
||||||
INSTALL \
|
INSTALL \
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
#include "crypto_pwbox.h"
|
#include "crypto_pwbox.h"
|
||||||
#include "di_ops.h"
|
#include "di_ops.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "pwbox.h"
|
||||||
|
|
||||||
/* 7 bytes "TORBOX0"
|
/* 8 bytes "TORBOX00"
|
||||||
1 byte: header len (H)
|
1 byte: header len (H)
|
||||||
H bytes: header, denoting secret key algorithm.
|
H bytes: header, denoting secret key algorithm.
|
||||||
16 bytes: IV
|
16 bytes: IV
|
||||||
@ -16,7 +17,7 @@
|
|||||||
32 bytes: HMAC-SHA256 of all previous bytes.
|
32 bytes: HMAC-SHA256 of all previous bytes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MAX_OVERHEAD (S2K_MAXLEN + 8 + 32 + CIPHER_IV_LEN)
|
#define MAX_OVERHEAD (S2K_MAXLEN + 8 + 1 + 32 + CIPHER_IV_LEN)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make an authenticated passphrase-encrypted blob to encode the
|
* Make an authenticated passphrase-encrypted blob to encode the
|
||||||
@ -32,31 +33,34 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out,
|
|||||||
const char *secret, size_t secret_len,
|
const char *secret, size_t secret_len,
|
||||||
unsigned s2k_flags)
|
unsigned s2k_flags)
|
||||||
{
|
{
|
||||||
uint8_t *result, *encrypted_portion, *hmac, *iv;
|
uint8_t *result = NULL, *encrypted_portion;
|
||||||
size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128);
|
size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128);
|
||||||
size_t result_len = encrypted_len + MAX_OVERHEAD;
|
ssize_t result_len;
|
||||||
int spec_len;
|
int spec_len;
|
||||||
uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
|
uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
|
||||||
|
pwbox_encoded_t *enc = NULL;
|
||||||
|
ssize_t enc_len;
|
||||||
|
|
||||||
crypto_cipher_t *cipher;
|
crypto_cipher_t *cipher;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
/* Allocate a buffer and put things in the right place. */
|
enc = pwbox_encoded_new();
|
||||||
result = tor_malloc_zero(result_len);
|
|
||||||
memcpy(result, "TORBOX0", 7);
|
|
||||||
|
|
||||||
spec_len = secret_to_key_make_specifier(result + 8,
|
pwbox_encoded_setlen_skey_header(enc, S2K_MAXLEN);
|
||||||
result_len - 8,
|
|
||||||
s2k_flags);
|
spec_len = secret_to_key_make_specifier(
|
||||||
if (spec_len < 0 || spec_len > 255)
|
pwbox_encoded_getarray_skey_header(enc),
|
||||||
|
S2K_MAXLEN,
|
||||||
|
s2k_flags);
|
||||||
|
if (spec_len < 0 || spec_len > S2K_MAXLEN)
|
||||||
goto err;
|
goto err;
|
||||||
result[7] = (uint8_t) spec_len;
|
pwbox_encoded_setlen_skey_header(enc, spec_len);
|
||||||
|
enc->header_len = spec_len;
|
||||||
|
|
||||||
tor_assert(8 + spec_len + CIPHER_IV_LEN + encrypted_len <= result_len);
|
crypto_rand((char*)enc->iv, sizeof(enc->iv));
|
||||||
|
|
||||||
iv = result + 8 + spec_len;
|
pwbox_encoded_setlen_data(enc, encrypted_len);
|
||||||
encrypted_portion = result + 8 + spec_len + CIPHER_IV_LEN;
|
encrypted_portion = pwbox_encoded_getarray_data(enc);
|
||||||
hmac = encrypted_portion + encrypted_len;
|
|
||||||
|
|
||||||
set_uint32(encrypted_portion, htonl(input_len));
|
set_uint32(encrypted_portion, htonl(input_len));
|
||||||
memcpy(encrypted_portion+4, input, input_len);
|
memcpy(encrypted_portion+4, input, input_len);
|
||||||
@ -64,24 +68,32 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out,
|
|||||||
/* Now that all the data is in position, derive some keys, encrypt, and
|
/* Now that all the data is in position, derive some keys, encrypt, and
|
||||||
* digest */
|
* digest */
|
||||||
if (secret_to_key_derivekey(keys, sizeof(keys),
|
if (secret_to_key_derivekey(keys, sizeof(keys),
|
||||||
result+8, spec_len,
|
pwbox_encoded_getarray_skey_header(enc),
|
||||||
|
spec_len,
|
||||||
secret, secret_len) < 0)
|
secret, secret_len) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
crypto_rand((char*)iv, CIPHER_IV_LEN);
|
cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
|
||||||
|
|
||||||
cipher = crypto_cipher_new_with_iv((char*)keys, (char*)iv);
|
|
||||||
crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len);
|
crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len);
|
||||||
crypto_cipher_free(cipher);
|
crypto_cipher_free(cipher);
|
||||||
|
|
||||||
crypto_hmac_sha256((char*)hmac,
|
result_len = pwbox_encoded_encoded_len(enc);
|
||||||
|
if (result_len < 0)
|
||||||
|
goto err;
|
||||||
|
result = tor_malloc(result_len);
|
||||||
|
enc_len = pwbox_encoded_encode(result, result_len, enc);
|
||||||
|
if (enc_len < 0)
|
||||||
|
goto err;
|
||||||
|
tor_assert(enc_len == result_len);
|
||||||
|
|
||||||
|
crypto_hmac_sha256((char*) result + result_len - 32,
|
||||||
(const char*)keys + CIPHER_KEY_LEN,
|
(const char*)keys + CIPHER_KEY_LEN,
|
||||||
sizeof(keys)-CIPHER_KEY_LEN,
|
DIGEST256_LEN,
|
||||||
(const char*)result,
|
(const char*)result,
|
||||||
8 + CIPHER_IV_LEN + spec_len + encrypted_len);
|
result_len - 32);
|
||||||
|
|
||||||
*out = result;
|
*out = result;
|
||||||
*outlen_out = 8 + CIPHER_IV_LEN + spec_len + encrypted_len + DIGEST256_LEN;
|
*outlen_out = result_len;
|
||||||
rv = 0;
|
rv = 0;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -90,6 +102,7 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out,
|
|||||||
rv = -1;
|
rv = -1;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
pwbox_encoded_free(enc);
|
||||||
memwipe(keys, 0, sizeof(keys));
|
memwipe(keys, 0, sizeof(keys));
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -109,47 +122,47 @@ crypto_unpwbox(uint8_t **out, size_t *outlen_out,
|
|||||||
const char *secret, size_t secret_len)
|
const char *secret, size_t secret_len)
|
||||||
{
|
{
|
||||||
uint8_t *result = NULL;
|
uint8_t *result = NULL;
|
||||||
const uint8_t *encrypted, *iv;
|
const uint8_t *encrypted;
|
||||||
uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
|
uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
|
||||||
size_t spec_bytes;
|
|
||||||
uint8_t hmac[DIGEST256_LEN];
|
uint8_t hmac[DIGEST256_LEN];
|
||||||
uint32_t result_len;
|
uint32_t result_len;
|
||||||
|
size_t encrypted_len;
|
||||||
crypto_cipher_t *cipher = NULL;
|
crypto_cipher_t *cipher = NULL;
|
||||||
int rv = UNPWBOX_CORRUPTED;
|
int rv = UNPWBOX_CORRUPTED;
|
||||||
|
ssize_t got_len;
|
||||||
|
|
||||||
if (input_len < 32)
|
pwbox_encoded_t *enc = NULL;
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (tor_memneq(inp, "TORBOX0", 7))
|
got_len = pwbox_encoded_parse(&enc, inp, input_len);
|
||||||
goto err;
|
if (got_len < 0 || (size_t)got_len != input_len)
|
||||||
|
|
||||||
spec_bytes = inp[7];
|
|
||||||
if (input_len < 8 + spec_bytes)
|
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
/* Now derive the keys and check the hmac. */
|
/* Now derive the keys and check the hmac. */
|
||||||
if (secret_to_key_derivekey(keys, sizeof(keys),
|
if (secret_to_key_derivekey(keys, sizeof(keys),
|
||||||
inp+8, spec_bytes,
|
pwbox_encoded_getarray_skey_header(enc),
|
||||||
|
pwbox_encoded_getlen_skey_header(enc),
|
||||||
secret, secret_len) < 0)
|
secret, secret_len) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
crypto_hmac_sha256((char *)hmac,
|
crypto_hmac_sha256((char *)hmac,
|
||||||
(const char*)keys + CIPHER_KEY_LEN, sizeof(keys)-CIPHER_KEY_LEN,
|
(const char*)keys + CIPHER_KEY_LEN, DIGEST256_LEN,
|
||||||
(const char*)inp, input_len - DIGEST256_LEN);
|
(const char*)inp, input_len - DIGEST256_LEN);
|
||||||
|
|
||||||
if (tor_memneq(hmac, inp + input_len - DIGEST256_LEN, DIGEST256_LEN)) {
|
if (tor_memneq(hmac, enc->hmac, DIGEST256_LEN)) {
|
||||||
rv = UNPWBOX_BAD_SECRET;
|
rv = UNPWBOX_BAD_SECRET;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
iv = inp + 8 + spec_bytes;
|
|
||||||
encrypted = inp + 8 + spec_bytes + CIPHER_IV_LEN;
|
|
||||||
|
|
||||||
/* How long is the plaintext? */
|
/* How long is the plaintext? */
|
||||||
cipher = crypto_cipher_new_with_iv((char*)keys, (char*)iv);
|
encrypted = pwbox_encoded_getarray_data(enc);
|
||||||
|
encrypted_len = pwbox_encoded_getlen_data(enc);
|
||||||
|
if (encrypted_len < 4)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
|
||||||
crypto_cipher_decrypt(cipher, (char*)&result_len, (char*)encrypted, 4);
|
crypto_cipher_decrypt(cipher, (char*)&result_len, (char*)encrypted, 4);
|
||||||
result_len = ntohl(result_len);
|
result_len = ntohl(result_len);
|
||||||
if (input_len < 8 + spec_bytes + 4 + result_len + 32)
|
if (encrypted_len < result_len + 4)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
/* Allocate a buffer and decrypt */
|
/* Allocate a buffer and decrypt */
|
||||||
@ -167,6 +180,7 @@ crypto_unpwbox(uint8_t **out, size_t *outlen_out,
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
crypto_cipher_free(cipher);
|
crypto_cipher_free(cipher);
|
||||||
|
pwbox_encoded_free(enc);
|
||||||
memwipe(keys, 0, sizeof(keys));
|
memwipe(keys, 0, sizeof(keys));
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ EXTRA_DIST+= \
|
|||||||
src/common/Makefile.nmake
|
src/common/Makefile.nmake
|
||||||
|
|
||||||
#CFLAGS = -Wall -Wpointer-arith -O2
|
#CFLAGS = -Wall -Wpointer-arith -O2
|
||||||
AM_CPPFLAGS += -I$(srcdir)/src/common -Isrc/common
|
AM_CPPFLAGS += -I$(srcdir)/src/common -Isrc/common -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel
|
||||||
|
|
||||||
if USE_OPENBSD_MALLOC
|
if USE_OPENBSD_MALLOC
|
||||||
libor_extra_source=src/ext/OpenBSD_malloc_Linux.c
|
libor_extra_source=src/ext/OpenBSD_malloc_Linux.c
|
||||||
@ -69,6 +69,7 @@ LIBOR_A_SOURCES = \
|
|||||||
src/common/util_process.c \
|
src/common/util_process.c \
|
||||||
src/common/sandbox.c \
|
src/common/sandbox.c \
|
||||||
src/ext/csiphash.c \
|
src/ext/csiphash.c \
|
||||||
|
src/ext/trunnel/trunnel.c \
|
||||||
$(libor_extra_source) \
|
$(libor_extra_source) \
|
||||||
$(libor_mempool_source)
|
$(libor_mempool_source)
|
||||||
|
|
||||||
@ -80,6 +81,7 @@ LIBOR_CRYPTO_A_SOURCES = \
|
|||||||
src/common/crypto_format.c \
|
src/common/crypto_format.c \
|
||||||
src/common/torgzip.c \
|
src/common/torgzip.c \
|
||||||
src/common/tortls.c \
|
src/common/tortls.c \
|
||||||
|
src/trunnel/pwbox.c \
|
||||||
$(libcrypto_extra_source)
|
$(libcrypto_extra_source)
|
||||||
|
|
||||||
LIBOR_EVENT_A_SOURCES = \
|
LIBOR_EVENT_A_SOURCES = \
|
||||||
|
306
src/ext/trunnel/trunnel-impl.h
Normal file
306
src/ext/trunnel/trunnel-impl.h
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
/* trunnel-impl.h -- Implementation helpers for trunnel, included by
|
||||||
|
* generated trunnel files
|
||||||
|
*
|
||||||
|
* Copyright 2014, The Tor Project, Inc.
|
||||||
|
* See license at the end of this file for copying information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TRUNNEL_IMPL_H_INCLUDED_
|
||||||
|
#define TRUNNEL_IMPL_H_INCLUDED_
|
||||||
|
#include "trunnel.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef TRUNNEL_LOCAL_H
|
||||||
|
#include "trunnel-local.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define uint8_t unsigned char
|
||||||
|
#define uint16_t unsigned short
|
||||||
|
#define uint32_t unsigned int
|
||||||
|
#define uint64_t unsigned __int64
|
||||||
|
#define inline __inline
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
uint32_t trunnel_htonl(uint32_t a);
|
||||||
|
uint32_t trunnel_ntohl(uint32_t a);
|
||||||
|
uint16_t trunnel_htons(uint16_t a);
|
||||||
|
uint16_t trunnel_ntohs(uint16_t a);
|
||||||
|
#else
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#define trunnel_htonl(x) htonl(x)
|
||||||
|
#define trunnel_htons(x) htons(x)
|
||||||
|
#define trunnel_ntohl(x) ntohl(x)
|
||||||
|
#define trunnel_ntohs(x) ntohs(x)
|
||||||
|
#endif
|
||||||
|
uint64_t trunnel_htonll(uint64_t a);
|
||||||
|
uint64_t trunnel_ntohll(uint64_t a);
|
||||||
|
|
||||||
|
#ifndef trunnel_assert
|
||||||
|
#define trunnel_assert(x) assert(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
trunnel_set_uint64(void *p, uint64_t v) {
|
||||||
|
memcpy(p, &v, 8);
|
||||||
|
}
|
||||||
|
static inline void
|
||||||
|
trunnel_set_uint32(void *p, uint32_t v) {
|
||||||
|
memcpy(p, &v, 4);
|
||||||
|
}
|
||||||
|
static inline void
|
||||||
|
trunnel_set_uint16(void *p, uint16_t v) {
|
||||||
|
memcpy(p, &v, 2);
|
||||||
|
}
|
||||||
|
static inline void
|
||||||
|
trunnel_set_uint8(void *p, uint8_t v) {
|
||||||
|
memcpy(p, &v, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t
|
||||||
|
trunnel_get_uint64(const void *p) {
|
||||||
|
uint64_t x;
|
||||||
|
memcpy(&x, p, 8);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
static inline uint32_t
|
||||||
|
trunnel_get_uint32(const void *p) {
|
||||||
|
uint32_t x;
|
||||||
|
memcpy(&x, p, 4);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
static inline uint16_t
|
||||||
|
trunnel_get_uint16(const void *p) {
|
||||||
|
uint16_t x;
|
||||||
|
memcpy(&x, p, 2);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
static inline uint8_t
|
||||||
|
trunnel_get_uint8(const void *p) {
|
||||||
|
return *(const uint8_t*)p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef TRUNNEL_DEBUG_FAILING_ALLOC
|
||||||
|
extern int trunnel_provoke_alloc_failure;
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
trunnel_malloc(size_t n)
|
||||||
|
{
|
||||||
|
if (trunnel_provoke_alloc_failure) {
|
||||||
|
if (--trunnel_provoke_alloc_failure == 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return malloc(n);
|
||||||
|
}
|
||||||
|
static inline void *
|
||||||
|
trunnel_calloc(size_t a, size_t b)
|
||||||
|
{
|
||||||
|
if (trunnel_provoke_alloc_failure) {
|
||||||
|
if (--trunnel_provoke_alloc_failure == 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return calloc(a,b);
|
||||||
|
}
|
||||||
|
static inline char *
|
||||||
|
trunnel_strdup(const char *s)
|
||||||
|
{
|
||||||
|
if (trunnel_provoke_alloc_failure) {
|
||||||
|
if (--trunnel_provoke_alloc_failure == 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return strdup(s);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#ifndef trunnel_malloc
|
||||||
|
#define trunnel_malloc(x) (malloc((x)))
|
||||||
|
#endif
|
||||||
|
#ifndef trunnel_calloc
|
||||||
|
#define trunnel_calloc(a,b) (calloc((a),(b)))
|
||||||
|
#endif
|
||||||
|
#ifndef trunnel_strdup
|
||||||
|
#define trunnel_strdup(s) (strdup((s)))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef trunnel_realloc
|
||||||
|
#define trunnel_realloc(a,b) realloc((a),(b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef trunnel_free_
|
||||||
|
#define trunnel_free_(x) (free(x))
|
||||||
|
#endif
|
||||||
|
#define trunnel_free(x) ((x) ? (trunnel_free_(x),0) : (0))
|
||||||
|
|
||||||
|
#ifndef trunnel_abort
|
||||||
|
#define trunnel_abort() abort()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef trunnel_memwipe
|
||||||
|
#define trunnel_memwipe(mem, len) ((void)0)
|
||||||
|
#define trunnel_wipestr(s) ((void)0)
|
||||||
|
#else
|
||||||
|
#define trunnel_wipestr(s) do { \
|
||||||
|
if (s) \
|
||||||
|
trunnel_memwipe(s, strlen(s)); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ====== dynamic arrays ======== */
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define TRUNNEL_DYNARRAY_GET(da, n) \
|
||||||
|
((da)->elts_[(n)])
|
||||||
|
#else
|
||||||
|
/** Return the 'n'th element of 'da'. */
|
||||||
|
#define TRUNNEL_DYNARRAY_GET(da, n) \
|
||||||
|
(((n) >= (da)->n_ ? (trunnel_abort(),0) : 0), (da)->elts_[(n)])
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Change the 'n'th element of 'da' to 'v'. */
|
||||||
|
#define TRUNNEL_DYNARRAY_SET(da, n, v) do { \
|
||||||
|
trunnel_assert((n) < (da)->n_); \
|
||||||
|
(da)->elts_[(n)] = (v); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/** Expand the dynamic array 'da' of 'elttype' so that it can hold at least
|
||||||
|
* 'howmanymore' elements than its current capacity. Always tries to increase
|
||||||
|
* the length of the array. On failure, run the code in 'on_fail' and goto
|
||||||
|
* trunnel_alloc_failed. */
|
||||||
|
#define TRUNNEL_DYNARRAY_EXPAND(elttype, da, howmanymore, on_fail) do { \
|
||||||
|
elttype *newarray; \
|
||||||
|
newarray = trunnel_dynarray_expand(&(da)->allocated_, \
|
||||||
|
(da)->elts_, (howmanymore), \
|
||||||
|
sizeof(elttype)); \
|
||||||
|
if (newarray == NULL) { \
|
||||||
|
on_fail; \
|
||||||
|
goto trunnel_alloc_failed; \
|
||||||
|
} \
|
||||||
|
(da)->elts_ = newarray; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/** Add 'v' to the end of the dynamic array 'da' of 'elttype', expanding it if
|
||||||
|
* necessary. code in 'on_fail' and goto trunnel_alloc_failed. */
|
||||||
|
#define TRUNNEL_DYNARRAY_ADD(elttype, da, v, on_fail) do { \
|
||||||
|
if ((da)->n_ == (da)->allocated_) { \
|
||||||
|
TRUNNEL_DYNARRAY_EXPAND(elttype, da, 1, on_fail); \
|
||||||
|
} \
|
||||||
|
(da)->elts_[(da)->n_++] = (v); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/** Return the number of elements in 'da'. */
|
||||||
|
#define TRUNNEL_DYNARRAY_LEN(da) ((da)->n_)
|
||||||
|
|
||||||
|
/** Remove all storage held by 'da' and set it to be empty. Does not free
|
||||||
|
* storage held by the elements themselves. */
|
||||||
|
#define TRUNNEL_DYNARRAY_CLEAR(da) do { \
|
||||||
|
trunnel_free((da)->elts_); \
|
||||||
|
(da)->elts_ = NULL; \
|
||||||
|
(da)->n_ = (da)->allocated_ = 0; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/** Remove all storage held by 'da' and set it to be empty. Does not free
|
||||||
|
* storage held by the elements themselves. */
|
||||||
|
#define TRUNNEL_DYNARRAY_WIPE(da) do { \
|
||||||
|
trunnel_memwipe((da)->elts_, (da)->allocated_ * sizeof((da)->elts_[0])); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/** Helper: wraps or implements an OpenBSD-style reallocarray. Behaves
|
||||||
|
* as realloc(a, x*y), but verifies that no overflow will occur in the
|
||||||
|
* multiplication. Returns NULL on failure. */
|
||||||
|
#ifndef trunnel_reallocarray
|
||||||
|
void *trunnel_reallocarray(void *a, size_t x, size_t y);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Helper to expand a dynamic array. Behaves as TRUNNEL_DYNARRAY_EXPAND(),
|
||||||
|
* taking the array of elements in 'ptr', a pointer to thethe current number
|
||||||
|
* of allocated elements in allocated_p, the minimum numbeer of elements to
|
||||||
|
* add in 'howmanymore', and the size of a single element in 'eltsize'.
|
||||||
|
*
|
||||||
|
* On success, adjust *allocated_p, and return the new value for the array of
|
||||||
|
* elements. On failure, adjust nothing and return NULL.
|
||||||
|
*/
|
||||||
|
void *trunnel_dynarray_expand(size_t *allocated_p, void *ptr,
|
||||||
|
size_t howmanymore, size_t eltsize);
|
||||||
|
|
||||||
|
/** Type for a function to free members of a dynarray of pointers. */
|
||||||
|
typedef void (*trunnel_free_fn_t)(void *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to change the length of a dynamic array. Takes pointers to the
|
||||||
|
* current allocated and n fields of the array in 'allocated_p' and 'len_p',
|
||||||
|
* and the current array of elements in 'ptr'; takes the length of a single
|
||||||
|
* element in 'eltsize'. Changes the length to 'newlen'. If 'newlen' is
|
||||||
|
* greater than the current length, pads the new elements with 0. If newlen
|
||||||
|
* is less than the current length, and free_fn is non-NULL, treat the
|
||||||
|
* array as an array of void *, and invoke free_fn() on each removed element.
|
||||||
|
*
|
||||||
|
* On success, adjust *allocated_p and *len_p, and return the new value for
|
||||||
|
* the array of elements. On failure, adjust nothing, set *errcode_ptr to 1,
|
||||||
|
* and return NULL.
|
||||||
|
*/
|
||||||
|
void *trunnel_dynarray_setlen(size_t *allocated_p, size_t *len_p,
|
||||||
|
void *ptr, size_t newlen,
|
||||||
|
size_t eltsize, trunnel_free_fn_t free_fn,
|
||||||
|
uint8_t *errcode_ptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper: return a pointer to the value of 'str' as a NUL-terminated string.
|
||||||
|
* Might have to reallocate the storage for 'str' in order to fit in the final
|
||||||
|
* NUL character. On allocation failure, return NULL.
|
||||||
|
*/
|
||||||
|
const char *trunnel_string_getstr(trunnel_string_t *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper: change the contents of 'str' to hold the 'len'-byte string in
|
||||||
|
* 'inp'. Adjusts the storage to have a terminating NUL that doesn't count
|
||||||
|
* towards the length of the string. On success, return 0. On failure, set
|
||||||
|
* *errcode_ptr to 1 and return -1.
|
||||||
|
*/
|
||||||
|
int trunnel_string_setstr0(trunnel_string_t *str, const char *inp, size_t len,
|
||||||
|
uint8_t *errcode_ptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As trunnel_dynarray_setlen, but adjusts a string rather than a dynamic
|
||||||
|
* array, and ensures that the new string is NUL-terminated.
|
||||||
|
*/
|
||||||
|
int trunnel_string_setlen(trunnel_string_t *str, size_t newlen,
|
||||||
|
uint8_t *errcode_ptr);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2014 The Tor Project, Inc.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
* Neither the names of the copyright owners nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
|
||||||
|
OWNER 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.
|
||||||
|
*/
|
242
src/ext/trunnel/trunnel.c
Normal file
242
src/ext/trunnel/trunnel.c
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
/* trunnel.c -- Helper functions to implement trunnel.
|
||||||
|
*
|
||||||
|
* Copyright 2014, The Tor Project, Inc.
|
||||||
|
* See license at the end of this file for copying information.
|
||||||
|
*
|
||||||
|
* See trunnel-impl.h for documentation of these functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "trunnel-impl.h"
|
||||||
|
|
||||||
|
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
|
||||||
|
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
|
# define IS_LITTLE_ENDIAN 1
|
||||||
|
#elif defined(BYTE_ORDER) && defined(ORDER_LITTLE_ENDIAN) && \
|
||||||
|
BYTE_ORDER == __ORDER_LITTLE_ENDIAN
|
||||||
|
# define IS_LITTLE_ENDIAN 1
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
# define IS_LITTLE_ENDIAN 1
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
# include <libkern/OSByteOrder.h>
|
||||||
|
# define BSWAP64(x) OSSwapLittleToHostInt64(x)
|
||||||
|
#elif defined(sun) || defined(__sun)
|
||||||
|
# include <sys/byteorder.h>
|
||||||
|
# ifndef _BIG_ENDIAN
|
||||||
|
# define IS_LITTLE_ENDIAN
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||||
|
# include <sys/endian.h>
|
||||||
|
# else
|
||||||
|
# include <endian.h>
|
||||||
|
# endif
|
||||||
|
# if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
|
||||||
|
__BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
# define IS_LITTLE_ENDIAN
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
uint16_t
|
||||||
|
trunnel_htons(uint16_t s)
|
||||||
|
{
|
||||||
|
return (s << 8) | (s >> 8);
|
||||||
|
}
|
||||||
|
uint16_t
|
||||||
|
trunnel_ntohs(uint16_t s)
|
||||||
|
{
|
||||||
|
return (s << 8) | (s >> 8);
|
||||||
|
}
|
||||||
|
uint32_t
|
||||||
|
trunnel_htonl(uint32_t s)
|
||||||
|
{
|
||||||
|
return (s << 24) |
|
||||||
|
((s << 8)&0xff0000) |
|
||||||
|
((s >> 8)&0xff00) |
|
||||||
|
(s >> 24);
|
||||||
|
}
|
||||||
|
uint32_t
|
||||||
|
trunnel_ntohl(uint32_t s)
|
||||||
|
{
|
||||||
|
return (s << 24) |
|
||||||
|
((s << 8)&0xff0000) |
|
||||||
|
((s >> 8)&0xff00) |
|
||||||
|
(s >> 24);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
trunnel_htonll(uint64_t a)
|
||||||
|
{
|
||||||
|
#ifdef IS_LITTLE_ENDIAN
|
||||||
|
return trunnel_htonl(a>>32) | (((uint64_t)trunnel_htonl(a))<<32);
|
||||||
|
#else
|
||||||
|
return a;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
trunnel_ntohll(uint64_t a)
|
||||||
|
{
|
||||||
|
return trunnel_htonll(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TRUNNEL_DEBUG_FAILING_ALLOC
|
||||||
|
/** Used for debugging and running tricky test cases: Makes the nth
|
||||||
|
* memoryation allocation call from now fail.
|
||||||
|
*/
|
||||||
|
int trunnel_provoke_alloc_failure = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *
|
||||||
|
trunnel_dynarray_expand(size_t *allocated_p, void *ptr,
|
||||||
|
size_t howmanymore, size_t eltsize)
|
||||||
|
{
|
||||||
|
size_t newsize = howmanymore + *allocated_p;
|
||||||
|
void *newarray = NULL;
|
||||||
|
if (newsize < 8)
|
||||||
|
newsize = 8;
|
||||||
|
if (newsize < *allocated_p * 2)
|
||||||
|
newsize = *allocated_p * 2;
|
||||||
|
if (newsize <= *allocated_p || newsize < howmanymore)
|
||||||
|
return NULL;
|
||||||
|
newarray = trunnel_reallocarray(ptr, newsize, eltsize);
|
||||||
|
if (newarray == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*allocated_p = newsize;
|
||||||
|
return newarray;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef trunnel_reallocarray
|
||||||
|
void *
|
||||||
|
trunnel_reallocarray(void *a, size_t x, size_t y)
|
||||||
|
{
|
||||||
|
#ifdef TRUNNEL_DEBUG_FAILING_ALLOC
|
||||||
|
if (trunnel_provoke_alloc_failure) {
|
||||||
|
if (--trunnel_provoke_alloc_failure == 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (x > SIZE_MAX / y)
|
||||||
|
return NULL;
|
||||||
|
return trunnel_realloc(a, x * y);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *
|
||||||
|
trunnel_string_getstr(trunnel_string_t *str)
|
||||||
|
{
|
||||||
|
trunnel_assert(str->allocated_ >= str->n_);
|
||||||
|
if (str->allocated_ == str->n_) {
|
||||||
|
TRUNNEL_DYNARRAY_EXPAND(char, str, 1, {});
|
||||||
|
}
|
||||||
|
str->elts_[str->n_] = 0;
|
||||||
|
return str->elts_;
|
||||||
|
trunnel_alloc_failed:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
trunnel_string_setstr0(trunnel_string_t *str, const char *val, size_t len,
|
||||||
|
uint8_t *errcode_ptr)
|
||||||
|
{
|
||||||
|
if (len == SIZE_MAX)
|
||||||
|
goto trunnel_alloc_failed;
|
||||||
|
if (str->allocated_ <= len) {
|
||||||
|
TRUNNEL_DYNARRAY_EXPAND(char, str, len + 1 - str->allocated_, {});
|
||||||
|
}
|
||||||
|
memcpy(str->elts_, val, len);
|
||||||
|
str->n_ = len;
|
||||||
|
str->elts_[len] = 0;
|
||||||
|
return 0;
|
||||||
|
trunnel_alloc_failed:
|
||||||
|
*errcode_ptr = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
trunnel_string_setlen(trunnel_string_t *str, size_t newlen,
|
||||||
|
uint8_t *errcode_ptr)
|
||||||
|
{
|
||||||
|
if (newlen == SIZE_MAX)
|
||||||
|
goto trunnel_alloc_failed;
|
||||||
|
if (str->allocated_ < newlen + 1) {
|
||||||
|
TRUNNEL_DYNARRAY_EXPAND(char, str, newlen + 1 - str->allocated_, {});
|
||||||
|
}
|
||||||
|
if (str->n_ < newlen) {
|
||||||
|
memset(& (str->elts_[str->n_]), 0, (newlen - str->n_));
|
||||||
|
}
|
||||||
|
str->n_ = newlen;
|
||||||
|
str->elts_[newlen] = 0;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
trunnel_alloc_failed:
|
||||||
|
*errcode_ptr = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
trunnel_dynarray_setlen(size_t *allocated_p, size_t *len_p,
|
||||||
|
void *ptr, size_t newlen,
|
||||||
|
size_t eltsize, trunnel_free_fn_t free_fn,
|
||||||
|
uint8_t *errcode_ptr)
|
||||||
|
{
|
||||||
|
if (*allocated_p < newlen) {
|
||||||
|
void *newptr = trunnel_dynarray_expand(allocated_p, ptr,
|
||||||
|
newlen - *allocated_p, eltsize);
|
||||||
|
if (newptr == NULL)
|
||||||
|
goto trunnel_alloc_failed;
|
||||||
|
ptr = newptr;
|
||||||
|
}
|
||||||
|
if (free_fn && *len_p > newlen) {
|
||||||
|
size_t i;
|
||||||
|
void **elts = (void **) ptr;
|
||||||
|
for (i = newlen; i < *len_p; ++i) {
|
||||||
|
free_fn(elts[i]);
|
||||||
|
elts[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*len_p < newlen) {
|
||||||
|
memset( ((char*)ptr) + (eltsize * *len_p), 0, (newlen - *len_p) * eltsize);
|
||||||
|
}
|
||||||
|
*len_p = newlen;
|
||||||
|
return ptr;
|
||||||
|
trunnel_alloc_failed:
|
||||||
|
*errcode_ptr = 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2014 The Tor Project, Inc.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
* Neither the names of the copyright owners nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
|
||||||
|
OWNER 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.
|
||||||
|
*/
|
60
src/ext/trunnel/trunnel.h
Normal file
60
src/ext/trunnel/trunnel.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/* trunnel.h -- Public declarations for trunnel, to be included
|
||||||
|
* in trunnel header files.
|
||||||
|
|
||||||
|
* Copyright 2014, The Tor Project, Inc.
|
||||||
|
* See license at the end of this file for copying information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TRUNNEL_H_INCLUDED_
|
||||||
|
#define TRUNNEL_H_INCLUDED_
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/** Macro to declare a variable-length dynamically allocated array. Trunnel
|
||||||
|
* uses these to store all variable-length arrays. */
|
||||||
|
#define TRUNNEL_DYNARRAY_HEAD(name, elttype) \
|
||||||
|
struct name { \
|
||||||
|
size_t n_; \
|
||||||
|
size_t allocated_; \
|
||||||
|
elttype *elts_; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initializer for a dynamic array of a given element type. */
|
||||||
|
#define TRUNNEL_DYNARRAY_INIT(elttype) { 0, 0, (elttype*)NULL }
|
||||||
|
|
||||||
|
/** Typedef used for storing variable-length arrays of char. */
|
||||||
|
typedef TRUNNEL_DYNARRAY_HEAD(trunnel_string_st, char) trunnel_string_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2014 The Tor Project, Inc.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
* Neither the names of the copyright owners nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
|
||||||
|
OWNER 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.
|
||||||
|
*/
|
@ -1,7 +1,9 @@
|
|||||||
include src/ext/include.am
|
include src/ext/include.am
|
||||||
|
include src/trunnel/include.am
|
||||||
include src/common/include.am
|
include src/common/include.am
|
||||||
include src/or/include.am
|
include src/or/include.am
|
||||||
include src/test/include.am
|
include src/test/include.am
|
||||||
include src/tools/include.am
|
include src/tools/include.am
|
||||||
include src/win32/include.am
|
include src/win32/include.am
|
||||||
include src/config/include.am
|
include src/config/include.am
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
|
|||||||
@TOR_LDFLAGS_libevent@
|
@TOR_LDFLAGS_libevent@
|
||||||
src_test_test_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \
|
src_test_test_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \
|
||||||
src/common/libor-crypto-testing.a $(LIBDONNA) \
|
src/common/libor-crypto-testing.a $(LIBDONNA) \
|
||||||
src/common/libor-event-testing.a \
|
src/common/libor-event-testing.a src/trunnel/libor-trunnel-testing.a \
|
||||||
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
|
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
|
||||||
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
|
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
|
||||||
|
|
||||||
|
29
src/trunnel/include.am
Normal file
29
src/trunnel/include.am
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
noinst_LIBRARIES += \
|
||||||
|
src/trunnel/libor-trunnel.a
|
||||||
|
|
||||||
|
if UNITTESTS_ENABLED
|
||||||
|
noinst_LIBRARIES += \
|
||||||
|
src/trunnel/libor-trunnel-testing.a
|
||||||
|
endif
|
||||||
|
|
||||||
|
AM_CPPFLAGS += -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel
|
||||||
|
|
||||||
|
TRUNNELSOURCES = \
|
||||||
|
src/ext/trunnel/trunnel.c \
|
||||||
|
src/trunnel/pwbox.c
|
||||||
|
|
||||||
|
TRUNNELHEADERS = \
|
||||||
|
src/ext/trunnel/trunnel.h \
|
||||||
|
src/ext/trunnel/trunnel-impl.h \
|
||||||
|
src/trunnel/trunnel-local.h \
|
||||||
|
src/trunnel/pwbox.h
|
||||||
|
|
||||||
|
src_trunnel_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES)
|
||||||
|
src_trunnel_libor_trunnel_a_CPPFLAGS = -DTRUNNEL_LOCAL_H $(AM_CPPFLAGS)
|
||||||
|
|
||||||
|
src_trunnel_libor_trunnel_testing_a_SOURCES = $(TRUNNELSOURCES)
|
||||||
|
src_trunnel_libor_trunnel_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS -DTRUNNEL_LOCAL_H $(AM_CPPFLAGS)
|
||||||
|
src_trunnel_libor_trunnel_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
||||||
|
|
||||||
|
noinst_HEADERS+= $(TRUNNELHEADERS)
|
509
src/trunnel/pwbox.c
Normal file
509
src/trunnel/pwbox.c
Normal file
@ -0,0 +1,509 @@
|
|||||||
|
|
||||||
|
/* pwbox.c -- generated by trunnel. */
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "trunnel-impl.h"
|
||||||
|
|
||||||
|
#include "pwbox.h"
|
||||||
|
|
||||||
|
#define TRUNNEL_SET_ERROR_CODE(obj) \
|
||||||
|
do { \
|
||||||
|
(obj)->trunnel_error_code_ = 1; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
pwbox_encoded_t *
|
||||||
|
pwbox_encoded_new(void)
|
||||||
|
{
|
||||||
|
pwbox_encoded_t *val = trunnel_calloc(1, sizeof(pwbox_encoded_t));
|
||||||
|
if (NULL == val)
|
||||||
|
return NULL;
|
||||||
|
val->fixedbytes0 = PWBOX0_CONST0;
|
||||||
|
val->fixedbytes1 = PWBOX0_CONST1;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Release all storage held inside 'obj', but do not free 'obj'.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
pwbox_encoded_clear(pwbox_encoded_t *obj)
|
||||||
|
{
|
||||||
|
(void) obj;
|
||||||
|
TRUNNEL_DYNARRAY_WIPE(&obj->skey_header);
|
||||||
|
TRUNNEL_DYNARRAY_CLEAR(&obj->skey_header);
|
||||||
|
TRUNNEL_DYNARRAY_WIPE(&obj->data);
|
||||||
|
TRUNNEL_DYNARRAY_CLEAR(&obj->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pwbox_encoded_free(pwbox_encoded_t *obj)
|
||||||
|
{
|
||||||
|
if (obj == NULL)
|
||||||
|
return;
|
||||||
|
pwbox_encoded_clear(obj);
|
||||||
|
trunnel_memwipe(obj, sizeof(pwbox_encoded_t));
|
||||||
|
trunnel_free_(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
pwbox_encoded_get_fixedbytes0(pwbox_encoded_t *inp)
|
||||||
|
{
|
||||||
|
return inp->fixedbytes0;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
pwbox_encoded_set_fixedbytes0(pwbox_encoded_t *inp, uint32_t val)
|
||||||
|
{
|
||||||
|
if (! ((val == PWBOX0_CONST0))) {
|
||||||
|
TRUNNEL_SET_ERROR_CODE(inp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
inp->fixedbytes0 = val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint32_t
|
||||||
|
pwbox_encoded_get_fixedbytes1(pwbox_encoded_t *inp)
|
||||||
|
{
|
||||||
|
return inp->fixedbytes1;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
pwbox_encoded_set_fixedbytes1(pwbox_encoded_t *inp, uint32_t val)
|
||||||
|
{
|
||||||
|
if (! ((val == PWBOX0_CONST1))) {
|
||||||
|
TRUNNEL_SET_ERROR_CODE(inp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
inp->fixedbytes1 = val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint8_t
|
||||||
|
pwbox_encoded_get_header_len(pwbox_encoded_t *inp)
|
||||||
|
{
|
||||||
|
return inp->header_len;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
pwbox_encoded_set_header_len(pwbox_encoded_t *inp, uint8_t val)
|
||||||
|
{
|
||||||
|
inp->header_len = val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t
|
||||||
|
pwbox_encoded_getlen_skey_header(const pwbox_encoded_t *inp)
|
||||||
|
{
|
||||||
|
return TRUNNEL_DYNARRAY_LEN(&inp->skey_header);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
pwbox_encoded_get_skey_header(pwbox_encoded_t *inp, size_t idx)
|
||||||
|
{
|
||||||
|
return TRUNNEL_DYNARRAY_GET(&inp->skey_header, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pwbox_encoded_set_skey_header(pwbox_encoded_t *inp, size_t idx, uint8_t elt)
|
||||||
|
{
|
||||||
|
TRUNNEL_DYNARRAY_SET(&inp->skey_header, idx, elt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
pwbox_encoded_add_skey_header(pwbox_encoded_t *inp, uint8_t elt)
|
||||||
|
{
|
||||||
|
#if SIZE_MAX >= UINT8_MAX
|
||||||
|
if (inp->skey_header.n_ == UINT8_MAX)
|
||||||
|
goto trunnel_alloc_failed;
|
||||||
|
#endif
|
||||||
|
TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->skey_header, elt, {});
|
||||||
|
return 0;
|
||||||
|
trunnel_alloc_failed:
|
||||||
|
TRUNNEL_SET_ERROR_CODE(inp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *
|
||||||
|
pwbox_encoded_getarray_skey_header(pwbox_encoded_t *inp)
|
||||||
|
{
|
||||||
|
return inp->skey_header.elts_;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
pwbox_encoded_setlen_skey_header(pwbox_encoded_t *inp, size_t newlen)
|
||||||
|
{
|
||||||
|
uint8_t *newptr;
|
||||||
|
#if UINT8_MAX < SIZE_MAX
|
||||||
|
if (newlen > UINT8_MAX)
|
||||||
|
goto trunnel_alloc_failed;
|
||||||
|
#endif
|
||||||
|
newptr = trunnel_dynarray_setlen(&inp->skey_header.allocated_,
|
||||||
|
&inp->skey_header.n_, inp->skey_header.elts_, newlen,
|
||||||
|
sizeof(inp->skey_header.elts_[0]), (trunnel_free_fn_t) NULL,
|
||||||
|
&inp->trunnel_error_code_);
|
||||||
|
if (newptr == NULL)
|
||||||
|
goto trunnel_alloc_failed;
|
||||||
|
inp->skey_header.elts_ = newptr;
|
||||||
|
return 0;
|
||||||
|
trunnel_alloc_failed:
|
||||||
|
TRUNNEL_SET_ERROR_CODE(inp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t
|
||||||
|
pwbox_encoded_getlen_iv(const pwbox_encoded_t *inp)
|
||||||
|
{
|
||||||
|
(void)inp; return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
pwbox_encoded_get_iv(const pwbox_encoded_t *inp, size_t idx)
|
||||||
|
{
|
||||||
|
trunnel_assert(idx < 16);
|
||||||
|
return inp->iv[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pwbox_encoded_set_iv(pwbox_encoded_t *inp, size_t idx, uint8_t elt)
|
||||||
|
{
|
||||||
|
trunnel_assert(idx < 16);
|
||||||
|
inp->iv[idx] = elt;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *
|
||||||
|
pwbox_encoded_getarray_iv(pwbox_encoded_t *inp)
|
||||||
|
{
|
||||||
|
return inp->iv;
|
||||||
|
}
|
||||||
|
size_t
|
||||||
|
pwbox_encoded_getlen_data(const pwbox_encoded_t *inp)
|
||||||
|
{
|
||||||
|
return TRUNNEL_DYNARRAY_LEN(&inp->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
pwbox_encoded_get_data(pwbox_encoded_t *inp, size_t idx)
|
||||||
|
{
|
||||||
|
return TRUNNEL_DYNARRAY_GET(&inp->data, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pwbox_encoded_set_data(pwbox_encoded_t *inp, size_t idx, uint8_t elt)
|
||||||
|
{
|
||||||
|
TRUNNEL_DYNARRAY_SET(&inp->data, idx, elt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
pwbox_encoded_add_data(pwbox_encoded_t *inp, uint8_t elt)
|
||||||
|
{
|
||||||
|
TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->data, elt, {});
|
||||||
|
return 0;
|
||||||
|
trunnel_alloc_failed:
|
||||||
|
TRUNNEL_SET_ERROR_CODE(inp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *
|
||||||
|
pwbox_encoded_getarray_data(pwbox_encoded_t *inp)
|
||||||
|
{
|
||||||
|
return inp->data.elts_;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
pwbox_encoded_setlen_data(pwbox_encoded_t *inp, size_t newlen)
|
||||||
|
{
|
||||||
|
uint8_t *newptr;
|
||||||
|
newptr = trunnel_dynarray_setlen(&inp->data.allocated_,
|
||||||
|
&inp->data.n_, inp->data.elts_, newlen,
|
||||||
|
sizeof(inp->data.elts_[0]), (trunnel_free_fn_t) NULL,
|
||||||
|
&inp->trunnel_error_code_);
|
||||||
|
if (newptr == NULL)
|
||||||
|
goto trunnel_alloc_failed;
|
||||||
|
inp->data.elts_ = newptr;
|
||||||
|
return 0;
|
||||||
|
trunnel_alloc_failed:
|
||||||
|
TRUNNEL_SET_ERROR_CODE(inp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t
|
||||||
|
pwbox_encoded_getlen_hmac(const pwbox_encoded_t *inp)
|
||||||
|
{
|
||||||
|
(void)inp; return 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
pwbox_encoded_get_hmac(const pwbox_encoded_t *inp, size_t idx)
|
||||||
|
{
|
||||||
|
trunnel_assert(idx < 32);
|
||||||
|
return inp->hmac[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pwbox_encoded_set_hmac(pwbox_encoded_t *inp, size_t idx, uint8_t elt)
|
||||||
|
{
|
||||||
|
trunnel_assert(idx < 32);
|
||||||
|
inp->hmac[idx] = elt;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *
|
||||||
|
pwbox_encoded_getarray_hmac(pwbox_encoded_t *inp)
|
||||||
|
{
|
||||||
|
return inp->hmac;
|
||||||
|
}
|
||||||
|
const char *
|
||||||
|
pwbox_encoded_check(const pwbox_encoded_t *obj)
|
||||||
|
{
|
||||||
|
if (obj == NULL)
|
||||||
|
return "Object was NULL";
|
||||||
|
if (obj->trunnel_error_code_)
|
||||||
|
return "A set function failed on this object";
|
||||||
|
if (! (obj->fixedbytes0 == PWBOX0_CONST0))
|
||||||
|
return "Integer out of bounds";
|
||||||
|
if (! (obj->fixedbytes1 == PWBOX0_CONST1))
|
||||||
|
return "Integer out of bounds";
|
||||||
|
if (TRUNNEL_DYNARRAY_LEN(&obj->skey_header) != obj->header_len)
|
||||||
|
return "Length mismatch for skey_header";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
pwbox_encoded_encoded_len(const pwbox_encoded_t *obj)
|
||||||
|
{
|
||||||
|
ssize_t result = 0;
|
||||||
|
|
||||||
|
if (NULL != pwbox_encoded_check(obj))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
|
||||||
|
/* Length of u32 fixedbytes0 IN [PWBOX0_CONST0] */
|
||||||
|
result += 4;
|
||||||
|
|
||||||
|
/* Length of u32 fixedbytes1 IN [PWBOX0_CONST1] */
|
||||||
|
result += 4;
|
||||||
|
|
||||||
|
/* Length of u8 header_len */
|
||||||
|
result += 1;
|
||||||
|
|
||||||
|
/* Length of u8 skey_header[header_len] */
|
||||||
|
result += TRUNNEL_DYNARRAY_LEN(&obj->skey_header);
|
||||||
|
|
||||||
|
/* Length of u8 iv[16] */
|
||||||
|
result += 16;
|
||||||
|
|
||||||
|
/* Length of u8 data[] */
|
||||||
|
result += TRUNNEL_DYNARRAY_LEN(&obj->data);
|
||||||
|
|
||||||
|
/* Length of u8 hmac[32] */
|
||||||
|
result += 32;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
pwbox_encoded_clear_errors(pwbox_encoded_t *obj)
|
||||||
|
{
|
||||||
|
int r = obj->trunnel_error_code_;
|
||||||
|
obj->trunnel_error_code_ = 0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
ssize_t
|
||||||
|
pwbox_encoded_encode(uint8_t *output, size_t avail, const pwbox_encoded_t *obj)
|
||||||
|
{
|
||||||
|
ssize_t result = 0;
|
||||||
|
size_t written = 0;
|
||||||
|
uint8_t *ptr = output;
|
||||||
|
const char *msg;
|
||||||
|
int enforce_avail = 0;
|
||||||
|
const size_t avail_orig = avail;
|
||||||
|
|
||||||
|
if (NULL != (msg = pwbox_encoded_check(obj)))
|
||||||
|
goto check_failed;
|
||||||
|
|
||||||
|
|
||||||
|
/* Encode u32 fixedbytes0 IN [PWBOX0_CONST0] */
|
||||||
|
trunnel_assert(written <= avail);
|
||||||
|
if (avail - written < 4)
|
||||||
|
goto truncated;
|
||||||
|
trunnel_set_uint32(ptr, trunnel_htonl(obj->fixedbytes0));
|
||||||
|
written += 4; ptr += 4;
|
||||||
|
|
||||||
|
/* Encode u32 fixedbytes1 IN [PWBOX0_CONST1] */
|
||||||
|
trunnel_assert(written <= avail);
|
||||||
|
if (avail - written < 4)
|
||||||
|
goto truncated;
|
||||||
|
trunnel_set_uint32(ptr, trunnel_htonl(obj->fixedbytes1));
|
||||||
|
written += 4; ptr += 4;
|
||||||
|
|
||||||
|
/* Encode u8 header_len */
|
||||||
|
trunnel_assert(written <= avail);
|
||||||
|
if (avail - written < 1)
|
||||||
|
goto truncated;
|
||||||
|
trunnel_set_uint8(ptr, (obj->header_len));
|
||||||
|
written += 1; ptr += 1;
|
||||||
|
|
||||||
|
/* Encode u8 skey_header[header_len] */
|
||||||
|
{
|
||||||
|
size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->skey_header);
|
||||||
|
trunnel_assert(obj->header_len == elt_len);
|
||||||
|
trunnel_assert(written <= avail);
|
||||||
|
if (avail - written < elt_len)
|
||||||
|
goto truncated;
|
||||||
|
memcpy(ptr, obj->skey_header.elts_, elt_len);
|
||||||
|
written += elt_len; ptr += elt_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encode u8 iv[16] */
|
||||||
|
trunnel_assert(written <= avail);
|
||||||
|
if (avail - written < 16)
|
||||||
|
goto truncated;
|
||||||
|
memcpy(ptr, obj->iv, 16);
|
||||||
|
written += 16; ptr += 16;
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Encode u8 data[] */
|
||||||
|
{
|
||||||
|
size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->data);
|
||||||
|
trunnel_assert(written <= avail);
|
||||||
|
if (avail - written < elt_len)
|
||||||
|
goto truncated;
|
||||||
|
memcpy(ptr, obj->data.elts_, elt_len);
|
||||||
|
written += elt_len; ptr += elt_len;
|
||||||
|
}
|
||||||
|
trunnel_assert(written <= avail);
|
||||||
|
if (avail - written < 32)
|
||||||
|
goto truncated;
|
||||||
|
avail = written + 32;
|
||||||
|
enforce_avail = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encode u8 hmac[32] */
|
||||||
|
trunnel_assert(written <= avail);
|
||||||
|
if (avail - written < 32) {
|
||||||
|
if (avail_orig - written < 32)
|
||||||
|
goto truncated;
|
||||||
|
else
|
||||||
|
goto check_failed;
|
||||||
|
}
|
||||||
|
memcpy(ptr, obj->hmac, 32);
|
||||||
|
written += 32; ptr += 32;
|
||||||
|
|
||||||
|
|
||||||
|
trunnel_assert(ptr == output + written);
|
||||||
|
if (enforce_avail && avail != written)
|
||||||
|
goto check_failed;
|
||||||
|
#ifdef TRUNNEL_CHECK_ENCODED_LEN
|
||||||
|
{
|
||||||
|
ssize_t encoded_len = pwbox_encoded_encoded_len(obj);
|
||||||
|
trunnel_assert(encoded_len >= 0);
|
||||||
|
trunnel_assert((size_t)encoded_len == written);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return written;
|
||||||
|
|
||||||
|
truncated:
|
||||||
|
result = -2;
|
||||||
|
goto fail;
|
||||||
|
check_failed:
|
||||||
|
(void)msg;
|
||||||
|
result = -1;
|
||||||
|
goto fail;
|
||||||
|
fail:
|
||||||
|
trunnel_assert(result < 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** As pwbox_encoded_parse(), but do not allocate the output object.
|
||||||
|
*/
|
||||||
|
static ssize_t
|
||||||
|
pwbox_encoded_parse_into(pwbox_encoded_t *obj, const uint8_t *input, const size_t len_in)
|
||||||
|
{
|
||||||
|
const uint8_t *ptr = input;
|
||||||
|
size_t remaining = len_in;
|
||||||
|
ssize_t result = 0;
|
||||||
|
(void)result;
|
||||||
|
|
||||||
|
/* Parse u32 fixedbytes0 IN [PWBOX0_CONST0] */
|
||||||
|
if (remaining < 4)
|
||||||
|
goto truncated;
|
||||||
|
obj->fixedbytes0 = trunnel_ntohl(trunnel_get_uint32(ptr));
|
||||||
|
remaining -= 4; ptr += 4;
|
||||||
|
if (! (obj->fixedbytes0 == PWBOX0_CONST0))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* Parse u32 fixedbytes1 IN [PWBOX0_CONST1] */
|
||||||
|
if (remaining < 4)
|
||||||
|
goto truncated;
|
||||||
|
obj->fixedbytes1 = trunnel_ntohl(trunnel_get_uint32(ptr));
|
||||||
|
remaining -= 4; ptr += 4;
|
||||||
|
if (! (obj->fixedbytes1 == PWBOX0_CONST1))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* Parse u8 header_len */
|
||||||
|
if (remaining < 1)
|
||||||
|
goto truncated;
|
||||||
|
obj->header_len = (trunnel_get_uint8(ptr));
|
||||||
|
remaining -= 1; ptr += 1;
|
||||||
|
|
||||||
|
/* Parse u8 skey_header[header_len] */
|
||||||
|
if (remaining < obj->header_len)
|
||||||
|
goto truncated;
|
||||||
|
TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->skey_header, obj->header_len, {});
|
||||||
|
obj->skey_header.n_ = obj->header_len;
|
||||||
|
memcpy(obj->skey_header.elts_, ptr, obj->header_len);
|
||||||
|
ptr += obj->header_len; remaining -= obj->header_len;
|
||||||
|
|
||||||
|
/* Parse u8 iv[16] */
|
||||||
|
if (remaining < (16))
|
||||||
|
goto truncated;
|
||||||
|
memcpy(obj->iv, ptr, 16);
|
||||||
|
{
|
||||||
|
unsigned idx;
|
||||||
|
for (idx = 0; idx < 16; ++idx)
|
||||||
|
obj->iv[idx] = (obj->iv[idx]);
|
||||||
|
}
|
||||||
|
remaining -= 16; ptr += 16;
|
||||||
|
{
|
||||||
|
size_t remaining_after;
|
||||||
|
if (remaining < 32)
|
||||||
|
goto truncated;
|
||||||
|
remaining_after = 32;
|
||||||
|
remaining = remaining - 32;
|
||||||
|
|
||||||
|
/* Parse u8 data[] */
|
||||||
|
TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->data, remaining, {});
|
||||||
|
obj->data.n_ = remaining;
|
||||||
|
memcpy(obj->data.elts_, ptr, remaining);
|
||||||
|
ptr += remaining; remaining -= remaining;
|
||||||
|
if (remaining != 0)
|
||||||
|
goto fail;
|
||||||
|
remaining = remaining_after;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse u8 hmac[32] */
|
||||||
|
if (remaining < (32))
|
||||||
|
goto truncated;
|
||||||
|
memcpy(obj->hmac, ptr, 32);
|
||||||
|
{
|
||||||
|
unsigned idx;
|
||||||
|
for (idx = 0; idx < 32; ++idx)
|
||||||
|
obj->hmac[idx] = (obj->hmac[idx]);
|
||||||
|
}
|
||||||
|
remaining -= 32; ptr += 32;
|
||||||
|
trunnel_assert(ptr + remaining == input + len_in);
|
||||||
|
return len_in - remaining;
|
||||||
|
|
||||||
|
truncated:
|
||||||
|
return -2;
|
||||||
|
trunnel_alloc_failed:
|
||||||
|
return -1;
|
||||||
|
fail:
|
||||||
|
result = -1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
pwbox_encoded_parse(pwbox_encoded_t **output, const uint8_t *input, const size_t len_in)
|
||||||
|
{
|
||||||
|
ssize_t result;
|
||||||
|
*output = pwbox_encoded_new();
|
||||||
|
if (NULL == *output)
|
||||||
|
return -1;
|
||||||
|
result = pwbox_encoded_parse_into(*output, input, len_in);
|
||||||
|
if (result < 0) {
|
||||||
|
pwbox_encoded_free(*output);
|
||||||
|
*output = NULL;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
171
src/trunnel/pwbox.h
Normal file
171
src/trunnel/pwbox.h
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
|
||||||
|
/* pwbox.h -- generated by trunnel. */
|
||||||
|
#ifndef TRUNNEL_PWBOX_H
|
||||||
|
#define TRUNNEL_PWBOX_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "trunnel.h"
|
||||||
|
|
||||||
|
#define PWBOX0_CONST0 1414484546
|
||||||
|
#define PWBOX0_CONST1 1331179568
|
||||||
|
#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_PWBOX_ENCODED)
|
||||||
|
struct pwbox_encoded_st {
|
||||||
|
uint32_t fixedbytes0;
|
||||||
|
uint32_t fixedbytes1;
|
||||||
|
uint8_t header_len;
|
||||||
|
TRUNNEL_DYNARRAY_HEAD(, uint8_t) skey_header;
|
||||||
|
uint8_t iv[16];
|
||||||
|
TRUNNEL_DYNARRAY_HEAD(, uint8_t) data;
|
||||||
|
uint8_t hmac[32];
|
||||||
|
uint8_t trunnel_error_code_;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
typedef struct pwbox_encoded_st pwbox_encoded_t;
|
||||||
|
/** Return a newly allocated pwbox_encoded with all elements set to
|
||||||
|
* zero.
|
||||||
|
*/
|
||||||
|
pwbox_encoded_t *pwbox_encoded_new(void);
|
||||||
|
/** Release all storage held by the pwbox_encoded in 'victim'. (Do
|
||||||
|
* nothing if 'victim' is NULL.)
|
||||||
|
*/
|
||||||
|
void pwbox_encoded_free(pwbox_encoded_t *victim);
|
||||||
|
/** Try to parse a pwbox_encoded from the buffer in 'input', using up
|
||||||
|
* to 'len_in' bytes from the input buffer. On success, return the
|
||||||
|
* number of bytes consumed and set *output to the newly allocated
|
||||||
|
* pwbox_encoded_t. On failure, return -2 if the input appears
|
||||||
|
* truncated, and -1 if the input is otherwise invalid.
|
||||||
|
*/
|
||||||
|
ssize_t pwbox_encoded_parse(pwbox_encoded_t **output, const uint8_t *input, const size_t len_in);
|
||||||
|
/** Return the number of bytes we expect to need to encode the
|
||||||
|
* pwbox_encoded in 'obj'. On failure, return a negative value. Note
|
||||||
|
* that this value may be an overestimate, and can even be an
|
||||||
|
* underestimate for certain unencodeable objects.
|
||||||
|
*/
|
||||||
|
ssize_t pwbox_encoded_encoded_len(const pwbox_encoded_t *obj);
|
||||||
|
/** Try to encode the pwbox_encoded from 'input' into the buffer at
|
||||||
|
* 'output', using up to 'avail' bytes of the output buffer. On
|
||||||
|
* success, return the number of bytes used. On failure, return -2 if
|
||||||
|
* the buffer was not long enough, and -1 if the input was invalid.
|
||||||
|
*/
|
||||||
|
ssize_t pwbox_encoded_encode(uint8_t *output, const size_t avail, const pwbox_encoded_t *input);
|
||||||
|
/** Check whether the internal state of the pwbox_encoded in 'obj' is
|
||||||
|
* consistent. Return NULL if it is, and a short message if it is not.
|
||||||
|
*/
|
||||||
|
const char *pwbox_encoded_check(const pwbox_encoded_t *obj);
|
||||||
|
/** Clear any errors that were set on the object 'obj' by its setter
|
||||||
|
* functions. Return true iff errors were cleared.
|
||||||
|
*/
|
||||||
|
int pwbox_encoded_clear_errors(pwbox_encoded_t *obj);
|
||||||
|
/** Return the value of the fixedbytes0 field of the pwbox_encoded_t
|
||||||
|
* in 'inp'
|
||||||
|
*/
|
||||||
|
uint32_t pwbox_encoded_get_fixedbytes0(pwbox_encoded_t *inp);
|
||||||
|
/** Set the value of the fixedbytes0 field of the pwbox_encoded_t in
|
||||||
|
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||||
|
* code on 'inp' on failure.
|
||||||
|
*/
|
||||||
|
int pwbox_encoded_set_fixedbytes0(pwbox_encoded_t *inp, uint32_t val);
|
||||||
|
/** Return the value of the fixedbytes1 field of the pwbox_encoded_t
|
||||||
|
* in 'inp'
|
||||||
|
*/
|
||||||
|
uint32_t pwbox_encoded_get_fixedbytes1(pwbox_encoded_t *inp);
|
||||||
|
/** Set the value of the fixedbytes1 field of the pwbox_encoded_t in
|
||||||
|
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||||
|
* code on 'inp' on failure.
|
||||||
|
*/
|
||||||
|
int pwbox_encoded_set_fixedbytes1(pwbox_encoded_t *inp, uint32_t val);
|
||||||
|
/** Return the value of the header_len field of the pwbox_encoded_t in
|
||||||
|
* 'inp'
|
||||||
|
*/
|
||||||
|
uint8_t pwbox_encoded_get_header_len(pwbox_encoded_t *inp);
|
||||||
|
/** Set the value of the header_len field of the pwbox_encoded_t in
|
||||||
|
* 'inp' to 'val'. Return 0 on success; return -1 and set the error
|
||||||
|
* code on 'inp' on failure.
|
||||||
|
*/
|
||||||
|
int pwbox_encoded_set_header_len(pwbox_encoded_t *inp, uint8_t val);
|
||||||
|
/** Return the length of the dynamic array holding the skey_header
|
||||||
|
* field of the pwbox_encoded_t in 'inp'.
|
||||||
|
*/
|
||||||
|
size_t pwbox_encoded_getlen_skey_header(const pwbox_encoded_t *inp);
|
||||||
|
/** Return the element at position 'idx' of the dynamic array field
|
||||||
|
* skey_header of the pwbox_encoded_t in 'inp'.
|
||||||
|
*/
|
||||||
|
uint8_t pwbox_encoded_get_skey_header(pwbox_encoded_t *inp, size_t idx);
|
||||||
|
/** Change the element at position 'idx' of the dynamic array field
|
||||||
|
* skey_header of the pwbox_encoded_t in 'inp', so that it will hold
|
||||||
|
* the value 'elt'.
|
||||||
|
*/
|
||||||
|
int pwbox_encoded_set_skey_header(pwbox_encoded_t *inp, size_t idx, uint8_t elt);
|
||||||
|
/** Append a new element 'elt' to the dynamic array field skey_header
|
||||||
|
* of the pwbox_encoded_t in 'inp'.
|
||||||
|
*/
|
||||||
|
int pwbox_encoded_add_skey_header(pwbox_encoded_t *inp, uint8_t elt);
|
||||||
|
/** Return a pointer to the variable-length array field skey_header of
|
||||||
|
* 'inp'.
|
||||||
|
*/
|
||||||
|
uint8_t * pwbox_encoded_getarray_skey_header(pwbox_encoded_t *inp);
|
||||||
|
/** Change the length of the variable-length array field skey_header
|
||||||
|
* of 'inp' to 'newlen'.Fill extra elements with 0. Return 0 on
|
||||||
|
* success; return -1 and set the error code on 'inp' on failure.
|
||||||
|
*/
|
||||||
|
int pwbox_encoded_setlen_skey_header(pwbox_encoded_t *inp, size_t newlen);
|
||||||
|
/** Return the (constant) length of the array holding the iv field of
|
||||||
|
* the pwbox_encoded_t in 'inp'.
|
||||||
|
*/
|
||||||
|
size_t pwbox_encoded_getlen_iv(const pwbox_encoded_t *inp);
|
||||||
|
/** Return the element at position 'idx' of the fixed array field iv
|
||||||
|
* of the pwbox_encoded_t in 'inp'.
|
||||||
|
*/
|
||||||
|
uint8_t pwbox_encoded_get_iv(const pwbox_encoded_t *inp, size_t idx);
|
||||||
|
/** Change the element at position 'idx' of the fixed array field iv
|
||||||
|
* of the pwbox_encoded_t in 'inp', so that it will hold the value
|
||||||
|
* 'elt'.
|
||||||
|
*/
|
||||||
|
int pwbox_encoded_set_iv(pwbox_encoded_t *inp, size_t idx, uint8_t elt);
|
||||||
|
/** Return a pointer to the 16-element array field iv of 'inp'.
|
||||||
|
*/
|
||||||
|
uint8_t * pwbox_encoded_getarray_iv(pwbox_encoded_t *inp);
|
||||||
|
/** Return the length of the dynamic array holding the data field of
|
||||||
|
* the pwbox_encoded_t in 'inp'.
|
||||||
|
*/
|
||||||
|
size_t pwbox_encoded_getlen_data(const pwbox_encoded_t *inp);
|
||||||
|
/** Return the element at position 'idx' of the dynamic array field
|
||||||
|
* data of the pwbox_encoded_t in 'inp'.
|
||||||
|
*/
|
||||||
|
uint8_t pwbox_encoded_get_data(pwbox_encoded_t *inp, size_t idx);
|
||||||
|
/** Change the element at position 'idx' of the dynamic array field
|
||||||
|
* data of the pwbox_encoded_t in 'inp', so that it will hold the
|
||||||
|
* value 'elt'.
|
||||||
|
*/
|
||||||
|
int pwbox_encoded_set_data(pwbox_encoded_t *inp, size_t idx, uint8_t elt);
|
||||||
|
/** Append a new element 'elt' to the dynamic array field data of the
|
||||||
|
* pwbox_encoded_t in 'inp'.
|
||||||
|
*/
|
||||||
|
int pwbox_encoded_add_data(pwbox_encoded_t *inp, uint8_t elt);
|
||||||
|
/** Return a pointer to the variable-length array field data of 'inp'.
|
||||||
|
*/
|
||||||
|
uint8_t * pwbox_encoded_getarray_data(pwbox_encoded_t *inp);
|
||||||
|
/** Change the length of the variable-length array field data of 'inp'
|
||||||
|
* to 'newlen'.Fill extra elements with 0. Return 0 on success; return
|
||||||
|
* -1 and set the error code on 'inp' on failure.
|
||||||
|
*/
|
||||||
|
int pwbox_encoded_setlen_data(pwbox_encoded_t *inp, size_t newlen);
|
||||||
|
/** Return the (constant) length of the array holding the hmac field
|
||||||
|
* of the pwbox_encoded_t in 'inp'.
|
||||||
|
*/
|
||||||
|
size_t pwbox_encoded_getlen_hmac(const pwbox_encoded_t *inp);
|
||||||
|
/** Return the element at position 'idx' of the fixed array field hmac
|
||||||
|
* of the pwbox_encoded_t in 'inp'.
|
||||||
|
*/
|
||||||
|
uint8_t pwbox_encoded_get_hmac(const pwbox_encoded_t *inp, size_t idx);
|
||||||
|
/** Change the element at position 'idx' of the fixed array field hmac
|
||||||
|
* of the pwbox_encoded_t in 'inp', so that it will hold the value
|
||||||
|
* 'elt'.
|
||||||
|
*/
|
||||||
|
int pwbox_encoded_set_hmac(pwbox_encoded_t *inp, size_t idx, uint8_t elt);
|
||||||
|
/** Return a pointer to the 32-element array field hmac of 'inp'.
|
||||||
|
*/
|
||||||
|
uint8_t * pwbox_encoded_getarray_hmac(pwbox_encoded_t *inp);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
14
src/trunnel/pwbox.trunnel
Normal file
14
src/trunnel/pwbox.trunnel
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
const PWBOX0_CONST0 = 0x544f5242; // TORB
|
||||||
|
const PWBOX0_CONST1 = 0x4f583030; // OX00
|
||||||
|
|
||||||
|
struct pwbox_encoded {
|
||||||
|
u32 fixedbytes0 IN [PWBOX0_CONST0];
|
||||||
|
u32 fixedbytes1 IN [PWBOX0_CONST1];
|
||||||
|
u8 header_len;
|
||||||
|
u8 skey_header[header_len];
|
||||||
|
u8 iv[16];
|
||||||
|
u8 data[..-32];
|
||||||
|
u8 hmac[32];
|
||||||
|
};
|
||||||
|
|
18
src/trunnel/trunnel-local.h
Normal file
18
src/trunnel/trunnel-local.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
#ifndef TRUNNEL_LOCAL_H_INCLUDED
|
||||||
|
#define TRUNNEL_LOCAL_H_INCLUDED
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "compat.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
|
||||||
|
#define trunnel_malloc tor_malloc
|
||||||
|
#define trunnel_calloc tor_calloc
|
||||||
|
#define trunnel_strdup tor_strdup
|
||||||
|
#define trunnel_free_ tor_free_
|
||||||
|
#define trunnel_realloc tor_realloc
|
||||||
|
#define trunnel_reallocarray tor_reallocarray
|
||||||
|
#define trunnel_assert tor_assert
|
||||||
|
#define trunnel_memwipe(mem, len) memwipe((mem), 0, (len))
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user