/** Check whether the ed25519-based curve25519 basepoint optimization seems to * be working. If so, return 0; otherwise return -1. */ static int curve25519_basepoint_spot_check(void) { static const uint8_t alicesk[32] = { 0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d, 0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45, 0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a, 0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a }; static const uint8_t alicepk[32] = { 0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54, 0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a, 0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4, 0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a }; const int loop_max=200; int save_use_ed = curve25519_use_ed; unsigned char e1[32] = { 5 }; unsigned char e2[32] = { 5 }; unsigned char x[32],y[32]; int i; int r=0; /* Check the most basic possible sanity via the test secret/public key pair * used in "Cryptography in NaCl - 2. Secret keys and public keys". This * may catch catastrophic failures on systems where Curve25519 is expensive, * without requiring a ton of key generation. */ curve25519_use_ed = 1; r |= curve25519_basepoint_impl(x, alicesk); if (fast_memneq(x, alicepk, 32)) goto fail; /* Ok, the optimization appears to produce passable results, try a few more * values, maybe there's something subtle wrong. */ for (i = 0; i < loop_max; ++i) { curve25519_use_ed = 0; r |= curve25519_basepoint_impl(x, e1); curve25519_use_ed = 1; r |= curve25519_basepoint_impl(y, e2); if (fast_memneq(x,y,32)) goto fail; memcpy(e1, x, 32); memcpy(e2, x, 32); } goto end; fail: r = -1; end: curve25519_use_ed = save_use_ed; return r; }
/** Test the OpenSSL counter mode implementation to see whether it has the * counter-mode bug from OpenSSL 1.0.0. If the implementation works, then * we will use it for future encryption/decryption operations. * * We can't just look at the OpenSSL version, since some distributions update * their OpenSSL packages without changing the version number. **/ int evaluate_ctr_for_aes(void) { /* Result of encrypting an all-zero block with an all-zero 128-bit AES key. * This should be the same as encrypting an all-zero block with an all-zero * 128-bit AES key in counter mode, starting at position 0 of the stream. */ static const unsigned char encrypt_zero[] = "\x66\xe9\x4b\xd4\xef\x8a\x2c\x3b\x88\x4c\xfa\x59\xca\x34\x2b\x2e"; unsigned char zero[16]; unsigned char output[16]; unsigned char ivec[16]; unsigned char ivec_tmp[16]; unsigned int pos, i; AES_KEY key; memset(zero, 0, sizeof(zero)); memset(ivec, 0, sizeof(ivec)); AES_set_encrypt_key(zero, 128, &key); pos = 0; /* Encrypting a block one byte at a time should make the error manifest * itself for known bogus openssl versions. */ for (i=0; i<16; ++i) AES_ctr128_encrypt(&zero[i], &output[i], 1, &key, ivec, ivec_tmp, &pos); if (fast_memneq(output, encrypt_zero, 16)) { /* Counter mode is buggy */ log_err(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; " "quitting tor."); exit(1); } return 0; }
/** * Helper: implements keypin_check and keypin_check_and_add. */ static int keypin_check_and_add_impl(const uint8_t *rsa_id_digest, const uint8_t *ed25519_id_key, const int do_not_add, const int replace) { keypin_ent_t search, *ent; memset(&search, 0, sizeof(search)); memcpy(search.rsa_id, rsa_id_digest, sizeof(search.rsa_id)); memcpy(search.ed25519_key, ed25519_id_key, sizeof(search.ed25519_key)); /* Search by RSA key digest first */ ent = HT_FIND(rsamap, &the_rsa_map, &search); if (ent) { tor_assert(fast_memeq(ent->rsa_id, rsa_id_digest, sizeof(ent->rsa_id))); if (tor_memeq(ent->ed25519_key, ed25519_id_key,sizeof(ent->ed25519_key))) { return KEYPIN_FOUND; /* Match on both keys. Great. */ } else { if (!replace) return KEYPIN_MISMATCH; /* Found RSA with different Ed key */ } } /* See if we know a different RSA key for this ed key */ if (! replace) { ent = HT_FIND(edmap, &the_ed_map, &search); if (ent) { /* If we got here, then the ed key matches and the RSA doesn't */ tor_assert(fast_memeq(ent->ed25519_key, ed25519_id_key, sizeof(ent->ed25519_key))); tor_assert(fast_memneq(ent->rsa_id, rsa_id_digest, sizeof(ent->rsa_id))); return KEYPIN_MISMATCH; } } /* Okay, this one is new to us. */ if (do_not_add) return KEYPIN_NOT_FOUND; ent = tor_memdup(&search, sizeof(search)); int r = keypin_add_or_replace_entry_in_map(ent); if (! replace) { tor_assert(r == 1); } else { tor_assert(r != 0); } keypin_journal_append_entry(rsa_id_digest, ed25519_id_key); return KEYPIN_ADDED; }
/* Make sure that the commitment and reveal information in <b>commit</b> * match. If they match return 0, return -1 otherwise. This function MUST be * used everytime we receive a new reveal value. Furthermore, the commit * object MUST have a reveal value and the hash of the reveal value. */ STATIC int verify_commit_and_reveal(const sr_commit_t *commit) { tor_assert(commit); log_debug(LD_DIR, "SR: Validating commit from authority %s", sr_commit_get_rsa_fpr(commit)); /* Check that the timestamps match. */ if (commit->commit_ts != commit->reveal_ts) { log_warn(LD_BUG, "SR: Commit timestamp %" PRIu64 " doesn't match reveal " "timestamp %" PRIu64, commit->commit_ts, commit->reveal_ts); goto invalid; } /* Verify that the hashed_reveal received in the COMMIT message, matches * the reveal we just received. */ { /* We first hash the reveal we just received. */ char received_hashed_reveal[sizeof(commit->hashed_reveal)]; /* Only sha3-256 is supported. */ if (commit->alg != SR_DIGEST_ALG) { goto invalid; } /* Use the invariant length since the encoded reveal variable has an * extra byte for the NUL terminated byte. */ if (crypto_digest256(received_hashed_reveal, commit->encoded_reveal, SR_REVEAL_BASE64_LEN, commit->alg) < 0) { /* Unable to digest the reveal blob, this is unlikely. */ goto invalid; } /* Now compare that with the hashed_reveal we received in COMMIT. */ if (fast_memneq(received_hashed_reveal, commit->hashed_reveal, sizeof(received_hashed_reveal))) { log_warn(LD_BUG, "SR: Received reveal value from authority %s " "doesn't match the commit value.", sr_commit_get_rsa_fpr(commit)); goto invalid; } } return 0; invalid: return -1; }
/** Check whether the given Ed25519 implementation seems to be working. * If so, return 0; otherwise return -1. */ static int ed25519_impl_spot_check(void) { static const uint8_t alicesk[32] = { 0xc5,0xaa,0x8d,0xf4,0x3f,0x9f,0x83,0x7b, 0xed,0xb7,0x44,0x2f,0x31,0xdc,0xb7,0xb1, 0x66,0xd3,0x85,0x35,0x07,0x6f,0x09,0x4b, 0x85,0xce,0x3a,0x2e,0x0b,0x44,0x58,0xf7 }; static const uint8_t alicepk[32] = { 0xfc,0x51,0xcd,0x8e,0x62,0x18,0xa1,0xa3, 0x8d,0xa4,0x7e,0xd0,0x02,0x30,0xf0,0x58, 0x08,0x16,0xed,0x13,0xba,0x33,0x03,0xac, 0x5d,0xeb,0x91,0x15,0x48,0x90,0x80,0x25 }; static const uint8_t alicemsg[2] = { 0xaf, 0x82 }; static const uint8_t alicesig[64] = { 0x62,0x91,0xd6,0x57,0xde,0xec,0x24,0x02, 0x48,0x27,0xe6,0x9c,0x3a,0xbe,0x01,0xa3, 0x0c,0xe5,0x48,0xa2,0x84,0x74,0x3a,0x44, 0x5e,0x36,0x80,0xd7,0xdb,0x5a,0xc3,0xac, 0x18,0xff,0x9b,0x53,0x8d,0x16,0xf2,0x90, 0xae,0x67,0xf7,0x60,0x98,0x4d,0xc6,0x59, 0x4a,0x7c,0x15,0xe9,0x71,0x6e,0xd2,0x8d, 0xc0,0x27,0xbe,0xce,0xea,0x1e,0xc4,0x0a }; const ed25519_impl_t *impl = get_ed_impl(); uint8_t sk[ED25519_SECKEY_LEN]; uint8_t pk[ED25519_PUBKEY_LEN]; uint8_t sig[ED25519_SIG_LEN]; int r = 0; /* Some implementations (eg: The modified Ed25519-donna) have handy self-test * code that sanity-checks the internals. If present, use that to screen out * catastrophic errors like massive compiler failure. */ if (impl->selftest && impl->selftest() != 0) goto fail; /* Validate results versus known answer tests. People really should be * running "make test" instead of relying on this, but it's better than * nothing. * * Test vectors taken from "EdDSA & Ed25519 - 6. Test Vectors for Ed25519 * (TEST3)" (draft-josefsson-eddsa-ed25519-03). */ /* Key expansion, public key derivation. */ if (impl->seckey_expand(sk, alicesk) < 0) goto fail; if (impl->pubkey(pk, sk) < 0) goto fail; if (fast_memneq(pk, alicepk, ED25519_PUBKEY_LEN)) goto fail; /* Signing, verification. */ if (impl->sign(sig, alicemsg, sizeof(alicemsg), sk, pk) < 0) return -1; if (fast_memneq(sig, alicesig, ED25519_SIG_LEN)) return -1; if (impl->open(sig, alicemsg, sizeof(alicemsg), pk) < 0) 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 * that will catch anything that the known answer tests won't. */ goto end; fail: r = -1; end: return r; }