Example #1
0
/** Check whether an RSA-TAP cross-certification is correct. Return 0 if it
 * is, -1 if it isn't. */
int
check_tap_onion_key_crosscert(const uint8_t *crosscert,
                              int crosscert_len,
                              const crypto_pk_t *onion_pkey,
                              const ed25519_public_key_t *master_id_pkey,
                              const uint8_t *rsa_id_digest)
{
  uint8_t *cc = tor_malloc(crypto_pk_keysize(onion_pkey));
  int cc_len =
    crypto_pk_public_checksig(onion_pkey,
                              (char*)cc,
                              crypto_pk_keysize(onion_pkey),
                              (const char*)crosscert,
                              crosscert_len);
  if (cc_len < 0) {
    goto err;
  }
  if (cc_len < DIGEST_LEN + ED25519_PUBKEY_LEN) {
    log_warn(LD_DIR, "Short signature on cross-certification with TAP key");
    goto err;
  }
  if (tor_memneq(cc, rsa_id_digest, DIGEST_LEN) ||
      tor_memneq(cc + DIGEST_LEN, master_id_pkey->pubkey,
                 ED25519_PUBKEY_LEN)) {
    log_warn(LD_DIR, "Incorrect cross-certification with TAP key");
    goto err;
  }

  tor_free(cc);
  return 0;
 err:
  tor_free(cc);
  return -1;
}
Example #2
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)
{
  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);

  const int signed_part_len = 32 + 4;
  int siglen = crypto_pk_private_sign(rsa_key,
                                      (char*)rsa_ed_crosscert_getarray_sig(cc),
                                      rsa_ed_crosscert_getlen_sig(cc),
                                      (char*)res, signed_part_len);
  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;
}
Example #3
0
static int
mock_crypto_pk_public_checksig__nocheck(const crypto_pk_t *env, char *to,
                                        size_t tolen,
                                        const char *from, size_t fromlen)
{
  tor_assert(env && to && from);
  (void)fromlen;
  /* We could look at from[0..fromlen-1] ... */
  tor_assert(tolen >= crypto_pk_keysize(env));
  size_t siglen = MIN(20, crypto_pk_keysize(env));
  memset(to, 0x01, siglen);
  return (int)siglen;
}
Example #4
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;
}
Example #5
0
static ssize_t
make_intro_from_plaintext(
    void *buf, size_t len, crypto_pk_t *key, void **cell_out)
{
  char *cell = NULL;
  ssize_t cell_len = -1, r;
  /* Assemble key digest and ciphertext, then construct the cell */
  ssize_t ciphertext_size;

  if (!(buf && key && len > 0 && cell_out)) goto done;

  /*
   * Figure out an upper bound on how big the ciphertext will be
   * (see crypto_pk_public_hybrid_encrypt())
   */
  ciphertext_size = PKCS1_OAEP_PADDING_OVERHEAD;
  ciphertext_size += crypto_pk_keysize(key);
  ciphertext_size += CIPHER_KEY_LEN;
  ciphertext_size += len;

  /*
   * Allocate space for the cell
   */
  memmgr_init_check_shared_mem(SHARED_SIZE, UIO_DEVICE, BASE_ADDRESS);
//  cell = tor_malloc(DIGEST_LEN + ciphertext_size);
  cell = memmgr_alloc(DIGEST_LEN + ciphertext_size);

  memmgr_assert(buf);
  

  /* Compute key digest (will be first DIGEST_LEN octets of cell) */
  r = crypto_pk_get_digest(key, cell);
  tt_assert(r >= 0);

  /* Do encryption */
  r = crypto_pk_public_hybrid_encrypt(
      key, cell + DIGEST_LEN, ciphertext_size,
      buf, len,
      PK_PKCS1_OAEP_PADDING, 0);
  tt_assert(r >= 0);

  /* Figure out cell length */
  cell_len = DIGEST_LEN + r;

  /* Output the cell */
  *cell_out = cell;

 done:
//  memmgr_free(cell);
  return cell_len;
}
Example #6
0
/** Given a router's 128 byte public key,
 * stores the following in onion_skin_out:
 *   - [42 bytes] OAEP padding
 *   - [16 bytes] Symmetric key for encrypting blob past RSA
 *   - [70 bytes] g^x part 1 (inside the RSA)
 *   - [58 bytes] g^x part 2 (symmetrically encrypted)
 *
 * Stores the DH private key into handshake_state_out for later completion
 * of the handshake.
 *
 * The meeting point/cookies and auth are zeroed out for now.
 */
