diff options
Diffstat (limited to 'src/common/crypto_ed25519.c')
-rw-r--r-- | src/common/crypto_ed25519.c | 165 |
1 files changed, 123 insertions, 42 deletions
diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c index 30ed772274..9c13e3bdf0 100644 --- a/src/common/crypto_ed25519.c +++ b/src/common/crypto_ed25519.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Tor Project, Inc. */ +/* Copyright (c) 2013-2017, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,26 +15,26 @@ * keys to and from the corresponding Curve25519 keys. */ +#define CRYPTO_ED25519_PRIVATE #include "orconfig.h" #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif -#include "crypto.h" - #include "crypto_curve25519.h" +#include "crypto_digest.h" #include "crypto_ed25519.h" #include "crypto_format.h" +#include "crypto_rand.h" +#include "crypto_util.h" #include "torlog.h" #include "util.h" +#include "util_format.h" #include "ed25519/ref10/ed25519_ref10.h" #include "ed25519/donna/ed25519_donna_tor.h" -#include <openssl/sha.h> - static void pick_ed25519_impl(void); -static int ed25519_impl_spot_check(void); /** An Ed25519 implementation, as a set of function pointers. */ typedef struct { @@ -59,6 +59,9 @@ typedef struct { int (*pubkey_from_curve25519_pubkey)(unsigned char *, const unsigned char *, int); + + int (*ed25519_scalarmult_with_group_order)(unsigned char *, + const unsigned char *); } ed25519_impl_t; /** The Ref10 Ed25519 implementation. This one is pure C and lightly @@ -79,6 +82,7 @@ static const ed25519_impl_t impl_ref10 = { ed25519_ref10_blind_public_key, ed25519_ref10_pubkey_from_curve25519_pubkey, + ed25519_ref10_scalarmult_with_group_order, }; /** The Ref10 Ed25519 implementation. This one is heavily optimized, but still @@ -99,6 +103,7 @@ static const ed25519_impl_t impl_donna = { ed25519_donna_blind_public_key, ed25519_donna_pubkey_from_curve25519_pubkey, + ed25519_donna_scalarmult_with_group_order, }; /** Which Ed25519 implementation are we using? NULL if we haven't decided @@ -147,7 +152,7 @@ crypto_ed25519_testing_restore_impl(void) ed25519_impl = saved_ed25519_impl; saved_ed25519_impl = NULL; } -#endif +#endif /* defined(TOR_UNIT_TESTS) */ /** * Initialize a new ed25519 secret key in <b>seckey_out</b>. If @@ -211,10 +216,18 @@ ed25519_keypair_generate(ed25519_keypair_t *keypair_out, int extra_strong) return 0; } +/** Return true iff 'pubkey' is set to zero (eg to indicate that it is not + * set). */ +int +ed25519_public_key_is_zero(const ed25519_public_key_t *pubkey) +{ + return tor_mem_is_zero((char*)pubkey->pubkey, ED25519_PUBKEY_LEN); +} + /* Return a heap-allocated array that contains <b>msg</b> prefixed by the * string <b>prefix_str</b>. Set <b>final_msg_len_out</b> to the size of the - * final array. If an error occured, return NULL. It's the resonsibility of the - * caller to free the returned array. */ + * final array. If an error occurred, return NULL. It's the responsibility of + * the caller to free the returned array. */ static uint8_t * get_prefixed_msg(const uint8_t *msg, size_t msg_len, const char *prefix_str, @@ -247,7 +260,7 @@ get_prefixed_msg(const uint8_t *msg, size_t msg_len, * Set <b>signature_out</b> to a signature of the <b>len</b>-byte message * <b>msg</b>, using the secret and public key in <b>keypair</b>. * - * Return 0 if we successfuly signed the message, otherwise return -1. + * Return 0 if we successfully signed the message, otherwise return -1. */ int ed25519_sign(ed25519_signature_t *signature_out, @@ -267,11 +280,11 @@ ed25519_sign(ed25519_signature_t *signature_out, * Like ed25519_sign(), but also prefix <b>msg</b> with <b>prefix_str</b> * before signing. <b>prefix_str</b> must be a NUL-terminated string. */ -int -ed25519_sign_prefixed(ed25519_signature_t *signature_out, - const uint8_t *msg, size_t msg_len, - const char *prefix_str, - const ed25519_keypair_t *keypair) +MOCK_IMPL(int, +ed25519_sign_prefixed,(ed25519_signature_t *signature_out, + const uint8_t *msg, size_t msg_len, + const char *prefix_str, + const ed25519_keypair_t *keypair)) { int retval; size_t prefixed_msg_len; @@ -281,9 +294,12 @@ ed25519_sign_prefixed(ed25519_signature_t *signature_out, prefixed_msg = get_prefixed_msg(msg, msg_len, prefix_str, &prefixed_msg_len); - if (!prefixed_msg) { + if (BUG(!prefixed_msg)) { + /* LCOV_EXCL_START -- only possible when the message and prefix are + * ridiculously huge */ log_warn(LD_GENERAL, "Failed to get prefixed msg."); return -1; + /* LCOV_EXCL_STOP */ } retval = ed25519_sign(signature_out, @@ -300,10 +316,10 @@ ed25519_sign_prefixed(ed25519_signature_t *signature_out, * * Return 0 if the signature is valid; -1 if it isn't. */ -int -ed25519_checksig(const ed25519_signature_t *signature, - const uint8_t *msg, size_t len, - const ed25519_public_key_t *pubkey) +MOCK_IMPL(int, +ed25519_checksig,(const ed25519_signature_t *signature, + const uint8_t *msg, size_t len, + const ed25519_public_key_t *pubkey)) { return get_ed_impl()->open(signature->sig, msg, len, pubkey->pubkey) < 0 ? -1 : 0; @@ -326,9 +342,12 @@ ed25519_checksig_prefixed(const ed25519_signature_t *signature, prefixed_msg = get_prefixed_msg(msg, msg_len, prefix_str, &prefixed_msg_len); - if (!prefixed_msg) { + if (BUG(!prefixed_msg)) { + /* LCOV_EXCL_START -- only possible when the message and prefix are + * ridiculously huge */ log_warn(LD_GENERAL, "Failed to get prefixed msg."); return -1; + /* LCOV_EXCL_STOP */ } retval = ed25519_checksig(signature, @@ -346,10 +365,10 @@ ed25519_checksig_prefixed(const ed25519_signature_t *signature, * was valid. Otherwise return -N, where N is the number of invalid * signatures. */ -int -ed25519_checksig_batch(int *okay_out, - const ed25519_checkable_t *checkable, - int n_checkable) +MOCK_IMPL(int, +ed25519_checksig_batch,(int *okay_out, + const ed25519_checkable_t *checkable, + int n_checkable)) { int i, res; const ed25519_impl_t *impl = get_ed_impl(); @@ -434,14 +453,16 @@ ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out, { const char string[] = "Derive high part of ed25519 key from curve25519 key"; ed25519_public_key_t pubkey_check; - SHA512_CTX ctx; - uint8_t sha512_output[64]; + crypto_digest_t *ctx; + uint8_t sha512_output[DIGEST512_LEN]; memcpy(out->seckey.seckey, inp->seckey.secret_key, 32); - SHA512_Init(&ctx); - SHA512_Update(&ctx, out->seckey.seckey, 32); - SHA512_Update(&ctx, string, sizeof(string)); - SHA512_Final(sha512_output, &ctx); + + ctx = crypto_digest512_new(DIGEST_SHA512); + crypto_digest_add_bytes(ctx, (const char*)out->seckey.seckey, 32); + crypto_digest_add_bytes(ctx, (const char*)string, sizeof(string)); + crypto_digest_get_digest(ctx, (char *)sha512_output, sizeof(sha512_output)); + crypto_digest_free(ctx); memcpy(out->seckey.seckey + 32, sha512_output, 32); ed25519_public_key_generate(&out->pubkey, &out->seckey); @@ -454,7 +475,6 @@ ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out, tor_assert(fast_memeq(pubkey_check.pubkey, out->pubkey.pubkey, 32)); memwipe(&pubkey_check, 0, sizeof(pubkey_check)); - memwipe(&ctx, 0, sizeof(ctx)); memwipe(sha512_output, 0, sizeof(sha512_output)); return 0; @@ -483,7 +503,8 @@ ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey, * service descriptors are encrypted with a key derived from the service's * long-term public key, and then signed with (and stored at a position * indexed by) a short-term key derived by blinding the long-term keys. - */ + * + * Return 0 if blinding was successful, else return -1. */ int ed25519_keypair_blind(ed25519_keypair_t *out, const ed25519_keypair_t *inp, @@ -494,7 +515,9 @@ ed25519_keypair_blind(ed25519_keypair_t *out, get_ed_impl()->blind_secret_key(out->seckey.seckey, inp->seckey.seckey, param); - ed25519_public_blind(&pubkey_check, &inp->pubkey, param); + if (ed25519_public_blind(&pubkey_check, &inp->pubkey, param) < 0) { + return -1; + } ed25519_public_key_generate(&out->pubkey, &out->seckey); tor_assert(fast_memeq(pubkey_check.pubkey, out->pubkey.pubkey, 32)); @@ -507,15 +530,14 @@ ed25519_keypair_blind(ed25519_keypair_t *out, /** * Given an ed25519 public key in <b>inp</b>, generate a corresponding blinded * public key in <b>out</b>, blinded with the 32-byte parameter in - * <b>param</b>. Return 0 on sucess, -1 on railure. + * <b>param</b>. Return 0 on success, -1 on railure. */ int ed25519_public_blind(ed25519_public_key_t *out, const ed25519_public_key_t *inp, const uint8_t *param) { - get_ed_impl()->blind_public_key(out->pubkey, inp->pubkey, param); - return 0; + return get_ed_impl()->blind_public_key(out->pubkey, inp->pubkey, param); } /** @@ -601,7 +623,7 @@ ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out, /** Release all storage held for <b>kp</b>. */ void -ed25519_keypair_free(ed25519_keypair_t *kp) +ed25519_keypair_free_(ed25519_keypair_t *kp) { if (! kp) return; @@ -620,10 +642,22 @@ ed25519_pubkey_eq(const ed25519_public_key_t *key1, return tor_memeq(key1->pubkey, key2->pubkey, ED25519_PUBKEY_LEN); } +/** + * Set <b>dest</b> to contain the same key as <b>src</b>. + */ +void +ed25519_pubkey_copy(ed25519_public_key_t *dest, + const ed25519_public_key_t *src) +{ + tor_assert(dest); + tor_assert(src); + memcpy(dest, src, sizeof(ed25519_public_key_t)); +} + /** Check whether the given Ed25519 implementation seems to be working. * If so, return 0; otherwise return -1. */ -static int -ed25519_impl_spot_check(void) +MOCK_IMPL(STATIC int, +ed25519_impl_spot_check,(void)) { static const uint8_t alicesk[32] = { 0xc5,0xaa,0x8d,0xf4,0x3f,0x9f,0x83,0x7b, @@ -686,13 +720,16 @@ ed25519_impl_spot_check(void) return -1; /* XXX/yawning: Someone that's more paranoid than I am, can write "Assume - * ref0 is cannonical, and fuzz impl against it" if they want, but I doubt + * ref0 is canonical, and fuzz impl against it" if they want, but I doubt * that will catch anything that the known answer tests won't. */ goto end; + // LCOV_EXCL_START -- We can only reach this if our ed25519 implementation is + // broken. fail: r = -1; + // LCOV_EXCL_STOP end: return r; } @@ -726,7 +763,7 @@ pick_ed25519_impl(void) /* LCOV_EXCL_STOP */ } -/* Initialize the Ed25519 implementation. This is neccessary if you're +/* Initialize the Ed25519 implementation. This is necessary if you're * going to use them in a multithreaded setting, and not otherwise. */ void ed25519_init(void) @@ -734,3 +771,47 @@ ed25519_init(void) pick_ed25519_impl(); } +/* Return true if <b>point</b> is the identity element of the ed25519 group. */ +static int +ed25519_point_is_identity_element(const uint8_t *point) +{ + /* The identity element in ed25159 is the point with coordinates (0,1). */ + static const uint8_t ed25519_identity[32] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + tor_assert(sizeof(ed25519_identity) == ED25519_PUBKEY_LEN); + return tor_memeq(point, ed25519_identity, sizeof(ed25519_identity)); +} + +/** Validate <b>pubkey</b> to ensure that it has no torsion component. + * Return 0 if <b>pubkey</b> is valid, else return -1. */ +int +ed25519_validate_pubkey(const ed25519_public_key_t *pubkey) +{ + uint8_t result[32] = {9}; + + /* First check that we were not given the identity element */ + if (ed25519_point_is_identity_element(pubkey->pubkey)) { + log_warn(LD_CRYPTO, "ed25519 pubkey is the identity"); + return -1; + } + + /* For any point on the curve, doing l*point should give the identity element + * (where l is the group order). Do the computation and check that the + * identity element is returned. */ + if (get_ed_impl()->ed25519_scalarmult_with_group_order(result, + pubkey->pubkey) < 0) { + log_warn(LD_CRYPTO, "ed25519 group order scalarmult failed"); + return -1; + } + + if (!ed25519_point_is_identity_element(result)) { + log_warn(LD_CRYPTO, "ed25519 validation failed"); + return -1; + } + + return 0; +} + |