/** Create new cross-certification object to certify <b>ed_key</b> as the * master ed25519 identity key for the RSA identity key <b>rsa_key</b>. * Allocates and stores the encoded certificate in *<b>cert</b>, and returns * the number of bytes stored. Returns negative on error.*/ ssize_t tor_make_rsa_ed25519_crosscert(const ed25519_public_key_t *ed_key, const crypto_pk_t *rsa_key, time_t expires, uint8_t **cert) { // It is later than 1985, since otherwise there would be no C89 // compilers. (Try to diagnose #22466.) tor_assert_nonfatal(expires >= 15 * 365 * 86400); uint8_t *res; rsa_ed_crosscert_t *cc = rsa_ed_crosscert_new(); memcpy(cc->ed_key, ed_key->pubkey, ED25519_PUBKEY_LEN); cc->expiration = (uint32_t) CEIL_DIV(expires, 3600); cc->sig_len = crypto_pk_keysize(rsa_key); rsa_ed_crosscert_setlen_sig(cc, crypto_pk_keysize(rsa_key)); ssize_t alloc_sz = rsa_ed_crosscert_encoded_len(cc); tor_assert(alloc_sz > 0); res = tor_malloc_zero(alloc_sz); ssize_t sz = rsa_ed_crosscert_encode(res, alloc_sz, cc); tor_assert(sz > 0 && sz <= alloc_sz); crypto_digest_t *d = crypto_digest256_new(DIGEST_SHA256); crypto_digest_add_bytes(d, RSA_ED_CROSSCERT_PREFIX, strlen(RSA_ED_CROSSCERT_PREFIX)); const int signed_part_len = 32 + 4; crypto_digest_add_bytes(d, (char*)res, signed_part_len); uint8_t digest[DIGEST256_LEN]; crypto_digest_get_digest(d, (char*)digest, sizeof(digest)); crypto_digest_free(d); int siglen = crypto_pk_private_sign(rsa_key, (char*)rsa_ed_crosscert_getarray_sig(cc), rsa_ed_crosscert_getlen_sig(cc), (char*)digest, sizeof(digest)); tor_assert(siglen > 0 && siglen <= (int)crypto_pk_keysize(rsa_key)); tor_assert(siglen <= UINT8_MAX); cc->sig_len = siglen; rsa_ed_crosscert_setlen_sig(cc, siglen); sz = rsa_ed_crosscert_encode(res, alloc_sz, cc); rsa_ed_crosscert_free(cc); *cert = res; return sz; }
/** Run unit tests for our SHA-1 functionality */ static void test_crypto_sha(void) { crypto_digest_t *d1 = NULL, *d2 = NULL; int i; char key[160]; char digest[32]; char data[50]; char d_out1[DIGEST_LEN], d_out2[DIGEST256_LEN]; char *mem_op_hex_tmp=NULL; /* Test SHA-1 with a test vector from the specification. */ i = crypto_digest(data, "abc", 3); test_memeq_hex(data, "A9993E364706816ABA3E25717850C26C9CD0D89D"); tt_int_op(i, ==, 0); /* Test SHA-256 with a test vector from the specification. */ i = crypto_digest256(data, "abc", 3, DIGEST_SHA256); test_memeq_hex(data, "BA7816BF8F01CFEA414140DE5DAE2223B00361A3" "96177A9CB410FF61F20015AD"); tt_int_op(i, ==, 0); /* Test HMAC-SHA-1 with test cases from RFC2202. */ /* Case 1. */ memset(key, 0x0b, 20); crypto_hmac_sha1(digest, key, 20, "Hi There", 8); test_streq(hex_str(digest, 20), "B617318655057264E28BC0B6FB378C8EF146BE00"); /* Case 2. */ crypto_hmac_sha1(digest, "Jefe", 4, "what do ya want for nothing?", 28); test_streq(hex_str(digest, 20), "EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79"); /* Case 4. */ base16_decode(key, 25, "0102030405060708090a0b0c0d0e0f10111213141516171819", 50); memset(data, 0xcd, 50); crypto_hmac_sha1(digest, key, 25, data, 50); test_streq(hex_str(digest, 20), "4C9007F4026250C6BC8414F9BF50C86C2D7235DA"); /* Case 5. */ memset(key, 0xaa, 80); crypto_hmac_sha1(digest, key, 80, "Test Using Larger Than Block-Size Key - Hash Key First", 54); test_streq(hex_str(digest, 20), "AA4AE5E15272D00E95705637CE8A3B55ED402112"); /* Test HMAC-SHA256 with test cases from wikipedia and RFC 4231 */ /* Case empty (wikipedia) */ crypto_hmac_sha256(digest, "", 0, "", 0); test_streq(hex_str(digest, 32), "B613679A0814D9EC772F95D778C35FC5FF1697C493715653C6C712144292C5AD"); /* Case quick-brown (wikipedia) */ crypto_hmac_sha256(digest, "key", 3, "The quick brown fox jumps over the lazy dog", 43); test_streq(hex_str(digest, 32), "F7BC83F430538424B13298E6AA6FB143EF4D59A14946175997479DBC2D1A3CD8"); /* "Test Case 1" from RFC 4231 */ memset(key, 0x0b, 20); crypto_hmac_sha256(digest, key, 20, "Hi There", 8); test_memeq_hex(digest, "b0344c61d8db38535ca8afceaf0bf12b" "881dc200c9833da726e9376c2e32cff7"); /* "Test Case 2" from RFC 4231 */ memset(key, 0x0b, 20); crypto_hmac_sha256(digest, "Jefe", 4, "what do ya want for nothing?", 28); test_memeq_hex(digest, "5bdcc146bf60754e6a042426089575c7" "5a003f089d2739839dec58b964ec3843"); /* "Test case 3" from RFC 4231 */ memset(key, 0xaa, 20); memset(data, 0xdd, 50); crypto_hmac_sha256(digest, key, 20, data, 50); test_memeq_hex(digest, "773ea91e36800e46854db8ebd09181a7" "2959098b3ef8c122d9635514ced565fe"); /* "Test case 4" from RFC 4231 */ base16_decode(key, 25, "0102030405060708090a0b0c0d0e0f10111213141516171819", 50); memset(data, 0xcd, 50); crypto_hmac_sha256(digest, key, 25, data, 50); test_memeq_hex(digest, "82558a389a443c0ea4cc819899f2083a" "85f0faa3e578f8077a2e3ff46729665b"); /* "Test case 5" from RFC 4231 */ memset(key, 0x0c, 20); crypto_hmac_sha256(digest, key, 20, "Test With Truncation", 20); test_memeq_hex(digest, "a3b6167473100ee06e0c796c2955552b"); /* "Test case 6" from RFC 4231 */ memset(key, 0xaa, 131); crypto_hmac_sha256(digest, key, 131, "Test Using Larger Than Block-Size Key - Hash Key First", 54); test_memeq_hex(digest, "60e431591ee0b67f0d8a26aacbf5b77f" "8e0bc6213728c5140546040f0ee37f54"); /* "Test case 7" from RFC 4231 */ memset(key, 0xaa, 131); crypto_hmac_sha256(digest, key, 131, "This is a test using a larger than block-size key and a " "larger than block-size data. The key needs to be hashed " "before being used by the HMAC algorithm.", 152); test_memeq_hex(digest, "9b09ffa71b942fcb27635fbcd5b0e944" "bfdc63644f0713938a7f51535c3a35e2"); /* Incremental digest code. */ d1 = crypto_digest_new(); test_assert(d1); crypto_digest_add_bytes(d1, "abcdef", 6); d2 = crypto_digest_dup(d1); test_assert(d2); crypto_digest_add_bytes(d2, "ghijkl", 6); crypto_digest_get_digest(d2, d_out1, sizeof(d_out1)); crypto_digest(d_out2, "abcdefghijkl", 12); test_memeq(d_out1, d_out2, DIGEST_LEN); crypto_digest_assign(d2, d1); crypto_digest_add_bytes(d2, "mno", 3); crypto_digest_get_digest(d2, d_out1, sizeof(d_out1)); crypto_digest(d_out2, "abcdefmno", 9); test_memeq(d_out1, d_out2, DIGEST_LEN); crypto_digest_get_digest(d1, d_out1, sizeof(d_out1)); crypto_digest(d_out2, "abcdef", 6); test_memeq(d_out1, d_out2, DIGEST_LEN); crypto_digest_free(d1); crypto_digest_free(d2); /* Incremental digest code with sha256 */ d1 = crypto_digest256_new(DIGEST_SHA256); test_assert(d1); crypto_digest_add_bytes(d1, "abcdef", 6); d2 = crypto_digest_dup(d1); test_assert(d2); crypto_digest_add_bytes(d2, "ghijkl", 6); crypto_digest_get_digest(d2, d_out1, sizeof(d_out1)); crypto_digest256(d_out2, "abcdefghijkl", 12, DIGEST_SHA256); test_memeq(d_out1, d_out2, DIGEST_LEN); crypto_digest_assign(d2, d1); crypto_digest_add_bytes(d2, "mno", 3); crypto_digest_get_digest(d2, d_out1, sizeof(d_out1)); crypto_digest256(d_out2, "abcdefmno", 9, DIGEST_SHA256); test_memeq(d_out1, d_out2, DIGEST_LEN); crypto_digest_get_digest(d1, d_out1, sizeof(d_out1)); crypto_digest256(d_out2, "abcdef", 6, DIGEST_SHA256); test_memeq(d_out1, d_out2, DIGEST_LEN); done: if (d1) crypto_digest_free(d1); if (d2) crypto_digest_free(d2); tor_free(mem_op_hex_tmp); }
/** * Read the measured bandwidth list <b>from_file</b>: * - store all the headers in <b>bw_file_headers</b>, * - apply bandwidth lines to the list of vote_routerstatus_t in * <b>routerstatuses</b>, * - cache bandwidth lines for dirserv_get_bandwidth_for_router(), * - expire old entries in the measured bandwidth cache, and * - store the DIGEST_SHA256 of the contents of the file in <b>digest_out</b>. * * Returns -1 on error, 0 otherwise. * * If the file can't be read, or is empty: * - <b>bw_file_headers</b> is empty, * - <b>routerstatuses</b> is not modified, * - the measured bandwidth cache is not modified, and * - <b>digest_out</b> is the zero-byte digest. * * Otherwise, if there is an error later in the file: * - <b>bw_file_headers</b> contains all the headers up to the error, * - <b>routerstatuses</b> is updated with all the relay lines up to the error, * - the measured bandwidth cache is updated with all the relay lines up to * the error, * - if the timestamp is valid and recent, old entries in the measured * bandwidth cache are expired, and * - <b>digest_out</b> is the digest up to the first read error (if any). * The digest is taken over all the readable file contents, even if the * file is outdated or unparseable. */ int dirserv_read_measured_bandwidths(const char *from_file, smartlist_t *routerstatuses, smartlist_t *bw_file_headers, uint8_t *digest_out) { FILE *fp = tor_fopen_cloexec(from_file, "r"); int applied_lines = 0; time_t file_time, now; int ok; /* This flag will be 1 only when the first successful bw measurement line * has been encountered, so that measured_bw_line_parse don't give warnings * if there are additional header lines, as introduced in Bandwidth List spec * version 1.1.0 */ int line_is_after_headers = 0; int rv = -1; char *line = NULL; size_t n = 0; crypto_digest_t *digest = crypto_digest256_new(DIGEST_SHA256); if (fp == NULL) { log_warn(LD_CONFIG, "Can't open bandwidth file at configured location: %s", from_file); goto err; } if (tor_getline(&line,&n,fp) <= 0) { log_warn(LD_DIRSERV, "Empty bandwidth file"); goto err; } /* If the line could be gotten, add it to the digest */ crypto_digest_add_bytes(digest, (const char *) line, strlen(line)); if (!strlen(line) || line[strlen(line)-1] != '\n') { log_warn(LD_DIRSERV, "Long or truncated time in bandwidth file: %s", escaped(line)); /* Continue adding lines to the digest. */ goto continue_digest; } line[strlen(line)-1] = '\0'; file_time = (time_t)tor_parse_ulong(line, 10, 0, ULONG_MAX, &ok, NULL); if (!ok) { log_warn(LD_DIRSERV, "Non-integer time in bandwidth file: %s", escaped(line)); goto continue_digest; } now = approx_time(); if ((now - file_time) > MAX_MEASUREMENT_AGE) { log_warn(LD_DIRSERV, "Bandwidth measurement file stale. Age: %u", (unsigned)(time(NULL) - file_time)); goto continue_digest; } /* If timestamp was correct and bw_file_headers is not NULL, * add timestamp to bw_file_headers */ if (bw_file_headers) smartlist_add_asprintf(bw_file_headers, "timestamp=%lu", (unsigned long)file_time); if (routerstatuses) smartlist_sort(routerstatuses, compare_vote_routerstatus_entries); while (!feof(fp)) { measured_bw_line_t parsed_line; if (tor_getline(&line, &n, fp) >= 0) { crypto_digest_add_bytes(digest, (const char *) line, strlen(line)); if (measured_bw_line_parse(&parsed_line, line, line_is_after_headers) != -1) { /* This condition will be true when the first complete valid bw line * has been encountered, which means the end of the header lines. */ line_is_after_headers = 1; /* Also cache the line for dirserv_get_bandwidth_for_router() */ dirserv_cache_measured_bw(&parsed_line, file_time); if (measured_bw_line_apply(&parsed_line, routerstatuses) > 0) applied_lines++; /* if the terminator is found, it is the end of header lines, set the * flag but do not store anything */ } else if (strcmp(line, BW_FILE_HEADERS_TERMINATOR) == 0) { line_is_after_headers = 1; /* if the line was not a correct relay line nor the terminator and * the end of the header lines has not been detected yet * and it is key_value and bw_file_headers did not reach the maximum * number of headers, * then assume this line is a header and add it to bw_file_headers */ } else if (bw_file_headers && (line_is_after_headers == 0) && string_is_key_value(LOG_DEBUG, line) && !strchr(line, ' ') && (smartlist_len(bw_file_headers) < MAX_BW_FILE_HEADER_COUNT_IN_VOTE)) { line[strlen(line)-1] = '\0'; smartlist_add_strdup(bw_file_headers, line); }; } } /* Now would be a nice time to clean the cache, too */ dirserv_expire_measured_bw_cache(now); log_info(LD_DIRSERV, "Bandwidth measurement file successfully read. " "Applied %d measurements.", applied_lines); rv = 0; continue_digest: /* Continue parsing lines to return the digest of the Bandwidth File. */ while (!feof(fp)) { if (tor_getline(&line, &n, fp) >= 0) { crypto_digest_add_bytes(digest, (const char *) line, strlen(line)); } } err: if (line) { // we need to raw_free this buffer because we got it from tor_getdelim() raw_free(line); } if (fp) fclose(fp); if (digest_out) crypto_digest_get_digest(digest, (char *) digest_out, DIGEST256_LEN); crypto_digest_free(digest); return rv; }
/** Initialize <b>crypto</b> from the key material in key_data. * * If <b>is_hs_v3</b> is set, this cpath will be used for next gen hidden * service circuits and <b>key_data</b> must be at least * HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN bytes in length. * * If <b>is_hs_v3</b> is not set, key_data must contain CPATH_KEY_MATERIAL_LEN * bytes, which are used as follows: * - 20 to initialize f_digest * - 20 to initialize b_digest * - 16 to key f_crypto * - 16 to key b_crypto * * (If 'reverse' is true, then f_XX and b_XX are swapped.) * * Return 0 if init was successful, else -1 if it failed. */ int relay_crypto_init(relay_crypto_t *crypto, const char *key_data, size_t key_data_len, int reverse, int is_hs_v3) { crypto_digest_t *tmp_digest; crypto_cipher_t *tmp_crypto; size_t digest_len = 0; size_t cipher_key_len = 0; tor_assert(crypto); tor_assert(key_data); tor_assert(!(crypto->f_crypto || crypto->b_crypto || crypto->f_digest || crypto->b_digest)); /* Basic key size validation */ if (is_hs_v3 && BUG(key_data_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) { goto err; } else if (!is_hs_v3 && BUG(key_data_len != CPATH_KEY_MATERIAL_LEN)) { goto err; } /* If we are using this crypto for next gen onion services use SHA3-256, otherwise use good ol' SHA1 */ if (is_hs_v3) { digest_len = DIGEST256_LEN; cipher_key_len = CIPHER256_KEY_LEN; crypto->f_digest = crypto_digest256_new(DIGEST_SHA3_256); crypto->b_digest = crypto_digest256_new(DIGEST_SHA3_256); } else { digest_len = DIGEST_LEN; cipher_key_len = CIPHER_KEY_LEN; crypto->f_digest = crypto_digest_new(); crypto->b_digest = crypto_digest_new(); } tor_assert(digest_len != 0); tor_assert(cipher_key_len != 0); const int cipher_key_bits = (int) cipher_key_len * 8; crypto_digest_add_bytes(crypto->f_digest, key_data, digest_len); crypto_digest_add_bytes(crypto->b_digest, key_data+digest_len, digest_len); crypto->f_crypto = crypto_cipher_new_with_bits(key_data+(2*digest_len), cipher_key_bits); if (!crypto->f_crypto) { log_warn(LD_BUG,"Forward cipher initialization failed."); goto err; } crypto->b_crypto = crypto_cipher_new_with_bits( key_data+(2*digest_len)+cipher_key_len, cipher_key_bits); if (!crypto->b_crypto) { log_warn(LD_BUG,"Backward cipher initialization failed."); goto err; } if (reverse) { tmp_digest = crypto->f_digest; crypto->f_digest = crypto->b_digest; crypto->b_digest = tmp_digest; tmp_crypto = crypto->f_crypto; crypto->f_crypto = crypto->b_crypto; crypto->b_crypto = tmp_crypto; } return 0; err: relay_crypto_clear(crypto); return -1; }