int
onion_skin_TAP_create(crypto_pk_t *dest_router_key,
                  crypto_dh_t **handshake_state_out,
                  char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */
{
  char challenge[DH1024_KEY_LEN];
  crypto_dh_t *dh = NULL;
  int dhbytes, pkbytes;

  tor_assert(dest_router_key);
  tor_assert(handshake_state_out);
  tor_assert(onion_skin_out);
  *handshake_state_out = NULL;
  memset(onion_skin_out, 0, TAP_ONIONSKIN_CHALLENGE_LEN);

  if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT)))
    goto err;

  dhbytes = crypto_dh_get_bytes(dh);
  pkbytes = (int) crypto_pk_keysize(dest_router_key);
  tor_assert(dhbytes == 128);
  tor_assert(pkbytes == 128);

  if (crypto_dh_get_public(dh, challenge, dhbytes))
    goto err;

  /* set meeting point, meeting cookie, etc here. Leave zero for now. */
  if (crypto_pk_obsolete_public_hybrid_encrypt(dest_router_key, onion_skin_out,
                                      TAP_ONIONSKIN_CHALLENGE_LEN,
                                      challenge, DH1024_KEY_LEN,
                                      PK_PKCS1_OAEP_PADDING, 1)<0)
    goto err;

  memwipe(challenge, 0, sizeof(challenge));
  *handshake_state_out = dh;

  return 0;
 err:
  /* LCOV_EXCL_START
   * We only get here if RSA encryption fails or DH keygen fails. Those
   * shouldn't be possible. */
  memwipe(challenge, 0, sizeof(challenge));
  if (dh) crypto_dh_free(dh);
  return -1;
  /* LCOV_EXCL_STOP */
}
Example #7
0
/** Given a router's 128 byte public key,
 * stores the following in onion_skin_out:
 *   - [42 bytes] OAEP padding
 *   - [16 bytes] Symmetric key for encrypting blob past RSA
 *   - [70 bytes] g^x part 1 (inside the RSA)
 *   - [58 bytes] g^x part 2 (symmetrically encrypted)
 *
 * Stores the DH private key into handshake_state_out for later completion
 * of the handshake.
 *
 * The meeting point/cookies and auth are zeroed out for now.
 */
int
onion_skin_TAP_create(crypto_pk_t *dest_router_key,
                  crypto_dh_t **handshake_state_out,
                  char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */
{
  char challenge[DH_KEY_LEN];
  crypto_dh_t *dh = NULL;
  int dhbytes, pkbytes;

  tor_assert(dest_router_key);
  tor_assert(handshake_state_out);
  tor_assert(onion_skin_out);
  *handshake_state_out = NULL;
  memset(onion_skin_out, 0, TAP_ONIONSKIN_CHALLENGE_LEN);

  if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT)))
    goto err;

  dhbytes = crypto_dh_get_bytes(dh);
  pkbytes = (int) crypto_pk_keysize(dest_router_key);
  tor_assert(dhbytes == 128);
  tor_assert(pkbytes == 128);

  if (crypto_dh_get_public(dh, challenge, dhbytes))
    goto err;

  note_crypto_pk_op(ENC_ONIONSKIN);

  /* set meeting point, meeting cookie, etc here. Leave zero for now. */
  if (crypto_pk_public_hybrid_encrypt(dest_router_key, onion_skin_out,
                                      TAP_ONIONSKIN_CHALLENGE_LEN,
                                      challenge, DH_KEY_LEN,
                                      PK_PKCS1_OAEP_PADDING, 1)<0)
    goto err;

  memwipe(challenge, 0, sizeof(challenge));
  *handshake_state_out = dh;

  return 0;
 err:
  memwipe(challenge, 0, sizeof(challenge));
  if (dh) crypto_dh_free(dh);
  return -1;
}
Example #8
0
/** Process an AUTHENTICATE cell from an OR connection.
 *
 * If it's ill-formed or we weren't supposed to get one or we're not doing a
 * v3 handshake, then mark the connection.  If it does not authenticate the
 * other side of the connection successfully (because it isn't signed right,
 * we didn't get a CERTS cell, etc) mark the connection.  Otherwise, accept
 * the identity of the router on the other side of the connection.
 */
