mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-19 18:00:33 +01:00
Merge branch 'libscrypt_trunnel_squashed'
Conflicts: src/test/test_crypto.c
This commit is contained in:
commit
764e008092
4
.gitignore
vendored
4
.gitignore
vendored
@ -174,6 +174,10 @@ cscope.*
|
||||
/src/tools/Makefile
|
||||
/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/tor-fw-helper
|
||||
/src/tools/tor-fw-helper/tor-fw-helper.exe
|
||||
|
@ -23,7 +23,6 @@ include src/include.am
|
||||
include doc/include.am
|
||||
include contrib/include.am
|
||||
|
||||
|
||||
EXTRA_DIST+= \
|
||||
ChangeLog \
|
||||
INSTALL \
|
||||
|
11
configure.ac
11
configure.ac
@ -153,6 +153,9 @@ AC_ARG_ENABLE(tool-name-check,
|
||||
AC_ARG_ENABLE(seccomp,
|
||||
AS_HELP_STRING(--disable-seccomp, do not attempt to use libseccomp))
|
||||
|
||||
AC_ARG_ENABLE(libscrypt,
|
||||
AS_HELP_STRING(--disable-libscrypt, do not attempt to use libscrypt))
|
||||
|
||||
dnl check for the correct "ar" when cross-compiling
|
||||
AN_MAKEVAR([AR], [AC_PROG_AR])
|
||||
AN_PROGRAM([ar], [AC_PROG_AR])
|
||||
@ -722,6 +725,14 @@ if test "x$enable_seccomp" != "xno"; then
|
||||
AC_SEARCH_LIBS(seccomp_init, [seccomp])
|
||||
fi
|
||||
|
||||
dnl ============================================================
|
||||
dnl Check for libscrypt
|
||||
|
||||
if test "x$enable_libscrypt" != "xno"; then
|
||||
AC_CHECK_HEADERS([libscrypt.h])
|
||||
AC_SEARCH_LIBS(libscrypt_scrypt, [scrypt])
|
||||
fi
|
||||
|
||||
dnl ============================================================
|
||||
dnl We need an implementation of curve25519.
|
||||
|
||||
|
@ -3001,50 +3001,6 @@ base32_decode(char *dest, size_t destlen, const char *src, size_t srclen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Implement RFC2440-style iterated-salted S2K conversion: convert the
|
||||
* <b>secret_len</b>-byte <b>secret</b> into a <b>key_out_len</b> byte
|
||||
* <b>key_out</b>. As in RFC2440, the first 8 bytes of s2k_specifier
|
||||
* are a salt; the 9th byte describes how much iteration to do.
|
||||
* Does not support <b>key_out_len</b> > DIGEST_LEN.
|
||||
*/
|
||||
void
|
||||
secret_to_key(char *key_out, size_t key_out_len, const char *secret,
|
||||
size_t secret_len, const char *s2k_specifier)
|
||||
{
|
||||
crypto_digest_t *d;
|
||||
uint8_t c;
|
||||
size_t count, tmplen;
|
||||
char *tmp;
|
||||
tor_assert(key_out_len < SIZE_T_CEILING);
|
||||
|
||||
#define EXPBIAS 6
|
||||
c = s2k_specifier[8];
|
||||
count = ((uint32_t)16 + (c & 15)) << ((c >> 4) + EXPBIAS);
|
||||
#undef EXPBIAS
|
||||
|
||||
tor_assert(key_out_len <= DIGEST_LEN);
|
||||
|
||||
d = crypto_digest_new();
|
||||
tmplen = 8+secret_len;
|
||||
tmp = tor_malloc(tmplen);
|
||||
memcpy(tmp,s2k_specifier,8);
|
||||
memcpy(tmp+8,secret,secret_len);
|
||||
secret_len += 8;
|
||||
while (count) {
|
||||
if (count >= secret_len) {
|
||||
crypto_digest_add_bytes(d, tmp, secret_len);
|
||||
count -= secret_len;
|
||||
} else {
|
||||
crypto_digest_add_bytes(d, tmp, count);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
crypto_digest_get_digest(d, key_out, key_out_len);
|
||||
memwipe(tmp, 0, tmplen);
|
||||
tor_free(tmp);
|
||||
crypto_digest_free(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to
|
||||
* the value <b>byte</b>.
|
||||
|
@ -280,12 +280,6 @@ int digest_from_base64(char *digest, const char *d64);
|
||||
int digest256_to_base64(char *d64, const char *digest);
|
||||
int digest256_from_base64(char *digest, const char *d64);
|
||||
|
||||
/** Length of RFC2440-style S2K specifier: the first 8 bytes are a salt, the
|
||||
* 9th describes how much iteration to do. */
|
||||
#define S2K_SPECIFIER_LEN 9
|
||||
void secret_to_key(char *key_out, size_t key_out_len, const char *secret,
|
||||
size_t secret_len, const char *s2k_specifier);
|
||||
|
||||
/** OpenSSL-based utility functions. */
|
||||
void memwipe(void *mem, uint8_t byte, size_t sz);
|
||||
|
||||
|
187
src/common/crypto_pwbox.c
Normal file
187
src/common/crypto_pwbox.c
Normal file
@ -0,0 +1,187 @@
|
||||
|
||||
#include "crypto.h"
|
||||
#include "crypto_s2k.h"
|
||||
#include "crypto_pwbox.h"
|
||||
#include "di_ops.h"
|
||||
#include "util.h"
|
||||
#include "pwbox.h"
|
||||
|
||||
/* 8 bytes "TORBOX00"
|
||||
1 byte: header len (H)
|
||||
H bytes: header, denoting secret key algorithm.
|
||||
16 bytes: IV
|
||||
Round up to multiple of 128 bytes, then encrypt:
|
||||
4 bytes: data len
|
||||
data
|
||||
zeros
|
||||
32 bytes: HMAC-SHA256 of all previous bytes.
|
||||
*/
|
||||
|
||||
#define MAX_OVERHEAD (S2K_MAXLEN + 8 + 1 + 32 + CIPHER_IV_LEN)
|
||||
|
||||
/**
|
||||
* Make an authenticated passphrase-encrypted blob to encode the
|
||||
* <b>input_len</b> bytes in <b>input</b> using the passphrase
|
||||
* <b>secret</b> of <b>secret_len</b> bytes. Allocate a new chunk of memory
|
||||
* to hold the encrypted data, and store a pointer to that memory in
|
||||
* *<b>out</b>, and its size in <b>outlen_out</b>. Use <b>s2k_flags</b> as an
|
||||
* argument to the passphrase-hashing function.
|
||||
*/
|
||||
int
|
||||
crypto_pwbox(uint8_t **out, size_t *outlen_out,
|
||||
const uint8_t *input, size_t input_len,
|
||||
const char *secret, size_t secret_len,
|
||||
unsigned s2k_flags)
|
||||
{
|
||||
uint8_t *result = NULL, *encrypted_portion;
|
||||
size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128);
|
||||
ssize_t result_len;
|
||||
int spec_len;
|
||||
uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
|
||||
pwbox_encoded_t *enc = NULL;
|
||||
ssize_t enc_len;
|
||||
|
||||
crypto_cipher_t *cipher;
|
||||
int rv;
|
||||
|
||||
enc = pwbox_encoded_new();
|
||||
|
||||
pwbox_encoded_setlen_skey_header(enc, S2K_MAXLEN);
|
||||
|
||||
spec_len = secret_to_key_make_specifier(
|
||||
pwbox_encoded_getarray_skey_header(enc),
|
||||
S2K_MAXLEN,
|
||||
s2k_flags);
|
||||
if (spec_len < 0 || spec_len > S2K_MAXLEN)
|
||||
goto err;
|
||||
pwbox_encoded_setlen_skey_header(enc, spec_len);
|
||||
enc->header_len = spec_len;
|
||||
|
||||
crypto_rand((char*)enc->iv, sizeof(enc->iv));
|
||||
|
||||
pwbox_encoded_setlen_data(enc, encrypted_len);
|
||||
encrypted_portion = pwbox_encoded_getarray_data(enc);
|
||||
|
||||
set_uint32(encrypted_portion, htonl(input_len));
|
||||
memcpy(encrypted_portion+4, input, input_len);
|
||||
|
||||
/* Now that all the data is in position, derive some keys, encrypt, and
|
||||
* digest */
|
||||
if (secret_to_key_derivekey(keys, sizeof(keys),
|
||||
pwbox_encoded_getarray_skey_header(enc),
|
||||
spec_len,
|
||||
secret, secret_len) < 0)
|
||||
goto err;
|
||||
|
||||
cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
|
||||
crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len);
|
||||
crypto_cipher_free(cipher);
|
||||
|
||||
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,
|
||||
DIGEST256_LEN,
|
||||
(const char*)result,
|
||||
result_len - 32);
|
||||
|
||||
*out = result;
|
||||
*outlen_out = result_len;
|
||||
rv = 0;
|
||||
goto out;
|
||||
|
||||
err:
|
||||
tor_free(result);
|
||||
rv = -1;
|
||||
|
||||
out:
|
||||
pwbox_encoded_free(enc);
|
||||
memwipe(keys, 0, sizeof(keys));
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to decrypt the passphrase-encrypted blob of <b>input_len</b> bytes in
|
||||
* <b>input</b> using the passphrase <b>secret</b> of <b>secret_len</b> bytes.
|
||||
* On success, return 0 and allocate a new chunk of memory to hold the
|
||||
* decrypted data, and store a pointer to that memory in *<b>out</b>, and its
|
||||
* size in <b>outlen_out</b>. On failure, return UNPWBOX_BAD_SECRET if
|
||||
* the passphrase might have been wrong, and UNPWBOX_CORRUPT if the object is
|
||||
* definitely corrupt.
|
||||
*/
|
||||
int
|
||||
crypto_unpwbox(uint8_t **out, size_t *outlen_out,
|
||||
const uint8_t *inp, size_t input_len,
|
||||
const char *secret, size_t secret_len)
|
||||
{
|
||||
uint8_t *result = NULL;
|
||||
const uint8_t *encrypted;
|
||||
uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
|
||||
uint8_t hmac[DIGEST256_LEN];
|
||||
uint32_t result_len;
|
||||
size_t encrypted_len;
|
||||
crypto_cipher_t *cipher = NULL;
|
||||
int rv = UNPWBOX_CORRUPTED;
|
||||
ssize_t got_len;
|
||||
|
||||
pwbox_encoded_t *enc = NULL;
|
||||
|
||||
got_len = pwbox_encoded_parse(&enc, inp, input_len);
|
||||
if (got_len < 0 || (size_t)got_len != input_len)
|
||||
goto err;
|
||||
|
||||
/* Now derive the keys and check the hmac. */
|
||||
if (secret_to_key_derivekey(keys, sizeof(keys),
|
||||
pwbox_encoded_getarray_skey_header(enc),
|
||||
pwbox_encoded_getlen_skey_header(enc),
|
||||
secret, secret_len) < 0)
|
||||
goto err;
|
||||
|
||||
crypto_hmac_sha256((char *)hmac,
|
||||
(const char*)keys + CIPHER_KEY_LEN, DIGEST256_LEN,
|
||||
(const char*)inp, input_len - DIGEST256_LEN);
|
||||
|
||||
if (tor_memneq(hmac, enc->hmac, DIGEST256_LEN)) {
|
||||
rv = UNPWBOX_BAD_SECRET;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* How long is the plaintext? */
|
||||
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);
|
||||
result_len = ntohl(result_len);
|
||||
if (encrypted_len < result_len + 4)
|
||||
goto err;
|
||||
|
||||
/* Allocate a buffer and decrypt */
|
||||
result = tor_malloc_zero(result_len);
|
||||
crypto_cipher_decrypt(cipher, (char*)result, (char*)encrypted+4, result_len);
|
||||
|
||||
*out = result;
|
||||
*outlen_out = result_len;
|
||||
|
||||
rv = UNPWBOX_OKAY;
|
||||
goto out;
|
||||
|
||||
err:
|
||||
tor_free(result);
|
||||
|
||||
out:
|
||||
crypto_cipher_free(cipher);
|
||||
pwbox_encoded_free(enc);
|
||||
memwipe(keys, 0, sizeof(keys));
|
||||
return rv;
|
||||
}
|
||||
|
20
src/common/crypto_pwbox.h
Normal file
20
src/common/crypto_pwbox.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef CRYPTO_PWBOX_H_INCLUDED_
|
||||
#define CRYPTO_PWBOX_H_INCLUDED_
|
||||
|
||||
#include "torint.h"
|
||||
|
||||
#define UNPWBOX_OKAY 0
|
||||
#define UNPWBOX_BAD_SECRET -1
|
||||
#define UNPWBOX_CORRUPTED -2
|
||||
|
||||
int crypto_pwbox(uint8_t **out, size_t *outlen_out,
|
||||
const uint8_t *inp, size_t input_len,
|
||||
const char *secret, size_t secret_len,
|
||||
unsigned s2k_flags);
|
||||
|
||||
int crypto_unpwbox(uint8_t **out, size_t *outlen_out,
|
||||
const uint8_t *inp, size_t input_len,
|
||||
const char *secret, size_t secret_len);
|
||||
|
||||
#endif
|
||||
|
457
src/common/crypto_s2k.c
Normal file
457
src/common/crypto_s2k.c
Normal file
@ -0,0 +1,457 @@
|
||||
/* Copyright (c) 2001, Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#define CRYPTO_S2K_PRIVATE
|
||||
|
||||
#include "crypto.h"
|
||||
#include "util.h"
|
||||
#include "compat.h"
|
||||
#include "crypto_s2k.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#ifdef HAVE_LIBSCRYPT_H
|
||||
#define HAVE_SCRYPT
|
||||
#include <libscrypt.h>
|
||||
#endif
|
||||
|
||||
/* Encoded secrets take the form:
|
||||
|
||||
u8 type;
|
||||
u8 salt_and_parameters[depends on type];
|
||||
u8 key[depends on type];
|
||||
|
||||
As a special case, if the encoded secret is exactly 29 bytes long,
|
||||
type 0 is understood.
|
||||
|
||||
Recognized types are:
|
||||
00 -- RFC2440. salt_and_parameters is 9 bytes. key is 20 bytes.
|
||||
salt_and_parameters is 8 bytes random salt,
|
||||
1 byte iteration info.
|
||||
01 -- PKBDF2_SHA1. salt_and_parameters is 17 bytes. key is 20 bytes.
|
||||
salt_and_parameters is 16 bytes random salt,
|
||||
1 byte iteration info.
|
||||
02 -- SCRYPT_SALSA208_SHA256. salt_and_parameters is 18 bytes. key is
|
||||
32 bytes.
|
||||
salt_and_parameters is 18 bytes random salt, 2 bytes iteration
|
||||
info.
|
||||
*/
|
||||
|
||||
#define S2K_TYPE_RFC2440 0
|
||||
#define S2K_TYPE_PBKDF2 1
|
||||
#define S2K_TYPE_SCRYPT 2
|
||||
|
||||
#define PBKDF2_SPEC_LEN 17
|
||||
#define PBKDF2_KEY_LEN 20
|
||||
|
||||
#define SCRYPT_SPEC_LEN 18
|
||||
#define SCRYPT_KEY_LEN 32
|
||||
|
||||
/** Given an algorithm ID (one of S2K_TYPE_*), return the length of the
|
||||
* specifier part of it, without the prefix type byte. */
|
||||
static int
|
||||
secret_to_key_spec_len(uint8_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case S2K_TYPE_RFC2440:
|
||||
return S2K_RFC2440_SPECIFIER_LEN;
|
||||
case S2K_TYPE_PBKDF2:
|
||||
return PBKDF2_SPEC_LEN;
|
||||
case S2K_TYPE_SCRYPT:
|
||||
return SCRYPT_SPEC_LEN;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Given an algorithm ID (one of S2K_TYPE_*), return the length of the
|
||||
* its preferred output. */
|
||||
static int
|
||||
secret_to_key_key_len(uint8_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case S2K_TYPE_RFC2440:
|
||||
return DIGEST_LEN;
|
||||
case S2K_TYPE_PBKDF2:
|
||||
return DIGEST_LEN;
|
||||
case S2K_TYPE_SCRYPT:
|
||||
return DIGEST256_LEN;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Given a specifier in <b>spec_and_key</b> of length
|
||||
* <b>spec_and_key_len</b>, along with its prefix algorithm ID byte, and along
|
||||
* with a key if <b>key_included</b> is true, check whether the whole
|
||||
* specifier-and-key is of valid length, and return the algorithm type if it
|
||||
* is. Set *<b>legacy_out</b> to 1 iff this is a legacy password hash or
|
||||
* legacy specifier. Return an error code on failure.
|
||||
*/
|
||||
static int
|
||||
secret_to_key_get_type(const uint8_t *spec_and_key, size_t spec_and_key_len,
|
||||
int key_included, int *legacy_out)
|
||||
{
|
||||
size_t legacy_len = S2K_RFC2440_SPECIFIER_LEN;
|
||||
uint8_t type;
|
||||
int total_len;
|
||||
|
||||
if (key_included)
|
||||
legacy_len += DIGEST_LEN;
|
||||
|
||||
if (spec_and_key_len == legacy_len) {
|
||||
*legacy_out = 1;
|
||||
return S2K_TYPE_RFC2440;
|
||||
}
|
||||
|
||||
*legacy_out = 0;
|
||||
if (spec_and_key_len == 0)
|
||||
return S2K_BAD_LEN;
|
||||
|
||||
type = spec_and_key[0];
|
||||
total_len = secret_to_key_spec_len(type);
|
||||
if (total_len < 0)
|
||||
return S2K_BAD_ALGORITHM;
|
||||
if (key_included) {
|
||||
int keylen = secret_to_key_key_len(type);
|
||||
if (keylen < 0)
|
||||
return S2K_BAD_ALGORITHM;
|
||||
total_len += keylen;
|
||||
}
|
||||
|
||||
if ((size_t)total_len + 1 == spec_and_key_len)
|
||||
return type;
|
||||
else
|
||||
return S2K_BAD_LEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a new random s2k specifier of type <b>type</b>, without prefixing
|
||||
* type byte, to <b>spec_out</b>, which must have enough room. May adjust
|
||||
* parameter choice based on <b>flags</b>.
|
||||
*/
|
||||
static int
|
||||
make_specifier(uint8_t *spec_out, uint8_t type, unsigned flags)
|
||||
{
|
||||
int speclen = secret_to_key_spec_len(type);
|
||||
if (speclen < 0)
|
||||
return S2K_BAD_ALGORITHM;
|
||||
|
||||
crypto_rand((char*)spec_out, speclen);
|
||||
switch (type) {
|
||||
case S2K_TYPE_RFC2440:
|
||||
/* Hash 64 k of data. */
|
||||
spec_out[S2K_RFC2440_SPECIFIER_LEN-1] = 96;
|
||||
break;
|
||||
case S2K_TYPE_PBKDF2:
|
||||
/* 131 K iterations */
|
||||
spec_out[PBKDF2_SPEC_LEN-1] = 17;
|
||||
break;
|
||||
case S2K_TYPE_SCRYPT:
|
||||
if (flags & S2K_FLAG_LOW_MEM) {
|
||||
/* N = 1<<12 */
|
||||
spec_out[SCRYPT_SPEC_LEN-2] = 12;
|
||||
} else {
|
||||
/* N = 1<<15 */
|
||||
spec_out[SCRYPT_SPEC_LEN-2] = 15;
|
||||
}
|
||||
/* r = 8; p = 2. */
|
||||
spec_out[SCRYPT_SPEC_LEN-1] = (3u << 4) | (1u << 0);
|
||||
break;
|
||||
default:
|
||||
tor_fragile_assert();
|
||||
return S2K_BAD_ALGORITHM;
|
||||
}
|
||||
|
||||
return speclen;
|
||||
}
|
||||
|
||||
/** Implement RFC2440-style iterated-salted S2K conversion: convert the
|
||||
* <b>secret_len</b>-byte <b>secret</b> into a <b>key_out_len</b> byte
|
||||
* <b>key_out</b>. As in RFC2440, the first 8 bytes of s2k_specifier
|
||||
* are a salt; the 9th byte describes how much iteration to do.
|
||||
* If <b>key_out_len</b> > DIGEST_LEN, use HDKF to expand the result.
|
||||
*/
|
||||
void
|
||||
secret_to_key_rfc2440(char *key_out, size_t key_out_len, const char *secret,
|
||||
size_t secret_len, const char *s2k_specifier)
|
||||
{
|
||||
crypto_digest_t *d;
|
||||
uint8_t c;
|
||||
size_t count, tmplen;
|
||||
char *tmp;
|
||||
uint8_t buf[DIGEST_LEN];
|
||||
tor_assert(key_out_len < SIZE_T_CEILING);
|
||||
|
||||
#define EXPBIAS 6
|
||||
c = s2k_specifier[8];
|
||||
count = ((uint32_t)16 + (c & 15)) << ((c >> 4) + EXPBIAS);
|
||||
#undef EXPBIAS
|
||||
|
||||
d = crypto_digest_new();
|
||||
tmplen = 8+secret_len;
|
||||
tmp = tor_malloc(tmplen);
|
||||
memcpy(tmp,s2k_specifier,8);
|
||||
memcpy(tmp+8,secret,secret_len);
|
||||
secret_len += 8;
|
||||
while (count) {
|
||||
if (count >= secret_len) {
|
||||
crypto_digest_add_bytes(d, tmp, secret_len);
|
||||
count -= secret_len;
|
||||
} else {
|
||||
crypto_digest_add_bytes(d, tmp, count);
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
crypto_digest_get_digest(d, (char*)buf, sizeof(buf));
|
||||
|
||||
if (key_out_len <= sizeof(buf)) {
|
||||
memcpy(key_out, buf, key_out_len);
|
||||
} else {
|
||||
crypto_expand_key_material_rfc5869_sha256(buf, DIGEST_LEN,
|
||||
(const uint8_t*)s2k_specifier, 8,
|
||||
(const uint8_t*)"EXPAND", 6,
|
||||
(uint8_t*)key_out, key_out_len);
|
||||
}
|
||||
memwipe(tmp, 0, tmplen);
|
||||
memwipe(buf, 0, sizeof(buf));
|
||||
tor_free(tmp);
|
||||
crypto_digest_free(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: given a valid specifier without prefix type byte in <b>spec</b>,
|
||||
* whose length must be correct, and given a secret passphrase <b>secret</b>
|
||||
* of length <b>secret_len</b>, compute the key and store it into
|
||||
* <b>key_out</b>, which must have enough room for secret_to_key_key_len(type)
|
||||
* bytes. Return the number of bytes written on success and an error code
|
||||
* on failure.
|
||||
*/
|
||||
STATIC int
|
||||
secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len,
|
||||
const uint8_t *spec, size_t spec_len,
|
||||
const char *secret, size_t secret_len,
|
||||
int type)
|
||||
{
|
||||
int rv;
|
||||
if (key_out_len > INT_MAX)
|
||||
return S2K_BAD_LEN;
|
||||
|
||||
switch (type) {
|
||||
case S2K_TYPE_RFC2440:
|
||||
secret_to_key_rfc2440((char*)key_out, key_out_len, secret, secret_len,
|
||||
(const char*)spec);
|
||||
return (int)key_out_len;
|
||||
|
||||
case S2K_TYPE_PBKDF2: {
|
||||
uint8_t log_iters;
|
||||
if (spec_len < 1 || secret_len > INT_MAX || spec_len > INT_MAX)
|
||||
return S2K_BAD_LEN;
|
||||
log_iters = spec[spec_len-1];
|
||||
if (log_iters > 31)
|
||||
return S2K_BAD_PARAMS;
|
||||
rv = PKCS5_PBKDF2_HMAC_SHA1(secret, (int)secret_len,
|
||||
spec, (int)spec_len-1,
|
||||
(1<<log_iters),
|
||||
(int)key_out_len, key_out);
|
||||
if (rv < 0)
|
||||
return S2K_FAILED;
|
||||
return (int)key_out_len;
|
||||
}
|
||||
|
||||
case S2K_TYPE_SCRYPT: {
|
||||
#ifdef HAVE_SCRYPT
|
||||
uint8_t log_N, log_r, log_p;
|
||||
uint64_t N;
|
||||
uint32_t r, p;
|
||||
if (spec_len < 2)
|
||||
return S2K_BAD_LEN;
|
||||
log_N = spec[spec_len-2];
|
||||
log_r = (spec[spec_len-1]) >> 4;
|
||||
log_p = (spec[spec_len-1]) & 15;
|
||||
if (log_N > 63)
|
||||
return S2K_BAD_PARAMS;
|
||||
N = ((uint64_t)1) << log_N;
|
||||
r = 1u << log_r;
|
||||
p = 1u << log_p;
|
||||
rv = libscrypt_scrypt((const uint8_t*)secret, secret_len,
|
||||
spec, spec_len-2, N, r, p, key_out, key_out_len);
|
||||
if (rv != 0)
|
||||
return S2K_FAILED;
|
||||
return (int)key_out_len;
|
||||
#else
|
||||
return S2K_NO_SCRYPT_SUPPORT;
|
||||
#endif
|
||||
}
|
||||
default:
|
||||
return S2K_BAD_ALGORITHM;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a specifier previously constructed with secret_to_key_make_specifier
|
||||
* in <b>spec</b> of length <b>spec_len</b>, and a secret password in
|
||||
* <b>secret</b> of length <b>secret_len</b>, generate <b>key_out_len</b>
|
||||
* bytes of cryptographic material in <b>key_out</b>. The native output of
|
||||
* the secret-to-key function will be truncated if key_out_len is short, and
|
||||
* expanded with HKDF if key_out_len is long. Returns S2K_OKAY on success,
|
||||
* and an error code on failure.
|
||||
*/
|
||||
int
|
||||
secret_to_key_derivekey(uint8_t *key_out, size_t key_out_len,
|
||||
const uint8_t *spec, size_t spec_len,
|
||||
const char *secret, size_t secret_len)
|
||||
{
|
||||
int legacy_format = 0;
|
||||
int type = secret_to_key_get_type(spec, spec_len, 0, &legacy_format);
|
||||
int r;
|
||||
|
||||
if (type < 0)
|
||||
return type;
|
||||
#ifndef HAVE_SCRYPT
|
||||
if (type == S2K_TYPE_SCRYPT)
|
||||
return S2K_NO_SCRYPT_SUPPORT;
|
||||
#endif
|
||||
|
||||
if (! legacy_format) {
|
||||
++spec;
|
||||
--spec_len;
|
||||
}
|
||||
|
||||
r = secret_to_key_compute_key(key_out, key_out_len, spec, spec_len,
|
||||
secret, secret_len, type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
else
|
||||
return S2K_OKAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new s2k algorithm specifier and salt in <b>buf</b>, according
|
||||
* to the bitwise-or of some S2K_FLAG_* options in <b>flags</b>. Up to
|
||||
* <b>buf_len</b> bytes of storage may be used in <b>buf</b>. Return the
|
||||
* number of bytes used on success and an error code on failure.
|
||||
*/
|
||||
int
|
||||
secret_to_key_make_specifier(uint8_t *buf, size_t buf_len, unsigned flags)
|
||||
{
|
||||
int rv;
|
||||
int spec_len;
|
||||
#ifdef HAVE_SCRYPT
|
||||
uint8_t type = S2K_TYPE_SCRYPT;
|
||||
#else
|
||||
uint8_t type = S2K_TYPE_RFC2440;
|
||||
#endif
|
||||
|
||||
if (flags & S2K_FLAG_NO_SCRYPT)
|
||||
type = S2K_TYPE_RFC2440;
|
||||
if (flags & S2K_FLAG_USE_PBKDF2)
|
||||
type = S2K_TYPE_PBKDF2;
|
||||
|
||||
spec_len = secret_to_key_spec_len(type);
|
||||
|
||||
if ((int)buf_len < spec_len + 1)
|
||||
return S2K_TRUNCATED;
|
||||
|
||||
buf[0] = type;
|
||||
rv = make_specifier(buf+1, type, flags);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
else
|
||||
return rv + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash a passphrase from <b>secret</b> of length <b>secret_len</b>, according
|
||||
* to the bitwise-or of some S2K_FLAG_* options in <b>flags</b>, and store the
|
||||
* hash along with salt and hashing parameters into <b>buf</b>. Up to
|
||||
* <b>buf_len</b> bytes of storage may be used in <b>buf</b>. Set
|
||||
* *<b>len_out</b> to the number of bytes used and return S2K_OKAY on success;
|
||||
* and return an error code on failure.
|
||||
*/
|
||||
int
|
||||
secret_to_key_new(uint8_t *buf,
|
||||
size_t buf_len,
|
||||
size_t *len_out,
|
||||
const char *secret, size_t secret_len,
|
||||
unsigned flags)
|
||||
{
|
||||
int key_len;
|
||||
int spec_len;
|
||||
int type;
|
||||
int rv;
|
||||
|
||||
spec_len = secret_to_key_make_specifier(buf, buf_len, flags);
|
||||
|
||||
if (spec_len < 0)
|
||||
return spec_len;
|
||||
|
||||
type = buf[0];
|
||||
key_len = secret_to_key_key_len(type);
|
||||
|
||||
if ((int)buf_len < key_len + spec_len)
|
||||
return S2K_TRUNCATED;
|
||||
|
||||
rv = secret_to_key_compute_key(buf + spec_len, key_len,
|
||||
buf + 1, spec_len-1,
|
||||
secret, secret_len, type);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
*len_out = spec_len + key_len;
|
||||
|
||||
return S2K_OKAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a hashed passphrase in <b>spec_and_key</b> of length
|
||||
* <b>spec_and_key_len</b> as generated by secret_to_key_new(), verify whether
|
||||
* it is a hash of the passphrase <b>secret</b> of length <b>secret_len</b>.
|
||||
* Return S2K_OKAY on a match, S2K_BAD_SECRET on a well-formed hash that
|
||||
* doesn't match this secret, and another error code on other errors.
|
||||
*/
|
||||
int
|
||||
secret_to_key_check(const uint8_t *spec_and_key, size_t spec_and_key_len,
|
||||
const char *secret, size_t secret_len)
|
||||
{
|
||||
int is_legacy = 0;
|
||||
int type = secret_to_key_get_type(spec_and_key, spec_and_key_len,
|
||||
1, &is_legacy);
|
||||
uint8_t buf[32];
|
||||
int spec_len;
|
||||
int key_len;
|
||||
int rv;
|
||||
|
||||
if (type < 0)
|
||||
return type;
|
||||
|
||||
if (! is_legacy) {
|
||||
spec_and_key++;
|
||||
spec_and_key_len--;
|
||||
}
|
||||
|
||||
spec_len = secret_to_key_spec_len(type);
|
||||
key_len = secret_to_key_key_len(type);
|
||||
tor_assert(spec_len > 0);
|
||||
tor_assert(key_len > 0);
|
||||
tor_assert(key_len <= (int) sizeof(buf));
|
||||
tor_assert((int)spec_and_key_len == spec_len + key_len);
|
||||
rv = secret_to_key_compute_key(buf, key_len,
|
||||
spec_and_key, spec_len,
|
||||
secret, secret_len, type);
|
||||
if (rv < 0)
|
||||
goto done;
|
||||
|
||||
if (tor_memeq(buf, spec_and_key + spec_len, key_len))
|
||||
rv = S2K_OKAY;
|
||||
else
|
||||
rv = S2K_BAD_SECRET;
|
||||
|
||||
done:
|
||||
memwipe(buf, 0, sizeof(buf));
|
||||
return rv;
|
||||
}
|
||||
|
73
src/common/crypto_s2k.h
Normal file
73
src/common/crypto_s2k.h
Normal file
@ -0,0 +1,73 @@
|
||||
/* Copyright (c) 2001, Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TOR_CRYPTO_S2K_H_INCLUDED
|
||||
#define TOR_CRYPTO_S2K_H_INCLUDED
|
||||
|
||||
#include <stdio.h>
|
||||
#include "torint.h"
|
||||
|
||||
/** Length of RFC2440-style S2K specifier: the first 8 bytes are a salt, the
|
||||
* 9th describes how much iteration to do. */
|
||||
#define S2K_RFC2440_SPECIFIER_LEN 9
|
||||
void secret_to_key_rfc2440(
|
||||
char *key_out, size_t key_out_len, const char *secret,
|
||||
size_t secret_len, const char *s2k_specifier);
|
||||
|
||||
/** Flag for secret-to-key function: do not use scrypt. */
|
||||
#define S2K_FLAG_NO_SCRYPT (1u<<0)
|
||||
/** Flag for secret-to-key functions: if using a memory-tuned s2k function,
|
||||
* assume that we have limited memory. */
|
||||
#define S2K_FLAG_LOW_MEM (1u<<1)
|
||||
/** Flag for secret-to-key functions: force use of pbkdf2. Without this, we
|
||||
* default to scrypt, then RFC2440. */
|
||||
#define S2K_FLAG_USE_PBKDF2 (1u<<2)
|
||||
|
||||
/** Maximum possible output length from secret_to_key_new. */
|
||||
#define S2K_MAXLEN 64
|
||||
|
||||
/** Error code from secret-to-key functions: all is well */
|
||||
#define S2K_OKAY 0
|
||||
/** Error code from secret-to-key functions: generic failure */
|
||||
#define S2K_FAILED -1
|
||||
/** Error code from secret-to-key functions: provided secret didn't match */
|
||||
#define S2K_BAD_SECRET -2
|
||||
/** Error code from secret-to-key functions: didn't recognize the algorithm */
|
||||
#define S2K_BAD_ALGORITHM -3
|
||||
/** Error code from secret-to-key functions: specifier wasn't valid */
|
||||
#define S2K_BAD_PARAMS -4
|
||||
/** Error code from secret-to-key functions: compiled without scrypt */
|
||||
#define S2K_NO_SCRYPT_SUPPORT -5
|
||||
/** Error code from secret-to-key functions: not enough space to write output.
|
||||
*/
|
||||
#define S2K_TRUNCATED -6
|
||||
/** Error code from secret-to-key functions: Wrong length for specifier. */
|
||||
#define S2K_BAD_LEN -7
|
||||
|
||||
int secret_to_key_new(uint8_t *buf,
|
||||
size_t buf_len,
|
||||
size_t *len_out,
|
||||
const char *secret, size_t secret_len,
|
||||
unsigned flags);
|
||||
|
||||
int secret_to_key_make_specifier(uint8_t *buf, size_t buf_len, unsigned flags);
|
||||
|
||||
int secret_to_key_check(const uint8_t *spec_and_key, size_t spec_and_key_len,
|
||||
const char *secret, size_t secret_len);
|
||||
|
||||
int secret_to_key_derivekey(uint8_t *key_out, size_t key_out_len,
|
||||
const uint8_t *spec, size_t spec_len,
|
||||
const char *secret, size_t secret_len);
|
||||
|
||||
#ifdef CRYPTO_S2K_PRIVATE
|
||||
STATIC int secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len,
|
||||
const uint8_t *spec, size_t spec_len,
|
||||
const char *secret, size_t secret_len,
|
||||
int type);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -16,7 +16,7 @@ EXTRA_DIST+= \
|
||||
src/common/Makefile.nmake
|
||||
|
||||
#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
|
||||
libor_extra_source=src/ext/OpenBSD_malloc_Linux.c
|
||||
@ -69,15 +69,19 @@ LIBOR_A_SOURCES = \
|
||||
src/common/util_process.c \
|
||||
src/common/sandbox.c \
|
||||
src/ext/csiphash.c \
|
||||
src/ext/trunnel/trunnel.c \
|
||||
$(libor_extra_source) \
|
||||
$(libor_mempool_source)
|
||||
|
||||
LIBOR_CRYPTO_A_SOURCES = \
|
||||
src/common/aes.c \
|
||||
src/common/crypto.c \
|
||||
src/common/crypto_pwbox.c \
|
||||
src/common/crypto_s2k.c \
|
||||
src/common/crypto_format.c \
|
||||
src/common/torgzip.c \
|
||||
src/common/tortls.c \
|
||||
src/trunnel/pwbox.c \
|
||||
$(libcrypto_extra_source)
|
||||
|
||||
LIBOR_EVENT_A_SOURCES = \
|
||||
@ -110,6 +114,8 @@ COMMONHEADERS = \
|
||||
src/common/container.h \
|
||||
src/common/crypto.h \
|
||||
src/common/crypto_curve25519.h \
|
||||
src/common/crypto_pwbox.h \
|
||||
src/common/crypto_s2k.h \
|
||||
src/common/di_ops.h \
|
||||
src/common/memarea.h \
|
||||
src/common/linux_syscalls.inc \
|
||||
|
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/trunnel/include.am
|
||||
include src/common/include.am
|
||||
include src/or/include.am
|
||||
include src/test/include.am
|
||||
include src/tools/include.am
|
||||
include src/win32/include.am
|
||||
include src/config/include.am
|
||||
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#include "crypto_s2k.h"
|
||||
#include "procmon.h"
|
||||
|
||||
/** Yield true iff <b>s</b> is the state of a control_connection_t that has
|
||||
@ -995,7 +996,8 @@ handle_control_setevents(control_connection_t *conn, uint32_t len,
|
||||
|
||||
/** Decode the hashed, base64'd passwords stored in <b>passwords</b>.
|
||||
* Return a smartlist of acceptable passwords (unterminated strings of
|
||||
* length S2K_SPECIFIER_LEN+DIGEST_LEN) on success, or NULL on failure.
|
||||
* length S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) on success, or NULL on
|
||||
* failure.
|
||||
*/
|
||||
smartlist_t *
|
||||
decode_hashed_passwords(config_line_t *passwords)
|
||||
@ -1011,16 +1013,17 @@ decode_hashed_passwords(config_line_t *passwords)
|
||||
|
||||
if (!strcmpstart(hashed, "16:")) {
|
||||
if (base16_decode(decoded, sizeof(decoded), hashed+3, strlen(hashed+3))<0
|
||||
|| strlen(hashed+3) != (S2K_SPECIFIER_LEN+DIGEST_LEN)*2) {
|
||||
|| strlen(hashed+3) != (S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN)*2) {
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
if (base64_decode(decoded, sizeof(decoded), hashed, strlen(hashed))
|
||||
!= S2K_SPECIFIER_LEN+DIGEST_LEN) {
|
||||
!= S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
smartlist_add(sl, tor_memdup(decoded, S2K_SPECIFIER_LEN+DIGEST_LEN));
|
||||
smartlist_add(sl,
|
||||
tor_memdup(decoded, S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN));
|
||||
}
|
||||
|
||||
return sl;
|
||||
@ -1173,8 +1176,10 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len,
|
||||
} else {
|
||||
SMARTLIST_FOREACH(sl, char *, expected,
|
||||
{
|
||||
secret_to_key(received,DIGEST_LEN,password,password_len,expected);
|
||||
if (tor_memeq(expected+S2K_SPECIFIER_LEN, received, DIGEST_LEN))
|
||||
secret_to_key_rfc2440(received,DIGEST_LEN,
|
||||
password,password_len,expected);
|
||||
if (tor_memeq(expected + S2K_RFC2440_SPECIFIER_LEN,
|
||||
received, DIGEST_LEN))
|
||||
goto ok;
|
||||
});
|
||||
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "connection_or.h"
|
||||
#include "control.h"
|
||||
#include "cpuworker.h"
|
||||
#include "crypto_s2k.h"
|
||||
#include "directory.h"
|
||||
#include "dirserv.h"
|
||||
#include "dirvote.h"
|
||||
@ -2674,11 +2675,11 @@ do_hash_password(void)
|
||||
{
|
||||
|
||||
char output[256];
|
||||
char key[S2K_SPECIFIER_LEN+DIGEST_LEN];
|
||||
char key[S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN];
|
||||
|
||||
crypto_rand(key, S2K_SPECIFIER_LEN-1);
|
||||
key[S2K_SPECIFIER_LEN-1] = (uint8_t)96; /* Hash 64 K of data. */
|
||||
secret_to_key(key+S2K_SPECIFIER_LEN, DIGEST_LEN,
|
||||
crypto_rand(key, S2K_RFC2440_SPECIFIER_LEN-1);
|
||||
key[S2K_RFC2440_SPECIFIER_LEN-1] = (uint8_t)96; /* Hash 64 K of data. */
|
||||
secret_to_key_rfc2440(key+S2K_RFC2440_SPECIFIER_LEN, DIGEST_LEN,
|
||||
get_options()->command_arg, strlen(get_options()->command_arg),
|
||||
key);
|
||||
base16_encode(output, sizeof(output), key, sizeof(key));
|
||||
|
@ -60,7 +60,7 @@ src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
|
||||
@TOR_LDFLAGS_libevent@
|
||||
src_test_test_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \
|
||||
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_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "orconfig.h"
|
||||
#define CRYPTO_CURVE25519_PRIVATE
|
||||
#define CRYPTO_S2K_PRIVATE
|
||||
#include "or.h"
|
||||
#include "test.h"
|
||||
#include "aes.h"
|
||||
@ -13,6 +14,8 @@
|
||||
#ifdef CURVE25519_ENABLED
|
||||
#include "crypto_curve25519.h"
|
||||
#endif
|
||||
#include "crypto_s2k.h"
|
||||
#include "crypto_pwbox.h"
|
||||
|
||||
extern const char AUTHORITY_SIGNKEY_3[];
|
||||
extern const char AUTHORITY_SIGNKEY_A_DIGEST[];
|
||||
@ -710,7 +713,7 @@ test_crypto_formats(void *arg)
|
||||
|
||||
/** Run unit tests for our secret-to-key passphrase hashing functionality. */
|
||||
static void
|
||||
test_crypto_s2k(void *arg)
|
||||
test_crypto_s2k_rfc2440(void *arg)
|
||||
{
|
||||
char buf[29];
|
||||
char buf2[29];
|
||||
@ -723,7 +726,7 @@ test_crypto_s2k(void *arg)
|
||||
buf3 = tor_malloc(65536);
|
||||
memset(buf3, 0, 65536);
|
||||
|
||||
secret_to_key(buf+9, 20, "", 0, buf);
|
||||
secret_to_key_rfc2440(buf+9, 20, "", 0, buf);
|
||||
crypto_digest(buf2+9, buf3, 1024);
|
||||
tt_mem_op(buf,==, buf2, 29);
|
||||
|
||||
@ -731,7 +734,7 @@ test_crypto_s2k(void *arg)
|
||||
memcpy(buf2,"vrbacrda",8);
|
||||
buf[8] = 96;
|
||||
buf2[8] = 96;
|
||||
secret_to_key(buf+9, 20, "12345678", 8, buf);
|
||||
secret_to_key_rfc2440(buf+9, 20, "12345678", 8, buf);
|
||||
for (i = 0; i < 65536; i += 16) {
|
||||
memcpy(buf3+i, "vrbacrda12345678", 16);
|
||||
}
|
||||
@ -742,6 +745,342 @@ test_crypto_s2k(void *arg)
|
||||
tor_free(buf3);
|
||||
}
|
||||
|
||||
static void
|
||||
run_s2k_tests(const unsigned flags, const unsigned type,
|
||||
int speclen, const int keylen, int legacy)
|
||||
{
|
||||
uint8_t buf[S2K_MAXLEN], buf2[S2K_MAXLEN], buf3[S2K_MAXLEN];
|
||||
int r;
|
||||
size_t sz;
|
||||
const char pw1[] = "You can't come in here unless you say swordfish!";
|
||||
const char pw2[] = "Now, I give you one more guess.";
|
||||
|
||||
r = secret_to_key_new(buf, sizeof(buf), &sz,
|
||||
pw1, strlen(pw1), flags);
|
||||
tt_int_op(r, ==, S2K_OKAY);
|
||||
tt_int_op(buf[0], ==, type);
|
||||
|
||||
tt_int_op(sz, ==, keylen + speclen);
|
||||
|
||||
if (legacy) {
|
||||
memmove(buf, buf+1, sz-1);
|
||||
--sz;
|
||||
--speclen;
|
||||
}
|
||||
|
||||
tt_int_op(S2K_OKAY, ==,
|
||||
secret_to_key_check(buf, sz, pw1, strlen(pw1)));
|
||||
|
||||
tt_int_op(S2K_BAD_SECRET, ==,
|
||||
secret_to_key_check(buf, sz, pw2, strlen(pw2)));
|
||||
|
||||
/* Move key to buf2, and clear it. */
|
||||
memset(buf3, 0, sizeof(buf3));
|
||||
memcpy(buf2, buf+speclen, keylen);
|
||||
memset(buf+speclen, 0, sz - speclen);
|
||||
|
||||
/* Derivekey should produce the same results. */
|
||||
tt_int_op(S2K_OKAY, ==,
|
||||
secret_to_key_derivekey(buf3, keylen, buf, speclen, pw1, strlen(pw1)));
|
||||
|
||||
tt_mem_op(buf2, ==, buf3, keylen);
|
||||
|
||||
/* Derivekey with a longer output should fill the output. */
|
||||
memset(buf2, 0, sizeof(buf2));
|
||||
tt_int_op(S2K_OKAY, ==,
|
||||
secret_to_key_derivekey(buf2, sizeof(buf2), buf, speclen,
|
||||
pw1, strlen(pw1)));
|
||||
|
||||
tt_mem_op(buf2, !=, buf3, sizeof(buf2));
|
||||
|
||||
memset(buf3, 0, sizeof(buf3));
|
||||
tt_int_op(S2K_OKAY, ==,
|
||||
secret_to_key_derivekey(buf3, sizeof(buf3), buf, speclen,
|
||||
pw1, strlen(pw1)));
|
||||
tt_mem_op(buf2, ==, buf3, sizeof(buf3));
|
||||
tt_assert(!tor_mem_is_zero((char*)buf2+keylen, sizeof(buf2)-keylen));
|
||||
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
test_crypto_s2k_general(void *arg)
|
||||
{
|
||||
const char *which = arg;
|
||||
|
||||
if (!strcmp(which, "scrypt")) {
|
||||
run_s2k_tests(0, 2, 19, 32, 0);
|
||||
} else if (!strcmp(which, "scrypt-low")) {
|
||||
run_s2k_tests(S2K_FLAG_LOW_MEM, 2, 19, 32, 0);
|
||||
} else if (!strcmp(which, "pbkdf2")) {
|
||||
run_s2k_tests(S2K_FLAG_USE_PBKDF2, 1, 18, 20, 0);
|
||||
} else if (!strcmp(which, "rfc2440")) {
|
||||
run_s2k_tests(S2K_FLAG_NO_SCRYPT, 0, 10, 20, 0);
|
||||
} else if (!strcmp(which, "rfc2440-legacy")) {
|
||||
run_s2k_tests(S2K_FLAG_NO_SCRYPT, 0, 10, 20, 1);
|
||||
} else {
|
||||
tt_fail();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_crypto_s2k_errors(void *arg)
|
||||
{
|
||||
uint8_t buf[S2K_MAXLEN], buf2[S2K_MAXLEN];
|
||||
size_t sz;
|
||||
|
||||
(void)arg;
|
||||
|
||||
/* Bogus specifiers: simple */
|
||||
tt_int_op(S2K_BAD_LEN, ==,
|
||||
secret_to_key_derivekey(buf, sizeof(buf),
|
||||
(const uint8_t*)"", 0, "ABC", 3));
|
||||
tt_int_op(S2K_BAD_ALGORITHM, ==,
|
||||
secret_to_key_derivekey(buf, sizeof(buf),
|
||||
(const uint8_t*)"\x10", 1, "ABC", 3));
|
||||
tt_int_op(S2K_BAD_LEN, ==,
|
||||
secret_to_key_derivekey(buf, sizeof(buf),
|
||||
(const uint8_t*)"\x01\x02", 2, "ABC", 3));
|
||||
|
||||
tt_int_op(S2K_BAD_LEN, ==,
|
||||
secret_to_key_check((const uint8_t*)"", 0, "ABC", 3));
|
||||
tt_int_op(S2K_BAD_ALGORITHM, ==,
|
||||
secret_to_key_check((const uint8_t*)"\x10", 1, "ABC", 3));
|
||||
tt_int_op(S2K_BAD_LEN, ==,
|
||||
secret_to_key_check((const uint8_t*)"\x01\x02", 2, "ABC", 3));
|
||||
|
||||
/* too long gets "BAD_LEN" too */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf[0] = 2;
|
||||
tt_int_op(S2K_BAD_LEN, ==,
|
||||
secret_to_key_derivekey(buf2, sizeof(buf2),
|
||||
buf, sizeof(buf), "ABC", 3));
|
||||
|
||||
/* Truncated output */
|
||||
#ifdef HAVE_LIBSCRYPT_H
|
||||
tt_int_op(S2K_TRUNCATED, ==, secret_to_key_new(buf, 50, &sz,
|
||||
"ABC", 3, 0));
|
||||
tt_int_op(S2K_TRUNCATED, ==, secret_to_key_new(buf, 50, &sz,
|
||||
"ABC", 3, S2K_FLAG_LOW_MEM));
|
||||
#endif
|
||||
tt_int_op(S2K_TRUNCATED, ==, secret_to_key_new(buf, 37, &sz,
|
||||
"ABC", 3, S2K_FLAG_USE_PBKDF2));
|
||||
tt_int_op(S2K_TRUNCATED, ==, secret_to_key_new(buf, 29, &sz,
|
||||
"ABC", 3, S2K_FLAG_NO_SCRYPT));
|
||||
|
||||
#ifdef HAVE_LIBSCRYPT_H
|
||||
tt_int_op(S2K_TRUNCATED, ==, secret_to_key_make_specifier(buf, 18, 0));
|
||||
tt_int_op(S2K_TRUNCATED, ==, secret_to_key_make_specifier(buf, 18,
|
||||
S2K_FLAG_LOW_MEM));
|
||||
#endif
|
||||
tt_int_op(S2K_TRUNCATED, ==, secret_to_key_make_specifier(buf, 17,
|
||||
S2K_FLAG_USE_PBKDF2));
|
||||
tt_int_op(S2K_TRUNCATED, ==, secret_to_key_make_specifier(buf, 9,
|
||||
S2K_FLAG_NO_SCRYPT));
|
||||
|
||||
/* Now try using type-specific bogus specifiers. */
|
||||
|
||||
/* It's a bad pbkdf2 buffer if it has an iteration count that would overflow
|
||||
* int32_t. */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf[0] = 1; /* pbkdf2 */
|
||||
buf[17] = 100; /* 1<<100 is much bigger than INT32_MAX */
|
||||
tt_int_op(S2K_BAD_PARAMS, ==,
|
||||
secret_to_key_derivekey(buf2, sizeof(buf2),
|
||||
buf, 18, "ABC", 3));
|
||||
|
||||
#ifdef HAVE_LIBSCRYPT_H
|
||||
/* It's a bad scrypt buffer if N would overflow uint64 */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf[0] = 2; /* scrypt */
|
||||
buf[17] = 100; /* 1<<100 is much bigger than UINT64_MAX */
|
||||
tt_int_op(S2K_BAD_PARAMS, ==,
|
||||
secret_to_key_derivekey(buf2, sizeof(buf2),
|
||||
buf, 19, "ABC", 3));
|
||||
#endif
|
||||
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
static void
|
||||
test_crypto_scrypt_vectors(void *arg)
|
||||
{
|
||||
char *mem_op_hex_tmp = NULL;
|
||||
uint8_t spec[64], out[64];
|
||||
|
||||
(void)arg;
|
||||
#ifndef HAVE_LIBSCRYPT_H
|
||||
if (1)
|
||||
tt_skip();
|
||||
#endif
|
||||
|
||||
/* Test vectors from
|
||||
http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00 section 11.
|
||||
|
||||
Note that the names of 'r' and 'N' are switched in that section. Or
|
||||
possibly in libscrypt.
|
||||
*/
|
||||
|
||||
base16_decode((char*)spec, sizeof(spec),
|
||||
"0400", 4);
|
||||
memset(out, 0x00, sizeof(out));
|
||||
tt_int_op(64, ==,
|
||||
secret_to_key_compute_key(out, 64, spec, 2, "", 0, 2));
|
||||
test_memeq_hex(out,
|
||||
"77d6576238657b203b19ca42c18a0497"
|
||||
"f16b4844e3074ae8dfdffa3fede21442"
|
||||
"fcd0069ded0948f8326a753a0fc81f17"
|
||||
"e8d3e0fb2e0d3628cf35e20c38d18906");
|
||||
|
||||
base16_decode((char*)spec, sizeof(spec),
|
||||
"4e61436c" "0A34", 12);
|
||||
memset(out, 0x00, sizeof(out));
|
||||
tt_int_op(64, ==,
|
||||
secret_to_key_compute_key(out, 64, spec, 6, "password", 8, 2));
|
||||
test_memeq_hex(out,
|
||||
"fdbabe1c9d3472007856e7190d01e9fe"
|
||||
"7c6ad7cbc8237830e77376634b373162"
|
||||
"2eaf30d92e22a3886ff109279d9830da"
|
||||
"c727afb94a83ee6d8360cbdfa2cc0640");
|
||||
|
||||
base16_decode((char*)spec, sizeof(spec),
|
||||
"536f6469756d43686c6f72696465" "0e30", 32);
|
||||
memset(out, 0x00, sizeof(out));
|
||||
tt_int_op(64, ==,
|
||||
secret_to_key_compute_key(out, 64, spec, 16,
|
||||
"pleaseletmein", 13, 2));
|
||||
test_memeq_hex(out,
|
||||
"7023bdcb3afd7348461c06cd81fd38eb"
|
||||
"fda8fbba904f8e3ea9b543f6545da1f2"
|
||||
"d5432955613f0fcf62d49705242a9af9"
|
||||
"e61e85dc0d651e40dfcf017b45575887");
|
||||
|
||||
base16_decode((char*)spec, sizeof(spec),
|
||||
"536f6469756d43686c6f72696465" "1430", 32);
|
||||
memset(out, 0x00, sizeof(out));
|
||||
tt_int_op(64, ==,
|
||||
secret_to_key_compute_key(out, 64, spec, 16,
|
||||
"pleaseletmein", 13, 2));
|
||||
test_memeq_hex(out,
|
||||
"2101cb9b6a511aaeaddbbe09cf70f881"
|
||||
"ec568d574a2ffd4dabe5ee9820adaa47"
|
||||
"8e56fd8f4ba5d09ffa1c6d927c40f4c3"
|
||||
"37304049e8a952fbcbf45c6fa77a41a4");
|
||||
|
||||
done:
|
||||
tor_free(mem_op_hex_tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
test_crypto_pbkdf2_vectors(void *arg)
|
||||
{
|
||||
char *mem_op_hex_tmp = NULL;
|
||||
uint8_t spec[64], out[64];
|
||||
(void)arg;
|
||||
|
||||
/* Test vectors from RFC6070, section 2 */
|
||||
base16_decode((char*)spec, sizeof(spec),
|
||||
"73616c74" "00" , 10);
|
||||
memset(out, 0x00, sizeof(out));
|
||||
tt_int_op(20, ==,
|
||||
secret_to_key_compute_key(out, 20, spec, 5, "password", 8, 1));
|
||||
test_memeq_hex(out, "0c60c80f961f0e71f3a9b524af6012062fe037a6");
|
||||
|
||||
base16_decode((char*)spec, sizeof(spec),
|
||||
"73616c74" "01" , 10);
|
||||
memset(out, 0x00, sizeof(out));
|
||||
tt_int_op(20, ==,
|
||||
secret_to_key_compute_key(out, 20, spec, 5, "password", 8, 1));
|
||||
test_memeq_hex(out, "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957");
|
||||
|
||||
base16_decode((char*)spec, sizeof(spec),
|
||||
"73616c74" "0C" , 10);
|
||||
memset(out, 0x00, sizeof(out));
|
||||
tt_int_op(20, ==,
|
||||
secret_to_key_compute_key(out, 20, spec, 5, "password", 8, 1));
|
||||
test_memeq_hex(out, "4b007901b765489abead49d926f721d065a429c1");
|
||||
|
||||
base16_decode((char*)spec, sizeof(spec),
|
||||
"73616c74" "18" , 10);
|
||||
memset(out, 0x00, sizeof(out));
|
||||
tt_int_op(20, ==,
|
||||
secret_to_key_compute_key(out, 20, spec, 5, "password", 8, 1));
|
||||
test_memeq_hex(out, "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984");
|
||||
|
||||
base16_decode((char*)spec, sizeof(spec),
|
||||
"73616c7453414c5473616c7453414c5473616c745"
|
||||
"3414c5473616c7453414c5473616c74" "0C" , 74);
|
||||
memset(out, 0x00, sizeof(out));
|
||||
tt_int_op(25, ==,
|
||||
secret_to_key_compute_key(out, 25, spec, 37,
|
||||
"passwordPASSWORDpassword", 24, 1));
|
||||
test_memeq_hex(out, "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038");
|
||||
|
||||
base16_decode((char*)spec, sizeof(spec),
|
||||
"7361006c74" "0c" , 12);
|
||||
memset(out, 0x00, sizeof(out));
|
||||
tt_int_op(16, ==,
|
||||
secret_to_key_compute_key(out, 16, spec, 6, "pass\0word", 9, 1));
|
||||
test_memeq_hex(out, "56fa6aa75548099dcc37d7f03425e0c3");
|
||||
|
||||
done:
|
||||
tor_free(mem_op_hex_tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
test_crypto_pwbox(void *arg)
|
||||
{
|
||||
uint8_t *boxed=NULL, *decoded=NULL;
|
||||
size_t len, dlen;
|
||||
unsigned i;
|
||||
const char msg[] = "This bunny reminds you that you still have a "
|
||||
"salamander in your sylladex. She is holding the bunny Dave got you. "
|
||||
"It’s sort of uncanny how similar they are, aside from the knitted "
|
||||
"enhancements. Seriously, what are the odds?? So weird.";
|
||||
const char pw[] = "I'm a night owl and a wise bird too";
|
||||
|
||||
const unsigned flags[] = { 0,
|
||||
S2K_FLAG_NO_SCRYPT,
|
||||
S2K_FLAG_LOW_MEM,
|
||||
S2K_FLAG_NO_SCRYPT|S2K_FLAG_LOW_MEM,
|
||||
S2K_FLAG_USE_PBKDF2 };
|
||||
(void)arg;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(flags); ++i) {
|
||||
tt_int_op(0, ==, crypto_pwbox(&boxed, &len, (const uint8_t*)msg, strlen(msg),
|
||||
pw, strlen(pw), flags[i]));
|
||||
tt_assert(boxed);
|
||||
tt_assert(len > 128+32);
|
||||
|
||||
tt_int_op(0, ==, crypto_unpwbox(&decoded, &dlen, boxed, len,
|
||||
pw, strlen(pw)));
|
||||
|
||||
tt_assert(decoded);
|
||||
tt_uint_op(dlen, ==, strlen(msg));
|
||||
tt_mem_op(decoded, ==, msg, dlen);
|
||||
|
||||
tor_free(decoded);
|
||||
|
||||
tt_int_op(UNPWBOX_BAD_SECRET, ==, crypto_unpwbox(&decoded, &dlen, boxed, len,
|
||||
pw, strlen(pw)-1));
|
||||
boxed[len-1] ^= 1;
|
||||
tt_int_op(UNPWBOX_BAD_SECRET, ==, crypto_unpwbox(&decoded, &dlen, boxed, len,
|
||||
pw, strlen(pw)));
|
||||
boxed[0] = 255;
|
||||
tt_int_op(UNPWBOX_CORRUPTED, ==, crypto_unpwbox(&decoded, &dlen, boxed, len,
|
||||
pw, strlen(pw)));
|
||||
|
||||
tor_free(boxed);
|
||||
}
|
||||
|
||||
done:
|
||||
tor_free(boxed);
|
||||
tor_free(decoded);
|
||||
|
||||
}
|
||||
|
||||
/** Test AES-CTR encryption and decryption with IV. */
|
||||
static void
|
||||
test_crypto_aes_iv(void *arg)
|
||||
@ -1304,7 +1643,23 @@ struct testcase_t crypto_tests[] = {
|
||||
{ "pk_fingerprints", test_crypto_pk_fingerprints, TT_FORK, NULL, NULL },
|
||||
CRYPTO_LEGACY(digests),
|
||||
CRYPTO_LEGACY(dh),
|
||||
CRYPTO_LEGACY(s2k),
|
||||
CRYPTO_LEGACY(s2k_rfc2440),
|
||||
#ifdef HAVE_LIBSCRYPT_H
|
||||
{ "s2k_scrypt", test_crypto_s2k_general, 0, &pass_data,
|
||||
(void*)"scrypt" },
|
||||
{ "s2k_scrypt_low", test_crypto_s2k_general, 0, &pass_data,
|
||||
(void*)"scrypt-low" },
|
||||
#endif
|
||||
{ "s2k_pbkdf2", test_crypto_s2k_general, 0, &pass_data,
|
||||
(void*)"pbkdf2" },
|
||||
{ "s2k_rfc2440_general", test_crypto_s2k_general, 0, &pass_data,
|
||||
(void*)"rfc2440" },
|
||||
{ "s2k_rfc2440_legacy", test_crypto_s2k_general, 0, &pass_data,
|
||||
(void*)"rfc2440-legacy" },
|
||||
{ "s2k_errors", test_crypto_s2k_errors, 0, NULL, NULL },
|
||||
{ "scrypt_vectors", test_crypto_scrypt_vectors, 0, NULL, NULL },
|
||||
{ "pbkdf2_vectors", test_crypto_pbkdf2_vectors, 0, NULL, NULL },
|
||||
{ "pwbox", test_crypto_pwbox, 0, NULL, NULL },
|
||||
{ "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"aes" },
|
||||
{ "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"evp" },
|
||||
CRYPTO_LEGACY(base32_decode),
|
||||
|
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