Пример #1
0
/** 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;
}
Пример #2
0
/** 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);
}
Пример #3
0
/**
 * 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;
}
Пример #4
0
/** 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;
}