static void
command_process_authenticate_cell(var_cell_t *cell, or_connection_t *conn)
{
  uint8_t expected[V3_AUTH_FIXED_PART_LEN];
  const uint8_t *auth;
  int authlen;

#define ERR(s)                                                  \
  do {                                                          \
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,                      \
           "Received a bad AUTHENTICATE cell from %s:%d: %s",   \
           safe_str(conn->_base.address), conn->_base.port, (s));       \
    connection_mark_for_close(TO_CONN(conn));                   \
    return;                                                     \
  } while (0)

  if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
    ERR("We're not doing a v3 handshake");
  if (conn->link_proto < 3)
    ERR("We're not using link protocol >= 3");
  if (conn->handshake_state->started_here)
    ERR("We originated this connection");
  if (conn->handshake_state->received_authenticate)
    ERR("We already got one!");
  if (conn->handshake_state->authenticated) {
    /* Should be impossible given other checks */
    ERR("The peer is already authenticated");
  }
  if (! conn->handshake_state->received_certs_cell)
    ERR("We never got a certs cell");
  if (conn->handshake_state->auth_cert == NULL)
    ERR("We never got an authentication certificate");
  if (conn->handshake_state->id_cert == NULL)
    ERR("We never got an identity certificate");
  if (cell->payload_len < 4)
    ERR("Cell was way too short");

  auth = cell->payload;
  {
    uint16_t type = ntohs(get_uint16(auth));
    uint16_t len = ntohs(get_uint16(auth+2));
    if (4 + len > cell->payload_len)
      ERR("Authenticator was truncated");

    if (type != AUTHTYPE_RSA_SHA256_TLSSECRET)
      ERR("Authenticator type was not recognized");

    auth += 4;
    authlen = len;
  }

  if (authlen < V3_AUTH_BODY_LEN + 1)
    ERR("Authenticator was too short");

  if (connection_or_compute_authenticate_cell_body(
                        conn, expected, sizeof(expected), NULL, 1) < 0)
    ERR("Couldn't compute expected AUTHENTICATE cell body");

  if (tor_memneq(expected, auth, sizeof(expected)))
    ERR("Some field in the AUTHENTICATE cell body was not as expected");

  {
    crypto_pk_t *pk = tor_tls_cert_get_key(
                                   conn->handshake_state->auth_cert);
    char d[DIGEST256_LEN];
    char *signed_data;
    size_t keysize;
    int signed_len;

    if (!pk)
      ERR("Internal error: couldn't get RSA key from AUTH cert.");
    crypto_digest256(d, (char*)auth, V3_AUTH_BODY_LEN, DIGEST_SHA256);

    keysize = crypto_pk_keysize(pk);
    signed_data = tor_malloc(keysize);
    signed_len = crypto_pk_public_checksig(pk, signed_data, keysize,
                                           (char*)auth + V3_AUTH_BODY_LEN,
                                           authlen - V3_AUTH_BODY_LEN);
    crypto_pk_free(pk);
    if (signed_len < 0) {
      tor_free(signed_data);
      ERR("Signature wasn't valid");
    }
    if (signed_len < DIGEST256_LEN) {
      tor_free(signed_data);
      ERR("Not enough data was signed");
    }
    /* Note that we deliberately allow *more* than DIGEST256_LEN bytes here,
     * in case they're later used to hold a SHA3 digest or something. */
    if (tor_memneq(signed_data, d, DIGEST256_LEN)) {
      tor_free(signed_data);
      ERR("Signature did not match data to be signed.");
    }
    tor_free(signed_data);
  }

  /* Okay, we are authenticated. */
  conn->handshake_state->received_authenticate = 1;
  conn->handshake_state->authenticated = 1;
  conn->handshake_state->digest_received_data = 0;
  {
    crypto_pk_t *identity_rcvd =
      tor_tls_cert_get_key(conn->handshake_state->id_cert);
    const digests_t *id_digests =
      tor_cert_get_id_digests(conn->handshake_state->id_cert);

    /* This must exist; we checked key type when reading the cert. */
    tor_assert(id_digests);

    memcpy(conn->handshake_state->authenticated_peer_id,
           id_digests->d[DIGEST_SHA1], DIGEST_LEN);

    connection_or_set_circid_type(conn, identity_rcvd);
    crypto_pk_free(identity_rcvd);

    connection_or_init_conn_from_address(conn,
                  &conn->_base.addr,
                  conn->_base.port,
                  (const char*)conn->handshake_state->authenticated_peer_id,
                  0);

    log_info(LD_OR, "Got an AUTHENTICATE cell from %s:%d: Looks good.",
             safe_str(conn->_base.address), conn->_base.port);
  }

#undef ERR
}
Example #9
0
/** Run unit tests for our public key crypto functions */
static void
test_crypto_pk(void)
{
  crypto_pk_t *pk1 = NULL, *pk2 = NULL;
  char *encoded = NULL;
  char data1[1024], data2[1024], data3[1024];
  size_t size;
  int i, j, p, len;

  /* Public-key ciphers */
  pk1 = pk_generate(0);
  pk2 = crypto_pk_new();
  test_assert(pk1 && pk2);
  test_assert(! crypto_pk_write_public_key_to_string(pk1, &encoded, &size));
  test_assert(! crypto_pk_read_public_key_from_string(pk2, encoded, size));
  test_eq(0, crypto_pk_cmp_keys(pk1, pk2));

  /* comparison between keys and NULL */
  tt_int_op(crypto_pk_cmp_keys(NULL, pk1), <, 0);
  tt_int_op(crypto_pk_cmp_keys(NULL, NULL), ==, 0);
  tt_int_op(crypto_pk_cmp_keys(pk1, NULL), >, 0);

  test_eq(128, crypto_pk_keysize(pk1));
  test_eq(1024, crypto_pk_num_bits(pk1));
  test_eq(128, crypto_pk_keysize(pk2));
  test_eq(1024, crypto_pk_num_bits(pk2));

  test_eq(128, crypto_pk_public_encrypt(pk2, data1, sizeof(data1),
                                        "Hello whirled.", 15,
                                        PK_PKCS1_OAEP_PADDING));
  test_eq(128, crypto_pk_public_encrypt(pk1, data2, sizeof(data1),
                                        "Hello whirled.", 15,
                                        PK_PKCS1_OAEP_PADDING));
  /* oaep padding should make encryption not match */
  test_memneq(data1, data2, 128);
  test_eq(15, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data1, 128,
                                        PK_PKCS1_OAEP_PADDING,1));
  test_streq(data3, "Hello whirled.");
  memset(data3, 0, 1024);
  test_eq(15, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data2, 128,
                                        PK_PKCS1_OAEP_PADDING,1));
  test_streq(data3, "Hello whirled.");
  /* Can't decrypt with public key. */
  test_eq(-1, crypto_pk_private_decrypt(pk2, data3, sizeof(data3), data2, 128,
                                        PK_PKCS1_OAEP_PADDING,1));
  /* Try again with bad padding */
  memcpy(data2+1, "XYZZY", 5);  /* This has fails ~ once-in-2^40 */
  test_eq(-1, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data2, 128,
                                        PK_PKCS1_OAEP_PADDING,1));

  /* File operations: save and load private key */
  test_assert(! crypto_pk_write_private_key_to_filename(pk1,
                                                        get_fname("pkey1")));
  /* failing case for read: can't read. */
  test_assert(crypto_pk_read_private_key_from_filename(pk2,
                                                   get_fname("xyzzy")) < 0);
  write_str_to_file(get_fname("xyzzy"), "foobar", 6);
  /* Failing case for read: no key. */
  test_assert(crypto_pk_read_private_key_from_filename(pk2,
                                                   get_fname("xyzzy")) < 0);
  test_assert(! crypto_pk_read_private_key_from_filename(pk2,
                                                         get_fname("pkey1")));
  test_eq(15, crypto_pk_private_decrypt(pk2, data3, sizeof(data3), data1, 128,
                                        PK_PKCS1_OAEP_PADDING,1));

  /* Now try signing. */
  strlcpy(data1, "Ossifrage", 1024);
  test_eq(128, crypto_pk_private_sign(pk1, data2, sizeof(data2), data1, 10));
  test_eq(10,
          crypto_pk_public_checksig(pk1, data3, sizeof(data3), data2, 128));
  test_streq(data3, "Ossifrage");
  /* Try signing digests. */
  test_eq(128, crypto_pk_private_sign_digest(pk1, data2, sizeof(data2),
                                             data1, 10));
  test_eq(20,
          crypto_pk_public_checksig(pk1, data3, sizeof(data3), data2, 128));
  test_eq(0, crypto_pk_public_checksig_digest(pk1, data1, 10, data2, 128));
  test_eq(-1, crypto_pk_public_checksig_digest(pk1, data1, 11, data2, 128));

  /*XXXX test failed signing*/

  /* Try encoding */
  crypto_pk_free(pk2);
  pk2 = NULL;
  i = crypto_pk_asn1_encode(pk1, data1, 1024);
  test_assert(i>0);
  pk2 = crypto_pk_asn1_decode(data1, i);
  test_assert(crypto_pk_cmp_keys(pk1,pk2) == 0);

  /* Try with hybrid encryption wrappers. */
  crypto_rand(data1, 1024);
  for (i = 0; i < 2; ++i) {
    for (j = 85; j < 140; ++j) {
      memset(data2,0,1024);
      memset(data3,0,1024);
      p = (i==0)?PK_PKCS1_PADDING:PK_PKCS1_OAEP_PADDING;
      len = crypto_pk_public_hybrid_encrypt(pk1,data2,sizeof(data2),
                                            data1,j,p,0);
      test_assert(len>=0);
      len = crypto_pk_private_hybrid_decrypt(pk1,data3,sizeof(data3),
                                             data2,len,p,1);
      test_eq(len,j);
      test_memeq(data1,data3,j);
    }
  }

  /* Try copy_full */
  crypto_pk_free(pk2);
  pk2 = crypto_pk_copy_full(pk1);
  test_assert(pk2 != NULL);
  test_neq_ptr(pk1, pk2);
  test_assert(crypto_pk_cmp_keys(pk1,pk2) == 0);

 done:
  if (pk1)
    crypto_pk_free(pk1);
  if (pk2)
    crypto_pk_free(pk2);
  tor_free(encoded);
}
Example #10
0
  *len_out = r;

  return tor_memdup(signature, r);
}

/** Check whether an RSA-TAP cross-certification is correct. Return 0 if it
 * is, -1 if it isn't. */
MOCK_IMPL(int,
check_tap_onion_key_crosscert,(const uint8_t *crosscert,
                               int crosscert_len,
                               const crypto_pk_t *onion_pkey,
                               const ed25519_public_key_t *master_id_pkey,
                               const uint8_t *rsa_id_digest))
{
  uint8_t *cc = tor_malloc(crypto_pk_keysize(onion_pkey));
  int cc_len =
    crypto_pk_public_checksig(onion_pkey,
                              (char*)cc,
                              crypto_pk_keysize(onion_pkey),
                              (const char*)crosscert,
                              crosscert_len);
  if (cc_len < 0) {
    goto err;
  }
  if (cc_len < DIGEST_LEN + ED25519_PUBKEY_LEN) {
    log_warn(LD_DIR, "Short signature on cross-certification with TAP key");
    goto err;
  }
  if (tor_memneq(cc, rsa_id_digest, DIGEST_LEN) ||
      tor_memneq(cc + DIGEST_LEN, master_id_pkey->pubkey,